diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-06-19 16:23:54 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-06-21 13:06:21 +0200 |
commit | 484fc8545fba6cb7516185e58db8075874d241b7 (patch) | |
tree | 643e8e5a18907bd9cf8e6c1eb7b7c9a0e6d4eb3c /src/gui | |
parent | 33f16af30764d82af3f6c196618165b7b5f5afee (diff) |
rhi: d3d11: Add compute and load/store res support
Also revise how we reset shader input/outputs at the beginning
of a pass.
Change-Id: I6d4057f32318ca09b12e16c602bb1033a3ec8e3c
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/rhi/qrhid3d11.cpp | 470 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11_p_p.h | 60 |
2 files changed, 450 insertions, 80 deletions
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index ce1617045b..6d5caec57a 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -376,7 +376,7 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const case QRhi::ElementIndexUint: return true; case QRhi::Compute: - return false; + return true; default: Q_UNREACHABLE(); return false; @@ -460,10 +460,11 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb); Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass); QD3D11GraphicsPipeline *psD = QRHI_RES(QD3D11GraphicsPipeline, ps); - const bool pipelineChanged = cbD->currentPipeline != ps || cbD->currentPipelineGeneration != psD->generation; + const bool pipelineChanged = cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation; if (pipelineChanged) { - cbD->currentPipeline = ps; + cbD->currentGraphicsPipeline = ps; + cbD->currentComputePipeline = nullptr; cbD->currentPipelineGeneration = psD->generation; QD3D11CommandBuffer::Command cmd; @@ -478,11 +479,16 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) { QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb); - Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass); - Q_ASSERT(cbD->currentPipeline); + Q_ASSERT(cbD->recordingPass != QD3D11CommandBuffer::NoPass); + QD3D11GraphicsPipeline *gfxPsD = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline); + QD3D11ComputePipeline *compPsD = QRHI_RES(QD3D11ComputePipeline, cbD->currentComputePipeline); - if (!srb) - srb = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline)->m_shaderResourceBindings; + if (!srb) { + if (gfxPsD) + srb = gfxPsD->m_shaderResourceBindings; + else + srb = compPsD->m_shaderResourceBindings; + } QD3D11ShaderResourceBindings *srbD = QRHI_RES(QD3D11ShaderResourceBindings, srb); @@ -525,6 +531,34 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind } } break; + case QRhiShaderResourceBinding::ImageLoad: + Q_FALLTHROUGH(); + case QRhiShaderResourceBinding::ImageStore: + Q_FALLTHROUGH(); + case QRhiShaderResourceBinding::ImageLoadStore: + { + QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex); + if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) { + srbUpdate = true; + bd.simage.id = texD->m_id; + bd.simage.generation = texD->generation; + } + } + break; + case QRhiShaderResourceBinding::BufferLoad: + Q_FALLTHROUGH(); + case QRhiShaderResourceBinding::BufferStore: + Q_FALLTHROUGH(); + case QRhiShaderResourceBinding::BufferLoadStore: + { + QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf); + if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) { + srbUpdate = true; + bd.sbuf.id = bufD->m_id; + bd.sbuf.generation = bufD->generation; + } + } + break; default: Q_UNREACHABLE(); break; @@ -534,10 +568,17 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind if (srbUpdate) updateShaderResourceBindings(srbD); - const bool srbChanged = cbD->currentSrb != srb || cbD->currentSrbGeneration != srbD->generation; + const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb); + const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation; - if (srbChanged || srbUpdate || hasDynamicOffsetInSrb) { - cbD->currentSrb = srb; + if (srbChanged || srbRebuilt || srbUpdate || hasDynamicOffsetInSrb) { + if (gfxPsD) { + cbD->currentGraphicsSrb = srb; + cbD->currentComputeSrb = nullptr; + } else { + cbD->currentGraphicsSrb = nullptr; + cbD->currentComputeSrb = srb; + } cbD->currentSrbGeneration = srbD->generation; QD3D11CommandBuffer::Command cmd; @@ -545,7 +586,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind cmd.args.bindShaderResources.srb = srbD; // dynamic offsets have to be applied at the time of executing the bind // operations, not here - cmd.args.bindShaderResources.offsetOnlyChange = !srbChanged && !srbUpdate && hasDynamicOffsetInSrb; + cmd.args.bindShaderResources.offsetOnlyChange = !srbChanged && !srbRebuilt && !srbUpdate && hasDynamicOffsetInSrb; cmd.args.bindShaderResources.dynamicOffsetCount = 0; if (hasDynamicOffsetInSrb) { if (dynamicOffsetCount < QD3D11CommandBuffer::Command::MAX_UBUF_BINDINGS) { @@ -599,7 +640,7 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb, cmd.args.bindVertexBuffers.startSlot = startBinding; cmd.args.bindVertexBuffers.slotCount = bindingCount; const QVector<QRhiVertexInputBinding> inputBindings = - QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline)->m_vertexInputLayout.bindings(); + QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline)->m_vertexInputLayout.bindings(); for (int i = 0, ie = qMin(bindingCount, inputBindings.count()); i != ie; ++i) { QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first); cmd.args.bindVertexBuffers.buffers[i] = bufD->buffer; @@ -688,7 +729,7 @@ void QRhiD3D11::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) QD3D11CommandBuffer::Command cmd; cmd.cmd = QD3D11CommandBuffer::Command::BlendConstants; - cmd.args.blendConstants.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline); + cmd.args.blendConstants.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline); cmd.args.blendConstants.c[0] = c.redF(); cmd.args.blendConstants.c[1] = c.greenF(); cmd.args.blendConstants.c[2] = c.blueF(); @@ -703,7 +744,7 @@ void QRhiD3D11::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) QD3D11CommandBuffer::Command cmd; cmd.cmd = QD3D11CommandBuffer::Command::StencilRef; - cmd.args.stencilRef.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline); + cmd.args.stencilRef.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline); cmd.args.stencilRef.ref = refValue; cbD->commands.append(cmd); } @@ -716,7 +757,7 @@ void QRhiD3D11::draw(QRhiCommandBuffer *cb, quint32 vertexCount, QD3D11CommandBuffer::Command cmd; cmd.cmd = QD3D11CommandBuffer::Command::Draw; - cmd.args.draw.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline); + cmd.args.draw.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline); cmd.args.draw.vertexCount = vertexCount; cmd.args.draw.instanceCount = instanceCount; cmd.args.draw.firstVertex = firstVertex; @@ -732,7 +773,7 @@ void QRhiD3D11::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, QD3D11CommandBuffer::Command cmd; cmd.cmd = QD3D11CommandBuffer::Command::DrawIndexed; - cmd.args.drawIndexed.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline); + cmd.args.drawIndexed.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline); cmd.args.drawIndexed.indexCount = indexCount; cmd.args.drawIndexed.instanceCount = instanceCount; cmd.args.drawIndexed.firstIndex = firstIndex; @@ -795,8 +836,12 @@ void QRhiD3D11::endExternal(QRhiCommandBuffer *cb) QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb); Q_ASSERT(cbD->commands.isEmpty()); cbD->resetCachedState(); - if (cbD->currentTarget) // could be compute, no rendertarget then - enqueueSetRenderTarget(cbD, cbD->currentTarget); + if (cbD->currentTarget) { // could be compute, no rendertarget then + QD3D11CommandBuffer::Command fbCmd; + fbCmd.cmd = QD3D11CommandBuffer::Command::SetRenderTarget; + fbCmd.args.setRenderTarget.rt = cbD->currentTarget; + cbD->commands.append(fbCmd); + } } QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) @@ -1379,14 +1424,6 @@ void QRhiD3D11::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *r enqueueResourceUpdates(cb, resourceUpdates); } -void QRhiD3D11::enqueueSetRenderTarget(QD3D11CommandBuffer *cbD, QRhiRenderTarget *rt) -{ - QD3D11CommandBuffer::Command fbCmd; - fbCmd.cmd = QD3D11CommandBuffer::Command::SetRenderTarget; - fbCmd.args.setRenderTarget.rt = rt; - cbD->commands.append(fbCmd); -} - void QRhiD3D11::beginPass(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &colorClearValue, @@ -1407,7 +1444,13 @@ void QRhiD3D11::beginPass(QRhiCommandBuffer *cb, wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents); wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents); } - enqueueSetRenderTarget(cbD, rt); + + QD3D11CommandBuffer::Command fbCmd; + fbCmd.cmd = QD3D11CommandBuffer::Command::ResetShaderResources; + cbD->commands.append(fbCmd); + fbCmd.cmd = QD3D11CommandBuffer::Command::SetRenderTarget; + fbCmd.args.setRenderTarget.rt = rt; + cbD->commands.append(fbCmd); QD3D11CommandBuffer::Command clearCmd; clearCmd.cmd = QD3D11CommandBuffer::Command::Clear; @@ -1499,6 +1542,10 @@ void QRhiD3D11::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch if (resourceUpdates) enqueueResourceUpdates(cb, resourceUpdates); + QD3D11CommandBuffer::Command cmd; + cmd.cmd = QD3D11CommandBuffer::Command::ResetShaderResources; + cbD->commands.append(cmd); + cbD->recordingPass = QD3D11CommandBuffer::ComputePass; } @@ -1515,16 +1562,34 @@ void QRhiD3D11::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *r void QRhiD3D11::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) { - Q_UNUSED(cb); - Q_UNUSED(ps); + QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb); + Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::ComputePass); + QD3D11ComputePipeline *psD = QRHI_RES(QD3D11ComputePipeline, ps); + const bool pipelineChanged = cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation; + + if (pipelineChanged) { + cbD->currentGraphicsPipeline = nullptr; + cbD->currentComputePipeline = psD; + cbD->currentPipelineGeneration = psD->generation; + + QD3D11CommandBuffer::Command cmd; + cmd.cmd = QD3D11CommandBuffer::Command::BindComputePipeline; + cmd.args.bindComputePipeline.ps = psD; + cbD->commands.append(cmd); + } } void QRhiD3D11::dispatch(QRhiCommandBuffer *cb, int x, int y, int z) { - Q_UNUSED(cb); - Q_UNUSED(x); - Q_UNUSED(y); - Q_UNUSED(z); + QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb); + Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::ComputePass); + + QD3D11CommandBuffer::Command cmd; + cmd.cmd = QD3D11CommandBuffer::Command::Dispatch; + cmd.args.dispatch.x = x; + cmd.args.dispatch.y = y; + cmd.args.dispatch.z = z; + cbD->commands.append(cmd); } void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) @@ -1537,12 +1602,21 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->fsubufoffsets.clear(); srbD->fsubufsizes.clear(); + srbD->csubufs.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(); + for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) { const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]); QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]); @@ -1571,6 +1645,11 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->fsubufoffsets.feed(b->binding, offsetInConstants); srbD->fsubufsizes.feed(b->binding, sizeInConstants); } + if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { + srbD->csubufs.feed(b->binding, bufD->buffer); + srbD->csubufoffsets.feed(b->binding, offsetInConstants); + srbD->csubufsizes.feed(b->binding, sizeInConstants); + } } break; case QRhiShaderResourceBinding::SampledTexture: @@ -1591,6 +1670,46 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->fssamplers.feed(b->binding, samplerD->samplerState); srbD->fsshaderresources.feed(b->binding, texD->srv); } + if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { + srbD->cssamplers.feed(b->binding, samplerD->samplerState); + srbD->csshaderresources.feed(b->binding, texD->srv); + } + } + break; + case QRhiShaderResourceBinding::ImageLoad: + Q_FALLTHROUGH(); + case QRhiShaderResourceBinding::ImageStore: + Q_FALLTHROUGH(); + case QRhiShaderResourceBinding::ImageLoadStore: + { + QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex); + bd.simage.id = texD->m_id; + bd.simage.generation = texD->generation; + if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { + ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level); + if (uav) + srbD->csUAVs.feed(b->binding, uav); + } else { + qWarning("Unordered access only supported at compute stage"); + } + } + break; + case QRhiShaderResourceBinding::BufferLoad: + Q_FALLTHROUGH(); + case QRhiShaderResourceBinding::BufferStore: + Q_FALLTHROUGH(); + case QRhiShaderResourceBinding::BufferLoadStore: + { + QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf); + bd.sbuf.id = bufD->m_id; + bd.sbuf.generation = bufD->generation; + if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { + ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(); + if (uav) + srbD->csUAVs.feed(b->binding, uav); + } else { + qWarning("Unordered access only supported at compute stage"); + } } break; default: @@ -1607,11 +1726,20 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD) srbD->fsubufoffsets.finish(); srbD->fsubufsizes.finish(); + srbD->csubufs.finish(); + srbD->csubufoffsets.finish(); + srbD->csubufsizes.finish(); + srbD->vssamplers.finish(); srbD->vsshaderresources.finish(); srbD->fssamplers.finish(); srbD->fsshaderresources.finish(); + + srbD->cssamplers.finish(); + srbD->csshaderresources.finish(); + + srbD->csUAVs.finish(); } void QRhiD3D11::executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD) @@ -1631,6 +1759,27 @@ void QRhiD3D11::executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD) } } +static void applyDynamicOffsets(QVarLengthArray<UINT, 4> *offsets, + int batchIndex, + QRhiBatchedBindings<ID3D11Buffer *> *ubufs, + QRhiBatchedBindings<UINT> *ubufoffsets, + const uint *dynOfsPairs, int dynOfsPairCount) +{ + const UINT count = ubufs->batches[batchIndex].resources.count(); + const UINT startBinding = ubufs->batches[batchIndex].startBinding; + *offsets = ubufoffsets->batches[batchIndex].resources; + for (UINT b = 0; b < count; ++b) { + for (int di = 0; di < dynOfsPairCount; ++di) { + const uint binding = dynOfsPairs[2 * di]; + if (binding == startBinding + b) { + const uint offsetInConstants = dynOfsPairs[2 * di + 1]; + (*offsets)[b] = offsetInConstants; + break; + } + } + } +} + void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, bool offsetOnlyChange) @@ -1653,6 +1802,15 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD, contextState.fsHighestActiveSrvBinding = qMax<int>(contextState.fsHighestActiveSrvBinding, batch.startBinding + batch.resources.count() - 1); } + + for (const auto &batch : srbD->cssamplers.batches) + context->CSSetSamplers(batch.startBinding, batch.resources.count(), batch.resources.constData()); + + for (const auto &batch : srbD->csshaderresources.batches) { + context->CSSetShaderResources(batch.startBinding, batch.resources.count(), batch.resources.constData()); + contextState.csHighestActiveSrvBinding = qMax<int>(contextState.csHighestActiveSrvBinding, + batch.startBinding + batch.resources.count() - 1); + } } for (int i = 0, ie = srbD->vsubufs.batches.count(); i != ie; ++i) { @@ -1663,21 +1821,10 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD, srbD->vsubufoffsets.batches[i].resources.constData(), srbD->vsubufsizes.batches[i].resources.constData()); } else { - const UINT count = srbD->vsubufs.batches[i].resources.count(); - const UINT startBinding = srbD->vsubufs.batches[i].startBinding; - QVarLengthArray<UINT, 4> offsets = srbD->vsubufoffsets.batches[i].resources; - for (UINT b = 0; b < count; ++b) { - for (int di = 0; di < dynOfsPairCount; ++di) { - const uint binding = dynOfsPairs[2 * di]; - if (binding == startBinding + b) { - const uint offsetInConstants = dynOfsPairs[2 * di + 1]; - offsets[b] = offsetInConstants; - break; - } - } - } - context->VSSetConstantBuffers1(startBinding, - count, + QVarLengthArray<UINT, 4> offsets; + applyDynamicOffsets(&offsets, i, &srbD->vsubufs, &srbD->vsubufoffsets, dynOfsPairs, dynOfsPairCount); + context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding, + srbD->vsubufs.batches[i].resources.count(), srbD->vsubufs.batches[i].resources.constData(), offsets.constData(), srbD->vsubufsizes.batches[i].resources.constData()); @@ -1692,33 +1839,73 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD, srbD->fsubufoffsets.batches[i].resources.constData(), srbD->fsubufsizes.batches[i].resources.constData()); } else { - const UINT count = srbD->fsubufs.batches[i].resources.count(); - const UINT startBinding = srbD->fsubufs.batches[i].startBinding; - QVarLengthArray<UINT, 4> offsets = srbD->fsubufoffsets.batches[i].resources; - for (UINT b = 0; b < count; ++b) { - for (int di = 0; di < dynOfsPairCount; ++di) { - const uint binding = dynOfsPairs[2 * di]; - if (binding == startBinding + b) { - const uint offsetInConstants = dynOfsPairs[2 * di + 1]; - offsets[b] = offsetInConstants; - break; - } - } - } - context->PSSetConstantBuffers1(startBinding, - count, + QVarLengthArray<UINT, 4> offsets; + applyDynamicOffsets(&offsets, i, &srbD->fsubufs, &srbD->fsubufoffsets, dynOfsPairs, dynOfsPairCount); + context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding, + srbD->fsubufs.batches[i].resources.count(), srbD->fsubufs.batches[i].resources.constData(), offsets.constData(), srbD->fsubufsizes.batches[i].resources.constData()); } } + + for (int i = 0, ie = srbD->csubufs.batches.count(); i != ie; ++i) { + if (!dynOfsPairCount) { + context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding, + srbD->csubufs.batches[i].resources.count(), + srbD->csubufs.batches[i].resources.constData(), + srbD->csubufoffsets.batches[i].resources.constData(), + srbD->csubufsizes.batches[i].resources.constData()); + } else { + QVarLengthArray<UINT, 4> offsets; + applyDynamicOffsets(&offsets, i, &srbD->csubufs, &srbD->csubufoffsets, dynOfsPairs, dynOfsPairCount); + context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding, + srbD->csubufs.batches[i].resources.count(), + srbD->csubufs.batches[i].resources.constData(), + offsets.constData(), + srbD->csubufsizes.batches[i].resources.constData()); + } + } + + for (int i = 0, ie = srbD->csUAVs.batches.count(); i != ie; ++i) { + const uint startBinding = srbD->csUAVs.batches[i].startBinding; + const uint count = srbD->csUAVs.batches[i].resources.count(); + context->CSSetUnorderedAccessViews(startBinding, + count, + srbD->csUAVs.batches[i].resources.constData(), + nullptr); + contextState.csHighestActiveUavBinding = qMax<int>(contextState.csHighestActiveUavBinding, + startBinding + count - 1); + } } -void QRhiD3D11::setRenderTarget(QRhiRenderTarget *rt) +void QRhiD3D11::resetShaderResources() { - // The new output cannot be bound as input from the previous frame, - // otherwise the debug layer complains. Avoid this. - const int nullsrvCount = qMax(contextState.vsHighestActiveSrvBinding, contextState.fsHighestActiveSrvBinding) + 1; + // Output cannot be bound on input etc. + + if (contextState.vsHasIndexBufferBound) { + context->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0); + contextState.vsHasIndexBufferBound = false; + } + + if (contextState.vsHighestActiveVertexBufferBinding >= 0) { + const int count = contextState.vsHighestActiveVertexBufferBinding + 1; + QVarLengthArray<ID3D11Buffer *, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nullbufs(count); + for (int i = 0; i < count; ++i) + nullbufs[i] = nullptr; + QVarLengthArray<UINT, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nullstrides(count); + for (int i = 0; i < count; ++i) + nullstrides[i] = 0; + QVarLengthArray<UINT, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nulloffsets(count); + for (int i = 0; i < count; ++i) + nulloffsets[i] = 0; + context->IASetVertexBuffers(0, count, nullbufs.constData(), nullstrides.constData(), nulloffsets.constData()); + contextState.vsHighestActiveVertexBufferBinding = -1; + } + + int nullsrvCount = qMax(contextState.vsHighestActiveSrvBinding, contextState.fsHighestActiveSrvBinding); + nullsrvCount = qMax(nullsrvCount, contextState.csHighestActiveSrvBinding); + nullsrvCount += 1; if (nullsrvCount > 0) { QVarLengthArray<ID3D11ShaderResourceView *, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> nullsrvs(nullsrvCount); @@ -1732,9 +1919,21 @@ void QRhiD3D11::setRenderTarget(QRhiRenderTarget *rt) context->PSSetShaderResources(0, contextState.fsHighestActiveSrvBinding + 1, nullsrvs.constData()); contextState.fsHighestActiveSrvBinding = -1; } + if (contextState.csHighestActiveSrvBinding >= 0) { + context->CSSetShaderResources(0, contextState.csHighestActiveSrvBinding + 1, nullsrvs.constData()); + contextState.csHighestActiveSrvBinding = -1; + } + } + + if (contextState.csHighestActiveUavBinding >= 0) { + const int nulluavCount = contextState.csHighestActiveUavBinding + 1; + QVarLengthArray<ID3D11UnorderedAccessView *, + D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> nulluavs(nulluavCount); + for (int i = 0; i < nulluavCount; ++i) + nulluavs[i] = nullptr; + context->CSSetUnorderedAccessViews(0, nulluavCount, nulluavs.constData(), nullptr); + contextState.csHighestActiveUavBinding = -1; } - QD3D11RenderTargetData *rtD = rtData(rt); - context->OMSetRenderTargets(rtD->colorAttCount, rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv); } void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain) @@ -1755,15 +1954,22 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * // it around by issuing a semi-fake OMSetRenderTargets early and // writing the first timestamp only afterwards. context->Begin(tsDisjoint); - setRenderTarget(×tampSwapChain->rt); + QD3D11RenderTargetData *rtD = rtData(×tampSwapChain->rt); + context->OMSetRenderTargets(rtD->colorAttCount, rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv); context->End(tsStart); // just record a timestamp, no Begin needed } } for (const QD3D11CommandBuffer::Command &cmd : qAsConst(cbD->commands)) { switch (cmd.cmd) { + case QD3D11CommandBuffer::Command::ResetShaderResources: + resetShaderResources(); + break; case QD3D11CommandBuffer::Command::SetRenderTarget: - setRenderTarget(cmd.args.setRenderTarget.rt); + { + QD3D11RenderTargetData *rtD = rtData(cmd.args.setRenderTarget.rt); + context->OMSetRenderTargets(rtD->colorAttCount, rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv); + } break; case QD3D11CommandBuffer::Command::Clear: { @@ -1805,6 +2011,9 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * } break; case QD3D11CommandBuffer::Command::BindVertexBuffers: + contextState.vsHighestActiveVertexBufferBinding = qMax<int>( + contextState.vsHighestActiveVertexBufferBinding, + cmd.args.bindVertexBuffers.startSlot + cmd.args.bindVertexBuffers.slotCount - 1); context->IASetVertexBuffers(cmd.args.bindVertexBuffers.startSlot, cmd.args.bindVertexBuffers.slotCount, cmd.args.bindVertexBuffers.buffers, @@ -1812,6 +2021,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * cmd.args.bindVertexBuffers.offsets); break; case QD3D11CommandBuffer::Command::BindIndexBuffer: + contextState.vsHasIndexBufferBound = true; context->IASetIndexBuffer(cmd.args.bindIndexBuffer.buffer, cmd.args.bindIndexBuffer.format, cmd.args.bindIndexBuffer.offset); @@ -1894,6 +2104,12 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain * case QD3D11CommandBuffer::Command::DebugMarkMsg: annotations->SetMarker(reinterpret_cast<LPCWSTR>(QString::fromLatin1(cmd.args.debugMark.s).utf16())); break; + case QD3D11CommandBuffer::Command::BindComputePipeline: + context->CSSetShader(cmd.args.bindComputePipeline.ps->cs, nullptr, 0); + break; + case QD3D11CommandBuffer::Command::Dispatch: + context->Dispatch(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z); + break; default: break; } @@ -1920,6 +2136,11 @@ void QD3D11Buffer::release() buffer->Release(); buffer = nullptr; + if (uav) { + uav->Release(); + uav = nullptr; + } + QRHI_RES_RHI(QRhiD3D11); QRHI_PROF; QRHI_PROF_F(releaseBuffer(this)); @@ -1935,6 +2156,8 @@ static inline uint toD3DBufferUsage(QRhiBuffer::UsageFlags usage) u |= D3D11_BIND_INDEX_BUFFER; if (usage.testFlag(QRhiBuffer::UniformBuffer)) u |= D3D11_BIND_CONSTANT_BUFFER; + if (usage.testFlag(QRhiBuffer::StorageBuffer)) + u |= D3D11_BIND_UNORDERED_ACCESS; return u; } @@ -1948,8 +2171,13 @@ bool QD3D11Buffer::build() return false; } + if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) { + qWarning("StorageBuffer cannot be combined with Dynamic"); + return false; + } + const int nonZeroSize = m_size <= 0 ? 256 : m_size; - const int roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned(nonZeroSize, 256) : nonZeroSize; + const int roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256 : 4); D3D11_BUFFER_DESC desc; memset(&desc, 0, sizeof(desc)); @@ -1957,6 +2185,7 @@ bool QD3D11Buffer::build() 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; + desc.MiscFlags = m_usage.testFlag(QRhiBuffer::StorageBuffer) ? D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS : 0; QRHI_RES_RHI(QRhiD3D11); HRESULT hr = rhiD->dev->CreateBuffer(&desc, nullptr, &buffer); @@ -1981,6 +2210,30 @@ bool QD3D11Buffer::build() return true; } +ID3D11UnorderedAccessView *QD3D11Buffer::unorderedAccessView() +{ + if (uav) + return uav; + + // SPIRV-Cross generated HLSL uses RWByteAddressBuffer + D3D11_UNORDERED_ACCESS_VIEW_DESC desc; + memset(&desc, 0, sizeof(desc)); + desc.Format = DXGI_FORMAT_R32_TYPELESS; + desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = 0; + desc.Buffer.NumElements = aligned(m_size, 4) / 4; + desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW; + + QRHI_RES_RHI(QRhiD3D11); + HRESULT hr = rhiD->dev->CreateUnorderedAccessView(buffer, &desc, &uav); + if (FAILED(hr)) { + qWarning("Failed to create UAV: %s", qPrintable(comErrorMessage(hr))); + return nullptr; + } + + return uav; +} + QD3D11RenderBuffer::QD3D11RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags) : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags) @@ -2097,6 +2350,8 @@ QD3D11Texture::QD3D11Texture(QRhiImplementation *rhi, Format format, const QSize int sampleCount, Flags flags) : QRhiTexture(rhi, format, pixelSize, sampleCount, flags) { + for (int i = 0; i < QRhi::MAX_LEVELS; ++i) + perLevelViews[i] = nullptr; } QD3D11Texture::~QD3D11Texture() @@ -2114,6 +2369,13 @@ void QD3D11Texture::release() srv = nullptr; } + for (int i = 0; i < QRhi::MAX_LEVELS; ++i) { + if (perLevelViews[i]) { + perLevelViews[i]->Release(); + perLevelViews[i] = nullptr; + } + } + if (owns) tex->Release(); @@ -2244,6 +2506,8 @@ bool QD3D11Texture::build() bindFlags |= D3D11_BIND_RENDER_TARGET; miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; } + if (m_flags.testFlag(UsedWithLoadStore)) + bindFlags |= D3D11_BIND_UNORDERED_ACCESS; D3D11_TEXTURE2D_DESC desc; memset(&desc, 0, sizeof(desc)); @@ -2306,6 +2570,37 @@ const QRhiNativeHandles *QD3D11Texture::nativeHandles() return &nativeHandlesStruct; } +ID3D11UnorderedAccessView *QD3D11Texture::unorderedAccessViewForLevel(int level) +{ + if (perLevelViews[level]) + return perLevelViews[level]; + + const bool isCube = m_flags.testFlag(CubeMap); + D3D11_UNORDERED_ACCESS_VIEW_DESC desc; + memset(&desc, 0, sizeof(desc)); + desc.Format = dxgiFormat; + if (isCube) { + desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY; + desc.Texture2DArray.MipSlice = level; + desc.Texture2DArray.FirstArraySlice = 0; + desc.Texture2DArray.ArraySize = 6; + } else { + desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; + desc.Texture2D.MipSlice = level; + } + + QRHI_RES_RHI(QRhiD3D11); + ID3D11UnorderedAccessView *uav = nullptr; + HRESULT hr = rhiD->dev->CreateUnorderedAccessView(tex, &desc, &uav); + if (FAILED(hr)) { + qWarning("Failed to create UAV: %s", qPrintable(comErrorMessage(hr))); + return nullptr; + } + + perLevelViews[level] = uav; + return uav; +} + QD3D11Sampler::QD3D11Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v) : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v) @@ -3121,11 +3416,40 @@ QD3D11ComputePipeline::~QD3D11ComputePipeline() void QD3D11ComputePipeline::release() { + QRHI_RES_RHI(QRhiD3D11); + + if (!cs) + return; + + cs->Release(); + cs = nullptr; + + rhiD->unregisterResource(this); } bool QD3D11ComputePipeline::build() { - return false; + if (cs) + release(); + + QRHI_RES_RHI(QRhiD3D11); + + QString error; + QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error); + if (bytecode.isEmpty()) { + qWarning("HLSL compute shader compilation failed: %s", qPrintable(error)); + return false; + } + + HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), bytecode.size(), nullptr, &cs); + if (FAILED(hr)) { + qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr))); + return false; + } + + generation += 1; + rhiD->registerResource(this); + return true; } QD3D11CommandBuffer::QD3D11CommandBuffer(QRhiImplementation *rhi) diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 775f256cb7..688f79b3b7 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -65,9 +65,12 @@ struct QD3D11Buffer : public QRhiBuffer void release() override; bool build() override; + ID3D11UnorderedAccessView *unorderedAccessView(); + ID3D11Buffer *buffer = nullptr; QByteArray dynBuf; bool hasPendingDynamicUpdates = false; + ID3D11UnorderedAccessView *uav = nullptr; uint generation = 0; friend class QRhiD3D11; }; @@ -101,6 +104,7 @@ struct QD3D11Texture : public QRhiTexture bool prepareBuild(QSize *adjustedSize = nullptr); bool finishBuild(); + ID3D11UnorderedAccessView *unorderedAccessViewForLevel(int level); ID3D11Texture2D *tex = nullptr; bool owns = true; @@ -109,6 +113,7 @@ struct QD3D11Texture : public QRhiTexture uint mipLevelCount = 0; DXGI_SAMPLE_DESC sampleDesc; QRhiD3D11TextureNativeHandles nativeHandlesStruct; + ID3D11UnorderedAccessView *perLevelViews[QRhi::MAX_LEVELS]; uint generation = 0; friend class QRhiD3D11; }; @@ -209,10 +214,20 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings quint64 samplerId; uint samplerGeneration; }; + struct BoundStorageImageData { + quint64 id; + uint generation; + }; + struct BoundStorageBufferData { + quint64 id; + uint generation; + }; struct BoundResourceData { union { BoundUniformBufferData ubuf; BoundSampledTextureData stex; + BoundStorageImageData simage; + BoundStorageBufferData sbuf; }; }; QVector<BoundResourceData> boundResourceData; @@ -225,12 +240,21 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings QRhiBatchedBindings<UINT> fsubufoffsets; QRhiBatchedBindings<UINT> fsubufsizes; + QRhiBatchedBindings<ID3D11Buffer *> csubufs; + QRhiBatchedBindings<UINT> csubufoffsets; + QRhiBatchedBindings<UINT> csubufsizes; + QRhiBatchedBindings<ID3D11SamplerState *> vssamplers; QRhiBatchedBindings<ID3D11ShaderResourceView *> vsshaderresources; QRhiBatchedBindings<ID3D11SamplerState *> fssamplers; QRhiBatchedBindings<ID3D11ShaderResourceView *> fsshaderresources; + QRhiBatchedBindings<ID3D11SamplerState *> cssamplers; + QRhiBatchedBindings<ID3D11ShaderResourceView *> csshaderresources; + + QRhiBatchedBindings<ID3D11UnorderedAccessView *> csUAVs; + friend class QRhiD3D11; }; @@ -260,6 +284,10 @@ struct QD3D11ComputePipeline : public QRhiComputePipeline ~QD3D11ComputePipeline(); void release() override; bool build() override; + + ID3D11ComputeShader *cs = nullptr; + uint generation = 0; + friend class QRhiD3D11; }; struct QD3D11SwapChain; @@ -272,6 +300,7 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer struct Command { enum Cmd { + ResetShaderResources, SetRenderTarget, Clear, Viewport, @@ -290,7 +319,9 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer GenMip, DebugMarkBegin, DebugMarkEnd, - DebugMarkMsg + DebugMarkMsg, + BindComputePipeline, + Dispatch }; enum ClearFlag { Color = 1, Depth = 2, Stencil = 4 }; Cmd cmd; @@ -392,6 +423,14 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer struct { char s[64]; } debugMark; + struct { + QD3D11ComputePipeline *ps; + } bindComputePipeline; + struct { + UINT x; + UINT y; + UINT z; + } dispatch; } args; }; @@ -404,9 +443,11 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer QVector<Command> commands; PassType recordingPass; QRhiRenderTarget *currentTarget; - QRhiGraphicsPipeline *currentPipeline; + QRhiGraphicsPipeline *currentGraphicsPipeline; + QRhiComputePipeline *currentComputePipeline; uint currentPipelineGeneration; - QRhiShaderResourceBindings *currentSrb; + QRhiShaderResourceBindings *currentGraphicsSrb; + QRhiShaderResourceBindings *currentComputeSrb; uint currentSrbGeneration; ID3D11Buffer *currentIndexBuffer; quint32 currentIndexOffset; @@ -438,9 +479,11 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer resetCachedState(); } void resetCachedState() { - currentPipeline = nullptr; + currentGraphicsPipeline = nullptr; + currentComputePipeline = nullptr; currentPipelineGeneration = 0; - currentSrb = nullptr; + currentGraphicsSrb = nullptr; + currentComputeSrb = nullptr; currentSrbGeneration = 0; currentIndexBuffer = nullptr; currentIndexOffset = 0; @@ -596,11 +639,10 @@ public: void bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, bool offsetOnlyChange); - void setRenderTarget(QRhiRenderTarget *rt); + void resetShaderResources(); void executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain = nullptr); DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const; void finishActiveReadbacks(); - void enqueueSetRenderTarget(QD3D11CommandBuffer *cbD, QRhiRenderTarget *rt); void reportLiveObjects(ID3D11Device *device); bool debugLayer = false; @@ -614,8 +656,12 @@ public: QRhiD3D11NativeHandles nativeHandlesStruct; struct { + int vsHighestActiveVertexBufferBinding = -1; + bool vsHasIndexBufferBound = false; int vsHighestActiveSrvBinding = -1; int fsHighestActiveSrvBinding = -1; + int csHighestActiveSrvBinding = -1; + int csHighestActiveUavBinding = -1; QD3D11SwapChain *currentSwapChain = nullptr; } contextState; |