From a9fcff852d25421024969c6151c10ae62152eaec Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 1 Apr 2023 17:32:34 -0500 Subject: [PATCH] rhi: Rewrite shader loading Multiple shader sources, simpler macro definition, and slightly more data driven. --- src/rhi/CMakeLists.txt | 2 + src/rhi/gl3_core/gl3_core_rhi.cpp | 150 ++++++++++++------------------ src/rhi/gl3_core/gl3_core_rhi.hpp | 2 +- src/rhi/shader_load_context.cpp | 51 ++++++++++ src/rhi/shader_load_context.hpp | 40 ++++++++ src/sdl/rhi_gl3_core_platform.cpp | 84 ++++++++++++----- src/sdl/rhi_gl3_core_platform.hpp | 3 +- 7 files changed, 219 insertions(+), 113 deletions(-) create mode 100644 src/rhi/shader_load_context.cpp create mode 100644 src/rhi/shader_load_context.hpp diff --git a/src/rhi/CMakeLists.txt b/src/rhi/CMakeLists.txt index 4ba10ae5b..d316b2e1d 100644 --- a/src/rhi/CMakeLists.txt +++ b/src/rhi/CMakeLists.txt @@ -2,6 +2,8 @@ target_sources(SRB2SDL2 PRIVATE handle.hpp rhi.cpp rhi.hpp + shader_load_context.cpp + shader_load_context.hpp ) add_subdirectory(gl3_core) diff --git a/src/rhi/gl3_core/gl3_core_rhi.cpp b/src/rhi/gl3_core/gl3_core_rhi.cpp index 7fd4daa7d..8e10545f6 100644 --- a/src/rhi/gl3_core/gl3_core_rhi.cpp +++ b/src/rhi/gl3_core/gl3_core_rhi.cpp @@ -20,6 +20,8 @@ #include #include +#include "../shader_load_context.hpp" + using namespace srb2; using namespace rhi; @@ -871,112 +873,82 @@ rhi::Handle GlCoreRhi::create_pipeline(const PipelineDesc& desc) GLuint program = 0; 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. - // In Khronos Group's brilliance, #version is required to be the first directive, - // but we need to insert #defines in-between. - std::string vert_src_processed; - std::string::size_type string_i = 0; - do + // Process vertex shader sources + std::vector vert_sources; + ShaderLoadContext vert_ctx; + vert_ctx.set_version("150 core"); + for (auto& attribute : desc.vertex_input.attr_layouts) { - std::string::size_type new_i = vert_src.find('\n', string_i); - if (new_i == std::string::npos) + for (auto const& require_attr : reqs.vertex_input.attributes) { - break; - } - 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) + if (require_attr.name == attribute.name && !require_attr.required) { - for (auto const& require_attr : reqs.vertex_input.attributes) - { - 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"); - } - } - } - } + vert_ctx.define(map_vertex_attribute_enable_define(attribute.name)); } } - string_i = new_i + 1; - } while (string_i != std::string::npos); - - std::string frag_src_processed; - string_i = 0; - do + } + for (auto& uniform_group : desc.uniform_input.enabled_uniforms) { - std::string::size_type new_i = frag_src.find('\n', string_i); - if (new_i == std::string::npos) + for (auto& uniform : uniform_group) { - break; - } - 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& req_uni_group : reqs.uniforms.uniform_groups) { - 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 "); - 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"); - } - } + vert_ctx.define(map_uniform_enable_define(uniform)); } } } } - 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()}; - const GLint vert_src_arr_lens[1] = {static_cast(vert_src_processed.size())}; - const char* frag_src_arr[1] = {frag_src_processed.c_str()}; - const GLint frag_src_arr_lens[1] = {static_cast(frag_src_processed.size())}; + // Process vertex shader sources + std::vector frag_sources; + ShaderLoadContext frag_ctx; + 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); - gl_->ShaderSource(vertex, 1, vert_src_arr, vert_src_arr_lens); + gl_->ShaderSource(vertex, vert_sources.size(), vert_sources.data(), NULL); gl_->CompileShader(vertex); GLint is_compiled = 0; gl_->GetShaderiv(vertex, GL_COMPILE_STATUS, &is_compiled); @@ -992,7 +964,7 @@ rhi::Handle GlCoreRhi::create_pipeline(const PipelineDesc& desc) ); } 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_->GetShaderiv(vertex, GL_COMPILE_STATUS, &is_compiled); if (is_compiled == GL_FALSE) diff --git a/src/rhi/gl3_core/gl3_core_rhi.hpp b/src/rhi/gl3_core/gl3_core_rhi.hpp index db39a324c..633e43754 100644 --- a/src/rhi/gl3_core/gl3_core_rhi.hpp +++ b/src/rhi/gl3_core/gl3_core_rhi.hpp @@ -70,7 +70,7 @@ struct GlCorePlatform virtual ~GlCorePlatform(); virtual void present() = 0; - virtual std::tuple find_shader_sources(PipelineProgram program) = 0; + virtual std::tuple, std::vector> find_shader_sources(PipelineProgram program) = 0; virtual Rect get_default_framebuffer_dimensions() = 0; }; diff --git a/src/rhi/shader_load_context.cpp b/src/rhi/shader_load_context.cpp new file mode 100644 index 000000000..45126a91f --- /dev/null +++ b/src/rhi/shader_load_context.cpp @@ -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 + +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 ShaderLoadContext::get_sources_array() +{ + std::vector 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; +} diff --git a/src/rhi/shader_load_context.hpp b/src/rhi/shader_load_context.hpp new file mode 100644 index 000000000..ecd6d26c1 --- /dev/null +++ b/src/rhi/shader_load_context.hpp @@ -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 +#include +#include + +namespace srb2::rhi +{ + +class ShaderLoadContext +{ + std::string version_; + std::string defines_; + std::vector 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 get_sources_array(); +}; + +}; // namespace srb2::rhi + +#endif // __SRB2_RHI_SHADER_LOAD_CONTEXT_HPP__ diff --git a/src/sdl/rhi_gl3_core_platform.cpp b/src/sdl/rhi_gl3_core_platform.cpp index 5de7eef70..79351d73e 100644 --- a/src/sdl/rhi_gl3_core_platform.cpp +++ b/src/sdl/rhi_gl3_core_platform.cpp @@ -9,7 +9,11 @@ #include "rhi_gl3_core_platform.hpp" +#include +#include + #include +#include #include "../cxxutil.hpp" #include "../w_wad.h" @@ -28,39 +32,75 @@ void SdlGlCorePlatform::present() SDL_GL_SwapWindow(window); } -std::tuple 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) { case rhi::PipelineProgram::kUnshaded: - vertex_lump_name = "rhi_glcore_vertex_unshaded"; - fragment_lump_name = "rhi_glcore_fragment_unshaded"; - break; + return "unshaded"; case rhi::PipelineProgram::kUnshadedPaletted: - vertex_lump_name = "rhi_glcore_vertex_unshadedpaletted"; - fragment_lump_name = "rhi_glcore_fragment_unshadedpaletted"; - break; + return "unshadedpaletted"; case rhi::PipelineProgram::kPostprocessWipe: - vertex_lump_name = "rhi_glcore_vertex_postprocesswipe"; - fragment_lump_name = "rhi_glcore_fragment_postprocesswipe"; - break; + return "postprocesswipe"; default: - std::terminate(); + return ""; + } +} + +static std::array 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 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(glsllist_lump), glsllist_lump_length)); + std::vector 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(source_lump), source_lump_length); } - lumpnum_t vertex_lump_num = W_GetNumForLongName(vertex_lump_name); - 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); + return sources; +} - std::string vertex_shader(static_cast(vertex_lump), vertex_lump_length); - std::string fragment_shader(static_cast(fragment_lump), fragment_lump_length); +std::tuple, std::vector> +SdlGlCorePlatform::find_shader_sources(rhi::PipelineProgram program) +{ + std::array glsllist_names = glsllist_lump_names(program); - return std::make_tuple(std::move(vertex_shader), std::move(fragment_shader)); + std::vector vertex_sources = get_sources_from_glsllist_lump(glsllist_names[0].c_str()); + std::vector 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() diff --git a/src/sdl/rhi_gl3_core_platform.hpp b/src/sdl/rhi_gl3_core_platform.hpp index 9522e4ba4..cebd8f304 100644 --- a/src/sdl/rhi_gl3_core_platform.hpp +++ b/src/sdl/rhi_gl3_core_platform.hpp @@ -25,7 +25,8 @@ struct SdlGlCorePlatform final : public GlCorePlatform virtual ~SdlGlCorePlatform(); virtual void present() override; - virtual std::tuple find_shader_sources(PipelineProgram program) override; + virtual std::tuple, std::vector> + find_shader_sources(PipelineProgram program) override; virtual Rect get_default_framebuffer_dimensions() override; };