diff options
Diffstat (limited to 'src/plugins/platforms/direct2d')
4 files changed, 135 insertions, 41 deletions
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp index be013f027b..59b543e6d5 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp @@ -49,6 +49,7 @@ #include "qwindowscontext.h" +#include <QtGui/QPainter> #include <QtGui/QWindow> #include <QtCore/QDebug> @@ -85,9 +86,18 @@ QWindowsDirect2DBackingStore::~QWindowsDirect2DBackingStore() { } -void QWindowsDirect2DBackingStore::beginPaint(const QRegion &) +void QWindowsDirect2DBackingStore::beginPaint(const QRegion ®ion) { - bitmap(nativeWindow(window())->pixmap())->deviceContext()->begin(); + QPixmap *pixmap = nativeWindow(window())->pixmap(); + bitmap(pixmap)->deviceContext()->begin(); + + QPainter painter(pixmap); + QColor clear(Qt::transparent); + + painter.setCompositionMode(QPainter::CompositionMode_Source); + + foreach (const QRect &r, region.rects()) + painter.fillRect(r, clear); } void QWindowsDirect2DBackingStore::endPaint() @@ -107,7 +117,7 @@ void QWindowsDirect2DBackingStore::flush(QWindow *targetWindow, const QRegion &r nativeWindow(targetWindow)->flush(copy.data(), region, offset); } - nativeWindow(targetWindow)->present(); + nativeWindow(targetWindow)->present(region); } void QWindowsDirect2DBackingStore::resize(const QSize &size, const QRegion ®ion) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index f131419140..a4e75f6571 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -343,7 +343,7 @@ public: D2D1::IdentityMatrix(), 1.0, NULL, - D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND), + D2D1_LAYER_OPTIONS1_NONE), NULL); pushedClips.push(LayerClip); } @@ -953,7 +953,7 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev) D2D1::IdentityMatrix(), 1.0, NULL, - D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND), + D2D1_LAYER_OPTIONS1_NONE), NULL); } else { QRect clip(0, 0, pdev->width(), pdev->height()); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp index 15ec0c3526..37987931b3 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -54,30 +54,15 @@ QT_BEGIN_NAMESPACE QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data) : QWindowsWindow(window, data) , m_needsFullFlush(true) + , m_directRendering(!(data.flags & Qt::FramelessWindowHint && window->format().hasAlpha())) { if (window->type() == Qt::Desktop) return; // No further handling for Qt::Desktop - DXGI_SWAP_CHAIN_DESC1 desc = {}; - - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - desc.SampleDesc.Count = 1; - desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.BufferCount = 1; - desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; - - HRESULT hr = QWindowsDirect2DContext::instance()->dxgiFactory()->CreateSwapChainForHwnd( - QWindowsDirect2DContext::instance()->d3dDevice(), // [in] IUnknown *pDevice - handle(), // [in] HWND hWnd - &desc, // [in] const DXGI_SWAP_CHAIN_DESC1 *pDesc - NULL, // [in] const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc - NULL, // [in] IDXGIOutput *pRestrictToOutput - m_swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain - - if (FAILED(hr)) - qWarning("%s: Could not create swap chain: %#x", __FUNCTION__, hr); + if (m_directRendering) + setupSwapChain(); - hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext( + HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext( D2D1_DEVICE_CONTEXT_OPTIONS_NONE, m_deviceContext.GetAddressOf()); if (FAILED(hr)) @@ -88,6 +73,17 @@ QWindowsDirect2DWindow::~QWindowsDirect2DWindow() { } +void QWindowsDirect2DWindow::setWindowFlags(Qt::WindowFlags flags) +{ + m_directRendering = !(flags & Qt::FramelessWindowHint && window()->format().hasAlpha()); + if (!m_directRendering) + m_swapChain.Reset(); // No need for the swap chain; release from memory + else if (!m_swapChain) + setupSwapChain(); + + QWindowsWindow::setWindowFlags(flags); +} + QPixmap *QWindowsDirect2DWindow::pixmap() { setupBitmap(); @@ -97,13 +93,20 @@ QPixmap *QWindowsDirect2DWindow::pixmap() void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset) { - DXGI_SWAP_CHAIN_DESC1 desc; - HRESULT hr = m_swapChain->GetDesc1(&desc); - QRect geom = geometry(); - - if (FAILED(hr) || (desc.Width != geom.width()) || (desc.Height != geom.height())) { - resizeSwapChain(geom.size()); - m_swapChain->GetDesc1(&desc); + QSize size; + if (m_directRendering) { + DXGI_SWAP_CHAIN_DESC1 desc; + HRESULT hr = m_swapChain->GetDesc1(&desc); + QRect geom = geometry(); + + if ((FAILED(hr) || (desc.Width != geom.width()) || (desc.Height != geom.height()))) { + resizeSwapChain(geom.size()); + m_swapChain->GetDesc1(&desc); + } + size.setWidth(desc.Width); + size.setHeight(desc.Height); + } else { + size = geometry().size(); } setupBitmap(); @@ -116,7 +119,7 @@ void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion ID2D1DeviceContext *dc = m_bitmap->deviceContext()->get(); if (!m_needsFullFlush) { QRegion clipped = region; - clipped &= QRect(0, 0, desc.Width, desc.Height); + clipped &= QRect(QPoint(), size); foreach (const QRect &rect, clipped.rects()) { QRectF rectF(rect); @@ -127,7 +130,7 @@ void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion to_d2d_rect_f(rectF.translated(offset.x(), offset.y()))); } } else { - QRectF rectF(0, 0, desc.Width, desc.Height); + QRectF rectF(QPoint(), size); dc->DrawBitmap(bitmap->bitmap(), to_d2d_rect_f(rectF), 1.0, @@ -140,9 +143,66 @@ void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion } } -void QWindowsDirect2DWindow::present() +void QWindowsDirect2DWindow::present(const QRegion ®ion) { - m_swapChain->Present(0, 0); + if (m_directRendering) { + m_swapChain->Present(0, 0); + return; + } + + ComPtr<IDXGISurface> bitmapSurface; + HRESULT hr = m_bitmap->bitmap()->GetSurface(&bitmapSurface); + Q_ASSERT(SUCCEEDED(hr)); + ComPtr<IDXGISurface1> dxgiSurface; + hr = bitmapSurface.As(&dxgiSurface); + Q_ASSERT(SUCCEEDED(hr)); + + HDC hdc; + hr = dxgiSurface->GetDC(FALSE, &hdc); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get DC for presenting the surface"); + return; + } + + const QRect bounds = window()->geometry(); + const SIZE size = { bounds.width(), bounds.height() }; + const POINT ptDst = { bounds.x(), bounds.y() }; + const POINT ptSrc = { 0, 0 }; + const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255.0 * opacity(), AC_SRC_ALPHA }; + const QRect r = region.boundingRect(); + const RECT dirty = { r.left(), r.top(), r.left() + r.width(), r.top() + r.height() }; + UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), NULL, + &ptDst, &size, hdc, &ptSrc, 0, &blend, ULW_ALPHA, &dirty }; + if (!UpdateLayeredWindowIndirect(handle(), &info)) + qErrnoWarning(GetLastError(), "Failed to update the layered window"); + + hr = dxgiSurface->ReleaseDC(NULL); + if (FAILED(hr)) + qErrnoWarning(hr, "Failed to release the DC for presentation"); +} + +void QWindowsDirect2DWindow::setupSwapChain() +{ + DXGI_SWAP_CHAIN_DESC1 desc = {}; + + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 1; + desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; + + HRESULT hr = QWindowsDirect2DContext::instance()->dxgiFactory()->CreateSwapChainForHwnd( + QWindowsDirect2DContext::instance()->d3dDevice(), // [in] IUnknown *pDevice + handle(), // [in] HWND hWnd + &desc, // [in] const DXGI_SWAP_CHAIN_DESC1 *pDesc + NULL, // [in] const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc + NULL, // [in] IDXGIOutput *pRestrictToOutput + m_swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain + + if (FAILED(hr)) + qWarning("%s: Could not create swap chain: %#x", __FUNCTION__, hr); + + m_needsFullFlush = true; } void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size) @@ -209,14 +269,34 @@ void QWindowsDirect2DWindow::setupBitmap() if (!m_deviceContext) return; - if (!m_swapChain) + if (m_directRendering && !m_swapChain) return; + HRESULT hr; ComPtr<IDXGISurface1> backBufferSurface; - HRESULT hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface)); - if (FAILED(hr)) { - qWarning("%s: Could not query backbuffer for DXGI Surface: %#x", __FUNCTION__, hr); - return; + if (m_directRendering) { + hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface)); + if (FAILED(hr)) { + qWarning("%s: Could not query backbuffer for DXGI Surface: %#x", __FUNCTION__, hr); + return; + } + } else { + const QRect rect = geometry(); + CD3D11_TEXTURE2D_DESC backBufferDesc(DXGI_FORMAT_B8G8R8A8_UNORM, rect.width(), rect.height(), 1, 1); + backBufferDesc.BindFlags = D3D11_BIND_RENDER_TARGET; + backBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE; + ComPtr<ID3D11Texture2D> backBufferTexture; + HRESULT hr = QWindowsDirect2DContext::instance()->d3dDevice()->CreateTexture2D(&backBufferDesc, NULL, &backBufferTexture); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to create backing texture for indirect rendering"); + return; + } + + hr = backBufferTexture.As(&backBufferSurface); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to cast back buffer surface to DXGI surface"); + return; + } } ComPtr<ID2D1Bitmap1> backBufferBitmap; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h index 47c790da5d..6835c9cf6f 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h @@ -56,9 +56,12 @@ public: QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data); ~QWindowsDirect2DWindow(); + void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; + QPixmap *pixmap(); void flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset); - void present(); + void present(const QRegion ®ion); + void setupSwapChain(); void resizeSwapChain(const QSize &size); QSharedPointer<QWindowsDirect2DBitmap> copyBackBuffer() const; @@ -72,6 +75,7 @@ private: QScopedPointer<QWindowsDirect2DBitmap> m_bitmap; QScopedPointer<QPixmap> m_pixmap; bool m_needsFullFlush; + bool m_directRendering; }; QT_END_NAMESPACE |