Merge branch 'rhi-refactoring' into 'master'

RHI Refactors

See merge request KartKrew/Kart!2486
This commit is contained in:
Eidolon 2024-11-02 17:29:54 +00:00
commit 37f70cb0a2
40 changed files with 1146 additions and 2120 deletions

View file

@ -319,7 +319,7 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
#endif
static void refresh_wipe_screen_texture(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, rhi::Handle<rhi::Texture>& tex)
static void refresh_wipe_screen_texture(rhi::Rhi& rhi, rhi::Handle<rhi::Texture>& tex)
{
bool recreate = false;
if (!tex)
@ -371,24 +371,17 @@ void F_WipeStartScreen(void)
return;
}
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
if (!ctx)
{
return;
}
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
refresh_wipe_screen_texture(*rhi, ctx, hw_state->wipe_frames.start);
refresh_wipe_screen_texture(*rhi, hw_state->wipe_frames.start);
hw_state->twodee_renderer->flush(*rhi, ctx, g_2d);
hw_state->twodee_renderer->flush(*rhi, g_2d);
rhi::Rect dst_region = {0, 0, static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height)};
rhi::TextureDetails backbuf_deets = rhi->get_texture_details(hw_state->backbuffer->color());
dst_region.w = std::min(dst_region.w, backbuf_deets.width);
dst_region.h = std::min(dst_region.h, backbuf_deets.height);
rhi->copy_framebuffer_to_texture(ctx, hw_state->wipe_frames.start, dst_region, dst_region);
rhi->copy_framebuffer_to_texture(hw_state->wipe_frames.start, dst_region, dst_region);
I_FinishUpdate();
#endif
@ -414,29 +407,22 @@ void F_WipeEndScreen(void)
return;
}
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
if (!ctx)
{
return;
}
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
refresh_wipe_screen_texture(*rhi, ctx, hw_state->wipe_frames.end);
refresh_wipe_screen_texture(*rhi, hw_state->wipe_frames.end);
hw_state->twodee_renderer->flush(*rhi, ctx, g_2d);
hw_state->twodee_renderer->flush(*rhi, g_2d);
rhi::Rect dst_region = {0, 0, static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height)};
rhi::TextureDetails backbuf_deets = rhi->get_texture_details(hw_state->backbuffer->color());
dst_region.w = std::min(dst_region.w, backbuf_deets.width);
dst_region.h = std::min(dst_region.h, backbuf_deets.height);
rhi->copy_framebuffer_to_texture(ctx, hw_state->wipe_frames.end, dst_region, dst_region);
rhi->copy_framebuffer_to_texture(hw_state->wipe_frames.end, dst_region, dst_region);
hw_state->blit_rect->set_output(0, 0, dst_region.w, dst_region.h, false, true);
rhi::TextureDetails start_deets = rhi->get_texture_details(hw_state->wipe_frames.start);
hw_state->blit_rect->set_texture(hw_state->wipe_frames.start, start_deets.width, start_deets.height);
hw_state->blit_rect->draw(*rhi, ctx);
hw_state->blit_rect->draw(*rhi);
I_FinishUpdate();
#endif
@ -535,7 +521,6 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col
g_wipeencorewiggle = 0;
}
rhi::Rhi* rhi = srb2::sys::get_rhi(srb2::sys::g_current_rhi);
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
if (reverse)
@ -550,7 +535,7 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col
}
hw_state->wipe->set_target_size(static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
hw_state->wipe->draw(*rhi, ctx);
hw_state->wipe->draw(*rhi);
}
I_OsPolling();

View file

@ -5,14 +5,10 @@ target_sources(SRB2SDL2 PRIVATE
blit_rect.cpp
blit_rect.hpp
hardware_state.hpp
pass_imgui.cpp
pass_imgui.hpp
pass_manager.cpp
pass_manager.hpp
imgui_renderer.cpp
imgui_renderer.hpp
pass_resource_managers.cpp
pass_resource_managers.hpp
pass.cpp
pass.hpp
patch_atlas.cpp
patch_atlas.hpp
postprocess_wipe.cpp

View file

@ -10,11 +10,14 @@
#include "blit_postimg_screens.hpp"
#include <cstddef>
#include <glm/mat3x3.hpp>
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <tcb/span.hpp>
#include "../p_tick.h"
#include "../i_time.h"
@ -36,34 +39,6 @@ struct BlitVertex
};
} // namespace
static const PipelineDesc kPostimgPipelineDesc =
{
PipelineProgram::kPostimg,
{{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}},
{{{{UniformName::kTime, UniformName::kProjection, UniformName::kModelView, UniformName::kTexCoord0Transform, UniformName::kTexCoord0Min, UniformName::kTexCoord0Max, UniformName::kPostimgWater, UniformName::kPostimgHeat}}}},
{{SamplerName::kSampler0}},
std::nullopt,
{std::nullopt, {true, true, true, true}},
PrimitiveType::kTriangles,
CullMode::kNone,
FaceWinding::kCounterClockwise,
{0.0, 0.0, 0.0, 1.0}
};
static const PipelineDesc kPostimgIndexedPipelineDesc =
{
PipelineProgram::kPostimg,
{{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}},
{{{{UniformName::kTime, UniformName::kProjection, UniformName::kModelView, UniformName::kTexCoord0Transform, UniformName::kTexCoord0Min, UniformName::kTexCoord0Max, UniformName::kPostimgWater, UniformName::kPostimgHeat}}}},
{{SamplerName::kSampler0, SamplerName::kSampler1}},
std::nullopt,
{std::nullopt, {true, true, true, true}},
PrimitiveType::kTriangles,
CullMode::kNone,
FaceWinding::kCounterClockwise,
{0.0, 0.0, 0.0, 1.0}
};
static const BlitVertex kVerts[] =
{{-.5f, -.5f, 0.f, 0.f, 0.f}, {.5f, -.5f, 0.f, 1.f, 0.f}, {-.5f, .5f, 0.f, 0.f, 1.f}, {.5f, .5f, 0.f, 1.f, 1.f}};
@ -99,105 +74,15 @@ BlitPostimgScreens::BlitPostimgScreens(PaletteManager* palette_mgr)
{
}
void BlitPostimgScreens::draw(Rhi& rhi, Handle<GraphicsContext> ctx)
void BlitPostimgScreens::draw(Rhi& rhi)
{
prepass(rhi);
transfer(rhi, ctx);
for (uint32_t i = 0; i < screens_; i++)
{
BlitPostimgScreens::ScreenData& data = screen_data_[i];
rhi.bind_pipeline(ctx, data.pipeline);
rhi.set_viewport(ctx, get_screen_viewport(i, screens_, target_width_, target_height_));
rhi.bind_uniform_set(ctx, 0, data.uniform_set);
rhi.bind_binding_set(ctx, data.binding_set);
rhi.bind_index_buffer(ctx, quad_ibo_);
rhi.draw_indexed(ctx, 6, 0);
}
}
void BlitPostimgScreens::prepass(Rhi& rhi)
{
if (!renderpass_)
{
renderpass_ = rhi.create_render_pass(
{
false,
AttachmentLoadOp::kClear,
AttachmentStoreOp::kStore,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare,
AttachmentLoadOp::kDontCare,
AttachmentStoreOp::kDontCare
}
);
}
if (!pipeline_)
{
pipeline_ = rhi.create_pipeline(kPostimgPipelineDesc);
}
if (!indexed_pipeline_)
{
indexed_pipeline_ = rhi.create_pipeline(kPostimgIndexedPipelineDesc);
}
if (!quad_vbo_)
{
quad_vbo_ = rhi.create_buffer({sizeof(kVerts), BufferType::kVertexBuffer, BufferUsage::kImmutable});
upload_quad_buffer_ = true;
}
if (!quad_ibo_)
{
quad_ibo_ = rhi.create_buffer({sizeof(kIndices), BufferType::kIndexBuffer, BufferUsage::kImmutable});
upload_quad_buffer_ = true;
}
screen_data_.clear();
}
void BlitPostimgScreens::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
{
// Upload needed buffers
if (upload_quad_buffer_)
{
rhi.update_buffer(ctx, quad_vbo_, 0, tcb::as_bytes(tcb::span(kVerts)));
rhi.update_buffer(ctx, quad_ibo_, 0, tcb::as_bytes(tcb::span(kIndices)));
upload_quad_buffer_ = false;
}
transfer(rhi);
for (uint32_t i = 0; i < screens_; i++)
{
BlitPostimgScreens::ScreenConfig& screen_config = screen_configs_[i];
BlitPostimgScreens::ScreenData data {};
if (screen_config.indexed)
{
data.pipeline = indexed_pipeline_;
}
else
{
data.pipeline = pipeline_;
}
VertexAttributeBufferBinding vertex_bindings[] = {{0, quad_vbo_}};
TextureBinding sampler_bindings[] =
{
{SamplerName::kSampler0, screen_config.source},
{SamplerName::kSampler1, palette_mgr_->palette()}
};
data.binding_set = rhi.create_binding_set(
ctx,
data.pipeline,
{
vertex_bindings,
tcb::span(sampler_bindings, screen_config.indexed ? 2 : 1)
}
);
BlitPostimgScreens::ScreenData& data = screen_data_[i];
glm::mat4 projection = glm::scale(glm::identity<glm::mat4>(), glm::vec3(2.f, -2.f, 1.f));
glm::mat4 modelview = glm::identity<glm::mat4>();
@ -222,19 +107,95 @@ void BlitPostimgScreens::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
glm::vec2 texcoord_min = screen_config.uv_offset;
glm::vec2 texcoord_max = screen_config.uv_offset + screen_config.uv_size;
UniformVariant uniforms[] =
{
static_cast<float>(leveltime),
projection,
modelview,
texcoord_transform,
texcoord_min,
texcoord_max,
screen_config.post.water,
screen_config.post.heat
};
RasterizerStateDesc r_state {};
r_state.cull = CullMode::kNone;
data.uniform_set = rhi.create_uniform_set(ctx, {uniforms});
rhi.bind_program(data.program);
rhi.set_rasterizer_state(r_state);
rhi.set_viewport(get_screen_viewport(i, screens_, target_width_, target_height_));
rhi.bind_vertex_attrib("a_position", quad_vbo_, rhi::VertexAttributeFormat::kFloat3, offsetof(BlitVertex, x), sizeof(BlitVertex));
rhi.bind_vertex_attrib("a_texcoord0", quad_vbo_, rhi::VertexAttributeFormat::kFloat2, offsetof(BlitVertex, u), sizeof(BlitVertex));
rhi.bind_index_buffer(quad_ibo_);
rhi.set_uniform("u_time", static_cast<float>(leveltime));
rhi.set_uniform("u_projection", projection);
rhi.set_uniform("u_modelview", modelview);
rhi.set_uniform("u_texcoord0_transform", texcoord_transform);
rhi.set_uniform("u_texcoord0_min", texcoord_min);
rhi.set_uniform("u_texcoord0_max", texcoord_max);
rhi.set_uniform("u_postimg_water", screen_config.post.water);
rhi.set_uniform("u_postimg_heat", screen_config.post.heat);
rhi.set_sampler("s_sampler0", 0, screen_config.source);
if (screen_config.indexed)
{
rhi.set_sampler("s_sampler1", 1, palette_mgr_->palette());
}
rhi.draw_indexed(6, 0);
}
}
void BlitPostimgScreens::prepass(Rhi& rhi)
{
if (!program_)
{
static const char* defines[1] = {
"ENABLE_S_SAMPLER0"
};
ProgramDesc desc {};
desc.name = "postimg";
desc.defines = tcb::make_span(defines);
program_ = rhi.create_program(desc);
}
if (!indexed_program_)
{
static const char* defines[2] = {
"ENABLE_S_SAMPLER0",
"ENABLE_S_SAMPLER1"
};
ProgramDesc desc {};
desc.name = "postimg";
desc.defines = tcb::make_span(defines);
program_ = rhi.create_program(desc);
}
if (!quad_vbo_)
{
quad_vbo_ = rhi.create_buffer({sizeof(kVerts), BufferType::kVertexBuffer, BufferUsage::kImmutable});
upload_quad_buffer_ = true;
}
if (!quad_ibo_)
{
quad_ibo_ = rhi.create_buffer({sizeof(kIndices), BufferType::kIndexBuffer, BufferUsage::kImmutable});
upload_quad_buffer_ = true;
}
screen_data_.clear();
}
void BlitPostimgScreens::transfer(Rhi& rhi)
{
// Upload needed buffers
if (upload_quad_buffer_)
{
rhi.update_buffer(quad_vbo_, 0, tcb::as_bytes(tcb::span(kVerts)));
rhi.update_buffer(quad_ibo_, 0, tcb::as_bytes(tcb::span(kIndices)));
upload_quad_buffer_ = false;
}
for (uint32_t i = 0; i < screens_; i++)
{
BlitPostimgScreens::ScreenConfig& screen_config = screen_configs_[i];
BlitPostimgScreens::ScreenData data {};
if (screen_config.indexed)
{
data.program = program_;
}
else
{
data.program = indexed_program_;
}
screen_data_[i] = std::move(data);
}

View file

@ -46,14 +46,11 @@ public:
private:
struct ScreenData
{
rhi::Handle<rhi::Pipeline> pipeline;
rhi::Handle<rhi::BindingSet> binding_set;
rhi::Handle<rhi::UniformSet> uniform_set;
rhi::Handle<rhi::Program> program;
};
rhi::Handle<rhi::Pipeline> pipeline_;
rhi::Handle<rhi::Pipeline> indexed_pipeline_;
rhi::Handle<rhi::RenderPass> renderpass_;
rhi::Handle<rhi::Program> program_;
rhi::Handle<rhi::Program> indexed_program_;
rhi::Handle<rhi::Buffer> quad_vbo_;
rhi::Handle<rhi::Buffer> quad_ibo_;
bool upload_quad_buffer_;
@ -67,12 +64,12 @@ private:
PaletteManager* palette_mgr_;
void prepass(rhi::Rhi& rhi);
void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void transfer(rhi::Rhi& rhi);
public:
explicit BlitPostimgScreens(PaletteManager* palette_mgr);
void draw(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void draw(rhi::Rhi& rhi);
void set_num_screens(uint32_t screens) noexcept
{

View file

@ -11,6 +11,7 @@
#include "blit_rect.hpp"
#include <optional>
#include <vector>
#include <glm/gtc/matrix_transform.hpp>
#include <tcb/span.hpp>
@ -38,95 +39,42 @@ static const BlitVertex kVerts[] =
static const uint16_t kIndices[] = {0, 1, 2, 1, 3, 2};
/// @brief Pipeline used for non-paletted source textures.
static const PipelineDesc kUnshadedPipelineDescription = {
PipelineProgram::kUnshaded,
{{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}},
{{{UniformName::kProjection}, {{UniformName::kModelView, UniformName::kTexCoord0Transform}}}},
{{// RGB/A texture
SamplerName::kSampler0}},
std::nullopt,
{std::nullopt, {true, true, true, true}},
PrimitiveType::kTriangles,
CullMode::kNone,
FaceWinding::kCounterClockwise,
{0.f, 0.f, 0.f, 1.f}};
/// @brief Pipeline used for sharp bilinear special blit.
static const PipelineDesc kSharpBilinearPipelineDescription = {
PipelineProgram::kSharpBilinear,
{{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}},
{{{UniformName::kProjection}, {{UniformName::kModelView, UniformName::kTexCoord0Transform, UniformName::kSampler0Size}}}},
{{// RGB/A texture
SamplerName::kSampler0}},
std::nullopt,
{std::nullopt, {true, true, true, true}},
PrimitiveType::kTriangles,
CullMode::kNone,
FaceWinding::kCounterClockwise,
{0.f, 0.f, 0.f, 1.f}};
/// @brief Pipeline used for CRT special blit
static const PipelineDesc kCrtPipelineDescription = {
PipelineProgram::kCrt,
{{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}},
{{{UniformName::kProjection}, {{UniformName::kModelView, UniformName::kTexCoord0Transform, UniformName::kSampler0Size}}}},
{{// RGB/A texture
SamplerName::kSampler0, SamplerName::kSampler1}},
std::nullopt,
{std::nullopt, {true, true, true, true}},
PrimitiveType::kTriangles,
CullMode::kNone,
FaceWinding::kCounterClockwise,
{0.f, 0.f, 0.f, 1.f}};
/// @brief Pipeline used for CRT special blit (sharp)
static const PipelineDesc kCrtSharpPipelineDescription = {
PipelineProgram::kCrtSharp,
{{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}},
{{{UniformName::kProjection}, {{UniformName::kModelView, UniformName::kTexCoord0Transform, UniformName::kSampler0Size}}}},
{{// RGB/A texture
SamplerName::kSampler0, SamplerName::kSampler1}},
std::nullopt,
{std::nullopt, {true, true, true, true}},
PrimitiveType::kTriangles,
CullMode::kNone,
FaceWinding::kCounterClockwise,
{0.f, 0.f, 0.f, 1.f}};
BlitRectPass::BlitRectPass() : BlitRectPass(BlitRectPass::BlitMode::kNearest) {}
BlitRectPass::BlitRectPass(BlitRectPass::BlitMode blit_mode) : blit_mode_(blit_mode) {}
BlitRectPass::~BlitRectPass() = default;
void BlitRectPass::draw(Rhi& rhi, Handle<GraphicsContext> ctx)
void BlitRectPass::draw(Rhi& rhi)
{
prepass(rhi);
transfer(rhi, ctx);
graphics(rhi, ctx);
transfer(rhi);
graphics(rhi);
}
void BlitRectPass::prepass(Rhi& rhi)
{
if (!pipeline_)
if (!program_)
{
ProgramDesc desc {};
const char* defines[1] = {"ENABLE_VA_TEXCOORD0"};
desc.defines = tcb::make_span(defines);
switch (blit_mode_)
{
case BlitRectPass::BlitMode::kNearest:
pipeline_ = rhi.create_pipeline(kUnshadedPipelineDescription);
break;
case BlitRectPass::BlitMode::kSharpBilinear:
pipeline_ = rhi.create_pipeline(kSharpBilinearPipelineDescription);
break;
case BlitRectPass::BlitMode::kCrt:
pipeline_ = rhi.create_pipeline(kCrtPipelineDescription);
break;
case BlitRectPass::BlitMode::kCrtSharp:
pipeline_ = rhi.create_pipeline(kCrtSharpPipelineDescription);
break;
default:
std::terminate();
case BlitRectPass::BlitMode::kNearest:
desc.name = "unshaded";
break;
case BlitRectPass::BlitMode::kSharpBilinear:
desc.name = "sharpbilinear";
break;
case BlitRectPass::BlitMode::kCrt:
desc.name = "crt";
break;
case BlitRectPass::BlitMode::kCrtSharp:
desc.name = "crtsharp";
break;
default:
std::terminate();
}
program_ = rhi.create_program(desc);
}
if (!quad_vbo_)
@ -156,17 +104,17 @@ void BlitRectPass::prepass(Rhi& rhi)
}
}
void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
void BlitRectPass::transfer(Rhi& rhi)
{
if (quad_vbo_needs_upload_ && quad_vbo_)
{
rhi.update_buffer(ctx, quad_vbo_, 0, tcb::as_bytes(tcb::span(kVerts)));
rhi.update_buffer(quad_vbo_, 0, tcb::as_bytes(tcb::span(kVerts)));
quad_vbo_needs_upload_ = false;
}
if (quad_ibo_needs_upload_ && quad_ibo_)
{
rhi.update_buffer(ctx, quad_ibo_, 0, tcb::as_bytes(tcb::span(kIndices)));
rhi.update_buffer(quad_ibo_, 0, tcb::as_bytes(tcb::span(kIndices)));
quad_ibo_needs_upload_ = false;
}
@ -227,9 +175,21 @@ void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
0, 0, 255, 255,
0, 0, 0, 255,
};
rhi.update_texture(ctx, dot_pattern_, {0, 0, 12, 4}, PixelFormat::kRGBA8, tcb::as_bytes(tcb::span(kDotPattern)));
rhi.update_texture(dot_pattern_, {0, 0, 12, 4}, PixelFormat::kRGBA8, tcb::as_bytes(tcb::span(kDotPattern)));
dot_pattern_needs_upload_ = false;
}
}
void BlitRectPass::graphics(Rhi& rhi)
{
rhi.bind_program(program_);
RasterizerStateDesc rs {};
rs.cull = CullMode::kNone;
rhi.set_rasterizer_state(rs);
rhi.bind_vertex_attrib("a_position", quad_vbo_, VertexAttributeFormat::kFloat3, offsetof(BlitVertex, x), sizeof(BlitVertex));
rhi.bind_vertex_attrib("a_texcoord0", quad_vbo_, VertexAttributeFormat::kFloat2, offsetof(BlitVertex, u), sizeof(BlitVertex));
float aspect = 1.0;
float output_aspect = 1.0;
@ -242,122 +202,46 @@ void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
rhi::TextureDetails texture_details = rhi.get_texture_details(texture_);
std::array<rhi::UniformVariant, 1> g1_uniforms = {{
// Projection
glm::scale(
glm::identity<glm::mat4>(),
glm::vec3(taller ? 1.f : 1.f / output_aspect, taller ? -1.f / (1.f / output_aspect) : -1.f, 1.f)
)
}};
glm::mat4 projection = glm::scale(
glm::identity<glm::mat4>(),
glm::vec3(taller ? 1.f : 1.f / output_aspect, taller ? -1.f / (1.f / output_aspect) : -1.f, 1.f)
);
glm::mat4 modelview = glm::scale(
glm::identity<glm::mat4>(),
glm::vec3(taller ? 2.f : 2.f * aspect, taller ? 2.f * (1.f / aspect) : 2.f, 1.f)
);;
glm::mat3 texcoord0_transform = glm::mat3(
glm::vec3(1.f, 0.f, 0.f),
glm::vec3(0.f, output_flip_ ? -1.f : 1.f, 0.f),
glm::vec3(0.f, output_flip_ ? 1.f : 0.f, 1.f)
);
glm::vec2 sampler0_size = glm::vec2(texture_details.width, texture_details.height);
uniform_sets_[0] = rhi.create_uniform_set(ctx, {g1_uniforms});
rhi.set_uniform("u_projection", projection);
rhi.set_uniform("u_modelview", modelview);
rhi.set_uniform("u_texcoord0_transform", texcoord0_transform);
switch (blit_mode_)
{
case BlitRectPass::BlitMode::kCrt:
{
std::array<rhi::UniformVariant, 3> g2_uniforms = {
// ModelView
glm::scale(
glm::identity<glm::mat4>(),
glm::vec3(taller ? 2.f : 2.f * aspect, taller ? 2.f * (1.f / aspect) : 2.f, 1.f)
),
// Texcoord0 Transform
glm::mat3(
glm::vec3(1.f, 0.f, 0.f),
glm::vec3(0.f, output_flip_ ? -1.f : 1.f, 0.f),
glm::vec3(0.f, output_flip_ ? 1.f : 0.f, 1.f)
),
// Sampler 0 Size
glm::vec2(texture_details.width, texture_details.height)
};
uniform_sets_[1] = rhi.create_uniform_set(ctx, {g2_uniforms});
std::array<rhi::VertexAttributeBufferBinding, 1> vbs = {{{0, quad_vbo_}}};
std::array<rhi::TextureBinding, 2> tbs = {{{rhi::SamplerName::kSampler0, texture_}, {rhi::SamplerName::kSampler1, dot_pattern_}}};
binding_set_ = rhi.create_binding_set(ctx, pipeline_, {vbs, tbs});
case BlitRectPass::BlitMode::kNearest:
break;
}
case BlitRectPass::BlitMode::kCrtSharp:
{
std::array<rhi::UniformVariant, 3> g2_uniforms = {
// ModelView
glm::scale(
glm::identity<glm::mat4>(),
glm::vec3(taller ? 2.f : 2.f * aspect, taller ? 2.f * (1.f / aspect) : 2.f, 1.f)
),
// Texcoord0 Transform
glm::mat3(
glm::vec3(1.f, 0.f, 0.f),
glm::vec3(0.f, output_flip_ ? -1.f : 1.f, 0.f),
glm::vec3(0.f, output_flip_ ? 1.f : 0.f, 1.f)
),
// Sampler 0 Size
glm::vec2(texture_details.width, texture_details.height)
};
uniform_sets_[1] = rhi.create_uniform_set(ctx, {g2_uniforms});
std::array<rhi::VertexAttributeBufferBinding, 1> vbs = {{{0, quad_vbo_}}};
std::array<rhi::TextureBinding, 2> tbs = {{{rhi::SamplerName::kSampler0, texture_}, {rhi::SamplerName::kSampler1, dot_pattern_}}};
binding_set_ = rhi.create_binding_set(ctx, pipeline_, {vbs, tbs});
break;
}
case BlitRectPass::BlitMode::kSharpBilinear:
{
std::array<rhi::UniformVariant, 3> g2_uniforms = {
// ModelView
glm::scale(
glm::identity<glm::mat4>(),
glm::vec3(taller ? 2.f : 2.f * aspect, taller ? 2.f * (1.f / aspect) : 2.f, 1.f)
),
// Texcoord0 Transform
glm::mat3(
glm::vec3(1.f, 0.f, 0.f),
glm::vec3(0.f, output_flip_ ? -1.f : 1.f, 0.f),
glm::vec3(0.f, output_flip_ ? 1.f : 0.f, 1.f)
),
// Sampler0 size
glm::vec2(texture_details.width, texture_details.height)
};
uniform_sets_[1] = rhi.create_uniform_set(ctx, {g2_uniforms});
std::array<rhi::VertexAttributeBufferBinding, 1> vbs = {{{0, quad_vbo_}}};
std::array<rhi::TextureBinding, 1> tbs = {{{rhi::SamplerName::kSampler0, texture_}}};
binding_set_ = rhi.create_binding_set(ctx, pipeline_, {vbs, tbs});
break;
}
default:
{
std::array<rhi::UniformVariant, 2> g2_uniforms = {
// ModelView
glm::scale(
glm::identity<glm::mat4>(),
glm::vec3(taller ? 2.f : 2.f * aspect, taller ? 2.f * (1.f / aspect) : 2.f, 1.f)
),
// Texcoord0 Transform
glm::mat3(
glm::vec3(1.f, 0.f, 0.f),
glm::vec3(0.f, output_flip_ ? -1.f : 1.f, 0.f),
glm::vec3(0.f, output_flip_ ? 1.f : 0.f, 1.f)
)
};
uniform_sets_[1] = rhi.create_uniform_set(ctx, {g2_uniforms});
std::array<rhi::VertexAttributeBufferBinding, 1> vbs = {{{0, quad_vbo_}}};
std::array<rhi::TextureBinding, 1> tbs = {{{rhi::SamplerName::kSampler0, texture_}}};
binding_set_ = rhi.create_binding_set(ctx, pipeline_, {vbs, tbs});
rhi.set_uniform("u_sampler0_size", sampler0_size);
break;
}
rhi.set_sampler("s_sampler0", 0, texture_);
switch (blit_mode_)
{
case BlitRectPass::BlitMode::kCrt:
rhi.set_sampler("s_sampler1", 1, dot_pattern_);
break;
case BlitRectPass::BlitMode::kCrtSharp:
rhi.set_sampler("s_sampler1", 1, dot_pattern_);
break;
default:
break;
}
}
void BlitRectPass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
{
rhi.bind_pipeline(ctx, pipeline_);
rhi.set_viewport(ctx, output_position_);
rhi.bind_uniform_set(ctx, 0, uniform_sets_[0]);
rhi.bind_uniform_set(ctx, 1, uniform_sets_[1]);
rhi.bind_binding_set(ctx, binding_set_);
rhi.bind_index_buffer(ctx, quad_ibo_);
rhi.draw_indexed(ctx, 6, 0);
rhi.set_viewport(output_position_);
rhi.bind_index_buffer(quad_ibo_);
rhi.draw_indexed(6, 0);
}

View file

@ -32,7 +32,7 @@ public:
};
private:
rhi::Handle<rhi::Pipeline> pipeline_;
rhi::Handle<rhi::Program> program_;
rhi::Handle<rhi::Texture> texture_;
uint32_t texture_width_ = 0;
uint32_t texture_height_ = 0;
@ -42,8 +42,6 @@ private:
bool output_flip_ = false;
rhi::Handle<rhi::Buffer> quad_vbo_;
rhi::Handle<rhi::Buffer> quad_ibo_;
std::array<rhi::Handle<rhi::UniformSet>, 2> uniform_sets_;
rhi::Handle<rhi::BindingSet> binding_set_;
BlitMode blit_mode_;
rhi::Handle<rhi::Texture> dot_pattern_;
@ -52,8 +50,8 @@ private:
bool dot_pattern_needs_upload_ = false;
void prepass(rhi::Rhi& rhi);
void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void transfer(rhi::Rhi& rhi);
void graphics(rhi::Rhi& rhi);
public:
@ -61,7 +59,7 @@ public:
BlitRectPass();
~BlitRectPass();
void draw(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void draw(rhi::Rhi& rhi);
/// @brief Set the next blit texture. Don't call during graphics phase!
/// @param texture the texture to use when blitting

View file

@ -13,6 +13,7 @@
#include "blit_postimg_screens.hpp"
#include "blit_rect.hpp"
#include "imgui_renderer.hpp"
#include "postprocess_wipe.hpp"
#include "resource_management.hpp"
#include "screen_capture.hpp"
@ -44,6 +45,7 @@ struct HardwareState
std::unique_ptr<BlitRectPass> crtsharp_blit_rect;
std::unique_ptr<ScreenshotPass> screen_capture;
std::unique_ptr<UpscaleBackbuffer> backbuffer;
std::unique_ptr<ImguiRenderer> imgui_renderer;
WipeFrames wipe_frames;
};

View file

@ -8,9 +8,10 @@
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include "pass_imgui.hpp"
#include "imgui_renderer.hpp"
#include <imgui.h>
#include <tcb/span.hpp>
#include "../v_video.h"
@ -18,39 +19,25 @@ using namespace srb2;
using namespace srb2::hwr2;
using namespace srb2::rhi;
static const PipelineDesc kPipelineDesc = {
PipelineProgram::kUnshaded,
{{{sizeof(ImDrawVert)}},
{{VertexAttributeName::kPosition, 0, 0},
{VertexAttributeName::kTexCoord0, 0, 12},
{VertexAttributeName::kColor, 0, 24}}},
{{{UniformName::kProjection}, {{UniformName::kModelView, UniformName::kTexCoord0Transform}}}},
{{SamplerName::kSampler0}},
PipelineDepthStencilStateDesc {true, true, CompareFunc::kAlways, false, {}, {}},
{BlendDesc {
BlendFactor::kSourceAlpha,
BlendFactor::kOneMinusSourceAlpha,
BlendFunction::kAdd,
BlendFactor::kOne,
BlendFactor::kOneMinusSourceAlpha,
BlendFunction::kAdd},
{true, true, true, true}},
PrimitiveType::kTriangles,
CullMode::kNone,
FaceWinding::kCounterClockwise,
{0.f, 0.f, 0.f, 1.f}};
ImguiPass::ImguiPass() : Pass()
ImguiRenderer::ImguiRenderer()
{
}
ImguiPass::~ImguiPass() = default;
ImguiRenderer::~ImguiRenderer() = default;
void ImguiPass::prepass(Rhi& rhi)
void ImguiRenderer::render(Rhi& rhi)
{
if (!pipeline_)
if (!program_)
{
pipeline_ = rhi.create_pipeline(kPipelineDesc);
const char* defines[2] = {
"ENABLE_VA_TEXCOORD0",
"ENABLE_VA_COLOR"
};
ProgramDesc desc;
desc.name = "unshaded";
desc.defines = tcb::make_span(defines);
program_ = rhi.create_program(desc);
}
ImGuiIO& io = ImGui::GetIO();
@ -75,6 +62,19 @@ void ImguiPass::prepass(Rhi& rhi)
io.Fonts->SetTexID(font_atlas_);
}
if (!default_tex_)
{
uint32_t pixel = 0xFFFFFFFF;
default_tex_ = rhi.create_texture({
TextureFormat::kRGBA,
1,
1,
TextureWrapMode::kRepeat,
TextureWrapMode::kRepeat
});
rhi.update_texture(default_tex_, {0, 0, 1, 1}, rhi::PixelFormat::kRGBA8, tcb::as_bytes(tcb::span(&pixel, 1)));
}
ImGui::Render();
ImDrawData* data = ImGui::GetDrawData();
@ -113,7 +113,14 @@ void ImguiPass::prepass(Rhi& rhi)
DrawCmd draw_cmd;
ImTextureID tex_id = cmd.GetTexID();
draw_cmd.tex = tex_id;
if (tex_id == 0)
{
draw_cmd.tex = default_tex_;
}
else
{
draw_cmd.tex = tex_id;
}
draw_cmd.v_offset = cmd.VtxOffset;
draw_cmd.i_offset = cmd.IdxOffset;
draw_cmd.elems = cmd.ElemCount;
@ -126,18 +133,12 @@ void ImguiPass::prepass(Rhi& rhi)
}
draw_lists_.push_back(std::move(hwr2_list));
}
}
void ImguiPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
{
ImGuiIO& io = ImGui::GetIO();
{
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
rhi.update_texture(
ctx,
font_atlas_,
{0, 0, static_cast<uint32_t>(width), static_cast<uint32_t>(height)},
rhi::PixelFormat::kRGBA8,
@ -162,74 +163,70 @@ void ImguiPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
}
tcb::span<ImDrawVert> vert_span = tcb::span(im_list->VtxBuffer.Data, im_list->VtxBuffer.size());
rhi.update_buffer(ctx, vbo, 0, tcb::as_bytes(vert_span));
rhi.update_buffer(vbo, 0, tcb::as_bytes(vert_span));
tcb::span<ImDrawIdx> index_span = tcb::span(im_list->IdxBuffer.Data, im_list->IdxBuffer.size());
rhi.update_buffer(ctx, ibo, 0, tcb::as_bytes(index_span));
// Uniform sets
std::array<UniformVariant, 1> g1_uniforms = {
// Projection
glm::mat4(
glm::vec4(2.f / vid.realwidth, 0.f, 0.f, 0.f),
glm::vec4(0.f, 2.f / vid.realheight, 0.f, 0.f),
glm::vec4(0.f, 0.f, 1.f, 0.f),
glm::vec4(-1.f, 1.f, 0.f, 1.f)
)
};
std::array<UniformVariant, 2> g2_uniforms = {
// ModelView
glm::mat4(
glm::vec4(1.f, 0.f, 0.f, 0.f),
glm::vec4(0.f, -1.f, 0.f, 0.f),
glm::vec4(0.f, 0.f, 1.f, 0.f),
glm::vec4(0.f, 0, 0.f, 1.f)
),
// Texcoord0 Transform
glm::mat3(
glm::vec3(1.f, 0.f, 0.f),
glm::vec3(0.f, 1.f, 0.f),
glm::vec3(0.f, 0.f, 1.f)
)
};
Handle<UniformSet> us_1 = rhi.create_uniform_set(ctx, {g1_uniforms});
Handle<UniformSet> us_2 = rhi.create_uniform_set(ctx, {g2_uniforms});
draw_list.us_1 = us_1;
draw_list.us_2 = us_2;
rhi.update_buffer(ibo, 0, tcb::as_bytes(index_span));
for (auto& draw_cmd : draw_list.cmds)
{
// Binding set
std::array<rhi::VertexAttributeBufferBinding, 1> vbos = {{{0, vbo}}};
std::array<rhi::TextureBinding, 1> tbs = {{{rhi::SamplerName::kSampler0, draw_cmd.tex}}};
rhi::Handle<rhi::BindingSet> binding_set = rhi.create_binding_set(ctx, pipeline_, {vbos, tbs});
draw_cmd.binding_set = binding_set;
draw_cmd.vbo = vbo;
draw_cmd.ibo = ibo;
draw_cmd.tex = draw_cmd.tex;
}
}
}
void ImguiPass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
{
rhi.begin_default_render_pass(ctx, false);
rhi.bind_pipeline(ctx, pipeline_);
rhi.bind_program(program_);
RasterizerStateDesc rs;
rs.cull = CullMode::kNone;
rs.winding = FaceWinding::kCounterClockwise;
rs.depth_test = true;
rs.depth_func = CompareFunc::kAlways;
rs.blend_enabled = true;
rs.blend_source_factor_color = BlendFactor::kSourceAlpha;
rs.blend_dest_factor_color = BlendFactor::kOneMinusSourceAlpha;
rs.blend_color_function = BlendFunction::kAdd;
rs.blend_source_factor_alpha = BlendFactor::kOne;
rs.blend_dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha;
rs.blend_alpha_function = BlendFunction::kAdd;
for (auto& draw_list : draw_lists_)
{
rhi.bind_uniform_set(ctx, 0, draw_list.us_1);
rhi.bind_uniform_set(ctx, 1, draw_list.us_2);
glm::mat4 projection = glm::mat4(
glm::vec4(2.f / vid.realwidth, 0.f, 0.f, 0.f),
glm::vec4(0.f, 2.f / vid.realheight, 0.f, 0.f),
glm::vec4(0.f, 0.f, 1.f, 0.f),
glm::vec4(-1.f, 1.f, 0.f, 1.f)
);
glm::mat4 modelview = glm::mat4(
glm::vec4(1.f, 0.f, 0.f, 0.f),
glm::vec4(0.f, -1.f, 0.f, 0.f),
glm::vec4(0.f, 0.f, 1.f, 0.f),
glm::vec4(0.f, 0, 0.f, 1.f)
);
glm::mat3 texcoord0_transform = glm::mat3(
glm::vec3(1.f, 0.f, 0.f),
glm::vec3(0.f, 1.f, 0.f),
glm::vec3(0.f, 0.f, 1.f)
);
rhi.set_uniform("u_projection", projection);
rhi.set_uniform("u_modelview", modelview);
rhi.set_uniform("u_texcoord0_transform", texcoord0_transform);
for (auto& cmd : draw_list.cmds)
{
rhi.bind_binding_set(ctx, cmd.binding_set);
rhi.bind_index_buffer(ctx, draw_list.ibo);
rhi.set_scissor(ctx, cmd.clip);
rhi.draw_indexed(ctx, cmd.elems, cmd.i_offset);
rs.scissor_test = true;
rs.scissor = cmd.clip;
rhi.set_rasterizer_state(rs);
rhi.bind_vertex_attrib("a_position", cmd.vbo, VertexAttributeFormat::kFloat3, offsetof(ImDrawVert, pos), sizeof(ImDrawVert));
rhi.bind_vertex_attrib("a_texcoord0", cmd.vbo, VertexAttributeFormat::kFloat2, offsetof(ImDrawVert, uv), sizeof(ImDrawVert));
rhi.bind_vertex_attrib("a_color", cmd.vbo, VertexAttributeFormat::kFloat4, offsetof(ImDrawVert, colf), sizeof(ImDrawVert));
rhi.set_sampler("s_sampler0", 0, cmd.tex);
rhi.bind_index_buffer(draw_list.ibo);
rhi.draw_indexed(cmd.elems, cmd.i_offset);
}
}
rhi.end_render_pass(ctx);
}
void ImguiPass::postpass(Rhi& rhi)
{
for (auto& list : draw_lists_)
{
rhi.destroy_buffer(list.vbo);

View file

@ -14,48 +14,41 @@
#include <vector>
#include "../rhi/rhi.hpp"
#include "pass.hpp"
namespace srb2::hwr2
{
class ImguiPass final : public Pass
class ImguiRenderer final
{
struct DrawCmd
{
rhi::Handle<rhi::Texture> tex;
uint32_t v_offset;
uint32_t elems;
uint32_t i_offset;
rhi::Rect clip;
rhi::Handle<rhi::BindingSet> binding_set;
rhi::Handle<rhi::Buffer> vbo;
rhi::Handle<rhi::Buffer> ibo;
rhi::Handle<rhi::Texture> tex;
};
struct DrawList
{
void* list;
rhi::Handle<rhi::Buffer> vbo;
rhi::Handle<rhi::Buffer> ibo;
rhi::Handle<rhi::UniformSet> us_1;
rhi::Handle<rhi::UniformSet> us_2;
std::vector<DrawCmd> cmds;
};
rhi::Handle<rhi::Pipeline> pipeline_;
rhi::Handle<rhi::Program> program_;
rhi::Handle<rhi::Texture> font_atlas_;
rhi::Handle<rhi::Texture> default_tex_;
std::vector<DrawList> draw_lists_;
public:
ImguiPass();
virtual ~ImguiPass();
ImguiRenderer();
virtual ~ImguiRenderer();
virtual void prepass(rhi::Rhi& rhi) override;
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void postpass(rhi::Rhi& rhi) override;
void render(rhi::Rhi& rhi);
};
} // namespace srb2::hwr2

View file

@ -1,16 +0,0 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2024 by Ronald "Eidolon" Kinard
// Copyright (C) 2024 by Kart Krew
//
// 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 "pass.hpp"
using namespace srb2;
using namespace srb2::hwr2;
Pass::~Pass() = default;

View file

@ -1,47 +0,0 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2024 by Ronald "Eidolon" Kinard
// Copyright (C) 2024 by Kart Krew
//
// 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_HWR2_PASS_HPP__
#define __SRB2_HWR2_PASS_HPP__
#include "../rhi/rhi.hpp"
namespace srb2::hwr2
{
/// @brief A rendering pass which performs logic during each phase of a frame render.
/// During rendering, all registered Pass's individual stages will be run together.
class Pass
{
public:
virtual ~Pass();
/// @brief Perform rendering logic and create necessary GPU resources.
/// @param rhi
virtual void prepass(rhi::Rhi& rhi) = 0;
/// @brief Upload contents for needed GPU resources. Passes must implement but this will be removed soon.
/// @param rhi
/// @param ctx
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) = 0;
/// @brief Issue draw calls.
/// @param rhi
/// @param ctx
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) = 0;
/// @brief Cleanup GPU resources. Transient resources should be cleaned up here.
/// @param rhi
virtual void postpass(rhi::Rhi& rhi) = 0;
};
} // namespace srb2::hwr2
#endif // __SRB2_HWR2_PASS_HPP__

View file

@ -1,189 +0,0 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2024 by Ronald "Eidolon" Kinard
// Copyright (C) 2024 by Kart Krew
//
// 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 "pass_manager.hpp"
using namespace srb2;
using namespace srb2::hwr2;
using namespace srb2::rhi;
namespace
{
class LambdaPass final : public Pass
{
PassManager* mgr_;
std::function<void(PassManager&, rhi::Rhi&)> prepass_func_;
std::function<void(PassManager&, rhi::Rhi&)> postpass_func_;
public:
LambdaPass(PassManager* mgr, std::function<void(PassManager&, rhi::Rhi&)> prepass_func);
LambdaPass(
PassManager* mgr,
std::function<void(PassManager&, rhi::Rhi&)> prepass_func,
std::function<void(PassManager&, rhi::Rhi&)> postpass_func
);
virtual ~LambdaPass();
virtual void prepass(rhi::Rhi& rhi) override;
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void postpass(rhi::Rhi& rhi) override;
};
} // namespace
LambdaPass::LambdaPass(PassManager* mgr, std::function<void(PassManager&, rhi::Rhi&)> prepass_func)
: mgr_(mgr), prepass_func_(prepass_func)
{
}
LambdaPass::LambdaPass(
PassManager* mgr,
std::function<void(PassManager&, rhi::Rhi&)> prepass_func,
std::function<void(PassManager&, rhi::Rhi&)> postpass_func
)
: mgr_(mgr), prepass_func_(prepass_func), postpass_func_(postpass_func)
{
}
LambdaPass::~LambdaPass() = default;
void LambdaPass::prepass(Rhi& rhi)
{
if (prepass_func_)
{
(prepass_func_)(*mgr_, rhi);
}
}
void LambdaPass::transfer(Rhi&, Handle<GraphicsContext>)
{
}
void LambdaPass::graphics(Rhi&, Handle<GraphicsContext>)
{
}
void LambdaPass::postpass(Rhi& rhi)
{
if (postpass_func_)
{
(postpass_func_)(*mgr_, rhi);
}
}
PassManager::PassManager() = default;
PassManager::PassManager(const PassManager&) = default;
PassManager& PassManager::operator=(const PassManager&) = default;
void PassManager::insert(const std::string& name, std::shared_ptr<Pass> pass)
{
SRB2_ASSERT(pass_by_name_.find(name) == pass_by_name_.end());
std::size_t index = passes_.size();
passes_.push_back(PassManagerEntry {name, pass, true});
pass_by_name_.insert({name, index});
}
void PassManager::insert(const std::string& name, std::function<void(PassManager&, Rhi&)> prepass_func)
{
insert(std::forward<const std::string>(name), std::make_shared<LambdaPass>(LambdaPass {this, prepass_func}));
}
void PassManager::insert(
const std::string& name,
std::function<void(PassManager&, Rhi&)> prepass_func,
std::function<void(PassManager&, Rhi&)> postpass_func
)
{
insert(
std::forward<const std::string>(name),
std::make_shared<LambdaPass>(LambdaPass {this, prepass_func, postpass_func})
);
}
void PassManager::set_pass_enabled(const std::string& name, bool enabled)
{
SRB2_ASSERT(pass_by_name_.find(name) != pass_by_name_.end());
passes_[pass_by_name_[name]].enabled = enabled;
}
std::weak_ptr<Pass> PassManager::for_name(const std::string& name)
{
auto itr = pass_by_name_.find(name);
if (itr == pass_by_name_.end())
{
return std::weak_ptr<Pass>();
}
return passes_[itr->second].pass;
}
void PassManager::prepass(Rhi& rhi)
{
for (auto& pass : passes_)
{
if (pass.enabled)
{
pass.pass->prepass(rhi);
}
}
}
void PassManager::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
{
for (auto& pass : passes_)
{
if (pass.enabled)
{
pass.pass->transfer(rhi, ctx);
}
}
}
void PassManager::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
{
for (auto& pass : passes_)
{
if (pass.enabled)
{
pass.pass->graphics(rhi, ctx);
}
}
}
void PassManager::postpass(Rhi& rhi)
{
for (auto& pass : passes_)
{
if (pass.enabled)
{
pass.pass->postpass(rhi);
}
}
}
void PassManager::render(Rhi& rhi)
{
if (passes_.empty())
{
return;
}
prepass(rhi);
Handle<GraphicsContext> gc = rhi.begin_graphics();
transfer(rhi, gc);
graphics(rhi, gc);
rhi.end_graphics(gc);
postpass(rhi);
}

View file

@ -1,66 +0,0 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2024 by Ronald "Eidolon" Kinard
// Copyright (C) 2024 by Kart Krew
//
// 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_HWR2_PASS_MANAGER_HPP__
#define __SRB2_HWR2_PASS_MANAGER_HPP__
#include <cstddef>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include "../rhi/rhi.hpp"
#include "pass.hpp"
namespace srb2::hwr2
{
class PassManager final : public Pass
{
struct PassManagerEntry
{
std::string name;
std::shared_ptr<Pass> pass;
bool enabled;
};
std::unordered_map<std::string, std::size_t> pass_by_name_;
std::vector<PassManagerEntry> passes_;
public:
PassManager();
PassManager(const PassManager&);
PassManager(PassManager&&) = delete;
PassManager& operator=(const PassManager&);
PassManager& operator=(PassManager&&) = delete;
virtual void prepass(rhi::Rhi& rhi) override;
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void postpass(rhi::Rhi& rhi) override;
void insert(const std::string& name, std::shared_ptr<Pass> pass);
void insert(const std::string& name, std::function<void(PassManager&, rhi::Rhi&)> prepass_func);
void insert(
const std::string& name,
std::function<void(PassManager&, rhi::Rhi&)> prepass_func,
std::function<void(PassManager&, rhi::Rhi&)> postpass_func
);
std::weak_ptr<Pass> for_name(const std::string& name);
void set_pass_enabled(const std::string& name, bool enabled);
void render(rhi::Rhi& rhi);
};
} // namespace srb2::hwr2
#endif // __SRB2_HWR2_PASS_MANAGER_HPP__

View file

@ -21,7 +21,7 @@ using namespace srb2;
using namespace srb2::hwr2;
using namespace srb2::rhi;
FramebufferManager::FramebufferManager() : Pass()
FramebufferManager::FramebufferManager()
{
}
@ -120,11 +120,11 @@ void FramebufferManager::prepass(Rhi& rhi)
}
}
void FramebufferManager::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
void FramebufferManager::transfer(Rhi& rhi)
{
}
void FramebufferManager::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
void FramebufferManager::graphics(Rhi& rhi)
{
}
@ -161,28 +161,28 @@ void MainPaletteManager::prepass(Rhi& rhi)
}
}
void MainPaletteManager::upload_palette(Rhi& rhi, Handle<GraphicsContext> ctx)
void MainPaletteManager::upload_palette(Rhi& rhi)
{
std::array<byteColor_t, kPaletteSize> palette_32;
for (std::size_t i = 0; i < kPaletteSize; i++)
{
palette_32[i] = V_GetColor(i).s;
}
rhi.update_texture(ctx, palette_, {0, 0, kPaletteSize, 1}, PixelFormat::kRGBA8, tcb::as_bytes(tcb::span(palette_32)));
rhi.update_texture(palette_, {0, 0, kPaletteSize, 1}, PixelFormat::kRGBA8, tcb::as_bytes(tcb::span(palette_32)));
}
void MainPaletteManager::upload_lighttables(Rhi& rhi, Handle<GraphicsContext> ctx)
void MainPaletteManager::upload_lighttables(Rhi& rhi)
{
if (colormaps != nullptr)
{
tcb::span<const std::byte> colormap_bytes = tcb::as_bytes(tcb::span(colormaps, kPaletteSize * kLighttableRows));
rhi.update_texture(ctx, lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, colormap_bytes);
rhi.update_texture(lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, colormap_bytes);
}
if (encoremap != nullptr)
{
tcb::span<const std::byte> encoremap_bytes = tcb::as_bytes(tcb::span(encoremap, kPaletteSize * kLighttableRows));
rhi.update_texture(ctx, encore_lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, encoremap_bytes);
rhi.update_texture(encore_lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, encoremap_bytes);
}
if (!lighttables_to_upload_.empty())
@ -192,23 +192,23 @@ void MainPaletteManager::upload_lighttables(Rhi& rhi, Handle<GraphicsContext> ct
Handle<Texture> lighttable_tex = find_extra_lighttable(lighttable);
SRB2_ASSERT(lighttable_tex != kNullHandle);
tcb::span<const std::byte> lighttable_bytes = tcb::as_bytes(tcb::span(lighttable, kPaletteSize * kLighttableRows));
rhi.update_texture(ctx, lighttable_tex, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, lighttable_bytes);
rhi.update_texture(lighttable_tex, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, lighttable_bytes);
}
lighttables_to_upload_.clear();
}
}
void MainPaletteManager::upload_default_colormap(Rhi& rhi, Handle<GraphicsContext> ctx)
void MainPaletteManager::upload_default_colormap(Rhi& rhi)
{
std::array<uint8_t, kPaletteSize> data;
for (std::size_t i = 0; i < kPaletteSize; i++)
{
data[i] = i;
}
rhi.update_texture(ctx, default_colormap_, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, tcb::as_bytes(tcb::span(data)));
rhi.update_texture(default_colormap_, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, tcb::as_bytes(tcb::span(data)));
}
void MainPaletteManager::upload_colormaps(Rhi& rhi, Handle<GraphicsContext> ctx)
void MainPaletteManager::upload_colormaps(Rhi& rhi)
{
for (auto to_upload : colormaps_to_upload_)
{
@ -218,7 +218,7 @@ void MainPaletteManager::upload_colormaps(Rhi& rhi, Handle<GraphicsContext> ctx)
rhi::Handle<rhi::Texture> map_texture = colormaps_.at(to_upload);
tcb::span<const std::byte> map_bytes = tcb::as_bytes(tcb::span(to_upload, kPaletteSize));
rhi.update_texture(ctx, map_texture, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, map_bytes);
rhi.update_texture(map_texture, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, map_bytes);
}
colormaps_to_upload_.clear();
}
@ -271,15 +271,15 @@ rhi::Handle<rhi::Texture> MainPaletteManager::find_extra_lighttable(srb2::NotNul
return lighttables_.at(lighttable);
}
void MainPaletteManager::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
void MainPaletteManager::transfer(Rhi& rhi)
{
upload_palette(rhi, ctx);
upload_lighttables(rhi, ctx);
upload_default_colormap(rhi, ctx);
upload_colormaps(rhi, ctx);
upload_palette(rhi);
upload_lighttables(rhi);
upload_default_colormap(rhi);
upload_colormaps(rhi);
}
void MainPaletteManager::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
void MainPaletteManager::graphics(Rhi& rhi)
{
}
@ -319,7 +319,7 @@ void CommonResourcesManager::prepass(Rhi& rhi)
}
}
void CommonResourcesManager::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
void CommonResourcesManager::transfer(Rhi& rhi)
{
if (!init_)
{
@ -330,13 +330,13 @@ void CommonResourcesManager::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
uint8_t transparent[4] = {0, 0, 0, 0};
tcb::span<const std::byte> transparent_bytes = tcb::as_bytes(tcb::span(transparent, 4));
rhi.update_texture(ctx, black_, {0, 0, 1, 1}, PixelFormat::kRGBA8, black_bytes);
rhi.update_texture(ctx, white_, {0, 0, 1, 1}, PixelFormat::kRGBA8, white_bytes);
rhi.update_texture(ctx, transparent_, {0, 0, 1, 1}, PixelFormat::kRGBA8, transparent_bytes);
rhi.update_texture(black_, {0, 0, 1, 1}, PixelFormat::kRGBA8, black_bytes);
rhi.update_texture(white_, {0, 0, 1, 1}, PixelFormat::kRGBA8, white_bytes);
rhi.update_texture(transparent_, {0, 0, 1, 1}, PixelFormat::kRGBA8, transparent_bytes);
}
}
void CommonResourcesManager::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
void CommonResourcesManager::graphics(Rhi& rhi)
{
}

View file

@ -16,12 +16,12 @@
#include <unordered_map>
#include <vector>
#include "pass.hpp"
#include "../rhi/rhi.hpp"
namespace srb2::hwr2
{
class FramebufferManager final : public Pass
class FramebufferManager final
{
rhi::Handle<rhi::Texture> main_color_;
std::array<rhi::Handle<rhi::Texture>, 2> post_colors_;
@ -36,10 +36,10 @@ public:
FramebufferManager();
virtual ~FramebufferManager();
virtual void prepass(rhi::Rhi& rhi) override;
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void postpass(rhi::Rhi& rhi) override;
void prepass(rhi::Rhi& rhi);
void transfer(rhi::Rhi& rhi);
void graphics(rhi::Rhi& rhi);
void postpass(rhi::Rhi& rhi);
/// @brief Swap the current and previous postprocess FB textures. Use between pass prepass phases to alternate.
void swap_post() noexcept
@ -70,7 +70,7 @@ public:
std::size_t height() const noexcept { return height_; }
};
class MainPaletteManager final : public Pass
class MainPaletteManager final
{
rhi::Handle<rhi::Texture> palette_;
rhi::Handle<rhi::Texture> lighttable_;
@ -82,19 +82,19 @@ class MainPaletteManager final : public Pass
std::vector<const uint8_t*> colormaps_to_upload_;
std::vector<const uint8_t*> lighttables_to_upload_;
void upload_palette(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void upload_lighttables(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void upload_default_colormap(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void upload_colormaps(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void upload_palette(rhi::Rhi& rhi);
void upload_lighttables(rhi::Rhi& rhi);
void upload_default_colormap(rhi::Rhi& rhi);
void upload_colormaps(rhi::Rhi& rhi);
public:
MainPaletteManager();
virtual ~MainPaletteManager();
virtual void prepass(rhi::Rhi& rhi) override;
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void postpass(rhi::Rhi& rhi) override;
void prepass(rhi::Rhi& rhi);
void transfer(rhi::Rhi& rhi);
void graphics(rhi::Rhi& rhi);
void postpass(rhi::Rhi& rhi);
rhi::Handle<rhi::Texture> palette() const noexcept { return palette_; }
rhi::Handle<rhi::Texture> lighttable() const noexcept { return lighttable_; }
@ -107,7 +107,7 @@ public:
rhi::Handle<rhi::Texture> find_extra_lighttable(srb2::NotNull<const uint8_t*> lighttable) const;
};
class CommonResourcesManager final : public Pass
class CommonResourcesManager final
{
bool init_ = false;
rhi::Handle<rhi::Texture> black_;
@ -118,10 +118,10 @@ public:
CommonResourcesManager();
virtual ~CommonResourcesManager();
virtual void prepass(rhi::Rhi& rhi) override;
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void postpass(rhi::Rhi& rhi) override;
void prepass(rhi::Rhi& rhi);
void transfer(rhi::Rhi& rhi);
void graphics(rhi::Rhi& rhi);
void postpass(rhi::Rhi& rhi);
rhi::Handle<rhi::Texture> black() const noexcept { return black_; }
rhi::Handle<rhi::Texture> white() const noexcept { return white_; }

View file

@ -216,7 +216,7 @@ static PatchAtlas create_atlas(Rhi& rhi, uint32_t size)
return new_atlas;
}
void PatchAtlasCache::pack(Rhi& rhi, Handle<GraphicsContext> ctx)
void PatchAtlasCache::pack(Rhi& rhi)
{
// Prepare stbrp rects for patches to be loaded.
std::vector<stbrp_rect> rects;
@ -310,7 +310,6 @@ void PatchAtlasCache::pack(Rhi& rhi, Handle<GraphicsContext> ctx)
convert_patch_to_trimmed_rg8_pixels(patch_to_upload, patch_data);
rhi.update_texture(
ctx,
atlas->tex_,
{static_cast<int32_t>(entry->x), static_cast<int32_t>(entry->y), entry->w, entry->h},
PixelFormat::kRG8,

View file

@ -20,8 +20,8 @@
#include <tcb/span.hpp>
#include "pass.hpp"
#include "../r_defs.h"
#include "../rhi/rhi.hpp"
extern "C"
{
@ -113,7 +113,7 @@ public:
void queue_patch(srb2::NotNull<const patch_t*> patch);
/// @brief Pack queued patches, allowing them to be looked up with find_patch.
void pack(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void pack(rhi::Rhi& rhi);
/// @brief Find the atlas a patch belongs to, or nullopt if it is not cached.
/// This may not be called if there are still patches that need to be packed.

View file

@ -41,41 +41,28 @@ static const uint16_t kPostprocessIndices[] = {0, 1, 2, 1, 3, 2};
} // namespace
static const PipelineDesc kWipePipelineDesc = {
PipelineProgram::kPostprocessWipe,
{{{sizeof(PostprocessVertex)}},
{
{VertexAttributeName::kPosition, 0, 0},
{VertexAttributeName::kTexCoord0, 0, 12},
}},
{{{{UniformName::kProjection, UniformName::kWipeColorizeMode, UniformName::kWipeEncoreSwizzle}}}},
{{SamplerName::kSampler0, SamplerName::kSampler1, SamplerName::kSampler2}},
std::nullopt,
{std::nullopt, {true, true, true, true}},
PrimitiveType::kTriangles,
CullMode::kNone,
FaceWinding::kCounterClockwise,
{0.f, 0.f, 0.f, 1.f}};
PostprocessWipePass::PostprocessWipePass()
{
}
PostprocessWipePass::~PostprocessWipePass() = default;
void PostprocessWipePass::draw(Rhi& rhi, Handle<GraphicsContext> ctx)
void PostprocessWipePass::draw(Rhi& rhi)
{
prepass(rhi);
transfer(rhi, ctx);
graphics(rhi, ctx);
transfer(rhi);
graphics(rhi);
postpass(rhi);
}
void PostprocessWipePass::prepass(Rhi& rhi)
{
if (!pipeline_)
if (!program_)
{
pipeline_ = rhi.create_pipeline(kWipePipelineDesc);
ProgramDesc desc;
desc.name = "postprocesswipe";
desc.defines = tcb::span<const char*>();
program_ = rhi.create_program(desc);
}
if (!vbo_)
@ -169,7 +156,7 @@ void PostprocessWipePass::prepass(Rhi& rhi)
});
}
void PostprocessWipePass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
void PostprocessWipePass::transfer(Rhi& rhi)
{
if (wipe_tex_ == kNullHandle)
{
@ -183,47 +170,44 @@ void PostprocessWipePass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
if (upload_vbo_)
{
rhi.update_buffer(ctx, vbo_, 0, tcb::as_bytes(tcb::span(kPostprocessVerts)));
rhi.update_buffer(vbo_, 0, tcb::as_bytes(tcb::span(kPostprocessVerts)));
upload_vbo_ = false;
}
if (upload_ibo_)
{
rhi.update_buffer(ctx, ibo_, 0, tcb::as_bytes(tcb::span(kPostprocessIndices)));
rhi.update_buffer(ibo_, 0, tcb::as_bytes(tcb::span(kPostprocessIndices)));
upload_ibo_ = false;
}
tcb::span<const std::byte> data = tcb::as_bytes(tcb::span(mask_data_));
rhi.update_texture(ctx, wipe_tex_, {0, 0, mask_w_, mask_h_}, PixelFormat::kR8, data);
UniformVariant uniforms[] = {
glm::scale(glm::identity<glm::mat4>(), glm::vec3(2.f, 2.f, 1.f)),
static_cast<int32_t>(wipe_color_mode_),
static_cast<int32_t>(wipe_swizzle_)
};
us_ = rhi.create_uniform_set(ctx, {tcb::span(uniforms)});
VertexAttributeBufferBinding vbos[] = {{0, vbo_}};
TextureBinding tx[] = {
{SamplerName::kSampler0, start_},
{SamplerName::kSampler1, end_},
{SamplerName::kSampler2, wipe_tex_}};
bs_ = rhi.create_binding_set(ctx, pipeline_, {vbos, tx});
rhi.update_texture(wipe_tex_, {0, 0, mask_w_, mask_h_}, PixelFormat::kR8, data);
}
void PostprocessWipePass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
void PostprocessWipePass::graphics(Rhi& rhi)
{
if (wipe_tex_ == kNullHandle)
{
return;
}
rhi.bind_pipeline(ctx, pipeline_);
rhi.set_viewport(ctx, {0, 0, width_, height_});
rhi.bind_uniform_set(ctx, 0, us_);
rhi.bind_binding_set(ctx, bs_);
rhi.bind_index_buffer(ctx, ibo_);
rhi.draw_indexed(ctx, 6, 0);
rhi.bind_program(program_);
RasterizerStateDesc desc {};
desc.cull = CullMode::kNone;
rhi.set_rasterizer_state(desc);
rhi.set_uniform("u_projection", glm::scale(glm::identity<glm::mat4>(), glm::vec3(2.f, 2.f, 1.f)));
rhi.set_uniform("u_wipe_colorize_mode", static_cast<int32_t>(wipe_color_mode_));
rhi.set_uniform("u_wipe_encore_swizzle", static_cast<int32_t>(wipe_swizzle_));
rhi.set_sampler("s_sampler0", 0, start_);
rhi.set_sampler("s_sampler1", 1, end_);
rhi.set_sampler("s_sampler2", 2, wipe_tex_);
rhi.bind_vertex_attrib("a_position", vbo_, VertexAttributeFormat::kFloat3, offsetof(PostprocessVertex, x), sizeof(PostprocessVertex));
rhi.bind_vertex_attrib("a_texcoord0", vbo_, VertexAttributeFormat::kFloat2, offsetof(PostprocessVertex, u), sizeof(PostprocessVertex));
rhi.set_viewport({0, 0, width_, height_});
rhi.bind_index_buffer(ibo_);
rhi.draw_indexed(6, 0);
}
void PostprocessWipePass::postpass(Rhi& rhi)

View file

@ -21,13 +21,11 @@ namespace srb2::hwr2
class PostprocessWipePass final
{
// Internal RHI resources
rhi::Handle<rhi::Pipeline> pipeline_;
rhi::Handle<rhi::Program> program_;
rhi::Handle<rhi::Buffer> vbo_;
bool upload_vbo_ = false;
rhi::Handle<rhi::Buffer> ibo_;
bool upload_ibo_ = false;
rhi::Handle<rhi::UniformSet> us_;
rhi::Handle<rhi::BindingSet> bs_;
rhi::Handle<rhi::Texture> wipe_tex_;
int wipe_color_mode_ = 0;
int wipe_swizzle_ = 0;
@ -44,15 +42,15 @@ class PostprocessWipePass final
uint32_t mask_h_ = 0;
void prepass(rhi::Rhi& rhi);
void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void transfer(rhi::Rhi& rhi);
void graphics(rhi::Rhi& rhi);
void postpass(rhi::Rhi& rhi);
public:
PostprocessWipePass();
virtual ~PostprocessWipePass();
void draw(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void draw(rhi::Rhi& rhi);
void set_start(rhi::Handle<rhi::Texture> start) noexcept { start_ = start; }

View file

@ -26,7 +26,7 @@ PaletteManager& PaletteManager::operator=(PaletteManager&&) = default;
constexpr std::size_t kPaletteSize = 256;
constexpr std::size_t kLighttableRows = LIGHTLEVELS;
void PaletteManager::update(Rhi& rhi, Handle<GraphicsContext> ctx)
void PaletteManager::update(Rhi& rhi)
{
if (!palette_)
{
@ -57,7 +57,7 @@ void PaletteManager::update(Rhi& rhi, Handle<GraphicsContext> ctx)
{
palette_32[i] = V_GetColor(i).s;
}
rhi.update_texture(ctx, palette_, {0, 0, kPaletteSize, 1}, PixelFormat::kRGBA8, tcb::as_bytes(tcb::span(palette_32)));
rhi.update_texture(palette_, {0, 0, kPaletteSize, 1}, PixelFormat::kRGBA8, tcb::as_bytes(tcb::span(palette_32)));
}
#if 0
@ -66,7 +66,7 @@ void PaletteManager::update(Rhi& rhi, Handle<GraphicsContext> ctx)
if (colormaps != nullptr)
{
tcb::span<const std::byte> colormap_bytes = tcb::as_bytes(tcb::span(colormaps, kPaletteSize * kLighttableRows));
rhi.update_texture(ctx, lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, colormap_bytes);
rhi.update_texture(lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, colormap_bytes);
}
// FIXME: This is broken, encoremap should not be used directly.
@ -74,7 +74,7 @@ void PaletteManager::update(Rhi& rhi, Handle<GraphicsContext> ctx)
if (encoremap != nullptr)
{
tcb::span<const std::byte> encoremap_bytes = tcb::as_bytes(tcb::span(encoremap, kPaletteSize * kLighttableRows));
rhi.update_texture(ctx, encore_lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, encoremap_bytes);
rhi.update_texture(encore_lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, encoremap_bytes);
}
}
#endif
@ -86,7 +86,7 @@ void PaletteManager::update(Rhi& rhi, Handle<GraphicsContext> ctx)
{
data[i] = i;
}
rhi.update_texture(ctx, default_colormap_, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, tcb::as_bytes(tcb::span(data)));
rhi.update_texture(default_colormap_, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, tcb::as_bytes(tcb::span(data)));
}
}
@ -107,7 +107,7 @@ void PaletteManager::destroy_per_frame_resources(Rhi& rhi)
lighttables_.clear();
}
Handle<Texture> PaletteManager::find_or_create_colormap(Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, srb2::NotNull<const uint8_t*> colormap)
Handle<Texture> PaletteManager::find_or_create_colormap(Rhi& rhi, srb2::NotNull<const uint8_t*> colormap)
{
if (colormaps_.find(colormap) != colormaps_.end())
{
@ -117,13 +117,13 @@ Handle<Texture> PaletteManager::find_or_create_colormap(Rhi& rhi, rhi::Handle<rh
Handle<Texture> texture = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp});
tcb::span<const std::byte> map_bytes = tcb::as_bytes(tcb::span(colormap.get(), kPaletteSize));
rhi.update_texture(ctx, texture, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, map_bytes);
rhi.update_texture(texture, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, map_bytes);
colormaps_.insert_or_assign(colormap, texture);
return texture;
}
Handle<Texture> PaletteManager::find_or_create_extra_lighttable(Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, srb2::NotNull<const uint8_t*> lighttable)
Handle<Texture> PaletteManager::find_or_create_extra_lighttable(Rhi& rhi, srb2::NotNull<const uint8_t*> lighttable)
{
if (lighttables_.find(lighttable) != lighttables_.end())
{
@ -133,7 +133,7 @@ Handle<Texture> PaletteManager::find_or_create_extra_lighttable(Rhi& rhi, rhi::H
Handle<Texture> texture = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, kLighttableRows, TextureWrapMode::kClamp, TextureWrapMode::kClamp});
tcb::span<const std::byte> lighttable_bytes = tcb::as_bytes(tcb::span(lighttable.get(), kPaletteSize * kLighttableRows));
rhi.update_texture(ctx, texture, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, lighttable_bytes);
rhi.update_texture(texture, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, lighttable_bytes);
lighttables_.insert_or_assign(lighttable, texture);
return texture;
@ -161,7 +161,7 @@ static uint32_t get_flat_size(lumpnum_t lump)
return lumpsize;
}
Handle<Texture> FlatTextureManager::find_or_create_indexed(Rhi& rhi, Handle<GraphicsContext> ctx, lumpnum_t lump)
Handle<Texture> FlatTextureManager::find_or_create_indexed(Rhi& rhi, lumpnum_t lump)
{
SRB2_ASSERT(lump != LUMPERROR);
@ -206,7 +206,7 @@ Handle<Texture> FlatTextureManager::find_or_create_indexed(Rhi& rhi, Handle<Grap
}
tcb::span<const std::byte> data_bytes = tcb::as_bytes(tcb::span(flat_data));
rhi.update_texture(ctx, new_tex, {0, 0, flat_size, flat_size}, rhi::PixelFormat::kRG8, data_bytes);
rhi.update_texture(new_tex, {0, 0, flat_size, flat_size}, rhi::PixelFormat::kRG8, data_bytes);
return new_tex;
}

View file

@ -45,11 +45,11 @@ public:
#endif
rhi::Handle<rhi::Texture> default_colormap() const noexcept { return default_colormap_; }
void update(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void update(rhi::Rhi& rhi);
void destroy_per_frame_resources(rhi::Rhi& rhi);
rhi::Handle<rhi::Texture> find_or_create_colormap(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, srb2::NotNull<const uint8_t*> colormap);
rhi::Handle<rhi::Texture> find_or_create_extra_lighttable(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, srb2::NotNull<const uint8_t*> lighttable);
rhi::Handle<rhi::Texture> find_or_create_colormap(rhi::Rhi& rhi, srb2::NotNull<const uint8_t*> colormap);
rhi::Handle<rhi::Texture> find_or_create_extra_lighttable(rhi::Rhi& rhi, srb2::NotNull<const uint8_t*> lighttable);
};
/*
@ -79,7 +79,7 @@ public:
/// in prepass.
/// @param flat_lump
/// @return
rhi::Handle<rhi::Texture> find_or_create_indexed(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, lumpnum_t flat_lump);
rhi::Handle<rhi::Texture> find_or_create_indexed(rhi::Rhi& rhi, lumpnum_t flat_lump);
};
} // namespace srb2::hwr2

View file

@ -21,7 +21,7 @@ using namespace srb2::rhi;
ScreenshotPass::ScreenshotPass() = default;
ScreenshotPass::~ScreenshotPass() = default;
void ScreenshotPass::capture(Rhi& rhi, Handle<GraphicsContext> ctx)
void ScreenshotPass::capture(Rhi& rhi)
{
bool doing_screenshot = takescreenshot || moviemode != MM_OFF || g_takemapthumbnail != TMT_NO;
@ -39,7 +39,7 @@ void ScreenshotPass::capture(Rhi& rhi, Handle<GraphicsContext> ctx)
packed_data_.resize(stride * height_);
tcb::span<std::byte> data_bytes = tcb::as_writable_bytes(tcb::span(pixel_data_));
rhi.read_pixels(ctx, {0, 0, width_, height_}, PixelFormat::kRGB8, data_bytes);
rhi.read_pixels({0, 0, width_, height_}, PixelFormat::kRGB8, data_bytes);
for (uint32_t row = 0; row < height_; row++)
{

View file

@ -21,7 +21,6 @@ namespace srb2::hwr2
class ScreenshotPass
{
rhi::Handle<rhi::RenderPass> render_pass_;
std::vector<uint8_t> pixel_data_;
std::vector<uint8_t> packed_data_;
uint32_t width_ = 0;
@ -31,7 +30,7 @@ public:
ScreenshotPass();
~ScreenshotPass();
void capture(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void capture(rhi::Rhi& rhi);
void set_source(uint32_t width, uint32_t height)
{

View file

@ -20,7 +20,7 @@ using namespace srb2::rhi;
SoftwareScreenRenderer::SoftwareScreenRenderer() = default;
SoftwareScreenRenderer::~SoftwareScreenRenderer() = default;
void SoftwareScreenRenderer::draw(Rhi& rhi, Handle<GraphicsContext> ctx)
void SoftwareScreenRenderer::draw(Rhi& rhi)
{
// Render the player views... or not yet? Needs to be moved out of D_Display in d_main.c
// Assume it's already been done and vid.buffer contains the composited splitscreen view.
@ -71,5 +71,5 @@ void SoftwareScreenRenderer::draw(Rhi& rhi, Handle<GraphicsContext> ctx)
screen_span = tcb::as_bytes(tcb::span(vid.buffer, width_ * height_));
}
rhi.update_texture(ctx, screen_texture_, {0, 0, width_, height_}, PixelFormat::kR8, screen_span);
rhi.update_texture(screen_texture_, {0, 0, width_, height_}, PixelFormat::kR8, screen_span);
}

View file

@ -34,7 +34,7 @@ public:
SoftwareScreenRenderer();
~SoftwareScreenRenderer();
void draw(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void draw(rhi::Rhi& rhi);
rhi::Handle<rhi::Texture> screen() const { return screen_texture_; }
};

View file

@ -43,78 +43,59 @@ static TwodeePipelineKey pipeline_key_for_cmd(const Draw2dCmd& cmd)
return {hwr2::get_blend_mode(cmd), hwr2::is_draw_lines(cmd)};
}
static PipelineDesc make_pipeline_desc(TwodeePipelineKey key)
static void set_blend_state(RasterizerStateDesc& desc, BlendMode blend)
{
constexpr const VertexInputDesc kTwodeeVertexInput = {
{{sizeof(TwodeeVertex)}},
{{VertexAttributeName::kPosition, 0, 0},
{VertexAttributeName::kTexCoord0, 0, 12},
{VertexAttributeName::kColor, 0, 20}}};
BlendDesc blend_desc;
switch (key.blend)
switch (blend)
{
case BlendMode::kAlphaTransparent:
blend_desc.source_factor_color = BlendFactor::kSourceAlpha;
blend_desc.dest_factor_color = BlendFactor::kOneMinusSourceAlpha;
blend_desc.color_function = BlendFunction::kAdd;
blend_desc.source_factor_alpha = BlendFactor::kOne;
blend_desc.dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha;
blend_desc.alpha_function = BlendFunction::kAdd;
desc.blend_source_factor_color = BlendFactor::kSourceAlpha;
desc.blend_dest_factor_color = BlendFactor::kOneMinusSourceAlpha;
desc.blend_color_function = BlendFunction::kAdd;
desc.blend_source_factor_alpha = BlendFactor::kOne;
desc.blend_dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha;
desc.blend_alpha_function = BlendFunction::kAdd;
break;
case BlendMode::kModulate:
blend_desc.source_factor_color = BlendFactor::kDest;
blend_desc.dest_factor_color = BlendFactor::kZero;
blend_desc.color_function = BlendFunction::kAdd;
blend_desc.source_factor_alpha = BlendFactor::kDestAlpha;
blend_desc.dest_factor_alpha = BlendFactor::kZero;
blend_desc.alpha_function = BlendFunction::kAdd;
desc.blend_source_factor_color = BlendFactor::kDest;
desc.blend_dest_factor_color = BlendFactor::kZero;
desc.blend_color_function = BlendFunction::kAdd;
desc.blend_source_factor_alpha = BlendFactor::kDestAlpha;
desc.blend_dest_factor_alpha = BlendFactor::kZero;
desc.blend_alpha_function = BlendFunction::kAdd;
break;
case BlendMode::kAdditive:
blend_desc.source_factor_color = BlendFactor::kSourceAlpha;
blend_desc.dest_factor_color = BlendFactor::kOne;
blend_desc.color_function = BlendFunction::kAdd;
blend_desc.source_factor_alpha = BlendFactor::kOne;
blend_desc.dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha;
blend_desc.alpha_function = BlendFunction::kAdd;
desc.blend_source_factor_color = BlendFactor::kSourceAlpha;
desc.blend_dest_factor_color = BlendFactor::kOne;
desc.blend_color_function = BlendFunction::kAdd;
desc.blend_source_factor_alpha = BlendFactor::kOne;
desc.blend_dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha;
desc.blend_alpha_function = BlendFunction::kAdd;
break;
case BlendMode::kSubtractive:
blend_desc.source_factor_color = BlendFactor::kSourceAlpha;
blend_desc.dest_factor_color = BlendFactor::kOne;
blend_desc.color_function = BlendFunction::kSubtract;
blend_desc.source_factor_alpha = BlendFactor::kOne;
blend_desc.dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha;
blend_desc.alpha_function = BlendFunction::kAdd;
desc.blend_source_factor_color = BlendFactor::kSourceAlpha;
desc.blend_dest_factor_color = BlendFactor::kOne;
desc.blend_color_function = BlendFunction::kSubtract;
desc.blend_source_factor_alpha = BlendFactor::kOne;
desc.blend_dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha;
desc.blend_alpha_function = BlendFunction::kAdd;
break;
case BlendMode::kReverseSubtractive:
blend_desc.source_factor_color = BlendFactor::kSourceAlpha;
blend_desc.dest_factor_color = BlendFactor::kOne;
blend_desc.color_function = BlendFunction::kReverseSubtract;
blend_desc.source_factor_alpha = BlendFactor::kOne;
blend_desc.dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha;
blend_desc.alpha_function = BlendFunction::kAdd;
desc.blend_source_factor_color = BlendFactor::kSourceAlpha;
desc.blend_dest_factor_color = BlendFactor::kOne;
desc.blend_color_function = BlendFunction::kReverseSubtract;
desc.blend_source_factor_alpha = BlendFactor::kOne;
desc.blend_dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha;
desc.blend_alpha_function = BlendFunction::kAdd;
break;
case BlendMode::kInvertDest:
blend_desc.source_factor_color = BlendFactor::kOne;
blend_desc.dest_factor_color = BlendFactor::kOne;
blend_desc.color_function = BlendFunction::kSubtract;
blend_desc.source_factor_alpha = BlendFactor::kZero;
blend_desc.dest_factor_alpha = BlendFactor::kDestAlpha;
blend_desc.alpha_function = BlendFunction::kAdd;
desc.blend_source_factor_color = BlendFactor::kOne;
desc.blend_dest_factor_color = BlendFactor::kOne;
desc.blend_color_function = BlendFunction::kSubtract;
desc.blend_source_factor_alpha = BlendFactor::kZero;
desc.blend_dest_factor_alpha = BlendFactor::kDestAlpha;
desc.blend_alpha_function = BlendFunction::kAdd;
break;
}
return {
PipelineProgram::kUnshadedPaletted,
kTwodeeVertexInput,
{{{UniformName::kProjection},
{{UniformName::kModelView, UniformName::kTexCoord0Transform, UniformName::kSampler0IsIndexedAlpha}}}},
{{SamplerName::kSampler0, SamplerName::kSampler1, SamplerName::kSampler2}},
std::nullopt,
{blend_desc, {true, true, true, true}},
key.lines ? PrimitiveType::kLines : PrimitiveType::kTriangles,
CullMode::kNone,
FaceWinding::kCounterClockwise,
{0.f, 0.f, 0.f, 1.f}};
}
void TwodeeRenderer::rewrite_patch_quad_vertices(Draw2dList& list, const Draw2dPatchQuad& cmd) const
@ -231,34 +212,18 @@ void TwodeeRenderer::rewrite_patch_quad_vertices(Draw2dList& list, const Draw2dP
list.vertices[vtx_offs + 3].v = clipped_vmax;
}
void TwodeeRenderer::initialize(Rhi& rhi, Handle<GraphicsContext> ctx)
void TwodeeRenderer::initialize(Rhi& rhi)
{
{
TwodeePipelineKey alpha_transparent_tris = {BlendMode::kAlphaTransparent, false};
TwodeePipelineKey modulate_tris = {BlendMode::kModulate, false};
TwodeePipelineKey additive_tris = {BlendMode::kAdditive, false};
TwodeePipelineKey subtractive_tris = {BlendMode::kSubtractive, false};
TwodeePipelineKey revsubtractive_tris = {BlendMode::kReverseSubtractive, false};
TwodeePipelineKey invertdest_tris = {BlendMode::kInvertDest, false};
TwodeePipelineKey alpha_transparent_lines = {BlendMode::kAlphaTransparent, true};
TwodeePipelineKey modulate_lines = {BlendMode::kModulate, true};
TwodeePipelineKey additive_lines = {BlendMode::kAdditive, true};
TwodeePipelineKey subtractive_lines = {BlendMode::kSubtractive, true};
TwodeePipelineKey revsubtractive_lines = {BlendMode::kReverseSubtractive, true};
TwodeePipelineKey invertdest_lines = {BlendMode::kInvertDest, true};
pipelines_.insert({alpha_transparent_tris, rhi.create_pipeline(make_pipeline_desc(alpha_transparent_tris))});
pipelines_.insert({modulate_tris, rhi.create_pipeline(make_pipeline_desc(modulate_tris))});
pipelines_.insert({additive_tris, rhi.create_pipeline(make_pipeline_desc(additive_tris))});
pipelines_.insert({subtractive_tris, rhi.create_pipeline(make_pipeline_desc(subtractive_tris))});
pipelines_.insert({revsubtractive_tris, rhi.create_pipeline(make_pipeline_desc(revsubtractive_tris))});
pipelines_.insert({invertdest_tris, rhi.create_pipeline(make_pipeline_desc(invertdest_tris))});
pipelines_.insert({alpha_transparent_lines, rhi.create_pipeline(make_pipeline_desc(alpha_transparent_lines))});
pipelines_.insert({modulate_lines, rhi.create_pipeline(make_pipeline_desc(modulate_lines))});
pipelines_.insert({additive_lines, rhi.create_pipeline(make_pipeline_desc(additive_lines))});
pipelines_.insert({subtractive_lines, rhi.create_pipeline(make_pipeline_desc(subtractive_lines))});
pipelines_.insert({revsubtractive_lines, rhi.create_pipeline(make_pipeline_desc(revsubtractive_lines))});
pipelines_.insert({invertdest_lines, rhi.create_pipeline(make_pipeline_desc(revsubtractive_lines))});
}
ProgramDesc prog_desc;
prog_desc.name = "unshadedpaletted";
const char* defines[] = {
"ENABLE_U_SAMPLER0_IS_INDEXED_ALPHA",
"ENABLE_S_SAMPLER2",
"ENABLE_VA_TEXCOORD0",
"ENABLE_VA_COLOR"
};
prog_desc.defines = tcb::make_span(defines);
program_ = rhi.create_program(prog_desc);
{
default_tex_ = rhi.create_texture({
@ -269,17 +234,17 @@ void TwodeeRenderer::initialize(Rhi& rhi, Handle<GraphicsContext> ctx)
TextureWrapMode::kClamp
});
std::array<uint8_t, 4> data = {0, 255, 0, 255};
rhi.update_texture(ctx, default_tex_, {0, 0, 2, 1}, PixelFormat::kRG8, tcb::as_bytes(tcb::span(data)));
rhi.update_texture(default_tex_, {0, 0, 2, 1}, PixelFormat::kRG8, tcb::as_bytes(tcb::span(data)));
}
initialized_ = true;
}
void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee)
void TwodeeRenderer::flush(Rhi& rhi, Twodee& twodee)
{
if (!initialized_)
{
initialize(rhi, ctx);
initialize(rhi);
}
// Stage 1 - command list patch detection
@ -297,7 +262,7 @@ void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee
}
if (cmd.colormap != nullptr)
{
palette_manager_->find_or_create_colormap(rhi, ctx, cmd.colormap);
palette_manager_->find_or_create_colormap(rhi, cmd.colormap);
}
},
[&](const Draw2dVertices& cmd) {}};
@ -309,7 +274,7 @@ void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee
{
patch_atlas_cache_->queue_patch(patch);
}
patch_atlas_cache_->pack(rhi, ctx);
patch_atlas_cache_->pack(rhi);
size_t list_index = 0;
for (auto& list : twodee)
@ -377,6 +342,8 @@ void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee
new_cmd.colormap = nullptr;
// safety: a command list is required to have at least 1 command
new_cmd.pipeline_key = pipeline_key_for_cmd(list.cmds[0]);
new_cmd.primitive = new_cmd.pipeline_key.lines ? PrimitiveType::kLines : PrimitiveType::kTriangles;
new_cmd.blend_mode = new_cmd.pipeline_key.blend;
merged_list.cmds.push_back(std::move(new_cmd));
for (auto& cmd : list.cmds)
@ -445,7 +412,7 @@ void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee
{
if (cmd.flat_lump != LUMPERROR)
{
flat_manager_->find_or_create_indexed(rhi, ctx, cmd.flat_lump);
flat_manager_->find_or_create_indexed(rhi, cmd.flat_lump);
std::optional<MergedTwodeeCommand::Texture> t = MergedTwodeeCommandFlatTexture {cmd.flat_lump};
the_new_one.texture = t;
}
@ -458,6 +425,8 @@ void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee
}};
std::visit(tex_visitor_again, cmd);
the_new_one.pipeline_key = pipeline_key_for_cmd(cmd);
the_new_one.primitive = the_new_one.pipeline_key.lines ? PrimitiveType::kLines : PrimitiveType::kTriangles;
the_new_one.blend_mode = the_new_one.pipeline_key.blend;
merged_list.cmds.push_back(std::move(the_new_one));
}
@ -492,26 +461,21 @@ void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee
tcb::span<const std::byte> vertex_data = tcb::as_bytes(tcb::span(orig_list.vertices));
tcb::span<const std::byte> index_data = tcb::as_bytes(tcb::span(orig_list.indices));
rhi.update_buffer(ctx, merged_list.vbo, 0, vertex_data);
rhi.update_buffer(ctx, merged_list.ibo, 0, index_data);
rhi.update_buffer(merged_list.vbo, 0, vertex_data);
rhi.update_buffer(merged_list.ibo, 0, index_data);
// Update the binding sets for each individual merged command
VertexAttributeBufferBinding vbos[] = {{0, merged_list.vbo}};
for (auto& mcmd : merged_list.cmds)
{
TextureBinding tx[3];
auto tex_visitor = srb2::Overload {
[&](Handle<Texture> texture)
{
tx[0] = {SamplerName::kSampler0, texture};
tx[1] = {SamplerName::kSampler1, palette_tex};
mcmd.texture_handle = texture;
},
[&](const MergedTwodeeCommandFlatTexture& tex)
{
Handle<Texture> th = flat_manager_->find_or_create_indexed(rhi, ctx, tex.lump);
Handle<Texture> th = flat_manager_->find_or_create_indexed(rhi, tex.lump);
SRB2_ASSERT(th != kNullHandle);
tx[0] = {SamplerName::kSampler0, th};
tx[1] = {SamplerName::kSampler1, palette_tex};
mcmd.texture_handle = th;
}};
if (mcmd.texture)
{
@ -519,49 +483,39 @@ void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee
}
else
{
tx[0] = {SamplerName::kSampler0, default_tex_};
tx[1] = {SamplerName::kSampler1, palette_tex};
mcmd.texture_handle = default_tex_;
}
const uint8_t* colormap = mcmd.colormap;
Handle<Texture> colormap_h = palette_manager_->default_colormap();
if (colormap)
{
colormap_h = palette_manager_->find_or_create_colormap(rhi, ctx, colormap);
colormap_h = palette_manager_->find_or_create_colormap(rhi, colormap);
SRB2_ASSERT(colormap_h != kNullHandle);
}
tx[2] = {SamplerName::kSampler2, colormap_h};
mcmd.binding_set =
rhi.create_binding_set(ctx, pipelines_[mcmd.pipeline_key], {tcb::span(vbos), tcb::span(tx)});
mcmd.colormap_handle = colormap_h;
}
ctx_list_itr++;
}
// Uniform sets
std::array<UniformVariant, 1> g1_uniforms = {
// Projection
glm::mat4(
glm::vec4(2.f / vid.width, 0.f, 0.f, 0.f),
glm::vec4(0.f, -2.f / vid.height, 0.f, 0.f),
glm::vec4(0.f, 0.f, 1.f, 0.f),
glm::vec4(-1.f, 1.f, 0.f, 1.f)
),
};
std::array<UniformVariant, 3> g2_uniforms = {
// ModelView
glm::identity<glm::mat4>(),
// Texcoord0 Transform
glm::identity<glm::mat3>(),
// Sampler 0 Is Indexed Alpha (yes, it always is)
static_cast<int32_t>(1)
};
Handle<UniformSet> us_1 = rhi.create_uniform_set(ctx, {tcb::span(g1_uniforms)});
Handle<UniformSet> us_2 = rhi.create_uniform_set(ctx, {tcb::span(g2_uniforms)});
// Presumably, we're already in a renderpass when flush is called
rhi.bind_program(program_);
rhi.set_uniform("u_projection", glm::mat4(
glm::vec4(2.f / vid.width, 0.f, 0.f, 0.f),
glm::vec4(0.f, -2.f / vid.height, 0.f, 0.f),
glm::vec4(0.f, 0.f, 1.f, 0.f),
glm::vec4(-1.f, 1.f, 0.f, 1.f)
));
rhi.set_uniform("u_modelview", glm::identity<glm::mat4>());
rhi.set_uniform("u_texcoord0_transform", glm::identity<glm::mat3>());
rhi.set_uniform("u_sampler0_is_indexed_alpha", static_cast<int32_t>(1));
rhi.set_sampler("s_sampler1", 1, palette_tex);
for (auto& list : cmd_lists_)
{
rhi.bind_vertex_attrib("a_position", list.vbo, VertexAttributeFormat::kFloat3, offsetof(TwodeeVertex, x), sizeof(TwodeeVertex));
rhi.bind_vertex_attrib("a_texcoord0", list.vbo, VertexAttributeFormat::kFloat2, offsetof(TwodeeVertex, u), sizeof(TwodeeVertex));
rhi.bind_vertex_attrib("a_color", list.vbo, VertexAttributeFormat::kFloat4, offsetof(TwodeeVertex, r), sizeof(TwodeeVertex));
for (auto& cmd : list.cmds)
{
if (cmd.elements == 0)
@ -570,15 +524,18 @@ void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee
// This shouldn't happen, but, just in case...
continue;
}
SRB2_ASSERT(pipelines_.find(cmd.pipeline_key) != pipelines_.end());
Handle<Pipeline> pl = pipelines_[cmd.pipeline_key];
rhi.bind_pipeline(ctx, pl);
rhi.set_viewport(ctx, {0, 0, static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height)});
rhi.bind_uniform_set(ctx, 0, us_1);
rhi.bind_uniform_set(ctx, 1, us_2);
rhi.bind_binding_set(ctx, cmd.binding_set);
rhi.bind_index_buffer(ctx, list.ibo);
rhi.draw_indexed(ctx, cmd.elements, cmd.index_offset);
RasterizerStateDesc desc;
desc.cull = CullMode::kNone;
desc.primitive = cmd.primitive;
desc.blend_enabled = true;
set_blend_state(desc, cmd.blend_mode);
// Set blend and primitives
rhi.set_rasterizer_state(desc);
rhi.set_viewport({0, 0, static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height)});
rhi.set_sampler("s_sampler0", 0, cmd.texture_handle);
rhi.set_sampler("s_sampler2", 2, cmd.colormap_handle);
rhi.bind_index_buffer(list.ibo);
rhi.draw_indexed(cmd.elements, cmd.index_offset);
}
}

View file

@ -11,10 +11,8 @@
#ifndef __SRB2_HWR2_PASS_TWODEE_HPP__
#define __SRB2_HWR2_PASS_TWODEE_HPP__
#include <memory>
#include <optional>
#include <tuple>
#include <unordered_map>
#include <variant>
#include <vector>
@ -65,10 +63,13 @@ struct MergedTwodeeCommandFlatTexture
struct MergedTwodeeCommand
{
using Texture = std::variant<rhi::Handle<rhi::Texture>, MergedTwodeeCommandFlatTexture>;
TwodeePipelineKey pipeline_key = {};
rhi::Handle<rhi::BindingSet> binding_set = {};
rhi::PrimitiveType primitive;
BlendMode blend_mode;
std::optional<Texture> texture;
TwodeePipelineKey pipeline_key;
rhi::Handle<rhi::Texture> texture_handle;
const uint8_t* colormap;
rhi::Handle<rhi::Texture> colormap_handle;
uint32_t index_offset = 0;
uint32_t elements = 0;
};
@ -94,14 +95,13 @@ class TwodeeRenderer final
std::vector<MergedTwodeeCommandList> cmd_lists_;
std::vector<std::tuple<rhi::Handle<rhi::Buffer>, std::size_t>> vbos_;
std::vector<std::tuple<rhi::Handle<rhi::Buffer>, std::size_t>> ibos_;
rhi::Handle<rhi::RenderPass> render_pass_;
rhi::Handle<rhi::Texture> output_;
rhi::Handle<rhi::Texture> default_tex_;
std::unordered_map<TwodeePipelineKey, rhi::Handle<rhi::Pipeline>> pipelines_;
rhi::Handle<rhi::Program> program_;
void rewrite_patch_quad_vertices(Draw2dList& list, const Draw2dPatchQuad& cmd) const;
void initialize(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void initialize(rhi::Rhi& rhi);
public:
TwodeeRenderer(
@ -118,7 +118,7 @@ public:
/// @brief Flush accumulated Twodee state and perform draws.
/// @param rhi
/// @param ctx
void flush(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, Twodee& twodee);
void flush(rhi::Rhi& rhi, Twodee& twodee);
};
} // namespace srb2::hwr2

View file

@ -27,7 +27,7 @@ static bool size_equal(Rhi& rhi, Handle<Texture> tex, uint32_t width, uint32_t h
return deets.width == width && deets.height == height;
}
void UpscaleBackbuffer::begin_pass(Rhi& rhi, Handle<GraphicsContext> ctx)
void UpscaleBackbuffer::begin_pass(Rhi& rhi)
{
uint32_t vid_width = static_cast<uint32_t>(vid.width);
uint32_t vid_height = static_cast<uint32_t>(vid.height);
@ -38,19 +38,6 @@ void UpscaleBackbuffer::begin_pass(Rhi& rhi, Handle<GraphicsContext> ctx)
remake = true;
}
auto new_renderpass = [&rhi = rhi](AttachmentLoadOp load_op, AttachmentStoreOp store_op)
{
RenderPassDesc desc {};
desc.use_depth_stencil = false;
desc.color_load_op = load_op;
desc.color_store_op = store_op;
desc.depth_load_op = load_op;
desc.depth_store_op = store_op;
desc.stencil_load_op = load_op;
desc.stencil_store_op = store_op;
return rhi.create_render_pass(desc);
};
if (remake)
{
if (color_)
@ -70,23 +57,16 @@ void UpscaleBackbuffer::begin_pass(Rhi& rhi, Handle<GraphicsContext> ctx)
RenderbufferDesc depth_tex {};
depth_tex.width = vid_width;
depth_tex.height = vid_height;
if (!renderpass_clear_)
{
renderpass_clear_ = new_renderpass(AttachmentLoadOp::kClear, AttachmentStoreOp::kStore);
}
}
else
{
if (!renderpass_)
{
renderpass_ = new_renderpass(AttachmentLoadOp::kLoad, AttachmentStoreOp::kStore);
}
}
RenderPassBeginInfo begin_info {};
begin_info.render_pass = remake ? renderpass_clear_ : renderpass_;
begin_info.clear_color = {0, 0, 0, 1};
begin_info.color_attachment = color_;
rhi.begin_render_pass(ctx, begin_info);
begin_info.color_load_op = rhi::AttachmentLoadOp::kLoad;
begin_info.color_store_op = rhi::AttachmentStoreOp::kStore;
begin_info.depth_load_op = rhi::AttachmentLoadOp::kLoad;
begin_info.depth_store_op = rhi::AttachmentStoreOp::kStore;
begin_info.stencil_load_op = rhi::AttachmentLoadOp::kLoad;
begin_info.stencil_store_op = rhi::AttachmentStoreOp::kStore;
rhi.push_render_pass(begin_info);
}

View file

@ -19,8 +19,6 @@ namespace srb2::hwr2
class UpscaleBackbuffer
{
rhi::Handle<rhi::Texture> color_;
rhi::Handle<rhi::RenderPass> renderpass_;
rhi::Handle<rhi::RenderPass> renderpass_clear_;
public:
UpscaleBackbuffer();
@ -31,7 +29,7 @@ public:
UpscaleBackbuffer& operator=(const UpscaleBackbuffer&) = delete;
UpscaleBackbuffer& operator=(UpscaleBackbuffer&&);
void begin_pass(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
void begin_pass(rhi::Rhi& rhi);
rhi::Handle<rhi::Texture> color() const noexcept { return color_; }
};

View file

@ -28,7 +28,6 @@ extern rhi::Handle<rhi::Rhi> g_current_rhi;
rhi::Rhi* get_rhi(rhi::Handle<rhi::Rhi> handle);
rhi::Handle<rhi::GraphicsContext> main_graphics_context();
hwr2::HardwareState* main_hardware_state();
} // namespace srb2::sys

View file

@ -56,7 +56,6 @@ using namespace srb2::rhi;
static Rhi* g_last_known_rhi = nullptr;
static bool g_imgui_frame_active = false;
static Handle<GraphicsContext> g_main_graphics_context;
static HardwareState g_hw_state;
Handle<Rhi> srb2::sys::g_current_rhi = kNullHandle;
@ -88,6 +87,7 @@ static void reset_hardware_state(Rhi* rhi)
g_hw_state.crtsharp_blit_rect = std::make_unique<BlitRectPass>(BlitRectPass::BlitMode::kCrtSharp);
g_hw_state.screen_capture = std::make_unique<ScreenshotPass>();
g_hw_state.backbuffer = std::make_unique<UpscaleBackbuffer>();
g_hw_state.imgui_renderer = std::make_unique<ImguiRenderer>();
g_hw_state.wipe_frames = {};
g_last_known_rhi = rhi;
@ -98,9 +98,7 @@ static void new_imgui_frame();
static void preframe_update(Rhi& rhi)
{
SRB2_ASSERT(g_main_graphics_context != kNullHandle);
g_hw_state.palette_manager->update(rhi, g_main_graphics_context);
g_hw_state.palette_manager->update(rhi);
new_twodee_frame();
new_imgui_frame();
}
@ -196,11 +194,6 @@ static void new_imgui_frame()
g_imgui_frame_active = true;
}
rhi::Handle<rhi::GraphicsContext> sys::main_graphics_context()
{
return g_main_graphics_context;
}
HardwareState* sys::main_hardware_state()
{
return &g_hw_state;
@ -209,11 +202,10 @@ HardwareState* sys::main_hardware_state()
void I_CaptureVideoFrame()
{
rhi::Rhi* rhi = srb2::sys::get_rhi(srb2::sys::g_current_rhi);
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
hw_state->screen_capture->set_source(static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
hw_state->screen_capture->capture(*rhi, ctx);
hw_state->screen_capture->capture(*rhi);
}
void I_StartDisplayUpdate(void)
@ -244,12 +236,9 @@ void I_StartDisplayUpdate(void)
reset_hardware_state(rhi);
}
rhi::Handle<rhi::GraphicsContext> ctx = rhi->begin_graphics();
HardwareState* hw_state = &g_hw_state;
hw_state->backbuffer->begin_pass(*rhi, ctx);
g_main_graphics_context = ctx;
hw_state->backbuffer->begin_pass(*rhi);
preframe_update(*rhi);
}
@ -283,68 +272,63 @@ void I_FinishUpdate(void)
return;
}
rhi::Handle<rhi::GraphicsContext> ctx = g_main_graphics_context;
// better hope the drawing code left the context in a render pass, I guess
g_hw_state.twodee_renderer->flush(*rhi, g_2d);
rhi->pop_render_pass();
if (ctx != kNullHandle)
rhi->push_default_render_pass(true);
// Upscale draw the backbuffer (with postprocessing maybe?)
if (cv_scr_scale.value != FRACUNIT)
{
// better hope the drawing code left the context in a render pass, I guess
g_hw_state.twodee_renderer->flush(*rhi, ctx, g_2d);
rhi->end_render_pass(ctx);
float f = std::max(FixedToFloat(cv_scr_scale.value), 0.f);
float w = vid.realwidth * f;
float h = vid.realheight * f;
float x = (vid.realwidth - w) * (0.5f + (FixedToFloat(cv_scr_x.value) * 0.5f));
float y = (vid.realheight - h) * (0.5f + (FixedToFloat(cv_scr_y.value) * 0.5f));
rhi->begin_default_render_pass(ctx, true);
// Upscale draw the backbuffer (with postprocessing maybe?)
if (cv_scr_scale.value != FRACUNIT)
{
float f = std::max(FixedToFloat(cv_scr_scale.value), 0.f);
float w = vid.realwidth * f;
float h = vid.realheight * f;
float x = (vid.realwidth - w) * (0.5f + (FixedToFloat(cv_scr_x.value) * 0.5f));
float y = (vid.realheight - h) * (0.5f + (FixedToFloat(cv_scr_y.value) * 0.5f));
g_hw_state.blit_rect->set_output(x, y, w, h, true, true);
g_hw_state.sharp_bilinear_blit_rect->set_output(x, y, w, h, true, true);
g_hw_state.crt_blit_rect->set_output(x, y, w, h, true, true);
g_hw_state.crtsharp_blit_rect->set_output(x, y, w, h, true, true);
}
else
{
g_hw_state.blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true);
g_hw_state.sharp_bilinear_blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true);
g_hw_state.crt_blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true);
g_hw_state.crtsharp_blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true);
}
g_hw_state.blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
g_hw_state.sharp_bilinear_blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
g_hw_state.crt_blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
g_hw_state.crtsharp_blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
switch (cv_scr_effect.value)
{
case 1:
rhi->update_texture_settings(ctx, g_hw_state.backbuffer->color(), TextureWrapMode::kClamp, TextureWrapMode::kClamp, TextureFilterMode::kLinear, TextureFilterMode::kLinear);
g_hw_state.sharp_bilinear_blit_rect->draw(*rhi, ctx);
break;
case 2:
rhi->update_texture_settings(ctx, g_hw_state.backbuffer->color(), TextureWrapMode::kClamp, TextureWrapMode::kClamp, TextureFilterMode::kLinear, TextureFilterMode::kLinear);
g_hw_state.crt_blit_rect->draw(*rhi, ctx);
break;
case 3:
rhi->update_texture_settings(ctx, g_hw_state.backbuffer->color(), TextureWrapMode::kClamp, TextureWrapMode::kClamp, TextureFilterMode::kLinear, TextureFilterMode::kLinear);
g_hw_state.crtsharp_blit_rect->draw(*rhi, ctx);
break;
default:
rhi->update_texture_settings(ctx, g_hw_state.backbuffer->color(), TextureWrapMode::kClamp, TextureWrapMode::kClamp, TextureFilterMode::kNearest, TextureFilterMode::kNearest);
g_hw_state.blit_rect->draw(*rhi, ctx);
break;
}
rhi->end_render_pass(ctx);
rhi->end_graphics(ctx);
g_main_graphics_context = kNullHandle;
postframe_update(*rhi);
g_hw_state.blit_rect->set_output(x, y, w, h, true, true);
g_hw_state.sharp_bilinear_blit_rect->set_output(x, y, w, h, true, true);
g_hw_state.crt_blit_rect->set_output(x, y, w, h, true, true);
g_hw_state.crtsharp_blit_rect->set_output(x, y, w, h, true, true);
}
else
{
g_hw_state.blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true);
g_hw_state.sharp_bilinear_blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true);
g_hw_state.crt_blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true);
g_hw_state.crtsharp_blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true);
}
g_hw_state.blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
g_hw_state.sharp_bilinear_blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
g_hw_state.crt_blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
g_hw_state.crtsharp_blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
switch (cv_scr_effect.value)
{
case 1:
rhi->update_texture_settings(g_hw_state.backbuffer->color(), TextureWrapMode::kClamp, TextureWrapMode::kClamp, TextureFilterMode::kLinear, TextureFilterMode::kLinear);
g_hw_state.sharp_bilinear_blit_rect->draw(*rhi);
break;
case 2:
rhi->update_texture_settings(g_hw_state.backbuffer->color(), TextureWrapMode::kClamp, TextureWrapMode::kClamp, TextureFilterMode::kLinear, TextureFilterMode::kLinear);
g_hw_state.crt_blit_rect->draw(*rhi);
break;
case 3:
rhi->update_texture_settings(g_hw_state.backbuffer->color(), TextureWrapMode::kClamp, TextureWrapMode::kClamp, TextureFilterMode::kLinear, TextureFilterMode::kLinear);
g_hw_state.crtsharp_blit_rect->draw(*rhi);
break;
default:
rhi->update_texture_settings(g_hw_state.backbuffer->color(), TextureWrapMode::kClamp, TextureWrapMode::kClamp, TextureFilterMode::kNearest, TextureFilterMode::kNearest);
g_hw_state.blit_rect->draw(*rhi);
break;
}
g_hw_state.imgui_renderer->render(*rhi);
rhi->pop_render_pass();
postframe_update(*rhi);
rhi->present();
rhi->finish();

File diff suppressed because it is too large Load diff

View file

@ -71,7 +71,7 @@ struct Gl2Platform
virtual ~Gl2Platform();
virtual void present() = 0;
virtual std::tuple<std::vector<std::string>, std::vector<std::string>> find_shader_sources(PipelineProgram program) = 0;
virtual std::tuple<std::vector<std::string>, std::vector<std::string>> find_shader_sources(const char* name) = 0;
virtual Rect get_default_framebuffer_dimensions() = 0;
};
@ -87,41 +87,19 @@ struct Gl2Buffer : public rhi::Buffer
rhi::BufferDesc desc;
};
struct Gl2RenderPass : public rhi::RenderPass
{
rhi::RenderPassDesc desc;
};
struct Gl2Renderbuffer : public rhi::Renderbuffer
{
uint32_t renderbuffer;
rhi::RenderbufferDesc desc;
};
struct Gl2UniformSet : public rhi::UniformSet
{
std::vector<rhi::UniformVariant> uniforms;
};
struct Gl2BindingSet : public rhi::BindingSet
{
std::vector<rhi::VertexAttributeBufferBinding> vertex_buffer_bindings;
std::unordered_map<rhi::SamplerName, uint32_t> textures {4};
};
struct Gl2Pipeline : public rhi::Pipeline
struct Gl2Program : public rhi::Program
{
uint32_t vertex_shader = 0;
uint32_t fragment_shader = 0;
uint32_t program = 0;
std::unordered_map<rhi::VertexAttributeName, uint32_t> attrib_locations {2};
std::unordered_map<rhi::UniformName, uint32_t> uniform_locations {2};
std::unordered_map<rhi::SamplerName, uint32_t> sampler_locations {2};
rhi::PipelineDesc desc;
};
struct Gl2GraphicsContext : public rhi::GraphicsContext
{
std::unordered_map<std::string, uint32_t> attrib_locations;
std::unordered_map<std::string, uint32_t> uniform_locations;
};
struct Gl2ActiveUniform
@ -136,13 +114,10 @@ class Gl2Rhi final : public Rhi
std::unique_ptr<GladGLContext> gl_;
Slab<Gl2RenderPass> render_pass_slab_;
Slab<Gl2Texture> texture_slab_;
Slab<Gl2Buffer> buffer_slab_;
Slab<Gl2Renderbuffer> renderbuffer_slab_;
Slab<Gl2Pipeline> pipeline_slab_;
Slab<Gl2UniformSet> uniform_set_slab_;
Slab<Gl2BindingSet> binding_set_slab_;
Slab<Gl2Program> program_slab_;
Handle<Buffer> current_index_buffer_;
@ -150,13 +125,12 @@ class Gl2Rhi final : public Rhi
struct DefaultRenderPassState
{
bool clear = false;
};
using RenderPassState = std::variant<DefaultRenderPassState, RenderPassBeginInfo>;
std::optional<RenderPassState> current_render_pass_;
std::optional<Handle<Pipeline>> current_pipeline_;
std::vector<RenderPassState> render_pass_stack_;
std::optional<Handle<Program>> current_program_;
PrimitiveType current_primitive_type_ = PrimitiveType::kPoints;
bool graphics_context_active_ = false;
uint32_t graphics_context_generation_ = 1;
uint32_t index_buffer_offset_ = 0;
uint8_t stencil_front_reference_ = 0;
@ -165,15 +139,18 @@ class Gl2Rhi final : public Rhi
uint8_t stencil_back_reference_ = 0;
uint8_t stencil_back_compare_mask_ = 0xFF;
uint8_t stencil_back_write_mask_ = 0xFF;
CompareFunc stencil_front_func_;
CompareFunc stencil_back_func_;
void apply_default_framebuffer(bool clear);
void apply_framebuffer(const RenderPassBeginInfo& info, bool allow_clear);
public:
Gl2Rhi(std::unique_ptr<Gl2Platform>&& platform, GlLoadFunc load_func);
virtual ~Gl2Rhi();
virtual Handle<RenderPass> create_render_pass(const RenderPassDesc& desc) override;
virtual void destroy_render_pass(Handle<RenderPass> handle) override;
virtual Handle<Pipeline> create_pipeline(const PipelineDesc& desc) override;
virtual void destroy_pipeline(Handle<Pipeline> handle) override;
virtual Handle<Program> create_program(const ProgramDesc& desc) override;
virtual void destroy_program(Handle<Program> handle) override;
virtual Handle<Texture> create_texture(const TextureDesc& desc) override;
virtual void destroy_texture(Handle<Texture> handle) override;
@ -187,58 +164,63 @@ public:
virtual uint32_t get_buffer_size(Handle<Buffer> buffer) override;
virtual void update_buffer(
Handle<GraphicsContext> ctx,
Handle<Buffer> buffer,
uint32_t offset,
tcb::span<const std::byte> data
) override;
virtual void update_texture(
Handle<GraphicsContext> ctx,
Handle<Texture> texture,
Rect region,
srb2::rhi::PixelFormat data_format,
tcb::span<const std::byte> data
) override;
virtual void update_texture_settings(
Handle<GraphicsContext> ctx,
Handle<Texture> texture,
TextureWrapMode u_wrap,
TextureWrapMode v_wrap,
TextureFilterMode min,
TextureFilterMode mag
) override;
virtual Handle<UniformSet>
create_uniform_set(Handle<GraphicsContext> ctx, const CreateUniformSetInfo& info) override;
virtual Handle<BindingSet>
create_binding_set(Handle<GraphicsContext> ctx, Handle<Pipeline> pipeline, const CreateBindingSetInfo& info)
override;
virtual Handle<GraphicsContext> begin_graphics() override;
virtual void end_graphics(Handle<GraphicsContext> ctx) override;
// Graphics context functions
virtual void begin_default_render_pass(Handle<GraphicsContext> ctx, bool clear) override;
virtual void begin_render_pass(Handle<GraphicsContext> ctx, const RenderPassBeginInfo& info) override;
virtual void end_render_pass(Handle<GraphicsContext> ctx) override;
virtual void bind_pipeline(Handle<GraphicsContext> ctx, Handle<Pipeline> pipeline) override;
virtual void bind_uniform_set(Handle<GraphicsContext> ctx, uint32_t slot, Handle<UniformSet> set) override;
virtual void bind_binding_set(Handle<GraphicsContext> ctx, Handle<BindingSet> set) override;
virtual void bind_index_buffer(Handle<GraphicsContext> ctx, Handle<Buffer> buffer) override;
virtual void set_scissor(Handle<GraphicsContext> ctx, const Rect& rect) override;
virtual void set_viewport(Handle<GraphicsContext> ctx, const Rect& rect) override;
virtual void draw(Handle<GraphicsContext> ctx, uint32_t vertex_count, uint32_t first_vertex) override;
virtual void draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count, uint32_t first_index) override;
virtual void push_default_render_pass(bool clear) override;
virtual void push_render_pass(const RenderPassBeginInfo& info) override;
virtual void pop_render_pass() override;
virtual void bind_program(Handle<Program> program) override;
virtual void bind_vertex_attrib(
const char* name,
Handle<Buffer> buffer,
VertexAttributeFormat format,
uint32_t offset,
uint32_t stride
) override;
virtual void bind_index_buffer(Handle<Buffer> buffer) override;
virtual void set_uniform(const char* name, float value) override;
virtual void set_uniform(const char* name, int value) override;
virtual void set_uniform(const char* name, glm::vec2 value) override;
virtual void set_uniform(const char* name, glm::vec3 value) override;
virtual void set_uniform(const char* name, glm::vec4 value) override;
virtual void set_uniform(const char* name, glm::ivec2 value) override;
virtual void set_uniform(const char* name, glm::ivec3 value) override;
virtual void set_uniform(const char* name, glm::ivec4 value) override;
virtual void set_uniform(const char* name, glm::mat2 value) override;
virtual void set_uniform(const char* name, glm::mat3 value) override;
virtual void set_uniform(const char* name, glm::mat4 value) override;
virtual void set_sampler(const char* name, uint32_t slot, Handle<Texture> texture) override;
virtual void set_rasterizer_state(const RasterizerStateDesc& desc) override;
virtual void set_viewport(const Rect& rect) override;
virtual void draw(uint32_t vertex_count, uint32_t first_vertex) override;
virtual void draw_indexed(uint32_t index_count, uint32_t first_index) override;
virtual void
read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, PixelFormat format, tcb::span<std::byte> out) override;
read_pixels(const Rect& rect, PixelFormat format, tcb::span<std::byte> out) override;
virtual void copy_framebuffer_to_texture(
Handle<GraphicsContext> ctx,
Handle<Texture> dst_tex,
const Rect& dst_region,
const Rect& src_region
) override;
virtual void set_stencil_reference(Handle<GraphicsContext> ctx, CullMode face, uint8_t reference) override;
virtual void set_stencil_compare_mask(Handle<GraphicsContext> ctx, CullMode face, uint8_t mask) override;
virtual void set_stencil_write_mask(Handle<GraphicsContext> ctx, CullMode face, uint8_t mask) override;
virtual void set_stencil_reference(CullMode face, uint8_t reference) override;
virtual void set_stencil_compare_mask(CullMode face, uint8_t mask) override;
virtual void set_stencil_write_mask(CullMode face, uint8_t mask) override;
virtual void present() override;

View file

@ -923,7 +923,7 @@ void Gles2Rhi::present()
platform_->present();
}
void Gles2Rhi::begin_default_render_pass(Handle<GraphicsContext> ctx)
void Gles2Rhi::push_default_render_pass(Handle<GraphicsContext> ctx)
{
SRB2_ASSERT(platform_ != nullptr);
SRB2_ASSERT(graphics_context_active_ == true);
@ -942,7 +942,7 @@ void Gles2Rhi::begin_default_render_pass(Handle<GraphicsContext> ctx)
current_render_pass_ = Gles2Rhi::DefaultRenderPassState {};
}
void Gles2Rhi::begin_render_pass(Handle<GraphicsContext> ctx, const RenderPassBeginInfo& info)
void Gles2Rhi::push_render_pass(Handle<GraphicsContext> ctx, const RenderPassBeginInfo& info)
{
SRB2_ASSERT(graphics_context_active_ == true && graphics_context_generation_ == ctx.generation());
SRB2_ASSERT(current_render_pass_.has_value() == false);
@ -981,7 +981,7 @@ void Gles2Rhi::begin_render_pass(Handle<GraphicsContext> ctx, const RenderPassBe
current_render_pass_ = info;
}
void Gles2Rhi::end_render_pass(Handle<GraphicsContext> ctx)
void Gles2Rhi::pop_render_pass(Handle<GraphicsContext> ctx)
{
SRB2_ASSERT(graphics_context_active_ == true && graphics_context_generation_ == ctx.generation());
SRB2_ASSERT(current_render_pass_.has_value() == true);

View file

@ -133,9 +133,9 @@ public:
virtual void end_graphics(Handle<GraphicsContext>&& ctx) override;
// Graphics context functions
virtual void begin_default_render_pass(Handle<GraphicsContext> ctx) override;
virtual void begin_render_pass(Handle<GraphicsContext> ctx, const RenderPassBeginInfo& info) override;
virtual void end_render_pass(Handle<GraphicsContext> ctx) override;
virtual void push_default_render_pass(Handle<GraphicsContext> ctx) override;
virtual void push_render_pass(Handle<GraphicsContext> ctx, const RenderPassBeginInfo& info) override;
virtual void pop_render_pass(Handle<GraphicsContext> ctx) override;
virtual void bind_pipeline(Handle<GraphicsContext> ctx, Handle<Pipeline> pipeline) override;
virtual void update_bindings(Handle<GraphicsContext> ctx, const UpdateBindingsInfo& info) override;
virtual void update_uniforms(Handle<GraphicsContext> ctx, tcb::span<UniformUpdateData> uniforms) override;

View file

@ -13,9 +13,7 @@
#include <cstdint>
#include <optional>
#include <set>
#include <variant>
#include <vector>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
@ -26,6 +24,7 @@
#include <tcb/span.hpp>
#include "../core/static_vec.hpp"
#include "glm/ext/vector_float2.hpp"
#include "handle.hpp"
namespace srb2::rhi
@ -40,11 +39,8 @@ struct Texture
{
};
struct Pipeline
{
};
struct RenderPass
/// @brief A linked rendering pipeline program combining a vertex shader and fragment shader.
struct Program
{
};
@ -403,16 +399,6 @@ struct ColorMask
bool a;
};
struct BlendDesc
{
BlendFactor source_factor_color;
BlendFactor dest_factor_color;
BlendFunction color_function;
BlendFactor source_factor_alpha;
BlendFactor dest_factor_alpha;
BlendFunction alpha_function;
};
enum class StencilOp
{
kKeep,
@ -425,53 +411,41 @@ enum class StencilOp
kDecrementWrap
};
struct PipelineStencilOpStateDesc
struct ProgramDesc
{
StencilOp fail;
StencilOp pass;
StencilOp depth_fail;
CompareFunc stencil_compare;
const char* name;
tcb::span<const char*> defines;
};
struct PipelineDepthStencilStateDesc
struct RasterizerStateDesc
{
bool depth_test;
bool depth_write;
CompareFunc depth_func;
bool stencil_test;
PipelineStencilOpStateDesc front;
PipelineStencilOpStateDesc back;
};
struct PipelineColorStateDesc
{
std::optional<BlendDesc> blend;
ColorMask color_mask;
};
struct PipelineDesc
{
PipelineProgram program;
VertexInputDesc vertex_input;
UniformInputDesc uniform_input;
SamplerInputDesc sampler_input;
std::optional<PipelineDepthStencilStateDesc> depth_stencil_state;
PipelineColorStateDesc color_state;
PrimitiveType primitive;
CullMode cull;
FaceWinding winding;
glm::vec4 blend_color;
};
struct RenderPassDesc
{
bool use_depth_stencil;
AttachmentLoadOp color_load_op;
AttachmentStoreOp color_store_op;
AttachmentLoadOp depth_load_op;
AttachmentStoreOp depth_store_op;
AttachmentLoadOp stencil_load_op;
AttachmentStoreOp stencil_store_op;
PrimitiveType primitive = PrimitiveType::kTriangles;
CullMode cull = CullMode::kBack;
FaceWinding winding = FaceWinding::kCounterClockwise;
ColorMask color_mask = {true, true, true, true};
bool blend_enabled = false;
glm::vec4 blend_color = {0.0, 0.0, 0.0, 0.0};
BlendFactor blend_source_factor_color = BlendFactor::kOne;
BlendFactor blend_dest_factor_color = BlendFactor::kZero;
BlendFunction blend_color_function = BlendFunction::kAdd;
BlendFactor blend_source_factor_alpha = BlendFactor::kOne;
BlendFactor blend_dest_factor_alpha = BlendFactor::kZero;
BlendFunction blend_alpha_function = BlendFunction::kAdd;
bool depth_test = false;
bool depth_write = true;
CompareFunc depth_func = CompareFunc::kLess;
bool stencil_test = false;
StencilOp front_fail = StencilOp::kKeep;
StencilOp front_pass = StencilOp::kKeep;
StencilOp front_depth_fail = StencilOp::kKeep;
CompareFunc front_stencil_compare = CompareFunc::kAlways;
StencilOp back_fail = StencilOp::kKeep;
StencilOp back_pass = StencilOp::kKeep;
StencilOp back_depth_fail = StencilOp::kKeep;
CompareFunc back_stencil_compare = CompareFunc::kAlways;
bool scissor_test = false;
Rect scissor = {};
};
struct RenderbufferDesc
@ -513,10 +487,15 @@ struct BufferDesc
struct RenderPassBeginInfo
{
Handle<RenderPass> render_pass;
Handle<Texture> color_attachment;
std::optional<Handle<Renderbuffer>> depth_stencil_attachment;
glm::vec4 clear_color;
AttachmentLoadOp color_load_op;
AttachmentStoreOp color_store_op;
AttachmentLoadOp depth_load_op;
AttachmentStoreOp depth_store_op;
AttachmentLoadOp stencil_load_op;
AttachmentStoreOp stencil_store_op;
};
using UniformVariant = std::variant<
@ -577,17 +556,6 @@ struct CreateBindingSetInfo
tcb::span<TextureBinding> sampler_textures;
};
struct UniformSet
{
};
struct BindingSet
{
};
struct GraphicsContext
{
};
struct TextureDetails
{
uint32_t width;
@ -604,10 +572,8 @@ struct Rhi
{
virtual ~Rhi();
virtual Handle<RenderPass> create_render_pass(const RenderPassDesc& desc) = 0;
virtual void destroy_render_pass(Handle<RenderPass> handle) = 0;
virtual Handle<Pipeline> create_pipeline(const PipelineDesc& desc) = 0;
virtual void destroy_pipeline(Handle<Pipeline> handle) = 0;
virtual Handle<Program> create_program(const ProgramDesc& desc) = 0;
virtual void destroy_program(Handle<Program> handle) = 0;
virtual Handle<Texture> create_texture(const TextureDesc& desc) = 0;
virtual void destroy_texture(Handle<Texture> handle) = 0;
@ -621,56 +587,63 @@ struct Rhi
virtual uint32_t get_buffer_size(Handle<Buffer> buffer) = 0;
virtual void update_buffer(
Handle<GraphicsContext> ctx,
Handle<Buffer> buffer,
uint32_t offset,
tcb::span<const std::byte> data
) = 0;
virtual void update_texture(
Handle<GraphicsContext> ctx,
Handle<Texture> texture,
Rect region,
srb2::rhi::PixelFormat data_format,
tcb::span<const std::byte> data
) = 0;
virtual void update_texture_settings(
Handle<GraphicsContext> ctx,
Handle<Texture> texture,
TextureWrapMode u_wrap,
TextureWrapMode v_wrap,
TextureFilterMode min,
TextureFilterMode mag
) = 0;
virtual Handle<UniformSet> create_uniform_set(Handle<GraphicsContext> ctx, const CreateUniformSetInfo& info) = 0;
virtual Handle<BindingSet>
create_binding_set(Handle<GraphicsContext> ctx, Handle<Pipeline> pipeline, const CreateBindingSetInfo& info) = 0;
virtual Handle<GraphicsContext> begin_graphics() = 0;
virtual void end_graphics(Handle<GraphicsContext> ctx) = 0;
// Graphics context functions
virtual void begin_default_render_pass(Handle<GraphicsContext> ctx, bool clear) = 0;
virtual void begin_render_pass(Handle<GraphicsContext> ctx, const RenderPassBeginInfo& info) = 0;
virtual void end_render_pass(Handle<GraphicsContext> ctx) = 0;
virtual void bind_pipeline(Handle<GraphicsContext> ctx, Handle<Pipeline> pipeline) = 0;
virtual void bind_uniform_set(Handle<GraphicsContext> ctx, uint32_t slot, Handle<UniformSet> set) = 0;
virtual void bind_binding_set(Handle<GraphicsContext> ctx, Handle<BindingSet> set) = 0;
virtual void bind_index_buffer(Handle<GraphicsContext> ctx, Handle<Buffer> buffer) = 0;
virtual void set_scissor(Handle<GraphicsContext> ctx, const Rect& rect) = 0;
virtual void set_viewport(Handle<GraphicsContext> ctx, const Rect& rect) = 0;
virtual void draw(Handle<GraphicsContext> ctx, uint32_t vertex_count, uint32_t first_vertex) = 0;
virtual void draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count, uint32_t first_index) = 0;
virtual void push_default_render_pass(bool clear) = 0;
virtual void push_render_pass(const RenderPassBeginInfo& info) = 0;
virtual void pop_render_pass() = 0;
virtual void bind_program(Handle<Program> program) = 0;
virtual void bind_vertex_attrib(
const char* name,
Handle<Buffer> buffer,
VertexAttributeFormat format,
uint32_t offset,
uint32_t stride
) = 0;
virtual void bind_index_buffer(Handle<Buffer> buffer) = 0;
virtual void set_uniform(const char* name, float value) = 0;
virtual void set_uniform(const char* name, int value) = 0;
virtual void set_uniform(const char* name, glm::vec2 value) = 0;
virtual void set_uniform(const char* name, glm::vec3 value) = 0;
virtual void set_uniform(const char* name, glm::vec4 value) = 0;
virtual void set_uniform(const char* name, glm::ivec2 value) = 0;
virtual void set_uniform(const char* name, glm::ivec3 value) = 0;
virtual void set_uniform(const char* name, glm::ivec4 value) = 0;
virtual void set_uniform(const char* name, glm::mat2 value) = 0;
virtual void set_uniform(const char* name, glm::mat3 value) = 0;
virtual void set_uniform(const char* name, glm::mat4 value) = 0;
virtual void set_sampler(const char* name, uint32_t slot, Handle<Texture> texture) = 0;
virtual void set_rasterizer_state(const RasterizerStateDesc& desc) = 0;
virtual void set_viewport(const Rect& rect) = 0;
virtual void draw(uint32_t vertex_count, uint32_t first_vertex) = 0;
virtual void draw_indexed(uint32_t index_count, uint32_t first_index) = 0;
virtual void
read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, PixelFormat format, tcb::span<std::byte> out) = 0;
read_pixels(const Rect& rect, PixelFormat format, tcb::span<std::byte> out) = 0;
virtual void copy_framebuffer_to_texture(
Handle<GraphicsContext> ctx,
Handle<Texture> dst_tex,
const Rect& dst_region,
const Rect& src_region
) = 0;
virtual void set_stencil_reference(Handle<GraphicsContext> ctx, CullMode face, uint8_t reference) = 0;
virtual void set_stencil_compare_mask(Handle<GraphicsContext> ctx, CullMode face, uint8_t mask) = 0;
virtual void set_stencil_write_mask(Handle<GraphicsContext> ctx, CullMode face, uint8_t mask) = 0;
virtual void set_stencil_reference(CullMode face, uint8_t reference) = 0;
virtual void set_stencil_compare_mask(CullMode face, uint8_t mask) = 0;
virtual void set_stencil_write_mask(CullMode face, uint8_t mask) = 0;
virtual void present() = 0;

View file

@ -12,6 +12,7 @@
/// \file
/// \brief SRB2 graphics stuff for SDL
#include <SDL_video.h>
#include <stdlib.h>
#include <errno.h>
#include <memory>

View file

@ -34,35 +34,10 @@ void SdlGl2Platform::present()
SDL_GL_SwapWindow(window);
}
static constexpr const char* pipeline_lump_slug(rhi::PipelineProgram program)
static std::array<std::string, 2> glsllist_lump_names(const char* name)
{
switch (program)
{
case rhi::PipelineProgram::kUnshaded:
return "unshaded";
case rhi::PipelineProgram::kUnshadedPaletted:
return "unshadedpaletted";
case rhi::PipelineProgram::kPostprocessWipe:
return "postprocesswipe";
case rhi::PipelineProgram::kPostimg:
return "postimg";
case rhi::PipelineProgram::kSharpBilinear:
return "sharpbilinear";
case rhi::PipelineProgram::kCrt:
return "crt";
case rhi::PipelineProgram::kCrtSharp:
return "crtsharp";
default:
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);
std::string vertex_list_name = fmt::format("rhi_glsllist_{}_vertex", name);
std::string fragment_list_name = fmt::format("rhi_glsllist_{}_fragment", name);
return {std::move(vertex_list_name), std::move(fragment_list_name)};
}
@ -132,9 +107,9 @@ static std::vector<std::string> get_sources_from_glsllist_lump(const char* lumpn
}
std::tuple<std::vector<std::string>, std::vector<std::string>>
SdlGl2Platform::find_shader_sources(rhi::PipelineProgram program)
SdlGl2Platform::find_shader_sources(const char* name)
{
std::array<std::string, 2> glsllist_names = glsllist_lump_names(program);
std::array<std::string, 2> glsllist_names = glsllist_lump_names(name);
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());

View file

@ -27,7 +27,7 @@ struct SdlGl2Platform final : public Gl2Platform
virtual void present() override;
virtual std::tuple<std::vector<std::string>, std::vector<std::string>>
find_shader_sources(PipelineProgram program) override;
find_shader_sources(const char* name) override;
virtual Rect get_default_framebuffer_dimensions() override;
};

View file

@ -2986,7 +2986,7 @@ void V_DrawStringScaled(
case gb_dpad: return {{1, 4, Draw::GenericButton::dpad}};
default: return {};
}
}();
}();
}
if (bt_inst)
@ -3766,11 +3766,10 @@ void VID_DisplaySoftwareScreen()
// TODO implement
// upload framebuffer, bind pipeline, draw
rhi::Rhi* rhi = srb2::sys::get_rhi(srb2::sys::g_current_rhi);
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
// Misnomer; this just uploads the screen to the software indexed screen texture
hw_state->software_screen_renderer->draw(*rhi, ctx);
hw_state->software_screen_renderer->draw(*rhi);
const int screens = std::clamp(r_splitscreen + 1, 1, MAXSPLITSCREENPLAYERS);
hw_state->blit_postimg_screens->set_num_screens(screens);
@ -3827,7 +3826,7 @@ void VID_DisplaySoftwareScreen()
}
// Post-process blit to the 'default' framebuffer
hw_state->blit_postimg_screens->draw(*rhi, ctx);
hw_state->blit_postimg_screens->draw(*rhi);
}
char *V_ParseText(const char *rawText)