Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqnxrasterwindow.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 - 2014 BlackBerry Limited. All rights reserved.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqnxglobal.h"
5
7#include "qqnxscreen.h"
8
9#include <QDebug>
10
11#include <errno.h>
12
13QT_BEGIN_NAMESPACE
14
15QQnxRasterWindow::QQnxRasterWindow(QWindow *window, screen_context_t context, bool needRootWindow) :
16 QQnxWindow(window, context, needRootWindow),
17 m_currentBufferIndex(-1),
18 m_previousBufferIndex(-1)
19{
20 initWindow();
21
22 const int val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE;
23 const int result = screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_USAGE, &val);
24 if (Q_UNLIKELY(result != 0))
25 qFatal("QQnxRasterWindow: failed to set window alpha usage, errno=%d", errno);
26}
27
28void QQnxRasterWindow::post(const QRegion &dirty)
29{
30 // How double-buffering works
31 // --------------------------
32 //
33 // The are two buffers, the previous one and the current one.
34 // The previous buffer always contains the complete, full image of the whole window when it
35 // was last posted.
36 // The current buffer starts with the complete, full image of the second to last posting
37 // of the window.
38 //
39 // During painting, Qt paints on the current buffer. Thus, when Qt has finished painting, the
40 // current buffer contains the second to last image plus the newly painted regions.
41 // Since the second to last image is too old, we copy over the image from the previous buffer, but
42 // only for those regions that Qt didn't paint (because that would overwrite what Qt has just
43 // painted). This is the copyPreviousToCurrent() call below.
44 //
45 // After the call to copyPreviousToCurrent(), the current buffer contains the complete, full image of the
46 // whole window in its current state, and we call screen_post_window() to make the new buffer
47 // available to libscreen (called "posting"). There, only the regions that Qt painted on are
48 // posted, as nothing else has changed.
49 //
50 // After that, the previous and the current buffers are swapped, and the whole cycle starts anew.
51
52 // Check if render buffer exists and something was rendered
53 if (m_currentBufferIndex != -1 && !dirty.isEmpty()) {
54 qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
55 QQnxBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
56
57#if defined(QQNX_INCREMENTAL_RASTER_UPDATE)
58 // Copy unmodified region from old render buffer to new render buffer;
59 // required to allow partial updates
60 QRegion preserve = m_previousDirty - dirty - m_scrolled;
61 blitPreviousToCurrent(preserve, 0, 0);
62
63 // Calculate region that changed
64 QRegion modified = preserve + dirty + m_scrolled;
65 QRect rect = modified.boundingRect();
66 int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() };
67
68 // Update the display with contents of render buffer
69 Q_SCREEN_CHECKERROR(
70 screen_post_window(nativeHandle(), currentBuffer.nativeBuffer(), 1, dirtyRect, 0),
71 "Failed to post window");
72#else
73 // Update the display with contents of render buffer
75 screen_post_window(nativeHandle(), currentBuffer.nativeBuffer(), 0, NULL, 0),
76 "Failed to post window");
77#endif
78
79 // Advance to next nender buffer
80 m_previousBufferIndex = m_currentBufferIndex++;
81 if (m_currentBufferIndex >= MAX_BUFFER_COUNT)
82 m_currentBufferIndex = 0;
83
84 // Save modified region and clear scrolled region
85 m_previousDirty = QRect(QPoint(0, 0), window()->size());
86 m_scrolled = QRegion();
87
89 }
90}
91
92void QQnxRasterWindow::scroll(const QRegion &region, int dx, int dy, bool flush)
93{
94 qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
95 blitPreviousToCurrent(region, dx, dy, flush);
96 m_scrolled += region;
97}
98
100{
101 qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
102
103 // Check if render buffer is invalid
104 if (m_currentBufferIndex == -1) {
105 auto platformScreen = static_cast<QQnxScreen *>(screen());
106 // Get all buffers available for rendering
107 screen_buffer_t buffers[MAX_BUFFER_COUNT];
108 const int result = screen_get_window_property_pv(nativeHandle(), SCREEN_PROPERTY_RENDER_BUFFERS,
109 (void **)buffers);
110 Q_SCREEN_CRITICALERROR(result, "Failed to query window buffers");
111
112 // Wrap each buffer and clear
113 for (int i = 0; i < MAX_BUFFER_COUNT; ++i) {
114 m_buffers[i] = QQnxBuffer(buffers[i]);
115
116 // Clear Buffer
117 int bg[] = { SCREEN_BLIT_COLOR, 0x00000000, SCREEN_BLIT_END };
118 Q_SCREEN_CHECKERROR(screen_fill(platformScreen->nativeContext(), buffers[i], bg),
119 "Failed to clear window buffer");
120 }
121
122 Q_SCREEN_CHECKERROR(screen_flush_blits(platformScreen->nativeContext(), SCREEN_WAIT_IDLE),
123 "Failed to flush blits");
124
125 // Use the first available render buffer
126 m_currentBufferIndex = 0;
127 m_previousBufferIndex = -1;
128 }
129
130 return m_buffers[m_currentBufferIndex];
131}
132
133void QQnxRasterWindow::setParent(const QPlatformWindow *wnd)
134{
135 QQnxWindow::setParent(wnd);
137}
138
140{
141 const QSize windowSize = window()->size();
142
143 if (windowSize != bufferSize())
144 setBufferSize(windowSize);
145}
146
148{
149 return static_cast<QQnxScreen *>(screen())->nativeFormat();
150}
151
153{
154 // Buffers were destroyed; reacquire them
155 m_previousBufferIndex = -1;
156 m_currentBufferIndex = -1;
157 m_previousDirty = QRegion();
158 m_scrolled = QRegion();
159}
160
161void QQnxRasterWindow::blitPreviousToCurrent(const QRegion &region, int dx, int dy, bool flush)
162{
163 qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
164
165 // Abort if previous buffer is invalid or if nothing to copy
166 if (m_previousBufferIndex == -1 || region.isEmpty())
167 return;
168
169 QQnxBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
170 QQnxBuffer &previousBuffer = m_buffers[m_previousBufferIndex];
171
172 // Break down region into non-overlapping rectangles
173 for (auto rit = region.rbegin(), rend = region.rend(); rit != rend; ++rit) {
174 // Clip rectangle to bounds of target
175 const QRect rect = rit->intersected(currentBuffer.rect());
176
177 if (rect.isEmpty())
178 continue;
179
180 // Setup blit operation
181 int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x(),
182 SCREEN_BLIT_SOURCE_Y, rect.y(),
183 SCREEN_BLIT_SOURCE_WIDTH, rect.width(),
184 SCREEN_BLIT_SOURCE_HEIGHT, rect.height(),
185 SCREEN_BLIT_DESTINATION_X, rect.x() + dx,
186 SCREEN_BLIT_DESTINATION_Y, rect.y() + dy,
187 SCREEN_BLIT_DESTINATION_WIDTH, rect.width(),
188 SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(),
189 SCREEN_BLIT_END };
190
191 // Queue blit operation
192 Q_SCREEN_CHECKERROR(screen_blit(m_screenContext, currentBuffer.nativeBuffer(),
193 previousBuffer.nativeBuffer(), attribs),
194 "Failed to blit buffers");
195 }
196
197 // Check if flush requested
198 if (flush) {
199 // Wait for all blits to complete
200 Q_SCREEN_CHECKERROR(screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE),
201 "Failed to flush blits");
202
203 // Buffer was modified outside the CPU
204 currentBuffer.invalidateInCache();
205 }
206}
207
208QT_END_NAMESPACE
void blitPreviousToCurrent(const QRegion &region, int dx, int dy, bool flush=false)
QQnxBuffer & renderBuffer()
void setParent(const QPlatformWindow *window) override
This function is called to enable native child window in QPA.
int pixelFormat() const override
void scroll(const QRegion &region, int dx, int dy, bool flush=false)
void resetBuffers() override
void post(const QRegion &dirty)
void windowPosted()
#define Q_SCREEN_CRITICALERROR(x, message)
Definition qqnxglobal.h:16
#define Q_SCREEN_CHECKERROR(x, message)
Definition qqnxglobal.h:13
#define MAX_BUFFER_COUNT
Definition qqnxwindow.h:24