diff options
author | Fabian Bumberger <fbumberger@rim.com> | 2013-09-02 15:49:51 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-18 11:28:26 +0200 |
commit | aed9a8d49b7470de6809c3bf747b14c7150d7ae6 (patch) | |
tree | fb566c75ccccf7623170629b61c0ac760c295d98 /src/plugins/platforms/qnx/qqnxrasterwindow.cpp | |
parent | e39d629ebe9044b505ac35eaae3ab9c214d452a2 (diff) |
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>
Diffstat (limited to 'src/plugins/platforms/qnx/qqnxrasterwindow.cpp')
-rw-r--r-- | src/plugins/platforms/qnx/qqnxrasterwindow.cpp | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp new file mode 100644 index 0000000000..fa54b341a5 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp @@ -0,0 +1,234 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqnxrasterwindow.h" +#include "qqnxscreen.h" + +#include <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 |