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"
49#pragma GCC optimize ("O2")
58static inline __attribute__((always_inline))
void VGA4_SETPIXELINROW(uint8_t * row,
int x,
int value) {
60 int shift = 6 - (x & 3) * 2;
61 row[brow] ^= ((value << shift) ^ row[brow]) & (3 << shift);
64static inline __attribute__((always_inline))
int VGA4_GETPIXELINROW(uint8_t * row,
int x) {
66 int shift = 6 - (x & 3) * 2;
67 return (row[brow] >> shift) & 3;
70#define VGA4_INVERTPIXELINROW(row, x) (row)[(x) >> 2] ^= 3 << (6 - ((x) & 3) * 2)
72static inline __attribute__((always_inline))
void VGA4_SETPIXEL(
int x,
int y,
int value) {
73 auto row = (uint8_t*) VGA4Controller::sgetScanline(y);
75 int shift = 6 - (x & 3) * 2;
76 row[brow] ^= ((value << shift) ^ row[brow]) & (3 << shift);
79#define VGA4_GETPIXEL(x, y) VGA4_GETPIXELINROW((uint8_t*)VGA4Controller::s_viewPort[(y)], (x))
81#define VGA4_INVERT_PIXEL(x, y) VGA4_INVERTPIXELINROW((uint8_t*)VGA4Controller::s_viewPort[(y)], (x))
84#define VGA4_COLUMNSQUANTUM 16
92VGA4Controller * VGA4Controller::s_instance =
nullptr;
96VGA4Controller::VGA4Controller()
100 m_packedPaletteIndexQuad_to_signals = (uint32_t *) heap_caps_malloc(256 *
sizeof(uint32_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
104VGA4Controller::~VGA4Controller()
106 heap_caps_free((
void *)m_packedPaletteIndexQuad_to_signals);
110void VGA4Controller::setupDefaultPalette()
112 setPaletteItem(0, RGB888(0, 0, 0));
113 setPaletteItem(1, RGB888(0, 0, 255));
114 setPaletteItem(2, RGB888(0, 255, 0));
115 setPaletteItem(3, RGB888(255, 255, 255));
119void VGA4Controller::setPaletteItem(
int index,
RGB888 const & color)
122 m_palette[index] = color;
123 auto packed222 = RGB888toPackedRGB222(color);
124 for (
int i = 0; i < 256; ++i) {
125 auto b = (uint8_t *) (m_packedPaletteIndexQuad_to_signals + i);
126 for (
int j = 0; j < 4; ++j) {
128 if (((i >> aj) & 3) == index) {
129 b[j ^ 2] = m_HVSync | packed222;
136void VGA4Controller::setPixelAt(PixelDesc
const & pixelDesc,
Rect & updateRect)
138 genericSetPixelAt(pixelDesc, updateRect,
139 [&] (
RGB888 const & color) {
return RGB888toPaletteIndex(color); },
147void VGA4Controller::absDrawLine(
int X1,
int Y1,
int X2,
int Y2, RGB888 color)
149 genericAbsDrawLine(
X1,
Y1,
X2,
Y2, color,
150 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
151 [&] (
int Y,
int X1,
int X2, uint8_t colorIndex) { rawFillRow(
Y,
X1,
X2, colorIndex); },
152 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); },
154 [&] (
int X,
int Y) { VGA4_INVERT_PIXEL(
X,
Y); }
160void VGA4Controller::rawFillRow(
int y,
int x1,
int x2, RGB888 color)
162 rawFillRow(y, x1, x2, RGB888toPaletteIndex(color));
167void VGA4Controller::rawFillRow(
int y,
int x1,
int x2, uint8_t colorIndex)
169 uint8_t * row = (uint8_t*) m_viewPort[y];
172 for (; x <= x2 && (x & 3) != 0; ++x) {
173 VGA4_SETPIXELINROW(row, x, colorIndex);
177 int sz = (x2 & ~3) - x;
178 memset((
void*)(row + x / 4), colorIndex | (colorIndex << 2) | (colorIndex << 4) | (colorIndex << 6), sz / 4);
182 for (; x <= x2; ++x) {
183 VGA4_SETPIXELINROW(row, x, colorIndex);
189void VGA4Controller::rawInvertRow(
int y,
int x1,
int x2)
191 auto row = m_viewPort[y];
192 for (
int x = x1; x <= x2; ++x)
193 VGA4_INVERTPIXELINROW(row, x);
197void VGA4Controller::rawCopyRow(
int x1,
int x2,
int srcY,
int dstY)
199 auto srcRow = (uint8_t*) m_viewPort[srcY];
200 auto dstRow = (uint8_t*) m_viewPort[dstY];
203 for (; x <= x2 && (x & 3) != 0; ++x) {
204 VGA4_SETPIXELINROW(dstRow, x, VGA4_GETPIXELINROW(srcRow, x));
207 auto src = (uint8_t*)(srcRow + x / 4);
208 auto dst = (uint8_t*)(dstRow + x / 4);
209 for (
int right = (x2 & ~3); x < right; x += 4)
212 for (x = (x2 & ~3); x <= x2; ++x) {
213 VGA4_SETPIXELINROW(dstRow, x, VGA4_GETPIXELINROW(srcRow, x));
218void VGA4Controller::swapRows(
int yA,
int yB,
int x1,
int x2)
220 auto rowA = (uint8_t*) m_viewPort[yA];
221 auto rowB = (uint8_t*) m_viewPort[yB];
224 for (; x <= x2 && (x & 3) != 0; ++x) {
225 uint8_t a = VGA4_GETPIXELINROW(rowA, x);
226 uint8_t b = VGA4_GETPIXELINROW(rowB, x);
227 VGA4_SETPIXELINROW(rowA, x, b);
228 VGA4_SETPIXELINROW(rowB, x, a);
231 auto a = (uint8_t*)(rowA + x / 4);
232 auto b = (uint8_t*)(rowB + x / 4);
233 for (
int right = (x2 & ~3); x < right; x += 4)
236 for (x = (x2 & ~3); x <= x2; ++x) {
237 uint8_t a = VGA4_GETPIXELINROW(rowA, x);
238 uint8_t b = VGA4_GETPIXELINROW(rowB, x);
239 VGA4_SETPIXELINROW(rowA, x, b);
240 VGA4_SETPIXELINROW(rowB, x, a);
245void VGA4Controller::drawEllipse(Size
const & size, Rect & updateRect)
247 genericDrawEllipse(size, updateRect,
248 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
254void VGA4Controller::clear(Rect & updateRect)
256 hideSprites(updateRect);
257 uint8_t paletteIndex = RGB888toPaletteIndex(getActualBrushColor());
258 uint8_t pattern4 = paletteIndex | (paletteIndex << 2) | (paletteIndex << 4) | (paletteIndex << 6);
259 for (
int y = 0; y < m_viewPortHeight; ++y)
260 memset((uint8_t*) m_viewPort[y], pattern4, m_viewPortWidth / 4);
266void VGA4Controller::VScroll(
int scroll, Rect & updateRect)
268 genericVScroll(scroll, updateRect,
269 [&] (
int yA,
int yB,
int x1,
int x2) { swapRows(yA, yB, x1, x2); },
270 [&] (
int yA,
int yB) { tswap(m_viewPort[yA], m_viewPort[yB]); },
271 [&] (
int y,
int x1,
int x2, RGB888 color) { rawFillRow(y, x1, x2, color); }
276void VGA4Controller::HScroll(
int scroll, Rect & updateRect)
278 hideSprites(updateRect);
279 uint8_t back = RGB888toPaletteIndex(getActualBrushColor());
280 uint8_t back4 = back | (back << 2) | (back << 4) | (back << 6);
282 int Y1 = paintState().scrollingRegion.Y1;
283 int Y2 = paintState().scrollingRegion.Y2;
284 int X1 = paintState().scrollingRegion.X1;
285 int X2 = paintState().scrollingRegion.X2;
288 bool HScrolllingRegionAligned = ((
X1 & 3) == 0 && (
width & 3) == 0);
292 for (
int y =
Y1; y <=
Y2; ++y) {
293 if (HScrolllingRegionAligned) {
295 uint8_t * row = (uint8_t*) (m_viewPort[y]) +
X1 / 4;
296 for (
int s = -scroll; s > 0;) {
300 uint8_t prev = back4;
301 for (
int i = sz - 1; i >= 0; --i) {
302 uint8_t lowbits = prev >> (8 - s * 2);
304 row[i] = (row[i] << (s * 2)) | lowbits;
310 auto sz =
width & ~3;
311 memmove(row, row + sc / 4, (sz - sc) / 4);
312 rawFillRow(y,
X2 - sc + 1,
X2, back);
318 auto row = (uint8_t*) m_viewPort[y];
319 for (
int x =
X1; x <=
X2 + scroll; ++x)
320 VGA4_SETPIXELINROW(row, x, VGA4_GETPIXELINROW(row, x - scroll));
322 rawFillRow(y,
X2 + 1 + scroll,
X2, back);
325 }
else if (scroll > 0) {
327 for (
int y =
Y1; y <=
Y2; ++y) {
328 if (HScrolllingRegionAligned) {
330 uint8_t * row = (uint8_t*) (m_viewPort[y]) +
X1 / 4;
331 for (
int s = scroll; s > 0;) {
335 uint8_t prev = back4;
336 for (
int i = 0; i < sz; ++i) {
337 uint8_t highbits = prev << (8 - s * 2);
339 row[i] = (row[i] >> (s * 2)) | highbits;
345 auto sz =
width & ~3;
346 memmove(row + sc / 4, row, (sz - sc) / 4);
347 rawFillRow(y,
X1,
X1 + sc - 1, back);
353 auto row = (uint8_t*) m_viewPort[y];
354 for (
int x =
X2 - scroll; x >=
X1; --x)
355 VGA4_SETPIXELINROW(row, x + scroll, VGA4_GETPIXELINROW(row, x));
357 rawFillRow(y,
X1,
X1 + scroll - 1, back);
365void VGA4Controller::drawGlyph(Glyph
const & glyph, GlyphOptions glyphOptions, RGB888 penColor, RGB888 brushColor, Rect & updateRect)
367 genericDrawGlyph(glyph, glyphOptions, penColor, brushColor, updateRect,
368 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
369 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
375void VGA4Controller::invertRect(Rect
const & rect, Rect & updateRect)
377 genericInvertRect(rect, updateRect,
378 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); }
385 genericSwapFGBG(rect, updateRect,
386 [&] (RGB888
const & color) {
return RGB888toPaletteIndex(color); },
387 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
396void VGA4Controller::copyRect(Rect
const & source, Rect & updateRect)
398 genericCopyRect(source, updateRect,
399 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
407void VGA4Controller::readScreen(Rect
const & rect, RGB888 * destBuf)
409 for (
int y = rect.Y1; y <= rect.Y2; ++y) {
410 auto row = (uint8_t*) m_viewPort[y];
411 for (
int x = rect.X1; x <= rect.X2; ++x, ++destBuf) {
412 const RGB222 v = m_palette[VGA4_GETPIXELINROW(row, x)];
413 *destBuf = RGB888(v.R * 85, v.G * 85, v.B * 85);
419void VGA4Controller::rawDrawBitmap_Native(
int destX,
int destY, Bitmap
const * bitmap,
int X1,
int Y1,
int XCount,
int YCount)
421 genericRawDrawBitmap_Native(destX, destY, (uint8_t*) bitmap->data, bitmap->width,
X1,
Y1, XCount, YCount,
422 [&] (
int y) { return (uint8_t*) m_viewPort[y]; },
428void VGA4Controller::rawDrawBitmap_Mask(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
430 auto foregroundColorIndex = RGB888toPaletteIndex(bitmap->foregroundColor);
431 genericRawDrawBitmap_Mask(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) { VGA4_SETPIXELINROW(row, x, foregroundColorIndex); }
439void VGA4Controller::rawDrawBitmap_RGBA2222(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
441 genericRawDrawBitmap_RGBA2222(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
442 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
444 [&] (uint8_t * row,
int x, uint8_t src) { VGA4_SETPIXELINROW(row, x, RGB2222toPaletteIndex(src)); }
449void VGA4Controller::rawDrawBitmap_RGBA8888(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
451 genericRawDrawBitmap_RGBA8888(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
452 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
453 [&] (uint8_t * row,
int x) {
return VGA4_GETPIXELINROW(row, x); },
454 [&] (uint8_t * row,
int x,
RGBA8888 const & src) { VGA4_SETPIXELINROW(row, x, RGB8888toPaletteIndex(src)); }
459void IRAM_ATTR VGA4Controller::ISRHandler(
void * arg)
461 #if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK
462 auto s1 = getCycleCount();
465 auto ctrl = (VGA4Controller *) arg;
467 if (I2S1.int_st.out_eof) {
469 auto const desc = (lldesc_t*) I2S1.out_eof_des_addr;
471 if (desc == s_frameResetDesc)
474 auto const width = ctrl->m_viewPortWidth;
475 auto const height = ctrl->m_viewPortHeight;
476 auto const packedPaletteIndexQuad_to_signals = (uint32_t
const *) ctrl->m_packedPaletteIndexQuad_to_signals;
477 auto const lines = ctrl->m_lines;
479 int scanLine = (s_scanLine + VGA4_LinesCount / 2) %
height;
481 auto lineIndex = scanLine & (VGA4_LinesCount - 1);
483 for (
int i = 0; i < VGA4_LinesCount / 2; ++i) {
485 auto src = (uint8_t
const *) s_viewPortVisible[scanLine];
486 auto dest = (uint32_t*) lines[lineIndex];
489 for (
int col = 0; col <
width; col += 16) {
491 auto src1 = *(src + 0);
492 auto src2 = *(src + 1);
493 auto src3 = *(src + 2);
494 auto src4 = *(src + 3);
498 auto v1 = packedPaletteIndexQuad_to_signals[src1];
499 auto v2 = packedPaletteIndexQuad_to_signals[src2];
500 auto v3 = packedPaletteIndexQuad_to_signals[src3];
501 auto v4 = packedPaletteIndexQuad_to_signals[src4];
516 s_scanLine += VGA4_LinesCount / 2;
518 if (scanLine >=
height && !ctrl->m_primitiveProcessingSuspended && spi_flash_cache_enabled() && ctrl->m_primitiveExecTask) {
521 vTaskNotifyGiveFromISR(ctrl->m_primitiveExecTask, NULL);
526 #if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK
527 s_vgapalctrlcycles += getCycleCount() - s1;
530 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::VGA4Controller definition.