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>
This commit is contained in:
Laszlo Agocs 2019-06-19 16:23:54 +02:00
parent 33f16af307
commit 484fc8545f
2 changed files with 450 additions and 80 deletions

View File

@ -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(&timestampSwapChain->rt);
QD3D11RenderTargetData *rtD = rtData(&timestampSwapChain->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)

View File

@ -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;