33#include "freertos/FreeRTOS.h"
34#include "freertos/task.h"
36#include "soc/i2s_struct.h"
37#include "soc/i2s_reg.h"
38#include "driver/periph_ctrl.h"
40#include "esp_spi_flash.h"
41#include "esp_heap_caps.h"
50#pragma GCC optimize ("O2")
65static inline __attribute__((always_inline))
void VGA8_SETPIXELINROW(uint8_t * row,
int x,
int value) {
66 uint32_t * bits24 = (uint32_t*)(row + (x >> 3) * 3);
67 int shift = 21 - (x & 7) * 3;
68 *bits24 ^= ((value << shift) ^ *bits24) & (7 << shift);
71static inline __attribute__((always_inline))
int VGA8_GETPIXELINROW(uint8_t * row,
int x) {
72 uint32_t * bits24 = (uint32_t*)(row + (x >> 3) * 3);
73 int shift = 21 - (x & 7) * 3;
74 return (*bits24 >> shift) & 7;
77#define VGA8_INVERTPIXELINROW(row, x) *((uint32_t*)(row + ((x) >> 3) * 3)) ^= 7 << (21 - ((x) & 7) * 3)
79static inline __attribute__((always_inline))
void VGA8_SETPIXEL(
int x,
int y,
int value) {
80 auto row = (uint8_t*) VGA8Controller::sgetScanline(y);
81 uint32_t * bits24 = (uint32_t*)(row + (x >> 3) * 3);
82 int shift = 21 - (x & 7) * 3;
83 *bits24 ^= ((value << shift) ^ *bits24) & (7 << shift);
86#define VGA8_GETPIXEL(x, y) VGA8_GETPIXELINROW((uint8_t*)VGA8Controller::s_viewPort[(y)], (x))
88#define VGA8_INVERT_PIXEL(x, y) VGA8_INVERTPIXELINROW((uint8_t*)VGA8Controller::s_viewPort[(y)], (x))
91#define VGA8_COLUMNSQUANTUM 16
99VGA8Controller * VGA8Controller::s_instance =
nullptr;
104VGA8Controller::VGA8Controller()
108 m_packedPaletteIndexPair_to_signals = (uint16_t *) heap_caps_malloc(256 *
sizeof(uint16_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
112VGA8Controller::~VGA8Controller()
114 heap_caps_free((
void *)m_packedPaletteIndexPair_to_signals);
118void VGA8Controller::setupDefaultPalette()
120 setPaletteItem(0, RGB888(0, 0, 0));
121 setPaletteItem(1, RGB888(128, 0, 0));
122 setPaletteItem(2, RGB888(0, 128, 0));
123 setPaletteItem(3, RGB888(0, 0, 128));
124 setPaletteItem(4, RGB888(255, 0, 0));
125 setPaletteItem(5, RGB888(0, 255, 0));
126 setPaletteItem(6, RGB888(0, 0, 255));
127 setPaletteItem(7, RGB888(255, 255, 255));
131void VGA8Controller::setPaletteItem(
int index,
RGB888 const & color)
134 m_palette[index] = color;
135 auto packed222 = RGB888toPackedRGB222(color);
136 for (
int i = 0; i < 8; ++i) {
137 m_packedPaletteIndexPair_to_signals[(index << 3) | i] &= 0xFF00;
138 m_packedPaletteIndexPair_to_signals[(index << 3) | i] |= (m_HVSync | packed222);
139 m_packedPaletteIndexPair_to_signals[(i << 3) | index] &= 0x00FF;
140 m_packedPaletteIndexPair_to_signals[(i << 3) | index] |= (m_HVSync | packed222) << 8;
145void VGA8Controller::setPixelAt(PixelDesc
const & pixelDesc,
Rect & updateRect)
147 genericSetPixelAt(pixelDesc, updateRect,
148 [&] (
RGB888 const & color) {
return RGB888toPaletteIndex(color); },
156void VGA8Controller::absDrawLine(
int X1,
int Y1,
int X2,
int Y2, RGB888 color)
158 genericAbsDrawLine(
X1,
Y1,
X2,
Y2, color,
159 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
160 [&] (
int Y,
int X1,
int X2, uint8_t colorIndex) { rawFillRow(
Y,
X1,
X2, colorIndex); },
161 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); },
163 [&] (
int X,
int Y) { VGA8_INVERT_PIXEL(
X,
Y); }
169void VGA8Controller::rawFillRow(
int y,
int x1,
int x2, RGB888 color)
171 rawFillRow(y, x1, x2, RGB888toPaletteIndex(color));
176void VGA8Controller::rawFillRow(
int y,
int x1,
int x2, uint8_t colorIndex)
178 uint8_t * row = (uint8_t*) m_viewPort[y];
179 for (; x1 <= x2; ++x1)
180 VGA8_SETPIXELINROW(row, x1, colorIndex);
185void VGA8Controller::rawInvertRow(
int y,
int x1,
int x2)
187 auto row = m_viewPort[y];
188 for (
int x = x1; x <= x2; ++x)
189 VGA8_INVERTPIXELINROW(row, x);
193void VGA8Controller::rawCopyRow(
int x1,
int x2,
int srcY,
int dstY)
195 auto srcRow = (uint8_t*) m_viewPort[srcY];
196 auto dstRow = (uint8_t*) m_viewPort[dstY];
197 for (; x1 <= x2; ++x1)
198 VGA8_SETPIXELINROW(dstRow, x1, VGA8_GETPIXELINROW(srcRow, x1));
202void VGA8Controller::swapRows(
int yA,
int yB,
int x1,
int x2)
204 auto rowA = (uint8_t*) m_viewPort[yA];
205 auto rowB = (uint8_t*) m_viewPort[yB];
206 for (; x1 <= x2; ++x1) {
207 uint8_t a = VGA8_GETPIXELINROW(rowA, x1);
208 uint8_t b = VGA8_GETPIXELINROW(rowB, x1);
209 VGA8_SETPIXELINROW(rowA, x1, b);
210 VGA8_SETPIXELINROW(rowB, x1, a);
215void VGA8Controller::drawEllipse(Size
const & size, Rect & updateRect)
217 genericDrawEllipse(size, updateRect,
218 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
224void VGA8Controller::clear(Rect & updateRect)
226 hideSprites(updateRect);
227 uint8_t paletteIndex = RGB888toPaletteIndex(getActualBrushColor());
228 uint32_t pattern8 = (paletteIndex) | (paletteIndex << 3) | (paletteIndex << 6) | (paletteIndex << 9) | (paletteIndex << 12) | (paletteIndex << 15) | (paletteIndex << 18) | (paletteIndex << 21);
229 for (
int y = 0; y < m_viewPortHeight; ++y) {
230 auto dest = (uint8_t*) m_viewPort[y];
231 for (
int x = 0; x < m_viewPortWidth; x += 8, dest += 3)
232 *((uint32_t*)dest) = (*((uint32_t*)dest) & 0xFF000000) | pattern8;
239void VGA8Controller::VScroll(
int scroll, Rect & updateRect)
241 genericVScroll(scroll, updateRect,
242 [&] (
int yA,
int yB,
int x1,
int x2) { swapRows(yA, yB, x1, x2); },
243 [&] (
int yA,
int yB) { tswap(m_viewPort[yA], m_viewPort[yB]); },
244 [&] (
int y,
int x1,
int x2, RGB888 color) { rawFillRow(y, x1, x2, color); }
250void VGA8Controller::HScroll(
int scroll, Rect & updateRect)
252 hideSprites(updateRect);
253 uint8_t back = RGB888toPaletteIndex(getActualBrushColor());
255 int Y1 = paintState().scrollingRegion.Y1;
256 int Y2 = paintState().scrollingRegion.Y2;
257 int X1 = paintState().scrollingRegion.X1;
258 int X2 = paintState().scrollingRegion.X2;
261 bool HScrolllingRegionAligned = ((
X1 & 7) == 0 && (
width & 7) == 0);
265 for (
int y =
Y1; y <=
Y2; ++y) {
266 for (
int s = -scroll; s > 0;) {
267 if (HScrolllingRegionAligned && s >= 8) {
269 uint8_t * row = (uint8_t*) (m_viewPort[y]) +
X1 / 8 * 3;
271 auto sz =
width & ~7;
272 memmove(row, row + sc / 8 * 3, (sz - sc) / 8 * 3);
273 rawFillRow(y,
X2 - sc + 1,
X2, back);
277 auto row = (uint8_t*) m_viewPort[y];
278 for (
int x =
X1; x <=
X2 - s; ++x)
279 VGA8_SETPIXELINROW(row, x, VGA8_GETPIXELINROW(row, x + s));
281 rawFillRow(y,
X2 - s + 1,
X2, back);
286 }
else if (scroll > 0) {
288 for (
int y =
Y1; y <=
Y2; ++y) {
289 for (
int s = scroll; s > 0;) {
290 if (HScrolllingRegionAligned && s >= 8) {
292 uint8_t * row = (uint8_t*) (m_viewPort[y]) +
X1 / 8 * 3;
294 auto sz =
width & ~7;
295 memmove(row + sc / 8 * 3, row, (sz - sc) / 8 * 3);
296 rawFillRow(y,
X1,
X1 + sc - 1, back);
300 auto row = (uint8_t*) m_viewPort[y];
301 for (
int x =
X2 - s; x >=
X1; --x)
302 VGA8_SETPIXELINROW(row, x + s, VGA8_GETPIXELINROW(row, x));
304 rawFillRow(y,
X1,
X1 + s - 1, back);
313void VGA8Controller::drawGlyph(Glyph
const & glyph, GlyphOptions glyphOptions, RGB888 penColor, RGB888 brushColor, Rect & updateRect)
315 genericDrawGlyph(glyph, glyphOptions, penColor, brushColor, updateRect,
316 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
317 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
323void VGA8Controller::invertRect(Rect
const & rect, Rect & updateRect)
325 genericInvertRect(rect, updateRect,
326 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); }
333 genericSwapFGBG(rect, updateRect,
334 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
335 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
344void VGA8Controller::copyRect(Rect
const & source, Rect & updateRect)
346 genericCopyRect(source, updateRect,
347 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
355void VGA8Controller::readScreen(Rect
const & rect, RGB888 * destBuf)
357 for (
int y = rect.Y1; y <= rect.Y2; ++y) {
358 auto row = (uint8_t*) m_viewPort[y];
359 for (
int x = rect.X1; x <= rect.X2; ++x, ++destBuf) {
360 const RGB222 v = m_palette[VGA8_GETPIXELINROW(row, x)];
361 *destBuf = RGB888(v.R * 85, v.G * 85, v.B * 85);
367void VGA8Controller::rawDrawBitmap_Native(
int destX,
int destY, Bitmap
const * bitmap,
int X1,
int Y1,
int XCount,
int YCount)
369 genericRawDrawBitmap_Native(destX, destY, (uint8_t*) bitmap->data, bitmap->width,
X1,
Y1, XCount, YCount,
370 [&] (
int y) { return (uint8_t*) m_viewPort[y]; },
376void VGA8Controller::rawDrawBitmap_Mask(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
378 auto foregroundColorIndex = RGB888toPaletteIndex(bitmap->foregroundColor);
379 genericRawDrawBitmap_Mask(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
380 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
382 [&] (uint8_t * row,
int x) { VGA8_SETPIXELINROW(row, x, foregroundColorIndex); }
387void VGA8Controller::rawDrawBitmap_RGBA2222(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
389 genericRawDrawBitmap_RGBA2222(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
390 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
392 [&] (uint8_t * row,
int x, uint8_t src) { VGA8_SETPIXELINROW(row, x, RGB2222toPaletteIndex(src)); }
397void VGA8Controller::rawDrawBitmap_RGBA8888(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
399 genericRawDrawBitmap_RGBA8888(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
400 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
401 [&] (uint8_t * row,
int x) {
return VGA8_GETPIXELINROW(row, x); },
402 [&] (uint8_t * row,
int x,
RGBA8888 const & src) { VGA8_SETPIXELINROW(row, x, RGB8888toPaletteIndex(src)); }
407void VGA8Controller::directSetPixel(
int x,
int y,
int value)
409 VGA8_SETPIXEL(x, y, value);
413void IRAM_ATTR VGA8Controller::ISRHandler(
void * arg)
415 #if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK
416 auto s1 = getCycleCount();
419 auto ctrl = (VGA8Controller *) arg;
421 if (I2S1.int_st.out_eof) {
423 auto const desc = (lldesc_t*) I2S1.out_eof_des_addr;
425 if (desc == s_frameResetDesc)
428 auto const width = ctrl->m_viewPortWidth;
429 auto const height = ctrl->m_viewPortHeight;
430 auto const packedPaletteIndexPair_to_signals = (uint16_t
const *) ctrl->m_packedPaletteIndexPair_to_signals;
431 auto const lines = ctrl->m_lines;
433 int scanLine = (s_scanLine + VGA8_LinesCount / 2) %
height;
435 auto lineIndex = scanLine & (VGA8_LinesCount - 1);
437 for (
int i = 0; i < VGA8_LinesCount / 2; ++i) {
439 auto src = (uint8_t
const *) s_viewPortVisible[scanLine];
440 auto dest = (uint16_t*) lines[lineIndex];
443 for (
int col = 0; col <
width; col += 16) {
445 auto w1 = *((uint16_t*)(src ));
446 auto w2 = *((uint16_t*)(src + 2));
447 auto w3 = *((uint16_t*)(src + 4));
451 auto src1 = w1 | (w2 << 16);
452 auto src2 = (w2 >> 8) | (w3 << 8);
454 auto v1 = packedPaletteIndexPair_to_signals[(src1 ) & 0x3f];
455 auto v2 = packedPaletteIndexPair_to_signals[(src1 >> 6) & 0x3f];
456 auto v3 = packedPaletteIndexPair_to_signals[(src1 >> 12) & 0x3f];
457 auto v4 = packedPaletteIndexPair_to_signals[(src1 >> 18) & 0x3f];
458 auto v5 = packedPaletteIndexPair_to_signals[(src2 ) & 0x3f];
459 auto v6 = packedPaletteIndexPair_to_signals[(src2 >> 6) & 0x3f];
460 auto v7 = packedPaletteIndexPair_to_signals[(src2 >> 12) & 0x3f];
461 auto v8 = packedPaletteIndexPair_to_signals[(src2 >> 18) & 0x3f];
481 s_scanLine += VGA8_LinesCount / 2;
483 if (scanLine >=
height && !ctrl->m_primitiveProcessingSuspended && spi_flash_cache_enabled() && ctrl->m_primitiveExecTask) {
486 vTaskNotifyGiveFromISR(ctrl->m_primitiveExecTask, NULL);
491 #if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK
492 s_vgapalctrlcycles += getCycleCount() - s1;
495 I2S1.int_clr.val = I2S1.int_st.val;
This file contains some utility classes and functions.
NativePixelFormat
This enum defines the display controller native pixel format.
Represents a 24 bit RGB color.
This file contains fabgl::GPIOStream definition.
This file contains fabgl::VGA8Controller definition.