15using Microsoft::WRL::ComPtr;
19QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window,
const QWindowsWindowData &data)
20 : QWindowsWindow(window, data)
21 , m_directRendering(!(data.flags & Qt::FramelessWindowHint && window->format().hasAlpha()))
23 if (m_directRendering)
26 HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext(
27 D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
28 m_deviceContext.GetAddressOf());
30 qWarning(
"%s: Couldn't create Direct2D Device context: %#lx",
__FUNCTION__, hr);
39 m_directRendering = !(flags & Qt::FramelessWindowHint && window()->format().hasAlpha());
40 if (!m_directRendering)
42 else if (!m_swapChain)
45 QWindowsWindow::setWindowFlags(flags);
52 return m_pixmap.data();
58 if (m_directRendering) {
59 DXGI_SWAP_CHAIN_DESC1 desc;
60 HRESULT hr = m_swapChain->GetDesc1(&desc);
61 QRect geom = geometry();
63 if (FAILED(hr) || (desc.Width != UINT(geom.width()) || (desc.Height != UINT(geom.height())))) {
65 m_swapChain->GetDesc1(&desc);
67 size.setWidth(
int(desc.Width));
68 size.setHeight(
int(desc.Height));
70 size = geometry().size();
77 if (bitmap != m_bitmap.data()) {
78 m_bitmap->deviceContext()->begin();
80 ID2D1DeviceContext *dc = m_bitmap->deviceContext()->get();
81 if (!m_needsFullFlush) {
82 QRegion clipped = region;
83 clipped &= QRect(QPoint(), size);
85 for (
const QRect &rect : clipped) {
87 dc->DrawBitmap(bitmap->bitmap(),
90 D2D1_INTERPOLATION_MODE_LINEAR,
91 to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
94 QRectF rectF(QPoint(), size);
95 dc->DrawBitmap(bitmap->bitmap(),
98 D2D1_INTERPOLATION_MODE_LINEAR,
99 to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
100 m_needsFullFlush =
false;
103 m_bitmap->deviceContext()->end();
109 if (m_directRendering) {
110 m_swapChain->Present(0, 0);
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));
122 hr = dxgiSurface->GetDC(FALSE, &hdc);
124 qErrnoWarning(hr,
"Failed to get DC for presenting the surface");
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");
140 hr = dxgiSurface->ReleaseDC(
nullptr);
142 qErrnoWarning(hr,
"Failed to release the DC for presentation");
147 DXGI_SWAP_CHAIN_DESC1 desc = {};
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;
155 HRESULT hr = QWindowsDirect2DContext::instance()->dxgiFactory()->CreateSwapChainForHwnd(
156 QWindowsDirect2DContext::instance()->d3dDevice(),
161 m_swapChain.ReleaseAndGetAddressOf());
164 qWarning(
"%s: Could not create swap chain: %#lx",
__FUNCTION__, hr);
166 m_needsFullFlush =
true;
173 m_deviceContext->SetTarget(
nullptr);
174 m_needsFullFlush =
true;
179 HRESULT hr = m_swapChain->ResizeBuffers(0,
180 UINT(size.width()), UINT(size.height()),
184 qWarning(
"%s: Could not resize swap chain: %#lx",
__FUNCTION__, hr);
189 const QSharedPointer<QWindowsDirect2DBitmap> null_result;
194 D2D1_PIXEL_FORMAT format = m_bitmap->bitmap()->GetPixelFormat();
195 D2D1_SIZE_U size = m_bitmap->bitmap()->GetPixelSize();
198 m_bitmap->bitmap()->GetDpi(&dpiX, &dpiY);
200 D2D1_BITMAP_PROPERTIES1 properties = {
204 D2D1_BITMAP_OPTIONS_TARGET,
207 ComPtr<ID2D1Bitmap1> copy;
208 HRESULT hr = m_deviceContext.Get()->CreateBitmap(size,
nullptr, 0, properties, ©);
211 qWarning(
"%s: Could not create staging bitmap: %#lx",
__FUNCTION__, hr);
215 hr = copy.Get()->CopyFromBitmap(
nullptr, m_bitmap->bitmap(),
nullptr);
217 qWarning(
"%s: Could not copy from bitmap! %#lx",
__FUNCTION__, hr);
229 if (!m_deviceContext)
232 if (m_directRendering && !m_swapChain)
236 ComPtr<IDXGISurface1> backBufferSurface;
237 if (m_directRendering) {
238 hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface));
240 qWarning(
"%s: Could not query backbuffer for DXGI Surface: %#lx",
__FUNCTION__, hr);
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;
251 qErrnoWarning(hr,
"Failed to create backing texture for indirect rendering");
255 hr = backBufferTexture.As(&backBufferSurface);
257 qErrnoWarning(hr,
"Failed to cast back buffer surface to DXGI surface");
262 ComPtr<ID2D1Bitmap1> backBufferBitmap;
263 hr = m_deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(),
nullptr, backBufferBitmap.GetAddressOf());
265 qWarning(
"%s: Could not create Direct2D Bitmap from DXGI Surface: %#lx",
__FUNCTION__, hr);
269 m_bitmap.reset(
new QWindowsDirect2DBitmap(backBufferBitmap.Get(), m_deviceContext.Get()));
271 QWindowsDirect2DPaintEngine::Flags flags = QWindowsDirect2DPaintEngine::NoFlag;
272 if (!m_directRendering)
273 flags |= QWindowsDirect2DPaintEngine::TranslucentTopLevelWindow;
274 auto *pp =
new QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixmapType,
277 m_pixmap.reset(
new QPixmap(pp));
ID3D11Device * d3dDevice() const
static QWindowsDirect2DContext * instance()
void setWindowFlags(Qt::WindowFlags flags) override
Requests setting the window flags of this surface to flags.
~QWindowsDirect2DWindow()
void present(const QRegion ®ion)
QSharedPointer< QWindowsDirect2DBitmap > copyBackBuffer() const
void flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset)
void resizeSwapChain(const QSize &size)