FabGL
ESP32 Display Controller and Graphics Library
cvbsbasecontroller.cpp
1/*
2 Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
3 Copyright (c) 2019-2022 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 "fabutils.h"
37#include "devdrivers/cvbsgenerator.h"
39
40
41#pragma GCC optimize ("O2")
42
43
44namespace fabgl {
45
46
47CVBSBaseController::CVBSBaseController()
48 : m_horizontalRate(1)
49{
50}
51
52
53void CVBSBaseController::init()
54{
55 CurrentVideoMode::set(VideoMode::CVBS);
56 m_primitiveProcessingSuspended = 1; // >0 suspended
57 m_viewPort = nullptr;
58 m_viewPortMemoryPool = nullptr;
59}
60
61
62void CVBSBaseController::begin(gpio_num_t videoGPIO)
63{
64 init();
65 m_CVBSGenerator.setVideoGPIO(videoGPIO);
66}
67
68
69void CVBSBaseController::begin()
70{
71 begin(GPIO_NUM_25);
72}
73
74
75void CVBSBaseController::end()
76{
77 m_CVBSGenerator.stop();
78}
79
80
81void CVBSBaseController::freeViewPort()
82{
83 if (m_viewPortMemoryPool) {
84 for (auto poolPtr = m_viewPortMemoryPool; *poolPtr; ++poolPtr)
85 heap_caps_free((void*) *poolPtr);
86 heap_caps_free(m_viewPortMemoryPool);
87 m_viewPortMemoryPool = nullptr;
88 }
89 if (m_viewPort) {
90 heap_caps_free(m_viewPort);
91 m_viewPort = nullptr;
92 }
93 if (isDoubleBuffered())
94 heap_caps_free(m_viewPortVisible);
95 m_viewPortVisible = nullptr;
96}
97
98
99// Warning: After call to suspendBackgroundPrimitiveExecution() adding primitives may cause a deadlock.
100// To avoid this a call to "processPrimitives()" should be performed very often.
101// Can be nested
102void CVBSBaseController::suspendBackgroundPrimitiveExecution()
103{
104 ++m_primitiveProcessingSuspended;
105}
106
107
108// Resume after suspendBackgroundPrimitiveExecution()
109// Can be nested
110void CVBSBaseController::resumeBackgroundPrimitiveExecution()
111{
112 m_primitiveProcessingSuspended = tmax(0, m_primitiveProcessingSuspended - 1);
113}
114
115
116void CVBSBaseController::setResolution(char const * modeline, int viewPortWidth, int viewPortHeight, bool doubleBuffered)
117{
118 auto params = CVBSGenerator::getParamsFromDesc(modeline);
119 if (params)
120 setResolution(params, viewPortWidth, viewPortHeight);
121}
122
123
124void CVBSBaseController::setResolution(CVBSParams const * params, int viewPortWidth, int viewPortHeight, bool doubleBuffered)
125{
126 // just in case setResolution() was called before
127 end();
128
129 m_CVBSGenerator.setup(params);
130
131 m_viewPortWidth = viewPortWidth < 0 ? m_CVBSGenerator.visibleSamples() : viewPortWidth;
132 m_viewPortHeight = viewPortHeight < 0 ? m_CVBSGenerator.visibleLines() * m_CVBSGenerator.params()->interlaceFactor : viewPortHeight;
133
134 // reduce viewport if more than one sample per color is required
135 m_viewPortWidth /= m_horizontalRate;
136
137 // inform base class about screen size
138 setScreenSize(m_viewPortWidth, m_viewPortHeight);
139
140 setDoubleBuffered(doubleBuffered);
141
142 // adjust view port size if necessary
143 checkViewPortSize();
144
145 // allocate the viewport
146 allocateViewPort();
147
148 // adjust again view port size if necessary
149 checkViewPortSize();
150
151 resetPaintState();
152}
153
154
155void CVBSBaseController::run()
156{
157 m_CVBSGenerator.run();
158}
159
160
161// this method may adjust m_viewPortHeight to the actual number of allocated rows.
162// to reduce memory allocation overhead try to allocate the minimum number of blocks.
163void CVBSBaseController::allocateViewPort(uint32_t allocCaps, int rowlen)
164{
165 int linesCount[FABGLIB_VIEWPORT_MEMORY_POOL_COUNT]; // where store number of lines for each pool
166 int poolsCount = 0; // number of allocated pools
167 int remainingLines = m_viewPortHeight;
168 m_viewPortHeight = 0; // m_viewPortHeight needs to be recalculated
169
170 if (isDoubleBuffered())
171 remainingLines *= 2;
172
173 // allocate pools
174 m_viewPortMemoryPool = (uint8_t * *) heap_caps_malloc(sizeof(uint8_t*) * (FABGLIB_VIEWPORT_MEMORY_POOL_COUNT + 1), MALLOC_CAP_32BIT);
175 while (remainingLines > 0 && poolsCount < FABGLIB_VIEWPORT_MEMORY_POOL_COUNT) {
176 int largestBlock = heap_caps_get_largest_free_block(allocCaps);
177 if (largestBlock < FABGLIB_MINFREELARGESTBLOCK)
178 break;
179 linesCount[poolsCount] = tmax(1, tmin(remainingLines, (largestBlock - FABGLIB_MINFREELARGESTBLOCK) / rowlen));
180 m_viewPortMemoryPool[poolsCount] = (uint8_t*) heap_caps_malloc(linesCount[poolsCount] * rowlen, allocCaps);
181 if (m_viewPortMemoryPool[poolsCount] == nullptr)
182 break;
183 remainingLines -= linesCount[poolsCount];
184 m_viewPortHeight += linesCount[poolsCount];
185 ++poolsCount;
186 }
187 m_viewPortMemoryPool[poolsCount] = nullptr;
188
189 // fill m_viewPort[] with line pointers
190 if (isDoubleBuffered()) {
191 m_viewPortHeight /= 2;
192 m_viewPortVisible = (volatile uint8_t * *) heap_caps_malloc(sizeof(uint8_t*) * m_viewPortHeight, MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL);
193 }
194 m_viewPort = (volatile uint8_t * *) heap_caps_malloc(sizeof(uint8_t*) * m_viewPortHeight, MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL);
195 if (!isDoubleBuffered())
196 m_viewPortVisible = m_viewPort;
197 for (int p = 0, l = 0; p < poolsCount; ++p) {
198 uint8_t * pool = m_viewPortMemoryPool[p];
199 for (int i = 0; i < linesCount[p]; ++i) {
200 if (l + i < m_viewPortHeight)
201 m_viewPort[l + i] = pool;
202 else
203 m_viewPortVisible[l + i - m_viewPortHeight] = pool; // set only when double buffered is enabled
204 pool += rowlen;
205 }
206 l += linesCount[p];
207 }
208}
209
210
211void IRAM_ATTR CVBSBaseController::swapBuffers()
212{
213 tswap(m_viewPort, m_viewPortVisible);
214}
215
216
217
218
219} // end of namespace
220
221
This file contains fabgl::CVBSBaseController definition.
#define FABGLIB_VIEWPORT_MEMORY_POOL_COUNT
Definition: fabglconf.h:126
#define FABGLIB_MINFREELARGESTBLOCK
Definition: fabglconf.h:130
This file contains some utility classes and functions.