summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi/qrhid3d11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/rhi/qrhid3d11.cpp')
-rw-r--r--src/gui/rhi/qrhid3d11.cpp2499
1 files changed, 1610 insertions, 889 deletions
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index 8e94d70502..b09baf57b2 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -1,59 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Gui module
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qrhid3d11_p_p.h"
-#include "qshader_p.h"
-#include "cs_tdr_p.h"
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qrhid3d11_p.h"
+#include "qshader.h"
+#include "vs_test_p.h"
#include <QWindow>
-#include <QOperatingSystemVersion>
#include <qmath.h>
-#include <private/qsystemlibrary_p.h>
-
-#include <d3dcompiler.h>
-#include <comdef.h>
-#include <dxgi1_3.h>
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/private/qsystemerror_p.h>
+#include "qrhid3dhelpers_p.h"
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
/*
- Direct3D 11 backend. Provides a double-buffered flip model (FLIP_DISCARD)
- swapchain. Textures and "static" buffers are USAGE_DEFAULT, leaving it to
+ Direct3D 11 backend. Provides a double-buffered flip model swapchain.
+ Textures and "static" buffers are USAGE_DEFAULT, leaving it to
UpdateSubResource to upload the data in any way it sees fit. "Dynamic"
buffers are USAGE_DYNAMIC and updating is done by mapping with WRITE_DISCARD.
(so here QRhiBuffer keeps a copy of the buffer contents and all of it is
@@ -63,10 +26,13 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiD3D11InitParams
- \internal
\inmodule QtGui
+ \since 6.6
\brief Direct3D 11 specific initialization parameters.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
A D3D11-based QRhi needs no special parameters for initialization. If
desired, enableDebugLayer can be set to \c true to enable the Direct3D
debug layer. This can be useful during development, but should be avoided
@@ -79,9 +45,7 @@ QT_BEGIN_NAMESPACE
\endcode
\note QRhiSwapChain should only be used in combination with QWindow
- instances that have their surface type set to QSurface::OpenGLSurface.
- There are currently no Direct3D specifics in the Windows platform support
- of Qt and therefore there is no separate QSurface type available.
+ instances that have their surface type set to QSurface::Direct3DSurface.
\section2 Working with existing Direct3D 11 devices
@@ -107,16 +71,71 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \variable QRhiD3D11InitParams::enableDebugLayer
+
+ When set to true, a debug device is created, assuming the debug layer is
+ available. The default value is false.
+*/
+
+/*!
\class QRhiD3D11NativeHandles
- \internal
\inmodule QtGui
+ \since 6.6
\brief Holds the D3D device and device context used by the QRhi.
\note The class uses \c{void *} as the type since including the COM-based
\c{d3d11.h} headers is not acceptable here. The actual types are
\c{ID3D11Device *} and \c{ID3D11DeviceContext *}.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
+/*!
+ \variable QRhiD3D11NativeHandles::dev
+
+ Points to a
+ \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nn-d3d11-id3d11device}{ID3D11Device}
+ or left set to \nullptr if no existing device is to be imported.
+
+ \note When importing a device, both the device and the device context must be set to valid objects.
+*/
+
+/*!
+ \variable QRhiD3D11NativeHandles::context
+
+ Points to a \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nn-d3d11-id3d11devicecontext}{ID3D11DeviceContext}
+ or left set to \nullptr if no existing device context is to be imported.
+
+ \note When importing a device, both the device and the device context must be set to valid objects.
+*/
+
+/*!
+ \variable QRhiD3D11NativeHandles::featureLevel
+
+ Specifies the feature level passed to
+ \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-d3d11createdevice}{D3D11CreateDevice()}.
+ Relevant only when QRhi creates the device, ignored when importing a device
+ and device context. When not set, the default rules outlined in the D3D
+ documentation apply.
+*/
+
+/*!
+ \variable QRhiD3D11NativeHandles::adapterLuidLow
+
+ The low part of the local identifier (LUID) of the DXGI adapter to use.
+ Relevant only when QRhi creates the device, ignored when importing a device
+ and device context.
+*/
+
+/*!
+ \variable QRhiD3D11NativeHandles::adapterLuidHigh
+
+ The high part of the local identifier (LUID) of the DXGI adapter to use.
+ Relevant only when QRhi creates the device, ignored when importing a device
+ and device context.
+*/
+
// help mingw with its ancient sdk headers
#ifndef DXGI_ADAPTER_FLAG_SOFTWARE
#define DXGI_ADAPTER_FLAG_SOFTWARE 2
@@ -126,20 +145,20 @@ QT_BEGIN_NAMESPACE
#define D3D11_1_UAV_SLOT_COUNT 64
#endif
+#ifndef D3D11_VS_INPUT_REGISTER_COUNT
+#define D3D11_VS_INPUT_REGISTER_COUNT 32
+#endif
+
QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importParams)
- : ofr(this),
- deviceCurse(this)
+ : ofr(this)
{
debugLayer = params->enableDebugLayer;
- deviceCurse.framesToActivate = params->framesUntilKillingDeviceViaTdr;
- deviceCurse.permanent = params->repeatDeviceKill;
-
if (importParams) {
if (importParams->dev && importParams->context) {
dev = reinterpret_cast<ID3D11Device *>(importParams->dev);
ID3D11DeviceContext *ctx = reinterpret_cast<ID3D11DeviceContext *>(importParams->context);
- if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&context)))) {
+ if (SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)))) {
// get rid of the ref added by QueryInterface
ctx->Release();
importedDeviceAndContext = true;
@@ -153,15 +172,6 @@ QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *import
}
}
-static QString comErrorMessage(HRESULT hr)
-{
- const _com_error comError(hr);
- QString result = QLatin1String("Error 0x") + QString::number(ulong(hr), 16);
- if (const wchar_t *msg = comError.ErrorMessage())
- result += QLatin1String(": ") + QString::fromWCharArray(msg);
- return result;
-}
-
template <class Int>
inline Int aligned(Int v, Int byteAlign)
{
@@ -171,20 +181,10 @@ inline Int aligned(Int v, Int byteAlign)
static IDXGIFactory1 *createDXGIFactory2()
{
IDXGIFactory1 *result = nullptr;
- const HRESULT hr = CreateDXGIFactory2(0, IID_IDXGIFactory2, reinterpret_cast<void **>(&result));
+ const HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast<void **>(&result));
if (FAILED(hr)) {
- qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", qPrintable(comErrorMessage(hr)));
- result = nullptr;
- }
- return result;
-}
-
-static IDXGIFactory1 *createDXGIFactory1()
-{
- IDXGIFactory1 *result = nullptr;
- const HRESULT hr = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast<void **>(&result));
- if (FAILED(hr)) {
- qWarning("CreateDXGIFactory1() failed to create DXGI factory: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
result = nullptr;
}
return result;
@@ -192,28 +192,39 @@ static IDXGIFactory1 *createDXGIFactory1()
bool QRhiD3D11::create(QRhi::Flags flags)
{
- Q_UNUSED(flags);
+ rhiFlags = flags;
uint devFlags = 0;
if (debugLayer)
devFlags |= D3D11_CREATE_DEVICE_DEBUG;
dxgiFactory = createDXGIFactory2();
- if (dxgiFactory != nullptr) {
- hasDxgi2 = true;
- supportsFlipDiscardSwapchain = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10
- && !qEnvironmentVariableIntValue("QT_D3D_NO_FLIP");
- } else {
- dxgiFactory = createDXGIFactory1();
- hasDxgi2 = false;
- supportsFlipDiscardSwapchain = false;
+ if (!dxgiFactory)
+ return false;
+
+ // For a FLIP_* swapchain Present(0, 0) is not necessarily
+ // sufficient to get non-blocking behavior, try using ALLOW_TEARING
+ // when available.
+ supportsAllowTearing = false;
+ IDXGIFactory5 *factory5 = nullptr;
+ if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5), reinterpret_cast<void **>(&factory5)))) {
+ BOOL allowTearing = false;
+ if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing))))
+ supportsAllowTearing = allowTearing;
+ factory5->Release();
}
- if (dxgiFactory == nullptr)
- return false;
+ if (qEnvironmentVariableIntValue("QT_D3D_FLIP_DISCARD"))
+ qWarning("The default swap effect is FLIP_DISCARD, QT_D3D_FLIP_DISCARD is now ignored");
+
+ // Support for flip model swapchains is required now (since we are
+ // targeting Windows 10+), but the option for using the old model is still
+ // there. (some features are not supported then, however)
+ useLegacySwapchainModel = qEnvironmentVariableIntValue("QT_D3D_NO_FLIP");
- qCDebug(QRHI_LOG_INFO, "DXGI 1.2 = %s, FLIP_DISCARD swapchain supported = %s",
- hasDxgi2 ? "true" : "false", supportsFlipDiscardSwapchain ? "true" : "false");
+ qCDebug(QRHI_LOG_INFO, "FLIP_* swapchain supported = true, ALLOW_TEARING supported = %s, use legacy (non-FLIP) model = %s",
+ supportsAllowTearing ? "true" : "false",
+ useLegacySwapchainModel ? "true" : "false");
if (!importedDeviceAndContext) {
IDXGIAdapter1 *adapter;
@@ -248,7 +259,7 @@ bool QRhiD3D11::create(QRhi::Flags flags)
}
}
- IDXGIAdapter1 *adapterToUse = nullptr;
+ activeAdapter = nullptr;
for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
@@ -259,18 +270,16 @@ bool QRhiD3D11::create(QRhi::Flags flags)
desc.VendorId,
desc.DeviceId,
desc.Flags);
- if (!adapterToUse && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
- adapterToUse = adapter;
+ if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
+ activeAdapter = adapter;
adapterLuid = desc.AdapterLuid;
- driverInfoStruct.deviceName = name.toUtf8();
- driverInfoStruct.deviceId = desc.DeviceId;
- driverInfoStruct.vendorId = desc.VendorId;
+ QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
qCDebug(QRHI_LOG_INFO, " using this adapter");
} else {
adapter->Release();
}
}
- if (!adapterToUse) {
+ if (!activeAdapter) {
qWarning("No adapter");
return false;
}
@@ -285,7 +294,7 @@ bool QRhiD3D11::create(QRhi::Flags flags)
}
ID3D11DeviceContext *ctx = nullptr;
- HRESULT hr = D3D11CreateDevice(adapterToUse, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
+ HRESULT hr = D3D11CreateDevice(activeAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
requestFeatureLevels ? requestedFeatureLevels.constData() : nullptr,
requestFeatureLevels ? requestedFeatureLevels.count() : 0,
D3D11_SDK_VERSION,
@@ -295,36 +304,75 @@ bool QRhiD3D11::create(QRhi::Flags flags)
qCDebug(QRHI_LOG_INFO, "Debug layer was requested but is not available. "
"Attempting to create D3D11 device without it.");
devFlags &= ~D3D11_CREATE_DEVICE_DEBUG;
- hr = D3D11CreateDevice(adapterToUse, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
+ hr = D3D11CreateDevice(activeAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
requestFeatureLevels ? requestedFeatureLevels.constData() : nullptr,
requestFeatureLevels ? requestedFeatureLevels.count() : 0,
D3D11_SDK_VERSION,
&dev, &featureLevel, &ctx);
}
- adapterToUse->Release();
if (FAILED(hr)) {
- qWarning("Failed to create D3D11 device and context: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create D3D11 device and context: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
- if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&context)))) {
- ctx->Release();
- } else {
+
+ const bool supports11_1 = SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)));
+ ctx->Release();
+ if (!supports11_1) {
qWarning("ID3D11DeviceContext1 not supported");
return false;
}
+
+ // Test if creating a Shader Model 5.0 vertex shader works; we want to
+ // fail already in create() if that's not the case.
+ ID3D11VertexShader *testShader = nullptr;
+ if (SUCCEEDED(dev->CreateVertexShader(g_testVertexShader, sizeof(g_testVertexShader), nullptr, &testShader))) {
+ testShader->Release();
+ } else {
+ static const char *msg = "D3D11 smoke test: Failed to create vertex shader";
+ if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
+ qCDebug(QRHI_LOG_INFO, "%s", msg);
+ else
+ qWarning("%s", msg);
+ return false;
+ }
+
+ D3D11_FEATURE_DATA_D3D11_OPTIONS features = {};
+ if (SUCCEEDED(dev->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &features, sizeof(features)))) {
+ // The D3D _runtime_ may be 11.1, but the underlying _driver_ may
+ // still not support this D3D_FEATURE_LEVEL_11_1 feature. (e.g.
+ // because it only does 11_0)
+ if (!features.ConstantBufferOffsetting) {
+ static const char *msg = "D3D11 smoke test: Constant buffer offsetting is not supported by the driver";
+ if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
+ qCDebug(QRHI_LOG_INFO, "%s", msg);
+ else
+ qWarning("%s", msg);
+ return false;
+ }
+ } else {
+ static const char *msg = "D3D11 smoke test: Failed to query D3D11_FEATURE_D3D11_OPTIONS";
+ if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
+ qCDebug(QRHI_LOG_INFO, "%s", msg);
+ else
+ qWarning("%s", msg);
+ return false;
+ }
} else {
Q_ASSERT(dev && context);
featureLevel = dev->GetFeatureLevel();
IDXGIDevice *dxgiDev = nullptr;
- if (SUCCEEDED(dev->QueryInterface(IID_IDXGIDevice, reinterpret_cast<void **>(&dxgiDev)))) {
+ if (SUCCEEDED(dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDev)))) {
IDXGIAdapter *adapter = nullptr;
if (SUCCEEDED(dxgiDev->GetAdapter(&adapter))) {
- DXGI_ADAPTER_DESC desc;
- adapter->GetDesc(&desc);
- adapterLuid = desc.AdapterLuid;
- driverInfoStruct.deviceName = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description)).toUtf8();
- driverInfoStruct.deviceId = desc.DeviceId;
- driverInfoStruct.vendorId = desc.VendorId;
+ IDXGIAdapter1 *adapter1 = nullptr;
+ if (SUCCEEDED(adapter->QueryInterface(__uuidof(IDXGIAdapter1), reinterpret_cast<void **>(&adapter1)))) {
+ DXGI_ADAPTER_DESC1 desc;
+ adapter1->GetDesc1(&desc);
+ adapterLuid = desc.AdapterLuid;
+ QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
+ adapter1->Release();
+ }
adapter->Release();
}
dxgiDev->Release();
@@ -332,7 +380,7 @@ bool QRhiD3D11::create(QRhi::Flags flags)
qCDebug(QRHI_LOG_INFO, "Using imported device %p", dev);
}
- if (FAILED(context->QueryInterface(IID_ID3DUserDefinedAnnotation, reinterpret_cast<void **>(&annotations))))
+ if (FAILED(context->QueryInterface(__uuidof(ID3DUserDefinedAnnotation), reinterpret_cast<void **>(&annotations))))
annotations = nullptr;
deviceLost = false;
@@ -343,9 +391,6 @@ bool QRhiD3D11::create(QRhi::Flags flags)
nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
- if (deviceCurse.framesToActivate > 0)
- deviceCurse.initResources();
-
return true;
}
@@ -363,7 +408,16 @@ void QRhiD3D11::destroy()
clearShaderCache();
- deviceCurse.releaseResources();
+ if (ofr.tsDisjointQuery) {
+ ofr.tsDisjointQuery->Release();
+ ofr.tsDisjointQuery = nullptr;
+ }
+ for (int i = 0; i < 2; ++i) {
+ if (ofr.tsQueries[i]) {
+ ofr.tsQueries[i]->Release();
+ ofr.tsQueries[i] = nullptr;
+ }
+ }
if (annotations) {
annotations->Release();
@@ -381,6 +435,16 @@ void QRhiD3D11::destroy()
}
}
+ if (dcompDevice) {
+ dcompDevice->Release();
+ dcompDevice = nullptr;
+ }
+
+ if (activeAdapter) {
+ activeAdapter->Release();
+ activeAdapter = nullptr;
+ }
+
if (dxgiFactory) {
dxgiFactory->Release();
dxgiFactory = nullptr;
@@ -391,7 +455,7 @@ void QRhiD3D11::reportLiveObjects(ID3D11Device *device)
{
// this works only when params.enableDebugLayer was true
ID3D11Debug *debug;
- if (SUCCEEDED(device->QueryInterface(IID_ID3D11Debug, reinterpret_cast<void **>(&debug)))) {
+ if (SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void **>(&debug)))) {
debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
debug->Release();
}
@@ -402,19 +466,13 @@ QList<int> QRhiD3D11::supportedSampleCounts() const
return { 1, 2, 4, 8 };
}
-DXGI_SAMPLE_DESC QRhiD3D11::effectiveSampleCount(int sampleCount) const
+DXGI_SAMPLE_DESC QRhiD3D11::effectiveSampleDesc(int sampleCount) const
{
DXGI_SAMPLE_DESC desc;
desc.Count = 1;
desc.Quality = 0;
- // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
- int s = qBound(1, sampleCount, 64);
-
- if (!supportedSampleCounts().contains(s)) {
- qWarning("Attempted to set unsupported sample count %d", sampleCount);
- return desc;
- }
+ const int s = effectiveSampleCount(sampleCount);
desc.Count = UINT(s);
if (s > 1)
@@ -430,7 +488,7 @@ QRhiSwapChain *QRhiD3D11::createSwapChain()
return new QD3D11SwapChain(this);
}
-QRhiBuffer *QRhiD3D11::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, int size)
+QRhiBuffer *QRhiD3D11::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
{
return new QD3D11Buffer(this, type, usage, size);
}
@@ -534,7 +592,7 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
case QRhi::ReadBackAnyTextureFormat:
return true;
case QRhi::PipelineCacheDataLoadSave:
- return false;
+ return true;
case QRhi::ImageDataStride:
return true;
case QRhi::RenderBufferImport:
@@ -543,6 +601,32 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::RenderTo3DTextureSlice:
return true;
+ case QRhi::TextureArrays:
+ return true;
+ case QRhi::Tessellation:
+ return true;
+ case QRhi::GeometryShader:
+ return true;
+ case QRhi::TextureArrayRange:
+ return true;
+ case QRhi::NonFillPolygonMode:
+ return true;
+ case QRhi::OneDimensionalTextures:
+ return true;
+ case QRhi::OneDimensionalTextureMipmaps:
+ return true;
+ case QRhi::HalfAttributes:
+ return true;
+ case QRhi::RenderToOneDimensionalTexture:
+ return true;
+ case QRhi::ThreeDimensionalTextureMipmaps:
+ return true;
+ case QRhi::MultiView:
+ return false;
+ case QRhi::TextureViewFormat:
+ return false; // because we use fully typed formats for textures and relaxed casting is a D3D12 thing
+ case QRhi::ResolveDepthStencil:
+ return false;
default:
Q_UNREACHABLE();
return false;
@@ -576,6 +660,14 @@ int QRhiD3D11::resourceLimit(QRhi::ResourceLimit limit) const
return D3D11_CS_THREAD_GROUP_MAX_Y;
case QRhi::MaxThreadGroupZ:
return D3D11_CS_THREAD_GROUP_MAX_Z;
+ case QRhi::TextureArraySizeMax:
+ return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
+ case QRhi::MaxUniformBufferRange:
+ return 65536;
+ case QRhi::MaxVertexInputs:
+ return D3D11_VS_INPUT_REGISTER_COUNT;
+ case QRhi::MaxVertexOutputs:
+ return D3D11_VS_OUTPUT_REGISTER_COUNT;
default:
Q_UNREACHABLE();
return 0;
@@ -592,9 +684,11 @@ QRhiDriverInfo QRhiD3D11::driverInfo() const
return driverInfoStruct;
}
-void QRhiD3D11::sendVMemStatsToProfiler()
+QRhiStats QRhiD3D11::statistics()
{
- // nothing to do here
+ QRhiStats result;
+ result.totalPipelineCreationTime = totalPipelineCreationTime();
+ return result;
}
bool QRhiD3D11::makeThreadLocalNativeContextCurrent()
@@ -606,6 +700,7 @@ bool QRhiD3D11::makeThreadLocalNativeContextCurrent()
void QRhiD3D11::releaseCachedResources()
{
clearShaderCache();
+ m_bytecodeCache.clear();
}
bool QRhiD3D11::isDeviceLost() const
@@ -613,14 +708,159 @@ bool QRhiD3D11::isDeviceLost() const
return deviceLost;
}
+struct QD3D11PipelineCacheDataHeader
+{
+ quint32 rhiId;
+ quint32 arch;
+ // no need for driver specifics
+ quint32 count;
+ quint32 dataSize;
+};
+
QByteArray QRhiD3D11::pipelineCacheData()
{
- return QByteArray();
+ QByteArray data;
+ if (m_bytecodeCache.isEmpty())
+ return data;
+
+ QD3D11PipelineCacheDataHeader header;
+ memset(&header, 0, sizeof(header));
+ header.rhiId = pipelineCacheRhiId();
+ header.arch = quint32(sizeof(void*));
+ header.count = m_bytecodeCache.count();
+
+ const size_t dataOffset = sizeof(header);
+ size_t dataSize = 0;
+ for (auto it = m_bytecodeCache.cbegin(), end = m_bytecodeCache.cend(); it != end; ++it) {
+ BytecodeCacheKey key = it.key();
+ QByteArray bytecode = it.value();
+ dataSize +=
+ sizeof(quint32) + key.sourceHash.size()
+ + sizeof(quint32) + key.target.size()
+ + sizeof(quint32) + key.entryPoint.size()
+ + sizeof(quint32) // compileFlags
+ + sizeof(quint32) + bytecode.size();
+ }
+
+ QByteArray buf(dataOffset + dataSize, Qt::Uninitialized);
+ char *p = buf.data() + dataOffset;
+ for (auto it = m_bytecodeCache.cbegin(), end = m_bytecodeCache.cend(); it != end; ++it) {
+ BytecodeCacheKey key = it.key();
+ QByteArray bytecode = it.value();
+
+ quint32 i = key.sourceHash.size();
+ memcpy(p, &i, 4);
+ p += 4;
+ memcpy(p, key.sourceHash.constData(), key.sourceHash.size());
+ p += key.sourceHash.size();
+
+ i = key.target.size();
+ memcpy(p, &i, 4);
+ p += 4;
+ memcpy(p, key.target.constData(), key.target.size());
+ p += key.target.size();
+
+ i = key.entryPoint.size();
+ memcpy(p, &i, 4);
+ p += 4;
+ memcpy(p, key.entryPoint.constData(), key.entryPoint.size());
+ p += key.entryPoint.size();
+
+ quint32 f = key.compileFlags;
+ memcpy(p, &f, 4);
+ p += 4;
+
+ i = bytecode.size();
+ memcpy(p, &i, 4);
+ p += 4;
+ memcpy(p, bytecode.constData(), bytecode.size());
+ p += bytecode.size();
+ }
+ Q_ASSERT(p == buf.data() + dataOffset + dataSize);
+
+ header.dataSize = quint32(dataSize);
+ memcpy(buf.data(), &header, sizeof(header));
+
+ return buf;
}
void QRhiD3D11::setPipelineCacheData(const QByteArray &data)
{
- Q_UNUSED(data);
+ if (data.isEmpty())
+ return;
+
+ const size_t headerSize = sizeof(QD3D11PipelineCacheDataHeader);
+ if (data.size() < qsizetype(headerSize)) {
+ qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Invalid blob size (header incomplete)");
+ return;
+ }
+ const size_t dataOffset = headerSize;
+ QD3D11PipelineCacheDataHeader header;
+ memcpy(&header, data.constData(), headerSize);
+
+ const quint32 rhiId = pipelineCacheRhiId();
+ if (header.rhiId != rhiId) {
+ qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
+ rhiId, header.rhiId);
+ return;
+ }
+ const quint32 arch = quint32(sizeof(void*));
+ if (header.arch != arch) {
+ qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Architecture does not match (%u, %u)",
+ arch, header.arch);
+ return;
+ }
+ if (header.count == 0)
+ return;
+
+ if (data.size() < qsizetype(dataOffset + header.dataSize)) {
+ qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Invalid blob size (data incomplete)");
+ return;
+ }
+
+ m_bytecodeCache.clear();
+
+ const char *p = data.constData() + dataOffset;
+ for (quint32 i = 0; i < header.count; ++i) {
+ quint32 len = 0;
+ memcpy(&len, p, 4);
+ p += 4;
+ QByteArray sourceHash(len, Qt::Uninitialized);
+ memcpy(sourceHash.data(), p, len);
+ p += len;
+
+ memcpy(&len, p, 4);
+ p += 4;
+ QByteArray target(len, Qt::Uninitialized);
+ memcpy(target.data(), p, len);
+ p += len;
+
+ memcpy(&len, p, 4);
+ p += 4;
+ QByteArray entryPoint(len, Qt::Uninitialized);
+ memcpy(entryPoint.data(), p, len);
+ p += len;
+
+ quint32 flags;
+ memcpy(&flags, p, 4);
+ p += 4;
+
+ memcpy(&len, p, 4);
+ p += 4;
+ QByteArray bytecode(len, Qt::Uninitialized);
+ memcpy(bytecode.data(), p, len);
+ p += len;
+
+ BytecodeCacheKey cacheKey;
+ cacheKey.sourceHash = sourceHash;
+ cacheKey.target = target;
+ cacheKey.entryPoint = entryPoint;
+ cacheKey.compileFlags = flags;
+
+ m_bytecodeCache.insert(cacheKey, bytecode);
+ }
+
+ qCDebug(QRHI_LOG_INFO, "Seeded bytecode cache with %d shaders", int(m_bytecodeCache.count()));
}
QRhiRenderBuffer *QRhiD3D11::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
@@ -631,10 +871,10 @@ QRhiRenderBuffer *QRhiD3D11::createRenderBuffer(QRhiRenderBuffer::Type type, con
}
QRhiTexture *QRhiD3D11::createTexture(QRhiTexture::Format format,
- const QSize &pixelSize, int depth,
+ const QSize &pixelSize, int depth, int arraySize,
int sampleCount, QRhiTexture::Flags flags)
{
- return new QD3D11Texture(this, format, pixelSize, depth, sampleCount, flags);
+ return new QD3D11Texture(this, format, pixelSize, depth, arraySize, sampleCount, flags);
}
QRhiSampler *QRhiD3D11::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
@@ -683,10 +923,13 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
}
}
-static const int RBM_SUPPORTED_STAGES = 3;
+static const int RBM_SUPPORTED_STAGES = 6;
static const int RBM_VERTEX = 0;
-static const int RBM_FRAGMENT = 1;
-static const int RBM_COMPUTE = 2;
+static const int RBM_HULL = 1;
+static const int RBM_DOMAIN = 2;
+static const int RBM_GEOMETRY = 3;
+static const int RBM_FRAGMENT = 4;
+static const int RBM_COMPUTE = 5;
void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
int dynamicOffsetCount,
@@ -708,7 +951,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
bool srbUpdate = false;
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
+ const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@@ -727,8 +970,10 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
}
break;
case QRhiShaderResourceBinding::SampledTexture:
+ case QRhiShaderResourceBinding::Texture:
+ case QRhiShaderResourceBinding::Sampler:
{
- const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex;
+ const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
if (bd.stex.count != data->count) {
bd.stex.count = data->count;
srbUpdate = true;
@@ -736,16 +981,24 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
for (int elem = 0; elem < data->count; ++elem) {
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex);
QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler);
- if (texD->generation != bd.stex.d[elem].texGeneration
- || texD->m_id != bd.stex.d[elem].texId
- || samplerD->generation != bd.stex.d[elem].samplerGeneration
- || samplerD->m_id != bd.stex.d[elem].samplerId)
+ // We use the same code path for both combined and separate
+ // images and samplers, so tex or sampler (but not both) can be
+ // null here.
+ Q_ASSERT(texD || samplerD);
+ const quint64 texId = texD ? texD->m_id : 0;
+ const uint texGen = texD ? texD->generation : 0;
+ const quint64 samplerId = samplerD ? samplerD->m_id : 0;
+ const uint samplerGen = samplerD ? samplerD->generation : 0;
+ if (texGen != bd.stex.d[elem].texGeneration
+ || texId != bd.stex.d[elem].texId
+ || samplerGen != bd.stex.d[elem].samplerGeneration
+ || samplerId != bd.stex.d[elem].samplerId)
{
srbUpdate = true;
- bd.stex.d[elem].texId = texD->m_id;
- bd.stex.d[elem].texGeneration = texD->generation;
- bd.stex.d[elem].samplerId = samplerD->m_id;
- bd.stex.d[elem].samplerGeneration = samplerD->generation;
+ bd.stex.d[elem].texId = texId;
+ bd.stex.d[elem].texGeneration = texGen;
+ bd.stex.d[elem].samplerId = samplerId;
+ bd.stex.d[elem].samplerGeneration = samplerGen;
}
}
}
@@ -785,6 +1038,9 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
memset(resBindMaps, 0, sizeof(resBindMaps));
if (gfxPsD) {
resBindMaps[RBM_VERTEX] = &gfxPsD->vs.nativeResourceBindingMap;
+ resBindMaps[RBM_HULL] = &gfxPsD->hs.nativeResourceBindingMap;
+ resBindMaps[RBM_DOMAIN] = &gfxPsD->ds.nativeResourceBindingMap;
+ resBindMaps[RBM_GEOMETRY] = &gfxPsD->gs.nativeResourceBindingMap;
resBindMaps[RBM_FRAGMENT] = &gfxPsD->fs.nativeResourceBindingMap;
} else {
resBindMaps[RBM_COMPUTE] = &compPsD->cs.nativeResourceBindingMap;
@@ -819,8 +1075,8 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
for (int i = 0; i < dynamicOffsetCount; ++i) {
const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
const uint binding = uint(dynOfs.first);
- Q_ASSERT(aligned(dynOfs.second, quint32(256)) == dynOfs.second);
- const uint offsetInConstants = dynOfs.second / 16;
+ Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
+ const quint32 offsetInConstants = dynOfs.second / 16;
*p++ = binding;
*p++ = offsetInConstants;
}
@@ -911,7 +1167,7 @@ void QRhiD3D11::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
// d3d expects top-left, QRhiViewport is bottom-left
float x, y, w, h;
- if (!qrhi_toTopLeftRenderTargetRect(outputSize, viewport.viewport(), &x, &y, &w, &h))
+ if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
return;
QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
@@ -933,7 +1189,7 @@ void QRhiD3D11::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
// d3d expects top-left, QRhiScissor is bottom-left
int x, y, w, h;
- if (!qrhi_toTopLeftRenderTargetRect(outputSize, scissor.scissor(), &x, &y, &w, &h))
+ if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
return;
QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
@@ -1041,7 +1297,6 @@ const QRhiNativeHandles *QRhiD3D11::nativeHandles(QRhiCommandBuffer *cb)
void QRhiD3D11::beginExternal(QRhiCommandBuffer *cb)
{
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
- // no timestampSwapChain, in order to avoid timestamp mess
executeCommandBuffer(cbD);
cbD->resetCommands();
}
@@ -1058,6 +1313,25 @@ void QRhiD3D11::endExternal(QRhiCommandBuffer *cb)
}
}
+double QRhiD3D11::lastCompletedGpuTime(QRhiCommandBuffer *cb)
+{
+ QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
+ return cbD->lastGpuTime;
+}
+
+static inline QD3D11RenderTargetData *rtData(QRhiRenderTarget *rt)
+{
+ switch (rt->resourceType()) {
+ case QRhiResource::SwapChainRenderTarget:
+ return &QRHI_RES(QD3D11SwapChainRenderTarget, rt)->d;
+ case QRhiResource::TextureRenderTarget:
+ return &QRHI_RES(QD3D11TextureRenderTarget, rt)->d;
+ default:
+ Q_UNREACHABLE();
+ return nullptr;
+ }
+}
+
QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
Q_UNUSED(flags);
@@ -1065,32 +1339,6 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
contextState.currentSwapChain = swapChainD;
const int currentFrameSlot = swapChainD->currentFrameSlot;
- QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
-
- if (swapChainD->timestampActive[currentFrameSlot]) {
- ID3D11Query *tsDisjoint = swapChainD->timestampDisjointQuery[currentFrameSlot];
- const int tsIdx = QD3D11SwapChain::BUFFER_COUNT * currentFrameSlot;
- ID3D11Query *tsStart = swapChainD->timestampQuery[tsIdx];
- ID3D11Query *tsEnd = swapChainD->timestampQuery[tsIdx + 1];
- quint64 timestamps[2];
- D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
- bool ok = true;
- ok &= context->GetData(tsDisjoint, &dj, sizeof(dj), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
- ok &= context->GetData(tsEnd, &timestamps[1], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
- // this above is often not ready, not even in frame_where_recorded+2,
- // not clear why. so make the whole thing async and do not touch the
- // queries until they are finally all available in frame this+2 or
- // this+4 or ...
- ok &= context->GetData(tsStart, &timestamps[0], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
- if (ok) {
- if (!dj.Disjoint && dj.Frequency) {
- const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
- // finally got a value, just report it, the profiler cares about min/max/avg anyway
- QRHI_PROF_F(swapChainFrameGpuTime(swapChain, elapsedMs));
- }
- swapChainD->timestampActive[currentFrameSlot] = false;
- } // else leave timestampActive set to true, will retry in a subsequent beginFrame
- }
swapChainD->cb.resetState();
@@ -1098,10 +1346,24 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
swapChainD->msaaRtv[currentFrameSlot] : swapChainD->backBufferRtv;
swapChainD->rt.d.dsv = swapChainD->ds ? swapChainD->ds->dsv : nullptr;
- QRHI_PROF_F(beginSwapChainFrame(swapChain));
-
finishActiveReadbacks();
+ if (swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex]) {
+ double elapsedSec = 0;
+ if (swapChainD->timestamps.tryQueryTimestamps(swapChainD->currentTimestampPairIndex, context, &elapsedSec))
+ swapChainD->cb.lastGpuTime = elapsedSec;
+ }
+
+ ID3D11Query *tsStart = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2];
+ ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[swapChainD->currentTimestampPairIndex];
+ const bool recordTimestamps = tsStart && tsDisjoint && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
+
+ QD3D11CommandBuffer::Command &cmd(swapChainD->cb.commands.get());
+ cmd.cmd = QD3D11CommandBuffer::Command::BeginFrame;
+ cmd.args.beginFrame.tsQuery = recordTimestamps ? tsStart : nullptr;
+ cmd.args.beginFrame.tsDisjointQuery = recordTimestamps ? tsDisjoint : nullptr;
+ cmd.args.beginFrame.swapchainData = rtData(&swapChainD->rt);
+
return QRhi::FrameOpSuccess;
}
@@ -1111,17 +1373,13 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
Q_ASSERT(contextState.currentSwapChain = swapChainD);
const int currentFrameSlot = swapChainD->currentFrameSlot;
- ID3D11Query *tsDisjoint = swapChainD->timestampDisjointQuery[currentFrameSlot];
- const int tsIdx = QD3D11SwapChain::BUFFER_COUNT * currentFrameSlot;
- ID3D11Query *tsStart = swapChainD->timestampQuery[tsIdx];
- ID3D11Query *tsEnd = swapChainD->timestampQuery[tsIdx + 1];
- const bool recordTimestamps = tsDisjoint && tsStart && tsEnd && !swapChainD->timestampActive[currentFrameSlot];
+ QD3D11CommandBuffer::Command &cmd(swapChainD->cb.commands.get());
+ cmd.cmd = QD3D11CommandBuffer::Command::EndFrame;
+ cmd.args.endFrame.tsQuery = nullptr; // done later manually, see below
+ cmd.args.endFrame.tsDisjointQuery = nullptr;
// send all commands to the context
- if (recordTimestamps)
- executeCommandBuffer(&swapChainD->cb, swapChainD);
- else
- executeCommandBuffer(&swapChainD->cb);
+ executeCommandBuffer(&swapChainD->cb);
if (swapChainD->sampleDesc.Count > 1) {
context->ResolveSubresource(swapChainD->backBufferTex, 0,
@@ -1129,29 +1387,39 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
swapChainD->colorFormat);
}
- // this is here because we want to include the time spent on the resolve as well
+ // this is here because we want to include the time spent on the ResolveSubresource as well
+ ID3D11Query *tsEnd = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2 + 1];
+ ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[swapChainD->currentTimestampPairIndex];
+ const bool recordTimestamps = tsEnd && tsDisjoint && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
if (recordTimestamps) {
context->End(tsEnd);
context->End(tsDisjoint);
- swapChainD->timestampActive[currentFrameSlot] = true;
+ swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex] = true;
+ swapChainD->currentTimestampPairIndex = (swapChainD->currentTimestampPairIndex + 1) % QD3D11SwapChainTimestamps::TIMESTAMP_PAIRS;
}
- QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
- // this must be done before the Present
- QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
-
if (!flags.testFlag(QRhi::SkipPresent)) {
- const UINT presentFlags = 0;
+ UINT presentFlags = 0;
+ if (swapChainD->swapInterval == 0 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
+ presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
+ if (!swapChainD->swapChain) {
+ qWarning("Failed to present: IDXGISwapChain is unavailable");
+ return QRhi::FrameOpError;
+ }
HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
qWarning("Device loss detected in Present()");
deviceLost = true;
return QRhi::FrameOpDeviceLost;
} else if (FAILED(hr)) {
- qWarning("Failed to present: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to present: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return QRhi::FrameOpError;
}
+ if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
+ dcompDevice->Commit();
+
// move on to the next buffer
swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D11SwapChain::BUFFER_COUNT;
} else {
@@ -1161,19 +1429,6 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
swapChainD->frameCount += 1;
contextState.currentSwapChain = nullptr;
- if (deviceCurse.framesToActivate > 0) {
- deviceCurse.framesLeft -= 1;
- if (deviceCurse.framesLeft == 0) {
- deviceCurse.framesLeft = deviceCurse.framesToActivate;
- if (!deviceCurse.permanent)
- deviceCurse.framesToActivate = -1;
-
- deviceCurse.activate();
- } else if (deviceCurse.framesLeft % 100 == 0) {
- qDebug("Impending doom: %d frames left", deviceCurse.framesLeft);
- }
- }
-
return QRhi::FrameOpSuccess;
}
@@ -1185,6 +1440,36 @@ QRhi::FrameOpResult QRhiD3D11::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi:
ofr.cbWrapper.resetState();
*cb = &ofr.cbWrapper;
+ if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
+ D3D11_QUERY_DESC queryDesc = {};
+ if (!ofr.tsDisjointQuery) {
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
+ HRESULT hr = dev->CreateQuery(&queryDesc, &ofr.tsDisjointQuery);
+ if (FAILED(hr)) {
+ qWarning("Failed to create timestamp disjoint query: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return QRhi::FrameOpError;
+ }
+ }
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP;
+ for (int i = 0; i < 2; ++i) {
+ if (!ofr.tsQueries[i]) {
+ HRESULT hr = dev->CreateQuery(&queryDesc, &ofr.tsQueries[i]);
+ if (FAILED(hr)) {
+ qWarning("Failed to create timestamp query: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return QRhi::FrameOpError;
+ }
+ }
+ }
+ }
+
+ QD3D11CommandBuffer::Command &cmd(ofr.cbWrapper.commands.get());
+ cmd.cmd = QD3D11CommandBuffer::Command::BeginFrame;
+ cmd.args.beginFrame.tsQuery = ofr.tsQueries[0] ? ofr.tsQueries[0] : nullptr;
+ cmd.args.beginFrame.tsDisjointQuery = ofr.tsDisjointQuery ? ofr.tsDisjointQuery : nullptr;
+ cmd.args.beginFrame.swapchainData = nullptr;
+
return QRhi::FrameOpSuccess;
}
@@ -1193,10 +1478,41 @@ QRhi::FrameOpResult QRhiD3D11::endOffscreenFrame(QRhi::EndFrameFlags flags)
Q_UNUSED(flags);
ofr.active = false;
+ QD3D11CommandBuffer::Command &cmd(ofr.cbWrapper.commands.get());
+ cmd.cmd = QD3D11CommandBuffer::Command::EndFrame;
+ cmd.args.endFrame.tsQuery = ofr.tsQueries[1] ? ofr.tsQueries[1] : nullptr;
+ cmd.args.endFrame.tsDisjointQuery = ofr.tsDisjointQuery ? ofr.tsDisjointQuery : nullptr;
+
executeCommandBuffer(&ofr.cbWrapper);
+ context->Flush();
finishActiveReadbacks();
+ if (ofr.tsQueries[0]) {
+ quint64 timestamps[2];
+ D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
+ HRESULT hr;
+ bool ok = true;
+ do {
+ hr = context->GetData(ofr.tsDisjointQuery, &dj, sizeof(dj), 0);
+ } while (hr == S_FALSE);
+ ok &= hr == S_OK;
+ do {
+ hr = context->GetData(ofr.tsQueries[1], &timestamps[1], sizeof(quint64), 0);
+ } while (hr == S_FALSE);
+ ok &= hr == S_OK;
+ do {
+ hr = context->GetData(ofr.tsQueries[0], &timestamps[0], sizeof(quint64), 0);
+ } while (hr == S_FALSE);
+ ok &= hr == S_OK;
+ if (ok) {
+ if (!dj.Disjoint && dj.Frequency) {
+ const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
+ ofr.cbWrapper.lastGpuTime = elapsedMs / 1000.0;
+ }
+ }
+ }
+
return QRhi::FrameOpSuccess;
}
@@ -1228,12 +1544,15 @@ static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTex
case QRhiTexture::R32F:
return DXGI_FORMAT_R32_FLOAT;
+ case QRhiTexture::RGB10A2:
+ return DXGI_FORMAT_R10G10B10A2_UNORM;
+
case QRhiTexture::D16:
return DXGI_FORMAT_R16_TYPELESS;
case QRhiTexture::D24:
- return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
+ return DXGI_FORMAT_R24G8_TYPELESS;
case QRhiTexture::D24S8:
- return DXGI_FORMAT_D24_UNORM_S8_UINT;
+ return DXGI_FORMAT_R24G8_TYPELESS;
case QRhiTexture::D32F:
return DXGI_FORMAT_R32_TYPELESS;
@@ -1281,7 +1600,7 @@ static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTex
}
}
-static inline QRhiTexture::Format colorTextureFormatFromDxgiFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
+static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
{
switch (format) {
case DXGI_FORMAT_R8G8B8A8_UNORM:
@@ -1296,16 +1615,14 @@ static inline QRhiTexture::Format colorTextureFormatFromDxgiFormat(DXGI_FORMAT f
if (flags)
(*flags) |= QRhiTexture::sRGB;
return QRhiTexture::BGRA8;
- case DXGI_FORMAT_R8_UNORM:
- return QRhiTexture::R8;
- case DXGI_FORMAT_R8G8_UNORM:
- return QRhiTexture::RG8;
- case DXGI_FORMAT_R16_UNORM:
- return QRhiTexture::R16;
- case DXGI_FORMAT_R16G16_UNORM:
- return QRhiTexture::RG16;
- default: // this cannot assert, must warn and return unknown
- qWarning("DXGI_FORMAT %d is not a recognized uncompressed color format", format);
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ return QRhiTexture::RGBA16F;
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ return QRhiTexture::RGBA32F;
+ case DXGI_FORMAT_R10G10B10A2_UNORM:
+ return QRhiTexture::RGB10A2;
+ default:
+ qWarning("DXGI_FORMAT %d cannot be read back", format);
break;
}
return QRhiTexture::UnknownFormat;
@@ -1336,7 +1653,7 @@ QRhi::FrameOpResult QRhiD3D11::finish()
} else {
Q_ASSERT(contextState.currentSwapChain);
Q_ASSERT(contextState.currentSwapChain->cb.recordingPass == QD3D11CommandBuffer::NoPass);
- executeCommandBuffer(&contextState.currentSwapChain->cb); // no timestampSwapChain, in order to avoid timestamp mess
+ executeCommandBuffer(&contextState.currentSwapChain->cb);
contextState.currentSwapChain->cb.resetCommands();
}
}
@@ -1430,7 +1747,6 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
{
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
- QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
@@ -1453,10 +1769,10 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
// since the ID3D11Buffer's size is rounded up to be a multiple of 256
// while the data we have has the original size.
D3D11_BOX box;
- box.left = UINT(u.offset);
+ box.left = u.offset;
box.top = box.front = 0;
box.back = box.bottom = 1;
- box.right = UINT(u.offset + u.data.size()); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
+ box.right = u.offset + u.data.size(); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
@@ -1464,22 +1780,23 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
if (bufD->m_type == QRhiBuffer::Dynamic) {
u.result->data.resize(u.readSize);
memcpy(u.result->data.data(), bufD->dynBuf + u.offset, size_t(u.readSize));
+ if (u.result->completed)
+ u.result->completed();
} else {
BufferReadback readback;
readback.result = u.result;
readback.byteSize = u.readSize;
- D3D11_BUFFER_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ D3D11_BUFFER_DESC desc = {};
desc.ByteWidth = readback.byteSize;
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
HRESULT hr = dev->CreateBuffer(&desc, nullptr, &readback.stagingBuf);
if (FAILED(hr)) {
- qWarning("Failed to create buffer: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create buffer: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
continue;
}
- QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(readback.stagingBuf)), bufD, readback.byteSize));
QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
@@ -1492,16 +1809,14 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cmd.args.copySubRes.srcSubRes = 0;
cmd.args.copySubRes.hasSrcBox = true;
D3D11_BOX box;
- box.left = UINT(u.offset);
+ box.left = u.offset;
box.top = box.front = 0;
box.back = box.bottom = 1;
- box.right = UINT(u.offset + u.readSize);
+ box.right = u.offset + u.readSize;
cmd.args.copySubRes.srcBox = box;
activeBufferReadbacks.append(readback);
}
- if (u.result->completed)
- u.result->completed();
}
}
for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
@@ -1510,7 +1825,7 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.dst);
for (int layer = 0, maxLayer = u.subresDesc.count(); layer < maxLayer; ++layer) {
for (int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
- for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
+ for (const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
}
}
@@ -1587,7 +1902,7 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
src = swapChainD->backBufferTex;
dxgiFormat = swapChainD->colorFormat;
pixelSize = swapChainD->pixelSize;
- format = colorTextureFormatFromDxgiFormat(dxgiFormat, nullptr);
+ format = swapchainReadbackTextureFormat(dxgiFormat, nullptr);
if (format == QRhiTexture::UnknownFormat)
continue;
}
@@ -1595,8 +1910,7 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
quint32 bpl = 0;
textureFormatInfo(format, pixelSize, &bpl, &byteSize, nullptr);
- D3D11_TEXTURE2D_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ D3D11_TEXTURE2D_DESC desc = {};
desc.Width = UINT(pixelSize.width());
desc.Height = UINT(pixelSize.height());
desc.MipLevels = 1;
@@ -1608,12 +1922,10 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
ID3D11Texture2D *stagingTex;
HRESULT hr = dev->CreateTexture2D(&desc, nullptr, &stagingTex);
if (FAILED(hr)) {
- qWarning("Failed to create readback staging texture: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create readback staging texture: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return;
}
- QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(stagingTex)),
- texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
- byteSize));
QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
@@ -1625,8 +1937,7 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cmd.args.copySubRes.src = src;
cmd.args.copySubRes.srcSubRes = subres;
if (is3D) {
- D3D11_BOX srcBox;
- memset(&srcBox, 0, sizeof(srcBox));
+ D3D11_BOX srcBox = {};
srcBox.front = UINT(u.rb.layer());
srcBox.right = desc.Width; // exclusive
srcBox.bottom = desc.Height;
@@ -1658,7 +1969,6 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
void QRhiD3D11::finishActiveReadbacks()
{
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
- QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
for (int i = activeTextureReadbacks.count() - 1; i >= 0; --i) {
const QRhiD3D11::TextureReadback &readback(activeTextureReadbacks[i]);
@@ -1680,11 +1990,11 @@ void QRhiD3D11::finishActiveReadbacks()
}
context->Unmap(readback.stagingTex, 0);
} else {
- qWarning("Failed to map readback staging texture: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to map readback staging texture: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
}
readback.stagingTex->Release();
- QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(readback.stagingTex))));
if (readback.result->completed)
completedCallbacks.append(readback.result->completed);
@@ -1702,11 +2012,11 @@ void QRhiD3D11::finishActiveReadbacks()
memcpy(readback.result->data.data(), mp.pData, readback.byteSize);
context->Unmap(readback.stagingBuf, 0);
} else {
- qWarning("Failed to map readback staging texture: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to map readback staging texture: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
}
readback.stagingBuf->Release();
- QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(readback.stagingBuf))));
if (readback.result->completed)
completedCallbacks.append(readback.result->completed);
@@ -1718,19 +2028,6 @@ void QRhiD3D11::finishActiveReadbacks()
f();
}
-static inline QD3D11RenderTargetData *rtData(QRhiRenderTarget *rt)
-{
- switch (rt->resourceType()) {
- case QRhiResource::RenderTarget:
- return &QRHI_RES(QD3D11ReferenceRenderTarget, rt)->d;
- case QRhiResource::TextureRenderTarget:
- return &QRHI_RES(QD3D11TextureRenderTarget, rt)->d;
- default:
- Q_UNREACHABLE();
- return nullptr;
- }
-}
-
void QRhiD3D11::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
{
Q_ASSERT(QRHI_RES(QD3D11CommandBuffer, cb)->recordingPass == QD3D11CommandBuffer::NoPass);
@@ -1758,6 +2055,8 @@ void QRhiD3D11::beginPass(QRhiCommandBuffer *cb,
QD3D11TextureRenderTarget *rtTex = QRHI_RES(QD3D11TextureRenderTarget, rt);
wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
+ if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D11Texture, QD3D11RenderBuffer>(rtTex->description(), rtD->currentResIdList))
+ rtTex->create();
}
cbD->commands.get().cmd = QD3D11CommandBuffer::Command::ResetShaderResources;
@@ -1785,7 +2084,7 @@ void QRhiD3D11::beginPass(QRhiCommandBuffer *cb,
cbD->recordingPass = QD3D11CommandBuffer::RenderPass;
cbD->currentTarget = rt;
- cbD->resetCachedShaderResourceState();
+ cbD->resetCachedState();
}
void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
@@ -1847,6 +2146,8 @@ void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
cmd.args.resolveSubRes.srcSubRes = D3D11CalcSubresource(0, UINT(colorAtt.layer()), 1);
cmd.args.resolveSubRes.format = dstTexD->dxgiFormat;
}
+ if (rtTex->m_desc.depthResolveTexture())
+ qWarning("Resolving multisample depth-stencil buffers is not supported with D3D");
}
cbD->recordingPass = QD3D11CommandBuffer::NoPass;
@@ -1871,7 +2172,7 @@ void QRhiD3D11::beginComputePass(QRhiCommandBuffer *cb,
cbD->recordingPass = QD3D11CommandBuffer::ComputePass;
- cbD->resetCachedShaderResourceState();
+ cbD->resetCachedState();
}
void QRhiD3D11::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
@@ -1921,7 +2222,7 @@ static inline QPair<int, int> mapBinding(int binding,
{
const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
if (!map || map->isEmpty())
- return { binding, binding }; // old QShader versions do not have this map, assume 1:1 mapping then
+ return { binding, binding }; // assume 1:1 mapping
auto it = map->constFind(binding);
if (it != map->cend())
@@ -1936,31 +2237,21 @@ static inline QPair<int, int> mapBinding(int binding,
void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
{
- srbD->vsubufs.clear();
- srbD->vsubuforigbindings.clear();
- srbD->vsubufoffsets.clear();
- srbD->vsubufsizes.clear();
+ srbD->vsUniformBufferBatches.clear();
+ srbD->hsUniformBufferBatches.clear();
+ srbD->dsUniformBufferBatches.clear();
+ srbD->gsUniformBufferBatches.clear();
+ srbD->fsUniformBufferBatches.clear();
+ srbD->csUniformBufferBatches.clear();
- srbD->fsubufs.clear();
- srbD->fsubuforigbindings.clear();
- srbD->fsubufoffsets.clear();
- srbD->fsubufsizes.clear();
+ srbD->vsSamplerBatches.clear();
+ srbD->hsSamplerBatches.clear();
+ srbD->dsSamplerBatches.clear();
+ srbD->gsSamplerBatches.clear();
+ srbD->fsSamplerBatches.clear();
+ srbD->csSamplerBatches.clear();
- srbD->csubufs.clear();
- srbD->csubuforigbindings.clear();
- srbD->csubufoffsets.clear();
- srbD->csubufsizes.clear();
-
- srbD->vssamplers.clear();
- srbD->vsshaderresources.clear();
-
- srbD->fssamplers.clear();
- srbD->fsshaderresources.clear();
-
- srbD->cssamplers.clear();
- srbD->csshaderresources.clear();
-
- srbD->csUAVs.clear();
+ srbD->csUavBatches.clear();
struct Stage {
struct Buffer {
@@ -1986,16 +2277,40 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
QVarLengthArray<Texture, 8> textures;
QVarLengthArray<Sampler, 8> samplers;
QVarLengthArray<Uav, 8> uavs;
+ void buildBufferBatches(QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches) const
+ {
+ for (const Buffer &buf : buffers) {
+ batches.ubufs.feed(buf.breg, buf.buffer);
+ batches.ubuforigbindings.feed(buf.breg, UINT(buf.binding));
+ batches.ubufoffsets.feed(buf.breg, buf.offsetInConstants);
+ batches.ubufsizes.feed(buf.breg, buf.sizeInConstants);
+ }
+ batches.finish();
+ }
+ void buildSamplerBatches(QD3D11ShaderResourceBindings::StageSamplerBatches &batches) const
+ {
+ for (const Texture &t : textures)
+ batches.shaderresources.feed(t.treg, t.srv);
+ for (const Sampler &s : samplers)
+ batches.samplers.feed(s.sreg, s.sampler);
+ batches.finish();
+ }
+ void buildUavBatches(QD3D11ShaderResourceBindings::StageUavBatches &batches) const
+ {
+ for (const Stage::Uav &u : uavs)
+ batches.uavs.feed(u.ureg, u.uav);
+ batches.finish();
+ }
} res[RBM_SUPPORTED_STAGES];
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
+ const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf);
- Q_ASSERT(aligned(b->u.ubuf.offset, 256) == b->u.ubuf.offset);
+ Q_ASSERT(aligned(b->u.ubuf.offset, 256u) == b->u.ubuf.offset);
bd.ubuf.id = bufD->m_id;
bd.ubuf.generation = bufD->generation;
// Dynamic ubuf offsets are not considered here, those are baked in
@@ -2004,16 +2319,31 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
// Metal) are different in this respect since those do not store
// per-srb vsubufoffsets etc. data so life's a bit easier for them.
// But here we have to defer baking in the dynamic offset.
- const uint offsetInConstants = uint(b->u.ubuf.offset) / 16;
+ const quint32 offsetInConstants = b->u.ubuf.offset / 16;
// size must be 16 mult. (in constants, i.e. multiple of 256 bytes).
// We can round up if needed since the buffers's actual size
// (ByteWidth) is always a multiple of 256.
- const uint sizeInConstants = uint(aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256) / 16);
+ const quint32 sizeInConstants = aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256u) / 16;
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
if (nativeBinding.first >= 0)
res[RBM_VERTEX].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
}
+ if (b->stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage)) {
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0)
+ res[RBM_HULL].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
+ }
+ if (b->stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage)) {
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0)
+ res[RBM_DOMAIN].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
+ }
+ if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) {
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0)
+ res[RBM_GEOMETRY].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
+ }
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
if (nativeBinding.first >= 0)
@@ -2027,10 +2357,15 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
}
break;
case QRhiShaderResourceBinding::SampledTexture:
+ case QRhiShaderResourceBinding::Texture:
+ case QRhiShaderResourceBinding::Sampler:
{
- const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex;
+ const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex;
bd.stex.count = data->count;
const QPair<int, int> nativeBindingVert = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
+ const QPair<int, int> nativeBindingHull = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps);
+ const QPair<int, int> nativeBindingDomain = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps);
+ const QPair<int, int> nativeBindingGeom = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps);
const QPair<int, int> nativeBindingFrag = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
const QPair<int, int> nativeBindingComp = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
// if SPIR-V binding b is mapped to tN and sN in HLSL, and it
@@ -2039,27 +2374,61 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
for (int elem = 0; elem < data->count; ++elem) {
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex);
QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler);
- bd.stex.d[elem].texId = texD->m_id;
- bd.stex.d[elem].texGeneration = texD->generation;
- bd.stex.d[elem].samplerId = samplerD->m_id;
- bd.stex.d[elem].samplerGeneration = samplerD->generation;
+ bd.stex.d[elem].texId = texD ? texD->m_id : 0;
+ bd.stex.d[elem].texGeneration = texD ? texD->generation : 0;
+ bd.stex.d[elem].samplerId = samplerD ? samplerD->m_id : 0;
+ bd.stex.d[elem].samplerGeneration = samplerD ? samplerD->generation : 0;
+ // Must handle all three cases (combined, separate, separate):
+ // first = texture binding, second = sampler binding
+ // first = texture binding
+ // first = sampler binding
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- if (nativeBindingVert.first >= 0 && nativeBindingVert.second >= 0) {
+ const int samplerBinding = texD && samplerD ? nativeBindingVert.second
+ : (samplerD ? nativeBindingVert.first : -1);
+ if (nativeBindingVert.first >= 0 && texD)
res[RBM_VERTEX].textures.append({ nativeBindingVert.first + elem, texD->srv });
- res[RBM_VERTEX].samplers.append({ nativeBindingVert.second + elem, samplerD->samplerState });
- }
+ if (samplerBinding >= 0)
+ res[RBM_VERTEX].samplers.append({ samplerBinding + elem, samplerD->samplerState });
+ }
+ if (b->stage.testFlag(QRhiShaderResourceBinding::TessellationControlStage)) {
+ const int samplerBinding = texD && samplerD ? nativeBindingHull.second
+ : (samplerD ? nativeBindingHull.first : -1);
+ if (nativeBindingHull.first >= 0 && texD)
+ res[RBM_HULL].textures.append({ nativeBindingHull.first + elem, texD->srv });
+ if (samplerBinding >= 0)
+ res[RBM_HULL].samplers.append({ samplerBinding + elem, samplerD->samplerState });
+ }
+ if (b->stage.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage)) {
+ const int samplerBinding = texD && samplerD ? nativeBindingDomain.second
+ : (samplerD ? nativeBindingDomain.first : -1);
+ if (nativeBindingDomain.first >= 0 && texD)
+ res[RBM_DOMAIN].textures.append({ nativeBindingDomain.first + elem, texD->srv });
+ if (samplerBinding >= 0)
+ res[RBM_DOMAIN].samplers.append({ samplerBinding + elem, samplerD->samplerState });
+ }
+ if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) {
+ const int samplerBinding = texD && samplerD ? nativeBindingGeom.second
+ : (samplerD ? nativeBindingGeom.first : -1);
+ if (nativeBindingGeom.first >= 0 && texD)
+ res[RBM_GEOMETRY].textures.append({ nativeBindingGeom.first + elem, texD->srv });
+ if (samplerBinding >= 0)
+ res[RBM_GEOMETRY].samplers.append({ samplerBinding + elem, samplerD->samplerState });
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- if (nativeBindingFrag.first >= 0 && nativeBindingFrag.second >= 0) {
+ const int samplerBinding = texD && samplerD ? nativeBindingFrag.second
+ : (samplerD ? nativeBindingFrag.first : -1);
+ if (nativeBindingFrag.first >= 0 && texD)
res[RBM_FRAGMENT].textures.append({ nativeBindingFrag.first + elem, texD->srv });
- res[RBM_FRAGMENT].samplers.append({ nativeBindingFrag.second + elem, samplerD->samplerState });
- }
+ if (samplerBinding >= 0)
+ res[RBM_FRAGMENT].samplers.append({ samplerBinding + elem, samplerD->samplerState });
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- if (nativeBindingComp.first >= 0 && nativeBindingComp.second >= 0) {
+ const int samplerBinding = texD && samplerD ? nativeBindingComp.second
+ : (samplerD ? nativeBindingComp.first : -1);
+ if (nativeBindingComp.first >= 0 && texD)
res[RBM_COMPUTE].textures.append({ nativeBindingComp.first + elem, texD->srv });
- res[RBM_COMPUTE].samplers.append({ nativeBindingComp.second + elem, samplerD->samplerState });
- }
+ if (samplerBinding >= 0)
+ res[RBM_COMPUTE].samplers.append({ samplerBinding + elem, samplerD->samplerState });
}
}
}
@@ -2093,7 +2462,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
if (nativeBinding.first >= 0) {
- ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView();
+ ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(b->u.sbuf.offset);
if (uav)
res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
}
@@ -2127,63 +2496,21 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
});
}
- for (const Stage::Buffer &buf : qAsConst(res[RBM_VERTEX].buffers)) {
- srbD->vsubufs.feed(buf.breg, buf.buffer);
- srbD->vsubuforigbindings.feed(buf.breg, UINT(buf.binding));
- srbD->vsubufoffsets.feed(buf.breg, buf.offsetInConstants);
- srbD->vsubufsizes.feed(buf.breg, buf.sizeInConstants);
- }
- srbD->vsubufsPresent = srbD->vsubufs.finish();
- srbD->vsubuforigbindings.finish();
- srbD->vsubufoffsets.finish();
- srbD->vsubufsizes.finish();
-
- for (const Stage::Buffer &buf : qAsConst(res[RBM_FRAGMENT].buffers)) {
- srbD->fsubufs.feed(buf.breg, buf.buffer);
- srbD->fsubuforigbindings.feed(buf.breg, UINT(buf.binding));
- srbD->fsubufoffsets.feed(buf.breg, buf.offsetInConstants);
- srbD->fsubufsizes.feed(buf.breg, buf.sizeInConstants);
- }
- srbD->fsubufsPresent = srbD->fsubufs.finish();
- srbD->fsubuforigbindings.finish();
- srbD->fsubufoffsets.finish();
- srbD->fsubufsizes.finish();
-
- for (const Stage::Buffer &buf : qAsConst(res[RBM_COMPUTE].buffers)) {
- srbD->csubufs.feed(buf.breg, buf.buffer);
- srbD->csubuforigbindings.feed(buf.breg, UINT(buf.binding));
- srbD->csubufoffsets.feed(buf.breg, buf.offsetInConstants);
- srbD->csubufsizes.feed(buf.breg, buf.sizeInConstants);
- }
- srbD->csubufsPresent = srbD->csubufs.finish();
- srbD->csubuforigbindings.finish();
- srbD->csubufoffsets.finish();
- srbD->csubufsizes.finish();
-
- for (const Stage::Texture &t : qAsConst(res[RBM_VERTEX].textures))
- srbD->vsshaderresources.feed(t.treg, t.srv);
- for (const Stage::Sampler &s : qAsConst(res[RBM_VERTEX].samplers))
- srbD->vssamplers.feed(s.sreg, s.sampler);
- srbD->vssamplersPresent = srbD->vssamplers.finish();
- srbD->vsshaderresources.finish();
-
- for (const Stage::Texture &t : qAsConst(res[RBM_FRAGMENT].textures))
- srbD->fsshaderresources.feed(t.treg, t.srv);
- for (const Stage::Sampler &s : qAsConst(res[RBM_FRAGMENT].samplers))
- srbD->fssamplers.feed(s.sreg, s.sampler);
- srbD->fssamplersPresent = srbD->fssamplers.finish();
- srbD->fsshaderresources.finish();
-
- for (const Stage::Texture &t : qAsConst(res[RBM_COMPUTE].textures))
- srbD->csshaderresources.feed(t.treg, t.srv);
- for (const Stage::Sampler &s : qAsConst(res[RBM_COMPUTE].samplers))
- srbD->cssamplers.feed(s.sreg, s.sampler);
- srbD->cssamplersPresent = srbD->cssamplers.finish();
- srbD->csshaderresources.finish();
-
- for (const Stage::Uav &u : qAsConst(res[RBM_COMPUTE].uavs))
- srbD->csUAVs.feed(u.ureg, u.uav);
- srbD->csUAVsPresent = srbD->csUAVs.finish();
+ res[RBM_VERTEX].buildBufferBatches(srbD->vsUniformBufferBatches);
+ res[RBM_HULL].buildBufferBatches(srbD->hsUniformBufferBatches);
+ res[RBM_DOMAIN].buildBufferBatches(srbD->dsUniformBufferBatches);
+ res[RBM_GEOMETRY].buildBufferBatches(srbD->gsUniformBufferBatches);
+ res[RBM_FRAGMENT].buildBufferBatches(srbD->fsUniformBufferBatches);
+ res[RBM_COMPUTE].buildBufferBatches(srbD->csUniformBufferBatches);
+
+ res[RBM_VERTEX].buildSamplerBatches(srbD->vsSamplerBatches);
+ res[RBM_HULL].buildSamplerBatches(srbD->hsSamplerBatches);
+ res[RBM_DOMAIN].buildSamplerBatches(srbD->dsSamplerBatches);
+ res[RBM_GEOMETRY].buildSamplerBatches(srbD->gsSamplerBatches);
+ res[RBM_FRAGMENT].buildSamplerBatches(srbD->fsSamplerBatches);
+ res[RBM_COMPUTE].buildSamplerBatches(srbD->csSamplerBatches);
+
+ res[RBM_COMPUTE].buildUavBatches(srbD->csUavBatches);
}
void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD)
@@ -2196,17 +2523,18 @@ void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD)
D3D11_MAPPED_SUBRESOURCE mp;
HRESULT hr = context->Map(bufD->buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
if (SUCCEEDED(hr)) {
- memcpy(mp.pData, bufD->dynBuf, size_t(bufD->m_size));
+ memcpy(mp.pData, bufD->dynBuf, bufD->m_size);
context->Unmap(bufD->buffer, 0);
} else {
- qWarning("Failed to map buffer: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to map buffer: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
}
}
static void applyDynamicOffsets(UINT *offsets,
int batchIndex,
- QRhiBatchedBindings<UINT> *originalBindings,
- QRhiBatchedBindings<UINT> *staticOffsets,
+ const QRhiBatchedBindings<UINT> *originalBindings,
+ const QRhiBatchedBindings<UINT> *staticOffsets,
const uint *dynOfsPairs, int dynOfsPairCount)
{
const int count = staticOffsets->batches[batchIndex].resources.count();
@@ -2237,162 +2565,92 @@ static inline uint clampedResourceCount(uint startSlot, int countSlots, uint max
return countSlots;
}
+#define SETUBUFBATCH(stagePrefixL, stagePrefixU) \
+ if (srbD->stagePrefixL##UniformBufferBatches.present) { \
+ const QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches(srbD->stagePrefixL##UniformBufferBatches); \
+ for (int i = 0, ie = batches.ubufs.batches.count(); i != ie; ++i) { \
+ const uint count = clampedResourceCount(batches.ubufs.batches[i].startBinding, \
+ batches.ubufs.batches[i].resources.count(), \
+ D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, \
+ #stagePrefixU " cbuf"); \
+ if (count) { \
+ if (!dynOfsPairCount) { \
+ context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \
+ count, \
+ batches.ubufs.batches[i].resources.constData(), \
+ batches.ubufoffsets.batches[i].resources.constData(), \
+ batches.ubufsizes.batches[i].resources.constData()); \
+ } else { \
+ applyDynamicOffsets(offsets, i, \
+ &batches.ubuforigbindings, &batches.ubufoffsets, \
+ dynOfsPairs, dynOfsPairCount); \
+ context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \
+ count, \
+ batches.ubufs.batches[i].resources.constData(), \
+ offsets, \
+ batches.ubufsizes.batches[i].resources.constData()); \
+ } \
+ } \
+ } \
+ }
+
+#define SETSAMPLERBATCH(stagePrefixL, stagePrefixU) \
+ if (srbD->stagePrefixL##SamplerBatches.present) { \
+ for (const auto &batch : srbD->stagePrefixL##SamplerBatches.samplers.batches) { \
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
+ D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, #stagePrefixU " sampler"); \
+ if (count) \
+ context->stagePrefixU##SetSamplers(batch.startBinding, count, batch.resources.constData()); \
+ } \
+ for (const auto &batch : srbD->stagePrefixL##SamplerBatches.shaderresources.batches) { \
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
+ D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, #stagePrefixU " SRV"); \
+ if (count) { \
+ context->stagePrefixU##SetShaderResources(batch.startBinding, count, batch.resources.constData()); \
+ contextState.stagePrefixL##HighestActiveSrvBinding = qMax(contextState.stagePrefixL##HighestActiveSrvBinding, \
+ int(batch.startBinding + count) - 1); \
+ } \
+ } \
+ }
+
+#define SETUAVBATCH(stagePrefixL, stagePrefixU) \
+ if (srbD->stagePrefixL##UavBatches.present) { \
+ for (const auto &batch : srbD->stagePrefixL##UavBatches.uavs.batches) { \
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
+ D3D11_1_UAV_SLOT_COUNT, #stagePrefixU " UAV"); \
+ if (count) { \
+ context->stagePrefixU##SetUnorderedAccessViews(batch.startBinding, \
+ count, \
+ batch.resources.constData(), \
+ nullptr); \
+ contextState.stagePrefixL##HighestActiveUavBinding = qMax(contextState.stagePrefixL##HighestActiveUavBinding, \
+ int(batch.startBinding + count) - 1); \
+ } \
+ } \
+ }
+
void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange)
{
UINT offsets[QD3D11CommandBuffer::MAX_DYNAMIC_OFFSET_COUNT];
- if (srbD->vsubufsPresent) {
- for (int i = 0, ie = srbD->vsubufs.batches.count(); i != ie; ++i) {
- const uint count = clampedResourceCount(srbD->vsubufs.batches[i].startBinding,
- srbD->vsubufs.batches[i].resources.count(),
- D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT,
- "VS cbuf");
- if (count) {
- if (!dynOfsPairCount) {
- context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding,
- count,
- srbD->vsubufs.batches[i].resources.constData(),
- srbD->vsubufoffsets.batches[i].resources.constData(),
- srbD->vsubufsizes.batches[i].resources.constData());
- } else {
- applyDynamicOffsets(offsets, i, &srbD->vsubuforigbindings, &srbD->vsubufoffsets,
- dynOfsPairs, dynOfsPairCount);
- context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding,
- count,
- srbD->vsubufs.batches[i].resources.constData(),
- offsets,
- srbD->vsubufsizes.batches[i].resources.constData());
- }
- }
- }
- }
-
- if (srbD->fsubufsPresent) {
- for (int i = 0, ie = srbD->fsubufs.batches.count(); i != ie; ++i) {
- const uint count = clampedResourceCount(srbD->fsubufs.batches[i].startBinding,
- srbD->fsubufs.batches[i].resources.count(),
- D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT,
- "PS cbuf");
- if (count) {
- if (!dynOfsPairCount) {
- context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding,
- count,
- srbD->fsubufs.batches[i].resources.constData(),
- srbD->fsubufoffsets.batches[i].resources.constData(),
- srbD->fsubufsizes.batches[i].resources.constData());
- } else {
- applyDynamicOffsets(offsets, i, &srbD->fsubuforigbindings, &srbD->fsubufoffsets,
- dynOfsPairs, dynOfsPairCount);
- context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding,
- count,
- srbD->fsubufs.batches[i].resources.constData(),
- offsets,
- srbD->fsubufsizes.batches[i].resources.constData());
- }
- }
- }
- }
-
- if (srbD->csubufsPresent) {
- for (int i = 0, ie = srbD->csubufs.batches.count(); i != ie; ++i) {
- const uint count = clampedResourceCount(srbD->csubufs.batches[i].startBinding,
- srbD->csubufs.batches[i].resources.count(),
- D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT,
- "CS cbuf");
- if (count) {
- if (!dynOfsPairCount) {
- context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding,
- count,
- srbD->csubufs.batches[i].resources.constData(),
- srbD->csubufoffsets.batches[i].resources.constData(),
- srbD->csubufsizes.batches[i].resources.constData());
- } else {
- applyDynamicOffsets(offsets, i, &srbD->csubuforigbindings, &srbD->csubufoffsets,
- dynOfsPairs, dynOfsPairCount);
- context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding,
- count,
- srbD->csubufs.batches[i].resources.constData(),
- offsets,
- srbD->csubufsizes.batches[i].resources.constData());
- }
- }
- }
- }
+ SETUBUFBATCH(vs, VS)
+ SETUBUFBATCH(hs, HS)
+ SETUBUFBATCH(ds, DS)
+ SETUBUFBATCH(gs, GS)
+ SETUBUFBATCH(fs, PS)
+ SETUBUFBATCH(cs, CS)
if (!offsetOnlyChange) {
- if (srbD->vssamplersPresent) {
- for (const auto &batch : srbD->vssamplers.batches) {
- const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
- D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "VS sampler");
- if (count)
- context->VSSetSamplers(batch.startBinding, count, batch.resources.constData());
- }
-
- for (const auto &batch : srbD->vsshaderresources.batches) {
- const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
- D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "VS SRV");
- if (count) {
- context->VSSetShaderResources(batch.startBinding, count, batch.resources.constData());
- contextState.vsHighestActiveSrvBinding = qMax(contextState.vsHighestActiveSrvBinding,
- int(batch.startBinding + count) - 1);
- }
- }
- }
-
- if (srbD->fssamplersPresent) {
- for (const auto &batch : srbD->fssamplers.batches) {
- const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
- D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "PS sampler");
- if (count)
- context->PSSetSamplers(batch.startBinding, count, batch.resources.constData());
- }
-
- for (const auto &batch : srbD->fsshaderresources.batches) {
- const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
- D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "PS SRV");
- if (count) {
- context->PSSetShaderResources(batch.startBinding, count, batch.resources.constData());
- contextState.fsHighestActiveSrvBinding = qMax(contextState.fsHighestActiveSrvBinding,
- int(batch.startBinding + count) - 1);
- }
- }
- }
-
- if (srbD->cssamplersPresent) {
- for (const auto &batch : srbD->cssamplers.batches) {
- const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
- D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "CS sampler");
- if (count)
- context->CSSetSamplers(batch.startBinding, count, batch.resources.constData());
- }
-
- for (const auto &batch : srbD->csshaderresources.batches) {
- const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
- D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "CS SRV");
- if (count) {
- context->CSSetShaderResources(batch.startBinding, count, batch.resources.constData());
- contextState.csHighestActiveSrvBinding = qMax(contextState.csHighestActiveSrvBinding,
- int(batch.startBinding + count) - 1);
- }
- }
- }
+ SETSAMPLERBATCH(vs, VS)
+ SETSAMPLERBATCH(hs, HS)
+ SETSAMPLERBATCH(ds, DS)
+ SETSAMPLERBATCH(gs, GS)
+ SETSAMPLERBATCH(fs, PS)
+ SETSAMPLERBATCH(cs, CS)
- if (srbD->csUAVsPresent) {
- for (const auto &batch : srbD->csUAVs.batches) {
- const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
- D3D11_1_UAV_SLOT_COUNT, "CS UAV");
- if (count) {
- context->CSSetUnorderedAccessViews(batch.startBinding,
- count,
- batch.resources.constData(),
- nullptr);
- contextState.csHighestActiveUavBinding = qMax(contextState.csHighestActiveUavBinding,
- int(batch.startBinding + count) - 1);
- }
- }
- }
+ SETUAVBATCH(cs, CS)
}
}
@@ -2421,6 +2679,9 @@ void QRhiD3D11::resetShaderResources()
}
int nullsrvCount = qMax(contextState.vsHighestActiveSrvBinding, contextState.fsHighestActiveSrvBinding);
+ nullsrvCount = qMax(nullsrvCount, contextState.hsHighestActiveSrvBinding);
+ nullsrvCount = qMax(nullsrvCount, contextState.dsHighestActiveSrvBinding);
+ nullsrvCount = qMax(nullsrvCount, contextState.gsHighestActiveSrvBinding);
nullsrvCount = qMax(nullsrvCount, contextState.csHighestActiveSrvBinding);
nullsrvCount += 1;
if (nullsrvCount > 0) {
@@ -2432,6 +2693,18 @@ void QRhiD3D11::resetShaderResources()
context->VSSetShaderResources(0, UINT(contextState.vsHighestActiveSrvBinding + 1), nullsrvs.constData());
contextState.vsHighestActiveSrvBinding = -1;
}
+ if (contextState.hsHighestActiveSrvBinding >= 0) {
+ context->HSSetShaderResources(0, UINT(contextState.hsHighestActiveSrvBinding + 1), nullsrvs.constData());
+ contextState.hsHighestActiveSrvBinding = -1;
+ }
+ if (contextState.dsHighestActiveSrvBinding >= 0) {
+ context->DSSetShaderResources(0, UINT(contextState.dsHighestActiveSrvBinding + 1), nullsrvs.constData());
+ contextState.dsHighestActiveSrvBinding = -1;
+ }
+ if (contextState.gsHighestActiveSrvBinding >= 0) {
+ context->GSSetShaderResources(0, UINT(contextState.gsHighestActiveSrvBinding + 1), nullsrvs.constData());
+ contextState.gsHighestActiveSrvBinding = -1;
+ }
if (contextState.fsHighestActiveSrvBinding >= 0) {
context->PSSetShaderResources(0, UINT(contextState.fsHighestActiveSrvBinding + 1), nullsrvs.constData());
contextState.fsHighestActiveSrvBinding = -1;
@@ -2453,31 +2726,52 @@ void QRhiD3D11::resetShaderResources()
}
}
-void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain)
+#define SETSHADER(StageL, StageU) \
+ if (psD->StageL.shader) { \
+ context->StageU##SetShader(psD->StageL.shader, nullptr, 0); \
+ currentShaderMask |= StageU##MaskBit; \
+ } else if (currentShaderMask & StageU##MaskBit) { \
+ context->StageU##SetShader(nullptr, nullptr, 0); \
+ currentShaderMask &= ~StageU##MaskBit; \
+ }
+
+void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
{
quint32 stencilRef = 0;
float blendConstants[] = { 1, 1, 1, 1 };
-
- if (timestampSwapChain) {
- const int currentFrameSlot = timestampSwapChain->currentFrameSlot;
- ID3D11Query *tsDisjoint = timestampSwapChain->timestampDisjointQuery[currentFrameSlot];
- const int tsIdx = QD3D11SwapChain::BUFFER_COUNT * currentFrameSlot;
- ID3D11Query *tsStart = timestampSwapChain->timestampQuery[tsIdx];
- if (tsDisjoint && tsStart && !timestampSwapChain->timestampActive[currentFrameSlot]) {
- // The timestamps seem to include vsync time with Present(1), except
- // when running on a non-primary gpu. This is not ideal. So try working
- // it around by issuing a semi-fake OMSetRenderTargets early and
- // writing the first timestamp only afterwards.
- context->Begin(tsDisjoint);
- QD3D11RenderTargetData *rtD = rtData(&timestampSwapChain->rt);
- context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
- context->End(tsStart); // just record a timestamp, no Begin needed
- }
- }
+ enum ActiveShaderMask {
+ VSMaskBit = 0x01,
+ HSMaskBit = 0x02,
+ DSMaskBit = 0x04,
+ GSMaskBit = 0x08,
+ PSMaskBit = 0x10
+ };
+ int currentShaderMask = 0xFF;
for (auto it = cbD->commands.cbegin(), end = cbD->commands.cend(); it != end; ++it) {
const QD3D11CommandBuffer::Command &cmd(*it);
switch (cmd.cmd) {
+ case QD3D11CommandBuffer::Command::BeginFrame:
+ if (cmd.args.beginFrame.tsDisjointQuery)
+ context->Begin(cmd.args.beginFrame.tsDisjointQuery);
+ if (cmd.args.beginFrame.tsQuery) {
+ if (cmd.args.beginFrame.swapchainData) {
+ // The timestamps seem to include vsync time with Present(1), except
+ // when running on a non-primary gpu. This is not ideal. So try working
+ // it around by issuing a semi-fake OMSetRenderTargets early and
+ // writing the first timestamp only afterwards.
+ QD3D11RenderTargetData *rtD = cmd.args.beginFrame.swapchainData;
+ context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
+ }
+ context->End(cmd.args.beginFrame.tsQuery); // no Begin() for D3D11_QUERY_TIMESTAMP
+ }
+ break;
+ case QD3D11CommandBuffer::Command::EndFrame:
+ if (cmd.args.endFrame.tsQuery)
+ context->End(cmd.args.endFrame.tsQuery);
+ if (cmd.args.endFrame.tsDisjointQuery)
+ context->End(cmd.args.endFrame.tsDisjointQuery);
+ break;
case QD3D11CommandBuffer::Command::ResetShaderResources:
resetShaderResources();
break;
@@ -2545,8 +2839,11 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
case QD3D11CommandBuffer::Command::BindGraphicsPipeline:
{
QD3D11GraphicsPipeline *psD = cmd.args.bindGraphicsPipeline.ps;
- context->VSSetShader(psD->vs.shader, nullptr, 0);
- context->PSSetShader(psD->fs.shader, nullptr, 0);
+ SETSHADER(vs, VS)
+ SETSHADER(hs, HS)
+ SETSHADER(ds, DS)
+ SETSHADER(gs, GS)
+ SETSHADER(fs, PS)
context->IASetPrimitiveTopology(psD->d3dTopology);
context->IASetInputLayout(psD->inputLayout); // may be null, that's ok
context->OMSetDepthStencilState(psD->dsState, stencilRef);
@@ -2632,7 +2929,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
}
}
-QD3D11Buffer::QD3D11Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
+QD3D11Buffer::QD3D11Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
: QRhiBuffer(rhi, type, usage, size)
{
}
@@ -2653,17 +2950,13 @@ void QD3D11Buffer::destroy()
delete[] dynBuf;
dynBuf = nullptr;
- if (uav) {
- uav->Release();
- uav = nullptr;
- }
+ for (auto it = uavs.begin(), end = uavs.end(); it != end; ++it)
+ it.value()->Release();
+ uavs.clear();
QRHI_RES_RHI(QRhiD3D11);
- if (rhiD) {
- QRHI_PROF;
- QRHI_PROF_F(releaseBuffer(this));
+ if (rhiD)
rhiD->unregisterResource(this);
- }
}
static inline uint toD3DBufferUsage(QRhiBuffer::UsageFlags usage)
@@ -2695,12 +2988,11 @@ bool QD3D11Buffer::create()
return false;
}
- const int nonZeroSize = m_size <= 0 ? 256 : m_size;
- const int roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256 : 4);
+ const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
+ const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
- D3D11_BUFFER_DESC desc;
- memset(&desc, 0, sizeof(desc));
- desc.ByteWidth = UINT(roundedSize);
+ D3D11_BUFFER_DESC desc = {};
+ desc.ByteWidth = roundedSize;
desc.Usage = m_type == Dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
desc.BindFlags = toD3DBufferUsage(m_usage);
desc.CPUAccessFlags = m_type == Dynamic ? D3D11_CPU_ACCESS_WRITE : 0;
@@ -2709,7 +3001,8 @@ bool QD3D11Buffer::create()
QRHI_RES_RHI(QRhiD3D11);
HRESULT hr = rhiD->dev->CreateBuffer(&desc, nullptr, &buffer);
if (FAILED(hr)) {
- qWarning("Failed to create buffer: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create buffer: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
@@ -2721,9 +3014,6 @@ bool QD3D11Buffer::create()
if (!m_objectName.isEmpty())
buffer->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
- QRHI_PROF;
- QRHI_PROF_F(newBuffer(this, quint32(roundedSize), m_type == Dynamic ? 2 : 1, m_type == Dynamic ? 1 : 0));
-
generation += 1;
rhiD->registerResource(this);
return true;
@@ -2751,7 +3041,8 @@ char *QD3D11Buffer::beginFullDynamicBufferUpdateForCurrentFrame()
QRHI_RES_RHI(QRhiD3D11);
HRESULT hr = rhiD->context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
if (FAILED(hr)) {
- qWarning("Failed to map buffer: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to map buffer: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return nullptr;
}
return static_cast<char *>(mp.pData);
@@ -2763,27 +3054,30 @@ void QD3D11Buffer::endFullDynamicBufferUpdateForCurrentFrame()
rhiD->context->Unmap(buffer, 0);
}
-ID3D11UnorderedAccessView *QD3D11Buffer::unorderedAccessView()
+ID3D11UnorderedAccessView *QD3D11Buffer::unorderedAccessView(quint32 offset)
{
- if (uav)
- return uav;
+ auto it = uavs.find(offset);
+ if (it != uavs.end())
+ return it.value();
// SPIRV-Cross generated HLSL uses RWByteAddressBuffer
- D3D11_UNORDERED_ACCESS_VIEW_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
desc.Format = DXGI_FORMAT_R32_TYPELESS;
desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
- desc.Buffer.FirstElement = 0;
- desc.Buffer.NumElements = UINT(aligned(m_size, 4) / 4);
+ desc.Buffer.FirstElement = offset / 4u;
+ desc.Buffer.NumElements = aligned(m_size - offset, 4u) / 4u;
desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
QRHI_RES_RHI(QRhiD3D11);
+ ID3D11UnorderedAccessView *uav = nullptr;
HRESULT hr = rhiD->dev->CreateUnorderedAccessView(buffer, &desc, &uav);
if (FAILED(hr)) {
- qWarning("Failed to create UAV: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create UAV: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return nullptr;
}
+ uavs[offset] = uav;
return uav;
}
@@ -2818,11 +3112,8 @@ void QD3D11RenderBuffer::destroy()
tex = nullptr;
QRHI_RES_RHI(QRhiD3D11);
- if (rhiD) {
- QRHI_PROF;
- QRHI_PROF_F(releaseRenderBuffer(this));
+ if (rhiD)
rhiD->unregisterResource(this);
- }
}
bool QD3D11RenderBuffer::create()
@@ -2834,10 +3125,9 @@ bool QD3D11RenderBuffer::create()
return false;
QRHI_RES_RHI(QRhiD3D11);
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
- D3D11_TEXTURE2D_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ D3D11_TEXTURE2D_DESC desc = {};
desc.Width = UINT(m_pixelSize.width());
desc.Height = UINT(m_pixelSize.height());
desc.MipLevels = 1;
@@ -2852,17 +3142,18 @@ bool QD3D11RenderBuffer::create()
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
if (FAILED(hr)) {
- qWarning("Failed to create color renderbuffer: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create color renderbuffer: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
- D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
- memset(&rtvDesc, 0, sizeof(rtvDesc));
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
rtvDesc.Format = dxgiFormat;
rtvDesc.ViewDimension = desc.SampleDesc.Count > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS
: D3D11_RTV_DIMENSION_TEXTURE2D;
hr = rhiD->dev->CreateRenderTargetView(tex, &rtvDesc, &rtv);
if (FAILED(hr)) {
- qWarning("Failed to create rtv: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create rtv: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
} else if (m_type == DepthStencil) {
@@ -2871,17 +3162,18 @@ bool QD3D11RenderBuffer::create()
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
if (FAILED(hr)) {
- qWarning("Failed to create depth-stencil buffer: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create depth-stencil buffer: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
- D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
- memset(&dsvDesc, 0, sizeof(dsvDesc));
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
dsvDesc.Format = dxgiFormat;
dsvDesc.ViewDimension = desc.SampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS
: D3D11_DSV_DIMENSION_TEXTURE2D;
hr = rhiD->dev->CreateDepthStencilView(tex, &dsvDesc, &dsv);
if (FAILED(hr)) {
- qWarning("Failed to create dsv: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create dsv: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
} else {
@@ -2891,9 +3183,7 @@ bool QD3D11RenderBuffer::create()
if (!m_objectName.isEmpty())
tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
- QRHI_PROF;
- QRHI_PROF_F(newRenderBuffer(this, false, false, int(sampleDesc.Count)));
-
+ generation += 1;
rhiD->registerResource(this);
return true;
}
@@ -2907,8 +3197,8 @@ QRhiTexture::Format QD3D11RenderBuffer::backingFormat() const
}
QD3D11Texture::QD3D11Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
- int sampleCount, Flags flags)
- : QRhiTexture(rhi, format, pixelSize, depth, sampleCount, flags)
+ int arraySize, int sampleCount, Flags flags)
+ : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
{
for (int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
perLevelViews[i] = nullptr;
@@ -2921,7 +3211,7 @@ QD3D11Texture::~QD3D11Texture()
void QD3D11Texture::destroy()
{
- if (!tex && !tex3D)
+ if (!tex && !tex3D && !tex1D)
return;
if (srv) {
@@ -2941,17 +3231,17 @@ void QD3D11Texture::destroy()
tex->Release();
if (tex3D)
tex3D->Release();
+ if (tex1D)
+ tex1D->Release();
}
tex = nullptr;
tex3D = nullptr;
+ tex1D = nullptr;
QRHI_RES_RHI(QRhiD3D11);
- if (rhiD) {
- QRHI_PROF;
- QRHI_PROF_F(releaseTexture(this));
+ if (rhiD)
rhiD->unregisterResource(this);
- }
}
static inline DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
@@ -2977,7 +3267,7 @@ static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
case QRhiTexture::Format::D16:
return DXGI_FORMAT_D16_UNORM;
case QRhiTexture::Format::D24:
- return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
+ return DXGI_FORMAT_D24_UNORM_S8_UINT;
case QRhiTexture::Format::D24S8:
return DXGI_FORMAT_D24_UNORM_S8_UINT;
case QRhiTexture::Format::D32F:
@@ -2990,19 +3280,23 @@ static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
bool QD3D11Texture::prepareCreate(QSize *adjustedSize)
{
- if (tex || tex3D)
+ if (tex || tex3D || tex1D)
destroy();
- const QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
const bool isDepth = isDepthTextureFormat(m_format);
const bool isCube = m_flags.testFlag(CubeMap);
const bool is3D = m_flags.testFlag(ThreeDimensional);
+ const bool isArray = m_flags.testFlag(TextureArray);
const bool hasMipMaps = m_flags.testFlag(MipMapped);
+ const bool is1D = m_flags.testFlag(OneDimensional);
+
+ const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
+ : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
QRHI_RES_RHI(QRhiD3D11);
dxgiFormat = toD3DTextureFormat(m_format, m_flags);
mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
if (sampleDesc.Count > 1) {
if (isCube) {
qWarning("Cubemap texture cannot be multisample");
@@ -3025,11 +3319,30 @@ bool QD3D11Texture::prepareCreate(QSize *adjustedSize)
qWarning("Texture cannot be both cube and 3D");
return false;
}
- m_depth = qMax(1, m_depth);
+ if (isArray && is3D) {
+ qWarning("Texture cannot be both array and 3D");
+ return false;
+ }
+ if (isCube && is1D) {
+ qWarning("Texture cannot be both cube and 1D");
+ return false;
+ }
+ if (is1D && is3D) {
+ qWarning("Texture cannot be both 1D and 3D");
+ return false;
+ }
if (m_depth > 1 && !is3D) {
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
return false;
}
+ if (m_arraySize > 0 && !isArray) {
+ qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
+ return false;
+ }
+ if (m_arraySize < 1 && isArray) {
+ qWarning("Texture is an array but array size is %d", m_arraySize);
+ return false;
+ }
if (adjustedSize)
*adjustedSize = size;
@@ -3043,28 +3356,68 @@ bool QD3D11Texture::finishCreate()
const bool isDepth = isDepthTextureFormat(m_format);
const bool isCube = m_flags.testFlag(CubeMap);
const bool is3D = m_flags.testFlag(ThreeDimensional);
+ const bool isArray = m_flags.testFlag(TextureArray);
+ const bool is1D = m_flags.testFlag(OneDimensional);
- D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
- memset(&srvDesc, 0, sizeof(srvDesc));
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = isDepth ? toD3DDepthTextureSRVFormat(m_format) : dxgiFormat;
if (isCube) {
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srvDesc.TextureCube.MipLevels = mipLevelCount;
} else {
- if (sampleDesc.Count > 1) {
- srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
- } else if (is3D) {
- srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
- srvDesc.Texture3D.MipLevels = mipLevelCount;
+ if (is1D) {
+ if (isArray) {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
+ srvDesc.Texture1DArray.MipLevels = mipLevelCount;
+ if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
+ srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
+ srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
+ } else {
+ srvDesc.Texture1DArray.FirstArraySlice = 0;
+ srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
+ }
+ } else {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
+ srvDesc.Texture1D.MipLevels = mipLevelCount;
+ }
+ } else if (isArray) {
+ if (sampleDesc.Count > 1) {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
+ if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
+ srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
+ srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
+ } else {
+ srvDesc.Texture2DMSArray.FirstArraySlice = 0;
+ srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
+ }
+ } else {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
+ srvDesc.Texture2DArray.MipLevels = mipLevelCount;
+ if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
+ srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
+ srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
+ } else {
+ srvDesc.Texture2DArray.FirstArraySlice = 0;
+ srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
+ }
+ }
} else {
- srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
- srvDesc.Texture2D.MipLevels = mipLevelCount;
+ if (sampleDesc.Count > 1) {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
+ } else if (is3D) {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
+ srvDesc.Texture3D.MipLevels = mipLevelCount;
+ } else {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = mipLevelCount;
+ }
}
}
HRESULT hr = rhiD->dev->CreateShaderResourceView(textureResource(), &srvDesc, &srv);
if (FAILED(hr)) {
- qWarning("Failed to create srv: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create srv: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
@@ -3081,6 +3434,8 @@ bool QD3D11Texture::create()
const bool isDepth = isDepthTextureFormat(m_format);
const bool isCube = m_flags.testFlag(CubeMap);
const bool is3D = m_flags.testFlag(ThreeDimensional);
+ const bool isArray = m_flags.testFlag(TextureArray);
+ const bool is1D = m_flags.testFlag(OneDimensional);
uint bindFlags = D3D11_BIND_SHADER_RESOURCE;
uint miscFlags = isCube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
@@ -3102,13 +3457,31 @@ bool QD3D11Texture::create()
bindFlags |= D3D11_BIND_UNORDERED_ACCESS;
QRHI_RES_RHI(QRhiD3D11);
- if (!is3D) {
- D3D11_TEXTURE2D_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ if (is1D) {
+ D3D11_TEXTURE1D_DESC desc = {};
+ desc.Width = UINT(size.width());
+ desc.MipLevels = mipLevelCount;
+ desc.ArraySize = isArray ? UINT(qMax(0, m_arraySize)) : 1;
+ desc.Format = dxgiFormat;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = bindFlags;
+ desc.MiscFlags = miscFlags;
+
+ HRESULT hr = rhiD->dev->CreateTexture1D(&desc, nullptr, &tex1D);
+ if (FAILED(hr)) {
+ qWarning("Failed to create 1D texture: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ if (!m_objectName.isEmpty())
+ tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()),
+ m_objectName.constData());
+ } else if (!is3D) {
+ D3D11_TEXTURE2D_DESC desc = {};
desc.Width = UINT(size.width());
desc.Height = UINT(size.height());
desc.MipLevels = mipLevelCount;
- desc.ArraySize = isCube ? 6 : 1;
+ desc.ArraySize = isCube ? 6 : (isArray ? UINT(qMax(0, m_arraySize)) : 1);
desc.Format = dxgiFormat;
desc.SampleDesc = sampleDesc;
desc.Usage = D3D11_USAGE_DEFAULT;
@@ -3117,17 +3490,17 @@ bool QD3D11Texture::create()
HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
if (FAILED(hr)) {
- qWarning("Failed to create 2D texture: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create 2D texture: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
if (!m_objectName.isEmpty())
tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
} else {
- D3D11_TEXTURE3D_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ D3D11_TEXTURE3D_DESC desc = {};
desc.Width = UINT(size.width());
desc.Height = UINT(size.height());
- desc.Depth = UINT(m_depth);
+ desc.Depth = UINT(qMax(1, m_depth));
desc.MipLevels = mipLevelCount;
desc.Format = dxgiFormat;
desc.Usage = D3D11_USAGE_DEFAULT;
@@ -3136,7 +3509,8 @@ bool QD3D11Texture::create()
HRESULT hr = rhiD->dev->CreateTexture3D(&desc, nullptr, &tex3D);
if (FAILED(hr)) {
- qWarning("Failed to create 3D texture: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create 3D texture: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
if (!m_objectName.isEmpty())
@@ -3146,9 +3520,6 @@ bool QD3D11Texture::create()
if (!finishCreate())
return false;
- QRHI_PROF;
- QRHI_PROF_F(newTexture(this, true, int(mipLevelCount), isCube ? 6 : 1, int(sampleDesc.Count)));
-
owns = true;
rhiD->registerResource(this);
return true;
@@ -3164,15 +3535,14 @@ bool QD3D11Texture::createFrom(QRhiTexture::NativeTexture src)
if (m_flags.testFlag(ThreeDimensional))
tex3D = reinterpret_cast<ID3D11Texture3D *>(src.object);
+ else if (m_flags.testFlags(OneDimensional))
+ tex1D = reinterpret_cast<ID3D11Texture1D *>(src.object);
else
tex = reinterpret_cast<ID3D11Texture2D *>(src.object);
if (!finishCreate())
return false;
- QRHI_PROF;
- QRHI_PROF_F(newTexture(this, false, int(mipLevelCount), m_flags.testFlag(CubeMap) ? 6 : 1, int(sampleDesc.Count)));
-
owns = false;
QRHI_RES_RHI(QRhiD3D11);
rhiD->registerResource(this);
@@ -3190,15 +3560,20 @@ ID3D11UnorderedAccessView *QD3D11Texture::unorderedAccessViewForLevel(int level)
return perLevelViews[level];
const bool isCube = m_flags.testFlag(CubeMap);
+ const bool isArray = m_flags.testFlag(TextureArray);
const bool is3D = m_flags.testFlag(ThreeDimensional);
- D3D11_UNORDERED_ACCESS_VIEW_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
desc.Format = dxgiFormat;
if (isCube) {
desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.MipSlice = UINT(level);
desc.Texture2DArray.FirstArraySlice = 0;
desc.Texture2DArray.ArraySize = 6;
+ } else if (isArray) {
+ desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
+ desc.Texture2DArray.MipSlice = UINT(level);
+ desc.Texture2DArray.FirstArraySlice = 0;
+ desc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
} else if (is3D) {
desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
desc.Texture3D.MipSlice = UINT(level);
@@ -3211,7 +3586,8 @@ ID3D11UnorderedAccessView *QD3D11Texture::unorderedAccessViewForLevel(int level)
ID3D11UnorderedAccessView *uav = nullptr;
HRESULT hr = rhiD->dev->CreateUnorderedAccessView(textureResource(), &desc, &uav);
if (FAILED(hr)) {
- qWarning("Failed to create UAV: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create UAV: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return nullptr;
}
@@ -3320,8 +3696,7 @@ bool QD3D11Sampler::create()
if (samplerState)
destroy();
- D3D11_SAMPLER_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ D3D11_SAMPLER_DESC desc = {};
desc.Filter = toD3DFilter(m_minFilter, m_magFilter, m_mipmapMode);
if (m_compareOp != Never)
desc.Filter = D3D11_FILTER(desc.Filter | 0x80);
@@ -3335,7 +3710,8 @@ bool QD3D11Sampler::create()
QRHI_RES_RHI(QRhiD3D11);
HRESULT hr = rhiD->dev->CreateSamplerState(&desc, &samplerState);
if (FAILED(hr)) {
- qWarning("Failed to create sampler state: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create sampler state: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
@@ -3357,7 +3733,9 @@ QD3D11RenderPassDescriptor::~QD3D11RenderPassDescriptor()
void QD3D11RenderPassDescriptor::destroy()
{
- // nothing to do here
+ QRHI_RES_RHI(QRhiD3D11);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QD3D11RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
@@ -3368,7 +3746,10 @@ bool QD3D11RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *ot
QRhiRenderPassDescriptor *QD3D11RenderPassDescriptor::newCompatibleRenderPassDescriptor() const
{
- return new QD3D11RenderPassDescriptor(m_rhi);
+ QD3D11RenderPassDescriptor *rpD = new QD3D11RenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiD3D11);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
QVector<quint32> QD3D11RenderPassDescriptor::serializedFormat() const
@@ -3376,33 +3757,33 @@ QVector<quint32> QD3D11RenderPassDescriptor::serializedFormat() const
return {};
}
-QD3D11ReferenceRenderTarget::QD3D11ReferenceRenderTarget(QRhiImplementation *rhi)
- : QRhiRenderTarget(rhi),
+QD3D11SwapChainRenderTarget::QD3D11SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
+ : QRhiSwapChainRenderTarget(rhi, swapchain),
d(rhi)
{
}
-QD3D11ReferenceRenderTarget::~QD3D11ReferenceRenderTarget()
+QD3D11SwapChainRenderTarget::~QD3D11SwapChainRenderTarget()
{
destroy();
}
-void QD3D11ReferenceRenderTarget::destroy()
+void QD3D11SwapChainRenderTarget::destroy()
{
// nothing to do here
}
-QSize QD3D11ReferenceRenderTarget::pixelSize() const
+QSize QD3D11SwapChainRenderTarget::pixelSize() const
{
return d.pixelSize;
}
-float QD3D11ReferenceRenderTarget::devicePixelRatio() const
+float QD3D11SwapChainRenderTarget::devicePixelRatio() const
{
return d.dpr;
}
-int QD3D11ReferenceRenderTarget::sampleCount() const
+int QD3D11SwapChainRenderTarget::sampleCount() const
{
return d.sampleCount;
}
@@ -3450,7 +3831,10 @@ void QD3D11TextureRenderTarget::destroy()
QRhiRenderPassDescriptor *QD3D11TextureRenderTarget::newCompatibleRenderPassDescriptor()
{
- return new QD3D11RenderPassDescriptor(m_rhi);
+ QD3D11RenderPassDescriptor *rpD = new QD3D11RenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiD3D11);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
bool QD3D11TextureRenderTarget::create()
@@ -3458,8 +3842,7 @@ bool QD3D11TextureRenderTarget::create()
if (rtv[0] || dsv)
destroy();
- const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments();
- Q_ASSERT(hasColorAttachments || m_desc.depthTexture());
+ Q_ASSERT(m_desc.colorAttachmentCount() > 0 || m_desc.depthTexture());
Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
@@ -3475,14 +3858,34 @@ bool QD3D11TextureRenderTarget::create()
Q_ASSERT(texture || rb);
if (texture) {
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, texture);
- D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
- memset(&rtvDesc, 0, sizeof(rtvDesc));
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags());
if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
rtvDesc.Texture2DArray.ArraySize = 1;
+ } else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
+ if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY;
+ rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
+ rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
+ rtvDesc.Texture1DArray.ArraySize = 1;
+ } else {
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D;
+ rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
+ }
+ } else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
+ if (texD->sampleDesc.Count > 1) {
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
+ rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
+ rtvDesc.Texture2DMSArray.ArraySize = 1;
+ } else {
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+ rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
+ rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
+ rtvDesc.Texture2DArray.ArraySize = 1;
+ }
} else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
@@ -3498,7 +3901,8 @@ bool QD3D11TextureRenderTarget::create()
}
HRESULT hr = rhiD->dev->CreateRenderTargetView(texD->textureResource(), &rtvDesc, &rtv[attIndex]);
if (FAILED(hr)) {
- qWarning("Failed to create rtv: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create rtv: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
ownsRtv[attIndex] = true;
@@ -3522,14 +3926,35 @@ bool QD3D11TextureRenderTarget::create()
if (m_desc.depthTexture()) {
ownsDsv = true;
QD3D11Texture *depthTexD = QRHI_RES(QD3D11Texture, m_desc.depthTexture());
- D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
- memset(&dsvDesc, 0, sizeof(dsvDesc));
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
dsvDesc.Format = toD3DDepthTextureDSVFormat(depthTexD->format());
dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS
: D3D11_DSV_DIMENSION_TEXTURE2D;
+ if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
+ if (depthTexD->sampleDesc.Count > 1) {
+ dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
+ if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
+ dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
+ dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
+ } else {
+ dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
+ dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
+ }
+ } else {
+ dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
+ if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
+ dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
+ dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
+ } else {
+ dsvDesc.Texture2DArray.FirstArraySlice = 0;
+ dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
+ }
+ }
+ }
HRESULT hr = rhiD->dev->CreateDepthStencilView(depthTexD->tex, &dsvDesc, &dsv);
if (FAILED(hr)) {
- qWarning("Failed to create dsv: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create dsv: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
if (d.colorAttCount == 0) {
@@ -3556,12 +3981,17 @@ bool QD3D11TextureRenderTarget::create()
d.dsv = dsv;
d.rp = QRHI_RES(QD3D11RenderPassDescriptor, m_renderPassDesc);
+ QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D11Texture, QD3D11RenderBuffer>(m_desc, &d.currentResIdList);
+
rhiD->registerResource(this);
return true;
}
QSize QD3D11TextureRenderTarget::pixelSize() const
{
+ if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D11Texture, QD3D11RenderBuffer>(m_desc, d.currentResIdList))
+ const_cast<QD3D11TextureRenderTarget *>(this)->create();
+
return d.pixelSize;
}
@@ -3589,6 +4019,10 @@ void QD3D11ShaderResourceBindings::destroy()
{
sortedBindings.clear();
boundResourceData.clear();
+
+ QRHI_RES_RHI(QRhiD3D11);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QD3D11ShaderResourceBindings::create()
@@ -3603,11 +4037,7 @@ bool QD3D11ShaderResourceBindings::create()
rhiD->updateLayoutDesc(this);
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
- std::sort(sortedBindings.begin(), sortedBindings.end(),
- [](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
- {
- return a.data()->binding < b.data()->binding;
- });
+ std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
boundResourceData.resize(sortedBindings.count());
@@ -3616,7 +4046,7 @@ bool QD3D11ShaderResourceBindings::create()
hasDynamicOffset = false;
for (const QRhiShaderResourceBinding &b : sortedBindings) {
- const QRhiShaderResourceBinding::Data *bd = b.data();
+ const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
hasDynamicOffset = true;
break;
@@ -3624,6 +4054,7 @@ bool QD3D11ShaderResourceBindings::create()
}
generation += 1;
+ rhiD->registerResource(this, false);
return true;
}
@@ -3631,13 +4062,8 @@ void QD3D11ShaderResourceBindings::updateResources(UpdateFlags flags)
{
sortedBindings.clear();
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
- if (!flags.testFlag(BindingsAreSorted)) {
- std::sort(sortedBindings.begin(), sortedBindings.end(),
- [](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
- {
- return a.data()->binding < b.data()->binding;
- });
- }
+ if (!flags.testFlag(BindingsAreSorted))
+ std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
Q_ASSERT(boundResourceData.count() == sortedBindings.count());
for (BoundResourceData &bd : boundResourceData)
@@ -3656,6 +4082,16 @@ QD3D11GraphicsPipeline::~QD3D11GraphicsPipeline()
destroy();
}
+template<typename T>
+inline void releasePipelineShader(T &s)
+{
+ if (s.shader) {
+ s.shader->Release();
+ s.shader = nullptr;
+ }
+ s.nativeResourceBindingMap.clear();
+}
+
void QD3D11GraphicsPipeline::destroy()
{
if (!dsState)
@@ -3679,17 +4115,11 @@ void QD3D11GraphicsPipeline::destroy()
rastState = nullptr;
}
- if (vs.shader) {
- vs.shader->Release();
- vs.shader = nullptr;
- }
- vs.nativeResourceBindingMap.clear();
-
- if (fs.shader) {
- fs.shader->Release();
- fs.shader = nullptr;
- }
- fs.nativeResourceBindingMap.clear();
+ releasePipelineShader(vs);
+ releasePipelineShader(hs);
+ releasePipelineShader(ds);
+ releasePipelineShader(gs);
+ releasePipelineShader(fs);
QRHI_RES_RHI(QRhiD3D11);
if (rhiD)
@@ -3711,6 +4141,19 @@ static inline D3D11_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
}
}
+static inline D3D11_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
+{
+ switch (mode) {
+ case QRhiGraphicsPipeline::Fill:
+ return D3D11_FILL_SOLID;
+ case QRhiGraphicsPipeline::Line:
+ return D3D11_FILL_WIREFRAME;
+ default:
+ Q_UNREACHABLE();
+ return D3D11_FILL_SOLID;
+ }
+}
+
static inline D3D11_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
{
switch (op) {
@@ -3794,13 +4237,37 @@ static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format
return DXGI_FORMAT_R32G32_SINT;
case QRhiVertexInputAttribute::SInt:
return DXGI_FORMAT_R32_SINT;
+ case QRhiVertexInputAttribute::Half4:
+ // Note: D3D does not support half3. Pass through half3 as half4.
+ case QRhiVertexInputAttribute::Half3:
+ return DXGI_FORMAT_R16G16B16A16_FLOAT;
+ case QRhiVertexInputAttribute::Half2:
+ return DXGI_FORMAT_R16G16_FLOAT;
+ case QRhiVertexInputAttribute::Half:
+ return DXGI_FORMAT_R16_FLOAT;
+ case QRhiVertexInputAttribute::UShort4:
+ // Note: D3D does not support UShort3. Pass through UShort3 as UShort4.
+ case QRhiVertexInputAttribute::UShort3:
+ return DXGI_FORMAT_R16G16B16A16_UINT;
+ case QRhiVertexInputAttribute::UShort2:
+ return DXGI_FORMAT_R16G16_UINT;
+ case QRhiVertexInputAttribute::UShort:
+ return DXGI_FORMAT_R16_UINT;
+ case QRhiVertexInputAttribute::SShort4:
+ // Note: D3D does not support SShort3. Pass through SShort3 as SShort4.
+ case QRhiVertexInputAttribute::SShort3:
+ return DXGI_FORMAT_R16G16B16A16_SINT;
+ case QRhiVertexInputAttribute::SShort2:
+ return DXGI_FORMAT_R16G16_SINT;
+ case QRhiVertexInputAttribute::SShort:
+ return DXGI_FORMAT_R16_SINT;
default:
Q_UNREACHABLE();
return DXGI_FORMAT_R32G32B32A32_FLOAT;
}
}
-static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t)
+static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t, int patchControlPointCount)
{
switch (t) {
case QRhiGraphicsPipeline::Triangles:
@@ -3813,6 +4280,9 @@ static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topol
return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP;
case QRhiGraphicsPipeline::Points:
return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
+ case QRhiGraphicsPipeline::Patches:
+ Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
+ return D3D11_PRIMITIVE_TOPOLOGY(D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
default:
Q_UNREACHABLE();
return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
@@ -3903,20 +4373,16 @@ static inline D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
}
}
-static pD3DCompile resolveD3DCompile()
+static inline QByteArray sourceHash(const QByteArray &source)
{
- for (const wchar_t *libraryName : {L"D3DCompiler_47", L"D3DCompiler_43"}) {
- QSystemLibrary library(libraryName);
- if (library.load()) {
- if (auto symbol = library.resolve("D3DCompile"))
- return reinterpret_cast<pD3DCompile>(symbol);
- }
- }
- return nullptr;
+ // taken from the GL backend, use the same mechanism to get a key
+ QCryptographicHash keyBuilder(QCryptographicHash::Sha1);
+ keyBuilder.addData(source);
+ return keyBuilder.result().toHex();
}
-static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, UINT flags,
- QString *error, QShaderKey *usedShaderKey)
+QByteArray QRhiD3D11::compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, uint flags,
+ QString *error, QShaderKey *usedShaderKey)
{
QShaderKey key = { QShader::DxbcShader, 50, shaderVariant };
QShaderCode dxbc = shader.shader(key);
@@ -3933,6 +4399,9 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian
return QByteArray();
}
+ if (usedShaderKey)
+ *usedShaderKey = key;
+
const char *target;
switch (shader.stage()) {
case QShader::VertexStage:
@@ -3958,7 +4427,18 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian
return QByteArray();
}
- static const pD3DCompile d3dCompile = resolveD3DCompile();
+ BytecodeCacheKey cacheKey;
+ if (rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave)) {
+ cacheKey.sourceHash = sourceHash(hlslSource.shader());
+ cacheKey.target = target;
+ cacheKey.entryPoint = hlslSource.entryPoint();
+ cacheKey.compileFlags = flags;
+ auto cacheIt = m_bytecodeCache.constFind(cacheKey);
+ if (cacheIt != m_bytecodeCache.constEnd())
+ return cacheIt.value();
+ }
+
+ static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
if (d3dCompile == nullptr) {
qWarning("Unable to resolve function D3DCompile()");
return QByteArray();
@@ -3979,13 +4459,14 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian
return QByteArray();
}
- if (usedShaderKey)
- *usedShaderKey = key;
-
QByteArray result;
result.resize(int(bytecode->GetBufferSize()));
memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
bytecode->Release();
+
+ if (rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
+ m_bytecodeCache.insert(cacheKey, result);
+
return result;
}
@@ -3995,27 +4476,27 @@ bool QD3D11GraphicsPipeline::create()
destroy();
QRHI_RES_RHI(QRhiD3D11);
+ rhiD->pipelineCreationStart();
if (!rhiD->sanityCheckGraphicsPipeline(this))
return false;
- D3D11_RASTERIZER_DESC rastDesc;
- memset(&rastDesc, 0, sizeof(rastDesc));
- rastDesc.FillMode = D3D11_FILL_SOLID;
+ D3D11_RASTERIZER_DESC rastDesc = {};
+ rastDesc.FillMode = toD3DFillMode(m_polygonMode);
rastDesc.CullMode = toD3DCullMode(m_cullMode);
rastDesc.FrontCounterClockwise = m_frontFace == CCW;
rastDesc.DepthBias = m_depthBias;
rastDesc.SlopeScaledDepthBias = m_slopeScaledDepthBias;
rastDesc.DepthClipEnable = true;
rastDesc.ScissorEnable = m_flags.testFlag(UsesScissor);
- rastDesc.MultisampleEnable = rhiD->effectiveSampleCount(m_sampleCount).Count > 1;
+ rastDesc.MultisampleEnable = rhiD->effectiveSampleDesc(m_sampleCount).Count > 1;
HRESULT hr = rhiD->dev->CreateRasterizerState(&rastDesc, &rastState);
if (FAILED(hr)) {
- qWarning("Failed to create rasterizer state: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create rasterizer state: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
- D3D11_DEPTH_STENCIL_DESC dsDesc;
- memset(&dsDesc, 0, sizeof(dsDesc));
+ D3D11_DEPTH_STENCIL_DESC dsDesc = {};
dsDesc.DepthEnable = m_depthTest;
dsDesc.DepthWriteMask = m_depthWrite ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
dsDesc.DepthFunc = toD3DCompareOp(m_depthOp);
@@ -4034,17 +4515,16 @@ bool QD3D11GraphicsPipeline::create()
}
hr = rhiD->dev->CreateDepthStencilState(&dsDesc, &dsState);
if (FAILED(hr)) {
- qWarning("Failed to create depth-stencil state: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create depth-stencil state: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
- D3D11_BLEND_DESC blendDesc;
- memset(&blendDesc, 0, sizeof(blendDesc));
+ D3D11_BLEND_DESC blendDesc = {};
blendDesc.IndependentBlendEnable = m_targetBlends.count() > 1;
for (int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
- D3D11_RENDER_TARGET_BLEND_DESC blend;
- memset(&blend, 0, sizeof(blend));
+ D3D11_RENDER_TARGET_BLEND_DESC blend = {};
blend.BlendEnable = b.enable;
blend.SrcBlend = toD3DBlendFactor(b.srcColor, true);
blend.DestBlend = toD3DBlendFactor(b.dstColor, true);
@@ -4056,19 +4536,19 @@ bool QD3D11GraphicsPipeline::create()
blendDesc.RenderTarget[i] = blend;
}
if (m_targetBlends.isEmpty()) {
- D3D11_RENDER_TARGET_BLEND_DESC blend;
- memset(&blend, 0, sizeof(blend));
+ D3D11_RENDER_TARGET_BLEND_DESC blend = {};
blend.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
blendDesc.RenderTarget[0] = blend;
}
hr = rhiD->dev->CreateBlendState(&blendDesc, &blendState);
if (FAILED(hr)) {
- qWarning("Failed to create blend state: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create blend state: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
QByteArray vsByteCode;
- for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
+ for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
auto cacheIt = rhiD->m_shaderCache.constFind(shaderStage);
if (cacheIt != rhiD->m_shaderCache.constEnd()) {
switch (shaderStage.type()) {
@@ -4078,6 +4558,21 @@ bool QD3D11GraphicsPipeline::create()
vsByteCode = cacheIt->bytecode;
vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
break;
+ case QRhiShaderStage::TessellationControl:
+ hs.shader = static_cast<ID3D11HullShader *>(cacheIt->s);
+ hs.shader->AddRef();
+ hs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
+ break;
+ case QRhiShaderStage::TessellationEvaluation:
+ ds.shader = static_cast<ID3D11DomainShader *>(cacheIt->s);
+ ds.shader->AddRef();
+ ds.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
+ break;
+ case QRhiShaderStage::Geometry:
+ gs.shader = static_cast<ID3D11GeometryShader *>(cacheIt->s);
+ gs.shader->AddRef();
+ gs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
+ break;
case QRhiShaderStage::Fragment:
fs.shader = static_cast<ID3D11PixelShader *>(cacheIt->s);
fs.shader->AddRef();
@@ -4093,8 +4588,8 @@ bool QD3D11GraphicsPipeline::create()
if (m_flags.testFlag(CompileShadersWithDebugInfo))
compileFlags |= D3DCOMPILE_DEBUG;
- const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), compileFlags,
- &error, &shaderKey);
+ const QByteArray bytecode = rhiD->compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), compileFlags,
+ &error, &shaderKey);
if (bytecode.isEmpty()) {
qWarning("HLSL shader compilation failed: %s", qPrintable(error));
return false;
@@ -4109,23 +4604,56 @@ bool QD3D11GraphicsPipeline::create()
case QRhiShaderStage::Vertex:
hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs.shader);
if (FAILED(hr)) {
- qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create vertex shader: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
vsByteCode = bytecode;
- if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey))
- vs.nativeResourceBindingMap = *map;
+ vs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap));
vs.shader->AddRef();
break;
+ case QRhiShaderStage::TessellationControl:
+ hr = rhiD->dev->CreateHullShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &hs.shader);
+ if (FAILED(hr)) {
+ qWarning("Failed to create hull shader: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ hs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
+ rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(hs.shader, bytecode, hs.nativeResourceBindingMap));
+ hs.shader->AddRef();
+ break;
+ case QRhiShaderStage::TessellationEvaluation:
+ hr = rhiD->dev->CreateDomainShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &ds.shader);
+ if (FAILED(hr)) {
+ qWarning("Failed to create domain shader: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ ds.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
+ rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(ds.shader, bytecode, ds.nativeResourceBindingMap));
+ ds.shader->AddRef();
+ break;
+ case QRhiShaderStage::Geometry:
+ hr = rhiD->dev->CreateGeometryShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &gs.shader);
+ if (FAILED(hr)) {
+ qWarning("Failed to create geometry shader: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ gs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
+ rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(gs.shader, bytecode, gs.nativeResourceBindingMap));
+ gs.shader->AddRef();
+ break;
case QRhiShaderStage::Fragment:
hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader);
if (FAILED(hr)) {
- qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create pixel shader: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
- if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey))
- fs.nativeResourceBindingMap = *map;
+ fs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs.shader, bytecode, fs.nativeResourceBindingMap));
fs.shader->AddRef();
break;
@@ -4135,7 +4663,7 @@ bool QD3D11GraphicsPipeline::create()
}
}
- d3dTopology = toD3DTopology(m_topology);
+ d3dTopology = toD3DTopology(m_topology, m_patchControlPointCount);
if (!vsByteCode.isEmpty()) {
QByteArrayList matrixSliceSemantics;
@@ -4143,8 +4671,7 @@ bool QD3D11GraphicsPipeline::create()
for (auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
it != itEnd; ++it)
{
- D3D11_INPUT_ELEMENT_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ D3D11_INPUT_ELEMENT_DESC desc = {};
// The output from SPIRV-Cross uses TEXCOORD<location> as the
// semantic, except for matrices that are unrolled into consecutive
// vec2/3/4s attributes and need TEXCOORD<location>_ as
@@ -4167,7 +4694,7 @@ bool QD3D11GraphicsPipeline::create()
const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
desc.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
- desc.InstanceDataStepRate = UINT(inputBinding->instanceStepRate());
+ desc.InstanceDataStepRate = inputBinding->instanceStepRate();
} else {
desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
}
@@ -4177,12 +4704,14 @@ bool QD3D11GraphicsPipeline::create()
hr = rhiD->dev->CreateInputLayout(inputDescs.constData(), UINT(inputDescs.count()),
vsByteCode, SIZE_T(vsByteCode.size()), &inputLayout);
if (FAILED(hr)) {
- qWarning("Failed to create input layout: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create input layout: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
} // else leave inputLayout set to nullptr; that's valid and it avoids a debug layer warning about an input layout with 0 elements
}
+ rhiD->pipelineCreationEnd();
generation += 1;
rhiD->registerResource(this);
return true;
@@ -4218,6 +4747,7 @@ bool QD3D11ComputePipeline::create()
destroy();
QRHI_RES_RHI(QRhiD3D11);
+ rhiD->pipelineCreationStart();
auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage);
if (cacheIt != rhiD->m_shaderCache.constEnd()) {
@@ -4230,8 +4760,8 @@ bool QD3D11ComputePipeline::create()
if (m_flags.testFlag(CompileShadersWithDebugInfo))
compileFlags |= D3DCOMPILE_DEBUG;
- const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), compileFlags,
- &error, &shaderKey);
+ const QByteArray bytecode = rhiD->compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), compileFlags,
+ &error, &shaderKey);
if (bytecode.isEmpty()) {
qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
return false;
@@ -4239,12 +4769,12 @@ bool QD3D11ComputePipeline::create()
HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs.shader);
if (FAILED(hr)) {
- qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create compute shader: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
- if (const QShader::NativeResourceBindingMap *map = m_shaderStage.shader().nativeResourceBindingMap(shaderKey))
- cs.nativeResourceBindingMap = *map;
+ cs.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES)
rhiD->clearShaderCache();
@@ -4254,6 +4784,7 @@ bool QD3D11ComputePipeline::create()
cs.shader->AddRef();
+ rhiD->pipelineCreationEnd();
generation += 1;
rhiD->registerResource(this);
return true;
@@ -4275,20 +4806,93 @@ void QD3D11CommandBuffer::destroy()
// nothing to do here
}
+bool QD3D11SwapChainTimestamps::prepare(QRhiD3D11 *rhiD)
+{
+ // Creates the query objects if not yet done, but otherwise calling this
+ // function is expected to be a no-op.
+
+ D3D11_QUERY_DESC queryDesc = {};
+ for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
+ if (!disjointQuery[i]) {
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
+ HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &disjointQuery[i]);
+ if (FAILED(hr)) {
+ qWarning("Failed to create timestamp disjoint query: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ }
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP;
+ for (int j = 0; j < 2; ++j) {
+ const int idx = 2 * i + j;
+ if (!query[idx]) {
+ HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &query[idx]);
+ if (FAILED(hr)) {
+ qWarning("Failed to create timestamp query: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void QD3D11SwapChainTimestamps::destroy()
+{
+ for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
+ active[i] = false;
+ if (disjointQuery[i]) {
+ disjointQuery[i]->Release();
+ disjointQuery[i] = nullptr;
+ }
+ for (int j = 0; j < 2; ++j) {
+ const int idx = TIMESTAMP_PAIRS * i + j;
+ if (query[idx]) {
+ query[idx]->Release();
+ query[idx] = nullptr;
+ }
+ }
+ }
+}
+
+bool QD3D11SwapChainTimestamps::tryQueryTimestamps(int pairIndex, ID3D11DeviceContext *context, double *elapsedSec)
+{
+ bool result = false;
+ if (!active[pairIndex])
+ return result;
+
+ ID3D11Query *tsDisjoint = disjointQuery[pairIndex];
+ ID3D11Query *tsStart = query[pairIndex * 2];
+ ID3D11Query *tsEnd = query[pairIndex * 2 + 1];
+ quint64 timestamps[2];
+ D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
+
+ bool ok = true;
+ ok &= context->GetData(tsDisjoint, &dj, sizeof(dj), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
+ ok &= context->GetData(tsEnd, &timestamps[1], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
+ ok &= context->GetData(tsStart, &timestamps[0], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
+
+ if (ok) {
+ if (!dj.Disjoint && dj.Frequency) {
+ const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
+ *elapsedSec = elapsedMs / 1000.0;
+ result = true;
+ }
+ active[pairIndex] = false;
+ } // else leave active set, will retry in a subsequent beginFrame
+
+ return result;
+}
+
QD3D11SwapChain::QD3D11SwapChain(QRhiImplementation *rhi)
- : QRhiSwapChain(rhi),
- rt(rhi),
- cb(rhi)
+ : QRhiSwapChain(rhi), rt(rhi, this), rtRight(rhi, this), cb(rhi)
{
backBufferTex = nullptr;
backBufferRtv = nullptr;
for (int i = 0; i < BUFFER_COUNT; ++i) {
msaaTex[i] = nullptr;
msaaRtv[i] = nullptr;
- timestampActive[i] = false;
- timestampDisjointQuery[i] = nullptr;
- timestampQuery[2 * i] = nullptr;
- timestampQuery[2 * i + 1] = nullptr;
}
}
@@ -4303,6 +4907,10 @@ void QD3D11SwapChain::releaseBuffers()
backBufferRtv->Release();
backBufferRtv = nullptr;
}
+ if (backBufferRtvRight) {
+ backBufferRtvRight->Release();
+ backBufferRtvRight = nullptr;
+ }
if (backBufferTex) {
backBufferTex->Release();
backBufferTex = nullptr;
@@ -4326,28 +4934,27 @@ void QD3D11SwapChain::destroy()
releaseBuffers();
- for (int i = 0; i < BUFFER_COUNT; ++i) {
- if (timestampDisjointQuery[i]) {
- timestampDisjointQuery[i]->Release();
- timestampDisjointQuery[i] = nullptr;
- }
- for (int j = 0; j < 2; ++j) {
- const int idx = BUFFER_COUNT * i + j;
- if (timestampQuery[idx]) {
- timestampQuery[idx]->Release();
- timestampQuery[idx] = nullptr;
- }
- }
- }
+ timestamps.destroy();
swapChain->Release();
swapChain = nullptr;
+ if (dcompVisual) {
+ dcompVisual->Release();
+ dcompVisual = nullptr;
+ }
+
+ if (dcompTarget) {
+ dcompTarget->Release();
+ dcompTarget = nullptr;
+ }
+
QRHI_RES_RHI(QRhiD3D11);
if (rhiD) {
- QRHI_PROF;
- QRHI_PROF_F(releaseSwapChain(this));
rhiD->unregisterResource(this);
+ // See Deferred Destruction Issues with Flip Presentation Swap Chains in
+ // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-flush
+ rhiD->context->Flush();
}
}
@@ -4361,22 +4968,67 @@ QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget()
return &rt;
}
+QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
+{
+ return targetBuffer == StereoTargetBuffer::LeftBuffer? &rt: &rtRight;
+}
+
QSize QD3D11SwapChain::surfacePixelSize()
{
Q_ASSERT(m_window);
return m_window->size() * m_window->devicePixelRatio();
}
+bool QD3D11SwapChain::isFormatSupported(Format f)
+{
+ if (f == SDR)
+ return true;
+
+ if (!m_window) {
+ qWarning("Attempted to call isFormatSupported() without a window set");
+ return false;
+ }
+
+ QRHI_RES_RHI(QRhiD3D11);
+ DXGI_OUTPUT_DESC1 desc1;
+ if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) {
+ if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
+ return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
+ }
+
+ return false;
+}
+
+QRhiSwapChainHdrInfo QD3D11SwapChain::hdrInfo()
+{
+ QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
+ // Must use m_window, not window, given this may be called before createOrResize().
+ if (m_window) {
+ QRHI_RES_RHI(QRhiD3D11);
+ DXGI_OUTPUT_DESC1 hdrOutputDesc;
+ if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
+ info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits;
+ info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
+ info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
+ info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits
+ info.sdrWhiteLevel = QRhiD3D::sdrWhiteLevelInNits(hdrOutputDesc);
+ }
+ }
+ return info;
+}
+
QRhiRenderPassDescriptor *QD3D11SwapChain::newCompatibleRenderPassDescriptor()
{
- return new QD3D11RenderPassDescriptor(m_rhi);
+ QD3D11RenderPassDescriptor *rpD = new QD3D11RenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiD3D11);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
bool QD3D11SwapChain::newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const
{
- D3D11_TEXTURE2D_DESC desc;
- memset(&desc, 0, sizeof(desc));
+ D3D11_TEXTURE2D_DESC desc = {};
desc.Width = UINT(size.width());
desc.Height = UINT(size.height());
desc.MipLevels = 1;
@@ -4389,17 +5041,18 @@ bool QD3D11SwapChain::newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI
QRHI_RES_RHI(QRhiD3D11);
HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, tex);
if (FAILED(hr)) {
- qWarning("Failed to create color buffer texture: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create color buffer texture: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
- D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
- memset(&rtvDesc, 0, sizeof(rtvDesc));
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
rtvDesc.Format = format;
rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;
hr = rhiD->dev->CreateRenderTargetView(*tex, &rtvDesc, rtv);
if (FAILED(hr)) {
- qWarning("Failed to create color buffer rtv: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create color buffer rtv: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
(*tex)->Release();
*tex = nullptr;
return false;
@@ -4408,6 +5061,19 @@ bool QD3D11SwapChain::newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI
return true;
}
+bool QRhiD3D11::ensureDirectCompositionDevice()
+{
+ if (dcompDevice)
+ return true;
+
+ qCDebug(QRHI_LOG_INFO, "Creating Direct Composition device (needed for semi-transparent windows)");
+ dcompDevice = QRhiD3D::createDirectCompositionDevice();
+ return dcompDevice ? true : false;
+}
+
+static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
+static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
+
bool QD3D11SwapChain::createOrResize()
{
// Can be called multiple times due to window resizes - that is not the
@@ -4415,6 +5081,7 @@ bool QD3D11SwapChain::createOrResize()
// resize the buffers then.
const bool needsRegistration = !window || window != m_window;
+ const bool stereo = m_window->format().stereo();
// except if the window actually changes
if (window && window != m_window)
@@ -4427,101 +5094,183 @@ bool QD3D11SwapChain::createOrResize()
if (pixelSize.isEmpty())
return false;
- colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
- const DXGI_FORMAT srgbAdjustedFormat = m_flags.testFlag(sRGB) ?
- DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
-
- const UINT swapChainFlags = 0;
+ HWND hwnd = reinterpret_cast<HWND>(window->winId());
+ HRESULT hr;
QRHI_RES_RHI(QRhiD3D11);
- bool useFlipDiscard = rhiD->hasDxgi2 && rhiD->supportsFlipDiscardSwapchain;
+
+ if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
+ if (!rhiD->useLegacySwapchainModel && rhiD->ensureDirectCompositionDevice()) {
+ if (!dcompTarget) {
+ hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd, false, &dcompTarget);
+ if (FAILED(hr)) {
+ qWarning("Failed to create Direct Compsition target for the window: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ }
+ }
+ if (dcompTarget && !dcompVisual) {
+ hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
+ if (FAILED(hr)) {
+ qWarning("Failed to create DirectComposition visual: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ }
+ }
+ }
+ // simple consistency check
+ if (window->requestedFormat().alphaBufferSize() <= 0)
+ qWarning("Swapchain says surface has alpha but the window has no alphaBufferSize set. "
+ "This may lead to problems.");
+ }
+
+ swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
+ swapChainFlags = 0;
+
+ // A non-flip swapchain can do Present(0) as expected without
+ // ALLOW_TEARING, and ALLOW_TEARING is not compatible with it at all so the
+ // flag must not be set then. Whereas for flip we should use it, if
+ // supported, to get better results for 'unthrottled' presentation.
+ if (swapInterval == 0 && rhiD->supportsAllowTearing)
+ swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
+
if (!swapChain) {
- HWND hwnd = reinterpret_cast<HWND>(window->winId());
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
-
- // Take a shortcut for alpha: our QWindow is OpenGLSurface so whatever
- // the platform plugin does to enable transparency for OpenGL window
- // will be sufficient for us too on the legacy (DISCARD) path. For
- // FLIP_DISCARD we'd need to use DirectComposition (create a
- // IDCompositionDevice/Target/Visual), avoid that for now.
- if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
- useFlipDiscard = false;
- if (window->requestedFormat().alphaBufferSize() <= 0)
- qWarning("Swapchain says surface has alpha but the window has no alphaBufferSize set. "
- "This may lead to problems.");
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
+ colorFormat = DEFAULT_FORMAT;
+ srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
+
+ DXGI_COLOR_SPACE_TYPE hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR
+ DXGI_OUTPUT_DESC1 hdrOutputDesc;
+ if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) {
+ // https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range
+ if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
+ switch (m_format) {
+ case HDRExtendedSrgbLinear:
+ colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
+ hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
+ srgbAdjustedColorFormat = colorFormat;
+ break;
+ case HDR10:
+ colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
+ hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
+ srgbAdjustedColorFormat = colorFormat;
+ break;
+ default:
+ break;
+ }
+ } else {
+ // This happens also when Use HDR is set to Off in the Windows
+ // Display settings. Show a helpful warning, but continue with the
+ // default non-HDR format.
+ qWarning("The output associated with the window is not HDR capable "
+ "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
+ }
}
- HRESULT hr;
- if (useFlipDiscard) {
- // We use FLIP_DISCARD which implies a buffer count of 2 (as opposed to the
- // old DISCARD with back buffer count == 1). This makes no difference for
- // the rest of the stuff except that automatic MSAA is unsupported and
- // needs to be implemented via a custom multisample render target and an
- // explicit resolve.
-
- DXGI_SWAP_CHAIN_DESC1 desc;
- memset(&desc, 0, sizeof(desc));
- desc.Width = UINT(pixelSize.width());
- desc.Height = UINT(pixelSize.height());
- desc.Format = colorFormat;
- desc.SampleDesc.Count = 1;
- desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- desc.BufferCount = BUFFER_COUNT;
+ // We use a FLIP model swapchain which implies a buffer count of 2
+ // (as opposed to the old DISCARD with back buffer count == 1).
+ // This makes no difference for the rest of the stuff except that
+ // automatic MSAA is unsupported and needs to be implemented via a
+ // custom multisample render target and an explicit resolve.
+
+ DXGI_SWAP_CHAIN_DESC1 desc = {};
+ desc.Width = UINT(pixelSize.width());
+ desc.Height = UINT(pixelSize.height());
+ desc.Format = colorFormat;
+ desc.SampleDesc.Count = 1;
+ desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ desc.BufferCount = BUFFER_COUNT;
+ desc.Flags = swapChainFlags;
+ desc.Scaling = rhiD->useLegacySwapchainModel ? DXGI_SCALING_STRETCH : DXGI_SCALING_NONE;
+ desc.SwapEffect = rhiD->useLegacySwapchainModel ? DXGI_SWAP_EFFECT_DISCARD : DXGI_SWAP_EFFECT_FLIP_DISCARD;
+ desc.Stereo = stereo;
+
+ if (dcompVisual) {
+ // With DirectComposition setting AlphaMode to STRAIGHT fails the
+ // swapchain creation, whereas the result seems to be identical
+ // with any of the other values, including IGNORE. (?)
+ desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
+
+ // DirectComposition has its own limitations, cannot use
+ // SCALING_NONE. So with semi-transparency requested we are forced
+ // to SCALING_STRETCH.
desc.Scaling = DXGI_SCALING_STRETCH;
- desc.SwapEffect = DXGI_SWAP_EFFECT(4); // DXGI_SWAP_EFFECT_FLIP_DISCARD
- // Do not bother with AlphaMode, if won't work unless we go through
- // DirectComposition. Instead, we just take the other (DISCARD)
- // path for now when alpha is requested.
- desc.Flags = swapChainFlags;
-
- IDXGISwapChain1 *sc1;
- hr = static_cast<IDXGIFactory2 *>(rhiD->dxgiFactory)->CreateSwapChainForHwnd(rhiD->dev, hwnd, &desc,
- nullptr, nullptr, &sc1);
- if (SUCCEEDED(hr))
- swapChain = sc1;
- } else {
- // Windows 7 for instance. Use DISCARD mode. Regardless, keep on
- // using our manual resolve for symmetry with the FLIP_DISCARD code
- // path when MSAA is requested.
-
- DXGI_SWAP_CHAIN_DESC desc;
- memset(&desc, 0, sizeof(desc));
- desc.BufferDesc.Width = UINT(pixelSize.width());
- desc.BufferDesc.Height = UINT(pixelSize.height());
- desc.BufferDesc.RefreshRate.Numerator = 60;
- desc.BufferDesc.RefreshRate.Denominator = 1;
- desc.BufferDesc.Format = colorFormat;
- desc.SampleDesc.Count = 1;
- desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- desc.BufferCount = 1;
- desc.OutputWindow = hwnd;
- desc.Windowed = true;
- desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
- desc.Flags = swapChainFlags;
-
- hr = rhiD->dxgiFactory->CreateSwapChain(rhiD->dev, &desc, &swapChain);
+ }
+
+ IDXGIFactory2 *fac = static_cast<IDXGIFactory2 *>(rhiD->dxgiFactory);
+ IDXGISwapChain1 *sc1;
+
+ if (dcompVisual)
+ hr = fac->CreateSwapChainForComposition(rhiD->dev, &desc, nullptr, &sc1);
+ else
+ hr = fac->CreateSwapChainForHwnd(rhiD->dev, hwnd, &desc, nullptr, nullptr, &sc1);
+
+ // If failed and we tried a HDR format, then try with SDR. This
+ // matches other backends, such as Vulkan where if the format is
+ // not supported, the default one is used instead.
+ if (FAILED(hr) && m_format != SDR) {
+ colorFormat = DEFAULT_FORMAT;
+ desc.Format = DEFAULT_FORMAT;
+ if (dcompVisual)
+ hr = fac->CreateSwapChainForComposition(rhiD->dev, &desc, nullptr, &sc1);
+ else
+ hr = fac->CreateSwapChainForHwnd(rhiD->dev, hwnd, &desc, nullptr, nullptr, &sc1);
+ }
+
+ if (SUCCEEDED(hr)) {
+ swapChain = sc1;
+ if (m_format != SDR) {
+ IDXGISwapChain3 *sc3 = nullptr;
+ if (SUCCEEDED(sc1->QueryInterface(__uuidof(IDXGISwapChain3), reinterpret_cast<void **>(&sc3)))) {
+ hr = sc3->SetColorSpace1(hdrColorSpace);
+ if (FAILED(hr))
+ qWarning("Failed to set color space on swapchain: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ sc3->Release();
+ } else {
+ qWarning("IDXGISwapChain3 not available, HDR swapchain will not work as expected");
+ }
+ }
+ if (dcompVisual) {
+ hr = dcompVisual->SetContent(sc1);
+ if (SUCCEEDED(hr)) {
+ hr = dcompTarget->SetRoot(dcompVisual);
+ if (FAILED(hr)) {
+ qWarning("Failed to associate Direct Composition visual with the target: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ }
+ } else {
+ qWarning("Failed to set content for Direct Composition visual: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ }
+ } else {
+ // disable Alt+Enter; not relevant when using DirectComposition
+ rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
+ }
}
if (FAILED(hr)) {
- qWarning("Failed to create D3D11 swapchain: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create D3D11 swapchain: %s"
+ " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
+ qPrintable(QSystemError::windowsComString(hr)),
+ desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
+ desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
return false;
}
- rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
} else {
releaseBuffers();
- const UINT count = useFlipDiscard ? BUFFER_COUNT : 1;
- HRESULT hr = swapChain->ResizeBuffers(count, UINT(pixelSize.width()), UINT(pixelSize.height()),
- colorFormat, swapChainFlags);
+ // flip model -> buffer count is the real buffer count, not 1 like with the legacy modes
+ hr = swapChain->ResizeBuffers(UINT(BUFFER_COUNT), UINT(pixelSize.width()), UINT(pixelSize.height()),
+ colorFormat, swapChainFlags);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
qWarning("Device loss detected in ResizeBuffers()");
rhiD->deviceLost = true;
return false;
} else if (FAILED(hr)) {
- qWarning("Failed to resize D3D11 swapchain: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to resize D3D11 swapchain: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
}
- // This looks odd (for FLIP_DISCARD, esp. compared with backends for Vulkan
+ // This looks odd (for FLIP_*, esp. compared with backends for Vulkan
// & co.) but the backbuffer is always at index 0, with magic underneath.
// Some explanation from
// https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-1-4-improvements
@@ -4535,25 +5284,39 @@ bool QD3D11SwapChain::createOrResize()
// swapchain."
// So just query index 0 once (per resize) and be done with it.
- HRESULT hr = swapChain->GetBuffer(0, IID_ID3D11Texture2D, reinterpret_cast<void **>(&backBufferTex));
+ hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&backBufferTex));
if (FAILED(hr)) {
- qWarning("Failed to query swapchain backbuffer: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to query swapchain backbuffer: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
- D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
- memset(&rtvDesc, 0, sizeof(rtvDesc));
- rtvDesc.Format = srgbAdjustedFormat;
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
+ rtvDesc.Format = srgbAdjustedColorFormat;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtv);
if (FAILED(hr)) {
- qWarning("Failed to create rtv for swapchain backbuffer: %s", qPrintable(comErrorMessage(hr)));
+ qWarning("Failed to create rtv for swapchain backbuffer: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
return false;
}
+ if (stereo) {
+ // Create a second render target view for the right eye
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+ rtvDesc.Texture2DArray.FirstArraySlice = 1;
+ rtvDesc.Texture2DArray.ArraySize = 1;
+ hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtvRight);
+ if (FAILED(hr)) {
+ qWarning("Failed to create rtv for swapchain backbuffer (right eye): %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ }
+
// Try to reduce stalls by having a dedicated MSAA texture per swapchain buffer.
for (int i = 0; i < BUFFER_COUNT; ++i) {
if (sampleDesc.Count > 1) {
- if (!newColorBuffer(pixelSize, srgbAdjustedFormat, sampleDesc, &msaaTex[i], &msaaRtv[i]))
+ if (!newColorBuffer(pixelSize, srgbAdjustedColorFormat, sampleDesc, &msaaTex[i], &msaaRtv[i]))
return false;
}
}
@@ -4578,9 +5341,9 @@ bool QD3D11SwapChain::createOrResize()
currentFrameSlot = 0;
frameCount = 0;
ds = m_depthStencil ? QRHI_RES(QD3D11RenderBuffer, m_depthStencil) : nullptr;
- swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
- QD3D11ReferenceRenderTarget *rtD = QRHI_RES(QD3D11ReferenceRenderTarget, &rt);
+ rt.setRenderPassDescriptor(m_renderPassDesc); // for the public getter in QRhiRenderTarget
+ QD3D11SwapChainRenderTarget *rtD = QRHI_RES(QD3D11SwapChainRenderTarget, &rt);
rtD->d.rp = QRHI_RES(QD3D11RenderPassDescriptor, m_renderPassDesc);
rtD->d.pixelSize = pixelSize;
rtD->d.dpr = float(window->devicePixelRatio());
@@ -4588,32 +5351,20 @@ bool QD3D11SwapChain::createOrResize()
rtD->d.colorAttCount = 1;
rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
- QRHI_PROF;
- QRHI_PROF_F(resizeSwapChain(this, BUFFER_COUNT, sampleDesc.Count > 1 ? BUFFER_COUNT : 0, int(sampleDesc.Count)));
- if (rhiP) {
- D3D11_QUERY_DESC queryDesc;
- memset(&queryDesc, 0, sizeof(queryDesc));
- for (int i = 0; i < BUFFER_COUNT; ++i) {
- if (!timestampDisjointQuery[i]) {
- queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
- HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &timestampDisjointQuery[i]);
- if (FAILED(hr)) {
- qWarning("Failed to create timestamp disjoint query: %s", qPrintable(comErrorMessage(hr)));
- break;
- }
- }
- queryDesc.Query = D3D11_QUERY_TIMESTAMP;
- for (int j = 0; j < 2; ++j) {
- const int idx = BUFFER_COUNT * i + j; // one pair per buffer (frame)
- if (!timestampQuery[idx]) {
- HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &timestampQuery[idx]);
- if (FAILED(hr)) {
- qWarning("Failed to create timestamp query: %s", qPrintable(comErrorMessage(hr)));
- break;
- }
- }
- }
- }
+ if (stereo) {
+ rtD = QRHI_RES(QD3D11SwapChainRenderTarget, &rtRight);
+ rtD->d.rp = QRHI_RES(QD3D11RenderPassDescriptor, m_renderPassDesc);
+ rtD->d.pixelSize = pixelSize;
+ rtD->d.dpr = float(window->devicePixelRatio());
+ rtD->d.sampleCount = int(sampleDesc.Count);
+ rtD->d.colorAttCount = 1;
+ rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
+ rtD->d.rtv[0] = backBufferRtvRight;
+ rtD->d.dsv = ds ? ds->dsv : nullptr;
+ }
+
+ if (rhiD->rhiFlags.testFlag(QRhi::EnableTimestamps)) {
+ timestamps.prepare(rhiD);
// timestamp queries are optional so we can go on even if they failed
}
@@ -4623,34 +5374,4 @@ bool QD3D11SwapChain::createOrResize()
return true;
}
-void QRhiD3D11::DeviceCurse::initResources()
-{
- framesLeft = framesToActivate;
-
- HRESULT hr = q->dev->CreateComputeShader(g_killDeviceByTimingOut, sizeof(g_killDeviceByTimingOut), nullptr, &cs);
- if (FAILED(hr)) {
- qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr)));
- return;
- }
-}
-
-void QRhiD3D11::DeviceCurse::releaseResources()
-{
- if (cs) {
- cs->Release();
- cs = nullptr;
- }
-}
-
-void QRhiD3D11::DeviceCurse::activate()
-{
- if (!cs)
- return;
-
- qDebug("Activating Curse. Goodbye Cruel World.");
-
- q->context->CSSetShader(cs, nullptr, 0);
- q->context->Dispatch(256, 1, 1);
-}
-
QT_END_NAMESPACE