ID3D12GraphicsCommandList::SetupOrderedAppendCounterX Method

Sets up an ordered append counter, enabling shader threads to append data in order of their launch. See Remarks for an example.

Syntax

public:
void SetupOrderedAppendCounterX(
         UINT CounterIndex,
         UINT RingBufferAvailableSpace,
         UINT GdsAddressOfTheCounterDwords,
         D3D12XBOX_ORDERED_APPEND_SHADER_STAGE ShaderStage,
         UINT Enable,
         UINT ReservedSetTo0
)  

Parameters

CounterIndex
Type: UINT 

[in] One of the eight hardware OA counters to associate with a Global Data Share (GDS) location.

RingBufferAvailableSpace
Type: UINT 

[in] The size for the WRAP operation of the counter.

GdsAddressOfTheCounterDwords
Type: UINT 

[in] The offset from the base 0 of GDS memory with which to associate the hardware OA counter.

ShaderStage
Type: D3D12XBOX_ORDERED_APPEND_SHADER_STAGE 

[in] The shader stage, as a D3D12XBOX_ORDERED_APPEND_SHADER_STAGE enumeration constant. Only the Compute Shader is currently supported; don’t use the other enumeration constants.

Enable
Type: UINT 

[in] Whether to enable this counter or to disable it.

ReservedSetTo0
Type: UINT 

[in] This parameter is reserved; set it to zero.

Return value

None.

Remarks

Ordered Append is a hardware feature of Xbox One akin to D3D AppendBuffer. Ordered Append allows shader threads to append data in order of their launch. It works by associating a DWORD in GDS with one of the eight hardware Ordered Append counters. In the shader, this functionality is triggered by using the __XB_GdsOrderedCount intrinsic; __XB_GdsOrderedCount implements the ds_ordered_count instruction in the shader to support Ordered Append.

The following is an example of a shader that compacts write indices and performs a write into an append buffer using Ordered Append.

After running this sample, the values in “osb” buffer will be scrambled, and the values in “asb” buffer will be ordered.

AppendStructuredBuffer<uint>
asb : register(u1);
RWByteAddressBuffer          osb : register(u0);

#define OA_WVGLAG_NONE      0
#define OA_WVFLAG_RELEASE   1
#define OA_WVFLAG_DONE      2

#define OA_COUNTER_OP_ADD           0
#define OA_COUNTER_OP_EXCHANGE      1
#define OA_COUNTER_OP_CONDXCHG32    2
#define OA_COUNTER_OP_WRAP          3

uint __ConstructOAFlags(
uint gdsOffsetInDwords,
uint oaWaveFlag,
uint oaCounterOp)
{
    // Hidden parameter -- top 16 bits can specify byte offset into GDS

    return (((gdsOffsetInDwords  & 0x3f) << 0) |
            ((oaWaveFlag         & 0x03) << 8) |
            ((oaCounterOp        & 0x03) << 10)) << 16;
}

[RootSignature("DescriptorTable(UAV(u0, numDescriptors=2), visibility=SHADER_VISIBILITY_ALL)")]
[numthreads(8, 8, 1)]
void main(uint3 dtid   : SV_DispatchThreadID)
{
    uint v = (dtid.x & 0xffff) + ((dtid.y & 0xffff) << 16);

    // Ordered append

    // Find how many live threads there are
    uint collapsedThreadIds = __XB_MBCNT64(uint2(0xffffffff, 0xffffffff));
    uint numLiveThreads = __XB_S_BCNT1_U64(__XB_Ballot64(true));

    // Always needs to be issued, to prevent GPU hang
    // The CPU needs to configure the counter and call DispatchX
    uint appendBase = __XB_GdsOrderedCount(
        numLiveThreads,
        __ConstructOAFlags(0x00, OA_WVFLAG_DONE, OA_COUNTER_OP_ADD));

    asb.Append(v);

    // It's ok to skip the write
    if (numLiveThreads)
    {
        uint addr = 4 * (appendBase + collapsedThreadIds);
        osb.Store(addr, v);
    }
}  

Below is the code-side setup required. To store the counter, this example uses the GDS slot with offset 0.

UINT zero = 0;
pCmdList->WriteGDSX(0, 1, &zero, D3D12XBOX_GDS_OPERATION_DEFAULT);
pCmdList->SetupOrderedAppendCounterX(0, 1024, 0, D3D12XBOX_ORDERED_APPEND_SHADER_STAGE_CS, 1, 0);
pCmdList->SetComputeRootSignature(m_pRS);
pCmdList->SetPipelineState(m_pPSO);
pCmdList->SetComputeRootDescriptorTable(0, m_uavDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
pCmdList->DispatchX(2, 1, 1, D3D12XBOX_DISPATCH_FLAG_FORCE_START_AT_000 |
                             D3D12XBOX_DISPATCH_FLAG_ENABLE_ORDERED_APPEND);
pCmdList->Close();  

Requirements

Header: Declared in d3d12_x.h.

Library: Use d3d12_x.lib.

See also

Reference

ID3D12GraphicsCommandList Interface

ID3D12GraphicsCommandList Members