mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-22 14:37:42 +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
|
||||
rhi.cpp
|
||||
rhi.hpp
|
||||
shader_load_context.cpp
|
||||
shader_load_context.hpp
|
||||
)
|
||||
|
||||
add_subdirectory(gl3_core)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include <glad/gl.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "../shader_load_context.hpp"
|
||||
|
||||
using namespace srb2;
|
||||
using namespace rhi;
|
||||
|
||||
|
|
@ -871,112 +873,82 @@ rhi::Handle<rhi::Pipeline> 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<const char*> 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<GLint>(vert_src_processed.size())};
|
||||
const char* frag_src_arr[1] = {frag_src_processed.c_str()};
|
||||
const GLint frag_src_arr_lens[1] = {static_cast<GLint>(frag_src_processed.size())};
|
||||
// Process vertex shader sources
|
||||
std::vector<const char*> 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<rhi::Pipeline> 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)
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ struct GlCorePlatform
|
|||
virtual ~GlCorePlatform();
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
|||
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 <array>
|
||||
#include <sstream>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "../cxxutil.hpp"
|
||||
#include "../w_wad.h"
|
||||
|
|
@ -28,39 +32,75 @@ void SdlGlCorePlatform::present()
|
|||
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)
|
||||
{
|
||||
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<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);
|
||||
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<const char*>(vertex_lump), vertex_lump_length);
|
||||
std::string fragment_shader(static_cast<const char*>(fragment_lump), fragment_lump_length);
|
||||
std::tuple<std::vector<std::string>, std::vector<std::string>>
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ struct SdlGlCorePlatform final : public GlCorePlatform
|
|||
virtual ~SdlGlCorePlatform();
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue