11#include " controllers/rendering/controllerrenderingengine.h"
2+ #include < QApplication>
23
34#include < QOffscreenSurface>
45#include < QOpenGLContext>
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
373444bool ControllerRenderingEngine::stop () {
0 commit comments