Improved Shader compilation

This commit is contained in:
Bruno Herbelin
2022-04-19 01:23:04 +02:00
parent c25427cf4a
commit 3c465f9a7a
2 changed files with 98 additions and 95 deletions

View File

@@ -73,74 +73,104 @@ GLenum blending_destination_function[9] = {GL_ONE_MINUS_SRC_ALPHA,// normal
GL_ZERO};
ShadingProgram::ShadingProgram(const std::string& vertex, const std::string& fragment) :
vertex_id_(0), fragment_id_(0), id_(0)
id_(0), need_compile_(true), vertex_(vertex), fragment_(fragment)
{
if (Resource::hasPath(vertex))
vertex_file_ = vertex;
else
vertex_code_ = vertex;
if (Resource::hasPath(fragment))
fragment_file_ = fragment;
else
fragment_code_ = fragment;
}
void ShadingProgram::init()
void ShadingProgram::setShaders(const std::string& vertex, const std::string& fragment)
{
if (vertex_code_.empty())
vertex_code_ = Resource::getText(vertex_file_);
if (fragment_code_.empty())
fragment_code_ = Resource::getText(fragment_file_);
if ( compile() )
link();
}
bool ShadingProgram::initialized()
{
return (id_ != 0);
vertex_ = vertex;
fragment_ = fragment;
need_compile_ = true;
}
bool ShadingProgram::compile()
{
const char* vcode = vertex_code_.c_str();
vertex_id_ = glCreateShader(GL_VERTEX_SHADER);
char infoLog[1024];
int success = GL_FALSE;
std::string vertex_code = vertex_;
if (Resource::hasPath(vertex_))
vertex_code = Resource::getText(vertex_);
std::string fragment_code = fragment_;
if (Resource::hasPath(fragment_))
fragment_code = Resource::getText(fragment_);
// VERTEX SHADER
const char* vcode = vertex_code.c_str();
unsigned int vertex_id_ = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_id_, 1, &vcode, NULL);
glCompileShader(vertex_id_);
const char* fcode = fragment_code_.c_str();
fragment_id_ = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_id_, 1, &fcode, NULL);
glCompileShader(fragment_id_);
glGetShaderiv(vertex_id_, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex_id_, 1024, NULL, infoLog);
Log::Warning("Error compiling Vertex ShadingProgram:\n%s", infoLog);
}
else {
// FRAGMENT SHADER
const char* fcode = fragment_code.c_str();
unsigned int fragment_id_ = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_id_, 1, &fcode, NULL);
glCompileShader(fragment_id_);
return checkCompileErr();
}
glGetShaderiv(fragment_id_, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment_id_, 1024, NULL, infoLog);
Log::Warning("Error compiling Fragment ShadingProgram:\n%s", infoLog);
glDeleteShader(vertex_id_);
}
else {
// LINK PROGRAM
void ShadingProgram::link()
{
id_ = glCreateProgram();
glAttachShader(id_, vertex_id_);
glAttachShader(id_, fragment_id_);
glLinkProgram(id_);
checkLinkingErr();
glUseProgram(id_);
glUniform1i(glGetUniformLocation(id_, "iChannel0"), 0);
glUniform1i(glGetUniformLocation(id_, "iChannel1"), 1);
glUseProgram(0);
glDeleteShader(vertex_id_);
vertex_id_ = 0;
glDeleteShader(fragment_id_);
fragment_id_ = 0;
// create new GL Program only if not already done
if (id_ == 0)
id_ = glCreateProgram();
// attach shaders and link
glAttachShader(id_, vertex_id_);
glAttachShader(id_, fragment_id_);
glLinkProgram(id_);
glGetProgramiv(id_, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(id_, 1024, NULL, infoLog);
Log::Warning("Error linking ShadingProgram:\n%s", infoLog);
glDeleteProgram(id_);
id_ = 0;
}
else {
// all good, set default uniforms
glUseProgram(id_);
glUniform1i(glGetUniformLocation(id_, "iChannel0"), 0);
glUniform1i(glGetUniformLocation(id_, "iChannel1"), 1);
}
// done (no more need for shaders)
glUseProgram(0);
glDeleteShader(vertex_id_);
glDeleteShader(fragment_id_);
}
}
// do not compile indefinitely
need_compile_ = false;
// inform of success
return success;
}
void ShadingProgram::use()
{
if (currentProgram_ == nullptr || currentProgram_ != this)
{
currentProgram_ = this;
// first time use ; compile
if (need_compile_)
compile();
// use program
glUseProgram(id_); // NB: if not linked, use 0 as default
// remember (avoid switching program)
currentProgram_ = this;
}
}
@@ -150,6 +180,15 @@ void ShadingProgram::enduse()
currentProgram_ = nullptr ;
}
void ShadingProgram::reset()
{
if (id_ != 0) {
glDeleteProgram(id_);
id_ = 0;
}
ShadingProgram::enduse();
}
template<>
void ShadingProgram::setUniform<int>(const std::string& name, int val) {
glUniform1i(glGetUniformLocation(id_, name.c_str()), val);
@@ -205,34 +244,6 @@ void ShadingProgram::setUniform<glm::mat4>(const std::string& name, glm::mat4 va
// glUniformMatrix4fv(glGetUniformLocation(id_, name.c_str()), 1, GL_FALSE, val);
// }
bool ShadingProgram::checkCompileErr()
{
int success;
char infoLog[1024];
glGetShaderiv(vertex_id_, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex_id_, 1024, NULL, infoLog);
Log::Warning("Error compiling Vertex ShadingProgram:\n%s", infoLog);
}
glGetShaderiv(fragment_id_, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment_id_, 1024, NULL, infoLog);
Log::Warning("Error compiling Fragment ShadingProgram:\n%s", infoLog);
}
return success;
}
void ShadingProgram::checkLinkingErr()
{
int success;
glGetProgramiv(id_, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[1024];
glGetProgramInfoLog(id_, 1024, NULL, infoLog);
Log::Warning("Error linking ShadingProgram:\n%s", infoLog);
}
}
bool Shader::force_blending_opacity = false;
@@ -259,10 +270,6 @@ void Shader::accept(Visitor& v) {
void Shader::use()
{
// initialization on first use
if (!program_->initialized())
program_->init();
// Use program
program_->use();

View File

@@ -13,27 +13,23 @@ class ShadingProgram
{
public:
// create GLSL Program from resource file (if exist) or code of vertex and fragment shaders
ShadingProgram(const std::string& vertex, const std::string& fragment);
ShadingProgram(const std::string& vertex = "", const std::string& fragment = "");
void setShaders(const std::string& vertex, const std::string& fragment);
void init();
bool initialized();
void use();
bool compile();
static void enduse();
void reset();
template<typename T> void setUniform(const std::string& name, T val);
template<typename T> void setUniform(const std::string& name, T val1, T val2);
template<typename T> void setUniform(const std::string& name, T val1, T val2, T val3);
static void enduse();
template<typename T> void setUniform(const std::string& name, T val1, T val2, T val3);
private:
bool checkCompileErr();
void checkLinkingErr();
bool compile();
void link();
unsigned int vertex_id_, fragment_id_, id_;
std::string vertex_code_;
std::string fragment_code_;
std::string vertex_file_;
std::string fragment_file_;
unsigned int id_;
bool need_compile_;
std::string vertex_;
std::string fragment_;
static ShadingProgram *currentProgram_;
};