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