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" 59 VGAController * VGAController::s_instance =
nullptr;
62 VGAController::VGAController()
68 void VGAController::init()
70 VGABaseController::init();
72 m_doubleBufferOverDMA =
true;
78 VGABaseController::suspendBackgroundPrimitiveExecution();
79 if (m_primitiveProcessingSuspended == 1) {
80 I2S1.int_clr.val = 0xFFFFFFFF;
81 I2S1.int_ena.out_eof = 0;
88 VGABaseController::resumeBackgroundPrimitiveExecution();
89 if (m_primitiveProcessingSuspended == 0) {
90 if (m_isr_handle ==
nullptr)
91 esp_intr_alloc(ETS_I2S1_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, VSyncInterrupt,
this, &m_isr_handle);
92 I2S1.int_clr.val = 0xFFFFFFFF;
93 I2S1.int_ena.out_eof = 1;
98 void VGAController::allocateViewPort()
100 VGABaseController::allocateViewPort(MALLOC_CAP_DMA, m_viewPortWidth);
104 void VGAController::setResolution(VGATimings
const& timings,
int viewPortWidth,
int viewPortHeight,
bool doubleBuffered)
106 VGABaseController::setResolution(timings, viewPortWidth, viewPortHeight, doubleBuffered);
109 for (
int i = 0; i < m_viewPortHeight; ++i)
110 fill(m_viewPort[i], 0, m_viewPortWidth, 0, 0, 0,
false,
false);
113 m_maxVSyncISRTime = ceil(1000000.0 / m_timings.frequency * m_timings.scanCount * m_HLineSize * (m_timings.VSyncPulse + m_timings.VBackPorch + m_timings.VFrontPorch + m_viewPortRow));
120 void VGAController::onSetupDMABuffer(lldesc_t
volatile * buffer,
bool isStartOfVertFrontPorch,
int scan,
bool isVisible,
int visibleRow)
123 if (isStartOfVertFrontPorch)
128 void IRAM_ATTR VGAController::VSyncInterrupt(
void * arg)
130 if (I2S1.int_st.out_eof) {
131 auto VGACtrl = (VGAController*)arg;
132 int64_t startTime = VGACtrl->backgroundPrimitiveTimeoutEnabled() ? esp_timer_get_time() : 0;
133 Rect updateRect = Rect(SHRT_MAX, SHRT_MAX, SHRT_MIN, SHRT_MIN);
136 if (VGACtrl->getPrimitiveISR(&prim) ==
false)
139 VGACtrl->execPrimitive(prim, updateRect,
true);
141 if (VGACtrl->m_primitiveProcessingSuspended)
144 }
while (!VGACtrl->backgroundPrimitiveTimeoutEnabled() || (startTime + VGACtrl->m_maxVSyncISRTime > esp_timer_get_time()));
145 VGACtrl->showSprites(updateRect);
147 I2S1.int_clr.val = I2S1.int_st.val;
151 void IRAM_ATTR VGAController::setPixelAt(PixelDesc
const & pixelDesc, Rect & updateRect)
153 genericSetPixelAt(pixelDesc, updateRect,
154 [&] (RGB888
const & color) {
return preparePixel(color); },
155 [&] (
int X,
int Y, uint8_t pattern) { VGA_PIXEL(
X,
Y) = pattern; }
162 void IRAM_ATTR VGAController::absDrawLine(
int X1,
int Y1,
int X2,
int Y2, RGB888 color)
164 genericAbsDrawLine(
X1,
Y1,
X2,
Y2, color,
165 [&] (RGB888
const & color) {
return preparePixel(color); },
166 [&] (
int Y,
int X1,
int X2, uint8_t pattern) { rawFillRow(
Y,
X1,
X2, pattern); },
167 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); },
168 [&] (
int X,
int Y, uint8_t pattern) { VGA_PIXEL(
X,
Y) = pattern; },
169 [&] (
int X,
int Y) { VGA_INVERT_PIXEL(
X,
Y); }
175 void IRAM_ATTR VGAController::rawFillRow(
int y,
int x1,
int x2, RGB888 color)
177 rawFillRow(y, x1, x2, preparePixel(color));
182 void IRAM_ATTR VGAController::rawFillRow(
int y,
int x1,
int x2, uint8_t pattern)
184 auto row = m_viewPort[y];
187 for (; x <= x2 && (x & 3) != 0; ++x) {
188 VGA_PIXELINROW(row, x) = pattern;
192 int sz = (x2 & ~3) - x;
193 memset((
void*)(row + x), pattern, sz);
197 for (; x <= x2; ++x) {
198 VGA_PIXELINROW(row, x) = pattern;
204 void IRAM_ATTR VGAController::rawInvertRow(
int y,
int x1,
int x2)
206 auto row = m_viewPort[y];
207 for (
int x = x1; x <= x2; ++x) {
208 uint8_t * px = (uint8_t*) &VGA_PIXELINROW(row, x);
209 *px = m_HVSync | ~(*px);
216 void IRAM_ATTR VGAController::swapRows(
int yA,
int yB,
int x1,
int x2)
218 uint8_t * rowA = (uint8_t*) m_viewPort[yA];
219 uint8_t * rowB = (uint8_t*) m_viewPort[yB];
222 for (; x <= x2 && (x & 3) != 0; ++x)
223 tswap(VGA_PIXELINROW(rowA, x), VGA_PIXELINROW(rowB, x));
225 uint32_t * a = (uint32_t*)(rowA + x);
226 uint32_t * b = (uint32_t*)(rowB + x);
227 for (
int right = (x2 & ~3); x < right; x += 4)
230 for (x = (x2 & ~3); x <= x2; ++x)
231 tswap(VGA_PIXELINROW(rowA, x), VGA_PIXELINROW(rowB, x));
235 void IRAM_ATTR VGAController::drawEllipse(Size
const & size, Rect & updateRect)
237 genericDrawEllipse(size, updateRect,
238 [&] (RGB888
const & color) {
return preparePixel(color); },
239 [&] (
int X,
int Y, uint8_t pattern) { VGA_PIXEL(
X,
Y) = pattern; }
244 void IRAM_ATTR VGAController::clear(Rect & updateRect)
246 hideSprites(updateRect);
247 uint8_t pattern = preparePixel(getActualBrushColor());
248 for (
int y = 0; y < m_viewPortHeight; ++y)
249 memset((uint8_t*) m_viewPort[y], pattern, m_viewPortWidth);
256 void IRAM_ATTR VGAController::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 pattern) { rawFillRow(y, x1, x2, pattern); }
266 int viewPortBuffersPerLine = 0;
268 switch (m_timings.HStartingBlock) {
271 viewPortBuffersPerLine = (m_viewPortCol + m_viewPortWidth) < m_timings.HVisibleArea ? 3 : 2;
275 viewPortBuffersPerLine = 3;
279 viewPortBuffersPerLine = 3;
283 viewPortBuffersPerLine = m_viewPortCol > 0 ? 3 : 2;
284 linePos = m_viewPortCol > 0 ? 1 : 0;
287 const int Y1 = paintState().scrollingRegion.Y1;
288 const int Y2 = paintState().scrollingRegion.Y2;
289 for (
int i =
Y1, idx =
Y1 * m_timings.scanCount; i <=
Y2; ++i)
290 for (
int scan = 0; scan < m_timings.scanCount; ++scan, ++idx)
291 setDMABufferView(m_viewPortRow * m_timings.scanCount + idx * viewPortBuffersPerLine + linePos, i, scan, m_viewPort,
false);
300 void IRAM_ATTR VGAController::HScroll(
int scroll, Rect & updateRect)
302 hideSprites(updateRect);
303 uint8_t pattern8 = preparePixel(getActualBrushColor());
304 uint16_t pattern16 = pattern8 << 8 | pattern8;
305 uint32_t pattern32 = pattern16 << 16 | pattern16;
307 int Y1 = paintState().scrollingRegion.Y1;
308 int Y2 = paintState().scrollingRegion.Y2;
309 int X1 = paintState().scrollingRegion.X1;
310 int X2 = paintState().scrollingRegion.X2;
313 int width32 =
width >> 2;
314 bool HScrolllingRegionAligned = ((
X1 & 3) == 0 && (
width & 3) == 0);
318 for (
int y =
Y1; y <=
Y2; ++y) {
319 if (HScrolllingRegionAligned) {
321 uint8_t * row = (uint8_t*) (m_viewPort[y] +
X1);
322 for (
int s = -scroll; s > 0;) {
326 int sz = (s & ~3) >> 2;
327 for (
int i = 0; i < width32 - sz; ++i, w += 4)
328 *((uint32_t*)w) = *((uint32_t*)w + sz);
329 for (
int i = tmax(0, width32 - sz); i < width32; ++i, w += 4)
330 *((uint32_t*)w) = pattern32;
332 }
else if ((s & 3) == 3) {
335 for (
int i = 1; i < width32; ++i, b += 4) {
342 b[1] = b[0] = b[3] = pattern8;
346 uint16_t * w = (uint16_t*) row;
347 for (
int i = 1; i < width32; ++i, w += 2) {
357 for (
int i = 1; i < width32; ++i, w += 4) {
358 *((uint32_t*)w) = *((uint32_t*)w) >> 8 | *((uint32_t*)w) << 24;
361 *((uint32_t*)w) = *((uint32_t*)w) >> 8 | *((uint32_t*)w) << 24;
368 uint8_t * row = (uint8_t*) m_viewPort[y];
369 for (
int x =
X1; x <=
X2 + scroll; ++x)
370 VGA_PIXELINROW(row, x) = VGA_PIXELINROW(row, x - scroll);
372 for (
int x =
X2 + 1 + scroll; x <=
X2; ++x)
373 VGA_PIXELINROW(row, x) = pattern8;
376 }
else if (scroll > 0) {
378 for (
int y =
Y1; y <=
Y2; ++y) {
379 if (HScrolllingRegionAligned) {
381 uint8_t * row = (uint8_t*) (m_viewPort[y] +
X1);
382 for (
int s = scroll; s > 0;) {
385 int sz = (s & ~3) >> 2;
386 uint8_t * w = row +
width - 4;
387 for (
int i = 0; i < width32 - sz; ++i, w -= 4)
388 *((uint32_t*)w) = *((uint32_t*)w - sz);
389 for (
int i = tmax(0, width32 - sz); i < width32; ++i, w -= 4)
390 *((uint32_t*)w) = pattern32;
392 }
else if ((s & 3) == 3) {
394 uint8_t * b = row +
width - 4;
395 for (
int i = 1; i < width32; ++i, b -= 4) {
402 b[0] = b[2] = b[3] = pattern8;
406 uint16_t * w = (uint16_t*) (row +
width - 4);
407 for (
int i = 1; i < width32; ++i, w -= 2) {
416 uint8_t * w = row +
width - 4;
417 for (
int i = 1; i < width32; ++i, w -= 4) {
418 *((uint32_t*)w) = *((uint32_t*)w) << 8 | *((uint32_t*)w) >> 24;
421 *((uint32_t*)w) = *((uint32_t*)w) << 8 | *((uint32_t*)w) >> 24;
428 uint8_t * row = (uint8_t*) m_viewPort[y];
429 for (
int x =
X2 - scroll; x >=
X1; --x)
430 VGA_PIXELINROW(row, x + scroll) = VGA_PIXELINROW(row, x);
432 for (
int x =
X1; x <
X1 + scroll; ++x)
433 VGA_PIXELINROW(row, x) = pattern8;
441 void IRAM_ATTR VGAController::drawGlyph(Glyph
const & glyph, GlyphOptions glyphOptions, RGB888 penColor, RGB888 brushColor, Rect & updateRect)
443 genericDrawGlyph(glyph, glyphOptions, penColor, brushColor, updateRect,
444 [&] (RGB888
const & color) {
return preparePixel(color); },
445 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
446 [&] (uint8_t * row,
int x, uint8_t pattern) { VGA_PIXELINROW(row, x) = pattern; }
451 void IRAM_ATTR VGAController::invertRect(Rect
const & rect, Rect & updateRect)
453 genericInvertRect(rect, updateRect,
454 [&] (
int Y,
int X1,
int X2) { rawInvertRow(
Y,
X1,
X2); }
459 void IRAM_ATTR VGAController::swapFGBG(Rect
const & rect, Rect & updateRect)
461 genericSwapFGBG(rect, updateRect,
462 [&] (RGB888
const & color) {
return preparePixel(color); },
463 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
464 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
465 [&] (uint8_t * row,
int x, uint8_t pattern) { VGA_PIXELINROW(row, x) = pattern; }
472 void IRAM_ATTR VGAController::copyRect(Rect
const & source, Rect & updateRect)
474 genericCopyRect(source, updateRect,
475 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
476 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
477 [&] (uint8_t * row,
int x, uint8_t pattern) { VGA_PIXELINROW(row, x) = pattern; }
485 for (
int y = rect.Y1; y <= rect.Y2; ++y) {
486 uint8_t * row = (uint8_t*) m_viewPort[y];
487 for (
int x = rect.X1; x <= rect.X2; ++x, ++destBuf) {
488 uint8_t rawpix = VGA_PIXELINROW(row, x);
489 *destBuf = RGB888((rawpix & 3) * 85, ((rawpix >> 2) & 3) * 85, ((rawpix >> 4) & 3) * 85);
498 uint8_t * dbuf = (uint8_t*) destBuf;
499 for (
int y = rect.Y1; y <= rect.Y2; ++y) {
500 uint8_t * row = (uint8_t*) m_viewPort[y];
501 for (
int x = rect.X1; x <= rect.X2; ++x, ++dbuf)
502 *dbuf = VGA_PIXELINROW(row, x) & ~VGA_SYNC_MASK;
510 uint8_t * sbuf = (uint8_t*) srcBuf;
511 for (
int y = rect.Y1; y <= rect.Y2; ++y) {
512 uint8_t * row = (uint8_t*) m_viewPort[y];
513 for (
int x = rect.X1; x <= rect.X2; ++x, ++sbuf)
514 VGA_PIXELINROW(row, x) = *sbuf | m_HVSync;
519 void IRAM_ATTR VGAController::rawDrawBitmap_Native(
int destX,
int destY,
Bitmap const * bitmap,
int X1,
int Y1,
int XCount,
int YCount)
521 genericRawDrawBitmap_Native(destX, destY, (uint8_t*) bitmap->data, bitmap->width,
X1,
Y1, XCount, YCount,
522 [&] (
int y) { return (uint8_t*) m_viewPort[y]; },
523 [&] (uint8_t * row,
int x, uint8_t src) { VGA_PIXELINROW(row, x) = m_HVSync | src; }
528 void IRAM_ATTR VGAController::rawDrawBitmap_Mask(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
530 auto foregroundPattern = preparePixel(bitmap->foregroundColor);
531 genericRawDrawBitmap_Mask(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
532 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
533 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
534 [&] (uint8_t * row,
int x) { VGA_PIXELINROW(row, x) = foregroundPattern; }
539 void IRAM_ATTR VGAController::rawDrawBitmap_RGBA2222(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
541 genericRawDrawBitmap_RGBA2222(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
542 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
543 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
544 [&] (uint8_t * row,
int x, uint8_t src) { VGA_PIXELINROW(row, x) = m_HVSync | (src & 0x3f); }
549 void IRAM_ATTR VGAController::rawDrawBitmap_RGBA8888(
int destX,
int destY, Bitmap
const * bitmap,
void * saveBackground,
int X1,
int Y1,
int XCount,
int YCount)
551 genericRawDrawBitmap_RGBA8888(destX, destY, bitmap, (uint8_t*)saveBackground,
X1,
Y1, XCount, YCount,
552 [&] (
int y) {
return (uint8_t*) m_viewPort[y]; },
553 [&] (uint8_t * row,
int x) {
return VGA_PIXELINROW(row, x); },
554 [&] (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); }
This file contains fabgl::GPIOStream definition.
This file contains fabgl::VGAController definition.
This file contains some utility classes and functions.
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.
Represents a 6 bit RGB color.