Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwindowsdirect2dwindow.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
10
11#include <d3d11.h>
12#include <d2d1_1.h>
13#include <dxgi1_2.h>
14
16
18
21 , m_directRendering(!(data.flags & Qt::FramelessWindowHint && window->format().hasAlpha()))
22{
23 if (window->type() == Qt::Desktop)
24 return; // No further handling for Qt::Desktop
25
26 if (m_directRendering)
28
29 HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext(
30 D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
31 m_deviceContext.GetAddressOf());
32 if (FAILED(hr))
33 qWarning("%s: Couldn't create Direct2D Device context: %#lx", __FUNCTION__, hr);
34}
35
39
41{
42 m_directRendering = !(flags & Qt::FramelessWindowHint && window()->format().hasAlpha());
43 if (!m_directRendering)
44 m_swapChain.Reset(); // No need for the swap chain; release from memory
45 else if (!m_swapChain)
47
49}
50
52{
53 setupBitmap();
54
55 return m_pixmap.data();
56}
57
59{
60 QSize size;
61 if (m_directRendering) {
62 DXGI_SWAP_CHAIN_DESC1 desc;
63 HRESULT hr = m_swapChain->GetDesc1(&desc);
64 QRect geom = geometry();
65
66 if (FAILED(hr) || (desc.Width != UINT(geom.width()) || (desc.Height != UINT(geom.height())))) {
67 resizeSwapChain(geom.size());
68 m_swapChain->GetDesc1(&desc);
69 }
70 size.setWidth(int(desc.Width));
71 size.setHeight(int(desc.Height));
72 } else {
73 size = geometry().size();
74 }
75
76 setupBitmap();
77 if (!m_bitmap)
78 return;
79
80 if (bitmap != m_bitmap.data()) {
81 m_bitmap->deviceContext()->begin();
82
83 ID2D1DeviceContext *dc = m_bitmap->deviceContext()->get();
84 if (!m_needsFullFlush) {
85 QRegion clipped = region;
86 clipped &= QRect(QPoint(), size);
87
88 for (const QRect &rect : clipped) {
89 QRectF rectF(rect);
90 dc->DrawBitmap(bitmap->bitmap(),
91 to_d2d_rect_f(rectF),
92 1.0,
93 D2D1_INTERPOLATION_MODE_LINEAR,
94 to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
95 }
96 } else {
97 QRectF rectF(QPoint(), size);
98 dc->DrawBitmap(bitmap->bitmap(),
99 to_d2d_rect_f(rectF),
100 1.0,
101 D2D1_INTERPOLATION_MODE_LINEAR,
102 to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
103 m_needsFullFlush = false;
104 }
105
106 m_bitmap->deviceContext()->end();
107 }
108}
109
111{
112 if (m_directRendering) {
113 m_swapChain->Present(0, 0);
114 return;
115 }
116
117 ComPtr<IDXGISurface> bitmapSurface;
118 HRESULT hr = m_bitmap->bitmap()->GetSurface(&bitmapSurface);
119 Q_ASSERT(SUCCEEDED(hr));
120 ComPtr<IDXGISurface1> dxgiSurface;
121 hr = bitmapSurface.As(&dxgiSurface);
122 Q_ASSERT(SUCCEEDED(hr));
123
124 HDC hdc;
125 hr = dxgiSurface->GetDC(FALSE, &hdc);
126 if (FAILED(hr)) {
127 qErrnoWarning(hr, "Failed to get DC for presenting the surface");
128 return;
129 }
130
131 const QRect bounds = window()->geometry();
132 const SIZE size = { bounds.width(), bounds.height() };
133 const POINT ptDst = { bounds.x(), bounds.y() };
134 const POINT ptSrc = { 0, 0 };
135 const BLENDFUNCTION blend = { AC_SRC_OVER, 0, BYTE(255.0 * opacity()), AC_SRC_ALPHA };
136 const QRect r = region.boundingRect();
137 const RECT dirty = { r.left(), r.top(), r.left() + r.width(), r.top() + r.height() };
138 UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), nullptr,
139 &ptDst, &size, hdc, &ptSrc, 0, &blend, ULW_ALPHA, &dirty };
140 if (!UpdateLayeredWindowIndirect(handle(), &info))
141 qErrnoWarning(int(GetLastError()), "Failed to update the layered window");
142
143 hr = dxgiSurface->ReleaseDC(nullptr);
144 if (FAILED(hr))
145 qErrnoWarning(hr, "Failed to release the DC for presentation");
146}
147
149{
150 DXGI_SWAP_CHAIN_DESC1 desc = {};
151
152 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
153 desc.SampleDesc.Count = 1;
154 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
155 desc.BufferCount = 1;
156 desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
157
158 HRESULT hr = QWindowsDirect2DContext::instance()->dxgiFactory()->CreateSwapChainForHwnd(
159 QWindowsDirect2DContext::instance()->d3dDevice(), // [in] IUnknown *pDevice
160 handle(), // [in] HWND hWnd
161 &desc, // [in] const DXGI_SWAP_CHAIN_DESC1 *pDesc
162 nullptr, // [in] const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc
163 nullptr, // [in] IDXGIOutput *pRestrictToOutput
164 m_swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain
165
166 if (FAILED(hr))
167 qWarning("%s: Could not create swap chain: %#lx", __FUNCTION__, hr);
168
169 m_needsFullFlush = true;
170}
171
173{
174 m_pixmap.reset();
175 m_bitmap.reset();
176 m_deviceContext->SetTarget(nullptr);
177 m_needsFullFlush = true;
178
179 if (!m_swapChain)
180 return;
181
182 HRESULT hr = m_swapChain->ResizeBuffers(0,
183 UINT(size.width()), UINT(size.height()),
184 DXGI_FORMAT_UNKNOWN,
185 0);
186 if (FAILED(hr))
187 qWarning("%s: Could not resize swap chain: %#lx", __FUNCTION__, hr);
188}
189
190QSharedPointer<QWindowsDirect2DBitmap> QWindowsDirect2DWindow::copyBackBuffer() const
191{
192 const QSharedPointer<QWindowsDirect2DBitmap> null_result;
193
194 if (!m_bitmap)
195 return null_result;
196
197 D2D1_PIXEL_FORMAT format = m_bitmap->bitmap()->GetPixelFormat();
198 D2D1_SIZE_U size = m_bitmap->bitmap()->GetPixelSize();
199
200 FLOAT dpiX, dpiY;
201 m_bitmap->bitmap()->GetDpi(&dpiX, &dpiY);
202
203 D2D1_BITMAP_PROPERTIES1 properties = {
204 format, // D2D1_PIXEL_FORMAT pixelFormat;
205 dpiX, // FLOAT dpiX;
206 dpiY, // FLOAT dpiY;
207 D2D1_BITMAP_OPTIONS_TARGET, // D2D1_BITMAP_OPTIONS bitmapOptions;
208 nullptr // _Field_size_opt_(1) ID2D1ColorContext *colorContext;
209 };
210 ComPtr<ID2D1Bitmap1> copy;
211 HRESULT hr = m_deviceContext.Get()->CreateBitmap(size, nullptr, 0, properties, &copy);
212
213 if (FAILED(hr)) {
214 qWarning("%s: Could not create staging bitmap: %#lx", __FUNCTION__, hr);
215 return null_result;
216 }
217
218 hr = copy.Get()->CopyFromBitmap(nullptr, m_bitmap->bitmap(), nullptr);
219 if (FAILED(hr)) {
220 qWarning("%s: Could not copy from bitmap! %#lx", __FUNCTION__, hr);
221 return null_result;
222 }
223
224 return QSharedPointer<QWindowsDirect2DBitmap>(new QWindowsDirect2DBitmap(copy.Get(), nullptr));
225}
226
227void QWindowsDirect2DWindow::setupBitmap()
228{
229 if (m_bitmap)
230 return;
231
232 if (!m_deviceContext)
233 return;
234
235 if (m_directRendering && !m_swapChain)
236 return;
237
238 HRESULT hr;
239 ComPtr<IDXGISurface1> backBufferSurface;
240 if (m_directRendering) {
241 hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface));
242 if (FAILED(hr)) {
243 qWarning("%s: Could not query backbuffer for DXGI Surface: %#lx", __FUNCTION__, hr);
244 return;
245 }
246 } else {
247 const QRect rect = geometry();
248 CD3D11_TEXTURE2D_DESC backBufferDesc(DXGI_FORMAT_B8G8R8A8_UNORM, UINT(rect.width()), UINT(rect.height()), 1, 1);
249 backBufferDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
250 backBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
251 ComPtr<ID3D11Texture2D> backBufferTexture;
252 HRESULT hr = QWindowsDirect2DContext::instance()->d3dDevice()->CreateTexture2D(&backBufferDesc, nullptr, &backBufferTexture);
253 if (FAILED(hr)) {
254 qErrnoWarning(hr, "Failed to create backing texture for indirect rendering");
255 return;
256 }
257
258 hr = backBufferTexture.As(&backBufferSurface);
259 if (FAILED(hr)) {
260 qErrnoWarning(hr, "Failed to cast back buffer surface to DXGI surface");
261 return;
262 }
263 }
264
265 ComPtr<ID2D1Bitmap1> backBufferBitmap;
266 hr = m_deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(), nullptr, backBufferBitmap.GetAddressOf());
267 if (FAILED(hr)) {
268 qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#lx", __FUNCTION__, hr);
269 return;
270 }
271
272 m_bitmap.reset(new QWindowsDirect2DBitmap(backBufferBitmap.Get(), m_deviceContext.Get()));
273
275 if (!m_directRendering)
278 flags,
279 m_bitmap.data());
280 m_pixmap.reset(new QPixmap(pp));
281}
282
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QWindow * window() const
Returns the window which belongs to the QPlatformWindow.
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr QRectF translated(qreal dx, qreal dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
Definition qrect.h:762
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRect boundingRect() const noexcept
Returns the bounding rectangle of this region.
T * data() const noexcept
Returns the value of the pointer referenced by this object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\inmodule QtCore
Definition qsize.h:25
bool hasAlpha() const
Returns true if the alpha buffer size is greater than zero.
\inmodule QtGui
Definition qwindow.h:63
QSurfaceFormat format() const override
Returns the actual format of this window.
Definition qwindow.cpp:946
QWindowsDirect2DDeviceContext * deviceContext() const
ID2D1Bitmap1 * bitmap() const
static QWindowsDirect2DContext * instance()
QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data)
void setWindowFlags(Qt::WindowFlags flags) override
Requests setting the window flags of this surface to flags.
void present(const QRegion &region)
QSharedPointer< QWindowsDirect2DBitmap > copyBackBuffer() const
void flush(QWindowsDirect2DBitmap *bitmap, const QRegion &region, const QPoint &offset)
void resizeSwapChain(const QSize &size)
Raster or OpenGL Window.
void setWindowFlags(Qt::WindowFlags flags) override
Requests setting the window flags of this surface to flags.
qreal opacity() const
QSurfaceFormat format() const override
Returns the actual surface format of the window.
QRect geometry() const override
Returns the current geometry of a window.
HWND handle() const override
rect
[4]
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
Definition qcompare.h:63
@ Desktop
Definition qnamespace.h:215
@ FramelessWindowHint
Definition qnamespace.h:225
static jboolean copy(JNIEnv *, jobject)
static const QCssKnownValue properties[NumProperties - 1]
#define qWarning
Definition qlogging.h:166
#define SIZE(large, small, mini)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLbitfield flags
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
static bool hasAlpha(const QImage &image)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
long HRESULT
D2D1_RECT_F to_d2d_rect_f(const QRectF &qrect)
aWidget window() -> setWindowTitle("New Window Title")
[2]
QHostInfo info
[0]