Merge branch 'blit-modes-crt' into 'master'

Add optional CRT screen effect

See merge request KartKrew/Kart!2032
This commit is contained in:
AJ Martinez 2024-03-08 08:40:55 +00:00
commit 9af4615e58
12 changed files with 341 additions and 25 deletions

View file

@ -430,6 +430,7 @@ consvar_t cv_scr_depth = Player("scr_depth", "16 bits").values({{8, "8 bits"}, {
//added : 03-02-98: default screen mode, as loaded/saved in config
consvar_t cv_scr_width = Player("scr_width", "640").values(CV_Unsigned);
consvar_t cv_scr_height = Player("scr_height", "400").values(CV_Unsigned);
consvar_t cv_scr_effect = Player("scr_effect", "Sharp Bilinear").values({{0, "Nearest"}, {1, "Sharp Bilinear"}, {2, "SalCRT"}}).save();
consvar_t cv_scr_scale = Player("scr_scale", "1.0").floating_point();
consvar_t cv_scr_x = Player("scr_x", "0.0").floating_point();

View file

@ -51,7 +51,36 @@ static const PipelineDesc kUnshadedPipelineDescription = {
FaceWinding::kCounterClockwise,
{0.f, 0.f, 0.f, 1.f}};
BlitRectPass::BlitRectPass() = default;
/// @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}};
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)
@ -65,7 +94,21 @@ void BlitRectPass::prepass(Rhi& rhi)
{
if (!pipeline_)
{
pipeline_ = rhi.create_pipeline(kUnshadedPipelineDescription);
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;
default:
std::terminate();
}
}
if (!quad_vbo_)
@ -79,6 +122,20 @@ void BlitRectPass::prepass(Rhi& rhi)
quad_ibo_ = rhi.create_buffer({sizeof(kIndices), BufferType::kIndexBuffer, BufferUsage::kImmutable});
quad_ibo_needs_upload_ = true;
}
if (blit_mode_ == BlitRectPass::BlitMode::kCrt && !dot_pattern_)
{
dot_pattern_ = rhi.create_texture({
rhi::TextureFormat::kRGBA,
12,
4,
rhi::TextureWrapMode::kRepeat,
rhi::TextureWrapMode::kRepeat,
rhi::TextureFilterMode::kLinear,
rhi::TextureFilterMode::kLinear
});
dot_pattern_needs_upload_ = true;
}
}
void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
@ -95,6 +152,67 @@ void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
quad_ibo_needs_upload_ = false;
}
if (dot_pattern_needs_upload_ && dot_pattern_)
{
// Listen. I'm a *very* particular kind of lazy.
// If I'm being honest, I just don't want to have to embed a .png in the pk3s and deal with that.
static const uint8_t kDotPattern[] = {
255, 0, 0, 255,
0, 0, 0, 255,
0, 255, 0, 255,
0, 0, 0, 255,
0, 0, 255, 255,
0, 0, 0, 255,
255, 0, 0, 255,
0, 0, 0, 255,
0, 255, 0, 255,
0, 0, 0, 255,
0, 0, 255, 255,
0, 0, 0, 255,
255, 0, 0, 255,
0, 0, 0, 255,
0, 255, 0, 255,
0, 0, 0, 255,
0, 0, 255, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
255, 0, 0, 255,
0, 0, 0, 255,
0, 255, 0, 255,
0, 0, 0, 255,
0, 0, 255, 255,
0, 0, 0, 255,
255, 0, 0, 255,
0, 0, 0, 255,
0, 255, 0, 255,
0, 0, 0, 255,
0, 0, 255, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
0, 0, 0, 255,
255, 0, 0, 255,
0, 0, 0, 255,
0, 255, 0, 255,
0, 0, 0, 255,
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)));
dot_pattern_needs_upload_ = false;
}
float aspect = 1.0;
float output_aspect = 1.0;
if (output_correct_aspect_)
@ -104,6 +222,8 @@ void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
}
bool taller = aspect > output_aspect;
rhi::TextureDetails texture_details = rhi.get_texture_details(texture_);
std::array<rhi::UniformVariant, 1> g1_uniforms = {{
// Projection
glm::scale(
@ -112,26 +232,81 @@ void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
)
}};
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_[0] = rhi.create_uniform_set(ctx, {g1_uniforms});
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});
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});
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});
break;
}
}
}
void BlitRectPass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)

View file

@ -21,6 +21,15 @@ namespace srb2::hwr2
/// @brief A render pass which blits a rect using a source texture or textures.
class BlitRectPass
{
public:
enum class BlitMode
{
kNearest,
kSharpBilinear,
kCrt,
};
private:
rhi::Handle<rhi::Pipeline> pipeline_;
rhi::Handle<rhi::Texture> texture_;
uint32_t texture_width_ = 0;
@ -33,15 +42,20 @@ class BlitRectPass
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_;
bool quad_vbo_needs_upload_ = false;
bool quad_ibo_needs_upload_ = false;
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);
public:
explicit BlitRectPass(BlitMode blit_mode);
BlitRectPass();
~BlitRectPass();

View file

@ -38,6 +38,8 @@ struct HardwareState
std::unique_ptr<BlitPostimgScreens> blit_postimg_screens;
std::unique_ptr<PostprocessWipePass> wipe;
std::unique_ptr<BlitRectPass> blit_rect;
std::unique_ptr<BlitRectPass> sharp_bilinear_blit_rect;
std::unique_ptr<BlitRectPass> crt_blit_rect;
std::unique_ptr<ScreenshotPass> screen_capture;
std::unique_ptr<UpscaleBackbuffer> backbuffer;
WipeFrames wipe_frames;

View file

@ -82,7 +82,9 @@ static void reset_hardware_state(Rhi* rhi)
g_hw_state.software_screen_renderer = std::make_unique<SoftwareScreenRenderer>();
g_hw_state.blit_postimg_screens = std::make_unique<BlitPostimgScreens>(g_hw_state.palette_manager.get());
g_hw_state.wipe = std::make_unique<PostprocessWipePass>();
g_hw_state.blit_rect = std::make_unique<BlitRectPass>();
g_hw_state.blit_rect = std::make_unique<BlitRectPass>(BlitRectPass::BlitMode::kNearest);
g_hw_state.sharp_bilinear_blit_rect = std::make_unique<BlitRectPass>(BlitRectPass::BlitMode::kSharpBilinear);
g_hw_state.crt_blit_rect = std::make_unique<BlitRectPass>(BlitRectPass::BlitMode::kCrt);
g_hw_state.screen_capture = std::make_unique<ScreenshotPass>();
g_hw_state.backbuffer = std::make_unique<UpscaleBackbuffer>();
g_hw_state.wipe_frames = {};
@ -294,13 +296,34 @@ void I_FinishUpdate(void)
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);
}
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.blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
g_hw_state.blit_rect->draw(*rhi, ctx);
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));
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;
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);

View file

@ -27,6 +27,9 @@ menuitem_t OPTIONS_Video[] =
{IT_STRING | IT_CVAR, "FPS Cap", "Handles the frame rate of the game (35 to match game logic)",
NULL, {.cvar = &cv_fpscap}, 0, 0},
{IT_STRING | IT_CVAR, "Screen Effect", "Uses a special effect when displaying the game.",
NULL, {.cvar = &cv_scr_effect}, 0, 0},
{IT_NOTHING|IT_SPACE, NULL, NULL,
NULL, {NULL}, 0, 0},

View file

@ -127,6 +127,19 @@ constexpr GLenum map_texture_wrap(rhi::TextureWrapMode wrap)
return GL_REPEAT;
case rhi::TextureWrapMode::kMirroredRepeat:
return GL_MIRRORED_REPEAT;
default:
return GL_REPEAT;
}
}
constexpr GLenum map_texture_filter(rhi::TextureFilterMode filter)
{
switch (filter)
{
case rhi::TextureFilterMode::kNearest:
return GL_NEAREST;
case rhi::TextureFilterMode::kLinear:
return GL_LINEAR;
default:
return GL_NEAREST;
}
@ -595,9 +608,9 @@ rhi::Handle<rhi::Texture> Gl2Rhi::create_texture(const rhi::TextureDesc& desc)
gl_->BindTexture(GL_TEXTURE_2D, name);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, map_texture_filter(desc.min));
GL_ASSERT;
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, map_texture_filter(desc.mag));
GL_ASSERT;
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, map_texture_wrap(desc.u_wrap));
GL_ASSERT;
@ -672,6 +685,34 @@ void Gl2Rhi::update_texture(
GL_ASSERT;
}
void Gl2Rhi::update_texture_settings(
Handle<GraphicsContext> ctx,
Handle<Texture> texture,
TextureWrapMode u_wrap,
TextureWrapMode v_wrap,
TextureFilterMode min,
TextureFilterMode mag
)
{
SRB2_ASSERT(graphics_context_active_ == true);
SRB2_ASSERT(texture_slab_.is_valid(texture) == true);
auto& t = texture_slab_[texture];
gl_->ActiveTexture(GL_TEXTURE0);
GL_ASSERT;
gl_->BindTexture(GL_TEXTURE_2D, t.texture);
GL_ASSERT;
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, map_texture_wrap(u_wrap));
GL_ASSERT;
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, map_texture_wrap(v_wrap));
GL_ASSERT;
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, map_texture_filter(min));
GL_ASSERT;
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, map_texture_filter(mag));
GL_ASSERT;
}
rhi::Handle<rhi::Buffer> Gl2Rhi::create_buffer(const rhi::BufferDesc& desc)
{
GLenum target = map_buffer_type(desc.type);

View file

@ -198,6 +198,14 @@ public:
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>

View file

@ -67,6 +67,26 @@ const ProgramRequirements srb2::rhi::kProgramRequirementsPostimg = {
ProgramSamplerRequirements {{{SamplerName::kSampler0, true}, {SamplerName::kSampler1, false}}}
};
const ProgramRequirements srb2::rhi::kProgramRequirementsSharpBilinear = {
ProgramVertexInputRequirements {
{ProgramVertexInput {VertexAttributeName::kPosition, VertexAttributeFormat::kFloat3, true},
ProgramVertexInput {VertexAttributeName::kTexCoord0, VertexAttributeFormat::kFloat2, false},
ProgramVertexInput {VertexAttributeName::kColor, VertexAttributeFormat::kFloat4, false}}},
ProgramUniformRequirements {
{{{{UniformName::kProjection, true}}},
{{{UniformName::kModelView, true}, {UniformName::kTexCoord0Transform, true}, {UniformName::kSampler0Size, true}}}}},
ProgramSamplerRequirements {{{SamplerName::kSampler0, true}}}};
const ProgramRequirements srb2::rhi::kProgramRequirementsCrt = {
ProgramVertexInputRequirements {
{ProgramVertexInput {VertexAttributeName::kPosition, VertexAttributeFormat::kFloat3, true},
ProgramVertexInput {VertexAttributeName::kTexCoord0, VertexAttributeFormat::kFloat2, false},
ProgramVertexInput {VertexAttributeName::kColor, VertexAttributeFormat::kFloat4, false}}},
ProgramUniformRequirements {
{{{{UniformName::kProjection, true}}},
{{{UniformName::kModelView, true}, {UniformName::kTexCoord0Transform, true}, {UniformName::kSampler0Size, true}}}}},
ProgramSamplerRequirements {{{SamplerName::kSampler0, true}, {SamplerName::kSampler1, true}}}};
const ProgramRequirements& rhi::program_requirements_for_program(PipelineProgram program) noexcept
{
switch (program)
@ -79,6 +99,10 @@ const ProgramRequirements& rhi::program_requirements_for_program(PipelineProgram
return kProgramRequirementsPostprocessWipe;
case PipelineProgram::kPostimg:
return kProgramRequirementsPostimg;
case PipelineProgram::kSharpBilinear:
return kProgramRequirementsSharpBilinear;
case PipelineProgram::kCrt:
return kProgramRequirementsCrt;
default:
std::terminate();
}

View file

@ -172,7 +172,9 @@ enum class PipelineProgram
kUnshaded,
kUnshadedPaletted,
kPostprocessWipe,
kPostimg
kPostimg,
kSharpBilinear,
kCrt
};
enum class BufferType
@ -285,6 +287,8 @@ extern const ProgramRequirements kProgramRequirementsUnshaded;
extern const ProgramRequirements kProgramRequirementsUnshadedPaletted;
extern const ProgramRequirements kProgramRequirementsPostprocessWipe;
extern const ProgramRequirements kProgramRequirementsPostimg;
extern const ProgramRequirements kProgramRequirementsSharpBilinear;
extern const ProgramRequirements kProgramRequirementsCrt;
const ProgramRequirements& program_requirements_for_program(PipelineProgram program) noexcept;
@ -480,6 +484,12 @@ enum class TextureWrapMode
kClamp
};
enum class TextureFilterMode
{
kNearest,
kLinear
};
struct TextureDesc
{
TextureFormat format;
@ -487,6 +497,8 @@ struct TextureDesc
uint32_t height;
TextureWrapMode u_wrap;
TextureWrapMode v_wrap;
TextureFilterMode min;
TextureFilterMode mag;
};
struct BufferDesc
@ -618,6 +630,14 @@ struct Rhi
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;

View file

@ -135,6 +135,7 @@ extern INT32 scr_bpp;
extern UINT8 *scr_borderpatch; // patch used to fill the view borders
extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_renderer, cv_renderhitbox, cv_fullscreen;
extern consvar_t cv_scr_effect;
extern consvar_t cv_vhseffect, cv_shittyscreen;
extern consvar_t cv_parallelsoftware;

View file

@ -44,6 +44,10 @@ static constexpr const char* pipeline_lump_slug(rhi::PipelineProgram program)
return "postprocesswipe";
case rhi::PipelineProgram::kPostimg:
return "postimg";
case rhi::PipelineProgram::kSharpBilinear:
return "sharpbilinear";
case rhi::PipelineProgram::kCrt:
return "crt";
default:
return "";
}