Skip to content

Commit 1c3ac22

Browse files
DrawCommandTest: added indirect draw test where args are written by compute shader
1 parent 2e8d4f1 commit 1c3ac22

File tree

2 files changed

+143
-15
lines changed

2 files changed

+143
-15
lines changed

Graphics/GraphicsEngine/include/BufferBase.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ class BufferBase : public DeviceObjectBase<typename EngineImplTraits::BufferInte
185185
IBufferView* pView = nullptr;
186186
CreateViewInternal(ViewDesc, &pView, true);
187187
VERIFY(pView != nullptr, "Failed to create default view for buffer '", this->m_Desc.Name, "'");
188-
VERIFY(pView->GetDesc().ViewType == ViewType, "Unexpected view type");
188+
VERIFY(pView == nullptr || pView->GetDesc().ViewType == ViewType, "Unexpected view type");
189189

190190
return static_cast<BufferViewImplType*>(pView);
191191
};

Tests/DiligentCoreAPITest/src/DrawCommandTest.cpp

Lines changed: 142 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2024 Diligent Graphics LLC
2+
* Copyright 2019-2025 Diligent Graphics LLC
33
* Copyright 2015-2019 Egor Yusov
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -400,6 +400,41 @@ void main(in VSInput VSIn,
400400
)"
401401
};
402402

403+
const std::string PrepareDrawArgsStructCS{
404+
R"(
405+
struct DrawArgs
406+
{
407+
uint NumVertices;
408+
uint NumInstances;
409+
uint StartVertexLocation;
410+
uint FirstInstanceLocation;
411+
};
412+
RWStructuredBuffer<DrawArgs> g_DrawArgsBuffer;
413+
414+
[numthreads(1, 1, 1)]
415+
void main()
416+
{
417+
// StartVertexLocation and FirstInstanceLocation are written on the CPU
418+
g_DrawArgsBuffer[1].NumVertices = 3;
419+
g_DrawArgsBuffer[1].NumInstances = 2;
420+
}
421+
)"
422+
};
423+
424+
const std::string PrepareDrawArgsFormattedCS{
425+
R"(
426+
RWBuffer<uint> g_DrawArgsBuffer;
427+
428+
[numthreads(1, 1, 1)]
429+
void main()
430+
{
431+
// StartVertexLocation and FirstInstanceLocation are written on the CPU
432+
g_DrawArgsBuffer[4] = 3;
433+
g_DrawArgsBuffer[5] = 2;
434+
}
435+
)"
436+
};
437+
403438
// clang-format on
404439

405440
} // namespace HLSL
@@ -811,6 +846,8 @@ class DrawCommandTest : public ::testing::Test
811846
USAGE BufferUsage,
812847
SHADER_VARIABLE_FLAGS VarFlags);
813848

849+
void TestDrawInstancedIndirect(bool UseCS);
850+
814851
static RefCntAutoPtr<IPipelineState> sm_pDrawProceduralPSO;
815852
static RefCntAutoPtr<IPipelineState> sm_pDrawPSO;
816853
static RefCntAutoPtr<IPipelineState> sm_pDraw_2xStride_PSO;
@@ -1874,7 +1911,15 @@ TEST_F(DrawCommandTest, DrawIndexedInstanced_FirstInstance_BaseVertex_FirstIndex
18741911

18751912
// Indirect draw calls
18761913

1877-
TEST_F(DrawCommandTest, DrawInstancedIndirect_FirstInstance_BaseVertex_FirstIndex_VBOffset_InstOffset)
1914+
struct IndirectDrawArgs
1915+
{
1916+
Uint32 NumVertices = 0;
1917+
Uint32 NumInstances = 0;
1918+
Uint32 StartVertexLocation = 0;
1919+
Uint32 FirstInstanceLocation = 0;
1920+
};
1921+
1922+
void DrawCommandTest::TestDrawInstancedIndirect(bool UseCS)
18781923
{
18791924
GPUTestingEnvironment* const pEnv = GPUTestingEnvironment::GetInstance();
18801925
IRenderDevice* const pDevice = pEnv->GetDevice();
@@ -1883,6 +1928,89 @@ TEST_F(DrawCommandTest, DrawInstancedIndirect_FirstInstance_BaseVertex_FirstInde
18831928

18841929
IDeviceContext* pContext = pEnv->GetDeviceContext();
18851930

1931+
constexpr Uint32 IndirectDrawData[] =
1932+
{
1933+
0, 0, 0, 0, // Offset
1934+
1935+
3, // NumVertices
1936+
2, // NumInstances
1937+
3, // StartVertexLocation
1938+
4 // FirstInstanceLocation
1939+
};
1940+
1941+
RefCntAutoPtr<IBuffer> pIndirectArgsBuff;
1942+
if (UseCS)
1943+
{
1944+
BufferDesc ArgsBuffDesc;
1945+
ArgsBuffDesc.Name = "Indirect draw args";
1946+
ArgsBuffDesc.BindFlags = BIND_INDIRECT_DRAW_ARGS | BIND_UNORDERED_ACCESS;
1947+
ArgsBuffDesc.Size = sizeof(IndirectDrawData);
1948+
if (pDevice->GetDeviceInfo().Type == RENDER_DEVICE_TYPE_D3D11)
1949+
{
1950+
ArgsBuffDesc.Mode = BUFFER_MODE_FORMATTED;
1951+
ArgsBuffDesc.ElementByteStride = sizeof(Uint32);
1952+
}
1953+
else
1954+
{
1955+
ArgsBuffDesc.Mode = BUFFER_MODE_STRUCTURED;
1956+
ArgsBuffDesc.ElementByteStride = sizeof(IndirectDrawArgs);
1957+
}
1958+
1959+
pDevice->CreateBuffer(ArgsBuffDesc, nullptr, &pIndirectArgsBuff);
1960+
ASSERT_TRUE(pIndirectArgsBuff);
1961+
RefCntAutoPtr<IBufferView> pIndirectArgsBuffUAV;
1962+
if (ArgsBuffDesc.Mode == BUFFER_MODE_STRUCTURED)
1963+
{
1964+
pIndirectArgsBuffUAV = pIndirectArgsBuff->GetDefaultView(BUFFER_VIEW_UNORDERED_ACCESS);
1965+
}
1966+
else
1967+
{
1968+
BufferViewDesc ViewDesc{"Indirect draw args UAV", BUFFER_VIEW_UNORDERED_ACCESS};
1969+
ViewDesc.Format = {VT_UINT32, 1};
1970+
pIndirectArgsBuff->CreateView(ViewDesc, &pIndirectArgsBuffUAV);
1971+
ASSERT_TRUE(pIndirectArgsBuffUAV);
1972+
}
1973+
1974+
// Write start vertex location and first instance location
1975+
pContext->UpdateBuffer(pIndirectArgsBuff, sizeof(Uint32) * 6, sizeof(Uint32) * 2, IndirectDrawData + 6, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
1976+
1977+
ShaderCreateInfo ShaderCI;
1978+
ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
1979+
ShaderCI.ShaderCompiler = pEnv->GetDefaultCompiler(ShaderCI.SourceLanguage);
1980+
1981+
RefCntAutoPtr<IShader> pCS;
1982+
{
1983+
ShaderCI.Desc = {"Indirect draw test CS", SHADER_TYPE_COMPUTE, true};
1984+
ShaderCI.EntryPoint = "main";
1985+
1986+
ShaderCI.Source = (ArgsBuffDesc.Mode == BUFFER_MODE_STRUCTURED) ?
1987+
HLSL::PrepareDrawArgsStructCS.c_str() :
1988+
HLSL::PrepareDrawArgsFormattedCS.c_str();
1989+
pDevice->CreateShader(ShaderCI, &pCS);
1990+
ASSERT_NE(pCS, nullptr);
1991+
}
1992+
1993+
ComputePipelineStateCreateInfo PSOCreateInfo{"Indirect draw test compute PSO"};
1994+
PSOCreateInfo.pCS = pCS;
1995+
PSOCreateInfo.PSODesc.ResourceLayout.DefaultVariableType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE;
1996+
RefCntAutoPtr<IPipelineState> pPSO;
1997+
pDevice->CreateComputePipelineState(PSOCreateInfo, &pPSO);
1998+
ASSERT_NE(pPSO, nullptr);
1999+
RefCntAutoPtr<IShaderResourceBinding> pSRB;
2000+
pPSO->CreateShaderResourceBinding(&pSRB, true);
2001+
ASSERT_NE(pSRB, nullptr);
2002+
2003+
pSRB->GetVariableByName(SHADER_TYPE_COMPUTE, "g_DrawArgsBuffer")->Set(pIndirectArgsBuffUAV);
2004+
pContext->SetPipelineState(pPSO);
2005+
pContext->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
2006+
// Write num vertices and num instances with compute shader
2007+
pContext->DispatchCompute({1, 1, 1});
2008+
}
2009+
else
2010+
{
2011+
pIndirectArgsBuff = CreateIndirectDrawArgsBuffer(IndirectDrawData, sizeof(IndirectDrawData));
2012+
}
2013+
18862014
SetRenderTargets(sm_pDrawInstancedPSO);
18872015

18882016
// clang-format off
@@ -1908,25 +2036,25 @@ TEST_F(DrawCommandTest, DrawInstancedIndirect_FirstInstance_BaseVertex_FirstInde
19082036
const Uint64 Offsets[] = {4 * sizeof(Vertex), 5 * sizeof(float4)};
19092037
pContext->SetVertexBuffers(0, _countof(pVBs), pVBs, Offsets, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, SET_VERTEX_BUFFERS_FLAG_RESET);
19102038

1911-
Uint32 IndirectDrawData[] =
1912-
{
1913-
0, 0, 0, 0, 0, // Offset
1914-
1915-
3, // NumVertices
1916-
2, // NumInstances
1917-
3, // StartVertexLocation
1918-
4 // FirstInstanceLocation
1919-
};
1920-
RefCntAutoPtr<IBuffer> pIndirectArgsBuff = CreateIndirectDrawArgsBuffer(IndirectDrawData, sizeof(IndirectDrawData));
1921-
19222039
DrawIndirectAttribs drawAttrs{pIndirectArgsBuff, DRAW_FLAG_VERIFY_ALL};
19232040
drawAttrs.AttribsBufferStateTransitionMode = RESOURCE_STATE_TRANSITION_MODE_TRANSITION;
1924-
drawAttrs.DrawArgsOffset = 5 * sizeof(Uint32);
2041+
drawAttrs.DrawArgsOffset = 4 * sizeof(Uint32);
19252042
pContext->DrawIndirect(drawAttrs);
19262043

19272044
Present();
19282045
}
19292046

2047+
TEST_F(DrawCommandTest, DrawInstancedIndirect_FirstInstance_BaseVertex_FirstIndex_VBOffset_InstOffset)
2048+
{
2049+
TestDrawInstancedIndirect(/*UseCS = */ false);
2050+
}
2051+
2052+
TEST_F(DrawCommandTest, DrawInstancedIndirect_FirstInstance_BaseVertex_FirstIndex_VBOffset_InstOffset_CS)
2053+
{
2054+
TestDrawInstancedIndirect(/*UseCS = */ true);
2055+
}
2056+
2057+
19302058
TEST_F(DrawCommandTest, DrawIndexedInstancedIndirect_FirstInstance_BaseVertex_FirstIndex_VBOffset_IBOffset_InstOffset)
19312059
{
19322060
GPUTestingEnvironment* const pEnv = GPUTestingEnvironment::GetInstance();

0 commit comments

Comments
 (0)