Add UAVs for fragment stage on DX11

Add support for UAV's in fragment stage. UAV's are required to implement
order independent transparency.

Task-number: QTBUG-130332
Change-Id: Ia539ff3f94df43d3276d1d242091d55eafcbfadb
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
Antti Määttä 2024-06-14 14:07:38 +03:00
parent d8ac4cd869
commit cf037274d1
2 changed files with 91 additions and 8 deletions

View File

@ -2392,6 +2392,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
srbD->csSamplerBatches.clear();
srbD->csUavBatches.clear();
srbD->fsUavBatches.clear();
struct Stage {
struct Buffer {
@ -2587,8 +2588,15 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
if (uav)
res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
}
} else if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
if (nativeBinding.first >= 0) {
ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level);
if (uav)
res[RBM_FRAGMENT].uavs.append({ nativeBinding.first, uav });
}
} else {
qWarning("Unordered access only supported at compute stage");
qWarning("Unordered access only supported at fragment/compute stage");
}
}
break;
@ -2650,6 +2658,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
res[RBM_FRAGMENT].buildSamplerBatches(srbD->fsSamplerBatches);
res[RBM_COMPUTE].buildSamplerBatches(srbD->csSamplerBatches);
res[RBM_FRAGMENT].buildUavBatches(srbD->fsUavBatches);
res[RBM_COMPUTE].buildUavBatches(srbD->csUavBatches);
}
@ -2771,7 +2780,9 @@ static inline uint clampedResourceCount(uint startSlot, int countSlots, uint max
void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange)
bool offsetOnlyChange,
QD3D11RenderTargetData *rtD,
RenderTargetUavUpdateState &rtUavState)
{
UINT offsets[QD3D11CommandBuffer::MAX_DYNAMIC_OFFSET_COUNT];
@ -2791,10 +2802,27 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
SETSAMPLERBATCH(cs, CS)
SETUAVBATCH(cs, CS)
if (srbD->fsUavBatches.present) {
for (const auto &batch : srbD->fsUavBatches.uavs.batches) {
const uint count = qMin(clampedResourceCount(batch.startBinding, batch.resources.count(),
D3D11_1_UAV_SLOT_COUNT, "fs UAV"),
uint(QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS));
if (count) {
if (rtUavState.update(rtD, batch.resources.constData(), count)) {
context->OMSetRenderTargetsAndUnorderedAccessViews(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv,
UINT(rtD->colorAttCount), count, batch.resources.constData(), nullptr);
}
contextState.fsHighestActiveUavBinding = qMax(contextState.fsHighestActiveUavBinding,
int(batch.startBinding + count) - 1);
}
}
}
}
}
void QRhiD3D11::resetShaderResources()
void QRhiD3D11::resetShaderResources(QD3D11RenderTargetData *rtD,
RenderTargetUavUpdateState &rtUavState)
{
// Output cannot be bound on input etc.
@ -2855,6 +2883,11 @@ void QRhiD3D11::resetShaderResources()
}
}
if (contextState.fsHighestActiveUavBinding >= 0) {
rtUavState.update(rtD);
context->OMSetRenderTargetsAndUnorderedAccessViews(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv, 0, 0, nullptr, nullptr);
contextState.fsHighestActiveUavBinding = -1;
}
if (contextState.csHighestActiveUavBinding >= 0) {
const int nulluavCount = contextState.csHighestActiveUavBinding + 1;
QVarLengthArray<ID3D11UnorderedAccessView *,
@ -2888,6 +2921,10 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
};
int currentShaderMask = 0xFF;
// Track render target and uav updates during executeCommandBuffer.
// Prevents multiple identical OMSetRenderTargetsAndUnorderedAccessViews calls.
RenderTargetUavUpdateState rtUavState;
for (auto it = cbD->commands.cbegin(), end = cbD->commands.cend(); it != end; ++it) {
const QD3D11CommandBuffer::Command &cmd(*it);
switch (cmd.cmd) {
@ -2901,7 +2938,9 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
// it around by issuing a semi-fake OMSetRenderTargets early and
// writing the first timestamp only afterwards.
QD3D11RenderTargetData *rtD = cmd.args.beginFrame.swapchainData;
rtUavState.update(rtD);
context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
cbD->prevRtD = rtD;
}
context->End(cmd.args.beginFrame.tsQuery); // no Begin() for D3D11_QUERY_TIMESTAMP
}
@ -2913,12 +2952,14 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
context->End(cmd.args.endFrame.tsDisjointQuery);
break;
case QD3D11CommandBuffer::Command::ResetShaderResources:
resetShaderResources();
resetShaderResources(cbD->prevRtD, rtUavState);
break;
case QD3D11CommandBuffer::Command::SetRenderTarget:
{
QD3D11RenderTargetData *rtD = rtData(cmd.args.setRenderTarget.rt);
context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
if (rtUavState.update(rtD))
context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
cbD->prevRtD = rtD;
}
break;
case QD3D11CommandBuffer::Command::Clear:
@ -2995,7 +3036,9 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
bindShaderResources(cmd.args.bindShaderResources.srb,
cmd.args.bindShaderResources.dynamicOffsetPairs,
cmd.args.bindShaderResources.dynamicOffsetCount,
cmd.args.bindShaderResources.offsetOnlyChange);
cmd.args.bindShaderResources.offsetOnlyChange,
cbD->prevRtD,
rtUavState);
break;
case QD3D11CommandBuffer::Command::StencilRef:
stencilRef = cmd.args.stencilRef.ref;
@ -5547,4 +5590,31 @@ bool QD3D11SwapChain::createOrResize()
return true;
}
bool RenderTargetUavUpdateState::update(QD3D11RenderTargetData *data, ID3D11UnorderedAccessView *const *uavs, int count)
{
bool ret = false;
if (dsv != data->dsv) {
dsv = data->dsv;
ret = true;
}
for (int i = 0; i < data->colorAttCount; i++) {
ret |= rtv[i] != data->rtv[i];
rtv[i] = data->rtv[i];
}
for (int i = data->colorAttCount; i < QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS; i++) {
ret |= rtv[i] != nullptr;
rtv[i] = nullptr;
}
for (int i = 0; i < count; i++) {
ret |= uav[i] != uavs[i];
uav[i] = uavs[i];
}
for (int i = count; i < QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS; i++) {
ret |= uav[i] != nullptr;
uav[i] = nullptr;
}
return ret;
}
QT_END_NAMESPACE

View File

@ -180,6 +180,14 @@ struct QD3D11TextureRenderTarget : public QRhiTextureRenderTarget
friend class QRhiD3D11;
};
struct RenderTargetUavUpdateState
{
ID3D11RenderTargetView *rtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS];
ID3D11DepthStencilView *dsv = nullptr;
std::array<ID3D11UnorderedAccessView *, QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS> uav;
bool update(QD3D11RenderTargetData *data, ID3D11UnorderedAccessView * const *uavs = nullptr, int count = 0);
};
struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
{
QD3D11ShaderResourceBindings(QRhiImplementation *rhi);
@ -285,6 +293,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
StageSamplerBatches csSamplerBatches;
StageUavBatches csUavBatches;
StageUavBatches fsUavBatches;
friend class QRhiD3D11;
};
@ -521,6 +530,7 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
DXGI_FORMAT currentIndexFormat;
ID3D11Buffer *currentVertexBuffers[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
quint32 currentVertexOffsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
QD3D11RenderTargetData *prevRtD;
QVarLengthArray<QByteArray, 4> dataRetainPool;
QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool;
@ -549,6 +559,7 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
recordingPass = NoPass;
// do not zero lastGpuTime
currentTarget = nullptr;
prevRtD = nullptr;
resetCommands();
resetCachedState();
}
@ -762,10 +773,11 @@ public:
void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]);
void executeBufferHostWrites(QD3D11Buffer *bufD);
void bindShaderResources(QD3D11ShaderResourceBindings *srbD,
const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange);
void resetShaderResources();
bool offsetOnlyChange, QD3D11RenderTargetData *rtD, RenderTargetUavUpdateState &rtUavState);
void resetShaderResources(QD3D11RenderTargetData *rtD, RenderTargetUavUpdateState &rtUavState);
void executeCommandBuffer(QD3D11CommandBuffer *cbD);
DXGI_SAMPLE_DESC effectiveSampleDesc(int sampleCount) const;
void finishActiveReadbacks();
@ -803,6 +815,7 @@ public:
int fsHighestActiveSrvBinding = -1;
int csHighestActiveSrvBinding = -1;
int csHighestActiveUavBinding = -1;
int fsHighestActiveUavBinding = -1;
QD3D11SwapChain *currentSwapChain = nullptr;
} contextState;