| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "IndirectRendering.azsli"
- #include <Atom/Features/IndirectRendering.azsli>
- #define ThreadBlockSize 128
- ShaderResourceGroupSemantic SRG_Frequency1
- {
- FrequencyId = 1;
- };
- ShaderResourceGroupSemantic SRG_Frequency2
- {
- FrequencyId = 2;
- };
- ShaderResourceGroupSemantic SRG_Frequency3
- {
- FrequencyId = 3;
- };
- ShaderResourceGroup CullSrg : SRG_Frequency1
- {
- float2 m_cullOffset; // The culling plane offset in homogenous space.
- uint m_inNumCommands;
- uint m_maxDrawIndirectCount;
- RWStructuredBuffer<uint> m_outNumCommands;
- };
- // This SRG contains the commands when using SequenceType::Draw option.
- ShaderResourceGroup IndirectDrawCommandsSrg : SRG_Frequency2
- {
- // Commands in one sequence
- struct IndirectCommandSequence
- {
- DrawIndexedIndirectCommand m_drawCommand;
- };
- StructuredBuffer<IndirectCommandSequence> m_inputCommands;
- RWStructuredBuffer<IndirectCommandSequence> m_outputCommands;
- // Copy a command from the input list or clear it's value to 0.
- void SetCommand(uint srcIndex, uint destIndex, bool clear = false)
- {
- if(clear)
- {
- m_outputCommands[destIndex] = (IndirectCommandSequence)0;
- }
- else
- {
- m_outputCommands[destIndex] = m_inputCommands[srcIndex];
- }
- }
- };
- // This SRG contains the commands when using SequenceType::IAInlineConstDraw option.
- ShaderResourceGroup IndirectIAInlineConstCommandsSrg : SRG_Frequency3
- {
- // Commands in one sequence
- struct IndirectCommandSequence
- {
- uint m_rootConstantsCommand;
- VertexViewIndirectCommand m_vertexCommand;
- IndexViewIndirectCommand m_indexCommand;
- DrawIndexedIndirectCommand m_drawCommand;
- };
- StructuredBuffer<IndirectCommandSequence> m_inputCommands;
- RWStructuredBuffer<IndirectCommandSequence> m_outputCommands;
- // Copy a command using from the input list or clear it's value to 0.
- void SetCommand(uint srcIndex, uint destIndex, bool clear = false)
- {
- if(clear)
- {
- m_outputCommands[destIndex] = (IndirectCommandSequence)0;
- }
- else
- {
- m_outputCommands[destIndex] = m_inputCommands[srcIndex];
- }
- }
- };
- option enum class SequenceType { Draw, IAInlineConstDraw} o_sequenceType = SequenceType::Draw;
- option bool o_countBufferSupported = false;
- [numthreads(ThreadBlockSize, 1, 1)]
- void MainCS(uint3 groupId : SV_GroupID, uint groupIndex : SV_GroupIndex)
- {
- // Each thread of the CS operates on one of the indirect commands.
- uint index = (groupId.x * ThreadBlockSize) + groupIndex;
- if(index < CullSrg::m_inNumCommands)
- {
- // We cull only in the X axis.
- // Calculate the left and right limits of the cull area.
- float4 left = mul(IndirectSceneSrg::m_matrix, float4(TransformInstancePos(float3(-1.0, 0, 0), IndirectSceneSrg::m_instancesData[index]), 1.0));
- left /= left.w;
- float4 right = mul(IndirectSceneSrg::m_matrix, float4(TransformInstancePos(float3(1.0, 0, 0), IndirectSceneSrg::m_instancesData[index]), 1.0));
- right /= right.w;
- uint outputIndex = index;
- bool setCommand = o_countBufferSupported ? false : true;
- bool clearCommand = true;
- // Check if we need to cull the primitive.
- if (CullSrg::m_cullOffset.x < right.x && left.x < CullSrg::m_cullOffset.y)
- {
- setCommand = true;
- clearCommand = false;
- // If count buffer is not supported, the output index is the same as the input index
- // and we just set the number of vertices to draw to 0 so no triangles are rendered.
- // If it is supported, the output index is calculated from the count buffer.
- if (o_countBufferSupported)
- {
- // The current value of the count buffer will be our output index. This value start with 0
- // and is increment by 1 after each thread writes a new command.
- // If multi indirect is not supported, then we need to divide the total draw calls in
- // multiple "groups". The count buffer will contain multiple values, one for each of these
- // groups, and we just apply an offset to the count buffer when submitting the indirect draw in CPU.
- uint i = 0;
- do
- {
- // Increment and retrieve the number atomically to get the output index.
- // If the value is over the allowed limit, we need to move to the next
- // "group". Since we already called InterlockedAdd (and incremented the value),
- // the count for the group will be greater than the allowed limit, but since the Indirect Draw
- // call on CPU will limit the max number of operations, it doesn't matter that the count
- // buffer value is over the limit.
- InterlockedAdd(CullSrg::m_outNumCommands[i++], uint(1), outputIndex);
- } while (outputIndex >= CullSrg::m_maxDrawIndirectCount);
- outputIndex = (i - 1) * CullSrg::m_maxDrawIndirectCount + outputIndex;
- }
- }
- if(setCommand)
- {
- // Copy or clear the output command
- switch(o_sequenceType)
- {
- case SequenceType::Draw:
- IndirectDrawCommandsSrg::SetCommand(index, outputIndex, clearCommand);
- break;
- case SequenceType::IAInlineConstDraw:
- IndirectIAInlineConstCommandsSrg::SetCommand(index, outputIndex, clearCommand);
- break;
- }
- }
- }
- }
|