diff options
author | Fabian Bumberger <fbumberger@rim.com> | 2013-07-08 11:12:47 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-08-08 12:55:48 +0200 |
commit | f5841521a43b3e3c3f60198079f253b2680ae0b8 (patch) | |
tree | 668386f3cca3b40969ae3ac83784763b92776129 | |
parent | 167a4447424de02372d3686bbeccde7234efc42b (diff) |
QNX: Enable rendering on different displays using OpenGL
Change-Id: Ife9c090cff732aba42a5cbc04640721e8fdde69d
Reviewed-by: Bernd Weimer <bweimer@blackberry.com>
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r-- | src/plugins/platforms/qnx/qqnxglcontext.cpp | 154 | ||||
-rw-r--r-- | src/plugins/platforms/qnx/qqnxglcontext.h | 15 | ||||
-rw-r--r-- | src/plugins/platforms/qnx/qqnxscreen.cpp | 12 | ||||
-rw-r--r-- | src/plugins/platforms/qnx/qqnxscreen.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/qnx/qqnxwindow.cpp | 129 | ||||
-rw-r--r-- | src/plugins/platforms/qnx/qqnxwindow.h | 17 |
6 files changed, 180 insertions, 148 deletions
diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp index ed959467ff..448509c69d 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -60,36 +60,10 @@ QT_BEGIN_NAMESPACE EGLDisplay QQnxGLContext::ms_eglDisplay = EGL_NO_DISPLAY; -static EGLenum checkEGLError(const char *msg) -{ - static const char *errmsg[] = - { - "EGL function succeeded", - "EGL is not initialized, or could not be initialized, for the specified display", - "EGL cannot access a requested resource", - "EGL failed to allocate resources for the requested operation", - "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", - "EGLConfig argument does not name a valid EGLConfig", - "EGLContext argument does not name a valid EGLContext", - "EGL current surface of the calling thread is no longer valid", - "EGLDisplay argument does not name a valid EGLDisplay", - "EGL arguments are inconsistent", - "EGLNativePixmapType argument does not refer to a valid native pixmap", - "EGLNativeWindowType argument does not refer to a valid native window", - "EGL one or more argument values are invalid", - "EGLSurface argument does not name a valid surface configured for rendering", - "EGL power management event has occurred", - }; - EGLenum error = eglGetError(); - fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); - return error; -} - QQnxGLContext::QQnxGLContext(QOpenGLContext *glContext) : QPlatformOpenGLContext(), m_glContext(glContext), - m_eglSurface(EGL_NO_SURFACE), - m_newSurfaceRequested(true) // Create a surface the first time makeCurrent() is called + m_currentEglSurface(EGL_NO_SURFACE) { qGLContextDebug() << Q_FUNC_INFO; QSurfaceFormat format = m_glContext->format(); @@ -168,9 +142,31 @@ QQnxGLContext::~QQnxGLContext() // Cleanup EGL context if it exists if (m_eglContext != EGL_NO_CONTEXT) eglDestroyContext(ms_eglDisplay, m_eglContext); +} - // Cleanup EGL surface if it exists - destroySurface(); +EGLenum QQnxGLContext::checkEGLError(const char *msg) +{ + static const char *errmsg[] = + { + "EGL function succeeded", + "EGL is not initialized, or could not be initialized, for the specified display", + "EGL cannot access a requested resource", + "EGL failed to allocate resources for the requested operation", + "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", + "EGLConfig argument does not name a valid EGLConfig", + "EGLContext argument does not name a valid EGLContext", + "EGL current surface of the calling thread is no longer valid", + "EGLDisplay argument does not name a valid EGLDisplay", + "EGL arguments are inconsistent", + "EGLNativePixmapType argument does not refer to a valid native pixmap", + "EGLNativeWindowType argument does not refer to a valid native window", + "EGL one or more argument values are invalid", + "EGLSurface argument does not name a valid surface configured for rendering", + "EGL power management event has occurred", + }; + EGLenum error = eglGetError(); + fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); + return error; } void QQnxGLContext::initialize() @@ -199,12 +195,6 @@ void QQnxGLContext::shutdown() eglTerminate(ms_eglDisplay); } -void QQnxGLContext::requestSurfaceChange() -{ - qGLContextDebug() << Q_FUNC_INFO; - m_newSurfaceRequested.testAndSetRelease(false, true); -} - bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) { qGLContextDebug() << Q_FUNC_INFO; @@ -216,14 +206,18 @@ bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) if (eglResult != EGL_TRUE) qFatal("QQnxGLContext: failed to set EGL API, err=%d", eglGetError()); - if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { - qGLContextDebug() << "New EGL surface requested"; + QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface); + if (!platformWindow) + return false; + + platformWindow->setPlatformOpenGLContext(this); + + if (m_currentEglSurface == EGL_NO_SURFACE || m_currentEglSurface != platformWindow->getSurface()) { + m_currentEglSurface = platformWindow->getSurface(); doneCurrent(); - destroySurface(); - createSurface(surface); } - eglResult = eglMakeCurrent(ms_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); + eglResult = eglMakeCurrent(ms_eglDisplay, m_currentEglSurface, m_currentEglSurface, m_eglContext); if (eglResult != EGL_TRUE) { checkEGLError("eglMakeCurrent"); qFatal("QQNX: failed to set current EGL context, err=%d", eglGetError()); @@ -248,18 +242,12 @@ void QQnxGLContext::doneCurrent() void QQnxGLContext::swapBuffers(QPlatformSurface *surface) { - Q_UNUSED(surface); qGLContextDebug() << Q_FUNC_INFO; + QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface); + if (!platformWindow) + return; - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (eglResult != EGL_TRUE) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // Post EGL surface to window - eglResult = eglSwapBuffers(ms_eglDisplay, m_eglSurface); - if (eglResult != EGL_TRUE) - qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError()); + platformWindow->swapEGLBuffers(); } QFunctionPointer QQnxGLContext::getProcAddress(const QByteArray &procName) @@ -275,6 +263,10 @@ QFunctionPointer QQnxGLContext::getProcAddress(const QByteArray &procName) return static_cast<QFunctionPointer>(eglGetProcAddress(procName.constData())); } +EGLDisplay QQnxGLContext::getEglDisplay() { + return ms_eglDisplay; +} + EGLint *QQnxGLContext::contextAttrs() { qGLContextDebug() << Q_FUNC_INFO; @@ -288,66 +280,4 @@ EGLint *QQnxGLContext::contextAttrs() #endif } -bool QQnxGLContext::isCurrent() const -{ - qGLContextDebug() << Q_FUNC_INFO; - return (eglGetCurrentContext() == m_eglContext); -} - -void QQnxGLContext::createSurface(QPlatformSurface *surface) -{ - qGLContextDebug() << Q_FUNC_INFO; - - // Get a pointer to the corresponding platform window - QQnxWindow *platformWindow = dynamic_cast<QQnxWindow*>(surface); - if (!platformWindow) - qFatal("QQNX: unable to create EGLSurface without a QQnxWindow"); - - // Link the window and context - platformWindow->setPlatformOpenGLContext(this); - - // Fetch the surface size from the window and update - // the window's buffers before we create the EGL surface - const QSize surfaceSize = platformWindow->requestedBufferSize(); - if (!surfaceSize.isValid()) { - qFatal("QQNX: Trying to create 0 size EGL surface. " - "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); - } - platformWindow->setBufferSize(surfaceSize); - - // Post root window, in case it hasn't been posted yet, to make it appear. - platformWindow->screen()->onWindowPost(platformWindow); - - // Obtain the native handle for our window - screen_window_t handle = platformWindow->nativeHandle(); - - const EGLint eglSurfaceAttrs[] = - { - EGL_RENDER_BUFFER, EGL_BACK_BUFFER, - EGL_NONE - }; - - // Create EGL surface - m_eglSurface = eglCreateWindowSurface(ms_eglDisplay, m_eglConfig, (EGLNativeWindowType) handle, eglSurfaceAttrs); - if (m_eglSurface == EGL_NO_SURFACE) { - checkEGLError("eglCreateWindowSurface"); - qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError()); - } -} - -void QQnxGLContext::destroySurface() -{ - qGLContextDebug() << Q_FUNC_INFO; - - // Destroy EGL surface if it exists - if (m_eglSurface != EGL_NO_SURFACE) { - EGLBoolean eglResult = eglDestroySurface(ms_eglDisplay, m_eglSurface); - if (eglResult != EGL_TRUE) { - qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError()); - } - } - - m_eglSurface = EGL_NO_SURFACE; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h index 6a7fca7df2..ff57861498 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.h +++ b/src/plugins/platforms/qnx/qqnxglcontext.h @@ -59,6 +59,8 @@ public: QQnxGLContext(QOpenGLContext *glContext); virtual ~QQnxGLContext(); + static EGLenum checkEGLError(const char *msg); + static void initialize(); static void shutdown(); @@ -71,13 +73,10 @@ public: virtual QSurfaceFormat format() const { return m_windowFormat; } - bool isCurrent() const; - - void createSurface(QPlatformSurface *surface); - void destroySurface(); - + static EGLDisplay getEglDisplay(); + EGLConfig getEglConfig() const { return m_eglConfig;} private: - /** \todo Should this be non-static so we can use additional displays? */ + //Can be static because different displays returne the same handle static EGLDisplay ms_eglDisplay; QSurfaceFormat m_windowFormat; @@ -85,9 +84,7 @@ private: EGLConfig m_eglConfig; EGLContext m_eglContext; - EGLSurface m_eglSurface; - - QAtomicInt m_newSurfaceRequested; + EGLSurface m_currentEglSurface; static EGLint *contextAttrs(); }; diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index 5aa1257f38..7959617443 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -126,7 +126,6 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, m_posted(false), m_keyboardHeight(0), m_nativeOrientation(Qt::PrimaryOrientation), - m_platformContext(0), m_cursor(new QQnxCursor()) { qScreenDebug() << Q_FUNC_INFO; @@ -482,9 +481,14 @@ void QQnxScreen::updateHierarchy() int topZorder; errno = 0; - result = screen_get_window_property_iv(rootWindow()->nativeHandle(), SCREEN_PROPERTY_ZORDER, &topZorder); - if (result != 0) - qFatal("QQnxScreen: failed to query root window z-order, errno=%d", errno); + if (isPrimaryScreen()) { + result = screen_get_window_property_iv(rootWindow()->nativeHandle(), SCREEN_PROPERTY_ZORDER, &topZorder); + if (result != 0) + qFatal("QQnxScreen: failed to query root window z-order, errno=%d", errno); + } else { + topZorder = 0; //We do not need z ordering on the secondary screen, because only one window + //is supported there + } topZorder++; // root window has the lowest z-order in the windowgroup diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h index 6e8c2c6a60..e498d27c14 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.h +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -133,7 +133,6 @@ private: Qt::ScreenOrientation m_nativeOrientation; QRect m_initialGeometry; QRect m_currentGeometry; - QPlatformOpenGLContext *m_platformContext; QList<QQnxWindow *> m_childWindows; QList<screen_window_t> m_overlays; diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 2bd5cfd801..45e565f24f 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -72,13 +72,15 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) m_window(0), m_currentBufferIndex(-1), m_previousBufferIndex(-1), -#if !defined(QT_NO_OPENGL) - m_platformOpenGLContext(0), -#endif m_screen(0), m_parentWindow(0), m_visible(false), m_windowState(Qt::WindowNoState), +#if !defined(QT_NO_OPENGL) + m_platformOpenGLContext(0), + m_newSurfaceRequested(true), + m_eglSurface(EGL_NO_SURFACE), +#endif m_requestedBufferSize(window->geometry().size()) { qWindowDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size(); @@ -86,7 +88,11 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) // Create child QNX window errno = 0; - result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); + if (static_cast<QQnxScreen *>(window->screen()->handle())->isPrimaryScreen()) { + result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); + } else { + result = screen_create_window(&m_window, m_screenContext); + } if (result != 0) qFatal("QQnxWindow: failed to create window, errno=%d", errno); @@ -172,6 +178,11 @@ QQnxWindow::~QQnxWindow() // Cleanup QNX window and its buffers screen_destroy_window(m_window); + +#if !defined(QT_NO_OPENGL) + // Cleanup EGL surface if it exists + destroyEGLSurface(); +#endif } void QQnxWindow::setGeometry(const QRect &rect) @@ -180,16 +191,16 @@ void QQnxWindow::setGeometry(const QRect &rect) #if !defined(QT_NO_OPENGL) // If this is an OpenGL window we need to request that the GL context updates - // the EGLsurface on which it is rendering. The surface will be recreated the - // next time QQnxGLContext::makeCurrent() is called. + // the EGLsurface on which it is rendering. { // We want the setting of the atomic bool in the GL context to be atomic with // setting m_requestedBufferSize and therefore extended the scope to include // that test. const QMutexLocker locker(&m_mutex); m_requestedBufferSize = rect.size(); - if (m_platformOpenGLContext != 0 && bufferSize() != rect.size()) - m_platformOpenGLContext->requestSurfaceChange(); + if (m_platformOpenGLContext != 0 && bufferSize() != rect.size()) { + m_newSurfaceRequested.testAndSetRelease(false, true); + } } #endif @@ -517,8 +528,12 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen) if (m_screen == platformScreen) return; - if (m_screen) + if (m_screen) { + qWindowDebug() << Q_FUNC_INFO << "Moving window to different screen"; m_screen->removeWindow(this); + screen_leave_window_group(m_window); + } + platformScreen->addWindow(this); m_screen = platformScreen; @@ -529,17 +544,20 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen) if (result != 0) qFatal("QQnxWindow: failed to set window display, errno=%d", errno); - // Add window to display's window group - errno = 0; - result = screen_join_window_group(m_window, platformScreen->windowGroupName()); - if (result != 0) - qFatal("QQnxWindow: failed to join window group, errno=%d", errno); - Q_FOREACH (QQnxWindow *childWindow, m_childWindows) { - // Only subwindows and tooltips need necessarily be moved to another display with the window. - if ((window()->type() & Qt::WindowType_Mask) == Qt::SubWindow || - (window()->type() & Qt::WindowType_Mask) == Qt::ToolTip) - childWindow->setScreen(platformScreen); + if (m_screen->isPrimaryScreen()) { + // Add window to display's window group + errno = 0; + result = screen_join_window_group(m_window, platformScreen->windowGroupName()); + if (result != 0) + qFatal("QQnxWindow: failed to join window group, errno=%d", errno); + + Q_FOREACH (QQnxWindow *childWindow, m_childWindows) { + // Only subwindows and tooltips need necessarily be moved to another display with the window. + if ((window()->type() & Qt::WindowType_Mask) == Qt::SubWindow || + (window()->type() & Qt::WindowType_Mask) == Qt::ToolTip) + childWindow->setScreen(platformScreen); + } } m_screen->updateHierarchy(); @@ -718,6 +736,79 @@ void QQnxWindow::minimize() #endif } +#if !defined(QT_NO_OPENGL) +void QQnxWindow::createEGLSurface() +{ + // Fetch the surface size from the window and update + // the window's buffers before we create the EGL surface + const QSize surfaceSize = requestedBufferSize(); + if (!surfaceSize.isValid()) { + qFatal("QQNX: Trying to create 0 size EGL surface. " + "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); + } + setBufferSize(surfaceSize); + + // Post root window, in case it hasn't been posted yet, to make it appear. + screen()->onWindowPost(0); + + const EGLint eglSurfaceAttrs[] = + { + EGL_RENDER_BUFFER, EGL_BACK_BUFFER, + EGL_NONE + }; + + qWindowDebug() << "Creating EGL surface" << platformOpenGLContext()->getEglDisplay() + << platformOpenGLContext()->getEglConfig(); + // Create EGL surface + m_eglSurface = eglCreateWindowSurface(platformOpenGLContext()->getEglDisplay() + , platformOpenGLContext()->getEglConfig(), + (EGLNativeWindowType) m_window, eglSurfaceAttrs); + if (m_eglSurface == EGL_NO_SURFACE) { + QQnxGLContext::checkEGLError("eglCreateWindowSurface"); + qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError()); + } +} + +void QQnxWindow::destroyEGLSurface() +{ + // Destroy EGL surface if it exists + if (m_eglSurface != EGL_NO_SURFACE) { + EGLBoolean eglResult = eglDestroySurface(platformOpenGLContext()->getEglDisplay(), m_eglSurface); + if (eglResult != EGL_TRUE) + qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError()); + } + + m_eglSurface = EGL_NO_SURFACE; +} + +void QQnxWindow::swapEGLBuffers() +{ + qWindowDebug() << Q_FUNC_INFO; + // Set current rendering API + EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); + if (eglResult != EGL_TRUE) + qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); + + // Post EGL surface to window + eglResult = eglSwapBuffers(m_platformOpenGLContext->getEglDisplay(), m_eglSurface); + if (eglResult != EGL_TRUE) + qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError()); +} + +EGLSurface QQnxWindow::getSurface() +{ + if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { + if (m_eglSurface != EGL_NO_SURFACE) { + platformOpenGLContext()->doneCurrent(); + destroyEGLSurface(); + } + createEGLSurface(); + } + + return m_eglSurface; +} +#endif + void QQnxWindow::updateZorder(int &topZorder) { errno = 0; diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index e30a469be7..4fabccf4cb 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -120,6 +120,13 @@ public: void blitFrom(QQnxWindow *sourceWindow, const QPoint &sourceOffset, const QRegion &targetRegion); void minimize(); +#if !defined(QT_NO_OPENGL) + void createEGLSurface(); + void destroyEGLSurface(); + void swapEGLBuffers(); + EGLSurface getSurface(); +#endif + private: QRect setGeometryHelper(const QRect &rect); void removeFromParent(); @@ -147,9 +154,6 @@ private: QRegion m_previousDirty; QRegion m_scrolled; -#if !defined(QT_NO_OPENGL) - QQnxGLContext *m_platformOpenGLContext; -#endif QQnxScreen *m_screen; QList<QQnxWindow*> m_childWindows; QQnxWindow *m_parentWindow; @@ -164,6 +168,13 @@ private: // EGL surface. All of this has to be done from the thread that is calling // QQnxGLContext::makeCurrent() mutable QMutex m_mutex; + +#if !defined(QT_NO_OPENGL) + QQnxGLContext *m_platformOpenGLContext; + QAtomicInt m_newSurfaceRequested; + EGLSurface m_eglSurface; +#endif + QSize m_requestedBufferSize; }; |