SPARK  0.1.0
A general purpose game engine written in C++.
Loading...
Searching...
No Matches
spark::render::DescriptorSet< BufferType, ImageType, SamplerType > Class Template Referenceabstract

Defines a set of descriptors. More...

#include <DescriptorSet.h>

Inheritance diagram for spark::render::DescriptorSet< BufferType, ImageType, SamplerType >:
spark::render::IDescriptorSet

Public Types

using buffer_type = BufferType
 
using image_type = ImageType
 
using sampler_type = SamplerType
 

Public Member Functions

virtual void update (unsigned int binding, const buffer_type &buffer, unsigned int buffer_element=0, unsigned int elements=0, unsigned int first_descriptor=0) const =0
 Updates a constant buffer within the IDescriptorSet.
 
virtual void update (unsigned int binding, const image_type &texture, unsigned int descriptor=0, unsigned int first_level=0, unsigned int levels=0, unsigned int first_layer=0, unsigned int layers=0) const =0
 Updates a constant buffer within the IDescriptorSet.
 
virtual void update (unsigned int binding, const sampler_type &sampler, unsigned int descriptor=0) const =0
 Updates a constant buffer within the IDescriptorSet.
 
virtual void attach (unsigned int binding, const image_type &image) const =0
 Attaches an image as an input attachment to a descriptor bound at binding.
 
- Public Member Functions inherited from spark::render::IDescriptorSet
void update (unsigned int binding, const IBuffer &buffer, unsigned int buffer_element=0, unsigned int elements=0, unsigned int first_descriptor=0) const
 Updates a constant buffer within the IDescriptorSet.
 
void update (unsigned int binding, const IImage &texture, unsigned int descriptor=0, unsigned int first_level=0, unsigned int levels=0, unsigned int first_layer=0, unsigned int layers=0) const
 Updates a texture within the current descriptor set.
 
void update (unsigned int binding, const ISampler &sampler, unsigned int descriptor=0) const
 Updates a sampler within the current descriptor set.
 
void attach (unsigned int binding, const IImage &image) const
 Attaches an image as an input attachment to a descriptor bound at binding.
 

Detailed Description

template<typename BufferType, typename ImageType, typename SamplerType>
class spark::render::DescriptorSet< BufferType, ImageType, SamplerType >

Defines a set of descriptors.

Template Parameters
BufferTypeThe type of the buffer interface. (inherits from IBuffer)
ImageTypeThe type of the image interface. (inherits from IImage)
SamplerTypeThe type of the sampler interface. (inherits from ISampler)

Descriptors can be grouped into multiple descriptor sets. It is generally a good practice to group descriptors based on the frequency of the updates they receive. For example, it typically makes sense to store the camera buffer in a descriptor set, since it only needs to be updated once per frame for each camera, whilst the object or material data should be stored in separate descriptor sets, that are possibly updated before each draw call.

From a shader perspective, a descriptor set is identified by a set (GLSL) or space (HLSL), whilst a descriptor is addressed by a binding (GLSL) or register (HLSL). Descriptor sets are read from GPU-visible memory, depending on how they are bound during the current draw call.

From a CPU perspective, think of a descriptor set as an array of pointers to different buffers (i.e. descriptors) for the shader. A descriptor can be bound to a set by calling IDescriptorSet::update(). Note that this does not automatically ensure, that the buffer memory is visible for the GPU. Instead, a buffer may also require a transfer into GPU visible memory, depending on the BufferUsage. However, as long as a descriptor within a set is mapped to a buffer, modifying this buffer also reflects the change to the shader, without requiring to update the descriptor, similarly to how modifying the object behind a pointer does not require the pointer to change.

Note, that there might be multiple descriptor set instances of the same DescriptorSetLayout, pointing to different IBuffer instances, depending on the number of frames in flight. Since multiple frames can be computed concurrently, it is important to properly synchronize descriptor set updates.

Generally, there are three strategies to choose from, that you can implement or mix in custom flavors, depending on your use case:

  • Naive: The naive approach most closely matches earlier graphics API concepts. Create one buffer per descriptor and synchronize frames. This basically means that each back buffer swap is synchronized to wait for the graphics pipeline. This way, writing to a buffer ensures, that it is only read within the frame of reference and modifying it does not interfere with other frames. This strategy is memory efficient, but may cause the GPU to stall. It may, however be a valid strategy, for data that is only written once or very infrequently.
  • Array of Buffers: The helper methods for creating and updating constant buffers are able to create buffer arrays. Those arrays can be used to create a buffer for each frame in flight. When binding a buffer to a descriptor, it is possible to bind only one element of the array. This way, each frame has its own buffer and does not interfere with other buffer writes.
  • Ring-Buffer: The most efficient (yet not always applicable) approach involves creating one large buffer array, that is bound to multiple descriptor sets. This ensures that the buffer memory stays contiguous and does not get fragmented. However, this requires to know upfront, how many buffers are required for each descriptor, which might not always be possible. Thus another flavor of using this technique involves a creating a large enough descriptor array and updating the descriptor set with an increasing array element for each object as a ring-buffer. As long as there are enough elements in the buffer, so that no second update interferes with a buffer write in an earlier frame, this method provides the most efficient approach. However, it may be hard or impossible to determine the ideal size of the ring-buffer upfront.

Note that samplers, textures and input attachments currently do not support array binding, since they are typically only updated once or require pipeline synchronization anyway.

Member Function Documentation

◆ attach()

template<typename BufferType , typename ImageType , typename SamplerType >
virtual void spark::render::DescriptorSet< BufferType, ImageType, SamplerType >::attach ( unsigned int binding,
const image_type & image ) const
pure virtual

Attaches an image as an input attachment to a descriptor bound at binding.

Parameters
bindingThe input attachment binding point.
imageThe image to bind to the input attachment descriptor.

◆ update() [1/3]

template<typename BufferType , typename ImageType , typename SamplerType >
virtual void spark::render::DescriptorSet< BufferType, ImageType, SamplerType >::update ( unsigned int binding,
const buffer_type & buffer,
unsigned int buffer_element = 0,
unsigned int elements = 0,
unsigned int first_descriptor = 0 ) const
pure virtual

Updates a constant buffer within the IDescriptorSet.

Parameters
bindingThe buffer binding point.
bufferThe constant buffer to write to the IDescriptorSet.
buffer_elementThe index of the first element to write to the IDescriptorSet.
elementsThe number of elements to write to the IDescriptorSet, or 0 to write all elements starting from buffer_element.
first_descriptorThe index of the first descriptor in the descriptor array to update.

◆ update() [2/3]

template<typename BufferType , typename ImageType , typename SamplerType >
virtual void spark::render::DescriptorSet< BufferType, ImageType, SamplerType >::update ( unsigned int binding,
const image_type & texture,
unsigned int descriptor = 0,
unsigned int first_level = 0,
unsigned int levels = 0,
unsigned int first_layer = 0,
unsigned int layers = 0 ) const
pure virtual

Updates a constant buffer within the IDescriptorSet.

Parameters
bindingThe buffer binding point.
bufferThe constant buffer to write to the IDescriptorSet.
buffer_elementThe index of the first element to write to the IDescriptorSet.
elementsThe number of elements to write to the IDescriptorSet, or 0 to write all elements starting from buffer_element.
first_descriptorThe index of the first descriptor in the descriptor array to update.

◆ update() [3/3]

template<typename BufferType , typename ImageType , typename SamplerType >
virtual void spark::render::DescriptorSet< BufferType, ImageType, SamplerType >::update ( unsigned int binding,
const sampler_type & sampler,
unsigned int descriptor = 0 ) const
pure virtual

Updates a constant buffer within the IDescriptorSet.

Parameters
bindingThe buffer binding point.
bufferThe constant buffer to write to the IDescriptorSet.
buffer_elementThe index of the first element to write to the IDescriptorSet.
elementsThe number of elements to write to the IDescriptorSet, or 0 to write all elements starting from buffer_element.
first_descriptorThe index of the first descriptor in the descriptor array to update.