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
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// Qt-Security score:significant reason:default
4
11
12#include <d3d11.h>
13#include <d2d1_1.h>
14#include <dxgi1_2.h>
15
16using Microsoft::WRL::ComPtr;
17
18QT_BEGIN_NAMESPACE
19
20QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data)
21 : QWindowsWindow(window, data)
22 , m_directRendering(!(data.flags & Qt::FramelessWindowHint && window->format().hasAlpha()))
23{
24 if (m_directRendering)
25 setupSwapChain();
26
27 HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext(
28 D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
29 m_deviceContext.GetAddressOf());
30 if (FAILED(hr))
31 qWarning("%s: Couldn't create Direct2D Device context: %#lx", __FUNCTION__, hr);
32}
33
37
38void QWindowsDirect2DWindow::setWindowFlags(Qt::WindowFlags flags)
39{
40 m_directRendering = !(flags & Qt::FramelessWindowHint && window()->format().hasAlpha());
41 if (!m_directRendering)
42 m_swapChain.Reset(); // No need for the swap chain; release from memory
43 else if (!m_swapChain)
45
46 QWindowsWindow::setWindowFlags(flags);
47}
48
50{
51 setupBitmap();
52
53 return m_pixmap.data();
54}
55
56void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion &region, const QPoint &offset)
57{
58 QSize size;
59 if (m_directRendering) {
60 DXGI_SWAP_CHAIN_DESC1 desc;
61 HRESULT hr = m_swapChain->GetDesc1(&desc);
62 QRect geom = geometry();
63
64 if (FAILED(hr) || (desc.Width != UINT(geom.width()) || (desc.Height != UINT(geom.height())))) {
65 resizeSwapChain(geom.size());
66 m_swapChain->GetDesc1(&desc);
67 }
68 size.setWidth(int(desc.Width));
69 size.setHeight(int(desc.Height));
70 } else {
71 size = geometry().size();
72 }
73
74 setupBitmap();
75 if (!m_bitmap)
76 return;
77
78 if (bitmap != m_bitmap.data()) {
79 m_bitmap->deviceContext()->begin();
80
81 ID2D1DeviceContext *dc = m_bitmap->deviceContext()->get();
82 if (!m_needsFullFlush) {
83 QRegion clipped = region;
84 clipped &= QRect(QPoint(), size);
85
86 for (const QRect &rect : clipped) {
87 QRectF rectF(rect);
88 dc->DrawBitmap(bitmap->bitmap(),
89 to_d2d_rect_f(rectF),
90 1.0,
91 D2D1_INTERPOLATION_MODE_LINEAR,
92 to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
93 }
94 } else {
95 QRectF rectF(QPoint(), size);
96 dc->DrawBitmap(bitmap->bitmap(),
97 to_d2d_rect_f(rectF),
98 1.0,
99 D2D1_INTERPOLATION_MODE_LINEAR,
100 to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
101 m_needsFullFlush = false;
102 }
103
104 m_bitmap->deviceContext()->end();
105 }
106}
107
108void QWindowsDirect2DWindow::present(const QRegion &region)
109{
110 if (m_directRendering) {
111 m_swapChain->Present(0, 0);
112 return;
113 }
114
115 ComPtr<IDXGISurface> bitmapSurface;
116 HRESULT hr = m_bitmap->bitmap()->GetSurface(&bitmapSurface);
117 Q_ASSERT(SUCCEEDED(hr));
118 ComPtr<IDXGISurface1> dxgiSurface;
119 hr = bitmapSurface.As(&dxgiSurface);
120 Q_ASSERT(SUCCEEDED(hr));
121
122 HDC hdc;
123 hr = dxgiSurface->GetDC(FALSE, &hdc);
124 if (FAILED(hr)) {
125 qErrnoWarning(hr, "Failed to get DC for presenting the surface");
126 return;
127 }
128
129 const QRect bounds = window()->geometry();
130 const SIZE size = { bounds.width(), bounds.height() };
131 const POINT ptDst = { bounds.x(), bounds.y() };
132 const POINT ptSrc = { 0, 0 };
133 const BLENDFUNCTION blend = { AC_SRC_OVER, 0, BYTE(255.0 * opacity()), AC_SRC_ALPHA };
134 const QRect r = region.boundingRect();
135 const RECT dirty = { r.left(), r.top(), r.left() + r.width(), r.top() + r.height() };
136 UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), nullptr,
137 &ptDst, &size, hdc, &ptSrc, 0, &blend, ULW_ALPHA, &dirty };
138 if (!UpdateLayeredWindowIndirect(handle(), &info))
139 qErrnoWarning(int(GetLastError()), "Failed to update the layered window");
140
141 hr = dxgiSurface->ReleaseDC(nullptr);
142 if (FAILED(hr))
143 qErrnoWarning(hr, "Failed to release the DC for presentation");
144}
145
147{
148 DXGI_SWAP_CHAIN_DESC1 desc = {};
149
150 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
151 desc.SampleDesc.Count = 1;
152 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
153 desc.BufferCount = 1;
154 desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
155
156 HRESULT hr = QWindowsDirect2DContext::instance()->dxgiFactory()->CreateSwapChainForHwnd(
157 QWindowsDirect2DContext::instance()->d3dDevice(), // [in] IUnknown *pDevice
158 handle(), // [in] HWND hWnd
159 &desc, // [in] const DXGI_SWAP_CHAIN_DESC1 *pDesc
160 nullptr, // [in] const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc
161 nullptr, // [in] IDXGIOutput *pRestrictToOutput
162 m_swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain
163
164 if (FAILED(hr))
165 qWarning("%s: Could not create swap chain: %#lx", __FUNCTION__, hr);
166
167 m_needsFullFlush = true;
168}
169
171{
172 m_pixmap.reset();
173 m_bitmap.reset();
174 m_deviceContext->SetTarget(nullptr);
175 m_needsFullFlush = true;
176
177 if (!m_swapChain)
178 return;
179
180 HRESULT hr = m_swapChain->ResizeBuffers(0,
181 UINT(size.width()), UINT(size.height()),
182 DXGI_FORMAT_UNKNOWN,
183 0);
184 if (FAILED(hr))
185 qWarning("%s: Could not resize swap chain: %#lx", __FUNCTION__, hr);
186}
187
189{
190 const QSharedPointer<QWindowsDirect2DBitmap> null_result;
191
192 if (!m_bitmap)
193 return null_result;
194
195 D2D1_PIXEL_FORMAT format = m_bitmap->bitmap()->GetPixelFormat();
196 D2D1_SIZE_U size = m_bitmap->bitmap()->GetPixelSize();
197
198 FLOAT dpiX, dpiY;
199 m_bitmap->bitmap()->GetDpi(&dpiX, &dpiY);
200
201 D2D1_BITMAP_PROPERTIES1 properties = {
202 format, // D2D1_PIXEL_FORMAT pixelFormat;
203 dpiX, // FLOAT dpiX;
204 dpiY, // FLOAT dpiY;
205 D2D1_BITMAP_OPTIONS_TARGET, // D2D1_BITMAP_OPTIONS bitmapOptions;
206 nullptr // _Field_size_opt_(1) ID2D1ColorContext *colorContext;
207 };
208 ComPtr<ID2D1Bitmap1> copy;
209 HRESULT hr = m_deviceContext.Get()->CreateBitmap(size, nullptr, 0, properties, &copy);
210
211 if (FAILED(hr)) {
212 qWarning("%s: Could not create staging bitmap: %#lx", __FUNCTION__, hr);
213 return null_result;
214 }
215
216 hr = copy.Get()->CopyFromBitmap(nullptr, m_bitmap->bitmap(), nullptr);
217 if (FAILED(hr)) {
218 qWarning("%s: Could not copy from bitmap! %#lx", __FUNCTION__, hr);
219 return null_result;
220 }
221
222 return QSharedPointer<QWindowsDirect2DBitmap>(new QWindowsDirect2DBitmap(copy.Get(), nullptr));
223}
224
225void QWindowsDirect2DWindow::setupBitmap()
226{
227 if (m_bitmap)
228 return;
229
230 if (!m_deviceContext)
231 return;
232
233 if (m_directRendering && !m_swapChain)
234 return;
235
236 HRESULT hr;
237 ComPtr<IDXGISurface1> backBufferSurface;
238 if (m_directRendering) {
239 hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface));
240 if (FAILED(hr)) {
241 qWarning("%s: Could not query backbuffer for DXGI Surface: %#lx", __FUNCTION__, hr);
242 return;
243 }
244 } else {
245 const QRect rect = geometry();
246 CD3D11_TEXTURE2D_DESC backBufferDesc(DXGI_FORMAT_B8G8R8A8_UNORM, UINT(rect.width()), UINT(rect.height()), 1, 1);
247 backBufferDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
248 backBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
249 ComPtr<ID3D11Texture2D> backBufferTexture;
250 HRESULT hr = QWindowsDirect2DContext::instance()->d3dDevice()->CreateTexture2D(&backBufferDesc, nullptr, &backBufferTexture);
251 if (FAILED(hr)) {
252 qErrnoWarning(hr, "Failed to create backing texture for indirect rendering");
253 return;
254 }
255
256 hr = backBufferTexture.As(&backBufferSurface);
257 if (FAILED(hr)) {
258 qErrnoWarning(hr, "Failed to cast back buffer surface to DXGI surface");
259 return;
260 }
261 }
262
263 ComPtr<ID2D1Bitmap1> backBufferBitmap;
264 hr = m_deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(), nullptr, backBufferBitmap.GetAddressOf());
265 if (FAILED(hr)) {
266 qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#lx", __FUNCTION__, hr);
267 return;
268 }
269
270 m_bitmap.reset(new QWindowsDirect2DBitmap(backBufferBitmap.Get(), m_deviceContext.Get()));
271
272 QWindowsDirect2DPaintEngine::Flags flags = QWindowsDirect2DPaintEngine::NoFlag;
273 if (!m_directRendering)
274 flags |= QWindowsDirect2DPaintEngine::TranslucentTopLevelWindow;
275 auto *pp = new QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixmapType,
276 flags,
277 m_bitmap.data());
278 m_pixmap.reset(new QPixmap(pp));
279}
280
281QT_END_NAMESPACE
ID2D1Bitmap1 * bitmap() const
IDXGIFactory2 * dxgiFactory() const
static QWindowsDirect2DContext * instance()
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)