Skip to content

Commit 631513b

Browse files
DeviceContextD3D11: fixed issue with PS UAVs being incorrectly unbound
1 parent f81fd2d commit 631513b

File tree

5 files changed

+217
-6
lines changed

5 files changed

+217
-6
lines changed

Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,18 +434,24 @@ void DeviceContextD3D11Impl::BindShaderResources(Uint32 BindSRBMask)
434434
PixelShaderUAVBindMode::Clear :
435435
PixelShaderUAVBindMode::Keep;
436436

437+
Uint32 UpToDateSRBMask = m_BindInfo.ActiveSRBMask & ~BindSRBMask;
437438
while (BindSRBMask != 0)
438439
{
439440
Uint32 SignBit = ExtractLSB(BindSRBMask);
440-
Uint32 sign = PlatformMisc::GetLSB(SignBit);
441-
VERIFY_EXPR(sign < m_pPipelineState->GetResourceSignatureCount());
442-
const D3D11ShaderResourceCounters& BaseBindings = m_pPipelineState->GetBaseBindings(sign);
441+
Uint32 SignIdx = PlatformMisc::GetLSB(SignBit);
442+
VERIFY_EXPR(SignIdx < m_pPipelineState->GetResourceSignatureCount());
443+
const D3D11ShaderResourceCounters& BaseBindings = m_pPipelineState->GetBaseBindings(SignIdx);
443444

444445
#ifdef DILIGENT_DEVELOPMENT
445-
m_BindInfo.BaseBindings[sign] = BaseBindings;
446+
m_BindInfo.BaseBindings[SignIdx] = BaseBindings;
446447
#endif
447-
const ShaderResourceCacheD3D11* pResourceCache = m_BindInfo.ResourceCaches[sign];
448-
DEV_CHECK_ERR(pResourceCache != nullptr, "Shader resource cache at index ", sign, " is null.");
448+
const ShaderResourceCacheD3D11* pResourceCache = m_BindInfo.ResourceCaches[SignIdx];
449+
if (pResourceCache == nullptr)
450+
{
451+
DEV_ERROR("Shader resource cache at index ", SignIdx, " is null.");
452+
continue;
453+
}
454+
449455
if (m_BindInfo.StaleSRBMask & SignBit)
450456
{
451457
// Bind all cache resources
@@ -467,6 +473,30 @@ void DeviceContextD3D11Impl::BindShaderResources(Uint32 BindSRBMask)
467473
BindDynamicCBs(*pResourceCache, BaseBindings);
468474
}
469475
}
476+
477+
if (PsUavBindMode == PixelShaderUAVBindMode::Clear)
478+
{
479+
// Check if SRBs that are not in the BindSRBMask contain UAVs.
480+
// In this case we should keep UAVs, not clear them.
481+
while (UpToDateSRBMask != 0)
482+
{
483+
Uint32 SignBit = ExtractLSB(UpToDateSRBMask);
484+
Uint32 SignIdx = PlatformMisc::GetLSB(SignBit);
485+
VERIFY_EXPR(SignIdx < m_pPipelineState->GetResourceSignatureCount());
486+
const ShaderResourceCacheD3D11* pResourceCache = m_BindInfo.ResourceCaches[SignIdx];
487+
if (pResourceCache == nullptr)
488+
{
489+
DEV_ERROR("Shader resource cache at index ", SignIdx, " is null.");
490+
continue;
491+
}
492+
if (pResourceCache->GetUAVCount(PSInd) > 0)
493+
{
494+
PsUavBindMode = PixelShaderUAVBindMode::Keep;
495+
break;
496+
}
497+
}
498+
}
499+
470500
m_BindInfo.StaleSRBMask &= ~m_BindInfo.ActiveSRBMask;
471501

472502
if (PsUavBindMode == PixelShaderUAVBindMode::Bind)

Tests/DiligentCoreAPITest/include/InlineShaders/ComputeShaderTestHLSL.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,28 @@ void main(in VSOutput VSOut)
106106
)"
107107
};
108108

109+
110+
const std::string FillTexturePS2{
111+
R"(
112+
struct VSOutput
113+
{
114+
float4 Pos : SV_Position;
115+
};
116+
117+
cbuffer Constants
118+
{
119+
float4 g_Color;
120+
};
121+
122+
RWTexture2D</*format=rgba8*/ float4> g_tex2DUAV : register(u0);
123+
124+
void main(in VSOutput VSOut)
125+
{
126+
g_tex2DUAV[uint2(VSOut.Pos.xy)] = float4(float2(uint2(VSOut.Pos.xy) % 256u) / 256.0, 0.0, 1.0) * g_Color;
127+
}
128+
)"
129+
};
130+
109131
// clang-format on
110132

111133
} // namespace HLSL

Tests/DiligentCoreAPITest/src/ComputeShaderTest.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,4 +463,150 @@ TEST(ComputeShaderTest, FillTexturePS_InRenderPass)
463463
TestFillTexturePS(true);
464464
}
465465

466+
TEST(ComputeShaderTest, FillTexturePS_Signatures)
467+
{
468+
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
469+
IRenderDevice* pDevice = pEnv->GetDevice();
470+
const RenderDeviceInfo& DeviceInfo = pDevice->GetDeviceInfo();
471+
if (!DeviceInfo.Features.ComputeShaders)
472+
{
473+
GTEST_SKIP() << "Compute shaders are not supported by this device";
474+
}
475+
476+
ISwapChain* pSwapChain = pEnv->GetSwapChain();
477+
IDeviceContext* pContext = pEnv->GetDeviceContext();
478+
479+
const SwapChainDesc& SCDesc = pSwapChain->GetDesc();
480+
481+
GPUTestingEnvironment::ScopedReset EnvironmentAutoReset;
482+
483+
RefCntAutoPtr<ITestingSwapChain> pTestingSwapChain{pSwapChain, IID_TestingSwapChain};
484+
if (!pTestingSwapChain)
485+
{
486+
GTEST_SKIP() << "Compute shader test requires testing swap chain";
487+
}
488+
489+
RefCntAutoPtr<ITextureView> pDummyRTV;
490+
if (DeviceInfo.IsWebGPUDevice())
491+
{
492+
// WebGPU does not support render passes without attachments (https://github.com/gpuweb/gpuweb/issues/503)
493+
RefCntAutoPtr<ITexture> pDummyTex = pEnv->CreateTexture("Dummy render target", SCDesc.ColorBufferFormat, BIND_RENDER_TARGET, SCDesc.Width, SCDesc.Height);
494+
ASSERT_TRUE(pDummyTex != nullptr);
495+
pDummyRTV = pDummyTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET);
496+
}
497+
498+
pContext->Flush();
499+
pContext->InvalidateState();
500+
501+
ComputeShaderReference(pSwapChain);
502+
503+
ShaderCreateInfo ShaderCI;
504+
ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
505+
ShaderCI.ShaderCompiler = pEnv->GetDefaultCompiler(ShaderCI.SourceLanguage);
506+
507+
ShaderCI.Desc = {"Compute shader test - FillTextureVS", SHADER_TYPE_VERTEX, true};
508+
ShaderCI.EntryPoint = "main";
509+
ShaderCI.Source = HLSL::FillTextureVS.c_str();
510+
RefCntAutoPtr<IShader> pVS;
511+
pDevice->CreateShader(ShaderCI, &pVS);
512+
ASSERT_NE(pVS, nullptr);
513+
514+
ShaderCI.Desc = {"Compute shader test - FillTexturePS", SHADER_TYPE_PIXEL, true};
515+
ShaderCI.EntryPoint = "main";
516+
ShaderCI.Source = HLSL::FillTexturePS2.c_str();
517+
RefCntAutoPtr<IShader> pPS;
518+
pDevice->CreateShader(ShaderCI, &pPS);
519+
ASSERT_NE(pPS, nullptr);
520+
521+
RefCntAutoPtr<IPipelineResourceSignature> pSignature0;
522+
{
523+
PipelineResourceSignatureDescX SignDesc{"ComputeShaderTest.FillTexturePS_InRenderPass - Signature 0"};
524+
SignDesc.AddResource(SHADER_TYPE_PIXEL, "Constants", 1u, SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE);
525+
pDevice->CreatePipelineResourceSignature(SignDesc, &pSignature0);
526+
ASSERT_NE(pSignature0, nullptr);
527+
}
528+
529+
RefCntAutoPtr<IPipelineResourceSignature> pSignature1;
530+
{
531+
PipelineResourceSignatureDescX SignDesc{"ComputeShaderTest.FillTexturePS_InRenderPass - Signature 1"};
532+
SignDesc.AddResource(SHADER_TYPE_PIXEL, "g_tex2DUAV", 1u, SHADER_RESOURCE_TYPE_TEXTURE_UAV, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, PIPELINE_RESOURCE_FLAG_NONE,
533+
WebGPUResourceAttribs{WEB_GPU_BINDING_TYPE_WRITE_ONLY_TEXTURE_UAV, RESOURCE_DIM_TEX_2D, TEX_FORMAT_RGBA8_UNORM});
534+
SignDesc.SetBindingIndex(1);
535+
pDevice->CreatePipelineResourceSignature(SignDesc, &pSignature1);
536+
ASSERT_NE(pSignature1, nullptr);
537+
}
538+
539+
GraphicsPipelineStateCreateInfoX PSOCreateInfo{"Compute shader test - output from PS"};
540+
541+
PSOCreateInfo.AddSignature(pSignature0);
542+
PSOCreateInfo.AddSignature(pSignature1);
543+
544+
PSOCreateInfo.GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_NONE;
545+
PSOCreateInfo.GraphicsPipeline.DepthStencilDesc.DepthEnable = False;
546+
547+
PSOCreateInfo.pVS = pVS;
548+
PSOCreateInfo.pPS = pPS;
549+
550+
if (DeviceInfo.IsWebGPUDevice())
551+
{
552+
PSOCreateInfo.GraphicsPipeline.NumRenderTargets = 1;
553+
PSOCreateInfo.GraphicsPipeline.RTVFormats[0] = SCDesc.ColorBufferFormat;
554+
PSOCreateInfo.GraphicsPipeline.BlendDesc.RenderTargets[0].RenderTargetWriteMask = COLOR_MASK_NONE;
555+
}
556+
557+
RefCntAutoPtr<IPipelineState> pPSO;
558+
pDevice->CreateGraphicsPipelineState(PSOCreateInfo, &pPSO);
559+
ASSERT_NE(pPSO, nullptr);
560+
561+
const float4 Zero{0};
562+
const float4 One{1};
563+
564+
RefCntAutoPtr<IBuffer> pBuffer0 = pEnv->CreateBuffer({"ComputeShaderTest.FillTexturePS_InRenderPass - Buffer 0", sizeof(Zero), BIND_UNIFORM_BUFFER}, &Zero);
565+
ASSERT_NE(pBuffer0, nullptr);
566+
RefCntAutoPtr<IBuffer> pBuffer1 = pEnv->CreateBuffer({"ComputeShaderTest.FillTexturePS_InRenderPass - Buffer 1", sizeof(One), BIND_UNIFORM_BUFFER}, &One);
567+
ASSERT_NE(pBuffer1, nullptr);
568+
569+
RefCntAutoPtr<IShaderResourceBinding> pSRB0[2];
570+
pSignature0->CreateShaderResourceBinding(&pSRB0[0], true);
571+
ASSERT_NE(pSRB0[0], nullptr);
572+
pSRB0[0]->GetVariableByName(SHADER_TYPE_PIXEL, "Constants")->Set(pBuffer0);
573+
574+
pSignature0->CreateShaderResourceBinding(&pSRB0[1], true);
575+
ASSERT_NE(pSRB0[1], nullptr);
576+
pSRB0[1]->GetVariableByName(SHADER_TYPE_PIXEL, "Constants")->Set(pBuffer1);
577+
578+
579+
RefCntAutoPtr<IShaderResourceBinding> pSRB1;
580+
pSignature1->CreateShaderResourceBinding(&pSRB1, true);
581+
ASSERT_NE(pSRB1, nullptr);
582+
pSRB1->GetVariableByName(SHADER_TYPE_PIXEL, "g_tex2DUAV")->Set(pTestingSwapChain->GetCurrentBackBufferUAV());
583+
584+
ITextureView* pRTVs[] = {pSwapChain->GetCurrentBackBufferRTV()};
585+
pContext->SetRenderTargets(1, pRTVs, pSwapChain->GetDepthBufferDSV(), RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
586+
587+
pContext->SetPipelineState(pPSO);
588+
pContext->CommitShaderResources(pSRB0[0], RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
589+
pContext->CommitShaderResources(pSRB1, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
590+
591+
if (DeviceInfo.IsWebGPUDevice())
592+
{
593+
ITextureView* pDummyRTVs[] = {pDummyRTV};
594+
pContext->SetRenderTargets(1, pDummyRTVs, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
595+
}
596+
else
597+
{
598+
pContext->SetRenderTargets(0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_NONE);
599+
}
600+
601+
Viewport VP{SCDesc};
602+
pContext->SetViewports(1, &VP, SCDesc.Width, SCDesc.Height);
603+
604+
pContext->Draw(DrawAttribs{3, DRAW_FLAG_VERIFY_ALL});
605+
606+
pContext->CommitShaderResources(pSRB0[1], RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
607+
pContext->Draw(DrawAttribs{3, DRAW_FLAG_VERIFY_ALL});
608+
609+
pSwapChain->Present();
610+
}
611+
466612
} // namespace

Tests/GPUTestFramework/include/GPUTestingEnvironment.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ class GPUTestingEnvironment : public TestingEnvironment
136136

137137
RefCntAutoPtr<ITexture> CreateTexture(const char* Name, TEXTURE_FORMAT Fmt, BIND_FLAGS BindFlags, Uint32 Width, Uint32 Height, const void* pInitData = nullptr);
138138

139+
RefCntAutoPtr<IBuffer> CreateBuffer(const BufferDesc& Desc, const void* pInitData = nullptr);
140+
139141
RefCntAutoPtr<ISampler> CreateSampler(const SamplerDesc& Desc);
140142

141143
void SetDefaultCompiler(SHADER_COMPILER compiler);

Tests/GPUTestFramework/src/GPUTestingEnvironment.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,17 @@ RefCntAutoPtr<ITexture> GPUTestingEnvironment::CreateTexture(const char* Name, T
747747
return pTexture;
748748
}
749749

750+
RefCntAutoPtr<IBuffer> GPUTestingEnvironment::CreateBuffer(const BufferDesc& Desc, const void* pInitData)
751+
{
752+
RefCntAutoPtr<IBuffer> pBuffer;
753+
754+
BufferData InitData{pInitData, Desc.Size};
755+
m_pDevice->CreateBuffer(Desc, pInitData ? &InitData : nullptr, &pBuffer);
756+
VERIFY_EXPR(pBuffer != nullptr);
757+
758+
return pBuffer;
759+
}
760+
750761
RefCntAutoPtr<ISampler> GPUTestingEnvironment::CreateSampler(const SamplerDesc& Desc)
751762
{
752763
RefCntAutoPtr<ISampler> pSampler;

0 commit comments

Comments
 (0)