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"
49#pragma GCC optimize ("O2")
62VGAController * VGAController::s_instance =
nullptr;
65VGAController::VGAController()
71void VGAController::init()
73 VGABaseController::init();
75 m_doubleBufferOverDMA =
true;
81 VGABaseController::suspendBackgroundPrimitiveExecution();
82 if (m_primitiveProcessingSuspended == 1) {
83 I2S1.int_clr.val = 0xFFFFFFFF;
84 I2S1.int_ena.out_eof = 0;
91 VGABaseController::resumeBackgroundPrimitiveExecution();
92 if (m_primitiveProcessingSuspended == 0) {
93 if (m_isr_handle ==
nullptr)
94 esp_intr_alloc(ETS_I2S1_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, VSyncInterrupt,
this, &m_isr_handle);
95 I2S1.int_clr.val = 0xFFFFFFFF;
96 I2S1.int_ena.out_eof = 1;
101void VGAController::allocateViewPort()
103 VGABaseController::allocateViewPort(MALLOC_CAP_DMA, m_viewPortWidth);
107void VGAController::setResolution(VGATimings
const& timings,
int viewPortWidth,
int viewPortHeight,
bool doubleBuffered)
109 VGABaseController::setResolution(timings, viewPortWidth, viewPortHeight, doubleBuffered);
112 for (
int i = 0; i < m_viewPortHeight; ++i)
113 fill(m_viewPort[i], 0, m_viewPortWidth, 0, 0, 0,
false,
false);
116 m_maxVSyncISRTime = ceil(1000000.0 / m_timings.frequency * m_timings.scanCount * m_HLineSize * (m_timings.VSyncPulse + m_timings.VBackPorch + m_timings.VFrontPorch + m_viewPortRow));
123void VGAController::onSetupDMABuffer(lldesc_t
volatile * buffer,
bool isStartOfVertFrontPorch,
int scan,
bool isVisible,
int visibleRow)
126 if (isStartOfVertFrontPorch)
131void IRAM_ATTR VGAController::VSyncInterrupt(
void * arg)
133 if (I2S1.int_st.out_eof) {
134 auto VGACtrl = (VGAController*)arg;
135 int64_t startTime = VGACtrl->backgroundPrimitiveTimeoutEnabled() ? esp_timer_get_time() : 0;
136 Rect updateRect = Rect(SHRT_MAX, SHRT_MAX, SHRT_MIN, SHRT_MIN);
139 if (VGACtrl->getPrimitiveISR(&prim) ==
false)
142 VGACtrl->execPrimitive(prim, updateRect,
true);
144 if (VGACtrl->m_primitiveProcessingSuspended)
147 }
while (!VGACtrl->backgroundPrimitiveTimeoutEnabled() || (startTime + VGACtrl->m_maxVSyncISRTime > esp_timer_get_time()));
148 VGACtrl->showSprites(updateRect);
150 I2S1.int_clr.val = I2S1.int_st.val;
154void IRAM_ATTR VGAController::setPixelAt(PixelDesc
const & pixelDesc, Rect & updateRect)
156 genericSetPixelAt(pixelDesc, updateRect,
157 [&] (RGB888
const & color) {
return preparePixel(color); },
158 [&] (
int X,
int Y, uint8_t pattern) { VGA_PIXEL(
X,
Y) = pattern; }
165void IRAM_ATTR VGAController::absDrawLine(
int X1,
int Y1,
int X2,
int Y2, RGB888 color)
167 genericAbsDrawLine(
X1,
Y1,
X2,
Y2, color,
168 [&] (RGB888
const & color) {
return preparePixel(color); },
169 [&] (
int Y,
int X1,
int X2, uint8_t pattern) { rawFillRow(
Y,
X1,
X2, pattern); },
170 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); },
171 [&] (
int X,
int Y, uint8_t pattern) { VGA_PIXEL(
X,
Y) = pattern; },
172 [&] (
int X,
int Y) { VGA_INVERT_PIXEL(
X,
Y); }
178void IRAM_ATTR VGAController::rawFillRow(
int y,
int x1,
int x2, RGB888 color)
180 rawFillRow(y, x1, x2, preparePixel(color));
185void IRAM_ATTR VGAController::rawFillRow(
int y,
int x1,
int x2, uint8_t pattern)
187 auto row = m_viewPort[y];
190 for (; x <= x2 && (x & 3) != 0; ++x) {
191 VGA_PIXELINROW(row, x) = pattern;
195 int sz = (x2 & ~3) - x;
196 memset((
void*)(row + x), pattern, sz);
200 for (; x <= x2; ++x) {
201 VGA_PIXELINROW(row, x) = pattern;
207void IRAM_ATTR VGAController::rawInvertRow(
int y,
int x1,
int x2)
209 auto row = m_viewPort[y];
210 for (
int x = x1; x <= x2; ++x) {
211 uint8_t * px = (uint8_t*) &VGA_PIXELINROW(row, x);
212 *px = m_HVSync | ~(*px);
219void IRAM_ATTR VGAController::swapRows(
int yA,
int yB,
int x1,
int x2)
221 uint8_t * rowA = (uint8_t*) m_viewPort[yA];
222 uint8_t * rowB = (uint8_t*) m_viewPort[yB];
225 for (; x <= x2 && (x & 3) != 0; ++x)
226 tswap(VGA_PIXELINROW(rowA, x), VGA_PIXELINROW(rowB, x));
228 uint32_t * a = (uint32_t*)(rowA + x);
229 uint32_t * b = (uint32_t*)(rowB + x);
230 for (
int right = (x2 & ~3); x < right; x += 4)
233 for (x = (x2 & ~3); x <= x2; ++x)
234 tswap(VGA_PIXELINROW(rowA, x), VGA_PIXELINROW(rowB, x));
238void IRAM_ATTR VGAController::drawEllipse(Size
const & size, Rect & updateRect)
240 genericDrawEllipse(size, updateRect,
241 [&] (RGB888
const & color) {
return preparePixel(color); },
242 [&] (
int X,
int Y, uint8_t pattern) { VGA_PIXEL(
X,
Y) = pattern; }
247void IRAM_ATTR VGAController::clear(Rect & updateRect)
249 hideSprites(updateRect);
250 uint8_t pattern = preparePixel(getActualBrushColor());
251 for (
int y = 0; y < m_viewPortHeight; ++y)
252 memset((uint8_t*) m_viewPort[y], pattern, m_viewPortWidth);
259void IRAM_ATTR VGAController::VScroll(
int scroll, Rect & updateRect)
261 genericVScroll(scroll, updateRect,
262 [&] (
int yA,
int yB,
int x1,
int x2) { swapRows(yA, yB, x1, x2); },
263 [&] (
int yA,
int yB) { tswap(m_viewPort[yA], m_viewPort[yB]); },
264 [&] (
int y,
int x1,
int x2, RGB888 pattern) { rawFillRow(y, x1, x2, pattern); }
269 int viewPortBuffersPerLine = 0;
271 switch (m_timings.HStartingBlock) {
274 viewPortBuffersPerLine = (m_viewPortCol + m_viewPortWidth) < m_timings.HVisibleArea ? 3 : 2;
278 viewPortBuffersPerLine = 3;
282 viewPortBuffersPerLine = 3;
286 viewPortBuffersPerLine = m_viewPortCol > 0 ? 3 : 2;
287 linePos = m_viewPortCol > 0 ? 1 : 0;
290 const int Y1 = paintState().scrollingRegion.Y1;
291 const int Y2 = paintState().scrollingRegion.Y2;
292 for (
int i =
Y1, idx =
Y1 * m_timings.scanCount; i <=
Y2; ++i)
293 for (
int scan = 0; scan < m_timings.scanCount; ++scan, ++idx)
294 setDMABufferView(m_viewPortRow * m_timings.scanCount + idx * viewPortBuffersPerLine + linePos, i, scan, m_viewPort,
false);
303void IRAM_ATTR VGAController::HScroll(
int scroll, Rect & updateRect)
305 hideSprites(updateRect);
306 uint8_t pattern8 = preparePixel(getActualBrushColor());
307 uint16_t pattern16 = pattern8 << 8 | pattern8;
308 uint32_t pattern32 = pattern16 << 16 | pattern16;
310 int Y1 = paintState().scrollingRegion.Y1;
311 int Y2 = paintState().scrollingRegion.Y2;
312 int X1 = paintState().scrollingRegion.X1;
313 int X2 = paintState().scrollingRegion.X2;
316 int width32 =
width >> 2;
317 bool HScrolllingRegionAligned = ((
X1 & 3) == 0 && (
width & 3) == 0);
321 for (
int y =
Y1; y <=
Y2; ++y) {
322 if (HScrolllingRegionAligned) {
324 uint8_t * row = (uint8_t*) (m_viewPort[y] +
X1);
325 for (
int s = -scroll; s > 0;) {
329 int sz = (s & ~3) >> 2;
330 for (
int i = 0; i < width32 - sz; ++i, w += 4)
331 *((uint32_t*)w) = *((uint32_t*)w + sz);
332 for (
int i = tmax(0, width32 - sz); i < width32; ++i, w += 4)
333 *((uint32_t*)w) = pattern32;
335 }
else if ((s & 3) == 3) {
338 for (
int i = 1; i < width32; ++i, b += 4) {
345 b[1] = b[0] = b[3] = pattern8;
349 uint16_t * w = (uint16_t*) row;
350 for (
int i = 1; i < width32; ++i, w += 2) {
360 for (
int i = 1; i < width32; ++i, w += 4) {
361 *((uint32_t*)w) = *((uint32_t*)w) >> 8 | *((uint32_t*)w) << 24;
364 *((uint32_t*)w) = *((uint32_t*)w) >> 8 | *((uint32_t*)w) << 24;
371 uint8_t * row = (uint8_t*) m_viewPort[y];
372 for (
int x =
X1; x <=
X2 + scroll; ++x)
373 VGA_PIXELINROW(row, x) = VGA_PIXELINROW(row, x - scroll);
375 for (
int x =
X2 + 1 + scroll; x <=
X2; ++x)
376 VGA_PIXELINROW(row, x) = pattern8;
379 }
else if (scroll > 0) {
381 for (
int y =
Y1; y <=
Y2; ++y) {
382 if (HScrolllingRegionAligned) {
384 uint8_t * row = (uint8_t*) (m_viewPort[y] +
X1);
385 for (
int s = scroll; s > 0;) {
388 int sz = (s & ~3) >> 2;
389 uint8_t * w = row +
width - 4;
390 for (
int i = 0; i < width32 - sz; ++i, w -= 4)
391 *((uint32_t*)w) = *((uint32_t*)w - sz);
392 for (
int i = tmax(0, width32 - sz); i < width32; ++i, w -= 4)
393 *((uint32_t*)w) = pattern32;
395 }
else if ((s & 3) == 3) {
397 uint8_t * b = row +
width - 4;
398 for (
int i = 1; i < width32; ++i, b -= 4) {
405 b[0] = b[2] = b[3] = pattern8;
409 uint16_t * w = (uint16_t*) (row +
width - 4);
410 for (
int i = 1; i < width32; ++i, w -= 2) {
419 uint8_t * w = row +
width - 4;
420 for (
int i = 1; i < width32; ++i, w -= 4) {
421 *((uint32_t*)w) = *((uint32_t*)w) << 8 | *((uint32_t*)w) >> 24;
424 *((uint32_t*)w) = *((uint32_t*)w) << 8 | *((uint32_t*)w) >> 24;
431 uint8_t * row = (uint8_t*) m_viewPort[y];
432 for (
int x =
X2 - scroll; x >=
X1; --x)
433 VGA_PIXELINROW(row, x + scroll) = VGA_PIXELINROW(row, x);
435 for (
int x =
X1; x <
X1 + scroll; ++x)
436 VGA_PIXELINROW(row, x) = pattern8;
444void IRAM_ATTR VGAController::drawGlyph(Glyph
const & glyph, GlyphOptions glyphOptions, RGB888 penColor, RGB888 brushColor, Rect & updateRect)
446 genericDrawGlyph(glyph, glyphOptions, penColor, brushColor, updateRect,
447 [&] (RGB888
const & color) {
return preparePixel(color); },
448 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
449 [&] (uint8_t * row,
int x, uint8_t pattern) { VGA_PIXELINROW(row, x) = pattern; }
454void IRAM_ATTR VGAController::invertRect(Rect
const & rect, Rect & updateRect)
456 genericInvertRect(rect, updateRect,
457 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); }
462void IRAM_ATTR VGAController::swapFGBG(Rect
const & rect, Rect & updateRect)
464 genericSwapFGBG(rect, updateRect,
465 [&] (RGB888
const & color) {
return preparePixel(color); },
466 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
467 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
468 [&] (uint8_t * row,
int x, uint8_t pattern) { VGA_PIXELINROW(row, x) = pattern; }
475void IRAM_ATTR VGAController::copyRect(Rect
const & source, Rect & updateRect)
477 genericCopyRect(source, updateRect,
478 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
479 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
480 [&] (uint8_t * row,
int x, uint8_t pattern) { VGA_PIXELINROW(row, x) = pattern; }
488 for (
int y = rect.Y1; y <= rect.Y2; ++y) {
489 uint8_t * row = (uint8_t*) m_viewPort[y];
490 for (
int x = rect.X1; x <= rect.X2; ++x, ++destBuf) {
491 uint8_t rawpix = VGA_PIXELINROW(row, x);
492 *destBuf = RGB888((rawpix & 3) * 85, ((rawpix >> 2) & 3) * 85, ((rawpix >> 4) & 3) * 85);
501 uint8_t * dbuf = (uint8_t*) destBuf;
502 for (
int y = rect.Y1; y <= rect.Y2; ++y) {
503 uint8_t * row = (uint8_t*) m_viewPort[y];
504 for (
int x = rect.X1; x <= rect.X2; ++x, ++dbuf)
505 *dbuf = VGA_PIXELINROW(row, x) & ~VGA_SYNC_MASK;
513 uint8_t * sbuf = (uint8_t*) srcBuf;
514 for (
int y = rect.Y1; y <= rect.Y2; ++y) {
515 uint8_t * row = (uint8_t*) m_viewPort[y];
516 for (
int x = rect.X1; x <= rect.X2; ++x, ++sbuf)
517 VGA_PIXELINROW(row, x) = *sbuf | m_HVSync;
522void IRAM_ATTR VGAController::rawDrawBitmap_Native(
int destX,
int destY,
Bitmap const * bitmap,
int X1,
int Y1,
int XCount,
int YCount)
524 genericRawDrawBitmap_Native(destX, destY, (uint8_t*) bitmap->data, bitmap->width,
X1,
Y1, XCount, YCount,
525 [&] (
int y) { return (uint8_t*) m_viewPort[y]; },
526 [&] (uint8_t * row,
int x, uint8_t src) { VGA_PIXELINROW(row, x) = m_HVSync | src; }
531void IRAM_ATTR VGAController::rawDrawBitmap_Mask(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
533 auto foregroundPattern = preparePixel(bitmap->foregroundColor);
534 genericRawDrawBitmap_Mask(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
535 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
536 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
537 [&] (uint8_t * row,
int x) { VGA_PIXELINROW(row, x) = foregroundPattern; }
542void IRAM_ATTR VGAController::rawDrawBitmap_RGBA2222(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
544 genericRawDrawBitmap_RGBA2222(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
545 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
546 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
547 [&] (uint8_t * row,
int x, uint8_t src) { VGA_PIXELINROW(row, x) = m_HVSync | (src & 0x3f); }
552void IRAM_ATTR VGAController::rawDrawBitmap_RGBA8888(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
554 genericRawDrawBitmap_RGBA8888(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
555 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
556 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
557 [&] (uint8_t * row,
int x,
RGBA8888 const & src) { VGA_PIXELINROW(row, x) = m_HVSync | (src.R >> 6) | (src.G >> 6 << 2) | (src.B >> 6 << 4); }
void suspendBackgroundPrimitiveExecution()
Suspends drawings.
void resumeBackgroundPrimitiveExecution()
Resumes drawings after suspendBackgroundPrimitiveExecution().
void readScreen(Rect const &rect, RGB222 *destBuf)
Reads pixels inside the specified rectangle.
void writeScreen(Rect const &rect, RGB222 *srcBuf)
Writes pixels inside the specified rectangle.
This file contains some utility classes and functions.
Represents a 6 bit RGB color.
This file contains fabgl::GPIOStream definition.
This file contains fabgl::VGAController definition.