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+
19302058TEST_F (DrawCommandTest, DrawIndexedInstancedIndirect_FirstInstance_BaseVertex_FirstIndex_VBOffset_IBOffset_InstOffset)
19312059{
19322060 GPUTestingEnvironment* const pEnv = GPUTestingEnvironment::GetInstance ();
0 commit comments