VPP  0.7
A high-level modern C++ API for Vulkan
Public Member Functions | List of all members
vpp::ioBuffer Class Reference

Binding point class for storage (read-write) data buffer to shaders. Place in your pipeline configuration class to declare a storage data buffer. More...

#include <vppLangIntUniform.hpp>

Public Member Functions

 ioBuffer (std::uint32_t set=0, int binding=-1)
 Creates the binding point. More...
 
auto operator= (const UniformBufferView &value)
 Binds a buffer to the binding point. More...
 

Detailed Description

Binding point class for storage (read-write) data buffer to shaders. Place in your pipeline configuration class to declare a storage data buffer.

This class should be used only to define a binding point inside your custom pipeline configuration (a PipelineConfig or ComputePipelineConfig subclass).

There are the following steps to consider when using storage buffers within pipeline config:

Example:

// define data structure for the buffer
template< ETag TAG >
struct TMyBufferStructure : public UniformStruct< TAG, TMyBufferStructure >
{
UniformFld< TAG, glm::mat4 > m_matrixField;
UniformFld< TAG, glm::vec4 > m_vectorField;
// ...
};
// it is convenient to make these typedefs
typedef TMyBufferStructure< vpp::CPU > CMyBufferStructure;
typedef TMyBufferStructure< vpp::GPU > GMyBufferStructure;
class MyPipelineConfig : public vpp::PipelineConfig
{
// defines the binding point - assume it contains TMyBufferStructure entries
vpp::ioBuffer m_ioBuffer;
// another binding point - assume it contains simple array of floats
vpp::ioBuffer m_ioBuffer2;
void bindDataBuffers (
vpp::ShaderDataBlock* pDataBlock )
{
// Note that multiple bindings may occur simultaneously.
// Also note that we use double parentheses, because this is
// a list constructed with overloaded comma operator, not multiple
// arguments.
pDataBlock->update ((
m_ioBuffer = buf1,
m_ioBuffer2 = buf2
));
}
void fVertexShader ( vpp::VertexShader* pShader )
{
using namespace vpp;
// Accessing a buffer containing single structure.
varBuffer ( m_ioBuffer );
Mat4 m1 = varBuffer [ & GMyBufferStructure::m_matrixField ];
varBuffer [ & GMyBufferStructure::m_vectorField ] =
m1 * Vec4 { 1.0f, 2.0f, 3.0f, 4.0f };
// Accessing a buffer containing array of structures.
varBufferArr ( m_ioBuffer );
Int arrayIdx = ...; // compute array index
Mat4 m2 = varBufferArr [ arrayIdx ][ & GMyBufferStructure::m_matrixField ];
varBufferArr [ arrayIdx ][ & GMyBufferStructure::m_vectorField ] =
m2 * Vec4 { 1.0f, 2.0f, 3.0f, 4.0f };
// Accessing a buffer containing array of scalars.
varBufferSimpleArr ( m_ioBuffer2 );
Int arrayIdx = ...; // compute array index
Float fv = varBufferSimpleArr [ arrayIdx ];
varBufferSimpleArr [ arrayIdx ] = fv * 2.0f;
}
};

Constructor & Destructor Documentation

◆ ioBuffer()

vpp::ioBuffer::ioBuffer ( std::uint32_t  set = 0,
int  binding = -1 
)

Creates the binding point.

Typically you do not need to specify any arguments for the constructor.

Optionally you can force the set and binding index. This feature may be useful if you need to interface VPP binding point with externally supplied shader (written in GLSL and compiled externally to SPIR-V blob).

Member Function Documentation

◆ operator=()

auto vpp::ioBuffer::operator= ( const UniformBufferView value)

Binds a buffer to the binding point.

Accepts single argument which is generic buffer abstraction represented by UniformBufferView object. Usually just use gvector object in that place (it will be automatically cast to UniformBufferView). Alternatively, any Vulkan read-write uniform buffer bound to memory may be used.

Calling this operator does not bind the buffer immediately. It only generates an entry inside ShaderDataBlock. The operator returns an opaque value that must be supplied to ShaderDataBlock::update method. Several buffers can be bound at once. The binding will actually occur when the ShaderDataBlock is selected in the rendering pipeline.

Example:

class MyPipelineConfig : public vpp::PipelineConfig
{
vpp::ioBuffer m_ioBuffer;
vpp::ioBuffer m_ioBuffer2;
void bindDataBuffers (
vpp::ShaderDataBlock* pDataBlock )
{
// Note that multiple bindings may occur simultaneously.
// Also note that we use double parentheses, because this is
// a list constructed with overloaded comma operator, not multiple
// arguments.
pDataBlock->update ((
m_ioBuffer = buf1,
m_ioBuffer2 = buf2
));
}
};
// later, when defining a render graph (irrelevant details not shown):
void initializeRenderGraph ( ... )
{
// Here fill the data block.
m_myPipelineConfig.bindDataBuffers ( myBuffer0, myBuffer1, & m_dataBlock );
// m_render is a Process node
m_renderGraph.m_render << [ this ]()
{
// this lambda routine defines a rendering sequence (render pass)
// select current pipeline
m_renderPass.pipeline ( 0, 0 ).cmdBind();
// bind the data block
m_dataBlock.cmdBind();
m_renderGraph.cmdDraw ( ... );
// synchronize buffers with recipient
cmdBufferPipelineBarrier (
m_ioBuffer,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, // which shader writes
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // which shader reads
VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT
);
cmdBufferPipelineBarrier (
m_ioBuffer2,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT
);
// You can select a different block (or pipeline) now and draw again.
};
}

The documentation for this class was generated from the following file: