Direct2D QPA: Draw directly to swap chain
Remove the intermediate pixmap in the backing store and draw directly to the window swap chain. This is faster and reduces memory pressure on the graphics card. In case of native child widgets we need to read back the back buffer, which incurs an extra copy in this case. In an artificial benchmark drawing animated full screen gradients as fast as possible this patch increases performance by 42% on my current machine from 480fps to around 680fps, i.e. the time for actually getting the pixels to the screen is now lower. Change-Id: Ifbeda0e199afec03cecfe76337679a9e9d082bdd Reviewed-by: Risto Avila <risto.avila@digia.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Andrew Knight <andrew.knight@digia.com>
This commit is contained in:
parent
89b70f3910
commit
ac448335f1
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -66,6 +66,16 @@ static inline QWindowsDirect2DPlatformPixmap *platformPixmap(QPixmap *p)
|
||||
return static_cast<QWindowsDirect2DPlatformPixmap *>(p->handle());
|
||||
}
|
||||
|
||||
static inline QWindowsDirect2DBitmap *bitmap(QPixmap *p)
|
||||
{
|
||||
return platformPixmap(p)->bitmap();
|
||||
}
|
||||
|
||||
static inline QWindowsDirect2DWindow *nativeWindow(QWindow *window)
|
||||
{
|
||||
return static_cast<QWindowsDirect2DWindow *>(window->handle());
|
||||
}
|
||||
|
||||
QWindowsDirect2DBackingStore::QWindowsDirect2DBackingStore(QWindow *window)
|
||||
: QPlatformBackingStore(window)
|
||||
{
|
||||
@ -77,36 +87,40 @@ QWindowsDirect2DBackingStore::~QWindowsDirect2DBackingStore()
|
||||
|
||||
void QWindowsDirect2DBackingStore::beginPaint(const QRegion &)
|
||||
{
|
||||
platformPixmap(m_pixmap.data())->bitmap()->deviceContext()->begin();
|
||||
bitmap(nativeWindow(window())->pixmap())->deviceContext()->begin();
|
||||
}
|
||||
|
||||
void QWindowsDirect2DBackingStore::endPaint()
|
||||
{
|
||||
platformPixmap(m_pixmap.data())->bitmap()->deviceContext()->end();
|
||||
bitmap(nativeWindow(window())->pixmap())->deviceContext()->end();
|
||||
}
|
||||
|
||||
QPaintDevice *QWindowsDirect2DBackingStore::paintDevice()
|
||||
{
|
||||
return m_pixmap.data();
|
||||
return nativeWindow(window())->pixmap();
|
||||
}
|
||||
|
||||
void QWindowsDirect2DBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset)
|
||||
void QWindowsDirect2DBackingStore::flush(QWindow *targetWindow, const QRegion ®ion, const QPoint &offset)
|
||||
{
|
||||
QPlatformWindow *pw = window->handle();
|
||||
if (pw && m_pixmap)
|
||||
static_cast<QWindowsDirect2DWindow *>(pw)->flush(platformPixmap(m_pixmap.data())->bitmap(), region, offset);
|
||||
if (targetWindow != window()) {
|
||||
QSharedPointer<QWindowsDirect2DBitmap> copy(nativeWindow(window())->copyBackBuffer());
|
||||
nativeWindow(targetWindow)->flush(copy.data(), region, offset);
|
||||
}
|
||||
|
||||
nativeWindow(targetWindow)->present();
|
||||
}
|
||||
|
||||
void QWindowsDirect2DBackingStore::resize(const QSize &size, const QRegion ®ion)
|
||||
{
|
||||
Q_UNUSED(region);
|
||||
QPixmap old = nativeWindow(window())->pixmap()->copy();
|
||||
|
||||
QScopedPointer<QPixmap> oldPixmap(m_pixmap.take());
|
||||
m_pixmap.reset(new QPixmap(size.width(), size.height()));
|
||||
nativeWindow(window())->resizeSwapChain(size);
|
||||
QPixmap *newPixmap = nativeWindow(window())->pixmap();
|
||||
|
||||
if (oldPixmap) {
|
||||
foreach (const QRect &rect, region.rects())
|
||||
platformPixmap(m_pixmap.data())->copy(oldPixmap->handle(), rect);
|
||||
if (!old.isNull()) {
|
||||
foreach (const QRect &rect, region.rects()) {
|
||||
platformPixmap(newPixmap)->copy(old.handle(), rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -50,6 +50,8 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWindowsDirect2DWindow;
|
||||
|
||||
class QWindowsDirect2DBackingStore : public QPlatformBackingStore
|
||||
{
|
||||
Q_DISABLE_COPY(QWindowsDirect2DBackingStore)
|
||||
@ -62,11 +64,8 @@ public:
|
||||
void endPaint();
|
||||
|
||||
QPaintDevice *paintDevice() Q_DECL_OVERRIDE;
|
||||
void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE;
|
||||
void flush(QWindow *targetWindow, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE;
|
||||
void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
QScopedPointer<QPixmap> m_pixmap;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -56,12 +56,27 @@ class QWindowsDirect2DPlatformPixmapPrivate
|
||||
{
|
||||
public:
|
||||
QWindowsDirect2DPlatformPixmapPrivate()
|
||||
: bitmap(new QWindowsDirect2DBitmap)
|
||||
, device(new QWindowsDirect2DPaintDevice(bitmap.data(), QInternal::Pixmap))
|
||||
: owns_bitmap(true)
|
||||
, bitmap(new QWindowsDirect2DBitmap)
|
||||
, device(new QWindowsDirect2DPaintDevice(bitmap, QInternal::Pixmap))
|
||||
, devicePixelRatio(1.0)
|
||||
{}
|
||||
|
||||
QScopedPointer<QWindowsDirect2DBitmap> bitmap;
|
||||
QWindowsDirect2DPlatformPixmapPrivate(QWindowsDirect2DBitmap *bitmap)
|
||||
: owns_bitmap(false)
|
||||
, bitmap(bitmap)
|
||||
, device(new QWindowsDirect2DPaintDevice(bitmap, QInternal::Pixmap))
|
||||
, devicePixelRatio(1.0)
|
||||
{}
|
||||
|
||||
~QWindowsDirect2DPlatformPixmapPrivate()
|
||||
{
|
||||
if (owns_bitmap)
|
||||
delete bitmap;
|
||||
}
|
||||
|
||||
bool owns_bitmap;
|
||||
QWindowsDirect2DBitmap *bitmap;
|
||||
QScopedPointer<QWindowsDirect2DPaintDevice> device;
|
||||
qreal devicePixelRatio;
|
||||
};
|
||||
@ -75,6 +90,19 @@ QWindowsDirect2DPlatformPixmap::QWindowsDirect2DPlatformPixmap(PixelType pixelTy
|
||||
setSerialNumber(qt_d2dpixmap_serno++);
|
||||
}
|
||||
|
||||
QWindowsDirect2DPlatformPixmap::QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixelType pixelType,
|
||||
QWindowsDirect2DBitmap *bitmap)
|
||||
: QPlatformPixmap(pixelType, Direct2DClass)
|
||||
, d_ptr(new QWindowsDirect2DPlatformPixmapPrivate(bitmap))
|
||||
{
|
||||
setSerialNumber(qt_d2dpixmap_serno++);
|
||||
|
||||
is_null = false;
|
||||
w = bitmap->size().width();
|
||||
h = bitmap->size().height();
|
||||
this->d = 32;
|
||||
}
|
||||
|
||||
QWindowsDirect2DPlatformPixmap::~QWindowsDirect2DPlatformPixmap()
|
||||
{
|
||||
|
||||
@ -173,7 +201,7 @@ void QWindowsDirect2DPlatformPixmap::setDevicePixelRatio(qreal scaleFactor)
|
||||
QWindowsDirect2DBitmap *QWindowsDirect2DPlatformPixmap::bitmap() const
|
||||
{
|
||||
Q_D(const QWindowsDirect2DPlatformPixmap);
|
||||
return d->bitmap.data();
|
||||
return d->bitmap;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -55,6 +55,9 @@ class QWindowsDirect2DPlatformPixmap : public QPlatformPixmap
|
||||
Q_DECLARE_PRIVATE(QWindowsDirect2DPlatformPixmap)
|
||||
public:
|
||||
QWindowsDirect2DPlatformPixmap(PixelType pixelType);
|
||||
|
||||
// We do NOT take ownership of the bitmap through this constructor!
|
||||
QWindowsDirect2DPlatformPixmap(PixelType pixelType, QWindowsDirect2DBitmap *bitmap);
|
||||
~QWindowsDirect2DPlatformPixmap();
|
||||
|
||||
virtual void resize(int width, int height);
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "qwindowsdirect2dwindow.h"
|
||||
#include "qwindowsdirect2ddevicecontext.h"
|
||||
#include "qwindowsdirect2dhelpers.h"
|
||||
#include "qwindowsdirect2dplatformpixmap.h"
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <d2d1_1.h>
|
||||
@ -87,6 +88,13 @@ QWindowsDirect2DWindow::~QWindowsDirect2DWindow()
|
||||
{
|
||||
}
|
||||
|
||||
QPixmap *QWindowsDirect2DWindow::pixmap()
|
||||
{
|
||||
setupBitmap();
|
||||
|
||||
return m_pixmap.data();
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset)
|
||||
{
|
||||
DXGI_SWAP_CHAIN_DESC1 desc;
|
||||
@ -102,32 +110,38 @@ void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion
|
||||
if (!m_bitmap)
|
||||
return;
|
||||
|
||||
m_bitmap->deviceContext()->begin();
|
||||
if (bitmap != m_bitmap.data()) {
|
||||
m_bitmap->deviceContext()->begin();
|
||||
|
||||
ID2D1DeviceContext *dc = m_bitmap->deviceContext()->get();
|
||||
if (!m_needsFullFlush) {
|
||||
QRegion clipped = region;
|
||||
clipped &= QRect(0, 0, desc.Width, desc.Height);
|
||||
ID2D1DeviceContext *dc = m_bitmap->deviceContext()->get();
|
||||
if (!m_needsFullFlush) {
|
||||
QRegion clipped = region;
|
||||
clipped &= QRect(0, 0, desc.Width, desc.Height);
|
||||
|
||||
foreach (const QRect &rect, clipped.rects()) {
|
||||
QRectF rectF(rect);
|
||||
foreach (const QRect &rect, clipped.rects()) {
|
||||
QRectF rectF(rect);
|
||||
dc->DrawBitmap(bitmap->bitmap(),
|
||||
to_d2d_rect_f(rectF),
|
||||
1.0,
|
||||
D2D1_INTERPOLATION_MODE_LINEAR,
|
||||
to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
|
||||
}
|
||||
} else {
|
||||
QRectF rectF(0, 0, desc.Width, desc.Height);
|
||||
dc->DrawBitmap(bitmap->bitmap(),
|
||||
to_d2d_rect_f(rectF),
|
||||
1.0,
|
||||
D2D1_INTERPOLATION_MODE_LINEAR,
|
||||
to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
|
||||
m_needsFullFlush = false;
|
||||
}
|
||||
} else {
|
||||
QRectF rectF(0, 0, desc.Width, desc.Height);
|
||||
dc->DrawBitmap(bitmap->bitmap(),
|
||||
to_d2d_rect_f(rectF),
|
||||
1.0,
|
||||
D2D1_INTERPOLATION_MODE_LINEAR,
|
||||
to_d2d_rect_f(rectF.translated(offset.x(), offset.y())));
|
||||
m_needsFullFlush = false;
|
||||
}
|
||||
|
||||
m_bitmap->deviceContext()->end();
|
||||
m_bitmap->deviceContext()->end();
|
||||
}
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::present()
|
||||
{
|
||||
m_swapChain->Present(0, 0);
|
||||
}
|
||||
|
||||
@ -136,6 +150,7 @@ void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size)
|
||||
if (!m_swapChain)
|
||||
return;
|
||||
|
||||
m_pixmap.reset();
|
||||
m_bitmap.reset();
|
||||
m_deviceContext->SetTarget(Q_NULLPTR);
|
||||
|
||||
@ -149,6 +164,43 @@ void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size)
|
||||
m_needsFullFlush = true;
|
||||
}
|
||||
|
||||
QSharedPointer<QWindowsDirect2DBitmap> QWindowsDirect2DWindow::copyBackBuffer() const
|
||||
{
|
||||
const QSharedPointer<QWindowsDirect2DBitmap> null_result;
|
||||
|
||||
if (!m_bitmap)
|
||||
return null_result;
|
||||
|
||||
D2D1_PIXEL_FORMAT format = m_bitmap->bitmap()->GetPixelFormat();
|
||||
D2D1_SIZE_U size = m_bitmap->bitmap()->GetPixelSize();
|
||||
|
||||
FLOAT dpiX, dpiY;
|
||||
m_bitmap->bitmap()->GetDpi(&dpiX, &dpiY);
|
||||
|
||||
D2D1_BITMAP_PROPERTIES1 properties = {
|
||||
format, // D2D1_PIXEL_FORMAT pixelFormat;
|
||||
dpiX, // FLOAT dpiX;
|
||||
dpiY, // FLOAT dpiY;
|
||||
D2D1_BITMAP_OPTIONS_TARGET, // D2D1_BITMAP_OPTIONS bitmapOptions;
|
||||
Q_NULLPTR // _Field_size_opt_(1) ID2D1ColorContext *colorContext;
|
||||
};
|
||||
ComPtr<ID2D1Bitmap1> copy;
|
||||
HRESULT hr = m_deviceContext.Get()->CreateBitmap(size, NULL, 0, properties, ©);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not create staging bitmap: %#x", __FUNCTION__, hr);
|
||||
return null_result;
|
||||
}
|
||||
|
||||
hr = copy.Get()->CopyFromBitmap(NULL, m_bitmap->bitmap(), NULL);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("%s: Could not copy from bitmap! %#x", __FUNCTION__, hr);
|
||||
return null_result;
|
||||
}
|
||||
|
||||
return QSharedPointer<QWindowsDirect2DBitmap>(new QWindowsDirect2DBitmap(copy.Get(), Q_NULLPTR));
|
||||
}
|
||||
|
||||
void QWindowsDirect2DWindow::setupBitmap()
|
||||
{
|
||||
if (m_bitmap)
|
||||
@ -175,6 +227,10 @@ void QWindowsDirect2DWindow::setupBitmap()
|
||||
}
|
||||
|
||||
m_bitmap.reset(new QWindowsDirect2DBitmap(backBufferBitmap.Get(), m_deviceContext.Get()));
|
||||
|
||||
QWindowsDirect2DPlatformPixmap *pp = new QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixmapType,
|
||||
m_bitmap.data());
|
||||
m_pixmap.reset(new QPixmap(pp));
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -56,16 +56,21 @@ public:
|
||||
QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data);
|
||||
~QWindowsDirect2DWindow();
|
||||
|
||||
QPixmap *pixmap();
|
||||
void flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset);
|
||||
void present();
|
||||
void resizeSwapChain(const QSize &size);
|
||||
|
||||
QSharedPointer<QWindowsDirect2DBitmap> copyBackBuffer() const;
|
||||
|
||||
private:
|
||||
void resizeSwapChain(const QSize &size);
|
||||
void setupBitmap();
|
||||
|
||||
private:
|
||||
Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain;
|
||||
Microsoft::WRL::ComPtr<ID2D1DeviceContext> m_deviceContext;
|
||||
QScopedPointer<QWindowsDirect2DBitmap> m_bitmap;
|
||||
QScopedPointer<QPixmap> m_pixmap;
|
||||
bool m_needsFullFlush;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user