refactor opengl shader and add shader builder

This commit is contained in:
Green Sky 2021-10-17 16:40:18 +02:00
parent 5ee0b7017f
commit 8e74256670
5 changed files with 213 additions and 7 deletions

View File

@ -38,6 +38,11 @@ namespace MM::OpenGL {
glBindBuffer(target, 0); glBindBuffer(target, 0);
} }
// for transform feedback
void bindBase(GLuint index, GLenum target = GL_TRANSFORM_FEEDBACK_BUFFER) const {
glBindBufferBase(target, index, _handle);
}
void resize(size_t size, GLenum usage) { void resize(size_t size, GLenum usage) {
glBindBuffer(GL_ARRAY_BUFFER, _handle); glBindBuffer(GL_ARRAY_BUFFER, _handle);
glBufferData(GL_ARRAY_BUFFER, size * sizeof(TInstance), nullptr, usage); glBufferData(GL_ARRAY_BUFFER, size * sizeof(TInstance), nullptr, usage);

View File

@ -1,6 +1,10 @@
#include "./shader.hpp" #include "./shader.hpp"
#include <map> #ifdef MM_OPENGL_3_GLES
#include <GLES3/gl3.h>
#else
#include <glad/glad.h>
#endif
#include <mm/services/filesystem.hpp> #include <mm/services/filesystem.hpp>

View File

@ -6,12 +6,6 @@
#include <unordered_map> #include <unordered_map>
#include <memory> #include <memory>
#ifdef MM_OPENGL_3_GLES
#include <GLES3/gl3.h>
#else
#include <glad/glad.h>
#endif
#include <glm/fwd.hpp> #include <glm/fwd.hpp>
#include <glm/mat3x3.hpp> #include <glm/mat3x3.hpp>
@ -22,7 +16,12 @@ namespace MM {
namespace MM::OpenGL { namespace MM::OpenGL {
// fwd
class ShaderBuilder;
class Shader { class Shader {
friend ShaderBuilder;
private: private:
uint32_t _rendererID; uint32_t _rendererID;
std::unordered_map<std::string, int32_t> _uniformLocationCache; std::unordered_map<std::string, int32_t> _uniformLocationCache;
@ -50,6 +49,7 @@ namespace MM::OpenGL {
void setUniformMat4f(const std::string& name, const glm::mat4& matrix); void setUniformMat4f(const std::string& name, const glm::mat4& matrix);
void setUniformMat3f(const std::string& name, const glm::mat3& matrix); void setUniformMat3f(const std::string& name, const glm::mat3& matrix);
// prefere ShaderBuilder
static std::shared_ptr<Shader> createF(Engine& engine, const char* vertexShaderPath, const char* fragmentShaderPath); static std::shared_ptr<Shader> createF(Engine& engine, const char* vertexShaderPath, const char* fragmentShaderPath);
static std::shared_ptr<Shader> create(const std::string& vertexShader, const std::string& fragmentShader); static std::shared_ptr<Shader> create(const std::string& vertexShader, const std::string& fragmentShader);

View File

@ -0,0 +1,145 @@
#include "./shader_builder.hpp"
#ifdef MM_OPENGL_3_GLES
#include <GLES3/gl3.h>
#else
#include <glad/glad.h>
#endif
#include <mm/services/filesystem.hpp>
#include <mm/logger.hpp>
#define LOG_CRIT(...) __LOG_CRIT( "OpenGL", __VA_ARGS__)
#define LOG_ERROR(...) __LOG_ERROR("OpenGL", __VA_ARGS__)
#define LOG_WARN(...) __LOG_WARN( "OpenGL", __VA_ARGS__)
#define LOG_INFO(...) __LOG_INFO( "OpenGL", __VA_ARGS__)
#define LOG_DEBUG(...) __LOG_DEBUG("OpenGL", __VA_ARGS__)
#define LOG_TRACE(...) __LOG_TRACE("OpenGL", __VA_ARGS__)
namespace MM::OpenGL {
ShaderBuilder::ShaderBuilder(void) {
}
ShaderBuilder::~ShaderBuilder(void) {
// after linking or in case of error, stages can be deleted
for (auto& stage : _stages) {
if (stage.id != 0) {
glDeleteShader(stage.id);
}
}
}
ShaderBuilder ShaderBuilder::start(void) {
return {};
}
std::shared_ptr<Shader> ShaderBuilder::finish(void) {
// check
for (auto& stage : _stages) {
if (stage.fail) {
// log error
return nullptr;
}
}
uint32_t program = glCreateProgram();
// attach
for (auto& stage : _stages) {
if (stage.id != 0) {
glAttachShader(program, stage.id);
}
}
// tf varying
if (!_tfs.empty()) {
std::vector<const char*> tmp_vars;
for (auto& tfv : _tfs) {
tmp_vars.push_back(tfv.var.c_str());
}
glTransformFeedbackVaryings(program, tmp_vars.size(), tmp_vars.data(), _tf_interleaved ? GL_INTERLEAVED_ATTRIBS : GL_SEPARATE_ATTRIBS);
}
glLinkProgram(program);
// diagnostics
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
if (isLinked == GL_FALSE) {
GLint maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(program, maxLength, &maxLength, infoLog.data());
LOG_ERROR("Linking Shader Programs: {}", infoLog.data());
// The program is useless now. So delete it.
glDeleteProgram(program);
return nullptr;
}
glValidateProgram(program);
GLint isValid = 0;
glGetProgramiv(program, GL_VALIDATE_STATUS, &isValid);
if (isValid == GL_FALSE) {
GLint maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(program, maxLength, &maxLength, infoLog.data());
LOG_ERROR("Validating Shader Programs: {}", infoLog.data());
// The program is useless now. So delete it.
glDeleteProgram(program);
return nullptr;
}
return std::shared_ptr<Shader>(new Shader(program));
}
ShaderBuilder& ShaderBuilder::addStageVertex(const std::string& shader_code) {
_stages[VERTEX].id = Shader::compile(GL_VERTEX_SHADER, shader_code);
if (_stages[VERTEX].id == 0) {
_stages[VERTEX].fail = true;
}
return *this;
}
ShaderBuilder& ShaderBuilder::addStageVertexF(MM::Engine& engine, const std::string& file_path) {
return addStageVertex(Shader::parse(engine, file_path));
}
ShaderBuilder& ShaderBuilder::addStageFragment(const std::string& shader_code) {
_stages[FRAGMENT].id = Shader::compile(GL_FRAGMENT_SHADER, shader_code);
if (_stages[FRAGMENT].id == 0) {
_stages[FRAGMENT].fail = true;
}
return *this;
}
ShaderBuilder& ShaderBuilder::addStageFragmentF(MM::Engine& engine, const std::string& file_path) {
return addStageFragment(Shader::parse(engine, file_path));
}
ShaderBuilder& ShaderBuilder::addTransformFeedbackVarying(const std::string& var_name) {
if (var_name.empty()) {
// log waring
return *this;
}
_tfs.push_back({var_name});
return *this;
}
} // MM::OpenGL

View File

@ -0,0 +1,52 @@
#pragma once
#include "./shader.hpp"
#include <vector>
namespace MM::OpenGL {
class ShaderBuilder {
private:
ShaderBuilder(void);
struct stage_t {
uint32_t id = 0;
bool fail = false;
};
enum stage_e {
VERTEX = 0,
FRAGMENT,
stage_e_MAX
};
stage_t _stages[stage_e_MAX];
struct transform_feedback_varying_t {
std::string var;
};
std::vector<transform_feedback_varying_t> _tfs;
bool _tf_interleaved = false;
public:
~ShaderBuilder(void);
ShaderBuilder& operator=(ShaderBuilder&) = delete;
static ShaderBuilder start(void);
std::shared_ptr<Shader> finish(void);
public:
ShaderBuilder& addStageVertex(const std::string& shader_code);
ShaderBuilder& addStageVertexF(MM::Engine& engine, const std::string& file_path);
ShaderBuilder& addStageFragment(const std::string& shader_code);
ShaderBuilder& addStageFragmentF(MM::Engine& engine, const std::string& file_path);
// TODO: geometry and tesselation stages
ShaderBuilder& addTransformFeedbackVarying(const std::string& var_name);
ShaderBuilder& setTransformFeedbackInterleaved(bool interleaved = true);
};
} // MM::OpenGL