mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-04-27 12:31:54 +00:00
rhi: Rewrite shader loading
Multiple shader sources, simpler macro definition, and slightly more data driven.
This commit is contained in:
parent
171a285caa
commit
a9fcff852d
7 changed files with 219 additions and 113 deletions
|
|
@ -2,6 +2,8 @@ target_sources(SRB2SDL2 PRIVATE
|
||||||
handle.hpp
|
handle.hpp
|
||||||
rhi.cpp
|
rhi.cpp
|
||||||
rhi.hpp
|
rhi.hpp
|
||||||
|
shader_load_context.cpp
|
||||||
|
shader_load_context.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(gl3_core)
|
add_subdirectory(gl3_core)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
#include <glad/gl.h>
|
#include <glad/gl.h>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
#include "../shader_load_context.hpp"
|
||||||
|
|
||||||
using namespace srb2;
|
using namespace srb2;
|
||||||
using namespace rhi;
|
using namespace rhi;
|
||||||
|
|
||||||
|
|
@ -871,112 +873,82 @@ rhi::Handle<rhi::Pipeline> GlCoreRhi::create_pipeline(const PipelineDesc& desc)
|
||||||
GLuint program = 0;
|
GLuint program = 0;
|
||||||
GlCorePipeline pipeline;
|
GlCorePipeline pipeline;
|
||||||
|
|
||||||
auto [vert_src, frag_src] = platform_->find_shader_sources(desc.program);
|
auto [vert_srcs, frag_srcs] = platform_->find_shader_sources(desc.program);
|
||||||
|
|
||||||
// TODO make use of multiple source files.
|
// Process vertex shader sources
|
||||||
// In Khronos Group's brilliance, #version is required to be the first directive,
|
std::vector<const char*> vert_sources;
|
||||||
// but we need to insert #defines in-between.
|
ShaderLoadContext vert_ctx;
|
||||||
std::string vert_src_processed;
|
vert_ctx.set_version("150 core");
|
||||||
std::string::size_type string_i = 0;
|
for (auto& attribute : desc.vertex_input.attr_layouts)
|
||||||
do
|
|
||||||
{
|
{
|
||||||
std::string::size_type new_i = vert_src.find('\n', string_i);
|
for (auto const& require_attr : reqs.vertex_input.attributes)
|
||||||
if (new_i == std::string::npos)
|
|
||||||
{
|
{
|
||||||
break;
|
if (require_attr.name == attribute.name && !require_attr.required)
|
||||||
}
|
|
||||||
std::string_view line_view(vert_src.c_str() + string_i, new_i - string_i + 1);
|
|
||||||
vert_src_processed.append(line_view);
|
|
||||||
if (line_view.rfind("#version ", 0) == 0)
|
|
||||||
{
|
|
||||||
for (auto& attribute : desc.vertex_input.attr_layouts)
|
|
||||||
{
|
{
|
||||||
for (auto const& require_attr : reqs.vertex_input.attributes)
|
vert_ctx.define(map_vertex_attribute_enable_define(attribute.name));
|
||||||
{
|
|
||||||
if (require_attr.name == attribute.name && !require_attr.required)
|
|
||||||
{
|
|
||||||
vert_src_processed.append("#define ");
|
|
||||||
vert_src_processed.append(map_vertex_attribute_enable_define(attribute.name));
|
|
||||||
vert_src_processed.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto& uniform_group : desc.uniform_input.enabled_uniforms)
|
|
||||||
{
|
|
||||||
for (auto& uniform : uniform_group)
|
|
||||||
{
|
|
||||||
for (auto const& req_uni_group : reqs.uniforms.uniform_groups)
|
|
||||||
{
|
|
||||||
for (auto const& req_uni : req_uni_group)
|
|
||||||
{
|
|
||||||
if (req_uni.name == uniform && !req_uni.required)
|
|
||||||
{
|
|
||||||
vert_src_processed.append("#define ");
|
|
||||||
vert_src_processed.append(map_uniform_enable_define(uniform));
|
|
||||||
vert_src_processed.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
string_i = new_i + 1;
|
}
|
||||||
} while (string_i != std::string::npos);
|
for (auto& uniform_group : desc.uniform_input.enabled_uniforms)
|
||||||
|
|
||||||
std::string frag_src_processed;
|
|
||||||
string_i = 0;
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
std::string::size_type new_i = frag_src.find('\n', string_i);
|
for (auto& uniform : uniform_group)
|
||||||
if (new_i == std::string::npos)
|
|
||||||
{
|
{
|
||||||
break;
|
for (auto const& req_uni_group : reqs.uniforms.uniform_groups)
|
||||||
}
|
|
||||||
std::string_view line_view(frag_src.c_str() + string_i, new_i - string_i + 1);
|
|
||||||
frag_src_processed.append(line_view);
|
|
||||||
if (line_view.rfind("#version ", 0) == 0)
|
|
||||||
{
|
|
||||||
for (auto& sampler : desc.sampler_input.enabled_samplers)
|
|
||||||
{
|
{
|
||||||
for (auto const& require_sampler : reqs.samplers.samplers)
|
for (auto const& req_uni : req_uni_group)
|
||||||
{
|
{
|
||||||
if (sampler == require_sampler.name && !require_sampler.required)
|
if (req_uni.name == uniform && !req_uni.required)
|
||||||
{
|
{
|
||||||
frag_src_processed.append("#define ");
|
vert_ctx.define(map_uniform_enable_define(uniform));
|
||||||
frag_src_processed.append(map_sampler_enable_define(sampler));
|
|
||||||
frag_src_processed.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto& uniform_group : desc.uniform_input.enabled_uniforms)
|
|
||||||
{
|
|
||||||
for (auto& uniform : uniform_group)
|
|
||||||
{
|
|
||||||
for (auto const& req_uni_group : reqs.uniforms.uniform_groups)
|
|
||||||
{
|
|
||||||
for (auto const& req_uni : req_uni_group)
|
|
||||||
{
|
|
||||||
if (req_uni.name == uniform && !req_uni.required)
|
|
||||||
{
|
|
||||||
frag_src_processed.append("#define ");
|
|
||||||
frag_src_processed.append(map_uniform_enable_define(uniform));
|
|
||||||
frag_src_processed.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
string_i = new_i + 1;
|
}
|
||||||
} while (string_i != std::string::npos);
|
for (auto& src : vert_srcs)
|
||||||
|
{
|
||||||
|
vert_ctx.add_source(std::move(src));
|
||||||
|
}
|
||||||
|
vert_sources = vert_ctx.get_sources_array();
|
||||||
|
|
||||||
const char* vert_src_arr[1] = {vert_src_processed.c_str()};
|
// Process vertex shader sources
|
||||||
const GLint vert_src_arr_lens[1] = {static_cast<GLint>(vert_src_processed.size())};
|
std::vector<const char*> frag_sources;
|
||||||
const char* frag_src_arr[1] = {frag_src_processed.c_str()};
|
ShaderLoadContext frag_ctx;
|
||||||
const GLint frag_src_arr_lens[1] = {static_cast<GLint>(frag_src_processed.size())};
|
frag_ctx.set_version("150 core");
|
||||||
|
for (auto& sampler : desc.sampler_input.enabled_samplers)
|
||||||
|
{
|
||||||
|
for (auto const& require_sampler : reqs.samplers.samplers)
|
||||||
|
{
|
||||||
|
if (sampler == require_sampler.name && !require_sampler.required)
|
||||||
|
{
|
||||||
|
frag_ctx.define(map_sampler_enable_define(sampler));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& uniform_group : desc.uniform_input.enabled_uniforms)
|
||||||
|
{
|
||||||
|
for (auto& uniform : uniform_group)
|
||||||
|
{
|
||||||
|
for (auto const& req_uni_group : reqs.uniforms.uniform_groups)
|
||||||
|
{
|
||||||
|
for (auto const& req_uni : req_uni_group)
|
||||||
|
{
|
||||||
|
if (req_uni.name == uniform && !req_uni.required)
|
||||||
|
{
|
||||||
|
frag_ctx.define(map_uniform_enable_define(uniform));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& src : frag_srcs)
|
||||||
|
{
|
||||||
|
frag_ctx.add_source(std::move(src));
|
||||||
|
}
|
||||||
|
frag_sources = frag_ctx.get_sources_array();
|
||||||
|
|
||||||
vertex = gl_->CreateShader(GL_VERTEX_SHADER);
|
vertex = gl_->CreateShader(GL_VERTEX_SHADER);
|
||||||
gl_->ShaderSource(vertex, 1, vert_src_arr, vert_src_arr_lens);
|
gl_->ShaderSource(vertex, vert_sources.size(), vert_sources.data(), NULL);
|
||||||
gl_->CompileShader(vertex);
|
gl_->CompileShader(vertex);
|
||||||
GLint is_compiled = 0;
|
GLint is_compiled = 0;
|
||||||
gl_->GetShaderiv(vertex, GL_COMPILE_STATUS, &is_compiled);
|
gl_->GetShaderiv(vertex, GL_COMPILE_STATUS, &is_compiled);
|
||||||
|
|
@ -992,7 +964,7 @@ rhi::Handle<rhi::Pipeline> GlCoreRhi::create_pipeline(const PipelineDesc& desc)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fragment = gl_->CreateShader(GL_FRAGMENT_SHADER);
|
fragment = gl_->CreateShader(GL_FRAGMENT_SHADER);
|
||||||
gl_->ShaderSource(fragment, 1, frag_src_arr, frag_src_arr_lens);
|
gl_->ShaderSource(fragment, frag_sources.size(), frag_sources.data(), NULL);
|
||||||
gl_->CompileShader(fragment);
|
gl_->CompileShader(fragment);
|
||||||
gl_->GetShaderiv(vertex, GL_COMPILE_STATUS, &is_compiled);
|
gl_->GetShaderiv(vertex, GL_COMPILE_STATUS, &is_compiled);
|
||||||
if (is_compiled == GL_FALSE)
|
if (is_compiled == GL_FALSE)
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ struct GlCorePlatform
|
||||||
virtual ~GlCorePlatform();
|
virtual ~GlCorePlatform();
|
||||||
|
|
||||||
virtual void present() = 0;
|
virtual void present() = 0;
|
||||||
virtual std::tuple<std::string, std::string> find_shader_sources(PipelineProgram program) = 0;
|
virtual std::tuple<std::vector<std::string>, std::vector<std::string>> find_shader_sources(PipelineProgram program) = 0;
|
||||||
virtual Rect get_default_framebuffer_dimensions() = 0;
|
virtual Rect get_default_framebuffer_dimensions() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
51
src/rhi/shader_load_context.cpp
Normal file
51
src/rhi/shader_load_context.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
// SONIC ROBO BLAST 2
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
||||||
|
//
|
||||||
|
// This program is free software distributed under the
|
||||||
|
// terms of the GNU General Public License, version 2.
|
||||||
|
// See the 'LICENSE' file for more details.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "shader_load_context.hpp"
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
|
using namespace srb2;
|
||||||
|
using namespace rhi;
|
||||||
|
|
||||||
|
ShaderLoadContext::ShaderLoadContext() = default;
|
||||||
|
|
||||||
|
void ShaderLoadContext::set_version(std::string_view version)
|
||||||
|
{
|
||||||
|
version_ = fmt::format("#version {}\n", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderLoadContext::add_source(const std::string& source)
|
||||||
|
{
|
||||||
|
sources_.push_back(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderLoadContext::add_source(std::string&& source)
|
||||||
|
{
|
||||||
|
sources_.push_back(std::move(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderLoadContext::define(std::string_view name)
|
||||||
|
{
|
||||||
|
defines_.append(fmt::format("#define {}\n", name));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> ShaderLoadContext::get_sources_array()
|
||||||
|
{
|
||||||
|
std::vector<const char*> ret;
|
||||||
|
|
||||||
|
ret.push_back(version_.c_str());
|
||||||
|
ret.push_back(defines_.c_str());
|
||||||
|
for (auto& source : sources_)
|
||||||
|
{
|
||||||
|
ret.push_back(source.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
40
src/rhi/shader_load_context.hpp
Normal file
40
src/rhi/shader_load_context.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
// SONIC ROBO BLAST 2
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
||||||
|
//
|
||||||
|
// This program is free software distributed under the
|
||||||
|
// terms of the GNU General Public License, version 2.
|
||||||
|
// See the 'LICENSE' file for more details.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef __SRB2_RHI_SHADER_LOAD_CONTEXT_HPP__
|
||||||
|
#define __SRB2_RHI_SHADER_LOAD_CONTEXT_HPP__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace srb2::rhi
|
||||||
|
{
|
||||||
|
|
||||||
|
class ShaderLoadContext
|
||||||
|
{
|
||||||
|
std::string version_;
|
||||||
|
std::string defines_;
|
||||||
|
std::vector<std::string> sources_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShaderLoadContext();
|
||||||
|
|
||||||
|
void set_version(std::string_view version);
|
||||||
|
void add_source(const std::string& source);
|
||||||
|
void add_source(std::string&& source);
|
||||||
|
|
||||||
|
void define(std::string_view name);
|
||||||
|
|
||||||
|
std::vector<const char*> get_sources_array();
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace srb2::rhi
|
||||||
|
|
||||||
|
#endif // __SRB2_RHI_SHADER_LOAD_CONTEXT_HPP__
|
||||||
|
|
@ -9,7 +9,11 @@
|
||||||
|
|
||||||
#include "rhi_gl3_core_platform.hpp"
|
#include "rhi_gl3_core_platform.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include "../cxxutil.hpp"
|
#include "../cxxutil.hpp"
|
||||||
#include "../w_wad.h"
|
#include "../w_wad.h"
|
||||||
|
|
@ -28,39 +32,75 @@ void SdlGlCorePlatform::present()
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::string, std::string> SdlGlCorePlatform::find_shader_sources(rhi::PipelineProgram program)
|
static constexpr const char* pipeline_lump_slug(rhi::PipelineProgram program)
|
||||||
{
|
{
|
||||||
const char* vertex_lump_name = nullptr;
|
|
||||||
const char* fragment_lump_name = nullptr;
|
|
||||||
switch (program)
|
switch (program)
|
||||||
{
|
{
|
||||||
case rhi::PipelineProgram::kUnshaded:
|
case rhi::PipelineProgram::kUnshaded:
|
||||||
vertex_lump_name = "rhi_glcore_vertex_unshaded";
|
return "unshaded";
|
||||||
fragment_lump_name = "rhi_glcore_fragment_unshaded";
|
|
||||||
break;
|
|
||||||
case rhi::PipelineProgram::kUnshadedPaletted:
|
case rhi::PipelineProgram::kUnshadedPaletted:
|
||||||
vertex_lump_name = "rhi_glcore_vertex_unshadedpaletted";
|
return "unshadedpaletted";
|
||||||
fragment_lump_name = "rhi_glcore_fragment_unshadedpaletted";
|
|
||||||
break;
|
|
||||||
case rhi::PipelineProgram::kPostprocessWipe:
|
case rhi::PipelineProgram::kPostprocessWipe:
|
||||||
vertex_lump_name = "rhi_glcore_vertex_postprocesswipe";
|
return "postprocesswipe";
|
||||||
fragment_lump_name = "rhi_glcore_fragment_postprocesswipe";
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
std::terminate();
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::array<std::string, 2> glsllist_lump_names(rhi::PipelineProgram program)
|
||||||
|
{
|
||||||
|
const char* pipeline_slug = pipeline_lump_slug(program);
|
||||||
|
|
||||||
|
std::string vertex_list_name = fmt::format("rhi_glsllist_{}_vertex", pipeline_slug);
|
||||||
|
std::string fragment_list_name = fmt::format("rhi_glsllist_{}_fragment", pipeline_slug);
|
||||||
|
|
||||||
|
return {std::move(vertex_list_name), std::move(fragment_list_name)};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> get_sources_from_glsllist_lump(const char* lumpname)
|
||||||
|
{
|
||||||
|
lumpnum_t glsllist_lump_num = W_GetNumForLongName(lumpname);
|
||||||
|
void* glsllist_lump = W_CacheLumpNum(glsllist_lump_num, PU_CACHE);
|
||||||
|
size_t glsllist_lump_length = W_LumpLength(glsllist_lump_num);
|
||||||
|
|
||||||
|
std::istringstream glsllist(std::string(static_cast<const char*>(glsllist_lump), glsllist_lump_length));
|
||||||
|
std::vector<std::string> sources;
|
||||||
|
for (std::string line; std::getline(glsllist, line); )
|
||||||
|
{
|
||||||
|
if (line.empty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line[0] == '#')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.back() == '\r')
|
||||||
|
{
|
||||||
|
line.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
lumpnum_t source_lump_num = W_GetNumForLongName(line.c_str());
|
||||||
|
void* source_lump = W_CacheLumpNum(source_lump_num, PU_CACHE);
|
||||||
|
size_t source_lump_length = W_LumpLength(source_lump_num);
|
||||||
|
|
||||||
|
sources.emplace_back(static_cast<const char*>(source_lump), source_lump_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
lumpnum_t vertex_lump_num = W_GetNumForLongName(vertex_lump_name);
|
return sources;
|
||||||
lumpnum_t fragment_lump_num = W_GetNumForLongName(fragment_lump_name);
|
}
|
||||||
size_t vertex_lump_length = W_LumpLength(vertex_lump_num);
|
|
||||||
size_t fragment_lump_length = W_LumpLength(fragment_lump_num);
|
|
||||||
void* vertex_lump = W_CacheLumpNum(vertex_lump_num, PU_CACHE);
|
|
||||||
void* fragment_lump = W_CacheLumpNum(fragment_lump_num, PU_CACHE);
|
|
||||||
|
|
||||||
std::string vertex_shader(static_cast<const char*>(vertex_lump), vertex_lump_length);
|
std::tuple<std::vector<std::string>, std::vector<std::string>>
|
||||||
std::string fragment_shader(static_cast<const char*>(fragment_lump), fragment_lump_length);
|
SdlGlCorePlatform::find_shader_sources(rhi::PipelineProgram program)
|
||||||
|
{
|
||||||
|
std::array<std::string, 2> glsllist_names = glsllist_lump_names(program);
|
||||||
|
|
||||||
return std::make_tuple(std::move(vertex_shader), std::move(fragment_shader));
|
std::vector<std::string> vertex_sources = get_sources_from_glsllist_lump(glsllist_names[0].c_str());
|
||||||
|
std::vector<std::string> fragment_sources = get_sources_from_glsllist_lump(glsllist_names[1].c_str());
|
||||||
|
|
||||||
|
return std::make_tuple(std::move(vertex_sources), std::move(fragment_sources));
|
||||||
}
|
}
|
||||||
|
|
||||||
rhi::Rect SdlGlCorePlatform::get_default_framebuffer_dimensions()
|
rhi::Rect SdlGlCorePlatform::get_default_framebuffer_dimensions()
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ struct SdlGlCorePlatform final : public GlCorePlatform
|
||||||
virtual ~SdlGlCorePlatform();
|
virtual ~SdlGlCorePlatform();
|
||||||
|
|
||||||
virtual void present() override;
|
virtual void present() override;
|
||||||
virtual std::tuple<std::string, std::string> find_shader_sources(PipelineProgram program) override;
|
virtual std::tuple<std::vector<std::string>, std::vector<std::string>>
|
||||||
|
find_shader_sources(PipelineProgram program) override;
|
||||||
virtual Rect get_default_framebuffer_dimensions() override;
|
virtual Rect get_default_framebuffer_dimensions() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue