Route shader creation through renderer GL
This commit is contained in:
342
src/shader.cpp
342
src/shader.cpp
@@ -88,6 +88,125 @@ std::int32_t get_opengl_attrib_location(std::uint32_t program, const char* name)
|
||||
return static_cast<std::int32_t>(glGetAttribLocation(static_cast<GLuint>(program), name));
|
||||
}
|
||||
|
||||
std::uint32_t create_opengl_shader(std::uint32_t stage) noexcept
|
||||
{
|
||||
return static_cast<std::uint32_t>(glCreateShader(static_cast<GLenum>(stage)));
|
||||
}
|
||||
|
||||
void set_opengl_shader_source(
|
||||
std::uint32_t shader,
|
||||
std::int32_t count,
|
||||
const char* const* sources) noexcept
|
||||
{
|
||||
glShaderSource(
|
||||
static_cast<GLuint>(shader),
|
||||
static_cast<GLsizei>(count),
|
||||
reinterpret_cast<const GLchar* const*>(sources),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void compile_opengl_shader(std::uint32_t shader) noexcept
|
||||
{
|
||||
glCompileShader(static_cast<GLuint>(shader));
|
||||
}
|
||||
|
||||
void query_opengl_shader_integer(
|
||||
std::uint32_t shader,
|
||||
std::uint32_t query,
|
||||
std::int32_t* value) noexcept
|
||||
{
|
||||
glGetShaderiv(
|
||||
static_cast<GLuint>(shader),
|
||||
static_cast<GLenum>(query),
|
||||
reinterpret_cast<GLint*>(value));
|
||||
}
|
||||
|
||||
void get_opengl_shader_info_log(
|
||||
std::uint32_t shader,
|
||||
std::int32_t capacity,
|
||||
std::int32_t* length,
|
||||
char* info_log) noexcept
|
||||
{
|
||||
glGetShaderInfoLog(
|
||||
static_cast<GLuint>(shader),
|
||||
static_cast<GLsizei>(capacity),
|
||||
reinterpret_cast<GLsizei*>(length),
|
||||
reinterpret_cast<GLchar*>(info_log));
|
||||
}
|
||||
|
||||
void delete_opengl_shader(std::uint32_t shader) noexcept
|
||||
{
|
||||
glDeleteShader(static_cast<GLuint>(shader));
|
||||
}
|
||||
|
||||
std::uint32_t create_opengl_program() noexcept
|
||||
{
|
||||
return static_cast<std::uint32_t>(glCreateProgram());
|
||||
}
|
||||
|
||||
void attach_opengl_shader(std::uint32_t program, std::uint32_t shader) noexcept
|
||||
{
|
||||
glAttachShader(static_cast<GLuint>(program), static_cast<GLuint>(shader));
|
||||
}
|
||||
|
||||
void link_opengl_program(std::uint32_t program) noexcept
|
||||
{
|
||||
glLinkProgram(static_cast<GLuint>(program));
|
||||
}
|
||||
|
||||
void bind_opengl_attrib_location(std::uint32_t program, std::uint32_t location, const char* name) noexcept
|
||||
{
|
||||
glBindAttribLocation(static_cast<GLuint>(program), static_cast<GLuint>(location), name);
|
||||
}
|
||||
|
||||
void query_opengl_program_integer(
|
||||
std::uint32_t program,
|
||||
std::uint32_t query,
|
||||
std::int32_t* value) noexcept
|
||||
{
|
||||
glGetProgramiv(
|
||||
static_cast<GLuint>(program),
|
||||
static_cast<GLenum>(query),
|
||||
reinterpret_cast<GLint*>(value));
|
||||
}
|
||||
|
||||
void get_opengl_program_info_log(
|
||||
std::uint32_t program,
|
||||
std::int32_t capacity,
|
||||
std::int32_t* length,
|
||||
char* info_log) noexcept
|
||||
{
|
||||
glGetProgramInfoLog(
|
||||
static_cast<GLuint>(program),
|
||||
static_cast<GLsizei>(capacity),
|
||||
reinterpret_cast<GLsizei*>(length),
|
||||
reinterpret_cast<GLchar*>(info_log));
|
||||
}
|
||||
|
||||
void get_opengl_active_uniform(
|
||||
std::uint32_t program,
|
||||
std::uint32_t index,
|
||||
std::int32_t capacity,
|
||||
std::int32_t* length,
|
||||
std::int32_t* size,
|
||||
std::uint32_t* type,
|
||||
char* name) noexcept
|
||||
{
|
||||
glGetActiveUniform(
|
||||
static_cast<GLuint>(program),
|
||||
static_cast<GLuint>(index),
|
||||
static_cast<GLsizei>(capacity),
|
||||
reinterpret_cast<GLsizei*>(length),
|
||||
reinterpret_cast<GLint*>(size),
|
||||
reinterpret_cast<GLenum*>(type),
|
||||
reinterpret_cast<GLchar*>(name));
|
||||
}
|
||||
|
||||
std::int32_t get_opengl_uniform_location(std::uint32_t program, const char* name) noexcept
|
||||
{
|
||||
return static_cast<std::int32_t>(glGetUniformLocation(static_cast<GLuint>(program), name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::map<kShader, Shader> ShaderManager::m_shaders;
|
||||
@@ -247,113 +366,212 @@ bool Shader::create(const std::string& vertex, const std::string& fragment)
|
||||
bool ret = true;
|
||||
App::I->render_task([this, &ret, vertex, fragment]
|
||||
{
|
||||
GLint status;
|
||||
static char infolog[4096];
|
||||
int infolen;
|
||||
const GLchar* source;
|
||||
|
||||
auto vs = glCreateShader(vertex_shader_stage());
|
||||
if (!vs)
|
||||
const auto vertex_shader = pp::renderer::gl::compile_opengl_shader_source(
|
||||
pp::renderer::gl::vertex_shader_stage(),
|
||||
vertex.c_str(),
|
||||
infolog,
|
||||
static_cast<std::int32_t>(sizeof(infolog)),
|
||||
pp::renderer::gl::OpenGlShaderCompileDispatch {
|
||||
.create_shader = create_opengl_shader,
|
||||
.shader_source = set_opengl_shader_source,
|
||||
.compile_shader = compile_opengl_shader,
|
||||
.get_shader_integer = query_opengl_shader_integer,
|
||||
.get_shader_info_log = get_opengl_shader_info_log,
|
||||
});
|
||||
if (!vertex_shader.ok())
|
||||
{
|
||||
ret = false;
|
||||
LOG("Shader::create() vertex compile failed because: %s", vertex_shader.status().message);
|
||||
return;
|
||||
}
|
||||
source = vertex.c_str();
|
||||
glShaderSource(vs, 1, &source, nullptr);
|
||||
glCompileShader(vs);
|
||||
glGetShaderiv(vs, shader_compile_status_query(), &status);
|
||||
glGetShaderInfoLog(vs, sizeof(infolog), &infolen, infolog);
|
||||
if (infolen > 0)
|
||||
if (vertex_shader.value().info_log_length > 0)
|
||||
{
|
||||
LOG("\nVERTEX SHADER: %s", m_path.c_str());
|
||||
parse_error(infolog, vertex);
|
||||
}
|
||||
if (status == 0)
|
||||
if (vertex_shader.value().compile_status == 0)
|
||||
{
|
||||
glDeleteShader(vs);
|
||||
const auto status = pp::renderer::gl::delete_opengl_shader(
|
||||
vertex_shader.value().shader_id,
|
||||
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||
.delete_shader = delete_opengl_shader,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("Shader::create() vertex shader cleanup failed because: %s", status.message);
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
|
||||
auto fs = glCreateShader(fragment_shader_stage());
|
||||
if (!fs)
|
||||
const auto fragment_shader = pp::renderer::gl::compile_opengl_shader_source(
|
||||
pp::renderer::gl::fragment_shader_stage(),
|
||||
fragment.c_str(),
|
||||
infolog,
|
||||
static_cast<std::int32_t>(sizeof(infolog)),
|
||||
pp::renderer::gl::OpenGlShaderCompileDispatch {
|
||||
.create_shader = create_opengl_shader,
|
||||
.shader_source = set_opengl_shader_source,
|
||||
.compile_shader = compile_opengl_shader,
|
||||
.get_shader_integer = query_opengl_shader_integer,
|
||||
.get_shader_info_log = get_opengl_shader_info_log,
|
||||
});
|
||||
if (!fragment_shader.ok())
|
||||
{
|
||||
glDeleteShader(vs);
|
||||
const auto status = pp::renderer::gl::delete_opengl_shader(
|
||||
vertex_shader.value().shader_id,
|
||||
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||
.delete_shader = delete_opengl_shader,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("Shader::create() vertex shader cleanup failed because: %s", status.message);
|
||||
ret = false;
|
||||
LOG("Shader::create() fragment compile failed because: %s", fragment_shader.status().message);
|
||||
return;
|
||||
}
|
||||
source = fragment.c_str();
|
||||
glShaderSource(fs, 1, &source, nullptr);
|
||||
glCompileShader(fs);
|
||||
glGetShaderiv(fs, shader_compile_status_query(), &status);
|
||||
glGetShaderInfoLog(fs, sizeof(infolog), &infolen, infolog);
|
||||
if (infolen > 0)
|
||||
if (fragment_shader.value().info_log_length > 0)
|
||||
{
|
||||
LOG("\nFRAGMENT SHADER: %s", m_path.c_str());
|
||||
parse_error(infolog, fragment);
|
||||
}
|
||||
if (status == 0)
|
||||
if (fragment_shader.value().compile_status == 0)
|
||||
{
|
||||
glDeleteShader(vs);
|
||||
glDeleteShader(fs);
|
||||
const auto vertex_cleanup = pp::renderer::gl::delete_opengl_shader(
|
||||
vertex_shader.value().shader_id,
|
||||
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||
.delete_shader = delete_opengl_shader,
|
||||
});
|
||||
const auto fragment_cleanup = pp::renderer::gl::delete_opengl_shader(
|
||||
fragment_shader.value().shader_id,
|
||||
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||
.delete_shader = delete_opengl_shader,
|
||||
});
|
||||
if (!vertex_cleanup.ok())
|
||||
LOG("Shader::create() vertex shader cleanup failed because: %s", vertex_cleanup.message);
|
||||
if (!fragment_cleanup.ok())
|
||||
LOG("Shader::create() fragment shader cleanup failed because: %s", fragment_cleanup.message);
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
|
||||
auto ps = glCreateProgram();
|
||||
if (!ps)
|
||||
const auto program = pp::renderer::gl::link_opengl_shader_program(
|
||||
vertex_shader.value().shader_id,
|
||||
fragment_shader.value().shader_id,
|
||||
pp::renderer::gl::panopainter_shader_attribute_bindings(),
|
||||
infolog,
|
||||
static_cast<std::int32_t>(sizeof(infolog)),
|
||||
pp::renderer::gl::OpenGlProgramLinkDispatch {
|
||||
.create_program = create_opengl_program,
|
||||
.attach_shader = attach_opengl_shader,
|
||||
.delete_shader = delete_opengl_shader,
|
||||
.link_program = link_opengl_program,
|
||||
.get_attrib_location = get_opengl_attrib_location,
|
||||
.bind_attrib_location = bind_opengl_attrib_location,
|
||||
.get_program_integer = query_opengl_program_integer,
|
||||
.get_program_info_log = get_opengl_program_info_log,
|
||||
});
|
||||
if (!program.ok())
|
||||
{
|
||||
glDeleteShader(vs);
|
||||
glDeleteShader(fs);
|
||||
const auto vertex_cleanup = pp::renderer::gl::delete_opengl_shader(
|
||||
vertex_shader.value().shader_id,
|
||||
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||
.delete_shader = delete_opengl_shader,
|
||||
});
|
||||
const auto fragment_cleanup = pp::renderer::gl::delete_opengl_shader(
|
||||
fragment_shader.value().shader_id,
|
||||
pp::renderer::gl::OpenGlShaderDeleteDispatch {
|
||||
.delete_shader = delete_opengl_shader,
|
||||
});
|
||||
if (!vertex_cleanup.ok())
|
||||
LOG("Shader::create() vertex shader cleanup failed because: %s", vertex_cleanup.message);
|
||||
if (!fragment_cleanup.ok())
|
||||
LOG("Shader::create() fragment shader cleanup failed because: %s", fragment_cleanup.message);
|
||||
ret = false;
|
||||
LOG("Shader::create() program link failed because: %s", program.status().message);
|
||||
return;
|
||||
}
|
||||
glAttachShader(ps, vs);
|
||||
glAttachShader(ps, fs);
|
||||
glDeleteShader(vs);
|
||||
glDeleteShader(fs);
|
||||
|
||||
glLinkProgram(ps);
|
||||
for (const auto& binding : pp::renderer::gl::panopainter_shader_attribute_bindings())
|
||||
{
|
||||
if (glGetAttribLocation(ps, binding.name) != -1)
|
||||
glBindAttribLocation(ps, static_cast<GLuint>(binding.location), binding.name);
|
||||
}
|
||||
|
||||
glLinkProgram(ps);
|
||||
glGetProgramiv(ps, program_link_status_query(), &status);
|
||||
glGetProgramInfoLog(ps, sizeof(infolog), &infolen, infolog);
|
||||
if (infolen > 0)
|
||||
if (program.value().info_log_length > 0)
|
||||
LOG("LINK SHADER: %s\n%s", m_path.c_str(), infolog);
|
||||
if (status == 0)
|
||||
if (program.value().link_status == 0)
|
||||
{
|
||||
glDeleteProgram(ps);
|
||||
const auto status = pp::renderer::gl::delete_opengl_program(
|
||||
program.value().program_id,
|
||||
pp::renderer::gl::OpenGlProgramDeleteDispatch {
|
||||
.use_program = use_opengl_program,
|
||||
.delete_program = delete_opengl_program,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("Shader::create() program cleanup failed because: %s", status.message);
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto cleanup_program = [](std::uint32_t program_id) noexcept {
|
||||
const auto status = pp::renderer::gl::delete_opengl_program(
|
||||
program_id,
|
||||
pp::renderer::gl::OpenGlProgramDeleteDispatch {
|
||||
.use_program = use_opengl_program,
|
||||
.delete_program = delete_opengl_program,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("Shader::create() program cleanup failed because: %s", status.message);
|
||||
};
|
||||
|
||||
// Parse shader uniforms
|
||||
{
|
||||
GLint count;
|
||||
GLint size; // size of the variable
|
||||
GLenum type; // type of the variable (float, vec3 or mat4, etc)
|
||||
const GLsizei bufSize = 64; // maximum name length
|
||||
GLchar name[bufSize]; // variable name in GLSL
|
||||
GLsizei length; // name length
|
||||
glGetProgramiv(ps, active_uniform_count_query(), &count);
|
||||
const auto uniform_count = pp::renderer::gl::query_opengl_program_integer(
|
||||
program.value().program_id,
|
||||
pp::renderer::gl::active_uniform_count_query(),
|
||||
pp::renderer::gl::OpenGlProgramIntegerDispatch {
|
||||
.get_program_integer = query_opengl_program_integer,
|
||||
});
|
||||
if (!uniform_count.ok())
|
||||
{
|
||||
LOG("Shader::create() uniform discovery failed because: %s", uniform_count.status().message);
|
||||
cleanup_program(program.value().program_id);
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
constexpr std::int32_t bufSize = 64; // maximum name length
|
||||
char uniform_name[bufSize]; // variable name in GLSL
|
||||
const auto count = uniform_count.value();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
glGetActiveUniform(ps, (GLuint)i, bufSize, &length, &size, &type, name);
|
||||
name[length] = 0;
|
||||
kShaderUniform id = static_cast<kShaderUniform>(pp::renderer::gl::shader_uniform_id(name));
|
||||
const auto uniform = pp::renderer::gl::get_opengl_active_uniform(
|
||||
program.value().program_id,
|
||||
static_cast<std::uint32_t>(i),
|
||||
uniform_name,
|
||||
bufSize,
|
||||
pp::renderer::gl::OpenGlActiveUniformDispatch {
|
||||
.get_active_uniform = get_opengl_active_uniform,
|
||||
});
|
||||
if (!uniform.ok())
|
||||
{
|
||||
LOG("Shader::create() active uniform discovery failed because: %s", uniform.status().message);
|
||||
cleanup_program(program.value().program_id);
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
kShaderUniform id = static_cast<kShaderUniform>(pp::renderer::gl::shader_uniform_id(uniform_name));
|
||||
if (m_umap.find(id) != m_umap.end())
|
||||
LOG("UNIFORM ALREADY DEFINED: %s", name);
|
||||
m_umap[id] = glGetUniformLocation(ps, name);
|
||||
//printf("Uniform #%d Type: %u Name: %s Loc: %d\n", i, type, name, glGetUniformLocation(ps, name));
|
||||
LOG("UNIFORM ALREADY DEFINED: %s", uniform_name);
|
||||
const auto location = pp::renderer::gl::get_opengl_uniform_location(
|
||||
program.value().program_id,
|
||||
uniform_name,
|
||||
pp::renderer::gl::OpenGlUniformLocationDispatch {
|
||||
.get_uniform_location = get_opengl_uniform_location,
|
||||
});
|
||||
if (!location.ok())
|
||||
{
|
||||
LOG("Shader::create() uniform location failed because: %s", location.status().message);
|
||||
cleanup_program(program.value().program_id);
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
m_umap[id] = location.value();
|
||||
}
|
||||
}
|
||||
|
||||
prog = ps;
|
||||
prog = program.value().program_id;
|
||||
});
|
||||
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user