rhi: d3d12: Implement multiview support
This relies on qsb being able to invoke dxc instead of fxc when the request HLSL (shader model) version is 6.1. (6.1 is required for SV_ViewID) This currently works only when conditioning offline with qsb (or via CMake), because qsb can easily invoke dxc instead of fxc. When shipping HLSL inside the .qsb package (so when -c is not specified or running the external tool fails), this won't work since the D3D12 backend still uses D3DCompile(), not IDxcCompiler. Support for that will be investigated separately. We also need to bump to ID3D12Device2 and ID3D12GraphicsCommandList1. With Windows 10 version 1703 being quite old now, this should not be a problem at run time. There are however issues at build time, namely that MinGW and MinGW/LLVM and similar seems to have ancient Windows SDK headers according to the CI test runs. None of the MSVC configurations have this in the CI, they have reasonable versions of d3d12.h and similar. Therefore, one important aspect of this change is that the D3D12 backend of QRhi will only be available from now on when the SDK headers are new enough (meaning ID3D12Device2 is declared, which is a several years old type now). Otherwise, QRhi::create() will simply fail when asking for D3D12 with a helpful warning message about the Qt build being crippled. Implementation-wise, there are surprises in store as well: The way the PSO is created needs to be revamped to follow the extensible approach that uses a pipeline state stream description. Both the graphics and compute pipeline creation is changed to use CreatePipelineState() and the associated machinery. This is only really essential for graphics pipelines since we know have to include data for view instancing (multiview). For compute the result is the same as before. Additionally, the view count must now be baked into the QRhiGraphicsPipeline. This means that applications must call setMultiViewCount() with the same value (typically 2) *both* on the render target's color attachment and on the pipeline. Backends that do not care about the pipeline's view count (GL, Vulkan) will of course ignore it, but if it's not set correctly D3D12 will fail. The manual test is updated accordingly. Fixes: QTBUG-114772 Change-Id: I93db7313377e711c2faeb956815899b12132d23b Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
parent
1d9bf6ea38
commit
b7d9b7fa69
@ -78,8 +78,10 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
|
|||||||
\l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp}{software
|
\l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp}{software
|
||||||
adapter} is still an option.
|
adapter} is still an option.
|
||||||
|
|
||||||
\li Direct3D 12.0 or newer, with Shader Model 5.0 or newer. The D3D12
|
\li Direct3D 12 on Windows 10 version 1703 and newer, with Shader Model 5.0
|
||||||
device is by default created with specifying a minimum feature level of
|
or newer. Qt requires ID3D12Device2 to be present, hence the requirement
|
||||||
|
for at least version 1703 of Windows 10. The D3D12 device is by default
|
||||||
|
created with specifying a minimum feature level of
|
||||||
\c{D3D_FEATURE_LEVEL_11_0}.
|
\c{D3D_FEATURE_LEVEL_11_0}.
|
||||||
|
|
||||||
\li Metal 1.2 or newer.
|
\li Metal 1.2 or newer.
|
||||||
@ -976,7 +978,9 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
|
|||||||
typically supported. When reported as supported, creating a
|
typically supported. When reported as supported, creating a
|
||||||
QRhiTextureRenderTarget with a QRhiColorAttachment that references a texture
|
QRhiTextureRenderTarget with a QRhiColorAttachment that references a texture
|
||||||
array and has \l{QRhiColorAttachment::setMultiViewCount()}{multiViewCount}
|
array and has \l{QRhiColorAttachment::setMultiViewCount()}{multiViewCount}
|
||||||
set enables recording a render pass that uses multiview rendering. Note that
|
set enables recording a render pass that uses multiview rendering. In addition,
|
||||||
|
any QRhiGraphicsPipeline used in that render pass must have
|
||||||
|
\l{QRhiGraphicsPipeline::setMultiViewCount()}{the same view count set}. Note that
|
||||||
multiview is only available in combination with 2D texture arrays. It cannot
|
multiview is only available in combination with 2D texture arrays. It cannot
|
||||||
be used to optimize the rendering into individual textures (e.g. two, for
|
be used to optimize the rendering into individual textures (e.g. two, for
|
||||||
the left and right eyes). Rather, the target of a multiview render pass is
|
the left and right eyes). Rather, the target of a multiview render pass is
|
||||||
@ -6772,6 +6776,26 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
|
|||||||
\sa QRhi::NonFillPolygonMode
|
\sa QRhi::NonFillPolygonMode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn int QRhiGraphicsPipeline::multiViewCount() const
|
||||||
|
\return the view count. The default is 0, indicating no multiview rendering.
|
||||||
|
\since 6.7
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void QRhiGraphicsPipeline::setMultiViewCount(int count)
|
||||||
|
Sets the view \a count for multiview rendering. The default is 0,
|
||||||
|
indicating no multiview rendering.
|
||||||
|
\a count must be 2 or larger to trigger multiview rendering.
|
||||||
|
|
||||||
|
Multiview is only available when the \l{QRhi::MultiView}{MultiView feature}
|
||||||
|
is reported as supported. The render target must be a 2D texture array, and
|
||||||
|
the color attachment for the render target must have the same \a count set.
|
||||||
|
|
||||||
|
\since 6.7
|
||||||
|
\sa QRhi::MultiView, QRhiColorAttachment::setMultiViewCount()
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class QRhiSwapChain
|
\class QRhiSwapChain
|
||||||
\inmodule QtGui
|
\inmodule QtGui
|
||||||
@ -8088,9 +8112,17 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRh
|
|||||||
#endif
|
#endif
|
||||||
case D3D12:
|
case D3D12:
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
#ifdef QRHI_D3D12_AVAILABLE
|
||||||
r->d = new QRhiD3D12(static_cast<QRhiD3D12InitParams *>(params),
|
r->d = new QRhiD3D12(static_cast<QRhiD3D12InitParams *>(params),
|
||||||
static_cast<QRhiD3D12NativeHandles *>(importDevice));
|
static_cast<QRhiD3D12NativeHandles *>(importDevice));
|
||||||
break;
|
break;
|
||||||
|
#else
|
||||||
|
qWarning("Qt was built without Direct3D 12 support. "
|
||||||
|
"This is likely due to having ancient SDK headers (such as d3d12.h) in the Qt build environment. "
|
||||||
|
"Rebuild Qt with an SDK supporting D3D12 features introduced in Windows 10 version 1703, "
|
||||||
|
"or use an MSVC build as those typically are built with more up-to-date SDKs.");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
qWarning("This platform has no Direct3D 12 support");
|
qWarning("This platform has no Direct3D 12 support");
|
||||||
break;
|
break;
|
||||||
|
@ -1441,6 +1441,9 @@ public:
|
|||||||
PolygonMode polygonMode() const {return m_polygonMode; }
|
PolygonMode polygonMode() const {return m_polygonMode; }
|
||||||
void setPolygonMode(PolygonMode mode) {m_polygonMode = mode; }
|
void setPolygonMode(PolygonMode mode) {m_polygonMode = mode; }
|
||||||
|
|
||||||
|
int multiViewCount() const { return m_multiViewCount; }
|
||||||
|
void setMultiViewCount(int count) { m_multiViewCount = count; }
|
||||||
|
|
||||||
virtual bool create() = 0;
|
virtual bool create() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -1464,6 +1467,7 @@ protected:
|
|||||||
float m_slopeScaledDepthBias = 0.0f;
|
float m_slopeScaledDepthBias = 0.0f;
|
||||||
int m_patchControlPointCount = 3;
|
int m_patchControlPointCount = 3;
|
||||||
PolygonMode m_polygonMode = Fill;
|
PolygonMode m_polygonMode = Fill;
|
||||||
|
int m_multiViewCount = 0;
|
||||||
QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
|
QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
|
||||||
QRhiVertexInputLayout m_vertexInputLayout;
|
QRhiVertexInputLayout m_vertexInputLayout;
|
||||||
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
|
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
|
||||||
|
@ -145,7 +145,7 @@ struct Q_GUI_EXPORT QRhiD3D12NativeHandles : public QRhiNativeHandles
|
|||||||
|
|
||||||
struct Q_GUI_EXPORT QRhiD3D12CommandBufferNativeHandles : public QRhiNativeHandles
|
struct Q_GUI_EXPORT QRhiD3D12CommandBufferNativeHandles : public QRhiNativeHandles
|
||||||
{
|
{
|
||||||
void *commandList = nullptr; // ID3D12GraphicsCommandList
|
void *commandList = nullptr; // ID3D12GraphicsCommandList1
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WIN/QDOC
|
#endif // WIN/QDOC
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#define QRHI_D3D12_HAS_OLD_PIX
|
#define QRHI_D3D12_HAS_OLD_PIX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ID3D12Device2_INTERFACE_DEFINED__
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -108,7 +110,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
/*!
|
/*!
|
||||||
\class QRhiD3D12CommandBufferNativeHandles
|
\class QRhiD3D12CommandBufferNativeHandles
|
||||||
\inmodule QtGui
|
\inmodule QtGui
|
||||||
\brief Holds the ID3D12GraphicsCommandList object that is backing a QRhiCommandBuffer.
|
\brief Holds the ID3D12GraphicsCommandList1 object that is backing a QRhiCommandBuffer.
|
||||||
|
|
||||||
\note The command list object is only guaranteed to be valid, and
|
\note The command list object is only guaranteed to be valid, and
|
||||||
in recording state, while recording a frame. That is, between a
|
in recording state, while recording a frame. That is, between a
|
||||||
@ -132,8 +134,14 @@ QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *import
|
|||||||
debugLayer = params->enableDebugLayer;
|
debugLayer = params->enableDebugLayer;
|
||||||
if (importParams) {
|
if (importParams) {
|
||||||
if (importParams->dev) {
|
if (importParams->dev) {
|
||||||
dev = reinterpret_cast<ID3D12Device *>(importParams->dev);
|
ID3D12Device *d3d12Device = reinterpret_cast<ID3D12Device *>(importParams->dev);
|
||||||
|
if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2), reinterpret_cast<void **>(&dev)))) {
|
||||||
|
// get rid of the ref added by QueryInterface
|
||||||
|
d3d12Device->Release();
|
||||||
importedDevice = true;
|
importedDevice = true;
|
||||||
|
} else {
|
||||||
|
qWarning("ID3D12Device2 not supported, cannot import device");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (importParams->commandQueue) {
|
if (importParams->commandQueue) {
|
||||||
cmdQueue = reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
|
cmdQueue = reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
|
||||||
@ -267,7 +275,7 @@ bool QRhiD3D12::create(QRhi::Flags flags)
|
|||||||
|
|
||||||
hr = D3D12CreateDevice(activeAdapter,
|
hr = D3D12CreateDevice(activeAdapter,
|
||||||
minimumFeatureLevel,
|
minimumFeatureLevel,
|
||||||
__uuidof(ID3D12Device),
|
__uuidof(ID3D12Device2),
|
||||||
reinterpret_cast<void **>(&dev));
|
reinterpret_cast<void **>(&dev));
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning("Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
|
qWarning("Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
|
||||||
@ -402,6 +410,10 @@ bool QRhiD3D12::create(QRhi::Flags flags)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
|
||||||
|
if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3))))
|
||||||
|
caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
|
||||||
|
|
||||||
deviceLost = false;
|
deviceLost = false;
|
||||||
offscreenActive = false;
|
offscreenActive = false;
|
||||||
|
|
||||||
@ -639,7 +651,7 @@ bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
case QRhi::ThreeDimensionalTextureMipmaps:
|
case QRhi::ThreeDimensionalTextureMipmaps:
|
||||||
return false; // we generate mipmaps ourselves with compute and this is not implemented
|
return false; // we generate mipmaps ourselves with compute and this is not implemented
|
||||||
case QRhi::MultiView:
|
case QRhi::MultiView:
|
||||||
return false;
|
return caps.multiView;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -796,6 +808,9 @@ void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
|
|||||||
}
|
}
|
||||||
|
|
||||||
cbD->cmdList->IASetPrimitiveTopology(psD->topology);
|
cbD->cmdList->IASetPrimitiveTopology(psD->topology);
|
||||||
|
|
||||||
|
if (psD->viewInstanceMask)
|
||||||
|
cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1465,7 +1480,7 @@ QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
|
|||||||
barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
|
barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
|
||||||
barrierGen.enqueueBufferedTransitionBarriers(cbD);
|
barrierGen.enqueueBufferedTransitionBarriers(cbD);
|
||||||
|
|
||||||
ID3D12GraphicsCommandList *cmdList = cbD->cmdList;
|
ID3D12GraphicsCommandList1 *cmdList = cbD->cmdList;
|
||||||
HRESULT hr = cmdList->Close();
|
HRESULT hr = cmdList->Close();
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning("Failed to close command list: %s",
|
qWarning("Failed to close command list: %s",
|
||||||
@ -1562,7 +1577,7 @@ QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
|
|||||||
offscreenActive = false;
|
offscreenActive = false;
|
||||||
|
|
||||||
QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
|
QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
|
||||||
ID3D12GraphicsCommandList *cmdList = cbD->cmdList;
|
ID3D12GraphicsCommandList1 *cmdList = cbD->cmdList;
|
||||||
HRESULT hr = cmdList->Close();
|
HRESULT hr = cmdList->Close();
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning("Failed to close command list: %s",
|
qWarning("Failed to close command list: %s",
|
||||||
@ -1603,7 +1618,7 @@ QRhi::FrameOpResult QRhiD3D12::finish()
|
|||||||
|
|
||||||
Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
|
Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
|
||||||
|
|
||||||
ID3D12GraphicsCommandList *cmdList = cbD->cmdList;
|
ID3D12GraphicsCommandList1 *cmdList = cbD->cmdList;
|
||||||
HRESULT hr = cmdList->Close();
|
HRESULT hr = cmdList->Close();
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning("Failed to close command list: %s",
|
qWarning("Failed to close command list: %s",
|
||||||
@ -2912,7 +2927,7 @@ DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleCount(int sampleCount, DXGI_FORMAT fo
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QRhiD3D12::startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList **cmdList)
|
bool QRhiD3D12::startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList1 **cmdList)
|
||||||
{
|
{
|
||||||
ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
|
ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
|
||||||
if (!*cmdList) {
|
if (!*cmdList) {
|
||||||
@ -2920,7 +2935,7 @@ bool QRhiD3D12::startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList **
|
|||||||
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||||
cmdAlloc,
|
cmdAlloc,
|
||||||
nullptr,
|
nullptr,
|
||||||
__uuidof(ID3D12GraphicsCommandList),
|
__uuidof(ID3D12GraphicsCommandList1),
|
||||||
reinterpret_cast<void **>(cmdList));
|
reinterpret_cast<void **>(cmdList));
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning("Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
|
qWarning("Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
|
||||||
@ -4412,19 +4427,21 @@ bool QD3D12TextureRenderTarget::create()
|
|||||||
qWarning("Could not look up texture handle for render target");
|
qWarning("Could not look up texture handle for render target");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const bool isMultiView = it->multiViewCount() >= 2;
|
||||||
|
UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
|
||||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
|
||||||
rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags());
|
rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags());
|
||||||
if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
|
if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
|
||||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||||
rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
|
rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
|
||||||
rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
|
rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
|
||||||
rtvDesc.Texture2DArray.ArraySize = 1;
|
rtvDesc.Texture2DArray.ArraySize = layerCount;
|
||||||
} else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
|
} else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
|
||||||
if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
|
if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
|
||||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
|
||||||
rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
|
rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
|
||||||
rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
|
rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
|
||||||
rtvDesc.Texture1DArray.ArraySize = 1;
|
rtvDesc.Texture1DArray.ArraySize = layerCount;
|
||||||
} else {
|
} else {
|
||||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
|
||||||
rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
|
rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
|
||||||
@ -4433,18 +4450,18 @@ bool QD3D12TextureRenderTarget::create()
|
|||||||
if (texD->sampleDesc.Count > 1) {
|
if (texD->sampleDesc.Count > 1) {
|
||||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
|
||||||
rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
|
rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
|
||||||
rtvDesc.Texture2DMSArray.ArraySize = 1;
|
rtvDesc.Texture2DMSArray.ArraySize = layerCount;
|
||||||
} else {
|
} else {
|
||||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||||
rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
|
rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
|
||||||
rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
|
rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
|
||||||
rtvDesc.Texture2DArray.ArraySize = 1;
|
rtvDesc.Texture2DArray.ArraySize = layerCount;
|
||||||
}
|
}
|
||||||
} else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
|
} else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
|
||||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
|
||||||
rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
|
rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
|
||||||
rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
|
rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
|
||||||
rtvDesc.Texture3D.WSize = 1;
|
rtvDesc.Texture3D.WSize = layerCount;
|
||||||
} else {
|
} else {
|
||||||
if (texD->sampleDesc.Count > 1) {
|
if (texD->sampleDesc.Count > 1) {
|
||||||
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
|
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
|
||||||
@ -5257,83 +5274,26 @@ bool QD3D12GraphicsPipeline::create()
|
|||||||
QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
|
QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
|
||||||
const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, DXGI_FORMAT(rpD->colorFormat[0]));
|
const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, DXGI_FORMAT(rpD->colorFormat[0]));
|
||||||
|
|
||||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
|
struct {
|
||||||
psoDesc.pRootSignature = rootSig;
|
QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
|
||||||
for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
|
QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
|
||||||
const int d3dStage = qd3d12_stage(shaderStage.type());
|
QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
|
||||||
switch (d3dStage) {
|
QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
|
||||||
case VS:
|
QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
|
||||||
psoDesc.VS.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
|
||||||
psoDesc.VS.BytecodeLength = shaderBytecode[d3dStage].size();
|
QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
|
||||||
break;
|
QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
|
||||||
case HS:
|
QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
|
||||||
psoDesc.HS.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
|
||||||
psoDesc.HS.BytecodeLength = shaderBytecode[d3dStage].size();
|
QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
|
||||||
break;
|
QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
|
||||||
case DS:
|
QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
|
||||||
psoDesc.DS.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
|
||||||
psoDesc.DS.BytecodeLength = shaderBytecode[d3dStage].size();
|
QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
|
||||||
break;
|
QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
|
||||||
case GS:
|
} stream;
|
||||||
psoDesc.GS.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
|
||||||
psoDesc.GS.BytecodeLength = shaderBytecode[d3dStage].size();
|
|
||||||
break;
|
|
||||||
case PS:
|
|
||||||
psoDesc.PS.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
|
||||||
psoDesc.PS.BytecodeLength = shaderBytecode[d3dStage].size();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Q_UNREACHABLE();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
psoDesc.BlendState.IndependentBlendEnable = m_targetBlends.count() > 1;
|
stream.rootSig.object = rootSig;
|
||||||
for (int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
|
|
||||||
const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
|
|
||||||
D3D12_RENDER_TARGET_BLEND_DESC blend = {};
|
|
||||||
blend.BlendEnable = b.enable;
|
|
||||||
blend.SrcBlend = toD3DBlendFactor(b.srcColor, true);
|
|
||||||
blend.DestBlend = toD3DBlendFactor(b.dstColor, true);
|
|
||||||
blend.BlendOp = toD3DBlendOp(b.opColor);
|
|
||||||
blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha, false);
|
|
||||||
blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha, false);
|
|
||||||
blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
|
|
||||||
blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
|
|
||||||
psoDesc.BlendState.RenderTarget[i] = blend;
|
|
||||||
}
|
|
||||||
if (m_targetBlends.isEmpty()) {
|
|
||||||
D3D12_RENDER_TARGET_BLEND_DESC blend = {};
|
|
||||||
blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
|
||||||
psoDesc.BlendState.RenderTarget[0] = blend;
|
|
||||||
}
|
|
||||||
|
|
||||||
psoDesc.SampleMask = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
psoDesc.RasterizerState.FillMode = toD3DFillMode(m_polygonMode);
|
|
||||||
psoDesc.RasterizerState.CullMode = toD3DCullMode(m_cullMode);
|
|
||||||
psoDesc.RasterizerState.FrontCounterClockwise = m_frontFace == CCW;
|
|
||||||
psoDesc.RasterizerState.DepthBias = m_depthBias;
|
|
||||||
psoDesc.RasterizerState.SlopeScaledDepthBias = m_slopeScaledDepthBias;
|
|
||||||
psoDesc.RasterizerState.DepthClipEnable = TRUE;
|
|
||||||
psoDesc.RasterizerState.MultisampleEnable = sampleDesc.Count > 1;
|
|
||||||
|
|
||||||
psoDesc.DepthStencilState.DepthEnable = m_depthTest;
|
|
||||||
psoDesc.DepthStencilState.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
|
|
||||||
psoDesc.DepthStencilState.DepthFunc = toD3DCompareOp(m_depthOp);
|
|
||||||
psoDesc.DepthStencilState.StencilEnable = m_stencilTest;
|
|
||||||
if (m_stencilTest) {
|
|
||||||
psoDesc.DepthStencilState.StencilReadMask = UINT8(m_stencilReadMask);
|
|
||||||
psoDesc.DepthStencilState.StencilWriteMask = UINT8(m_stencilWriteMask);
|
|
||||||
psoDesc.DepthStencilState.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
|
|
||||||
psoDesc.DepthStencilState.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
|
|
||||||
psoDesc.DepthStencilState.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
|
|
||||||
psoDesc.DepthStencilState.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
|
|
||||||
psoDesc.DepthStencilState.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
|
|
||||||
psoDesc.DepthStencilState.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
|
|
||||||
psoDesc.DepthStencilState.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
|
|
||||||
psoDesc.DepthStencilState.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
|
QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
|
||||||
QByteArrayList matrixSliceSemantics;
|
QByteArrayList matrixSliceSemantics;
|
||||||
@ -5371,24 +5331,113 @@ bool QD3D12GraphicsPipeline::create()
|
|||||||
inputDescs.append(desc);
|
inputDescs.append(desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!inputDescs.isEmpty()) {
|
|
||||||
psoDesc.InputLayout.pInputElementDescs = inputDescs.constData();
|
|
||||||
psoDesc.InputLayout.NumElements = inputDescs.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
psoDesc.PrimitiveTopologyType = toD3DTopologyType(m_topology);
|
stream.inputLayout.object.NumElements = inputDescs.count();
|
||||||
|
stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ? nullptr : inputDescs.constData();
|
||||||
|
|
||||||
|
stream.primitiveTopology.object = toD3DTopologyType(m_topology);
|
||||||
topology = toD3DTopology(m_topology, m_patchControlPointCount);
|
topology = toD3DTopology(m_topology, m_patchControlPointCount);
|
||||||
|
|
||||||
psoDesc.NumRenderTargets = rpD->colorAttachmentCount;
|
for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
|
||||||
|
const int d3dStage = qd3d12_stage(shaderStage.type());
|
||||||
|
switch (d3dStage) {
|
||||||
|
case VS:
|
||||||
|
stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
||||||
|
stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
|
||||||
|
break;
|
||||||
|
case HS:
|
||||||
|
stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
||||||
|
stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
|
||||||
|
break;
|
||||||
|
case DS:
|
||||||
|
stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
||||||
|
stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
|
||||||
|
break;
|
||||||
|
case GS:
|
||||||
|
stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
||||||
|
stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
|
||||||
|
break;
|
||||||
|
case PS:
|
||||||
|
stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
|
||||||
|
stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
|
||||||
|
stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
|
||||||
|
stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
|
||||||
|
stream.rasterizerState.object.DepthBias = m_depthBias;
|
||||||
|
stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
|
||||||
|
stream.rasterizerState.object.DepthClipEnable = TRUE;
|
||||||
|
stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
|
||||||
|
|
||||||
|
stream.depthStencilState.object.DepthEnable = m_depthTest;
|
||||||
|
stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
|
||||||
|
stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
|
||||||
|
stream.depthStencilState.object.StencilEnable = m_stencilTest;
|
||||||
|
if (m_stencilTest) {
|
||||||
|
stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
|
||||||
|
stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
|
||||||
|
stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
|
||||||
|
stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
|
||||||
|
stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
|
||||||
|
stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
|
||||||
|
stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
|
||||||
|
stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
|
||||||
|
stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
|
||||||
|
stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
|
||||||
|
for (int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
|
||||||
|
const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
|
||||||
|
D3D12_RENDER_TARGET_BLEND_DESC blend = {};
|
||||||
|
blend.BlendEnable = b.enable;
|
||||||
|
blend.SrcBlend = toD3DBlendFactor(b.srcColor, true);
|
||||||
|
blend.DestBlend = toD3DBlendFactor(b.dstColor, true);
|
||||||
|
blend.BlendOp = toD3DBlendOp(b.opColor);
|
||||||
|
blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha, false);
|
||||||
|
blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha, false);
|
||||||
|
blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
|
||||||
|
blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
|
||||||
|
stream.blendState.object.RenderTarget[i] = blend;
|
||||||
|
}
|
||||||
|
if (m_targetBlends.isEmpty()) {
|
||||||
|
D3D12_RENDER_TARGET_BLEND_DESC blend = {};
|
||||||
|
blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||||
|
stream.blendState.object.RenderTarget[0] = blend;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
|
||||||
for (int i = 0; i < rpD->colorAttachmentCount; ++i)
|
for (int i = 0; i < rpD->colorAttachmentCount; ++i)
|
||||||
psoDesc.RTVFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
|
stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
|
||||||
psoDesc.DSVFormat = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
|
|
||||||
psoDesc.SampleDesc = sampleDesc;
|
stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
|
||||||
|
|
||||||
|
stream.sampleDesc.object = sampleDesc;
|
||||||
|
|
||||||
|
stream.sampleMask.object = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
viewInstanceMask = 0;
|
||||||
|
const bool isMultiView = m_multiViewCount >= 2;
|
||||||
|
stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
|
||||||
|
QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
|
||||||
|
if (isMultiView) {
|
||||||
|
for (int i = 0; i < m_multiViewCount; ++i) {
|
||||||
|
viewInstanceMask |= (1 << i);
|
||||||
|
viewInstanceLocations.append({ 0, UINT(i) });
|
||||||
|
}
|
||||||
|
stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
|
||||||
|
}
|
||||||
|
|
||||||
|
const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = { sizeof(stream), &stream };
|
||||||
|
|
||||||
ID3D12PipelineState *pso = nullptr;
|
ID3D12PipelineState *pso = nullptr;
|
||||||
HRESULT hr = rhiD->dev->CreateGraphicsPipelineState(&psoDesc,
|
HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void **>(&pso));
|
||||||
__uuidof(ID3D12PipelineState),
|
|
||||||
reinterpret_cast<void **>(&pso));
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning("Failed to create graphics pipeline state: %s",
|
qWarning("Failed to create graphics pipeline state: %s",
|
||||||
qPrintable(QSystemError::windowsComString(hr)));
|
qPrintable(QSystemError::windowsComString(hr)));
|
||||||
@ -5487,14 +5536,16 @@ bool QD3D12ComputePipeline::create()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
|
struct {
|
||||||
psoDesc.pRootSignature = rootSig;
|
QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
|
||||||
psoDesc.CS.pShaderBytecode = shaderBytecode.constData();
|
QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
|
||||||
psoDesc.CS.BytecodeLength = shaderBytecode.size();
|
} stream;
|
||||||
|
stream.rootSig.object = rootSig;
|
||||||
|
stream.CS.object.pShaderBytecode = shaderBytecode.constData();
|
||||||
|
stream.CS.object.BytecodeLength = shaderBytecode.size();
|
||||||
|
const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = { sizeof(stream), &stream };
|
||||||
ID3D12PipelineState *pso = nullptr;
|
ID3D12PipelineState *pso = nullptr;
|
||||||
HRESULT hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
|
HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void **>(&pso));
|
||||||
__uuidof(ID3D12PipelineState),
|
|
||||||
reinterpret_cast<void **>(&pso));
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning("Failed to create compute pipeline state: %s",
|
qWarning("Failed to create compute pipeline state: %s",
|
||||||
qPrintable(QSystemError::windowsComString(hr)));
|
qPrintable(QSystemError::windowsComString(hr)));
|
||||||
@ -6141,3 +6192,5 @@ bool QD3D12SwapChain::createOrResize()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // __ID3D12Device2_INTERFACE_DEFINED__
|
||||||
|
@ -30,6 +30,15 @@
|
|||||||
|
|
||||||
#include "D3D12MemAlloc.h"
|
#include "D3D12MemAlloc.h"
|
||||||
|
|
||||||
|
// ID3D12Device2 and ID3D12GraphicsCommandList1 and types and enums introduced
|
||||||
|
// with those are hard requirements now. These should be declared in any
|
||||||
|
// moderately recent d3d12.h, but if it is an SDK from before Windows 10
|
||||||
|
// version 1703 then these types could be missing. In the absence of other
|
||||||
|
// options, handle this by skipping all the code and making QRhi::create() fail
|
||||||
|
// in such builds.
|
||||||
|
#ifdef __ID3D12Device2_INTERFACE_DEFINED__
|
||||||
|
#define QRHI_D3D12_AVAILABLE
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
static const int QD3D12_FRAMES_IN_FLIGHT = 2;
|
static const int QD3D12_FRAMES_IN_FLIGHT = 2;
|
||||||
@ -863,6 +872,7 @@ struct QD3D12GraphicsPipeline : public QRhiGraphicsPipeline
|
|||||||
QD3D12ObjectHandle rootSigHandle;
|
QD3D12ObjectHandle rootSigHandle;
|
||||||
std::array<QD3D12ShaderStageData, 5> stageData;
|
std::array<QD3D12ShaderStageData, 5> stageData;
|
||||||
D3D12_PRIMITIVE_TOPOLOGY topology;
|
D3D12_PRIMITIVE_TOPOLOGY topology;
|
||||||
|
UINT viewInstanceMask = 0;
|
||||||
uint generation = 0;
|
uint generation = 0;
|
||||||
friend class QRhiD3D12;
|
friend class QRhiD3D12;
|
||||||
};
|
};
|
||||||
@ -889,7 +899,7 @@ struct QD3D12CommandBuffer : public QRhiCommandBuffer
|
|||||||
|
|
||||||
const QRhiNativeHandles *nativeHandles();
|
const QRhiNativeHandles *nativeHandles();
|
||||||
|
|
||||||
ID3D12GraphicsCommandList *cmdList = nullptr; // not owned
|
ID3D12GraphicsCommandList1 *cmdList = nullptr; // not owned
|
||||||
QRhiD3D12CommandBufferNativeHandles nativeHandlesStruct;
|
QRhiD3D12CommandBufferNativeHandles nativeHandlesStruct;
|
||||||
|
|
||||||
enum PassType {
|
enum PassType {
|
||||||
@ -984,12 +994,19 @@ struct QD3D12SwapChain : public QRhiSwapChain
|
|||||||
ID3D12Fence *fence = nullptr;
|
ID3D12Fence *fence = nullptr;
|
||||||
HANDLE fenceEvent = nullptr;
|
HANDLE fenceEvent = nullptr;
|
||||||
UINT64 fenceCounter = 0;
|
UINT64 fenceCounter = 0;
|
||||||
ID3D12GraphicsCommandList *cmdList = nullptr;
|
ID3D12GraphicsCommandList1 *cmdList = nullptr;
|
||||||
} frameRes[QD3D12_FRAMES_IN_FLIGHT];
|
} frameRes[QD3D12_FRAMES_IN_FLIGHT];
|
||||||
|
|
||||||
int currentFrameSlot = 0; // index in frameRes
|
int currentFrameSlot = 0; // index in frameRes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type>
|
||||||
|
struct alignas(void*) QD3D12PipelineStateSubObject
|
||||||
|
{
|
||||||
|
D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type = Type;
|
||||||
|
T object = {};
|
||||||
|
};
|
||||||
|
|
||||||
class QRhiD3D12 : public QRhiImplementation
|
class QRhiD3D12 : public QRhiImplementation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -1111,7 +1128,7 @@ public:
|
|||||||
void waitGpu();
|
void waitGpu();
|
||||||
DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount, DXGI_FORMAT format) const;
|
DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount, DXGI_FORMAT format) const;
|
||||||
bool ensureDirectCompositionDevice();
|
bool ensureDirectCompositionDevice();
|
||||||
bool startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList **cmdList);
|
bool startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList1 **cmdList);
|
||||||
void enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
|
void enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
|
||||||
void finishActiveReadbacks(bool forced = false);
|
void finishActiveReadbacks(bool forced = false);
|
||||||
bool ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
|
bool ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
|
||||||
@ -1122,7 +1139,7 @@ public:
|
|||||||
void bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD);
|
void bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD);
|
||||||
|
|
||||||
bool debugLayer = false;
|
bool debugLayer = false;
|
||||||
ID3D12Device *dev = nullptr;
|
ID3D12Device2 *dev = nullptr;
|
||||||
D3D_FEATURE_LEVEL minimumFeatureLevel = D3D_FEATURE_LEVEL(0);
|
D3D_FEATURE_LEVEL minimumFeatureLevel = D3D_FEATURE_LEVEL(0);
|
||||||
LUID adapterLuid = {};
|
LUID adapterLuid = {};
|
||||||
bool importedDevice = false;
|
bool importedDevice = false;
|
||||||
@ -1187,8 +1204,14 @@ public:
|
|||||||
const QRhiShaderResourceBinding::Data::StorageImageData &d,
|
const QRhiShaderResourceBinding::Data::StorageImageData &d,
|
||||||
QD3D12ShaderResourceVisitor::StorageOp op,
|
QD3D12ShaderResourceVisitor::StorageOp op,
|
||||||
int shaderRegister);
|
int shaderRegister);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool multiView = false;
|
||||||
|
} caps;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // __ID3D12Device2_INTERFACE_DEFINED__
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
qsb --view-count 2 --glsl "300 es,330" --hlsl 61 multiview.vert -o multiview.vert.qsb
|
qsb --view-count 2 --glsl "300 es,330" --hlsl 61 -c multiview.vert -o multiview.vert.qsb
|
||||||
qsb --glsl "300 es,330" --hlsl 61 multiview.frag -o multiview.frag.qsb
|
qsb --glsl "300 es,330" --hlsl 61 -c multiview.frag -o multiview.frag.qsb
|
||||||
qsb --glsl "300 es,330" --hlsl 61 texture.vert -o texture.vert.qsb
|
qsb --glsl "300 es,330" --hlsl 61 -c texture.vert -o texture.vert.qsb
|
||||||
qsb --glsl "300 es,330" --hlsl 61 texture.frag -o texture.frag.qsb
|
qsb --glsl "300 es,330" --hlsl 61 -c texture.frag -o texture.frag.qsb
|
||||||
|
@ -64,7 +64,7 @@ void Window::customInit()
|
|||||||
QRhiColorAttachment multiViewAtt(d.tex);
|
QRhiColorAttachment multiViewAtt(d.tex);
|
||||||
// using array elements 0 and 1
|
// using array elements 0 and 1
|
||||||
multiViewAtt.setLayer(0);
|
multiViewAtt.setLayer(0);
|
||||||
multiViewAtt.setMultiViewCount(2);
|
multiViewAtt.setMultiViewCount(2); // the view count must be set both on the render target and the pipeline
|
||||||
QRhiTextureRenderTargetDescription rtDesc(multiViewAtt);
|
QRhiTextureRenderTargetDescription rtDesc(multiViewAtt);
|
||||||
d.rt = m_r->newTextureRenderTarget(rtDesc);
|
d.rt = m_r->newTextureRenderTarget(rtDesc);
|
||||||
d.releasePool << d.rt;
|
d.releasePool << d.rt;
|
||||||
@ -155,7 +155,7 @@ void Window::customInit()
|
|||||||
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/multiview.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/multiview.vert.qsb")) },
|
||||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/multiview.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/multiview.frag.qsb")) }
|
||||||
});
|
});
|
||||||
|
d.triPs->setMultiViewCount(2); // the view count must be set both on the render target and the pipeline
|
||||||
inputLayout.setBindings({
|
inputLayout.setBindings({
|
||||||
{ 5 * sizeof(float) }
|
{ 5 * sizeof(float) }
|
||||||
});
|
});
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user