aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp')
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp361
1 files changed, 240 insertions, 121 deletions
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
index 45b9de9ece..2644c693ce 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
@@ -42,6 +42,7 @@
#include "cs_mipmapgen.hlslh"
#include <QString>
#include <QColor>
+#include <QLoggingCategory>
#include <qmath.h>
#include <qalgorithms.h>
@@ -69,18 +70,30 @@ QT_BEGIN_NAMESPACE
{ static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
DECLARE_DEBUG_VAR(render)
+DECLARE_DEBUG_VAR(descheap)
+DECLARE_DEBUG_VAR(buffer)
+DECLARE_DEBUG_VAR(texture)
+
+// Except for system info on startup.
+Q_LOGGING_CATEGORY(QSG_LOG_INFO_GENERAL, "qt.scenegraph.general")
+
+
+// Any changes to the defaults below must be reflected in adaptations.qdoc as
+// well and proven by qmlbench or similar.
static const int DEFAULT_SWAP_CHAIN_BUFFER_COUNT = 3;
static const int DEFAULT_FRAME_IN_FLIGHT_COUNT = 2;
static const int DEFAULT_WAITABLE_SWAP_CHAIN_MAX_LATENCY = 0;
-static const int MAX_DRAW_CALLS_PER_LIST = 128;
+static const int MAX_DRAW_CALLS_PER_LIST = 4096;
static const int MAX_CACHED_ROOTSIG = 16;
static const int MAX_CACHED_PSO = 64;
static const int GPU_CBVSRVUAV_DESCRIPTORS = 512;
+static const DXGI_FORMAT RT_COLOR_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
+
static const int BUCKETS_PER_HEAP = 8; // must match freeMap
static const int DESCRIPTORS_PER_BUCKET = 32; // the bit map (freeMap) is quint32
static const int MAX_DESCRIPTORS_PER_HEAP = BUCKETS_PER_HEAP * DESCRIPTORS_PER_BUCKET;
@@ -94,8 +107,8 @@ D3D12_CPU_DESCRIPTOR_HANDLE QSGD3D12CPUDescriptorHeapManager::allocate(D3D12_DES
if (heap.freeMap[bucket]) {
uint freePos = qCountTrailingZeroBits(heap.freeMap[bucket]);
heap.freeMap[bucket] &= ~(1UL << freePos);
- if (Q_UNLIKELY(debug_render()))
- qDebug("descriptor handle type %x reserve in bucket %d index %d", type, bucket, freePos);
+ if (Q_UNLIKELY(debug_descheap()))
+ qDebug("descriptor handle heap %p type %x reserve in bucket %d index %d", &heap, type, bucket, freePos);
freePos += bucket * DESCRIPTORS_PER_BUCKET;
h = heap.start;
h.ptr += freePos * heap.handleSize;
@@ -121,7 +134,7 @@ D3D12_CPU_DESCRIPTOR_HANDLE QSGD3D12CPUDescriptorHeapManager::allocate(D3D12_DES
heap.start = heap.heap->GetCPUDescriptorHandleForHeapStart();
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_descheap()))
qDebug("new descriptor heap, type %x, start %llu", type, heap.start.ptr);
heap.freeMap[0] = 0xFFFFFFFE;
@@ -145,8 +158,8 @@ void QSGD3D12CPUDescriptorHeapManager::release(D3D12_CPU_DESCRIPTOR_HANDLE handl
const int bucket = pos / DESCRIPTORS_PER_BUCKET;
const int indexInBucket = pos - bucket * DESCRIPTORS_PER_BUCKET;
heap.freeMap[bucket] |= 1UL << indexInBucket;
- if (Q_UNLIKELY(debug_render()))
- qDebug("free descriptor handle type %x bucket %d index %d", type, bucket, indexInBucket);
+ if (Q_UNLIKELY(debug_descheap()))
+ qDebug("free descriptor handle heap %p type %x bucket %d index %d", &heap, type, bucket, indexInBucket);
return;
}
}
@@ -184,18 +197,22 @@ static void getHardwareAdapter(IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapte
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
const QString name = QString::fromUtf16((char16_t *) desc.Description);
- qDebug("Adapter %d: '%s' (flags 0x%x)", adapterIndex, qPrintable(name), desc.Flags);
+ qCDebug(QSG_LOG_INFO_GENERAL, "Adapter %d: '%s' (flags 0x%x)", adapterIndex, qPrintable(name), desc.Flags);
}
if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX")) {
const int adapterIndex = qEnvironmentVariableIntValue("QT_D3D_ADAPTER_INDEX");
- if (SUCCEEDED(factory->EnumAdapters1(adapterIndex, &adapter))
- && SUCCEEDED(D3D12CreateDevice(adapter.Get(), fl, _uuidof(ID3D12Device), nullptr))) {
+ if (SUCCEEDED(factory->EnumAdapters1(adapterIndex, &adapter))) {
adapter->GetDesc1(&desc);
const QString name = QString::fromUtf16((char16_t *) desc.Description);
- qDebug("Using requested adapter '%s'", qPrintable(name));
- *outAdapter = adapter.Detach();
- return;
+ HRESULT hr = D3D12CreateDevice(adapter.Get(), fl, _uuidof(ID3D12Device), nullptr);
+ if (SUCCEEDED(hr)) {
+ qCDebug(QSG_LOG_INFO_GENERAL, "Using requested adapter '%s'", qPrintable(name));
+ *outAdapter = adapter.Detach();
+ return;
+ } else {
+ qWarning("Failed to create device for requested adapter '%s': 0x%x", qPrintable(name), hr);
+ }
}
}
@@ -206,7 +223,7 @@ static void getHardwareAdapter(IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapte
if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), fl, _uuidof(ID3D12Device), nullptr))) {
const QString name = QString::fromUtf16((char16_t *) desc.Description);
- qDebug("Using adapter '%s'", qPrintable(name));
+ qCDebug(QSG_LOG_INFO_GENERAL, "Using adapter '%s'", qPrintable(name));
break;
}
}
@@ -270,7 +287,7 @@ void QSGD3D12DeviceManager::ensureCreated()
}
if (warp) {
- qDebug("Using WARP");
+ qCDebug(QSG_LOG_INFO_GENERAL, "Using WARP");
m_factory->EnumWarpAdapter(IID_PPV_ARGS(&adapter));
HRESULT hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
if (FAILED(hr)) {
@@ -283,14 +300,14 @@ void QSGD3D12DeviceManager::ensureCreated()
if (SUCCEEDED(adapter.As(&adapter3))) {
DXGI_QUERY_VIDEO_MEMORY_INFO vidMemInfo;
if (SUCCEEDED(adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &vidMemInfo))) {
- qDebug("Video memory info: LOCAL: Budget %llu KB CurrentUsage %llu KB AvailableForReservation %llu KB CurrentReservation %llu KB",
- vidMemInfo.Budget / 1024, vidMemInfo.CurrentUsage / 1024,
- vidMemInfo.AvailableForReservation / 1024, vidMemInfo.CurrentReservation / 1024);
+ qCDebug(QSG_LOG_INFO_GENERAL, "Video memory info: LOCAL: Budget %llu KB CurrentUsage %llu KB AvailableForReservation %llu KB CurrentReservation %llu KB",
+ vidMemInfo.Budget / 1024, vidMemInfo.CurrentUsage / 1024,
+ vidMemInfo.AvailableForReservation / 1024, vidMemInfo.CurrentReservation / 1024);
}
if (SUCCEEDED(adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &vidMemInfo))) {
- qDebug("Video memory info: NON-LOCAL: Budget %llu KB CurrentUsage %llu KB AvailableForReservation %llu KB CurrentReservation %llu KB",
- vidMemInfo.Budget / 1024, vidMemInfo.CurrentUsage / 1024,
- vidMemInfo.AvailableForReservation / 1024, vidMemInfo.CurrentReservation / 1024);
+ qCDebug(QSG_LOG_INFO_GENERAL, "Video memory info: NON-LOCAL: Budget %llu KB CurrentUsage %llu KB AvailableForReservation %llu KB CurrentReservation %llu KB",
+ vidMemInfo.Budget / 1024, vidMemInfo.CurrentUsage / 1024,
+ vidMemInfo.AvailableForReservation / 1024, vidMemInfo.CurrentReservation / 1024);
}
}
}
@@ -313,14 +330,14 @@ QSGD3D12Engine::~QSGD3D12Engine()
delete d;
}
-bool QSGD3D12Engine::attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples)
+bool QSGD3D12Engine::attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha)
{
if (d->isInitialized()) {
qWarning("QSGD3D12Engine: Cannot attach active engine to window");
return false;
}
- d->initialize(window, size, dpr, surfaceFormatSamples);
+ d->initialize(window, size, dpr, surfaceFormatSamples, alpha);
return d->isInitialized();
}
@@ -480,14 +497,15 @@ void QSGD3D12Engine::queueTextureResize(uint id, const QSize &size)
d->queueTextureResize(id, size);
}
-void QSGD3D12Engine::queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos)
+void QSGD3D12Engine::queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos, TextureUploadFlags flags)
{
- d->queueTextureUpload(id, QVector<QImage>() << image, QVector<QPoint>() << dstPos);
+ d->queueTextureUpload(id, QVector<QImage>() << image, QVector<QPoint>() << dstPos, flags);
}
-void QSGD3D12Engine::queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos)
+void QSGD3D12Engine::queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos,
+ TextureUploadFlags flags)
{
- d->queueTextureUpload(id, images, dstPos);
+ d->queueTextureUpload(id, images, dstPos, flags);
}
void QSGD3D12Engine::releaseTexture(uint id)
@@ -535,31 +553,11 @@ void QSGD3D12Engine::simulateDeviceLoss()
d->simulateDeviceLoss();
}
-QSGRendererInterface::GraphicsApi QSGD3D12Engine::graphicsApi() const
-{
- return Direct3D12;
-}
-
-void *QSGD3D12Engine::getResource(Resource resource) const
+void *QSGD3D12Engine::getResource(QQuickWindow *, QSGRendererInterface::Resource resource) const
{
return d->getResource(resource);
}
-QSGRendererInterface::ShaderType QSGD3D12Engine::shaderType() const
-{
- return HLSL;
-}
-
-QSGRendererInterface::ShaderCompilationTypes QSGD3D12Engine::shaderCompilationType() const
-{
- return OfflineCompilation;
-}
-
-QSGRendererInterface::ShaderSourceTypes QSGD3D12Engine::shaderSourceType() const
-{
- return ShaderByteCode;
-}
-
static inline quint32 alignedSize(quint32 size, quint32 byteAlign)
{
return (size + byteAlign - 1) & ~(byteAlign - 1);
@@ -684,6 +682,13 @@ void QSGD3D12EnginePrivate::releaseResources()
commandQueue = nullptr;
copyCommandQueue = nullptr;
+
+#ifndef Q_OS_WINRT
+ dcompTarget = nullptr;
+ dcompVisual = nullptr;
+ dcompDevice = nullptr;
+#endif
+
swapChain = nullptr;
delete presentFence;
@@ -696,7 +701,7 @@ void QSGD3D12EnginePrivate::releaseResources()
// 'window' must be kept, may just be a device loss
}
-void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples)
+void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha)
{
if (initialized)
return;
@@ -705,6 +710,7 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
windowSize = size;
windowDpr = dpr;
windowSamples = qMax(1, surfaceFormatSamples); // may be -1 or 0, whereas windowSamples is uint and >= 1
+ windowAlpha = alpha;
swapChainBufferCount = qMin(qEnvironmentVariableIntValue("QT_D3D_BUFFER_COUNT"), MAX_SWAP_CHAIN_BUFFER_COUNT);
if (swapChainBufferCount < 2)
@@ -720,22 +726,53 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
else
waitableSwapChainMaxLatency = qBound(0, qEnvironmentVariableIntValue(latReqEnvVar), 16);
- qDebug("d3d12 engine init. swap chain buffer count %d, max frames prepared without blocking %d",
- swapChainBufferCount, frameInFlightCount);
+ if (qEnvironmentVariableIsSet("QSG_INFO"))
+ const_cast<QLoggingCategory &>(QSG_LOG_INFO_GENERAL()).setEnabled(QtDebugMsg, true);
+
+ qCDebug(QSG_LOG_INFO_GENERAL, "d3d12 engine init. swap chain buffer count %d, max frames prepared without blocking %d",
+ swapChainBufferCount, frameInFlightCount);
if (waitableSwapChainMaxLatency)
- qDebug("Swap chain frame latency waitable object enabled. Frame latency is %d", waitableSwapChainMaxLatency);
+ qCDebug(QSG_LOG_INFO_GENERAL, "Swap chain frame latency waitable object enabled. Frame latency is %d", waitableSwapChainMaxLatency);
- if (qEnvironmentVariableIntValue("QT_D3D_DEBUG") != 0) {
- qDebug("Enabling debug layer");
+ const bool debugLayer = qEnvironmentVariableIntValue("QT_D3D_DEBUG") != 0;
+ if (debugLayer) {
+ qCDebug(QSG_LOG_INFO_GENERAL, "Enabling debug layer");
+#if !defined(Q_OS_WINRT) || !defined(NDEBUG)
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
debugController->EnableDebugLayer();
+#else
+ qCDebug(QSG_LOG_INFO_GENERAL, "Using DebugInterface will not allow certification to pass");
+#endif
}
QSGD3D12DeviceManager *dev = deviceManager();
device = dev->ref();
dev->registerDeviceLossObserver(this);
+ if (debugLayer) {
+ ComPtr<ID3D12InfoQueue> infoQueue;
+ if (SUCCEEDED(device->QueryInterface(IID_PPV_ARGS(&infoQueue)))) {
+ infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
+ infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
+ const bool breakOnWarning = qEnvironmentVariableIntValue("QT_D3D_DEBUG_BREAK_ON_WARNING") != 0;
+ infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, breakOnWarning);
+ D3D12_INFO_QUEUE_FILTER filter = {};
+ D3D12_MESSAGE_ID suppressedMessages[] = {
+ // When using a render target other than the default one we
+ // have no way to know the custom clear color, if there is one.
+ D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE
+ };
+ filter.DenyList.NumIDs = _countof(suppressedMessages);
+ filter.DenyList.pIDList = suppressedMessages;
+ // setting the filter would enable Info messages which we don't need
+ D3D12_MESSAGE_SEVERITY infoSev = D3D12_MESSAGE_SEVERITY_INFO;
+ filter.DenyList.NumSeverities = 1;
+ filter.DenyList.pSeverityList = &infoSev;
+ infoQueue->PushStorageFilter(&filter);
+ }
+ }
+
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
if (FAILED(device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)))) {
@@ -752,28 +789,91 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
#ifndef Q_OS_WINRT
HWND hwnd = reinterpret_cast<HWND>(w);
- DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
- swapChainDesc.BufferCount = swapChainBufferCount;
- swapChainDesc.BufferDesc.Width = windowSize.width() * windowDpr;
- swapChainDesc.BufferDesc.Height = windowSize.height() * windowDpr;
- swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // D3D12 requires the flip model
- swapChainDesc.OutputWindow = hwnd;
- swapChainDesc.SampleDesc.Count = 1; // Flip does not support MSAA so no choice here
- swapChainDesc.Windowed = TRUE;
- if (waitableSwapChainMaxLatency)
- swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+ if (windowAlpha) {
+ // Go through DirectComposition for semi-transparent windows since the
+ // traditional approaches won't fly with flip model swapchains.
+ HRESULT hr = DCompositionCreateDevice(nullptr, IID_PPV_ARGS(&dcompDevice));
+ if (SUCCEEDED(hr)) {
+ hr = dcompDevice->CreateTargetForHwnd(hwnd, true, &dcompTarget);
+ if (SUCCEEDED(hr)) {
+ hr = dcompDevice->CreateVisual(&dcompVisual);
+ if (FAILED(hr)) {
+ qWarning("Failed to create DirectComposition visual: 0x%x", hr);
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("Failed to create DirectComposition target: 0x%x", hr);
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("Failed to create DirectComposition device: 0x%x", hr);
+ windowAlpha = false;
+ }
+ }
- ComPtr<IDXGISwapChain> baseSwapChain;
- HRESULT hr = dev->dxgi()->CreateSwapChain(commandQueue.Get(), &swapChainDesc, &baseSwapChain);
- if (FAILED(hr)) {
- qWarning("Failed to create swap chain: 0x%x", hr);
- return;
+ if (windowAlpha) {
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
+ swapChainDesc.Width = windowSize.width() * windowDpr;
+ swapChainDesc.Height = windowSize.height() * windowDpr;
+ swapChainDesc.Format = RT_COLOR_FORMAT;
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.BufferCount = swapChainBufferCount;
+ swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
+ swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
+ if (waitableSwapChainMaxLatency)
+ swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+
+ ComPtr<IDXGISwapChain1> baseSwapChain;
+ HRESULT hr = dev->dxgi()->CreateSwapChainForComposition(commandQueue.Get(), &swapChainDesc, nullptr, &baseSwapChain);
+ if (SUCCEEDED(hr)) {
+ if (SUCCEEDED(baseSwapChain.As(&swapChain))) {
+ hr = dcompVisual->SetContent(swapChain.Get());
+ if (SUCCEEDED(hr)) {
+ hr = dcompTarget->SetRoot(dcompVisual.Get());
+ if (FAILED(hr)) {
+ qWarning("SetRoot failed for DirectComposition target: 0x%x", hr);
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("SetContent failed for DirectComposition visual: 0x%x", hr);
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("Failed to cast swap chain");
+ windowAlpha = false;
+ }
+ } else {
+ qWarning("Failed to create swap chain for composition: 0x%x", hr);
+ windowAlpha = false;
+ }
}
- if (FAILED(baseSwapChain.As(&swapChain))) {
- qWarning("Failed to cast swap chain");
- return;
+
+ if (!windowAlpha) {
+ DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
+ swapChainDesc.BufferCount = swapChainBufferCount;
+ swapChainDesc.BufferDesc.Width = windowSize.width() * windowDpr;
+ swapChainDesc.BufferDesc.Height = windowSize.height() * windowDpr;
+ swapChainDesc.BufferDesc.Format = RT_COLOR_FORMAT;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // D3D12 requires the flip model
+ swapChainDesc.OutputWindow = hwnd;
+ swapChainDesc.SampleDesc.Count = 1; // Flip does not support MSAA so no choice here
+ swapChainDesc.Windowed = TRUE;
+ if (waitableSwapChainMaxLatency)
+ swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+
+ ComPtr<IDXGISwapChain> baseSwapChain;
+ HRESULT hr = dev->dxgi()->CreateSwapChain(commandQueue.Get(), &swapChainDesc, &baseSwapChain);
+ if (FAILED(hr)) {
+ qWarning("Failed to create swap chain: 0x%x", hr);
+ return;
+ }
+ if (FAILED(baseSwapChain.As(&swapChain))) {
+ qWarning("Failed to cast swap chain");
+ return;
+ }
}
dev->dxgi()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
@@ -781,7 +881,7 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = windowSize.width() * windowDpr;
swapChainDesc.Height = windowSize.height() * windowDpr;
- swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swapChainDesc.Format = RT_COLOR_FORMAT;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = swapChainBufferCount;
@@ -798,7 +898,7 @@ void QSGD3D12EnginePrivate::initialize(WId w, const QSize &size, float dpr, int
return;
}
if (FAILED(baseSwapChain.As(&swapChain))) {
- qWarning("Failed to case swap chain");
+ qWarning("Failed to cast swap chain");
return;
}
@@ -932,7 +1032,7 @@ ID3D12Resource *QSGD3D12EnginePrivate::createColorBuffer(D3D12_CPU_DESCRIPTOR_HA
const QVector4D &clearColor, uint samples)
{
D3D12_CLEAR_VALUE clearValue = {};
- clearValue.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ clearValue.Format = RT_COLOR_FORMAT;
clearValue.Color[0] = clearColor.x();
clearValue.Color[1] = clearColor.y();
clearValue.Color[2] = clearColor.z();
@@ -947,7 +1047,7 @@ ID3D12Resource *QSGD3D12EnginePrivate::createColorBuffer(D3D12_CPU_DESCRIPTOR_HA
rtDesc.Height = size.height();
rtDesc.DepthOrArraySize = 1;
rtDesc.MipLevels = 1;
- rtDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ rtDesc.Format = RT_COLOR_FORMAT;
rtDesc.SampleDesc = makeSampleDesc(rtDesc.Format, samples);
rtDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
@@ -1013,7 +1113,9 @@ void QSGD3D12EnginePrivate::setupDefaultRenderTargets()
device->CreateRenderTargetView(defaultRT[i].Get(), nullptr, defaultRTV[i]);
} else {
const QSize size(windowSize.width() * windowDpr, windowSize.height() * windowDpr);
- const QColor cc(Qt::white); // ### what if setClearColor? non-fatal but debug layer warns...
+ // Not optimal if the user called setClearColor, but there's so
+ // much we can do. The debug layer warning is suppressed so we're good to go.
+ const QColor cc(Qt::white);
const QVector4D clearColor(cc.redF(), cc.greenF(), cc.blueF(), cc.alphaF());
ID3D12Resource *msaaRT = createColorBuffer(defaultRTV[i], size, clearColor, windowSamples);
if (msaaRT)
@@ -1054,7 +1156,7 @@ void QSGD3D12EnginePrivate::setWindowSize(const QSize &size, float dpr)
const int w = windowSize.width() * windowDpr;
const int h = windowSize.height() * windowDpr;
- HRESULT hr = swapChain->ResizeBuffers(swapChainBufferCount, w, h, DXGI_FORMAT_R8G8B8A8_UNORM,
+ HRESULT hr = swapChain->ResizeBuffers(swapChainBufferCount, w, h, RT_COLOR_FORMAT,
waitableSwapChainMaxLatency ? DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT : 0);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
deviceManager()->deviceLossDetected();
@@ -1138,7 +1240,7 @@ void QSGD3D12EnginePrivate::resolveMultisampledTarget(ID3D12Resource *msaa,
barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_RESOLVE_DEST;
commandList->ResourceBarrier(2, barriers);
- commandList->ResolveSubresource(resolve, 0, msaa, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
+ commandList->ResolveSubresource(resolve, 0, msaa, 0, RT_COLOR_FORMAT);
barriers[0].Transition.pResource = msaa;
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_RESOLVE_SOURCE;
@@ -1193,7 +1295,7 @@ void QSGD3D12EnginePrivate::ensureBuffer(Buffer *buf)
// buffer contents rebuild with a slightly larger total size does
// not lead to creating a new buffer.
const quint32 sz = alignedSize(buf->cpuDataRef.size, 4096);
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug("new buffer[pf=%d] of size %d (actual data size %d)", currentPFrameIndex, sz, buf->cpuDataRef.size);
bfd.buffer.Attach(createBuffer(sz));
bfd.resourceSize = sz;
@@ -1215,7 +1317,7 @@ void QSGD3D12EnginePrivate::updateBuffer(Buffer *buf)
return;
}
for (const auto &r : qAsConst(buf->cpuDataRef.dirty)) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug("%p o %d s %d", buf, r.first, r.second);
memcpy(p + r.first, buf->cpuDataRef.p + r.first, r.second);
}
@@ -1226,7 +1328,7 @@ void QSGD3D12EnginePrivate::updateBuffer(Buffer *buf)
void QSGD3D12EnginePrivate::ensureDevice()
{
if (!initialized && window)
- initialize(window, windowSize, windowDpr, windowSamples);
+ initialize(window, windowSize, windowDpr, windowSamples, windowAlpha);
}
void QSGD3D12EnginePrivate::beginFrame()
@@ -1296,13 +1398,13 @@ void QSGD3D12EnginePrivate::beginFrame()
for (uint id : qAsConst(prevFrameData.buffersUsedInFrame)) {
Buffer &b(buffers[id - 1]);
if (b.d[currentPFrameIndex].buffer && b.d[currentPFrameIndex].dataSize == b.cpuDataRef.size) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug() << "frame" << frameIndex << "takes dirty" << b.d[prevPFrameIndex].dirty
<< "from frame" << frameIndex - delta << "for buffer" << id;
for (const auto &range : qAsConst(b.d[prevPFrameIndex].dirty))
addDirtyRange(&b.cpuDataRef.dirty, range.first, range.second, b.cpuDataRef.size);
} else {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug() << "frame" << frameIndex << "makes all dirty from frame" << frameIndex - delta
<< "for buffer" << id;
addDirtyRange(&b.cpuDataRef.dirty, 0, b.cpuDataRef.size, b.cpuDataRef.size);
@@ -1316,7 +1418,7 @@ void QSGD3D12EnginePrivate::beginFrame()
const quint64 finishedFrameIndex = frameIndex - frameInFlightCount; // we know since we just blocked for this
// pfd conveniently refers to the same slot that was used by that frame
if (!pfd.pendingTextureUploads.isEmpty()) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("Removing texture upload data for frame %d", finishedFrameIndex);
for (uint id : qAsConst(pfd.pendingTextureUploads)) {
const int idx = id - 1;
@@ -1330,13 +1432,13 @@ void QSGD3D12EnginePrivate::beginFrame()
t.lastWaitFenceValue = 0;
t.stagingBuffers.clear();
t.stagingHeaps.clear();
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("Cleaned staging data for texture %u", id);
}
}
pfd.pendingTextureUploads.clear();
if (!pfd.pendingTextureMipMap.isEmpty()) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug() << "cleaning mipmap generation data for " << pfd.pendingTextureMipMap;
// no special cleanup is needed as mipmap generation uses the frame's resources
pfd.pendingTextureMipMap.clear();
@@ -1350,7 +1452,7 @@ void QSGD3D12EnginePrivate::beginFrame()
}
}
if (!hasPending) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("no more pending textures");
copyCommandAllocator->Reset();
}
@@ -1471,7 +1573,7 @@ void QSGD3D12EnginePrivate::endDrawCalls(bool lastInFrame)
PersistentFrameData &pfd(pframeData[currentPFrameIndex]);
// Now is the time to sync all the changed areas in the buffers.
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug() << "buffers used in drawcall set" << pfd.buffersUsedInDrawCallSet;
for (uint id : qAsConst(pfd.buffersUsedInDrawCallSet))
updateBuffer(&buffers[id - 1]);
@@ -1496,12 +1598,12 @@ void QSGD3D12EnginePrivate::endDrawCalls(bool lastInFrame)
pfd.pendingTextureMipMap.insert(id);
}
if (topFenceValue) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("added wait for texture fence %llu", topFenceValue);
commandQueue->Wait(textureUploadFence.Get(), topFenceValue);
// Generate mipmaps after the wait, when necessary.
if (!pfd.pendingTextureMipMap.isEmpty()) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug() << "starting mipmap generation for" << pfd.pendingTextureMipMap;
for (uint id : qAsConst(pfd.pendingTextureMipMap))
mipmapper.queueGenerate(textures[id - 1]);
@@ -1580,8 +1682,8 @@ void QSGD3D12EnginePrivate::endLayer()
// Root signature:
// [0] CBV - always present
-// [1] table with 1 SRV per texture (optional)
-// one static sampler per texture (optional)
+// [1] table with one SRV per texture (must be a table since root descriptor SRVs cannot be textures) - optional
+// one static sampler per texture - optional
//
// SRVs can be created freely via QSGD3D12CPUDescriptorHeapManager and stored
// in QSGD3D12TextureView. The engine will copy them onto a dedicated,
@@ -1612,17 +1714,17 @@ void QSGD3D12EnginePrivate::finalizePipeline(const QSGD3D12PipelineState &pipeli
rootParams[0].Descriptor.RegisterSpace = 0;
++rootParamCount;
+ D3D12_DESCRIPTOR_RANGE tvDescRange;
if (pipelineState.shaders.rootSig.textureViewCount > 0) {
rootParams[rootParamCount].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
rootParams[rootParamCount].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
rootParams[rootParamCount].DescriptorTable.NumDescriptorRanges = 1;
- D3D12_DESCRIPTOR_RANGE descRange;
- descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
- descRange.NumDescriptors = pipelineState.shaders.rootSig.textureViewCount;
- descRange.BaseShaderRegister = 0; // t0, t1, ...
- descRange.RegisterSpace = 0;
- descRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
- rootParams[rootParamCount].DescriptorTable.pDescriptorRanges = &descRange;
+ tvDescRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ tvDescRange.NumDescriptors = pipelineState.shaders.rootSig.textureViewCount;
+ tvDescRange.BaseShaderRegister = 0; // t0, t1, ...
+ tvDescRange.RegisterSpace = 0;
+ tvDescRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ rootParams[rootParamCount].DescriptorTable.pDescriptorRanges = &tvDescRange;
++rootParamCount;
}
@@ -1657,7 +1759,8 @@ void QSGD3D12EnginePrivate::finalizePipeline(const QSGD3D12PipelineState &pipeli
ComPtr<ID3DBlob> signature;
ComPtr<ID3DBlob> error;
if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
- qWarning("Failed to serialize root signature");
+ QByteArray msg(static_cast<const char *>(error->GetBufferPointer()), error->GetBufferSize());
+ qWarning("Failed to serialize root signature: %s", qPrintable(msg));
return;
}
if (FAILED(device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(),
@@ -1762,7 +1865,7 @@ void QSGD3D12EnginePrivate::finalizePipeline(const QSGD3D12PipelineState &pipeli
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE(pipelineState.topologyType);
psoDesc.NumRenderTargets = 1;
- psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ psoDesc.RTVFormats[0] = RT_COLOR_FORMAT;
psoDesc.DSVFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
psoDesc.SampleDesc = defaultRT[0]->GetDesc().SampleDesc;
@@ -2046,7 +2149,7 @@ void QSGD3D12EnginePrivate::ensureGPUDescriptorHeap(int cbvSrvUavDescriptorCount
while (pfd.cbvSrvUavNextFreeDescriptorIndex + cbvSrvUavDescriptorCount > newSize)
newSize *= 2;
if (newSize != pfd.gpuCbvSrvUavHeapSize) {
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_descheap()))
qDebug("Out of space for SRVs, creating new CBV-SRV-UAV descriptor heap with descriptor count %d", newSize);
deferredDelete(pfd.gpuCbvSrvUavHeap);
createCbvSrvUavHeap(currentPFrameIndex, newSize);
@@ -2077,6 +2180,11 @@ void QSGD3D12EnginePrivate::present()
return;
}
+#ifndef Q_OS_WINRT
+ if (dcompDevice)
+ dcompDevice->Commit();
+#endif
+
++presentFrameIndex;
}
@@ -2132,7 +2240,7 @@ void QSGD3D12EnginePrivate::releaseBuffer(uint id)
const int idx = id - 1;
Q_ASSERT(idx < buffers.count());
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug("releasing buffer %u", id);
Buffer &b(buffers[idx]);
@@ -2166,7 +2274,7 @@ void QSGD3D12EnginePrivate::resetBuffer(uint id, const quint8 *data, int size)
Q_ASSERT(idx < buffers.count() && buffers[idx].entryInUse());
Buffer &b(buffers[idx]);
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_buffer()))
qDebug("reset buffer %u, size %d", id, size);
b.cpuDataRef.p = data;
@@ -2218,7 +2326,7 @@ uint QSGD3D12EnginePrivate::genTexture()
return id;
}
-static inline DXGI_FORMAT textureFormat(QImage::Format format, bool wantsAlpha, bool mipmap,
+static inline DXGI_FORMAT textureFormat(QImage::Format format, bool wantsAlpha, bool mipmap, bool force32bit,
QImage::Format *imageFormat, int *bytesPerPixel)
{
DXGI_FORMAT f = DXGI_FORMAT_R8G8B8A8_UNORM;
@@ -2230,8 +2338,12 @@ static inline DXGI_FORMAT textureFormat(QImage::Format format, bool wantsAlpha,
case QImage::Format_Grayscale8:
case QImage::Format_Indexed8:
case QImage::Format_Alpha8:
- f = DXGI_FORMAT_R8_UNORM;
- bpp = 1;
+ if (!force32bit) {
+ f = DXGI_FORMAT_R8_UNORM;
+ bpp = 1;
+ } else {
+ convFormat = QImage::Format_RGBA8888;
+ }
break;
case QImage::Format_RGB32:
f = DXGI_FORMAT_B8G8R8A8_UNORM;
@@ -2307,7 +2419,9 @@ void QSGD3D12EnginePrivate::createTexture(uint id, const QSize &size, QImage::Fo
textureDesc.Height = adjustedSize.height();
textureDesc.DepthOrArraySize = 1;
textureDesc.MipLevels = !t.mipmap() ? 1 : QSGD3D12Engine::mipMapLevels(adjustedSize);
- textureDesc.Format = textureFormat(format, t.alpha(), t.mipmap(), nullptr, nullptr);
+ textureDesc.Format = textureFormat(format, t.alpha(), t.mipmap(),
+ createFlags.testFlag(QSGD3D12Engine::TextureAlways32Bit),
+ nullptr, nullptr);
textureDesc.SampleDesc.Count = 1;
textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
if (t.mipmap())
@@ -2344,7 +2458,7 @@ void QSGD3D12EnginePrivate::createTexture(uint id, const QSize &size, QImage::Fo
}
}
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("created texture %u, size %dx%d, miplevels %d", id, adjustedSize.width(), adjustedSize.height(), textureDesc.MipLevels);
}
@@ -2365,7 +2479,7 @@ void QSGD3D12EnginePrivate::queueTextureResize(uint id, const QSize &size)
return;
}
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("resizing texture %u, size %dx%d", id, size.width(), size.height());
D3D12_RESOURCE_DESC textureDesc = t.texture->GetDesc();
@@ -2417,11 +2531,12 @@ void QSGD3D12EnginePrivate::queueTextureResize(uint id, const QSize &size)
t.fenceValue = nextTextureUploadFenceValue.fetchAndAddAcquire(1) + 1;
copyCommandQueue->Signal(textureUploadFence.Get(), t.fenceValue);
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("submitted old content copy for texture %u on the copy queue, fence %llu", id, t.fenceValue);
}
-void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos)
+void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos,
+ QSGD3D12Engine::TextureUploadFlags flags)
{
Q_ASSERT(id);
Q_ASSERT(images.count() == dstPos.count());
@@ -2449,7 +2564,7 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i
t.fenceValue = nextTextureUploadFenceValue.fetchAndAddAcquire(1) + 1;
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("adding upload for texture %u on the copy queue, fence %llu", id, t.fenceValue);
D3D12_RESOURCE_DESC textureDesc = t.texture->GetDesc();
@@ -2458,14 +2573,16 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i
int totalSize = 0;
for (const QImage &image : images) {
int bytesPerPixel;
- textureFormat(image.format(), t.alpha(), t.mipmap(), nullptr, &bytesPerPixel);
+ textureFormat(image.format(), t.alpha(), t.mipmap(),
+ flags.testFlag(QSGD3D12Engine::TextureUploadAlways32Bit),
+ nullptr, &bytesPerPixel);
const int w = !t.mipmap() ? image.width() : adjustedTextureSize.width();
const int h = !t.mipmap() ? image.height() : adjustedTextureSize.height();
const int stride = alignedSize(w * bytesPerPixel, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
totalSize += alignedSize(h * stride, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT);
}
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("%d sub-uploads, heap size %d bytes", images.count(), totalSize);
// Instead of individual committed resources for each upload buffer,
@@ -2490,8 +2607,10 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i
for (int i = 0; i < images.count(); ++i) {
QImage::Format convFormat;
int bytesPerPixel;
- textureFormat(images[i].format(), t.alpha(), t.mipmap(), &convFormat, &bytesPerPixel);
- if (Q_UNLIKELY(debug_render() && i == 0))
+ textureFormat(images[i].format(), t.alpha(), t.mipmap(),
+ flags.testFlag(QSGD3D12Engine::TextureUploadAlways32Bit),
+ &convFormat, &bytesPerPixel);
+ if (Q_UNLIKELY(debug_texture() && i == 0))
qDebug("source image format %d, target format %d, bpp %d", images[i].format(), convFormat, bytesPerPixel);
QImage convImage = images[i].format() == convFormat ? images[i] : images[i].convertToFormat(convFormat);
@@ -2566,7 +2685,7 @@ void QSGD3D12EnginePrivate::releaseTexture(uint id)
const int idx = id - 1;
Q_ASSERT(idx < textures.count());
- if (Q_UNLIKELY(debug_render()))
+ if (Q_UNLIKELY(debug_texture()))
qDebug("releasing texture %d", id);
Texture &t(textures[idx]);
@@ -2825,7 +2944,7 @@ void QSGD3D12EnginePrivate::createRenderTarget(uint id, const QSize &size, const
textureDesc.Height = size.height();
textureDesc.DepthOrArraySize = 1;
textureDesc.MipLevels = 1;
- textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ textureDesc.Format = RT_COLOR_FORMAT;
textureDesc.SampleDesc.Count = 1;
textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;