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:
Fabian Bumberger 2013-09-02 15:49:51 +02:00 committed by The Qt Project
parent e39d629ebe
commit aed9a8d49b
11 changed files with 717 additions and 474 deletions

View File

@ -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
}

View 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

View 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

View File

@ -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;

View File

@ -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

View File

@ -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 &region, 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 &region, 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 &region, 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

View File

@ -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;

View 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 &currentBuffer = 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 &region, 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 &region, 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 &currentBuffer = 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

View 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 &region, 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 &region, 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

View File

@ -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 &region, 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 &currentBuffer = 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 &region, 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 &region, 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 &currentBuffer = 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

View File

@ -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 &region, 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 &region, int dx, int dy, bool flush=false);
void blitHelper(QQnxBuffer &source, QQnxBuffer &target, const QPoint &sourceOffset,
const QPoint &targetOffset, const QRegion &region, 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