Buffers

  • _ua_ -> allows UAV access (default is formatted/sampled view)

  • _sr_ -> allows SRV access (default is formatted/sampled view)

  • _cb -> allows const buffer access

  • _one_frame_ -> for cb to indicate this buffer contents is only valid this frame after a discard write

  • _persistent_ -> for cb counter part to _one_frame_, buffer holds its contents until changed

  • _byte_address -> for ua and sr to indicate byte address view

  • _structured -> for ua and sr to indicate structured view

  • _readback -> buffer is used for read back

  • _indirect -> buffer can be an indirect argument

  • _staging -> staging buffer

class Sbuffer : public D3dResource, public ResourceChecker

The Sbuffer class represents a buffer used for 3D rendering.

This class is derived from the D3dResource class and provides functionality for locking and unlocking the buffer, retrieving buffer information, and updating buffer data. It represents all possible buffer types in the engine.

Public Functions

inline virtual bool setReloadCallback(IReloadData*)

Set the Reload Callback object for the buffer.

Returns:

true if the callback was successfully set, false otherwise

inline virtual int restype() const final override

Returns the type of the D3dResource. It is always RES3D_SBUF for Sbuffer objects.

Todo:

make RES3D_ a enum class.

Returns:

int RES3D_SBUF.

virtual int lock(uint32_t ofs_bytes, uint32_t size_bytes, void **p, int flags) = 0

Locks a portion of the buffer for reading or writing.

Warning

It is better to use lock_sbuffer method for more safety.

Parameters:
  • ofs_bytes – The offset in bytes from the beginning of the buffer.

  • size_bytes – The size in bytes of the portion to lock. The whole buffer will be locked if 0.

  • p – A pointer to a void pointer that will receive the locked memory address.

  • flags – Additional flags to control the locking behavior.

Returns:

An integer representing the result of the lock operation. 0 if the lock failed, 1 if the lock succeeded.

virtual int unlock() = 0

Unlocks the buffer after it has been locked.

Returns:

An integer representing the result of the unlock operation. 0 if the unlock failed, 1 if the unlock succeeded.

virtual int getFlags() const = 0

Get the Flags object.

Returns:

Flags that control the buffer behavior and was set on a buffer creation.

inline const char *getBufName() const

Get the Buffer name.

Returns:

The name of the buffer.

inline virtual int getElementSize() const

Get the size of the structured buffer element.

This method works only for structured buffers.

Returns:

The size of the buffer element.

inline virtual int getNumElements() const

Get the amount of elements in the structured buffer.

This method works only for structured buffers.

Returns:

int amount of elements in the buffer.

inline virtual bool copyTo(Sbuffer *dest)

Copy current buffer to another buffer. The sizes of the buffers should match exactly.

Parameters:

dest – The destination buffer.

Returns:

true if the buffer was successfully copied, false otherwise.

inline virtual bool copyTo(Sbuffer *dest, uint32_t dst_ofs_bytes, uint32_t src_ofs_bytes, uint32_t size_bytes)

Copy a portion of the buffer to another buffer. Both buffers must be large enough for the copied portion offset and size.

Parameters:
  • dest – The destination buffer.

  • dst_ofs_bytes – The offset in bytes from the beginning of the destination buffer.

  • src_ofs_bytes – The offset in bytes from the beginning of the source buffer.

  • size_bytes – The size in bytes of the portion to copy.

Returns:

true if the buffer was successfully copied, false otherwise.

template<typename T>
inline int lockEx(uint32_t ofs_bytes, uint32_t size_bytes, T **p, int flags)

Locks a portion of the buffer for reading or writing.

Warning

It is better to use lock_sbuffer method for more safety.

Template Parameters:

T – type of the data to lock

Parameters:
  • ofs_bytes – offset in bytes from the beginning of the buffer

  • size_bytes – size in bytes of the portion to lock

  • p – pointer to a pointer that will receive the locked memory address

  • flags – additional flags to control the locking behavior VBLOCK_*

Returns:

int 0 if the lock failed, 1 if the lock succeeded

inline bool updateDataWithLock(uint32_t ofs_bytes, uint32_t size_bytes, const void *src, int lockFlags)

Updates buffer content with the specified data using lock/memcpy/unlock.

Parameters:
  • ofs_bytes – offset in bytes from the beginning of the buffer

  • size_bytes – size in bytes of the portion to update. Must be non-zero.

  • src – pointer to the source data

  • lockFlags – additional flags to control the locking behavior VBLOCK_*

Returns:

true if the buffer was successfully updated, false otherwise

inline virtual bool updateData(uint32_t ofs_bytes, uint32_t size_bytes, const void *src, uint32_t lockFlags)

Updates buffer content with the specified data using lock/memcpy/unlock.

Parameters:
  • ofs_bytes – offset in bytes from the beginning of the buffer

  • size_bytes – size in bytes of the portion to update. Must be non-zero.

  • src – pointer to the source data

  • lockFlags – additional flags to control the locking behavior VBLOCK_*

Returns:

true if the buffer was successfully updated, false otherwise

inline int lock(uint32_t ofs_bytes, uint32_t size_bytes, uint16_t **p, int flags)

Lock method specified for index buffer with 16-bit indices.

Parameters:
  • ofs_bytes – offset in bytes from the beginning of the buffer

  • size_bytes – size in bytes of the portion to lock

  • p – pointer to a pointer that will receive the locked memory address

  • flags – additional flags to control the locking behavior VBLOCK_*

Returns:

int 0 if the lock failed, 1 if the lock succeeded

inline int lock32(uint32_t ofs_bytes, uint32_t size_bytes, uint32_t **p, int flags)

Lock method specified for index buffer with 32-bit indices.

Parameters:
  • ofs_bytes – offset in bytes from the beginning of the buffer

  • size_bytes – size in bytes of the portion to lock

  • p – pointer to a pointer that will receive the locked memory address

  • flags – additional flags to control the locking behavior VBLOCK_*

Returns:

int 0 if the lock failed, 1 if the lock succeeded

Protected Functions

inline ~Sbuffer() override
struct IReloadData

Interface for a callback that is called when the buffer is restored after device reset.

Public Functions

inline virtual ~IReloadData()
virtual void reloadD3dRes(Sbuffer *sb) = 0

Reloads content of the buffer.

Parameters:

sb – The buffer to fill.

virtual void destroySelf() = 0

Destroys the callback object. Will be called on a buffer destruction.

namespace d3d

Functions

Sbuffer *create_sbuffer(int struct_size, int elements, unsigned flags, unsigned texfmt, const char *name)

Creates a buffer with the specified parameters.

The buffer can be used for various purposes, such as constant buffers, structured buffers, byte address buffers, and more. It is an uber method, and not all combinations of parameters are valid. Use d3d::buffers namespace for more specific buffer creation methods.

Parameters:
  • struct_size – The size of each structure in the buffer.

  • elements – The number of elements in the buffer.

  • flags – Additional flags for the buffer.

  • texfmt – The texture format for tBuffers.

  • name – The name of the buffer.

Returns:

A pointer to the created buffer.

bool set_buffer(unsigned shader_stage, unsigned slot, Sbuffer *buffer)

Sets an Sbuffer for a specific shader stage and slot.

Parameters:
  • shader_stage – The shader stage to set the buffer for. One of STAGE_ values.

  • slot – The slot to bind the buffer to.

  • buffer – A pointer to the Sbuffer to set.

Returns:

True if the buffer was successfully set, false otherwise.

bool set_rwbuffer(unsigned shader_stage, unsigned slot, Sbuffer *buffer)

Sets a read-write Sbuffer for a specific shader stage and slot.

Parameters:
  • shader_stage – The shader stage to set the buffer for. One of STAGE_ values.

  • slot – The slot to bind the buffer to.

  • buffer – A pointer to the Sbuffer to set.

Returns:

True if the buffer was successfully set, false otherwise.

namespace buffers

Enums

enum class Init : uint32_t

Enumeration for buffer initialization options. Not all buffer types currently support it.

Values:

enumerator No

We don’t know anything about buffer content on creation.

enumerator Zero

A resource guaranteed to be zeroed on the first usage.

enum class Indirect : uint32_t

The Indirect enum represents different GPU indirect buffer types.

Values:

enumerator Dispatch
enumerator Draw
enumerator DrawIndexed

Functions

template<typename T>
inline uint32_t cb_array_reg_count(uint32_t array_size)

Calculate the number of register (in const buffer term) count for a given array size of type T. Structure must be aligned as float4 to not have problems with alignment in cbuffer.

Template Parameters:

T – The type of the array elements.

Parameters:

array_size – The size of the array.

Returns:

The registers count.

template<typename T>
inline uint32_t cb_struct_reg_count()

Calculate the number of register (in const buffer term) count for a single instance of a type T. Structure must be aligned as float4 to not have problems with alignment in cbuffer.

Template Parameters:

T – The type of the structure.

Returns:

The registers count.

inline Sbuffer *create_persistent_cb(uint32_t registers_count, const char *name)

Create a persistent constant buffer.

Such buffers could be updated from time to time. It is recommended to use cb_array_reg_count and cb_struct_reg_count methods to calculate registers_count.

Warning

This buffer will not be restored after device reset!

Parameters:
  • registers_count – The number of registers in the buffer. Must be not bigger than 4096.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

Created persistent constant buffer.

inline Sbuffer *create_one_frame_cb(uint32_t registers_count, const char *name)

Create an one frame constant buffer.

Such buffers must be updated every frame (you can skip update if the buffer is not used this frame). Because of that we don’t care about its content on device reset. It is recommended to use cb_array_reg_count and cb_struct_reg_count methods to calculate registers_count.

Parameters:
  • registers_count – The number of registers. Must be not bigger than 4096.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

  • buffer_init – The initialization option for the buffer.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_ua_sr_byte_address(uint32_t size_in_dwords, const char *name, Init buffer_init = Init::No)

Create a byte address buffer, which can be used thorugh an unordered access view or through a shader resource view in shaders. In a shader you can declare the buffer using (RW)ByteAddressBuffer. Such a buffer is always 16-byte aligned.

Todo:

Use registers instead of dwords for size because of alignment.

Parameters:
  • size_in_dwords – The size of the buffer in dwords.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

  • buffer_init – The initialization option for the buffer.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_ua_sr_structured(uint32_t structure_size, uint32_t elements_count, const char *name, Init buffer_init = Init::No)

Create a structured buffer, which can be used thorugh an unordered access view or through a shader resource view in shaders. In a shader you can declare the buffer using (RW)StructuredBuffer<StructureType>. StructureType is a kind of template parameter here.

Parameters:
  • structure_size – The size of the structure of the buffer elements. Usually it is a sizeof(StructureType).

  • elements_count – The number of elements in the buffer.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

  • buffer_init – The initialization option for the buffer.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_ua_byte_address(uint32_t size_in_dwords, const char *name)

Create a byte address buffer, which can be used thorugh an unordered access view in shaders. In a shader you can declare the buffer using RWByteAddressBuffer. Such a buffer is always 16-byte aligned.

Todo:

Use registers instead of dwords for size because of alignment.

Parameters:
  • size_in_dwords – The size of the buffer in dwords.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_ua_structured(uint32_t structure_size, uint32_t elements_count, const char *name)

Create a structured buffer, which can be used thorugh an unordered access view in shaders. In a shader you can declare the buffer using RWStructuredBuffer<StructureType>. StructureType is a kind of template parameter here.

Parameters:
  • structure_size – The size of the structure of the buffer elements. Usually it is a sizeof(StructureType).

  • elements_count – The number of elements in the buffer.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_ua_byte_address_readback(uint32_t size_in_dwords, const char *name, Init buffer_init = Init::No)

The same as create_ua_byte_address but its content can be read on CPU. Such a buffer is always 16-byte aligned.

Todo:

Use registers instead of dwords for size because of alignment.

Parameters:
  • size_in_dwords – The size of the buffer in dwords.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

  • buffer_init – The initialization option for the buffer.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_ua_structured_readback(uint32_t structure_size, uint32_t elements_count, const char *name, Init buffer_init = Init::No)

The same as create_ua_structured but its content can be read on CPU.

Parameters:
  • structure_size – The size of the structure of the buffer elements. Usually it is a sizeof(StructureType).

  • elements_count – The number of elements in the buffer.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

  • buffer_init – The initialization option for the buffer.

Returns:

A pointer to the created buffer.

inline uint32_t dword_count_per_call(Indirect indirect_type)

Returns the amount of dwords per indirect command parameters based on the given indirect buffer type.

Parameters:

indirect_type – The type of indirect operation (Dispatch, Draw, or DrawIndexed).

Returns:

The amount of dwords per indirect command parameters.

inline Sbuffer *create_ua_indirect(Indirect indirect_type, uint32_t records_count, const char *name)

Creates an indirect buffer filled by the GPU.

Parameters:
  • indirect_type – The type of the indirect commands stored in the buffer.

  • records_count – The number of indirect records in the buffer.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_indirect(Indirect indirect_type, uint32_t records_count, const char *name)

Creates an indirect buffer filled by the CPU.

Parameters:
  • indirect_type – The type of the indirect commands stored in the buffer.

  • records_count – The number of indirect records in the buffer.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_staging(uint32_t size_in_bytes, const char *name)

Creates a buffer for data transfer from CPU to GPU.

Parameters:
  • size_in_bytes – The size of the buffer in bytes.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_persistent_sr_tbuf(uint32_t elements_count, uint32_t format, const char *name, Init buffer_init = Init::No)

Create a t-buffer, which can be used through a shader resource view in shaders. In a shader you can declare the buffer using Buffer<BufferFormat>. BufferFormat is a kind of template parameter here.

The total size of the buffer is sizeof(format) * elements_count.

It is a persistent buffer, so you can update it with VBLOCK_WRITEONLY flag. Locked part of the buffer content will be overwritten.

Warning

The buffer type can be used only for the code which will be used for DX10 compatible hardware.

Parameters:
  • elements_count – The number of elements in the buffer.

  • format – The format of each element in the buffer. It must be a valid texture format. Not all texture formats are allowed.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

  • buffer_init – The initialization option for the buffer.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_persistent_sr_byte_address(uint32_t size_in_dwords, const char *name, Init buffer_init = Init::No)

Create a byte address buffer, which can be used through a shader resource view in shaders. In a shader you can declare the buffer using ByteAddressBuffer.

It is a persistent buffer, so you can update it with VBLOCK_WRITEONLY flag. Locked part of the buffer content will be overwritten.

Parameters:
  • size_in_dwords – The size of the buffer in dwords.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

  • buffer_init – The initialization option for the buffer.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_persistent_sr_structured(uint32_t structure_size, uint32_t elements_count, const char *name, Init buffer_init = Init::No)

Create a structured buffer, which can be used through a shader resource view in shaders. In a shader you can declare the buffer using StructuredBuffer<StructureType>. StructureType is a kind of template parameter here.

It is a persistent buffer, so you can update it with VBLOCK_WRITEONLY flag. Locked part of the buffer content will be overwritten.

Declare StructureType in *.hlsli file and include it both in C++ and shader code.

Parameters:
  • structure_size – The size of the structure of the buffer elements. Usually it is a sizeof(StructureType).

  • elements_count – The number of elements in the buffer.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

  • buffer_init – The initialization option for the buffer.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_one_frame_sr_tbuf(uint32_t elements_count, uint32_t format, const char *name)

Create a t-buffer, which can be used through a shader resource view in shaders. In a shader you can declare the buffer using Buffer<BufferFormat>. BufferFormat is a kind of template parameter here.

The total size of the buffer is sizeof(format) * elements_count. To use the buffer, lock it with VBLOCK_DISCARD flag (and with VBLOCK_NOOVERWRITE during the frame) and fill it on CPU. On the next frame data in the buffer could be invalid, so don’t read from it until you fill it with lock again.

Warning

The buffer type can be used only for the code which will be used for DX10 compatible hardware.

Parameters:
  • elements_count – The number of elements in the buffer.

  • format – The format of each element in the buffer. It must be a valid texture format. Not all texture formats are allowed.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_one_frame_sr_byte_address(uint32_t size_in_dwords, const char *name)

Create a byte address buffer, which can be used through a shader resource view in shaders. In a shader you can declare the buffer using ByteAddressBuffer.

To use the buffer, lock it with VBLOCK_DISCARD flag (and with VBLOCK_NOOVERWRITE during the frame) and fill it on CPU. On the next frame data in the buffer could be invalid, so don’t read from it until you fill it with lock again.

Parameters:
  • size_in_dwords – The size of the buffer in dwords.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_one_frame_sr_structured(uint32_t structure_size, uint32_t elements_count, const char *name)

Create a structured buffer, which can be used through a shader resource view in shaders. In a shader you can declare the buffer using StructuredBuffer<StructureType>. StructureType is a kind of template parameter here.

To use the buffer, lock it with VBLOCK_DISCARD flag (and with VBLOCK_NOOVERWRITE during the frame) and fill it on CPU. On the next frame data in the buffer could be invalid, so don’t read from it until you fill it with lock again.

Declare StructureType in *.hlsli file and include it both in C++ and shader code.

Parameters:
  • structure_size – The size of the structure of the buffer elements. Usually it is a sizeof(StructureType).

  • elements_count – The number of elements in the buffer.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

A pointer to the created buffer.

inline Sbuffer *create_raytrace_scratch_buffer(uint32_t size_in_bytes, const char *name)

Creates a buffer to be used as scratch space for bottom acceleration structure builds and updates. This buffer is used as input for ::raytrace::BottomAccelerationStructureBuildInfo::scratchSpaceBuffer which is used by d3d::build_bottom_acceleration_structure.

This buffer is not meant to be accessed in any other way than to be used as a this scratch buffer, as it is used as temporary storage for the on GPU build and update process of bottom acceleration structure and its contents is highly device and device driver specific and can’t be used for anything else anyway.

Sizes needed are provided by the d3d::create_raytrace_bottom_acceleration_structure function.

Parameters:
  • size_in_bytes – The size in bytes of the scratch buffer.

  • name – The name of the buffer, used for debugging purposes, like showing in in statistcs, and frame debuggers like PIX.

Returns:

A pointer to the created buffer. Returns nullptr on failure. Possible failures are device lost state or out of memory.

Variables

constexpr uint32_t CBUFFER_REGISTER_SIZE = 16

The size of the cbuffer register. It should have a size divisible by sizeof(float4), because the cbuffer is a set of float4 registers.

constexpr uint32_t BYTE_ADDRESS_ELEMENT_SIZE = sizeof(uint32_t)

The size of an element of a byte address buffer.