FabGL
ESP32 Display Controller and Graphics Library
vgadirectcontroller.cpp
1 /*
2  Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
3  Copyright (c) 2019-2021 Fabrizio Di Vittorio.
4  All rights reserved.
5 
6 
7 * Please contact fdivitto2013@gmail.com if you need a commercial license.
8 
9 
10 * This library and related software is available under GPL v3.
11 
12  FabGL is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  FabGL is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with FabGL. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 
27 
28 #include <alloca.h>
29 #include <stdarg.h>
30 #include <math.h>
31 #include <string.h>
32 
33 #include "freertos/FreeRTOS.h"
34 #include "freertos/task.h"
35 
36 #include "soc/i2s_struct.h"
37 #include "soc/i2s_reg.h"
38 #include "driver/periph_ctrl.h"
39 #include "soc/rtc.h"
40 #include "esp_spi_flash.h"
41 #include "esp_heap_caps.h"
42 
43 #include "fabutils.h"
44 #include "vgadirectcontroller.h"
45 #include "devdrivers/swgenerator.h"
46 
47 
48 
49 #pragma GCC optimize ("O2")
50 
51 
52 namespace fabgl {
53 
54 
55 
56 
57 
58 /*************************************************************************************/
59 /* VGADirectController definitions */
60 
61 
62 VGADirectController * VGADirectController::s_instance = nullptr;
63 volatile int VGADirectController::s_scanLine;
64 lldesc_t volatile * VGADirectController::s_frameResetDesc;
65 bool VGADirectController::s_VSync;
66 lldesc_t volatile * * VGADirectController::s_DMALines = nullptr;
67 
68 
69 
71  : m_linesCount(2),
72  m_lines(nullptr),
73  m_drawScanlineCallback(nullptr),
74  m_autoRun(autoRun)
75 {
76  s_instance = this;
77 }
78 
79 
80 void VGADirectController::init()
81 {
82  VGABaseController::init();
83  m_doubleBufferOverDMA = false;
84 }
85 
86 
87 void VGADirectController::allocateViewPort()
88 {
89  m_lines = (uint8_t**) heap_caps_malloc(sizeof(uint8_t*) * m_linesCount, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
90  m_lines[0] = (uint8_t*) heap_caps_malloc(m_viewPortWidth * m_linesCount, MALLOC_CAP_DMA);
91  for (int i = 1; i < m_linesCount; ++i)
92  m_lines[i] = m_lines[0] + i * m_viewPortWidth;
93  s_DMALines = new lldesc_t volatile *[m_viewPortHeight];
94 }
95 
96 
97 void VGADirectController::freeViewPort()
98 {
99  VGABaseController::freeViewPort();
100 
101  heap_caps_free((void*)m_lines[0]);
102  heap_caps_free((void*)m_lines);
103  m_lines = nullptr;
104  delete s_DMALines;
105 }
106 
107 
108 void VGADirectController::setResolution(VGATimings const& timings, int viewPortWidth, int viewPortHeight, bool doubleBuffered)
109 {
110  // fail if setDrawScanlineCallback() has not been called
111  if (!m_drawScanlineCallback)
112  return;
113 
114  VGABaseController::setResolution(timings, viewPortWidth, viewPortHeight, doubleBuffered);
115 
116  if (m_autoRun)
117  run();
118 }
119 
120 
122 {
123  // must be started before interrupt alloc
124  startGPIOStream();
125 
126  s_scanLine = 0;
127 
128  // ESP_INTR_FLAG_LEVEL1: should be less than PS2Controller interrupt level, necessary when running on the same core
129  if (m_isr_handle == nullptr) {
130  CoreUsage::setBusiestCore(FABGLIB_VIDEO_CPUINTENSIVE_TASKS_CORE);
131  esp_intr_alloc_pinnedToCore(ETS_I2S1_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM, ISRHandler, this, &m_isr_handle, FABGLIB_VIDEO_CPUINTENSIVE_TASKS_CORE);
132  I2S1.int_clr.val = 0xFFFFFFFF;
133  I2S1.int_ena.out_eof = 1;
134  }
135 }
136 
137 
138 void VGADirectController::onSetupDMABuffer(lldesc_t volatile * buffer, bool isStartOfVertFrontPorch, int scan, bool isVisible, int visibleRow)
139 {
140  if (isVisible) {
141  s_DMALines[visibleRow] = buffer;
142 
143  buffer->buf = (uint8_t *) m_lines[visibleRow % m_linesCount];
144 
145  // generate interrupt every half m_linesCount
146  if ((scan == 0 && (visibleRow % (m_linesCount / 2)) == 0)) {
147  if (visibleRow == 0)
148  s_frameResetDesc = buffer;
149  buffer->eof = 1;
150  }
151  }
152 }
153 
154 
155 void VGADirectController::setScanlineBuffer(int scanline, uint8_t volatile * lineBuffer)
156 {
157  s_DMALines[scanline]->buf = lineBuffer;
158 }
159 
160 
161 uint8_t volatile * VGADirectController::getScanlineBuffer(int scanline)
162 {
163  return s_DMALines[scanline]->buf;
164 }
165 
166 
167 uint8_t volatile * VGADirectController::getDefaultScanlineBuffer(int scanline)
168 {
169  return m_lines[scanline % m_linesCount];
170 }
171 
172 
173 void VGADirectController::setPixelAt(PixelDesc const & pixelDesc, Rect & updateRect)
174 {
175 }
176 
177 
178 void VGADirectController::absDrawLine(int X1, int Y1, int X2, int Y2, RGB888 color)
179 {
180 }
181 
182 
183 void VGADirectController::rawFillRow(int y, int x1, int x2, RGB888 color)
184 {
185 }
186 
187 
188 void VGADirectController::rawFillRow(int y, int x1, int x2, uint8_t colorIndex)
189 {
190 }
191 
192 
193 void VGADirectController::rawInvertRow(int y, int x1, int x2)
194 {
195 }
196 
197 
198 void VGADirectController::rawCopyRow(int x1, int x2, int srcY, int dstY)
199 {
200 }
201 
202 
203 void VGADirectController::swapRows(int yA, int yB, int x1, int x2)
204 {
205 }
206 
207 
208 void VGADirectController::drawEllipse(Size const & size, Rect & updateRect)
209 {
210 }
211 
212 
213 void VGADirectController::clear(Rect & updateRect)
214 {
215 }
216 
217 
218 void VGADirectController::VScroll(int scroll, Rect & updateRect)
219 {
220 }
221 
222 
223 void VGADirectController::HScroll(int scroll, Rect & updateRect)
224 {
225 }
226 
227 
228 void VGADirectController::drawGlyph(Glyph const & glyph, GlyphOptions glyphOptions, RGB888 penColor, RGB888 brushColor, Rect & updateRect)
229 {
230 }
231 
232 
233 void VGADirectController::invertRect(Rect const & rect, Rect & updateRect)
234 {
235 }
236 
237 
238 void VGADirectController::swapFGBG(Rect const & rect, Rect & updateRect)
239 {
240 }
241 
242 
243 void VGADirectController::copyRect(Rect const & source, Rect & updateRect)
244 {
245 }
246 
247 
248 void VGADirectController::readScreen(Rect const & rect, RGB888 * destBuf)
249 {
250 }
251 
252 
253 void VGADirectController::rawDrawBitmap_Native(int destX, int destY, Bitmap const * bitmap, int X1, int Y1, int XCount, int YCount)
254 {
255 }
256 
257 
258 void VGADirectController::rawDrawBitmap_Mask(int destX, int destY, Bitmap const * bitmap, void * saveBackground, int X1, int Y1, int XCount, int YCount)
259 {
260 }
261 
262 
263 void VGADirectController::rawDrawBitmap_RGBA2222(int destX, int destY, Bitmap const * bitmap, void * saveBackground, int X1, int Y1, int XCount, int YCount)
264 {
265 }
266 
267 
268 void VGADirectController::rawDrawBitmap_RGBA8888(int destX, int destY, Bitmap const * bitmap, void * saveBackground, int X1, int Y1, int XCount, int YCount)
269 {
270 }
271 
272 
273 void IRAM_ATTR VGADirectController::ISRHandler(void * arg)
274 {
275  #if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK
276  auto s1 = getCycleCount();
277  #endif
278 
279  if (I2S1.int_st.out_eof) {
280 
281  auto ctrl = (VGADirectController *) arg;
282 
283  auto viewPortHeight = ctrl->m_viewPortHeight;
284 
285  auto desc = (volatile lldesc_t*) I2S1.out_eof_des_addr;
286 
287  if (desc == s_frameResetDesc) {
288  s_scanLine = 0;
289  s_VSync = false;
290  }
291 
292  int linesCount = ctrl->m_linesCount;
293  int scanLine = (s_scanLine + linesCount / 2) % viewPortHeight;
294 
295  const auto lineIndex = scanLine & (linesCount - 1);
296 
297  ctrl->m_drawScanlineCallback(ctrl->m_drawScanlineArg, (uint8_t*)(ctrl->m_lines[lineIndex]), scanLine);
298 
299  s_scanLine += linesCount / 2;
300 
301  if (s_scanLine >= viewPortHeight)
302  s_VSync = true;
303 
304  }
305 
306  #if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK
307  s_vgapalctrlcycles += getCycleCount() - s1;
308  #endif
309 
310  I2S1.int_clr.val = I2S1.int_st.val;
311 }
312 
313 
314 
315 } // end of namespace
316 
int16_t X2
Definition: fabutils.h:180
uint8_t volatile * getDefaultScanlineBuffer(int scanline)
Gets default scanline buffer.
void setScanlineBuffer(int scanline, uint8_t volatile *lineBuffer)
Sets a scanline buffer.
int16_t Y2
Definition: fabutils.h:181
uint8_t volatile * getScanlineBuffer(int scanline)
Gets current scanline buffer.
int16_t Y1
Definition: fabutils.h:179
This file contains fabgl::GPIOStream definition.
int16_t X1
Definition: fabutils.h:178
#define FABGLIB_VIDEO_CPUINTENSIVE_TASKS_CORE
Definition: fabglconf.h:138
This file contains some utility classes and functions.
Definition: canvas.cpp:36
Represents a rectangle.
Definition: fabutils.h:226
This file contains fabgl::VGADirectController definition.
void run()
Begins to call the callback function and to display video frames.
VGADirectController(bool autoRun=true)
Initializes a new instance of VGADirectController.