Split QQnxWindow into QQnxEglWindow and QQnxRasterWindow
Change-Id: I2fb4096ccca54fa6631aa16c9b8d1308b0a6b918 Reviewed-by: Sergio Ahumada <sergio.ahumada@digia.com> Reviewed-by: Rafael Roquetto <rafael.roquetto@kdab.com> Reviewed-by: Thomas McGuire <thomas.mcguire@kdab.com> Reviewed-by: Kevin Krammer <kevin.krammer@kdab.com>
This commit is contained in:
parent
e39d629ebe
commit
aed9a8d49b
@ -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
|
||||
}
|
||||
|
204
src/plugins/platforms/qnx/qqnxeglwindow.cpp
Normal file
204
src/plugins/platforms/qnx/qqnxeglwindow.cpp
Normal file
@ -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 <QDebug>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#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
|
97
src/plugins/platforms/qnx/qqnxeglwindow.h
Normal file
97
src/plugins/platforms/qnx/qqnxeglwindow.h
Normal file
@ -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 <QtCore/QMutex>
|
||||
|
||||
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
|
@ -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<QQnxWindow*>(surface);
|
||||
QQnxEglWindow *platformWindow = dynamic_cast<QQnxEglWindow*>(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<QQnxWindow*>(surface);
|
||||
QQnxEglWindow *platformWindow = dynamic_cast<QQnxEglWindow*>(surface);
|
||||
if (!platformWindow)
|
||||
return;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 <QtCore/QDebug>
|
||||
|
||||
@ -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<QQnxWindow*>(m_window->handle());
|
||||
return static_cast<QQnxRasterWindow*>(m_window->handle());
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -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<ScrollOp> m_scrollOpList;
|
||||
|
234
src/plugins/platforms/qnx/qqnxrasterwindow.cpp
Normal file
234
src/plugins/platforms/qnx/qqnxrasterwindow.cpp
Normal file
@ -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 <QDebug>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#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<QRect> 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
|
82
src/plugins/platforms/qnx/qqnxrasterwindow.h
Normal file
82
src/plugins/platforms/qnx/qqnxrasterwindow.h
Normal file
@ -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
|
@ -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<QQnxScreen *>(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<QQnxScreen *>(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<QRect> 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
|
||||
|
@ -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 <qpa/qplatformwindow.h>
|
||||
|
||||
#include "qqnxbuffer.h"
|
||||
|
||||
#include <QtGui/QImage>
|
||||
#include <QtCore/QMutex>
|
||||
|
||||
#if !defined(QT_NO_OPENGL)
|
||||
#include <EGL/egl.h>
|
||||
#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<QQnxWindow*>& 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<QQnxWindow*> 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
|
||||
|
Loading…
Reference in New Issue
Block a user