29 #include "freertos/FreeRTOS.h" 30 #include "freertos/task.h" 32 #include "soc/i2s_struct.h" 33 #include "soc/i2s_reg.h" 34 #include "driver/periph_ctrl.h" 35 #include "rom/lldesc.h" 37 #include "esp_spi_flash.h" 38 #include "esp_heap_caps.h" 55 static inline __attribute__((always_inline))
void VGA2_SETPIXELINROW(uint8_t * row,
int x,
int value) {
57 row[brow] ^= (-value ^ row[brow]) & (0x80 >> (x & 7));
60 static inline __attribute__((always_inline))
int VGA2_GETPIXELINROW(uint8_t * row,
int x) {
62 return (row[brow] & (0x80 >> (x & 7))) != 0;
65 #define VGA2_INVERTPIXELINROW(row, x) (row)[(x) >> 3] ^= (0x80 >> ((x) & 7)) 67 static inline __attribute__((always_inline))
void VGA2_SETPIXEL(
int x,
int y,
int value) {
68 auto row = (uint8_t*) VGA2Controller::sgetScanline(y);
70 row[brow] ^= (-value ^ row[brow]) & (0x80 >> (x & 7));
73 #define VGA2_GETPIXEL(x, y) VGA2_GETPIXELINROW((uint8_t*)VGA2Controller::s_viewPort[(y)], (x)) 75 #define VGA2_INVERT_PIXEL(x, y) VGA2_INVERTPIXELINROW((uint8_t*)VGA2Controller::s_viewPort[(y)], (x)) 84 VGA2Controller * VGA2Controller::s_instance =
nullptr;
88 VGA2Controller::VGA2Controller()
92 m_packedPaletteIndexOctet_to_signals = (uint64_t *) heap_caps_malloc(256 *
sizeof(uint64_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
96 VGA2Controller::~VGA2Controller()
98 heap_caps_free((
void *)m_packedPaletteIndexOctet_to_signals);
102 void VGA2Controller::setupDefaultPalette()
112 m_palette[index] = color;
113 auto packed222 = RGB888toPackedRGB222(color);
114 for (
int i = 0; i < 256; ++i) {
115 auto b = (uint8_t *) (m_packedPaletteIndexOctet_to_signals + i);
116 for (
int j = 0; j < 8; ++j) {
118 if ((index == 0 && ((1 << aj) & i) == 0) || (index == 1 && ((1 << aj) & i) != 0)) {
119 b[j ^ 2] = m_HVSync | packed222;
126 void VGA2Controller::setPixelAt(PixelDesc
const & pixelDesc,
Rect & updateRect)
128 genericSetPixelAt(pixelDesc, updateRect,
129 [&] (
RGB888 const & color) {
return RGB888toPaletteIndex(color); },
137 void VGA2Controller::absDrawLine(
int X1,
int Y1,
int X2,
int Y2, RGB888 color)
139 genericAbsDrawLine(
X1,
Y1,
X2,
Y2, color,
140 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
141 [&] (
int Y,
int X1,
int X2, uint8_t colorIndex) { rawFillRow(
Y,
X1,
X2, colorIndex); },
142 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); },
144 [&] (
int X,
int Y) { VGA2_INVERT_PIXEL(
X,
Y); }
150 void VGA2Controller::rawFillRow(
int y,
int x1,
int x2, RGB888 color)
152 rawFillRow(y, x1, x2, RGB888toPaletteIndex(color));
157 void VGA2Controller::rawFillRow(
int y,
int x1,
int x2, uint8_t colorIndex)
159 uint8_t * row = (uint8_t*) m_viewPort[y];
162 for (; x <= x2 && (x & 7) != 0; ++x) {
163 VGA2_SETPIXELINROW(row, x, colorIndex);
167 int sz = (x2 & ~7) - x;
168 memset((
void*)(row + x / 8), colorIndex ? 0xFF : 0x00, sz / 8);
172 for (; x <= x2; ++x) {
173 VGA2_SETPIXELINROW(row, x, colorIndex);
179 void VGA2Controller::rawInvertRow(
int y,
int x1,
int x2)
181 auto row = m_viewPort[y];
182 for (
int x = x1; x <= x2; ++x)
183 VGA2_INVERTPIXELINROW(row, x);
187 void VGA2Controller::rawCopyRow(
int x1,
int x2,
int srcY,
int dstY)
189 auto srcRow = (uint8_t*) m_viewPort[srcY];
190 auto dstRow = (uint8_t*) m_viewPort[dstY];
193 for (; x <= x2 && (x & 7) != 0; ++x) {
194 VGA2_SETPIXELINROW(dstRow, x, VGA2_GETPIXELINROW(srcRow, x));
197 auto src = (uint8_t*)(srcRow + x / 8);
198 auto dst = (uint8_t*)(dstRow + x / 8);
199 for (
int right = (x2 & ~7); x < right; x += 8)
202 for (x = (x2 & ~7); x <= x2; ++x) {
203 VGA2_SETPIXELINROW(dstRow, x, VGA2_GETPIXELINROW(srcRow, x));
208 void VGA2Controller::swapRows(
int yA,
int yB,
int x1,
int x2)
210 auto rowA = (uint8_t*) m_viewPort[yA];
211 auto rowB = (uint8_t*) m_viewPort[yB];
214 for (; x <= x2 && (x & 7) != 0; ++x) {
215 uint8_t a = VGA2_GETPIXELINROW(rowA, x);
216 uint8_t b = VGA2_GETPIXELINROW(rowB, x);
217 VGA2_SETPIXELINROW(rowA, x, b);
218 VGA2_SETPIXELINROW(rowB, x, a);
221 auto a = (uint8_t*)(rowA + x / 8);
222 auto b = (uint8_t*)(rowB + x / 8);
223 for (
int right = (x2 & ~7); x < right; x += 8)
226 for (x = (x2 & ~7); x <= x2; ++x) {
227 uint8_t a = VGA2_GETPIXELINROW(rowA, x);
228 uint8_t b = VGA2_GETPIXELINROW(rowB, x);
229 VGA2_SETPIXELINROW(rowA, x, b);
230 VGA2_SETPIXELINROW(rowB, x, a);
235 void VGA2Controller::drawEllipse(Size
const & size, Rect & updateRect)
237 genericDrawEllipse(size, updateRect,
238 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
244 void VGA2Controller::clear(Rect & updateRect)
246 hideSprites(updateRect);
247 uint8_t paletteIndex = RGB888toPaletteIndex(getActualBrushColor());
248 uint8_t pattern8 = paletteIndex ? 0xFF : 0x00;
249 for (
int y = 0; y < m_viewPortHeight; ++y)
250 memset((uint8_t*) m_viewPort[y], pattern8, m_viewPortWidth / 8);
256 void VGA2Controller::VScroll(
int scroll, Rect & updateRect)
258 genericVScroll(scroll, updateRect,
259 [&] (
int yA,
int yB,
int x1,
int x2) { swapRows(yA, yB, x1, x2); },
260 [&] (
int yA,
int yB) { tswap(m_viewPort[yA], m_viewPort[yB]); },
261 [&] (
int y,
int x1,
int x2, RGB888 color) { rawFillRow(y, x1, x2, color); }
266 void VGA2Controller::HScroll(
int scroll, Rect & updateRect)
268 hideSprites(updateRect);
269 uint8_t back = RGB888toPaletteIndex(getActualBrushColor());
270 uint8_t back8 = back ? 0xFF : 0x00;
272 int Y1 = paintState().scrollingRegion.Y1;
273 int Y2 = paintState().scrollingRegion.Y2;
274 int X1 = paintState().scrollingRegion.X1;
275 int X2 = paintState().scrollingRegion.X2;
278 bool HScrolllingRegionAligned = ((
X1 & 7) == 0 && (
width & 7) == 0);
282 for (
int y =
Y1; y <=
Y2; ++y) {
283 if (HScrolllingRegionAligned) {
285 uint8_t * row = (uint8_t*) (m_viewPort[y]) +
X1 / 8;
286 for (
int s = -scroll; s > 0;) {
290 uint8_t prev = back8;
291 for (
int i = sz - 1; i >= 0; --i) {
292 uint8_t lowbits = prev >> (8 - s);
294 row[i] = (row[i] << s) | lowbits;
300 auto sz =
width & ~7;
301 memmove(row, row + sc / 8, (sz - sc) / 8);
302 rawFillRow(y,
X2 - sc + 1,
X2, back);
308 auto row = (uint8_t*) m_viewPort[y];
309 for (
int x =
X1; x <=
X2 + scroll; ++x)
310 VGA2_SETPIXELINROW(row, x, VGA2_GETPIXELINROW(row, x - scroll));
312 rawFillRow(y,
X2 + 1 + scroll,
X2, back);
315 }
else if (scroll > 0) {
317 for (
int y =
Y1; y <=
Y2; ++y) {
318 if (HScrolllingRegionAligned) {
320 uint8_t * row = (uint8_t*) (m_viewPort[y]) +
X1 / 8;
321 for (
int s = scroll; s > 0;) {
325 uint8_t prev = back8;
326 for (
int i = 0; i < sz; ++i) {
327 uint8_t highbits = prev << (8 - s);
329 row[i] = (row[i] >> s) | highbits;
335 auto sz =
width & ~7;
336 memmove(row + sc / 8, row, (sz - sc) / 8);
337 rawFillRow(y,
X1,
X1 + sc - 1, back);
343 auto row = (uint8_t*) m_viewPort[y];
344 for (
int x =
X2 - scroll; x >=
X1; --x)
345 VGA2_SETPIXELINROW(row, x + scroll, VGA2_GETPIXELINROW(row, x));
347 rawFillRow(y,
X1,
X1 + scroll - 1, back);
355 void VGA2Controller::drawGlyph(Glyph
const & glyph, GlyphOptions glyphOptions, RGB888 penColor, RGB888 brushColor, Rect & updateRect)
357 genericDrawGlyph(glyph, glyphOptions, penColor, brushColor, updateRect,
358 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
359 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
365 void VGA2Controller::invertRect(Rect
const & rect, Rect & updateRect)
367 genericInvertRect(rect, updateRect,
368 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); }
373 void VGA2Controller::swapFGBG(Rect
const & rect, Rect & updateRect)
375 genericSwapFGBG(rect, updateRect,
376 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
377 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
386 void VGA2Controller::copyRect(Rect
const & source, Rect & updateRect)
388 genericCopyRect(source, updateRect,
389 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
397 void VGA2Controller::readScreen(Rect
const & rect, RGB888 * destBuf)
399 for (
int y = rect.Y1; y <= rect.Y2; ++y) {
400 auto row = (uint8_t*) m_viewPort[y];
401 for (
int x = rect.X1; x <= rect.X2; ++x, ++destBuf) {
402 const RGB222 v = m_palette[VGA2_GETPIXELINROW(row, x)];
403 *destBuf = RGB888(v.R * 85, v.G * 85, v.B * 85);
409 void VGA2Controller::rawDrawBitmap_Native(
int destX,
int destY, Bitmap
const * bitmap,
int X1,
int Y1,
int XCount,
int YCount)
411 genericRawDrawBitmap_Native(destX, destY, (uint8_t*) bitmap->data, bitmap->width,
X1,
Y1, XCount, YCount,
412 [&] (
int y) { return (uint8_t*) m_viewPort[y]; },
418 void VGA2Controller::rawDrawBitmap_Mask(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
420 auto foregroundColorIndex = RGB888toPaletteIndex(bitmap->foregroundColor);
421 genericRawDrawBitmap_Mask(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
422 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
424 [&] (uint8_t * row,
int x) { VGA2_SETPIXELINROW(row, x, foregroundColorIndex); }
429 void VGA2Controller::rawDrawBitmap_RGBA2222(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
431 genericRawDrawBitmap_RGBA2222(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
432 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
434 [&] (uint8_t * row,
int x, uint8_t src) { VGA2_SETPIXELINROW(row, x, RGB2222toPaletteIndex(src)); }
439 void VGA2Controller::rawDrawBitmap_RGBA8888(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
441 genericRawDrawBitmap_RGBA8888(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
442 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
443 [&] (uint8_t * row,
int x) {
return VGA2_GETPIXELINROW(row, x); },
444 [&] (uint8_t * row,
int x,
RGBA8888 const & src) { VGA2_SETPIXELINROW(row, x, RGB8888toPaletteIndex(src)); }
449 #pragma GCC optimize ("O2") 452 void IRAM_ATTR VGA2Controller::ISRHandler(
void * arg)
454 #if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK 455 auto s1 = getCycleCount();
458 auto ctrl = (VGA2Controller *) arg;
460 if (I2S1.int_st.out_eof) {
462 auto const desc = (lldesc_t*) I2S1.out_eof_des_addr;
464 if (desc == s_frameResetDesc)
467 auto const width = ctrl->m_viewPortWidth;
468 auto const height = ctrl->m_viewPortHeight;
469 auto const packedPaletteIndexOctet_to_signals = (uint64_t
const *) ctrl->m_packedPaletteIndexOctet_to_signals;
470 auto const lines = ctrl->m_lines;
472 int scanLine = (s_scanLine + VGA2_LinesCount / 2) %
height;
474 auto lineIndex = scanLine & (VGA2_LinesCount - 1);
476 for (
int i = 0; i < VGA2_LinesCount / 2; ++i) {
478 auto src = (uint8_t
const *) s_viewPortVisible[scanLine];
479 auto dest = (uint64_t*) lines[lineIndex];
482 for (
int col = 0; col <
width; col += 16) {
484 auto src1 = *(src + 0);
485 auto src2 = *(src + 1);
489 auto v1 = packedPaletteIndexOctet_to_signals[src1];
490 auto v2 = packedPaletteIndexOctet_to_signals[src2];
504 s_scanLine += VGA2_LinesCount / 2;
506 if (scanLine >=
height && !ctrl->m_primitiveProcessingSuspended && spi_flash_cache_enabled()) {
509 vTaskNotifyGiveFromISR(ctrl->m_primitiveExecTask, NULL);
514 #if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK 515 s_vgapalctrlcycles += getCycleCount() - s1;
518 I2S1.int_clr.val = I2S1.int_st.val;
Represents a 24 bit RGB color.
This file contains fabgl::GPIOStream definition.
void setPaletteItem(int index, RGB888 const &color)
Determines color of specified palette item.
This file contains fabgl::VGA2Controller definition.
This file contains some utility classes and functions.
NativePixelFormat
This enum defines the display controller native pixel format.