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