Describes indirect buffers and how to implement them on the Xbox One.
The following sections explain indirect buffers and how to implement them on the Xbox One dev kit:
For a more detailed example, see the RenderTechniques XDK sample. For more information on running the XDK samples, see Running the XDK Samples.
Indirect buffers function similarly to constant buffers in that they contain user specified information, for graphics purposes. Unlike constant buffers, an indirect buffer is a pointer to a contiguous block of allocated memory. You specify the size of the allocation, and you can write any data you like to the buffer using pointer arithmetic and standard memory management guidelines.
Indirect buffers are primarily used in deferred rendering, because the buffer can be accessed by any thread. You may need to implement a fence system to ensure that you arent simultaneously reading/writing to the buffer. Indirect buffers are also useful for reducing memory bandwidth because you only need to pass a single pointer.
Indirect buffers are created in a similar manner to traditional buffers. Use an ID3D11Buffer pointer to reference the buffer, and a D3D11_BUFFER_DESC for buffer details. The main difference between indirect buffers and traditional buffers is that indirect buffers must allocate a block of memory before creating the buffer.
Before creating the buffer, you will need to create a buffer description using D3D11_BUFFER_DESC. When initializing the buffer description, set MiscFlags to D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS. The ByteWidth value determines the size of the buffer in bytes.
Note The ByteWidth for an indirect buffer must be AT LEAST 12 bytes
C++
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = 0;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS;
bufferDesc.StructureByteStride = sizeof( DrawIndexedInstancesParams );
bufferDesc.ByteWidth = numberOfBuffers * sizeof( DrawIndexedInstancesParams );
You must allocate a block of memory for the indirect buffer. Call VirtualAlloc(), which functions very similarly to malloc() but with additional input specifications. VirtualAlloc returns a void* pointer to the new array.
Note Choosing an arbitrary size for your indirect buffer allows you to store additional data in the buffer. Be sure to account for this when setting the ByteStride value of the buffer description
C++
m_pIndirectBufferPlacementMemory = VirtualAlloc( nullptr, memorySizeAligned, MEM_LARGE_PAGES | MEM_GRAPHICS | MEM_RESERVE | MEM_COMMIT, PAGE_WRITECOMBINE | PAGE_READWRITE );
After the space has been allocated, you must create the indirect buffer with a call to ID3D11DeviceX::CreatePlacementBuffer(). CreatePlacementBuffer takes three parameters as input. The address of the ID3D11_BUFFER_DESC, the void* pointer returned by VirtualAlloc, and finally, the ID3D11Buffer pointer that you will use to reference this indirect buffer. CreatePlacementBuffer will return E_INVALID_ARG if the buffer description’s ByteWidth is less than 12 bytes.
C++
XSF_ERROR_IF_FAILED( pDev->CreatePlacementBuffer( &bufferDesc, m_pIndirectBufferPlacementMemory, m_spIndirectBuffer.ReleaseAndGetAddressOf() ) );
The indirect buffer functions like a traditional chunk of allocated memory. Use pointer arithmetic and typecasting to write any data you like to the buffer. If you are using indirect buffers in combination with threads (deferred rendering for example) you may want to implement a fence system to avoid simultaneous read/write errors.
If you rendering to multiple D3D11_STAGEs or need to use a different constant buffer slot, call ID3D11DeviceContextX::RemapConstantBufferInheritance().
C++
pCtx->RemapConstantBufferInheritance( D3D11_STAGE_PS, 0, D3D11_STAGE_PS, 1 );
Use ID3D11DeviceContext::DrawIndexedInstancedIndirect() to render indexed primitives. To render non-indexed primitives, call ID3D11DeviceContext::DrawInstancedIndirect()
C++
pCtx->DrawIndexedInstancedIndirect( pIndirectBuffer, bufferOffsetBytes );