Using TZGLP's SSBO Module - harrand/Topaz-2 GitHub Wiki
Consider the following vertex-shader for a total of three vertices (to render a simple triangle):
#version 430
layout(std430, binding = 0) buffer position_data
{
float positions[9];
};
void main()
{
gl_Position = vec4(positions[gl_VertexID*3], positions[(gl_VertexID*3) + 1], positions[(gl_VertexID*3) + 2], 1.0);
}
On the C++ side, you must do the following:
- Add an SSBO to an existing
tz::gl::Object
and provide a binding ID to the SSBO. This id must be the same as the binding in the shader. - Doing this naively means that this is likely to be hard-coded.
- Hard-coding IDs like this is a nightmare for maintenance.
Luckily, TZGLP (tz::gl::ShaderPreprocessor
) has a bespoke module specifically to ease this annoyance. Using this module provides access to a new preprocessor-directive in shader component source-code: #ssbo
.
The vertex-shader is now:
#version 430
#ssbo position_data
{
float positions[9];
};
void main()
{
gl_Position = vec4(positions[gl_VertexID*3], positions[(gl_VertexID*3) + 1], positions[(gl_VertexID*3) + 2], 1.0);
}
The binding ID will be automatically generated by the TZGLP module. You can access it by obtaining a pointer to the module via the ShaderPreprocessor.
Note: This demo already exists in the repository and you can easily run this by cloning Topaz-2 and building the target called 'topaz_ssbo_tzglp_demo'
#include "core/core.hpp"
#include "core/debug/print.hpp"
#include "gl/shader.hpp"
#include "gl/shader_preprocessor.hpp"
#include "gl/shader_compiler.hpp"
#include "gl/object.hpp"
#include "gl/buffer.hpp"
#include "gl/frame.hpp"
#include "gl/modules/ssbo.hpp"
#include "GLFW/glfw3.h"
const char *vertexShaderSource = "#version 430\n"
"layout (location = 0) in uint pos_index;\n"
"#ssbo position_buffer\n"
"{\n"
" float positions[9];\n"
"};\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(positions[gl_VertexID*3], positions[(gl_VertexID*3) + 1], positions[(gl_VertexID*3) + 2], 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 430\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(0.8f, 0.15f, 0.0f, 1.0f);\n"
"}\n\0";
int main()
{
// Minimalist Graphics Demo.
tz::core::initialise("Topaz TZGLP SSBO Demo");
{
tz::gl::Object o;
tz::gl::p::SSBOModule* ssbo_module = nullptr;
tz::gl::ShaderPreprocessor pre{vertexShaderSource};
{
std::size_t ssbo_module_id = pre.emplace_module<tz::gl::p::SSBOModule>(&o);
pre.preprocess();
// Get the module after use.
ssbo_module = static_cast<tz::gl::p::SSBOModule*>(pre[ssbo_module_id]);
}
std::size_t ssbo_id = ssbo_module->get_buffer_id(ssbo_module->size() - 1);
tz::gl::SSBO* ssbo = o.get<tz::gl::BufferType::ShaderStorage>(ssbo_id);
tz::gl::ShaderCompiler cpl;
tz::gl::ShaderProgram prg;
tz::gl::Shader* vs = prg.emplace(tz::gl::ShaderType::Vertex);
// We want to upload the preprocessed source.
vs->upload_source(pre.result());
tz::gl::Shader* fs = prg.emplace(tz::gl::ShaderType::Fragment);
fs->upload_source(fragmentShaderSource);
cpl.compile(*vs);
cpl.compile(*fs);
cpl.link(prg);
const float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
ssbo->bind();
ssbo->terminal_resize(sizeof(vertices));
tz::mem::UniformPool<float> vertex_pool = ssbo->map_pool<float>();
for(std::size_t i = 0; i < vertex_pool.capacity(); i++)
vertex_pool.set(i, vertices[i]);
auto add_pos = [&vertex_pool](float x, float y, float z)
{
vertex_pool[0] += x;
vertex_pool[3] += x;
vertex_pool[6] += x;
vertex_pool[1] += y;
vertex_pool[4] += y;
vertex_pool[7] += y;
vertex_pool[2] += z;
vertex_pool[5] += z;
vertex_pool[8] += z;
};
ssbo->unbind();
o.unbind();
tz::core::IWindow& wnd = tz::core::get().window();
wnd.register_this();
wnd.emplace_custom_key_listener([&add_pos](tz::input::KeyPressEvent e)
{
switch(e.key)
{
case GLFW_KEY_W:
add_pos(0.0f, 0.05f, 0.0f);
tz::debug_printf("moving forward.\n");
break;
case GLFW_KEY_S:
add_pos(0.0f, -0.05f, 0.0f);
tz::debug_printf("moving backward.\n");
break;
case GLFW_KEY_A:
add_pos(-0.05f, 0.0f, 0.0f);
tz::debug_printf("moving left\n");
break;
case GLFW_KEY_D:
add_pos(0.05f, 0.0f, 0.0f);
tz::debug_printf("moving right\n");
break;
}
});
glClearColor(0.0f, 0.3f, 0.15f, 1.0f);
while(!wnd.is_close_requested())
{
wnd.get_frame()->clear();
prg.bind();
o.bind();
ssbo->bind();
o.render(1);
wnd.update();
tz::core::update();
}
tz::core::terminate();
}