Skip to content

Commit adc1bf6

Browse files
committed
feat: add OpenGL ES for controller screen rendering
1 parent ff87e63 commit adc1bf6

File tree

1 file changed

+93
-22
lines changed

1 file changed

+93
-22
lines changed

src/controllers/rendering/controllerrenderingengine.cpp

Lines changed: 93 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "controllers/rendering/controllerrenderingengine.h"
2+
#include <QApplication>
23

34
#include <QOffscreenSurface>
45
#include <QOpenGLContext>
@@ -10,6 +11,8 @@
1011
#include <QQuickRenderTarget>
1112
#include <QQuickWindow>
1213
#include <QThread>
14+
#include <QTimer>
15+
#include <QtEndian>
1316

1417
#include "controllers/controller.h"
1518
#include "controllers/controllerenginethreadcontrol.h"
@@ -49,16 +52,15 @@ ControllerRenderingEngine::ControllerRenderingEngine(
4952
switch (m_screenInfo.pixelFormat) {
5053
case QImage::Format_RGB16:
5154
m_GLDataFormat = GL_RGB;
55+
#ifndef QT_OPENGL_ES_2
5256
if (m_screenInfo.reversedColor) {
53-
#ifdef QT_OPENGL_ES_2
54-
m_isValid = false;
55-
kLogger.critical() << "Reversed RGB16 format is not supported in OpenGL ES";
56-
#else
5757
m_GLDataType = GL_UNSIGNED_SHORT_5_6_5_REV;
58-
#endif
5958
} else {
59+
#endif
6060
m_GLDataType = GL_UNSIGNED_SHORT_5_6_5;
61+
#ifndef QT_OPENGL_ES_2
6162
}
63+
#endif
6264
break;
6365
case QImage::Format_RGB888:
6466
if (m_screenInfo.reversedColor) {
@@ -213,6 +215,7 @@ void ControllerRenderingEngine::setup(std::shared_ptr<QQmlEngine> qmlEngine) {
213215
}
214216

215217
m_renderControl = std::make_unique<QQuickRenderControl>(this);
218+
m_renderControl->setSamples(format.samples());
216219
m_quickWindow = std::make_unique<QQuickWindow>(m_renderControl.get());
217220

218221
if (!qmlEngine->incubationController()) {
@@ -261,10 +264,10 @@ void ControllerRenderingEngine::renderFrame() {
261264

262265
VERIFY_OR_TERMINATE(m_offscreenSurface->isValid(), "OffscreenSurface isn't valid anymore.");
263266
VERIFY_OR_TERMINATE(m_context->isValid(), "GLContext isn't valid anymore.");
264-
VERIFY_OR_TERMINATE(m_context->makeCurrent(m_offscreenSurface.get()),
265-
"Couldn't make the GLContext current to the OffscreenSurface.");
266267

267268
if (!m_fbo) {
269+
VERIFY_OR_TERMINATE(m_context->makeCurrent(m_offscreenSurface.get()),
270+
"Couldn't make the GLContext current to the OffscreenSurface.");
268271
ScopedTimer t(QStringLiteral("ControllerRenderingEngine::renderFrame::initFBO"));
269272
VERIFY_OR_TERMINATE(
270273
QOpenGLFramebufferObject::hasOpenGLFramebufferObjects(),
@@ -288,18 +291,24 @@ void ControllerRenderingEngine::renderFrame() {
288291
m_screenInfo.size));
289292

290293
m_quickWindow->setGeometry(0, 0, m_screenInfo.size.width(), m_screenInfo.size.height());
294+
295+
m_context->doneCurrent();
291296
}
292297

293298
m_nextFrameStart = Clock::now();
294299

295-
m_renderControl->beginFrame();
296-
297300
if (m_pEngineThreadControl) {
298-
m_pEngineThreadControl->pause();
301+
if (!m_pEngineThreadControl->pause()) {
302+
kLogger.debug() << "Couldn't pause the GUI thread. Rescheduling frame rendering";
303+
QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
304+
return;
305+
}
299306
}
300307

301308
m_renderControl->polishItems();
302309

310+
m_renderControl->beginFrame();
311+
303312
{
304313
ScopedTimer t(QStringLiteral("ControllerRenderingEngine::renderFrame::sync"));
305314
VERIFY_OR_DEBUG_ASSERT(m_renderControl->sync()) {
@@ -310,27 +319,38 @@ void ControllerRenderingEngine::renderFrame() {
310319
if (m_pEngineThreadControl) {
311320
m_pEngineThreadControl->resume();
312321
}
322+
323+
VERIFY_OR_TERMINATE(m_offscreenSurface->isValid(), "OffscreenSurface isn't valid anymore.");
324+
VERIFY_OR_TERMINATE(m_context->makeCurrent(m_offscreenSurface.get()),
325+
"Couldn't make the GLContext current to the OffscreenSurface.");
326+
327+
#ifdef QT_OPENGL_ES_2
328+
// OpenGL ES doesn't support extended format and type when reading pixel and
329+
// only support GL_RGBA/GL_UNSIGNED_BYTE On this platform, we fallback to Qt
330+
// for the pixel transformation, using QImage conversion capabilities
331+
QImage fboImage(m_screenInfo.size, QImage::Format_RGBA8888);
332+
#else
313333
QImage fboImage(m_screenInfo.size, m_screenInfo.pixelFormat);
334+
#endif
314335

315336
VERIFY_OR_DEBUG_ASSERT(m_fbo->bind()) {
316337
kLogger.warning() << "Couldn't bind the FBO.";
317338
}
318339
GLenum glError;
340+
// Flush any remaining GL errors.
341+
while ((glError = m_context->functions()->glGetError()) != GL_NO_ERROR) {
342+
kLogger.debug() << "Retrieved a previously unhandled GL error: " << glError;
343+
}
344+
#ifndef QT_OPENGL_ES_2
319345
m_context->functions()->glFlush();
320346
glError = m_context->functions()->glGetError();
321-
VERIFY_OR_TERMINATE(glError == GL_NO_ERROR, "GLError: " << glError);
347+
VERIFY_OR_TERMINATE(glError == GL_NO_ERROR, "GLError after glFlush: " << glError);
322348
if (static_cast<std::endian>(m_screenInfo.endian) != std::endian::native) {
323-
#ifdef QT_OPENGL_ES_2
324-
kLogger.critical()
325-
<< "Screen endianness mismatches native endianness, but OpenGL "
326-
"ES does not let us specify a reverse pixel store order. "
327-
"This will likely lead to invalid colors.";
328-
#else
329349
m_context->functions()->glPixelStorei(GL_PACK_SWAP_BYTES, GL_TRUE);
330-
#endif
331350
}
332351
glError = m_context->functions()->glGetError();
333-
VERIFY_OR_TERMINATE(glError == GL_NO_ERROR, "GLError: " << glError);
352+
VERIFY_OR_TERMINATE(glError == GL_NO_ERROR, "GLError after glPixelStorei: " << glError);
353+
#endif
334354

335355
QDateTime timestamp = QDateTime::currentDateTime();
336356
m_renderControl->render();
@@ -346,28 +366,79 @@ void ControllerRenderingEngine::renderFrame() {
346366
0,
347367
m_screenInfo.size.width(),
348368
m_screenInfo.size.height(),
369+
#ifndef QT_OPENGL_ES_2
349370
m_GLDataFormat,
350371
m_GLDataType,
372+
#else
373+
GL_RGBA,
374+
GL_UNSIGNED_BYTE,
375+
#endif
351376
fboImage.bits());
352377
}
353378
glError = m_context->functions()->glGetError();
354-
VERIFY_OR_TERMINATE(glError == GL_NO_ERROR, "GLError: " << glError);
379+
VERIFY_OR_TERMINATE(glError == GL_NO_ERROR, "GLError after glReadPixels: " << glError);
355380
VERIFY_OR_DEBUG_ASSERT(!fboImage.isNull()) {
356381
kLogger.warning() << "Screen frame is null!";
357382
}
358383
VERIFY_OR_DEBUG_ASSERT(m_fbo->release()) {
359384
kLogger.debug() << "Couldn't release the FBO.";
360385
}
361386

387+
m_context->doneCurrent();
388+
389+
#ifdef QT_OPENGL_ES_2
390+
fboImage.convertTo(m_screenInfo.pixelFormat);
391+
392+
// OpenGL ES doesn't support extended reverse format (suffixed with _REV) so
393+
// we use QImage function for this
394+
if (static_cast<std::endian>(m_screenInfo.endian) != std::endian::native) {
395+
fboImage.rgbSwap();
396+
}
397+
398+
// OpenGL ES doesn't support explicit endianness (GL_PACK_SWAP_BYTES) se we
399+
// use Qt helper function to convert the pixel buffer. Only 16 and 32 bit
400+
// pixel format are supported currently.
401+
switch (static_cast<std::endian>(m_screenInfo.endian)) {
402+
case std::endian::big:
403+
switch (m_screenInfo.pixelFormat) {
404+
case QImage::Format_RGB16:
405+
qToBigEndian<quint16>(fboImage.bits(), fboImage.sizeInBytes() / 2, fboImage.bits());
406+
break;
407+
case QImage::Format_RGBA8888:
408+
qToBigEndian<quint32>(fboImage.bits(), fboImage.sizeInBytes() / 4, fboImage.bits());
409+
break;
410+
default:
411+
kLogger.critical()
412+
<< "Screen endianness mismatches native endianness, but OpenGL "
413+
"ES does not let us specify a reverse pixel store order. "
414+
"This will likely lead to invalid colors.";
415+
}
416+
break;
417+
case std::endian::little:
418+
switch (m_screenInfo.pixelFormat) {
419+
case QImage::Format_RGB16:
420+
qToLittleEndian<quint16>(fboImage.bits(), fboImage.sizeInBytes(), fboImage.bits());
421+
break;
422+
case QImage::Format_RGBA8888:
423+
qToLittleEndian<quint32>(fboImage.bits(), fboImage.sizeInBytes(), fboImage.bits());
424+
break;
425+
default:
426+
kLogger.critical()
427+
<< "Screen endianness mismatches native endianness, but OpenGL "
428+
"ES does not let us specify a reverse pixel store order. "
429+
"This will likely lead to invalid colors.";
430+
}
431+
break;
432+
}
433+
#endif
434+
362435
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
363436
fboImage.flip(Qt::Vertical);
364437
#else
365438
fboImage.mirror(false, true);
366439
#endif
367440

368441
emit frameRendered(m_screenInfo, fboImage.copy(), timestamp);
369-
370-
m_context->doneCurrent();
371442
}
372443

373444
bool ControllerRenderingEngine::stop() {

0 commit comments

Comments
 (0)