diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 7c497b4434..c9d83272e8 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -41,7 +41,8 @@ CONFIG(blackberry) { #DEFINES += QQNXWINDOW_DEBUG #DEFINES += QQNXCURSOR_DEBUG #DEFINES += QQNXFILEPICKER_DEBUG - +#DEFINES += QQNXEGLWINDOW_DEBUG +#DEFINES += QQNXRASTERWINDOW_DEBUG SOURCES = main.cpp \ qqnxbuffer.cpp \ @@ -56,7 +57,8 @@ SOURCES = main.cpp \ qqnxabstractnavigator.cpp \ qqnxabstractvirtualkeyboard.cpp \ qqnxservices.cpp \ - qqnxcursor.cpp + qqnxcursor.cpp \ + qqnxrasterwindow.cpp HEADERS = main.h \ qqnxbuffer.h \ @@ -72,7 +74,8 @@ HEADERS = main.h \ qqnxabstractnavigator.h \ qqnxabstractvirtualkeyboard.h \ qqnxservices.h \ - qqnxcursor.h + qqnxcursor.h \ + qqnxrasterwindow.h CONFIG(qqnx_screeneventthread) { DEFINES += QQNX_SCREENEVENTTHREAD @@ -83,9 +86,11 @@ CONFIG(qqnx_screeneventthread) { LIBS += -lscreen contains(QT_CONFIG, opengles2) { - SOURCES += qqnxglcontext.cpp + SOURCES += qqnxglcontext.cpp \ + qqnxeglwindow.cpp - HEADERS += qqnxglcontext.h + HEADERS += qqnxglcontext.h \ + qqnxeglwindow.h LIBS += -lEGL } diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp new file mode 100644 index 0000000000..9a947d7fad --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp @@ -0,0 +1,204 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qqnxeglwindow.h" +#include "qqnxscreen.h" + +#include + +#include + +#if defined(QQNXEGLWINDOW_DEBUG) +#define qEglWindowDebug qDebug +#else +#define qEglWindowDebug QT_NO_QDEBUG_MACRO +#endif + +QT_BEGIN_NAMESPACE + +QQnxEglWindow::QQnxEglWindow(QWindow *window, screen_context_t context) : + QQnxWindow(window, context), + m_requestedBufferSize(window->geometry().size()), + m_platformOpenGLContext(0), + m_newSurfaceRequested(true), + m_eglSurface(EGL_NO_SURFACE) +{ + initWindow(); +} + +QQnxEglWindow::~QQnxEglWindow() +{ + // Cleanup EGL surface if it exists + destroyEGLSurface(); +} + +void QQnxEglWindow::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); + + const EGLint eglSurfaceAttrs[] = + { + EGL_RENDER_BUFFER, EGL_BACK_BUFFER, + EGL_NONE + }; + + qEglWindowDebug() << "Creating EGL surface" << platformOpenGLContext()->getEglDisplay() + << platformOpenGLContext()->getEglConfig(); + // Create EGL surface + m_eglSurface = eglCreateWindowSurface(platformOpenGLContext()->getEglDisplay() + , platformOpenGLContext()->getEglConfig(), + (EGLNativeWindowType) nativeHandle(), eglSurfaceAttrs); + if (m_eglSurface == EGL_NO_SURFACE) { + QQnxGLContext::checkEGLError("eglCreateWindowSurface"); + qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError()); + } + + screen()->onWindowPost(0); +} + +void QQnxEglWindow::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 QQnxEglWindow::swapEGLBuffers() +{ + qEglWindowDebug() << 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 QQnxEglWindow::getSurface() +{ + if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { + if (m_eglSurface != EGL_NO_SURFACE) { + platformOpenGLContext()->doneCurrent(); + destroyEGLSurface(); + } + createEGLSurface(); + } + + return m_eglSurface; +} + +void QQnxEglWindow::setGeometry(const QRect &rect) +{ + //We need to request that the GL context updates + // 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_newSurfaceRequested.testAndSetRelease(false, true); + } + QQnxWindow::setGeometry(rect); +} + +QSize QQnxEglWindow::requestedBufferSize() const +{ + const QMutexLocker locker(&m_mutex); + return m_requestedBufferSize; +} + +void QQnxEglWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext) +{ + // This function does not take ownership of the platform gl context. + // It is owned by the frontend QOpenGLContext + m_platformOpenGLContext = platformOpenGLContext; +} + +int QQnxEglWindow::pixelFormat() const +{ + const QSurfaceFormat format = m_platformOpenGLContext->format(); + // Extract size of color channels from window format + const int redSize = format.redBufferSize(); + if (redSize == -1) + qFatal("QQnxWindow: red size not defined"); + + const int greenSize = format.greenBufferSize(); + if (greenSize == -1) + qFatal("QQnxWindow: green size not defined"); + + const int blueSize = format.blueBufferSize(); + if (blueSize == -1) + qFatal("QQnxWindow: blue size not defined"); + + // select matching native format + if (redSize == 5 && greenSize == 6 && blueSize == 5) + return SCREEN_FORMAT_RGB565; + else if (redSize == 8 && greenSize == 8 && blueSize == 8) + return SCREEN_FORMAT_RGBA8888; + + qFatal("QQnxWindow: unsupported pixel format"); +} + +void QQnxEglWindow::resetBuffers() +{ + const QMutexLocker locker(&m_mutex); + m_requestedBufferSize = QSize(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h new file mode 100644 index 0000000000..e7dae6a458 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxeglwindow.h @@ -0,0 +1,97 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQNXEGLWINDOW_H +#define QQNXEGLWINDOW_H + +#include "qqnxwindow.h" +#include "qqnxglcontext.h" + +#include + +QT_BEGIN_NAMESPACE + +class QQnxGLContext; + +class QQnxEglWindow : public QQnxWindow +{ +public: + QQnxEglWindow(QWindow *window, screen_context_t context); + ~QQnxEglWindow(); + + void createEGLSurface(); + void destroyEGLSurface(); + void swapEGLBuffers(); + EGLSurface getSurface(); + + void setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext); + QQnxGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; } + + void setGeometry(const QRect &rect); + + // Called by QQnxGLContext::createSurface() + QSize requestedBufferSize() const; + + WindowType windowType() const Q_DECL_OVERRIDE { return EGL; } + +protected: + int pixelFormat() const; + void resetBuffers(); + +private: + QSize m_requestedBufferSize; + + // This mutex is used to protect access to the m_requestedBufferSize + // member. This member is used in conjunction with QQnxGLContext::requestNewSurface() + // to coordinate recreating the EGL surface which involves destroying any + // existing EGL surface; resizing the native window buffers; and creating a new + // EGL surface. All of this has to be done from the thread that is calling + // QQnxGLContext::makeCurrent() + mutable QMutex m_mutex; + + QQnxGLContext *m_platformOpenGLContext; + QAtomicInt m_newSurfaceRequested; + EGLSurface m_eglSurface; +}; + +QT_END_NAMESPACE + +#endif // QQNXEGLWINDOW_H diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp index 448509c69d..355f52c46e 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -40,9 +40,8 @@ ****************************************************************************/ #include "qqnxglcontext.h" -#include "qqnxrootwindow.h" #include "qqnxscreen.h" -#include "qqnxwindow.h" +#include "qqnxeglwindow.h" #include "private/qeglconvenience_p.h" @@ -206,7 +205,7 @@ bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) if (eglResult != EGL_TRUE) qFatal("QQnxGLContext: failed to set EGL API, err=%d", eglGetError()); - QQnxWindow *platformWindow = dynamic_cast(surface); + QQnxEglWindow *platformWindow = dynamic_cast(surface); if (!platformWindow) return false; @@ -243,7 +242,7 @@ void QQnxGLContext::doneCurrent() void QQnxGLContext::swapBuffers(QPlatformSurface *surface) { qGLContextDebug() << Q_FUNC_INFO; - QQnxWindow *platformWindow = dynamic_cast(surface); + QQnxEglWindow *platformWindow = dynamic_cast(surface); if (!platformWindow) return; diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index fa9961ccce..bd627fef0b 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -53,6 +53,11 @@ #include "qqnxabstractvirtualkeyboard.h" #include "qqnxservices.h" +#include "qqnxrasterwindow.h" +#if !defined(QT_NO_OPENGL) +#include "qqnxeglwindow.h" +#endif + #if defined(Q_OS_BLACKBERRY) #include "qqnxbpseventfilter.h" #include "qqnxnavigatorbps.h" @@ -331,7 +336,18 @@ bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const { qIntegrationDebug() << Q_FUNC_INFO; - return new QQnxWindow(window, m_screenContext); + QSurface::SurfaceType surfaceType = window->surfaceType(); + switch (surfaceType) { + case QSurface::RasterSurface: + return new QQnxRasterWindow(window, m_screenContext); +#if !defined(QT_NO_OPENGL) + case QSurface::OpenGLSurface: + return new QQnxEglWindow(window, m_screenContext); +#endif + default: + qFatal("QQnxWindow: unsupported window API"); + } + return 0; } QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *window) const diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp index 5481b118e8..57914cf2fb 100644 --- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp +++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -40,7 +40,7 @@ ****************************************************************************/ #include "qqnxrasterbackingstore.h" -#include "qqnxwindow.h" +#include "qqnxrasterwindow.h" #include @@ -70,15 +70,16 @@ QQnxRasterBackingStore::~QQnxRasterBackingStore() QPaintDevice *QQnxRasterBackingStore::paintDevice() { - QQnxWindow *platformWindow = this->platformWindow(); - if (platformWindow->hasBuffers()) - return platformWindow->renderBuffer().image(); + if (platformWindow() && platformWindow()->hasBuffers()) + return platformWindow()->renderBuffer().image(); return 0; } void QQnxRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { + Q_UNUSED(offset) + qRasterBackingStoreDebug() << Q_FUNC_INFO << "w =" << this->window(); // Sometimes this method is called even though there is nothing to be @@ -96,8 +97,7 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const // child windows, are performed; conceptually ,child windows have no buffers // (actually they do have a 1x1 placeholder buffer due to libscreen limitations), // since Qt will only draw to the backing store of the top-level window. - QQnxWindow *platformWindow = this->platformWindow(); - if (!targetWindow || targetWindow == platformWindow) { + if (!targetWindow || targetWindow == platformWindow()) { // visit all pending scroll operations for (int i = m_scrollOpList.size() - 1; i >= 0; i--) { @@ -105,14 +105,14 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const // do the scroll operation ScrollOp &op = m_scrollOpList[i]; QRegion srcArea = op.totalArea.intersected( op.totalArea.translated(-op.dx, -op.dy) ); - platformWindow->scroll(srcArea, op.dx, op.dy); + platformWindow()->scroll(srcArea, op.dx, op.dy); } // clear all pending scroll operations m_scrollOpList.clear(); // update the display with newly rendered content - platformWindow->post(region); + platformWindow()->post(region); } m_hasUnflushedPaintOperations = false; @@ -174,10 +174,10 @@ void QQnxRasterBackingStore::endPaint() qRasterBackingStoreDebug() << Q_FUNC_INFO << "w =" << window(); } -QQnxWindow *QQnxRasterBackingStore::platformWindow() const +QQnxRasterWindow *QQnxRasterBackingStore::platformWindow() const { Q_ASSERT(m_window->handle()); - return static_cast(m_window->handle()); + return static_cast(m_window->handle()); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.h b/src/plugins/platforms/qnx/qqnxrasterbackingstore.h index 4e682aa52d..35efd68571 100644 --- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.h +++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.h @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE -class QQnxWindow; +class QQnxRasterWindow; class QQnxRasterBackingStore : public QPlatformBackingStore { @@ -72,7 +72,7 @@ private: int dy; }; - QQnxWindow *platformWindow() const; + QQnxRasterWindow *platformWindow() const; QWindow *m_window; QList m_scrollOpList; diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp new file mode 100644 index 0000000000..fa54b341a5 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp @@ -0,0 +1,234 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqnxrasterwindow.h" +#include "qqnxscreen.h" + +#include + +#include + +#if defined(QQNXRASTERWINDOW_DEBUG) +#define qRasterWindowDebug qDebug +#else +#define qRasterWindowDebug QT_NO_QDEBUG_MACRO +#endif + +QT_BEGIN_NAMESPACE + +QQnxRasterWindow::QQnxRasterWindow(QWindow *window, screen_context_t context) : + QQnxWindow(window, context), + m_currentBufferIndex(-1), + m_previousBufferIndex(-1) +{ + initWindow(); +} + +void QQnxRasterWindow::post(const QRegion &dirty) +{ + // How double-buffering works + // -------------------------- + // + // The are two buffers, the previous one and the current one. + // The previous buffer always contains the complete, full image of the whole window when it + // was last posted. + // The current buffer starts with the complete, full image of the second to last posting + // of the window. + // + // During painting, Qt paints on the current buffer. Thus, when Qt has finished painting, the + // current buffer contains the second to last image plus the newly painted regions. + // Since the second to last image is too old, we copy over the image from the previous buffer, but + // only for those regions that Qt didn't paint (because that would overwrite what Qt has just + // painted). This is the copyPreviousToCurrent() call below. + // + // After the call to copyPreviousToCurrent(), the current buffer contains the complete, full image of the + // whole window in its current state, and we call screen_post_window() to make the new buffer + // available to libscreen (called "posting"). There, only the regions that Qt painted on are + // posted, as nothing else has changed. + // + // After that, the previous and the current buffers are swapped, and the whole cycle starts anew. + + // Check if render buffer exists and something was rendered + if (m_currentBufferIndex != -1 && !dirty.isEmpty()) { + qRasterWindowDebug() << Q_FUNC_INFO << "window =" << window(); + QQnxBuffer ¤tBuffer = m_buffers[m_currentBufferIndex]; + + // Copy unmodified region from old render buffer to new render buffer; + // required to allow partial updates + QRegion preserve = m_previousDirty - dirty - m_scrolled; + blitPreviousToCurrent(preserve, 0, 0); + + // Calculate region that changed + QRegion modified = preserve + dirty + m_scrolled; + QRect rect = modified.boundingRect(); + int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() }; + + // Update the display with contents of render buffer + errno = 0; + int result = screen_post_window(nativeHandle(), currentBuffer.nativeBuffer(), 1, dirtyRect, 0); + if (result != 0) + qFatal("QQnxWindow: failed to post window buffer, errno=%d", errno); + + // Advance to next nender buffer + m_previousBufferIndex = m_currentBufferIndex++; + if (m_currentBufferIndex >= MAX_BUFFER_COUNT) + m_currentBufferIndex = 0; + + // Save modified region and clear scrolled region + m_previousDirty = dirty; + m_scrolled = QRegion(); + // Notify screen that window posted + if (screen() != 0) + screen()->onWindowPost(this); + } +} + +void QQnxRasterWindow::scroll(const QRegion ®ion, int dx, int dy, bool flush) +{ + qRasterWindowDebug() << Q_FUNC_INFO << "window =" << window(); + blitPreviousToCurrent(region, dx, dy, flush); + m_scrolled += region; +} + +QQnxBuffer &QQnxRasterWindow::renderBuffer() +{ + qRasterWindowDebug() << Q_FUNC_INFO << "window =" << window(); + + // Check if render buffer is invalid + if (m_currentBufferIndex == -1) { + // Get all buffers available for rendering + errno = 0; + screen_buffer_t buffers[MAX_BUFFER_COUNT]; + int result = screen_get_window_property_pv(nativeHandle(), SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers); + if (result != 0) + qFatal("QQnxRasterWindow: failed to query window buffers, errno=%d", errno); + + // Wrap each buffer and clear + for (int i = 0; i < MAX_BUFFER_COUNT; ++i) { + m_buffers[i] = QQnxBuffer(buffers[i]); + + // Clear Buffer + errno = 0; + int bg[] = { SCREEN_BLIT_COLOR, 0x00000000, SCREEN_BLIT_END }; + result = screen_fill(screen()->nativeContext(), buffers[i], bg); + if (result != 0) + qFatal("QQnxWindow: failed to clear window buffer, errno=%d", errno); + } + + errno = 0; + result = screen_flush_blits(screen()->nativeContext(), 0); + if (result != 0) + qFatal("QQnxWindow: failed to flush blits, errno=%d", errno); + + // Use the first available render buffer + m_currentBufferIndex = 0; + m_previousBufferIndex = -1; + } + + return m_buffers[m_currentBufferIndex]; +} + +int QQnxRasterWindow::pixelFormat() const +{ + return screen()->nativeFormat(); +} + +void QQnxRasterWindow::resetBuffers() +{ + // Buffers were destroyed; reacquire them + m_currentBufferIndex = -1; + m_previousDirty = QRegion(); + m_scrolled = QRegion(); +} + +void QQnxRasterWindow::blitPreviousToCurrent(const QRegion ®ion, int dx, int dy, bool flush) +{ + qRasterWindowDebug() << Q_FUNC_INFO << "window =" << window(); + + // Abort if previous buffer is invalid or if nothing to copy + if (m_previousBufferIndex == -1 || region.isEmpty()) + return; + + QQnxBuffer ¤tBuffer = m_buffers[m_currentBufferIndex]; + QQnxBuffer &previousBuffer = m_buffers[m_previousBufferIndex]; + + // Break down region into non-overlapping rectangles + const QVector rects = region.rects(); + for (int i = rects.size() - 1; i >= 0; i--) { + // Clip rectangle to bounds of target + const QRect rect = rects[i].intersected(currentBuffer.rect()); + + if (rect.isEmpty()) + continue; + + // Setup blit operation + int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x(), + SCREEN_BLIT_SOURCE_Y, rect.y(), + SCREEN_BLIT_SOURCE_WIDTH, rect.width(), + SCREEN_BLIT_SOURCE_HEIGHT, rect.height(), + SCREEN_BLIT_DESTINATION_X, rect.x() + dx, + SCREEN_BLIT_DESTINATION_Y, rect.y() + dy, + SCREEN_BLIT_DESTINATION_WIDTH, rect.width(), + SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(), + SCREEN_BLIT_END }; + + // Queue blit operation + errno = 0; + const int result = screen_blit(m_screenContext, currentBuffer.nativeBuffer(), + previousBuffer.nativeBuffer(), attribs); + if (result != 0) + qFatal("QQnxWindow: failed to blit buffers, errno=%d", errno); + } + + // Check if flush requested + if (flush) { + // Wait for all blits to complete + errno = 0; + const int result = screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE); + if (result != 0) + qFatal("QQnxWindow: failed to flush blits, errno=%d", errno); + + // Buffer was modified outside the CPU + currentBuffer.invalidateInCache(); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.h b/src/plugins/platforms/qnx/qqnxrasterwindow.h new file mode 100644 index 0000000000..8bd42bc320 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxrasterwindow.h @@ -0,0 +1,82 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQNXRASTERWINDOW_H +#define QQNXRASTERWINDOW_H + +#include "qqnxwindow.h" +#include "qqnxbuffer.h" + +QT_BEGIN_NAMESPACE + +class QQnxRasterWindow : public QQnxWindow +{ +public: + QQnxRasterWindow(QWindow *window, screen_context_t context); + + void post(const QRegion &dirty); + + void scroll(const QRegion ®ion, int dx, int dy, bool flush=false); + + QQnxBuffer &renderBuffer(); + + bool hasBuffers() const { return !bufferSize().isEmpty(); } + + WindowType windowType() const Q_DECL_OVERRIDE { return Raster; } + +protected: + int pixelFormat() const; + void resetBuffers(); + + // Copies content from the previous buffer (back buffer) to the current buffer (front buffer) + void blitPreviousToCurrent(const QRegion ®ion, int dx, int dy, bool flush=false); + +private: + QRegion m_previousDirty; + QRegion m_scrolled; + int m_currentBufferIndex; + int m_previousBufferIndex; + QQnxBuffer m_buffers[MAX_BUFFER_COUNT]; +}; + +QT_END_NAMESPACE + +#endif // QQNXRASTERWINDOW_H diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 61b13099fd..a5e899aa7e 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -70,19 +70,11 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) : QPlatformWindow(window), m_screenContext(context), m_window(0), - m_currentBufferIndex(-1), - m_previousBufferIndex(-1), m_screen(0), m_parentWindow(0), m_visible(false), m_exposed(true), - 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()) + m_windowState(Qt::WindowNoState) { qWindowDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size(); int result; @@ -96,70 +88,6 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) } if (result != 0) qFatal("QQnxWindow: failed to create window, errno=%d", errno); - - // Set window buffer usage based on rendering API - int val; - QSurface::SurfaceType surfaceType = window->surfaceType(); - switch (surfaceType) { - case QSurface::RasterSurface: - val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE; - break; - case QSurface::OpenGLSurface: - val = SCREEN_USAGE_OPENGL_ES2; - break; - default: - qFatal("QQnxWindow: unsupported window API"); - break; - } - - errno = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window buffer usage, errno=%d", errno); - - // Alpha channel is always pre-multiplied if present - errno = 0; - val = SCREEN_PRE_MULTIPLIED_ALPHA; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window alpha mode, errno=%d", errno); - - // Blend the window with Source Over Porter-Duff behavior onto whatever's - // behind it. - // - // If the desired use-case is opaque, the Widget painting framework will - // already fill in the alpha channel with full opacity. - errno = 0; - val = SCREEN_TRANSPARENCY_SOURCE_OVER; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window transparency, errno=%d", errno); - - // Set the window swap interval - errno = 0; - val = 1; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window swap interval, errno=%d", errno); - - if (window->flags() & Qt::WindowDoesNotAcceptFocus) { - errno = 0; - val = SCREEN_SENSITIVITY_NO_FOCUS; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window sensitivity, errno=%d", errno); - } - - setScreen(static_cast(window->screen()->handle())); - - // Add window to plugin's window mapper - QQnxIntegration::addWindow(m_window, window); - - // Qt never calls these setters after creating the window, so we need to do that ourselves here - setWindowState(window->windowState()); - if (window->parent() && window->parent()->handle()) - setParent(window->parent()->handle()); - setGeometryHelper(window->geometry()); } QQnxWindow::~QQnxWindow() @@ -179,32 +107,12 @@ 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) { const QRect oldGeometry = setGeometryHelper(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. - { - // 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_newSurfaceRequested.testAndSetRelease(false, true); - } - } -#endif - // Send a geometry change event to Qt (triggers resizeEvent() in QWindow/QWidget). // Calling flushWindowSystemEvents() here would flush input events which @@ -350,12 +258,6 @@ bool QQnxWindow::isExposed() const return m_visible && m_exposed; } -QSize QQnxWindow::requestedBufferSize() const -{ - const QMutexLocker locker(&m_mutex); - return m_requestedBufferSize; -} - void QQnxWindow::adjustBufferSize() { if (m_parentWindow) @@ -383,13 +285,7 @@ void QQnxWindow::setBufferSize(const QSize &size) // Create window buffers if they do not exist if (m_bufferSize.isEmpty()) { - val[0] = m_screen->nativeFormat(); -#if !defined(QT_NO_OPENGL) - // Get pixel format from EGL config if using OpenGL; - // otherwise inherit pixel format of window's screen - if (m_platformOpenGLContext != 0) - val[0] = platformWindowFormatToNativeFormat(m_platformOpenGLContext->format()); -#endif + val[0] = pixelFormat(); errno = 0; result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val); @@ -424,119 +320,7 @@ void QQnxWindow::setBufferSize(const QSize &size) // Cache new buffer size m_bufferSize = nonEmptySize; - - // Buffers were destroyed; reacquire them - m_currentBufferIndex = -1; - m_previousDirty = QRegion(); - m_scrolled = QRegion(); - - const QMutexLocker locker(&m_mutex); - m_requestedBufferSize = QSize(); -} - -QQnxBuffer &QQnxWindow::renderBuffer() -{ - qWindowDebug() << Q_FUNC_INFO << "window =" << window(); - - // Check if render buffer is invalid - if (m_currentBufferIndex == -1) { - // Get all buffers available for rendering - errno = 0; - screen_buffer_t buffers[MAX_BUFFER_COUNT]; - int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers); - if (result != 0) - qFatal("QQnxWindow: failed to query window buffers, errno=%d", errno); - - // Wrap each buffer and clear - for (int i = 0; i < MAX_BUFFER_COUNT; ++i) { - m_buffers[i] = QQnxBuffer(buffers[i]); - - // Clear Buffer - errno = 0; - int bg[] = { SCREEN_BLIT_COLOR, 0x00000000, SCREEN_BLIT_END }; - result = screen_fill(m_screen->nativeContext(), buffers[i], bg); - if (result != 0) - qFatal("QQnxWindow: failed to clear window buffer, errno=%d", errno); - } - - errno = 0; - result = screen_flush_blits(m_screen->nativeContext(), 0); - if (result != 0) - qFatal("QQnxWindow: failed to flush blits, errno=%d", errno); - - // Use the first available render buffer - m_currentBufferIndex = 0; - m_previousBufferIndex = -1; - } - - return m_buffers[m_currentBufferIndex]; -} - -void QQnxWindow::scroll(const QRegion ®ion, int dx, int dy, bool flush) -{ - qWindowDebug() << Q_FUNC_INFO << "window =" << window(); - blitPreviousToCurrent(region, dx, dy, flush); - m_scrolled += region; -} - -void QQnxWindow::post(const QRegion &dirty) -{ - // How double-buffering works - // -------------------------- - // - // The are two buffers, the previous one and the current one. - // The previous buffer always contains the complete, full image of the whole window when it - // was last posted. - // The current buffer starts with the complete, full image of the second to last posting - // of the window. - // - // During painting, Qt paints on the current buffer. Thus, when Qt has finished painting, the - // current buffer contains the second to last image plus the newly painted regions. - // Since the second to last image is too old, we copy over the image from the previous buffer, but - // only for those regions that Qt didn't paint (because that would overwrite what Qt has just - // painted). This is the copyPreviousToCurrent() call below. - // - // After the call to copyPreviousToCurrent(), the current buffer contains the complete, full image of the - // whole window in its current state, and we call screen_post_window() to make the new buffer - // available to libscreen (called "posting"). There, only the regions that Qt painted on are - // posted, as nothing else has changed. - // - // After that, the previous and the current buffers are swapped, and the whole cycle starts anew. - - // Check if render buffer exists and something was rendered - if (m_currentBufferIndex != -1 && !dirty.isEmpty()) { - qWindowDebug() << Q_FUNC_INFO << "window =" << window(); - QQnxBuffer ¤tBuffer = m_buffers[m_currentBufferIndex]; - - // Copy unmodified region from old render buffer to new render buffer; - // required to allow partial updates - QRegion preserve = m_previousDirty - dirty - m_scrolled; - blitPreviousToCurrent(preserve, 0, 0); - - // Calculate region that changed - QRegion modified = preserve + dirty + m_scrolled; - QRect rect = modified.boundingRect(); - int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() }; - - // Update the display with contents of render buffer - errno = 0; - int result = screen_post_window(m_window, currentBuffer.nativeBuffer(), 1, dirtyRect, 0); - if (result != 0) - qFatal("QQnxWindow: failed to post window buffer, errno=%d", errno); - - // Advance to next nender buffer - m_previousBufferIndex = m_currentBufferIndex++; - if (m_currentBufferIndex >= MAX_BUFFER_COUNT) - m_currentBufferIndex = 0; - - // Save modified region and clear scrolled region - m_previousDirty = dirty; - m_scrolled = QRegion(); - - // Notify screen that window posted - if (m_screen != 0) - m_screen->onWindowPost(this); - } + resetBuffers(); } void QQnxWindow::setScreen(QQnxScreen *platformScreen) @@ -702,15 +486,6 @@ void QQnxWindow::gainedFocus() QWindowSystemInterface::handleWindowActivated(window()); } -#if !defined(QT_NO_OPENGL) -void QQnxWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext) -{ - // This function does not take ownership of the platform gl context. - // It is owned by the frontend QOpenGLContext - m_platformOpenGLContext = platformOpenGLContext; -} -#endif - QQnxWindow *QQnxWindow::findWindow(screen_window_t windowHandle) { if (m_window == windowHandle) @@ -725,19 +500,6 @@ QQnxWindow *QQnxWindow::findWindow(screen_window_t windowHandle) return 0; } -void QQnxWindow::blitFrom(QQnxWindow *sourceWindow, const QPoint &sourceOffset, const QRegion &targetRegion) -{ - if (!sourceWindow || sourceWindow->m_previousBufferIndex == -1 || targetRegion.isEmpty()) - return; - - qWindowDebug() << Q_FUNC_INFO << window() << sourceWindow->window() << sourceOffset << targetRegion; - - QQnxBuffer &sourceBuffer = sourceWindow->m_buffers[sourceWindow->m_previousBufferIndex]; - QQnxBuffer &targetBuffer = renderBuffer(); - - blitHelper(sourceBuffer, targetBuffer, sourceOffset, QPoint(0, 0), targetRegion, true); -} - void QQnxWindow::minimize() { #if defined(Q_OS_BLACKBERRY) && !defined(Q_OS_BLACKBERRY_TABLET) @@ -759,78 +521,53 @@ void QQnxWindow::minimize() #endif } -#if !defined(QT_NO_OPENGL) -void QQnxWindow::createEGLSurface() +void QQnxWindow::initWindow() { - // 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); + // Alpha channel is always pre-multiplied if present + errno = 0; + int val = SCREEN_PRE_MULTIPLIED_ALPHA; + int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val); + if (result != 0) + qFatal("QQnxWindow: failed to set window alpha mode, errno=%d", errno); - // Post root window, in case it hasn't been posted yet, to make it appear. - screen()->onWindowPost(0); + // Blend the window with Source Over Porter-Duff behavior onto whatever's + // behind it. + // + // If the desired use-case is opaque, the Widget painting framework will + // already fill in the alpha channel with full opacity. + errno = 0; + val = SCREEN_TRANSPARENCY_SOURCE_OVER; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, &val); + if (result != 0) + qFatal("QQnxWindow: failed to set window transparency, errno=%d", errno); - const EGLint eglSurfaceAttrs[] = - { - EGL_RENDER_BUFFER, EGL_BACK_BUFFER, - EGL_NONE - }; + // Set the window swap interval + errno = 0; + val = 1; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val); + if (result != 0) + qFatal("QQnxWindow: failed to set window swap interval, errno=%d", errno); - 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()); + if (window()->flags() & Qt::WindowDoesNotAcceptFocus) { + errno = 0; + val = SCREEN_SENSITIVITY_NO_FOCUS; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val); + if (result != 0) + qFatal("QQnxWindow: failed to set window sensitivity, errno=%d", errno); } - m_eglSurface = EGL_NO_SURFACE; + setScreen(static_cast(window()->screen()->handle())); + + // Add window to plugin's window mapper + QQnxIntegration::addWindow(m_window, window()); + + // Qt never calls these setters after creating the window, so we need to do that ourselves here + setWindowState(window()->windowState()); + if (window()->parent() && window()->parent()->handle()) + setParent(window()->parent()->handle()); + setGeometryHelper(window()->geometry()); } -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) { @@ -876,89 +613,5 @@ void QQnxWindow::applyWindowState() } } -void QQnxWindow::blitHelper(QQnxBuffer &source, QQnxBuffer &target, const QPoint &sourceOffset, - const QPoint &targetOffset, const QRegion ®ion, bool flush) -{ - // Break down region into non-overlapping rectangles - const QVector rects = region.rects(); - for (int i = rects.size() - 1; i >= 0; i--) { - // Clip rectangle to bounds of target - const QRect rect = rects[i].intersected(target.rect()); - - if (rect.isEmpty()) - continue; - - // Setup blit operation - int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x() + sourceOffset.x(), - SCREEN_BLIT_SOURCE_Y, rect.y() + sourceOffset.y(), - SCREEN_BLIT_SOURCE_WIDTH, rect.width(), - SCREEN_BLIT_SOURCE_HEIGHT, rect.height(), - SCREEN_BLIT_DESTINATION_X, rect.x() + targetOffset.x(), - SCREEN_BLIT_DESTINATION_Y, rect.y() + targetOffset.y(), - SCREEN_BLIT_DESTINATION_WIDTH, rect.width(), - SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(), - SCREEN_BLIT_END }; - - // Queue blit operation - errno = 0; - const int result = screen_blit(m_screenContext, target.nativeBuffer(), - source.nativeBuffer(), attribs); - if (result != 0) - qFatal("QQnxWindow: failed to blit buffers, errno=%d", errno); - } - - // Check if flush requested - if (flush) { - // Wait for all blits to complete - errno = 0; - const int result = screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE); - if (result != 0) - qFatal("QQnxWindow: failed to flush blits, errno=%d", errno); - - // Buffer was modified outside the CPU - target.invalidateInCache(); - } -} - -void QQnxWindow::blitPreviousToCurrent(const QRegion ®ion, int dx, int dy, bool flush) -{ - qWindowDebug() << Q_FUNC_INFO << "window =" << window(); - - // Abort if previous buffer is invalid or if nothing to copy - if (m_previousBufferIndex == -1 || region.isEmpty()) - return; - - QQnxBuffer ¤tBuffer = m_buffers[m_currentBufferIndex]; - QQnxBuffer &previousBuffer = m_buffers[m_previousBufferIndex]; - - blitHelper(previousBuffer, currentBuffer, QPoint(0, 0), QPoint(dx, dy), region, flush); -} - -int QQnxWindow::platformWindowFormatToNativeFormat(const QSurfaceFormat &format) -{ - qWindowDebug() << Q_FUNC_INFO; - // Extract size of colour channels from window format - int redSize = format.redBufferSize(); - if (redSize == -1) - qFatal("QQnxWindow: red size not defined"); - - int greenSize = format.greenBufferSize(); - if (greenSize == -1) - qFatal("QQnxWindow: green size not defined"); - - int blueSize = format.blueBufferSize(); - if (blueSize == -1) - qFatal("QQnxWindow: blue size not defined"); - - // select matching native format - if (redSize == 5 && greenSize == 6 && blueSize == 5) { - return SCREEN_FORMAT_RGB565; - } else if (redSize == 8 && greenSize == 8 && blueSize == 8) { - return SCREEN_FORMAT_RGBA8888; - } else { - qFatal("QQnxWindow: unsupported pixel format"); - return 0; - } -} QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index cd1980d994..a63a215511 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -44,11 +44,6 @@ #include -#include "qqnxbuffer.h" - -#include -#include - #if !defined(QT_NO_OPENGL) #include #endif @@ -60,9 +55,6 @@ QT_BEGIN_NAMESPACE // all surfaces double buffered #define MAX_BUFFER_COUNT 2 -#if !defined(QT_NO_OPENGL) -class QQnxGLContext; -#endif class QQnxScreen; class QSurfaceFormat; @@ -71,6 +63,11 @@ class QQnxWindow : public QPlatformWindow { friend class QQnxScreen; public: + enum WindowType { + EGL, + Raster + }; + QQnxWindow(QWindow *window, screen_context_t context); virtual ~QQnxWindow(); @@ -83,17 +80,9 @@ public: WId winId() const { return (WId)m_window; } screen_window_t nativeHandle() const { return m_window; } - // Called by QQnxGLContext::createSurface() - QSize requestedBufferSize() const; - void adjustBufferSize(); void setBufferSize(const QSize &size); QSize bufferSize() const { return m_bufferSize; } - bool hasBuffers() const { return !m_bufferSize.isEmpty(); } - - QQnxBuffer &renderBuffer(); - void scroll(const QRegion ®ion, int dx, int dy, bool flush=false); - void post(const QRegion &dirty); void setScreen(QQnxScreen *platformScreen); @@ -111,22 +100,18 @@ public: QQnxScreen *screen() const { return m_screen; } const QList& children() const { return m_childWindows; } -#if !defined(QT_NO_OPENGL) - void setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext); - QQnxGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; } -#endif - QQnxWindow *findWindow(screen_window_t windowHandle); - 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 + virtual WindowType windowType() const = 0; +protected: + virtual int pixelFormat() const = 0; + virtual void resetBuffers() = 0; + + void initWindow(); + + screen_context_t m_screenContext; private: QRect setGeometryHelper(const QRect &rect); @@ -136,24 +121,8 @@ private: void updateZorder(int &topZorder); void applyWindowState(); - void fetchBuffers(); - - // Copies content from the previous buffer (back buffer) to the current buffer (front buffer) - void blitPreviousToCurrent(const QRegion ®ion, int dx, int dy, bool flush=false); - - void blitHelper(QQnxBuffer &source, QQnxBuffer &target, const QPoint &sourceOffset, - const QPoint &targetOffset, const QRegion ®ion, bool flush = false); - - static int platformWindowFormatToNativeFormat(const QSurfaceFormat &format); - - screen_context_t m_screenContext; screen_window_t m_window; QSize m_bufferSize; - QQnxBuffer m_buffers[MAX_BUFFER_COUNT]; - int m_currentBufferIndex; - int m_previousBufferIndex; - QRegion m_previousDirty; - QRegion m_scrolled; QQnxScreen *m_screen; QList m_childWindows; @@ -162,22 +131,6 @@ private: bool m_exposed; QRect m_unmaximizedGeometry; Qt::WindowState m_windowState; - - // This mutex is used to protect access to the m_requestedBufferSize - // member. This member is used in conjunction with QQnxGLContext::requestNewSurface() - // to coordinate recreating the EGL surface which involves destroying any - // existing EGL surface; resizing the native window buffers; and creating a new - // 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; }; QT_END_NAMESPACE