Render: Add and implement shader storage buffer (SSBO)
This commit is contained in:
@@ -25,8 +25,8 @@ struct DirectionalLight {
|
|||||||
vec3 specular;
|
vec3 specular;
|
||||||
};
|
};
|
||||||
|
|
||||||
const int MAX_DIRECTIONAL_LIGHTS = 32;
|
const int MAX_DIRECTIONAL_LIGHTS = 4;
|
||||||
layout(std140, binding = 1) uniform DirectionalLights {
|
layout(std430, binding = 0) buffer DirectionalLights {
|
||||||
DirectionalLight u_directionalLight[MAX_DIRECTIONAL_LIGHTS];
|
DirectionalLight u_directionalLight[MAX_DIRECTIONAL_LIGHTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint> // int32_t, uint32_t
|
#include <cstdint> // int32_t, uint32_t
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ uint32_t BufferElement::getTypeGL() const
|
|||||||
return BufferElement::getTypeGL(m_type);
|
return BufferElement::getTypeGL(m_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t BufferElement::getTypeSize(const BufferElementType type)
|
uint32_t BufferElement::getTypeSize(BufferElementType type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BufferElementType::None:
|
case BufferElementType::None:
|
||||||
@@ -86,7 +86,7 @@ uint32_t BufferElement::getTypeSize(const BufferElementType type)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t BufferElement::getTypeCount(const BufferElementType type)
|
uint32_t BufferElement::getTypeCount(BufferElementType type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BufferElementType::None:
|
case BufferElementType::None:
|
||||||
@@ -133,7 +133,7 @@ uint32_t BufferElement::getTypeCount(const BufferElementType type)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t BufferElement::getTypeGL(const BufferElementType type)
|
uint32_t BufferElement::getTypeGL(BufferElementType type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BufferElementType::None:
|
case BufferElementType::None:
|
||||||
@@ -177,6 +177,58 @@ uint32_t BufferElement::getTypeGL(const BufferElementType type)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t BufferElement::getGLTypeSize(uint32_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case GL_BOOL:
|
||||||
|
case GL_INT:
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
case GL_FLOAT:
|
||||||
|
return 4;
|
||||||
|
case GL_BOOL_VEC2:
|
||||||
|
case GL_INT_VEC2:
|
||||||
|
case GL_UNSIGNED_INT_VEC2:
|
||||||
|
case GL_FLOAT_VEC2:
|
||||||
|
return 4 * 2;
|
||||||
|
case GL_BOOL_VEC3:
|
||||||
|
case GL_INT_VEC3:
|
||||||
|
case GL_UNSIGNED_INT_VEC3:
|
||||||
|
case GL_FLOAT_VEC3:
|
||||||
|
return 4 * 3;
|
||||||
|
case GL_BOOL_VEC4:
|
||||||
|
case GL_INT_VEC4:
|
||||||
|
case GL_UNSIGNED_INT_VEC4:
|
||||||
|
case GL_FLOAT_VEC4:
|
||||||
|
return 4 * 4;
|
||||||
|
case GL_FLOAT_MAT2:
|
||||||
|
return 4 * 2 * 2;
|
||||||
|
case GL_FLOAT_MAT3:
|
||||||
|
return 4 * 3 * 3;
|
||||||
|
case GL_FLOAT_MAT4:
|
||||||
|
return 4 * 4 * 4;
|
||||||
|
|
||||||
|
case GL_DOUBLE:
|
||||||
|
return 8;
|
||||||
|
case GL_DOUBLE_VEC2:
|
||||||
|
return 8 * 2;
|
||||||
|
case GL_DOUBLE_VEC3:
|
||||||
|
return 8 * 3;
|
||||||
|
case GL_DOUBLE_VEC4:
|
||||||
|
return 8 * 4;
|
||||||
|
case GL_DOUBLE_MAT2:
|
||||||
|
return 8 * 2 * 2;
|
||||||
|
case GL_DOUBLE_MAT3:
|
||||||
|
return 8 * 3 * 3;
|
||||||
|
case GL_DOUBLE_MAT4:
|
||||||
|
return 8 * 4 * 4;
|
||||||
|
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
};
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
BufferLayout::BufferLayout(const std::initializer_list<BufferElement>& elements)
|
BufferLayout::BufferLayout(const std::initializer_list<BufferElement>& elements)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Inferno {
|
|||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
// https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)
|
// https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)
|
||||||
enum class BufferElementType {
|
enum class BufferElementType : uint8_t {
|
||||||
None = 0,
|
None = 0,
|
||||||
Bool, Bool2, Bool3, Bool4, // bvec
|
Bool, Bool2, Bool3, Bool4, // bvec
|
||||||
Int, Int2, Int3, Int4, // ivec
|
Int, Int2, Int3, Int4, // ivec
|
||||||
@@ -39,9 +39,10 @@ public:
|
|||||||
uint32_t getTypeSize() const;
|
uint32_t getTypeSize() const;
|
||||||
uint32_t getTypeCount() const;
|
uint32_t getTypeCount() const;
|
||||||
uint32_t getTypeGL() const;
|
uint32_t getTypeGL() const;
|
||||||
static uint32_t getTypeSize(const BufferElementType type);
|
static uint32_t getTypeSize(BufferElementType type);
|
||||||
static uint32_t getTypeCount(const BufferElementType type);
|
static uint32_t getTypeCount(BufferElementType type);
|
||||||
static uint32_t getTypeGL(const BufferElementType type);
|
static uint32_t getTypeGL(BufferElementType type);
|
||||||
|
static uint32_t getGLTypeSize(uint32_t type);
|
||||||
|
|
||||||
BufferElementType type() const { return m_type; }
|
BufferElementType type() const { return m_type; }
|
||||||
std::string name() const { return m_name; }
|
std::string name() const { return m_name; }
|
||||||
@@ -49,11 +50,11 @@ public:
|
|||||||
uint32_t offset() const { return m_offset; }
|
uint32_t offset() const { return m_offset; }
|
||||||
bool normalized() const { return m_normalized; }
|
bool normalized() const { return m_normalized; }
|
||||||
|
|
||||||
void setType(const BufferElementType& type) { m_type = type; }
|
void setType(BufferElementType type) { m_type = type; }
|
||||||
void setName(const std::string& name) { m_name = name; }
|
void setName(const std::string& name) { m_name = name; }
|
||||||
void setSize(const uint32_t& size) { m_size = size; }
|
void setSize(uint32_t size) { m_size = size; }
|
||||||
void setOffset(const uint32_t& offset) { m_offset = offset; }
|
void setOffset(uint32_t offset) { m_offset = offset; }
|
||||||
void setNormalized(const bool& normalized) { m_normalized = normalized; }
|
void setNormalized(bool normalized) { m_normalized = normalized; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BufferElementType m_type;
|
BufferElementType m_type;
|
||||||
|
|||||||
@@ -34,9 +34,6 @@ void Renderer<T>::endScene()
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
uint32_t Renderer<T>::m_maxSupportedTextureSlots = 0;
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Renderer<T>::initialize()
|
void Renderer<T>::initialize()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,9 +16,10 @@
|
|||||||
#include "glm/ext/vector_float4.hpp" // glm::vec4
|
#include "glm/ext/vector_float4.hpp" // glm::vec4
|
||||||
#include "ruc/singleton.h"
|
#include "ruc/singleton.h"
|
||||||
|
|
||||||
|
#include "inferno/asset/shader.h"
|
||||||
|
|
||||||
namespace Inferno {
|
namespace Inferno {
|
||||||
|
|
||||||
class Shader;
|
|
||||||
class Texture;
|
class Texture;
|
||||||
class TransformComponent;
|
class TransformComponent;
|
||||||
class VertexArray;
|
class VertexArray;
|
||||||
@@ -79,6 +80,8 @@ public:
|
|||||||
|
|
||||||
void setEnableDepthBuffer(bool state) { m_enableDepthBuffer = state; }
|
void setEnableDepthBuffer(bool state) { m_enableDepthBuffer = state; }
|
||||||
|
|
||||||
|
uint32_t shaderID() const { return m_shader->id(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Renderer() {}
|
Renderer() {}
|
||||||
virtual ~Renderer() { destroy(); };
|
virtual ~Renderer() { destroy(); };
|
||||||
@@ -106,7 +109,7 @@ protected:
|
|||||||
T* m_vertexBufferPtr { nullptr };
|
T* m_vertexBufferPtr { nullptr };
|
||||||
|
|
||||||
// Texture units
|
// Texture units
|
||||||
static uint32_t m_maxSupportedTextureSlots;
|
static inline uint32_t m_maxSupportedTextureSlots { 0 };
|
||||||
uint32_t m_textureSlotIndex { 1 };
|
uint32_t m_textureSlotIndex { 1 };
|
||||||
std::array<std::shared_ptr<Texture>, maxTextureSlots> m_textureSlots;
|
std::array<std::shared_ptr<Texture>, maxTextureSlots> m_textureSlots;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Riyyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdint> // int32_t, uint8_t, uintt32_t
|
||||||
|
|
||||||
|
#include "glad/glad.h"
|
||||||
|
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2
|
||||||
|
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3
|
||||||
|
#include "glm/ext/vector_float4.hpp" // glm::vec4
|
||||||
|
|
||||||
|
#include "inferno/render/buffer.h"
|
||||||
|
#include "inferno/render/shader-storage-buffer.h"
|
||||||
|
|
||||||
|
namespace Inferno {
|
||||||
|
|
||||||
|
ShaderStorageBuffer::ShaderStorageBuffer(s)
|
||||||
|
{
|
||||||
|
// Get maximum uniformbuffer bindings the GPU supports
|
||||||
|
int32_t maxBindingPoints = 0;
|
||||||
|
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxBindingPoints);
|
||||||
|
m_maxBindingPoints = static_cast<uint8_t>(maxBindingPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderStorageBuffer::~ShaderStorageBuffer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/56512216#answer-56513136
|
||||||
|
void ShaderStorageBuffer::setLayout(std::string_view blockName, uint8_t bindingPoint, uint32_t shaderID)
|
||||||
|
{
|
||||||
|
VERIFY(bindingPoint < m_maxBindingPoints,
|
||||||
|
"shader storage buffer exceeded binding points: {}/{}", bindingPoint, m_maxBindingPoints);
|
||||||
|
|
||||||
|
if (!exists(blockName)) {
|
||||||
|
m_blocks[blockName.data()] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferBlock& block = m_blocks[blockName.data()];
|
||||||
|
block.bindingPoint = bindingPoint;
|
||||||
|
block.memberOffsets.clear();
|
||||||
|
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, block.id);
|
||||||
|
|
||||||
|
// Get the shader block index
|
||||||
|
uint32_t resourceIndex = glGetProgramResourceIndex(shaderID, GL_SHADER_STORAGE_BLOCK, blockName.data());
|
||||||
|
VERIFY(resourceIndex != GL_INVALID_INDEX, "block doesnt exist in shader: {}::{}", blockName, shaderID);
|
||||||
|
|
||||||
|
// Get the amount of member variables
|
||||||
|
uint32_t prop = GL_NUM_ACTIVE_VARIABLES;
|
||||||
|
int32_t memberCount;
|
||||||
|
glGetProgramResourceiv(shaderID, GL_SHADER_STORAGE_BLOCK, resourceIndex, 1, &prop, 1, nullptr, &memberCount);
|
||||||
|
|
||||||
|
// Get the indices of the members
|
||||||
|
prop = GL_ACTIVE_VARIABLES;
|
||||||
|
std::vector<int32_t> members(memberCount);
|
||||||
|
glGetProgramResourceiv(shaderID, GL_SHADER_STORAGE_BLOCK, resourceIndex, 1, &prop, (int32_t)members.size(), nullptr, members.data());
|
||||||
|
|
||||||
|
// Reserve memory for the names of the members
|
||||||
|
int32_t memberNameSize;
|
||||||
|
glGetProgramInterfaceiv(shaderID, GL_BUFFER_VARIABLE, GL_MAX_NAME_LENGTH, &memberNameSize);
|
||||||
|
std::vector<char> memberNameBuffer(memberNameSize);
|
||||||
|
|
||||||
|
int32_t lastOffset = 0;
|
||||||
|
int32_t lastType = 0;
|
||||||
|
for (int32_t i = 0; i < memberCount; i++) {
|
||||||
|
|
||||||
|
// Get name of buffer variable
|
||||||
|
int32_t stringLength;
|
||||||
|
glGetProgramResourceName(shaderID, GL_BUFFER_VARIABLE, members[i], memberNameSize, &stringLength, memberNameBuffer.data());
|
||||||
|
std::string memberName = std::string(memberNameBuffer.begin(), memberNameBuffer.begin() + stringLength);
|
||||||
|
|
||||||
|
// Get the other data needed for computing
|
||||||
|
|
||||||
|
uint32_t props[7] = {
|
||||||
|
GL_OFFSET, // 0
|
||||||
|
GL_TYPE, // 1
|
||||||
|
GL_ARRAY_SIZE, // 2
|
||||||
|
GL_ARRAY_STRIDE, // 3
|
||||||
|
GL_MATRIX_STRIDE, // 4
|
||||||
|
GL_TOP_LEVEL_ARRAY_SIZE, // 5
|
||||||
|
GL_TOP_LEVEL_ARRAY_STRIDE, // 6
|
||||||
|
};
|
||||||
|
int32_t params[7];
|
||||||
|
glGetProgramResourceiv(shaderID, GL_BUFFER_VARIABLE, members[i], 7, props, 7, nullptr, params);
|
||||||
|
|
||||||
|
// ruc::error("{}", memberName);
|
||||||
|
// ruc::error("\n Offset: {}, type: {:#x}, arraySize: {}, arrayStride: {},\n matrixStride: {}, top level size: {}, top level stride: {}\n",
|
||||||
|
// params[0], params[1], params[2], params[3], params[4], params[5], params[6]);
|
||||||
|
|
||||||
|
// Array of structs
|
||||||
|
if (params[5] != 1 && params[6 != 0]) {
|
||||||
|
size_t bracketOpen = memberName.find_first_of('[');
|
||||||
|
size_t bracketClose = memberName.find_first_of(']');
|
||||||
|
std::string memberNameBegin = memberName.substr(0, bracketOpen); // name: myArray[0].member -> myArray
|
||||||
|
std::string memberNameMember = memberName.substr(bracketClose + 1); // name: myArray[0].member -> .member
|
||||||
|
for (int32_t j = 0; j < params[5]; ++j) {
|
||||||
|
lastOffset = params[0] + (j * params[6]); // calc offset
|
||||||
|
lastType = params[1];
|
||||||
|
|
||||||
|
// Only add the member variant the first time its encountered
|
||||||
|
if (j == 0 && block.memberOffsets.find(memberNameBegin) == block.memberOffsets.end()) {
|
||||||
|
block.memberOffsets.emplace(memberNameBegin, lastOffset); // name: myArray
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only add the index variant the first time its encountered
|
||||||
|
std::string memberNameIndex = memberNameBegin + "[" + std::to_string(j) + "]"; // name: myArray -> myArray[i]
|
||||||
|
if (block.memberOffsets.find(memberNameIndex) == block.memberOffsets.end()) {
|
||||||
|
block.memberOffsets.emplace(memberNameIndex, lastOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
block.memberOffsets.emplace(memberNameIndex + memberNameMember, // name: myArray -> myArray[i].member
|
||||||
|
lastOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Array of primitives
|
||||||
|
else if (params[2] != 1 && params[3] != 0) {
|
||||||
|
std::string memberNameBegin = memberName.substr(0, memberName.find_first_of('[')); // name: myArray[0] -> myArray
|
||||||
|
for (int32_t j = 0; j < params[2]; ++j) {
|
||||||
|
lastOffset = params[0] + (j * params[3]); // calc offset
|
||||||
|
lastType = params[1];
|
||||||
|
|
||||||
|
// Only add the member variant the first time its encountered
|
||||||
|
if (j == 0) {
|
||||||
|
block.memberOffsets.emplace(memberNameBegin, lastOffset); // name: myArray
|
||||||
|
}
|
||||||
|
|
||||||
|
block.memberOffsets.emplace(memberNameBegin + "[" + std::to_string(j) + "]", // name: myArray -> myArray[i]
|
||||||
|
lastOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Matrix case
|
||||||
|
else if (params[4] != 0) {
|
||||||
|
lastType = params[1];
|
||||||
|
lastOffset = params[0];
|
||||||
|
block.memberOffsets.emplace(memberName, params[0]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastType = params[1];
|
||||||
|
lastOffset = params[0];
|
||||||
|
block.memberOffsets.emplace(memberName, params[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block.size = lastOffset + BufferElement::getGLTypeSize(lastType);
|
||||||
|
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
||||||
|
|
||||||
|
// Results
|
||||||
|
// for (auto [k, v] : block.memberOffsets) {
|
||||||
|
// ruc::error("{}:{}", k, v);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderStorageBuffer::create(std::string_view blockName)
|
||||||
|
{
|
||||||
|
VERIFY(exists(blockName), "shader storage buffer block doesnt exist");
|
||||||
|
|
||||||
|
BufferBlock& block = m_blocks[blockName.data()];
|
||||||
|
|
||||||
|
if (block.id != 0) {
|
||||||
|
glDeleteBuffers(1, &block.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate buffer
|
||||||
|
block.id = UINT_MAX;
|
||||||
|
glGenBuffers(1, &block.id);
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, block.id);
|
||||||
|
glBufferData(GL_SHADER_STORAGE_BUFFER, block.size, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
||||||
|
|
||||||
|
// Bind buffer to binding point
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, block.bindingPoint, block.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderStorageBuffer::setValue(std::string_view blockName, std::string_view member, bool value)
|
||||||
|
{
|
||||||
|
setValue(blockName, member, static_cast<uint32_t>(value), sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderStorageBuffer::setValue(std::string_view blockName, std::string_view member, glm::mat2 value)
|
||||||
|
{
|
||||||
|
setValue(blockName, member, static_cast<glm::mat4>(value), sizeof(glm::vec4) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderStorageBuffer::setValue(std::string_view blockName, std::string_view member, glm::mat3 value)
|
||||||
|
{
|
||||||
|
setValue(blockName, member, static_cast<glm::mat4>(value), sizeof(glm::vec4) * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Inferno
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Riyyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <cstdint> // uint8_t, uint32_t
|
||||||
|
#include <string_view>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "glad/glad.h"
|
||||||
|
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2
|
||||||
|
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3
|
||||||
|
#include "ruc/singleton.h"
|
||||||
|
|
||||||
|
#define CHECK_SET_CALL(blockName, member) \
|
||||||
|
VERIFY(exists(blockName), "shader storage buffer block doesnt exist: {}", blockName); \
|
||||||
|
const BufferBlock& block = m_blocks[blockName.data()]; \
|
||||||
|
VERIFY(block.memberOffsets.find(member.data()) != block.memberOffsets.end(), \
|
||||||
|
"shader storage buffer member doesnt exist: {}", member);
|
||||||
|
|
||||||
|
namespace Inferno {
|
||||||
|
|
||||||
|
struct BufferBlock {
|
||||||
|
uint32_t id { 0 };
|
||||||
|
uint32_t size { 0 };
|
||||||
|
uint8_t bindingPoint { 0 };
|
||||||
|
std::unordered_map<std::string, uint32_t> memberOffsets {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShaderStorageBuffer final : public ruc::Singleton<ShaderStorageBuffer> { // Shader Storage Buffer Object, SSBO
|
||||||
|
public:
|
||||||
|
ShaderStorageBuffer(s);
|
||||||
|
virtual ~ShaderStorageBuffer();
|
||||||
|
|
||||||
|
void setLayout(std::string_view blockName, uint8_t bindingPoint, uint32_t shaderID);
|
||||||
|
void create(std::string_view blockName);
|
||||||
|
|
||||||
|
bool exists(std::string_view blockName) const { return m_blocks.find(blockName.data()) != m_blocks.end(); }
|
||||||
|
|
||||||
|
template<typename T> // Capture value by reference, instead of decaying to pointer
|
||||||
|
void setValue(std::string_view blockName, std::string_view member, T&& value, size_t size = 0)
|
||||||
|
{
|
||||||
|
CHECK_SET_CALL(blockName, member);
|
||||||
|
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, block.id);
|
||||||
|
glBufferSubData(GL_SHADER_STORAGE_BUFFER, block.memberOffsets.at(member.data()), (size) ? size : sizeof(T), &value);
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
||||||
|
}
|
||||||
|
// Exceptions:
|
||||||
|
void setValue(std::string_view blockName, std::string_view member, bool value);
|
||||||
|
void setValue(std::string_view blockName, std::string_view member, glm::mat2 value);
|
||||||
|
void setValue(std::string_view blockName, std::string_view member, glm::mat3 value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t m_maxBindingPoints { 0 };
|
||||||
|
std::unordered_map<std::string, BufferBlock> m_blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Inferno
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Riyyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "glm/ext/vector_float3.hpp" // glm::vec3
|
||||||
|
|
||||||
|
namespace Inferno {
|
||||||
|
|
||||||
|
// Shader storage block layouts, using std430 memory layout rules
|
||||||
|
|
||||||
|
#define MAX_DIRECTIONAL_LIGHTS 4
|
||||||
|
struct alignas(16) DirectionalLightBlock {
|
||||||
|
alignas(16) glm::vec3 direction { 0 };
|
||||||
|
|
||||||
|
alignas(16) glm::vec3 ambient { 0 };
|
||||||
|
alignas(16) glm::vec3 diffuse { 0 };
|
||||||
|
alignas(16) glm::vec3 specular { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Inferno
|
||||||
@@ -59,6 +59,7 @@ void Uniformbuffer::setLayout(std::string_view blockName, uint8_t bindingPoint,
|
|||||||
|
|
||||||
UniformbufferBlock& block = m_blocks[blockName];
|
UniformbufferBlock& block = m_blocks[blockName];
|
||||||
block.bindingPoint = bindingPoint;
|
block.bindingPoint = bindingPoint;
|
||||||
|
block.uniformLocations.clear();
|
||||||
|
|
||||||
// Example block layout:
|
// Example block layout:
|
||||||
// - mat3
|
// - mat3
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdint> // uint8_t, uint32_t
|
#include <cstdint> // uint8_t, uint32_t
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -13,36 +15,18 @@
|
|||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2
|
#include "glm/ext/matrix_float2x2.hpp" // glm::mat2
|
||||||
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3
|
#include "glm/ext/matrix_float3x3.hpp" // glm::mat3
|
||||||
#include "glm/ext/vector_float3.hpp" // glm::vec3
|
|
||||||
#include "ruc/singleton.h"
|
#include "ruc/singleton.h"
|
||||||
|
|
||||||
#include "inferno/render/buffer.h"
|
#include "inferno/render/buffer.h"
|
||||||
|
|
||||||
#define CHECK_SET_CALL(blockName, member) \
|
#define CHECK_UNIFORM_SET_CALL(blockName, member) \
|
||||||
VERIFY(exists(blockName), "uniformbuffer block doesnt exist"); \
|
VERIFY(exists(blockName), "uniformbuffer block doesnt exist: {}", blockName); \
|
||||||
const UniformbufferBlock& block = m_blocks[blockName]; \
|
const UniformbufferBlock& block = m_blocks[blockName]; \
|
||||||
VERIFY(block.uniformLocations.find(member.data()) != block.uniformLocations.end(), \
|
VERIFY(block.uniformLocations.find(member.data()) != block.uniformLocations.end(), \
|
||||||
"uniformbuffer block member doesnt exist");
|
"uniformbuffer member doesnt exist: {}", member);
|
||||||
|
|
||||||
namespace Inferno {
|
namespace Inferno {
|
||||||
|
|
||||||
// Uniform block layouts, using std140 memory layout rules
|
|
||||||
|
|
||||||
#define MAX_DIRECTIONAL_LIGHTS 32
|
|
||||||
struct UniformDirectionalLight {
|
|
||||||
glm::vec3 direction { 0 };
|
|
||||||
float __padding0 { 0 };
|
|
||||||
|
|
||||||
glm::vec3 ambient { 0 };
|
|
||||||
float __padding1 { 0 };
|
|
||||||
glm::vec3 diffuse { 0 };
|
|
||||||
float __padding2 { 0 };
|
|
||||||
glm::vec3 specular { 0 };
|
|
||||||
float __padding3 { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
|
|
||||||
struct UniformbufferBlock {
|
struct UniformbufferBlock {
|
||||||
uint32_t id { 0 };
|
uint32_t id { 0 };
|
||||||
uint32_t size { 0 };
|
uint32_t size { 0 };
|
||||||
@@ -62,7 +46,7 @@ public:
|
|||||||
template<typename T> // Capture value by reference, instead of decaying to pointer
|
template<typename T> // Capture value by reference, instead of decaying to pointer
|
||||||
void setValue(std::string_view blockName, std::string_view member, T&& value, size_t size = 0)
|
void setValue(std::string_view blockName, std::string_view member, T&& value, size_t size = 0)
|
||||||
{
|
{
|
||||||
CHECK_SET_CALL(blockName, member);
|
CHECK_UNIFORM_SET_CALL(blockName, member);
|
||||||
|
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, block.id);
|
glBindBuffer(GL_UNIFORM_BUFFER, block.id);
|
||||||
glBufferSubData(GL_UNIFORM_BUFFER, block.uniformLocations.at(member.data()), (size) ? size : sizeof(T), &value);
|
glBufferSubData(GL_UNIFORM_BUFFER, block.uniformLocations.at(member.data()), (size) ? size : sizeof(T), &value);
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
#include "inferno/render/framebuffer.h"
|
#include "inferno/render/framebuffer.h"
|
||||||
#include "inferno/render/render-command.h"
|
#include "inferno/render/render-command.h"
|
||||||
#include "inferno/render/renderer.h"
|
#include "inferno/render/renderer.h"
|
||||||
|
#include "inferno/render/shader-storage-buffer.h"
|
||||||
|
#include "inferno/render/shader-structs.h"
|
||||||
#include "inferno/render/uniformbuffer.h"
|
#include "inferno/render/uniformbuffer.h"
|
||||||
#include "inferno/system/camerasystem.h"
|
#include "inferno/system/camerasystem.h"
|
||||||
#include "inferno/system/rendersystem.h"
|
#include "inferno/system/rendersystem.h"
|
||||||
@@ -57,16 +59,8 @@ void RenderSystem::initialize(uint32_t width, uint32_t height)
|
|||||||
});
|
});
|
||||||
Uniformbuffer::the().create("Camera");
|
Uniformbuffer::the().create("Camera");
|
||||||
|
|
||||||
Uniformbuffer::the().setLayout(
|
ShaderStorageBuffer::the().setLayout("DirectionalLights", 0, RendererPostProcess::the().shaderID());
|
||||||
"DirectionalLights",
|
ShaderStorageBuffer::the().create("DirectionalLights");
|
||||||
{
|
|
||||||
.size = sizeof(UniformDirectionalLight) * MAX_DIRECTIONAL_LIGHTS,
|
|
||||||
.bindingPoint = 1,
|
|
||||||
.uniformLocations = {
|
|
||||||
{ "u_directionalLight", 0 },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
Uniformbuffer::the().create("DirectionalLights");
|
|
||||||
|
|
||||||
ruc::info("RenderSystem initialized");
|
ruc::info("RenderSystem initialized");
|
||||||
}
|
}
|
||||||
@@ -137,15 +131,21 @@ void RenderSystem::renderGeometry()
|
|||||||
Uniformbuffer::the().setValue("Camera", "u_projectionView", projection * view);
|
Uniformbuffer::the().setValue("Camera", "u_projectionView", projection * view);
|
||||||
Uniformbuffer::the().setValue("Camera", "u_position", translate);
|
Uniformbuffer::the().setValue("Camera", "u_position", translate);
|
||||||
|
|
||||||
static UniformDirectionalLight directionalLights[1] = {
|
static DirectionalLightBlock directionalLights[2] = {
|
||||||
{
|
{
|
||||||
.direction = { -8.0f, -8.0f, -8.0f },
|
.direction = { -8.0f, -8.0f, -8.0f },
|
||||||
.ambient = { 0.1f, 0.1f, 0.1f },
|
.ambient = { 0.1f, 0.1f, 0.1f },
|
||||||
.diffuse = { 1.0f, 1.0f, 1.0f },
|
.diffuse = { 1.0f, 1.0f, 1.0f },
|
||||||
.specular = { 1.0f, 1.0f, 1.0f },
|
.specular = { 1.0f, 1.0f, 1.0f },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.direction = { 8.0f, 8.0f, 8.0f },
|
||||||
|
.ambient = { 0.1f, 0.1f, 0.1f },
|
||||||
|
.diffuse = { 1.0f, 1.0f, 1.0f },
|
||||||
|
.specular = { 1.0f, 0.0f, 0.0f },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Uniformbuffer::the().setValue("DirectionalLights", "u_directionalLight", directionalLights);
|
ShaderStorageBuffer::the().setValue("DirectionalLights", "u_directionalLight", directionalLights);
|
||||||
|
|
||||||
auto modelView = m_registry->view<TransformComponent, ModelComponent>();
|
auto modelView = m_registry->view<TransformComponent, ModelComponent>();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user