From debe4146eb89536334049e70e57da8692088cb55 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Tue, 12 Dec 2023 11:28:54 -0600 Subject: [PATCH] Added support for shader structures. --- src/dawn/component/ui/UICanvas.cpp | 9 +- src/dawnopengl/display/shader/CMakeLists.txt | 1 + src/dawnopengl/display/shader/Shader.hpp | 111 ++++++++++++------ .../display/shader/ShaderParameter.cpp | 20 ++++ .../display/shader/ShaderParameter.hpp | 33 ++++++ .../display/shader/ShaderStructure.hpp | 81 +++++++++++++ .../display/shader/SimpleTexturedShader.cpp | 15 +-- .../display/shader/SimpleTexturedShader.hpp | 3 +- src/dawnopengl/display/shader/UIShader.cpp | 63 +++++----- src/dawnopengl/display/shader/UIShader.hpp | 12 +- 10 files changed, 268 insertions(+), 80 deletions(-) create mode 100644 src/dawnopengl/display/shader/ShaderParameter.cpp create mode 100644 src/dawnopengl/display/shader/ShaderParameter.hpp create mode 100644 src/dawnopengl/display/shader/ShaderStructure.hpp diff --git a/src/dawn/component/ui/UICanvas.cpp b/src/dawn/component/ui/UICanvas.cpp index ce8cfde9..5dc6fe11 100644 --- a/src/dawn/component/ui/UICanvas.cpp +++ b/src/dawn/component/ui/UICanvas.cpp @@ -34,11 +34,10 @@ std::vector> UICanvas::getPasses( .view = ctx.camera->getItem()->getWorldTransform(), .model = selfTransform }; - - data.colors[0] = COLOR_WHITE; - data.colors[1] = COLOR_RED; - data.colors[2] = COLOR_GREEN; - data.colors[3] = COLOR_BLUE; + + data.test.first = COLOR_RED; + data.test.random = glm::vec3(0, 1, 0); + data.test.second = COLOR_BLUE; auto pass = createRenderPass( std::ref(*this), diff --git a/src/dawnopengl/display/shader/CMakeLists.txt b/src/dawnopengl/display/shader/CMakeLists.txt index c73ac167..2407fb33 100644 --- a/src/dawnopengl/display/shader/CMakeLists.txt +++ b/src/dawnopengl/display/shader/CMakeLists.txt @@ -10,4 +10,5 @@ target_sources(${DAWN_TARGET_NAME} ShaderStage.cpp SimpleTexturedShader.cpp UIShader.cpp + ShaderParameter.cpp ) \ No newline at end of file diff --git a/src/dawnopengl/display/shader/Shader.hpp b/src/dawnopengl/display/shader/Shader.hpp index 791c18b3..28378a26 100644 --- a/src/dawnopengl/display/shader/Shader.hpp +++ b/src/dawnopengl/display/shader/Shader.hpp @@ -11,6 +11,9 @@ #include "display/Color.hpp" #include "display/Texture.hpp" +#include "ShaderParameter.hpp" +#include "ShaderStructure.hpp" + namespace Dawn { typedef GLuint shadertexturebinding_t; @@ -18,53 +21,32 @@ namespace Dawn { GLSL_330_CORE }; - struct ShaderOpenGLParameter { - std::string name; - size_t offset; - enum ShaderParameterType type; - int32_t count; - - GLint location = -1; - - ShaderOpenGLParameter( - const std::string &name, - const void *offset, - const enum ShaderParameterType type - ) { - this->name = name; - this->offset = (size_t)offset; - this->type = type; - this->count = 1; - } - - ShaderOpenGLParameter( - const std::string &name, - const void *offset, - const enum ShaderParameterType type, - const int32_t count - ) { - this->name = name; - this->offset = (size_t)offset; - this->type = type; - this->count = count; - } - }; - template class Shader : public IShader { private: std::vector> stages; - std::vector parameters; + std::vector parameters; + std::vector structures; enum ShaderOpenGLVariant variant; GLuint shaderProgram = -1; protected: + /** + * Overridable function to get the stages for the shader. + * + * @param variant The variant of the shader to use. + * @param rel The relative data to use. + * @param stages The stages to add to. + * @param parameters The parameters to add to. + * @param structures The structures to add to. + */ virtual void getStages( const enum ShaderOpenGLVariant variant, const T *rel, std::vector> &stages, - std::vector ¶meters + std::vector ¶meters, + std::vector &structures ) = 0; public: @@ -82,7 +64,8 @@ namespace Dawn { variant, &dummy, stages, - parameters + parameters, + structures ); // Create the shader program @@ -108,7 +91,7 @@ namespace Dawn { std::for_each( parameters.begin(), parameters.end(), - [&](struct ShaderOpenGLParameter ¶m) { + [&](struct ShaderParameter ¶m) { // Correct offset param.offset = param.offset - (size_t)(&dummy); param.location = glGetUniformLocation( @@ -124,6 +107,28 @@ namespace Dawn { } ); + // Map structures + std::for_each( + structures.begin(), + structures.end(), + [&](struct IShaderStructure &structure) { + structure.offset = structure.offset - (size_t)(&dummy); + structure.location = glGetUniformBlockIndex( + shaderProgram, + structure.structureName.c_str() + ); + assertNoGLError(); + assertTrue( + structure.location != -1, + "Failed to get location for structure %s.", + structure.structureName.c_str() + ); + + // Create the buffer + glGenBuffers(1, &structure.buffer); + } + ); + this->bind(); } @@ -191,9 +196,43 @@ namespace Dawn { default: assertUnreachable("Unsupported ShaderOpenGLVariant"); } + + // Upload structures + for(auto structure : structures) { + switch(structure.structureType) { + case ShaderOpenGLStructureType::STD140: { + // Upload the data + glBindBuffer(GL_UNIFORM_BUFFER, structure.buffer); + assertNoGLError(); + glBindBufferBase(GL_UNIFORM_BUFFER, structure.location, structure.buffer); + assertNoGLError(); + glBufferData( + GL_UNIFORM_BUFFER, + structure.size, + (void*)((size_t)&this->data + (size_t)structure.offset), + GL_STATIC_DRAW + ); + assertNoGLError(); + break; + } + + default: + assertUnreachable("Unsupported ShaderOpenGLStructureType"); + } + } } ~Shader() { + // Delete the structures + for(auto structure : structures) { + assertTrue(structure.buffer != -1, "Invalid buffer."); + glDeleteBuffers(1, &structure.buffer); + assertNoGLError(); + } + + // Delete the shader program + glDeleteProgram(shaderProgram); + assertNoGLError(); } }; } \ No newline at end of file diff --git a/src/dawnopengl/display/shader/ShaderParameter.cpp b/src/dawnopengl/display/shader/ShaderParameter.cpp new file mode 100644 index 00000000..befc2e46 --- /dev/null +++ b/src/dawnopengl/display/shader/ShaderParameter.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "ShaderParameter.hpp" + +using namespace Dawn; + +ShaderParameter::ShaderParameter( + const std::string &name, + const void *offset, + const enum ShaderParameterType type, + const size_t count +) { + this->name = name; + this->offset = (size_t)offset; + this->type = type; + this->count = count; +} \ No newline at end of file diff --git a/src/dawnopengl/display/shader/ShaderParameter.hpp b/src/dawnopengl/display/shader/ShaderParameter.hpp new file mode 100644 index 00000000..1b87da7a --- /dev/null +++ b/src/dawnopengl/display/shader/ShaderParameter.hpp @@ -0,0 +1,33 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma once +#include "display/shader/IShader.hpp" +#include "dawnopengl.hpp" + +namespace Dawn { + struct ShaderParameter { + std::string name; + size_t offset; + enum ShaderParameterType type; + size_t count; + GLint location = -1; + + /** + * Construct a new shader parameter. + * + * @param name Name of the parameter within the shader. + * @param offset Offset, relative to the structure of the data. + * @param type Type of the parameter. + * @param count How many elements in the array (if multiple). + */ + ShaderParameter( + const std::string &name, + const void *offset, + const enum ShaderParameterType type, + const size_t count = 1 + ); + }; +} \ No newline at end of file diff --git a/src/dawnopengl/display/shader/ShaderStructure.hpp b/src/dawnopengl/display/shader/ShaderStructure.hpp new file mode 100644 index 00000000..4cbc9048 --- /dev/null +++ b/src/dawnopengl/display/shader/ShaderStructure.hpp @@ -0,0 +1,81 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma ocne +#include "display/shader/ShaderParameter.hpp" + +namespace Dawn { + enum class ShaderOpenGLStructureType { + STD140 + }; + + struct IShaderStructure { + std::string structureName; + size_t offset; + enum ShaderOpenGLStructureType structureType; + size_t size; + // size_t count; + std::vector parameters; + GLint location = -1; + GLuint buffer = -1; + }; + + template + struct ShaderStructure final : public IShaderStructure { + public: + /** + * Constructs a new shader structure. Shader structures allow for larger + * amounts/volumes of data to be passed to the shader in a single call. + * Ideally I wouldn't really need this as I wanted the entire shader to + * basically be a single large structure, but OpenGL doesn't support that + * so I have to do this instead. + * + * @param structureName Structure name within the shader. + * @param offset Offset, within the data structure, that this structure + * starts at. + * @param structureType The type of structure data format to use. + * @param getParameters A callback that, when invoked, will populate the + * parameters vector with the parameters for this + * structure. + */ + ShaderStructure( + const std::string &structureName, + const void *offset, + const enum ShaderOpenGLStructureType structureType, + std::function< + void(const T&, std::vector&) + > getParameters + ) { + this->structureName = structureName; + this->offset = (size_t)offset; + this->structureType = structureType; + this->size = sizeof(T); + this->parameters = std::vector(); + + T dummy; + getParameters(dummy, this->parameters); + + // Update offsets. + std::for_each( + this->parameters.begin(), + this->parameters.end(), + [&](struct ShaderParameter ¶m) { + param.offset -= (size_t)(&dummy); + + // Check for non-aligned OpenGL structures. + if(param.offset % sizeof(glm::vec4) != 0) { + assertUnreachable( + "%s%s%s", + "Non-aligned OpenGL structure detected on param ", + param.name.c_str(), + "!\nEnsure you have padded correctly." + ); + } + } + ); + + } + }; +} \ No newline at end of file diff --git a/src/dawnopengl/display/shader/SimpleTexturedShader.cpp b/src/dawnopengl/display/shader/SimpleTexturedShader.cpp index efd52dfc..bca7d20f 100644 --- a/src/dawnopengl/display/shader/SimpleTexturedShader.cpp +++ b/src/dawnopengl/display/shader/SimpleTexturedShader.cpp @@ -11,7 +11,8 @@ void SimpleTexturedShader::getStages( const enum ShaderOpenGLVariant variant, const struct SimpleTexturedShaderData *rel, std::vector> &stages, - std::vector ¶meters + std::vector ¶meters, + std::vector &structures ) { // Stages std::shared_ptr vertex; @@ -61,37 +62,37 @@ void SimpleTexturedShader::getStages( stages.push_back(fragment); // Parameters - parameters.push_back(ShaderOpenGLParameter( + parameters.push_back(ShaderParameter( "u_Projection", &rel->projection, ShaderParameterType::MAT4 )); - parameters.push_back(ShaderOpenGLParameter( + parameters.push_back(ShaderParameter( "u_View", &rel->view, ShaderParameterType::MAT4 )); - parameters.push_back(ShaderOpenGLParameter( + parameters.push_back(ShaderParameter( "u_Model", &rel->model, ShaderParameterType::MAT4 )); - parameters.push_back(ShaderOpenGLParameter( + parameters.push_back(ShaderParameter( "u_Color", &rel->color, ShaderParameterType::COLOR )); - parameters.push_back(ShaderOpenGLParameter( + parameters.push_back(ShaderParameter( "u_HasTexture", &rel->hasTexture, ShaderParameterType::BOOLEAN )); - parameters.push_back(ShaderOpenGLParameter( + parameters.push_back(ShaderParameter( "u_Texture", &rel->texture, ShaderParameterType::TEXTURE diff --git a/src/dawnopengl/display/shader/SimpleTexturedShader.hpp b/src/dawnopengl/display/shader/SimpleTexturedShader.hpp index 5b30df56..ed23bea1 100644 --- a/src/dawnopengl/display/shader/SimpleTexturedShader.hpp +++ b/src/dawnopengl/display/shader/SimpleTexturedShader.hpp @@ -22,7 +22,8 @@ namespace Dawn { const enum ShaderOpenGLVariant variant, const struct SimpleTexturedShaderData *rel, std::vector> &stages, - std::vector ¶meters + std::vector ¶meters, + std::vector &structures ) override; }; } \ No newline at end of file diff --git a/src/dawnopengl/display/shader/UIShader.cpp b/src/dawnopengl/display/shader/UIShader.cpp index a2d33874..34d2487b 100644 --- a/src/dawnopengl/display/shader/UIShader.cpp +++ b/src/dawnopengl/display/shader/UIShader.cpp @@ -11,7 +11,8 @@ void UIShader::getStages( const enum ShaderOpenGLVariant variant, const struct UIShaderData *rel, std::vector> &stages, - std::vector ¶meters + std::vector ¶meters, + std::vector &structures ) { // Stages std::shared_ptr vertex; @@ -38,10 +39,14 @@ void UIShader::getStages( ShaderStageType::FRAGMENT, "#version 330 core\n" "in vec2 o_TextCoord;\n" - "uniform vec4 u_Color[4];\n" + "layout (std140) uniform ub_Color {\n" + "vec4 first;\n" + "vec3 random;\n" + "vec4 second;\n" + "};\n" "out vec4 o_Color;\n" "void main() {\n" - "o_Color = u_Color[2];\n" + "o_Color = second;\n" "}\n" ); break; @@ -55,46 +60,46 @@ void UIShader::getStages( stages.push_back(fragment); // Parameters - parameters.push_back(ShaderOpenGLParameter( + parameters.push_back(ShaderParameter( "u_Projection", &rel->projection, ShaderParameterType::MAT4 )); - parameters.push_back(ShaderOpenGLParameter( + parameters.push_back(ShaderParameter( "u_View", &rel->view, ShaderParameterType::MAT4 )); - parameters.push_back(ShaderOpenGLParameter( + parameters.push_back(ShaderParameter( "u_Model", &rel->model, ShaderParameterType::MAT4 )); - parameters.push_back(ShaderOpenGLParameter( - "u_Color", - &rel->colors, - ShaderParameterType::COLOR, - 4 + structures.push_back(ShaderStructure( + "ub_Color", + &rel->test, + ShaderOpenGLStructureType::STD140, + [&](const struct TestStruct &rel, std::vector ¶meters) { + parameters.push_back(ShaderParameter( + "first", + &rel.first, + ShaderParameterType::COLOR + )); + + parameters.push_back(ShaderParameter( + "random", + &rel.random, + ShaderParameterType::VEC3 + )); + + parameters.push_back(ShaderParameter( + "second", + &rel.second, + ShaderParameterType::COLOR + )); + } )); - - // parameters.push_back(ShaderOpenGLParameter( - // "u_Color", - // &rel->color, - // ShaderParameterType::COLOR - // )); - - // parameters.push_back(ShaderOpenGLParameter( - // "u_HasTexture", - // &rel->hasTexture, - // ShaderParameterType::BOOLEAN - // )); - - // parameters.push_back(ShaderOpenGLParameter( - // "u_Texture", - // &rel->texture, - // ShaderParameterType::TEXTURE - // )); } \ No newline at end of file diff --git a/src/dawnopengl/display/shader/UIShader.hpp b/src/dawnopengl/display/shader/UIShader.hpp index a664f192..f5f85e46 100644 --- a/src/dawnopengl/display/shader/UIShader.hpp +++ b/src/dawnopengl/display/shader/UIShader.hpp @@ -7,11 +7,18 @@ #include "display/shader/Shader.hpp" namespace Dawn { + struct TestStruct { + struct Color first; + glm::vec3 random; + float_t padded; + struct Color second; + }; + struct UIShaderData { glm::mat4 projection; glm::mat4 view; glm::mat4 model; - struct Color colors[4]; + struct TestStruct test; }; class UIShader : public Shader { @@ -20,7 +27,8 @@ namespace Dawn { const enum ShaderOpenGLVariant variant, const struct UIShaderData *rel, std::vector> &stages, - std::vector ¶meters + std::vector ¶meters, + std::vector &structures ) override; }; } \ No newline at end of file