diff --git a/src/hwr2/CMakeLists.txt b/src/hwr2/CMakeLists.txt index 8e525cad9..d961c57e6 100644 --- a/src/hwr2/CMakeLists.txt +++ b/src/hwr2/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources(SRB2SDL2 PRIVATE + blendmode.hpp pass_blit_postimg_screens.cpp pass_blit_postimg_screens.hpp pass_blit_rect.cpp diff --git a/src/hwr2/blendmode.hpp b/src/hwr2/blendmode.hpp new file mode 100644 index 000000000..b90e0b02e --- /dev/null +++ b/src/hwr2/blendmode.hpp @@ -0,0 +1,28 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by Ronald "Eidolon" Kinard +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#ifndef __SRB2_HWR2_BLENDMODE_HPP__ +#define __SRB2_HWR2_BLENDMODE_HPP__ + +namespace srb2::hwr2 +{ + +enum class BlendMode +{ + kAlphaTransparent, + kModulate, + kAdditive, + kSubtractive, + kReverseSubtractive, + kInvertDest +}; + +} // namespace srb2::hwr2 + +#endif // __SRB2_HWR2_BLENDMODE_HPP__ diff --git a/src/hwr2/pass_resource_managers.cpp b/src/hwr2/pass_resource_managers.cpp index 58ea993eb..a6f2a52cc 100644 --- a/src/hwr2/pass_resource_managers.cpp +++ b/src/hwr2/pass_resource_managers.cpp @@ -12,6 +12,7 @@ #include #include +#include "../r_state.h" #include "../v_video.h" #include "../z_zone.h" @@ -139,28 +140,148 @@ void FramebufferManager::postpass(Rhi& rhi) { } -MainPaletteManager::MainPaletteManager() : Pass() -{ -} - +MainPaletteManager::MainPaletteManager() = default; MainPaletteManager::~MainPaletteManager() = default; +constexpr std::size_t kPaletteSize = 256; +constexpr std::size_t kLighttableRows = LIGHTLEVELS; + void MainPaletteManager::prepass(Rhi& rhi) { if (!palette_) { - palette_ = rhi.create_texture({TextureFormat::kRGBA, 256, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); + palette_ = rhi.create_texture({TextureFormat::kRGBA, kPaletteSize, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); } + + if (!lighttable_) + { + lighttable_ = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, kLighttableRows, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); + } + + if (!encore_lighttable_) + { + encore_lighttable_ = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, kLighttableRows, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); + } + + if (!default_colormap_) + { + default_colormap_ = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); + } +} + +void MainPaletteManager::upload_palette(Rhi& rhi, Handle ctx) +{ + std::array 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))); +} + +void MainPaletteManager::upload_lighttables(Rhi& rhi, Handle ctx) +{ + tcb::span colormap_bytes = tcb::as_bytes(tcb::span(colormaps, kPaletteSize * kLighttableRows)); + rhi.update_texture(ctx, lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, colormap_bytes); + + if (encoremap != nullptr) + { + tcb::span encoremap_bytes = tcb::as_bytes(tcb::span(encoremap, kPaletteSize * kLighttableRows)); + rhi.update_texture(ctx, lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, encoremap_bytes); + } + + if (!lighttables_to_upload_.empty()) + { + for (auto lighttable : lighttables_to_upload_) + { + Handle lighttable_tex = find_extra_lighttable(lighttable); + SRB2_ASSERT(lighttable_tex != kNullHandle); + tcb::span lighttable_bytes = tcb::as_bytes(tcb::span(lighttable, kPaletteSize * kLighttableRows)); + rhi.update_texture(ctx, lighttable_tex, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, lighttable_bytes); + } + lighttables_to_upload_.clear(); + } +} + +void MainPaletteManager::upload_default_colormap(Rhi& rhi, Handle ctx) +{ + std::array 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))); +} + +void MainPaletteManager::upload_colormaps(Rhi& rhi, Handle ctx) +{ + for (auto to_upload : colormaps_to_upload_) + { + SRB2_ASSERT(to_upload != nullptr); + SRB2_ASSERT(colormaps_.find(to_upload) != colormaps_.end()); + + rhi::Handle map_texture = colormaps_.at(to_upload); + + tcb::span map_bytes = tcb::as_bytes(tcb::span(to_upload, kPaletteSize)); + rhi.update_texture(ctx, map_texture, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, map_bytes); + } + colormaps_to_upload_.clear(); +} + +rhi::Handle MainPaletteManager::find_or_create_colormap(rhi::Rhi& rhi, srb2::NotNull colormap) +{ + if (colormaps_.find(colormap) != colormaps_.end()) + { + return colormaps_[colormap]; + } + + Handle texture = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); + + colormaps_.insert_or_assign(colormap, texture); + colormaps_to_upload_.push_back(colormap); + return texture; +} + +rhi::Handle MainPaletteManager::find_colormap(srb2::NotNull colormap) const +{ + if (colormaps_.find(colormap) == colormaps_.end()) + { + return kNullHandle; + } + + return colormaps_.at(colormap); +} + +rhi::Handle MainPaletteManager::find_or_create_extra_lighttable(Rhi& rhi, srb2::NotNull lighttable) +{ + if (lighttables_.find(lighttable) != lighttables_.end()) + { + return lighttables_[lighttable]; + } + + Handle texture = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, kLighttableRows, TextureWrapMode::kClamp, TextureWrapMode::kClamp}); + + lighttables_.insert_or_assign(lighttable, texture); + lighttables_to_upload_.push_back(lighttable); + return texture; +} + +rhi::Handle MainPaletteManager::find_extra_lighttable(srb2::NotNull lighttable) const +{ + if (lighttables_.find(lighttable) == lighttables_.end()) + { + return kNullHandle; + } + + return lighttables_.at(lighttable); } void MainPaletteManager::transfer(Rhi& rhi, Handle ctx) { - std::array palette_32; - for (std::size_t i = 0; i < 256; i++) - { - palette_32[i] = V_GetColor(i).s; - } - rhi.update_texture(ctx, palette_, {0, 0, 256, 1}, PixelFormat::kRGBA8, tcb::as_bytes(tcb::span(palette_32))); + upload_palette(rhi, ctx); + upload_lighttables(rhi, ctx); + upload_default_colormap(rhi, ctx); + upload_colormaps(rhi, ctx); } void MainPaletteManager::graphics(Rhi& rhi, Handle ctx) @@ -169,6 +290,13 @@ void MainPaletteManager::graphics(Rhi& rhi, Handle ctx) void MainPaletteManager::postpass(Rhi& rhi) { + // Delete all colormap textures so they'll be recreated next frame + // Unfortunately the 256x1 translation colormaps are sometimes freed at runtime + for (auto& cm : colormaps_) + { + rhi.destroy_texture(cm.second); + } + colormaps_.clear(); } CommonResourcesManager::CommonResourcesManager() = default; diff --git a/src/hwr2/pass_resource_managers.hpp b/src/hwr2/pass_resource_managers.hpp index 30c158572..11e7fad95 100644 --- a/src/hwr2/pass_resource_managers.hpp +++ b/src/hwr2/pass_resource_managers.hpp @@ -74,6 +74,19 @@ public: class MainPaletteManager final : public Pass { rhi::Handle palette_; + rhi::Handle lighttable_; + rhi::Handle encore_lighttable_; + rhi::Handle default_colormap_; + + std::unordered_map> colormaps_; + std::unordered_map> lighttables_; + std::vector colormaps_to_upload_; + std::vector lighttables_to_upload_; + + void upload_palette(rhi::Rhi& rhi, rhi::Handle ctx); + void upload_lighttables(rhi::Rhi& rhi, rhi::Handle ctx); + void upload_default_colormap(rhi::Rhi& rhi, rhi::Handle ctx); + void upload_colormaps(rhi::Rhi& rhi, rhi::Handle ctx); public: MainPaletteManager(); @@ -85,6 +98,14 @@ public: virtual void postpass(rhi::Rhi& rhi) override; rhi::Handle palette() const noexcept { return palette_; } + rhi::Handle lighttable() const noexcept { return lighttable_; } + rhi::Handle encore_lighttable() const noexcept { return encore_lighttable_; } + rhi::Handle default_colormap() const noexcept { return default_colormap_; } + + rhi::Handle find_or_create_colormap(rhi::Rhi& rhi, srb2::NotNull colormap); + rhi::Handle find_colormap(srb2::NotNull colormap) const; + rhi::Handle find_or_create_extra_lighttable(rhi::Rhi& rhi, srb2::NotNull lighttable); + rhi::Handle find_extra_lighttable(srb2::NotNull lighttable) const; }; class CommonResourcesManager final : public Pass diff --git a/src/hwr2/pass_twodee.cpp b/src/hwr2/pass_twodee.cpp index 326caab0c..ed30706df 100644 --- a/src/hwr2/pass_twodee.cpp +++ b/src/hwr2/pass_twodee.cpp @@ -14,6 +14,7 @@ #include #include +#include "blendmode.hpp" #include "../r_patch.h" #include "../v_video.h" #include "../z_zone.h" @@ -25,9 +26,6 @@ using namespace srb2::rhi; struct srb2::hwr2::TwodeePassData { Handle default_tex; - Handle default_colormap_tex; - std::unordered_map> colormaps; - std::vector colormaps_to_upload; std::unordered_map> pipelines; bool upload_default_tex = false; }; @@ -61,7 +59,7 @@ static PipelineDesc make_pipeline_desc(TwodeePipelineKey key) BlendDesc blend_desc; switch (key.blend) { - case Draw2dBlend::kAlphaTransparent: + case BlendMode::kAlphaTransparent: blend_desc.source_factor_color = BlendFactor::kSourceAlpha; blend_desc.dest_factor_color = BlendFactor::kOneMinusSourceAlpha; blend_desc.color_function = BlendFunction::kAdd; @@ -69,7 +67,7 @@ static PipelineDesc make_pipeline_desc(TwodeePipelineKey key) blend_desc.dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha; blend_desc.alpha_function = BlendFunction::kAdd; break; - case Draw2dBlend::kModulate: + case BlendMode::kModulate: blend_desc.source_factor_color = BlendFactor::kDest; blend_desc.dest_factor_color = BlendFactor::kZero; blend_desc.color_function = BlendFunction::kAdd; @@ -77,7 +75,7 @@ static PipelineDesc make_pipeline_desc(TwodeePipelineKey key) blend_desc.dest_factor_alpha = BlendFactor::kZero; blend_desc.alpha_function = BlendFunction::kAdd; break; - case Draw2dBlend::kAdditive: + case BlendMode::kAdditive: blend_desc.source_factor_color = BlendFactor::kSourceAlpha; blend_desc.dest_factor_color = BlendFactor::kOne; blend_desc.color_function = BlendFunction::kAdd; @@ -85,7 +83,7 @@ static PipelineDesc make_pipeline_desc(TwodeePipelineKey key) blend_desc.dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha; blend_desc.alpha_function = BlendFunction::kAdd; break; - case Draw2dBlend::kSubtractive: + case BlendMode::kSubtractive: blend_desc.source_factor_color = BlendFactor::kSourceAlpha; blend_desc.dest_factor_color = BlendFactor::kOne; blend_desc.color_function = BlendFunction::kSubtract; @@ -93,7 +91,7 @@ static PipelineDesc make_pipeline_desc(TwodeePipelineKey key) blend_desc.dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha; blend_desc.alpha_function = BlendFunction::kAdd; break; - case Draw2dBlend::kReverseSubtractive: + case BlendMode::kReverseSubtractive: blend_desc.source_factor_color = BlendFactor::kSourceAlpha; blend_desc.dest_factor_color = BlendFactor::kOne; blend_desc.color_function = BlendFunction::kReverseSubtract; @@ -101,7 +99,7 @@ static PipelineDesc make_pipeline_desc(TwodeePipelineKey key) blend_desc.dest_factor_alpha = BlendFactor::kOneMinusSourceAlpha; blend_desc.alpha_function = BlendFunction::kAdd; break; - case Draw2dBlend::kInvertDest: + case BlendMode::kInvertDest: blend_desc.source_factor_color = BlendFactor::kOne; blend_desc.dest_factor_color = BlendFactor::kOne; blend_desc.color_function = BlendFunction::kSubtract; @@ -248,18 +246,18 @@ void TwodeePass::prepass(Rhi& rhi) if (data_->pipelines.size() == 0) { - TwodeePipelineKey alpha_transparent_tris = {Draw2dBlend::kAlphaTransparent, false}; - TwodeePipelineKey modulate_tris = {Draw2dBlend::kModulate, false}; - TwodeePipelineKey additive_tris = {Draw2dBlend::kAdditive, false}; - TwodeePipelineKey subtractive_tris = {Draw2dBlend::kSubtractive, false}; - TwodeePipelineKey revsubtractive_tris = {Draw2dBlend::kReverseSubtractive, false}; - TwodeePipelineKey invertdest_tris = {Draw2dBlend::kInvertDest, false}; - TwodeePipelineKey alpha_transparent_lines = {Draw2dBlend::kAlphaTransparent, true}; - TwodeePipelineKey modulate_lines = {Draw2dBlend::kModulate, true}; - TwodeePipelineKey additive_lines = {Draw2dBlend::kAdditive, true}; - TwodeePipelineKey subtractive_lines = {Draw2dBlend::kSubtractive, true}; - TwodeePipelineKey revsubtractive_lines = {Draw2dBlend::kReverseSubtractive, true}; - TwodeePipelineKey invertdest_lines = {Draw2dBlend::kInvertDest, true}; + 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}; data_->pipelines.insert({alpha_transparent_tris, rhi.create_pipeline(make_pipeline_desc(alpha_transparent_tris))}); data_->pipelines.insert({modulate_tris, rhi.create_pipeline(make_pipeline_desc(modulate_tris))}); data_->pipelines.insert({additive_tris, rhi.create_pipeline(make_pipeline_desc(additive_tris))}); @@ -285,17 +283,6 @@ void TwodeePass::prepass(Rhi& rhi) }); data_->upload_default_tex = true; } - if (!data_->default_colormap_tex) - { - data_->default_colormap_tex = rhi.create_texture({ - TextureFormat::kLuminance, - 256, - 1, - TextureWrapMode::kClamp, - TextureWrapMode::kClamp - }); - data_->upload_default_tex = true; - } if (!render_pass_) { render_pass_ = rhi.create_render_pass( @@ -313,7 +300,6 @@ void TwodeePass::prepass(Rhi& rhi) // Stage 1 - command list patch detection std::unordered_set found_patches; - std::unordered_set found_colormaps; for (const auto& list : *ctx_) { for (const auto& cmd : list.cmds) @@ -327,7 +313,7 @@ void TwodeePass::prepass(Rhi& rhi) } if (cmd.colormap != nullptr) { - found_colormaps.insert(cmd.colormap); + palette_manager_->find_or_create_colormap(rhi, cmd.colormap); } }, [&](const Draw2dVertices& cmd) {}}; @@ -341,17 +327,6 @@ void TwodeePass::prepass(Rhi& rhi) } patch_atlas_cache_->pack(rhi); - for (auto colormap : found_colormaps) - { - if (data_->colormaps.find(colormap) == data_->colormaps.end()) - { - Handle colormap_tex = rhi.create_texture({TextureFormat::kLuminance, 256, 1}); - data_->colormaps.insert({colormap, colormap_tex}); - } - - data_->colormaps_to_upload.push_back(colormap); - } - size_t list_index = 0; for (auto& list : *ctx_) { @@ -535,34 +510,9 @@ void TwodeePass::transfer(Rhi& rhi, Handle ctx) std::array data = {0, 255, 0, 255}; rhi.update_texture(ctx, data_->default_tex, {0, 0, 2, 1}, PixelFormat::kRG8, tcb::as_bytes(tcb::span(data))); - std::array colormap_data; - for (size_t i = 0; i < 256; i++) - { - colormap_data[i] = i; - } - rhi.update_texture( - ctx, - data_->default_colormap_tex, - {0, 0, 256, 1}, - PixelFormat::kR8, - tcb::as_bytes(tcb::span(colormap_data)) - ); - data_->upload_default_tex = false; } - for (auto colormap : data_->colormaps_to_upload) - { - rhi.update_texture( - ctx, - data_->colormaps[colormap], - {0, 0, 256, 1}, - rhi::PixelFormat::kR8, - tcb::as_bytes(tcb::span(colormap, 256)) - ); - } - data_->colormaps_to_upload.clear(); - Handle palette_tex = palette_manager_->palette(); // Update the buffers for each list @@ -606,11 +556,11 @@ void TwodeePass::transfer(Rhi& rhi, Handle ctx) } const uint8_t* colormap = mcmd.colormap; - Handle colormap_h = data_->default_colormap_tex; + Handle colormap_h = palette_manager_->default_colormap(); if (colormap) { - SRB2_ASSERT(data_->colormaps.find(colormap) != data_->colormaps.end()); - colormap_h = data_->colormaps[colormap]; + colormap_h = palette_manager_->find_colormap(colormap); + SRB2_ASSERT(colormap_h != kNullHandle); } tx[2] = {SamplerName::kSampler2, colormap_h}; mcmd.binding_set = diff --git a/src/hwr2/pass_twodee.hpp b/src/hwr2/pass_twodee.hpp index 15a0924a4..8c72fc92e 100644 --- a/src/hwr2/pass_twodee.hpp +++ b/src/hwr2/pass_twodee.hpp @@ -34,7 +34,7 @@ struct TwodeePassData; /// @brief Hash map key for caching pipelines struct TwodeePipelineKey { - Draw2dBlend blend; + BlendMode blend; bool lines; bool operator==(const TwodeePipelineKey& r) const noexcept { return !(blend != r.blend || lines != r.lines); } diff --git a/src/hwr2/twodee.cpp b/src/hwr2/twodee.cpp index 8a15234fe..a54f13218 100644 --- a/src/hwr2/twodee.cpp +++ b/src/hwr2/twodee.cpp @@ -89,7 +89,7 @@ void Draw2dVerticesBuilder::done() list.cmds.push_back(tris_); } -Draw2dBlend srb2::hwr2::get_blend_mode(const Draw2dCmd& cmd) noexcept +BlendMode srb2::hwr2::get_blend_mode(const Draw2dCmd& cmd) noexcept { auto visitor = srb2::Overload { [&](const Draw2dPatchQuad& cmd) { return cmd.blend; }, diff --git a/src/hwr2/twodee.hpp b/src/hwr2/twodee.hpp index af0f60bc5..319034e6c 100644 --- a/src/hwr2/twodee.hpp +++ b/src/hwr2/twodee.hpp @@ -19,6 +19,7 @@ #include +#include "blendmode.hpp" #include "../cxxutil.hpp" #include "../doomtype.h" @@ -38,16 +39,6 @@ struct TwodeeVertex float a; }; -enum class Draw2dBlend -{ - kAlphaTransparent, - kModulate, - kAdditive, - kSubtractive, - kReverseSubtractive, - kInvertDest -}; - struct Draw2dPatchQuad { std::size_t begin_index = 0; @@ -56,7 +47,7 @@ struct Draw2dPatchQuad // A null patch ptr means no patch is drawn const patch_t* patch = nullptr; const uint8_t* colormap = nullptr; - Draw2dBlend blend; + BlendMode blend; float r = 0.f; float g = 0.f; float b = 0.f; @@ -81,14 +72,14 @@ struct Draw2dVertices std::size_t begin_index = 0; std::size_t begin_element = 0; std::size_t elements = 0; - Draw2dBlend blend = Draw2dBlend::kAlphaTransparent; + BlendMode blend = BlendMode::kAlphaTransparent; lumpnum_t flat_lump = UINT32_MAX; // LUMPERROR but not loading w_wad.h from this header bool lines = false; }; using Draw2dCmd = std::variant; -Draw2dBlend get_blend_mode(const Draw2dCmd& cmd) noexcept; +BlendMode get_blend_mode(const Draw2dCmd& cmd) noexcept; bool is_draw_lines(const Draw2dCmd& cmd) noexcept; std::size_t elements(const Draw2dCmd& cmd) noexcept; @@ -194,7 +185,7 @@ public: return *this; } - Draw2dQuadBuilder& blend(Draw2dBlend blend) + Draw2dQuadBuilder& blend(BlendMode blend) { quad_.blend = blend; return *this; @@ -245,7 +236,7 @@ public: return *this; } - Draw2dVerticesBuilder& blend(Draw2dBlend blend) + Draw2dVerticesBuilder& blend(BlendMode blend) { tris_.blend = blend; return *this; diff --git a/src/rhi/gl3_core/gl3_core_rhi.cpp b/src/rhi/gl3_core/gl3_core_rhi.cpp index 18985ac43..7d6481f6d 100644 --- a/src/rhi/gl3_core/gl3_core_rhi.cpp +++ b/src/rhi/gl3_core/gl3_core_rhi.cpp @@ -886,7 +886,6 @@ void GlCoreRhi::destroy_renderbuffer(rhi::Handle handle) rhi::Handle GlCoreRhi::create_pipeline(const PipelineDesc& desc) { - SRB2_ASSERT(graphics_context_active_ == false); SRB2_ASSERT(platform_ != nullptr); // TODO assert compatibility of pipeline description with program using ProgramRequirements @@ -1414,26 +1413,32 @@ void GlCoreRhi::bind_pipeline(Handle ctx, Handle pipe if (desc.depth_stencil_state->stencil_test) { gl_->Enable(GL_STENCIL_TEST); + stencil_front_reference_ = 0; + stencil_back_reference_ = 0; + stencil_front_compare_mask_ = 0xFF; + stencil_back_compare_mask_ = 0xFF; + stencil_front_write_mask_ = 0xFF; + stencil_back_write_mask_ = 0xFF; GL_ASSERT; gl_->StencilFuncSeparate( GL_FRONT, map_compare_func(desc.depth_stencil_state->front.stencil_compare), - desc.depth_stencil_state->front.reference, - desc.depth_stencil_state->front.compare_mask + stencil_front_reference_, + stencil_front_compare_mask_ ); GL_ASSERT; gl_->StencilFuncSeparate( GL_BACK, map_compare_func(desc.depth_stencil_state->back.stencil_compare), - desc.depth_stencil_state->back.reference, - desc.depth_stencil_state->back.compare_mask + stencil_back_reference_, + stencil_back_compare_mask_ ); GL_ASSERT; - gl_->StencilMaskSeparate(GL_FRONT, desc.depth_stencil_state->front.write_mask); + gl_->StencilMaskSeparate(GL_FRONT, stencil_front_write_mask_); GL_ASSERT; - gl_->StencilMaskSeparate(GL_BACK, desc.depth_stencil_state->back.write_mask); + gl_->StencilMaskSeparate(GL_BACK, stencil_back_write_mask_); GL_ASSERT; } else @@ -1732,6 +1737,87 @@ void GlCoreRhi::read_pixels(Handle ctx, const Rect& rect, Pixel gl_->ReadPixels(rect.x, rect.y, rect.w, rect.h, layout, type, out.data()); } +void GlCoreRhi::set_stencil_reference(Handle ctx, CullMode face, uint8_t reference) +{ + SRB2_ASSERT(face != CullMode::kNone); + SRB2_ASSERT(graphics_context_active_ == true && graphics_context_generation_ == ctx.generation()); + SRB2_ASSERT(current_render_pass_.has_value()); + SRB2_ASSERT(current_pipeline_.has_value()); + + auto& pl = pipeline_slab_[*current_pipeline_]; + + if (face == CullMode::kFront) + { + stencil_front_reference_ = reference; + gl_->StencilFuncSeparate( + GL_FRONT, + map_compare_func(pl.desc.depth_stencil_state->front.stencil_compare), + stencil_front_reference_, + stencil_front_compare_mask_ + ); + } + else if (face == CullMode::kBack) + { + stencil_back_reference_ = reference; + gl_->StencilFuncSeparate( + GL_BACK, + map_compare_func(pl.desc.depth_stencil_state->back.stencil_compare), + stencil_back_reference_, + stencil_back_compare_mask_ + ); + } +} + +void GlCoreRhi::set_stencil_compare_mask(Handle ctx, CullMode face, uint8_t compare_mask) +{ + SRB2_ASSERT(face != CullMode::kNone); + SRB2_ASSERT(graphics_context_active_ == true && graphics_context_generation_ == ctx.generation()); + SRB2_ASSERT(current_render_pass_.has_value()); + SRB2_ASSERT(current_pipeline_.has_value()); + + auto& pl = pipeline_slab_[*current_pipeline_]; + + if (face == CullMode::kFront) + { + stencil_front_compare_mask_ = compare_mask; + gl_->StencilFuncSeparate( + GL_FRONT, + map_compare_func(pl.desc.depth_stencil_state->front.stencil_compare), + stencil_front_reference_, + stencil_front_compare_mask_ + ); + } + else if (face == CullMode::kBack) + { + stencil_back_compare_mask_ = compare_mask; + gl_->StencilFuncSeparate( + GL_BACK, + map_compare_func(pl.desc.depth_stencil_state->back.stencil_compare), + stencil_back_reference_, + stencil_back_compare_mask_ + ); + } +} + +void GlCoreRhi::set_stencil_write_mask(Handle ctx, CullMode face, uint8_t write_mask) +{ + SRB2_ASSERT(face != CullMode::kNone); + SRB2_ASSERT(graphics_context_active_ == true && graphics_context_generation_ == ctx.generation()); + SRB2_ASSERT(current_render_pass_.has_value()); + SRB2_ASSERT(current_pipeline_.has_value()); + + if (face == CullMode::kFront) + { + stencil_front_write_mask_ = write_mask; + gl_->StencilMaskSeparate(GL_FRONT, stencil_front_write_mask_); + } + else if (face == CullMode::kBack) + { + stencil_back_write_mask_ = write_mask; + gl_->StencilMaskSeparate(GL_BACK, stencil_back_write_mask_); + } +} + TextureDetails GlCoreRhi::get_texture_details(Handle texture) { SRB2_ASSERT(texture_slab_.is_valid(texture)); diff --git a/src/rhi/gl3_core/gl3_core_rhi.hpp b/src/rhi/gl3_core/gl3_core_rhi.hpp index 8814ac36f..b5f499422 100644 --- a/src/rhi/gl3_core/gl3_core_rhi.hpp +++ b/src/rhi/gl3_core/gl3_core_rhi.hpp @@ -46,11 +46,11 @@ struct std::hash { std::size_t operator()(const srb2::rhi::GlCoreFramebufferKey& key) const { - std::size_t color_hash = std::hash>()(key.color); + std::size_t color_hash = std::hash>()(key.color); std::size_t depth_stencil_hash = 0; if (key.depth_stencil) { - depth_stencil_hash = std::hash>()(*key.depth_stencil); + depth_stencil_hash = std::hash>()(*key.depth_stencil); } return color_hash ^ (depth_stencil_hash << 1); } @@ -164,6 +164,13 @@ class GlCoreRhi final : public Rhi uint32_t index_buffer_offset_ = 0; uint32_t transfer_context_generation_ = 0; + uint8_t stencil_front_reference_ = 0; + uint8_t stencil_front_compare_mask_ = 0xFF; + uint8_t stencil_front_write_mask_ = 0xFF; + uint8_t stencil_back_reference_ = 0; + uint8_t stencil_back_compare_mask_ = 0xFF; + uint8_t stencil_back_write_mask_ = 0xFF; + std::vector> disposal_; public: @@ -225,6 +232,9 @@ public: virtual void draw_indexed(Handle ctx, uint32_t index_count, uint32_t first_index) override; virtual void read_pixels(Handle ctx, const Rect& rect, PixelFormat format, tcb::span out) override; + virtual void set_stencil_reference(Handle ctx, CullMode face, uint8_t reference) override; + virtual void set_stencil_compare_mask(Handle ctx, CullMode face, uint8_t mask) override; + virtual void set_stencil_write_mask(Handle ctx, CullMode face, uint8_t mask) override; virtual void present() override; diff --git a/src/rhi/handle.hpp b/src/rhi/handle.hpp index df160c564..282a924da 100644 --- a/src/rhi/handle.hpp +++ b/src/rhi/handle.hpp @@ -314,7 +314,7 @@ namespace std { template -struct hash> +struct hash> { std::size_t operator()(const srb2::rhi::Handle& e) const { diff --git a/src/rhi/rhi.hpp b/src/rhi/rhi.hpp index 0187cf9fc..20f0bb7ae 100644 --- a/src/rhi/rhi.hpp +++ b/src/rhi/rhi.hpp @@ -424,9 +424,6 @@ struct PipelineStencilOpStateDesc StencilOp pass; StencilOp depth_fail; CompareFunc stencil_compare; - uint32_t compare_mask; - uint32_t write_mask; - uint32_t reference; }; struct PipelineDepthStencilStateDesc @@ -648,6 +645,9 @@ struct Rhi virtual void draw_indexed(Handle ctx, uint32_t index_count, uint32_t first_index) = 0; virtual void read_pixels(Handle ctx, const Rect& rect, PixelFormat format, tcb::span out) = 0; + virtual void set_stencil_reference(Handle ctx, CullMode face, uint8_t reference) = 0; + virtual void set_stencil_compare_mask(Handle ctx, CullMode face, uint8_t mask) = 0; + virtual void set_stencil_write_mask(Handle ctx, CullMode face, uint8_t mask) = 0; virtual void present() = 0; diff --git a/src/v_video.cpp b/src/v_video.cpp index e60a5462d..d25778061 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -31,6 +31,7 @@ #include "m_misc.h" #include "m_random.h" #include "doomstat.h" +#include "hwr2/blendmode.hpp" #ifdef HWRENDER #include "hardware/hw_glob.h" @@ -914,27 +915,27 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca { falpha = (10 - alphalevel) / 10.f; } - hwr2::Draw2dBlend blend = hwr2::Draw2dBlend::kAlphaTransparent; + hwr2::BlendMode blend = hwr2::BlendMode::kAlphaTransparent; switch (blendmode) { case AST_MODULATE: - blend = hwr2::Draw2dBlend::kModulate; + blend = hwr2::BlendMode::kModulate; break; case AST_ADD: - blend = hwr2::Draw2dBlend::kAdditive; + blend = hwr2::BlendMode::kAdditive; break; // Note: SRB2 has these blend modes flipped compared to GL and Vulkan. // SRB2's Subtract is Dst - Src. OpenGL is Src - Dst. And vice versa for reverse. // Twodee will use the GL definitions. case AST_SUBTRACT: - blend = hwr2::Draw2dBlend::kReverseSubtractive; + blend = hwr2::BlendMode::kReverseSubtractive; break; case AST_REVERSESUBTRACT: - blend = hwr2::Draw2dBlend::kSubtractive; + blend = hwr2::BlendMode::kSubtractive; break; default: - blend = hwr2::Draw2dBlend::kAlphaTransparent; + blend = hwr2::BlendMode::kAlphaTransparent; break; } @@ -1187,7 +1188,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) float a = 0.5f; // alphalevel is unused in GL?? g_2d.begin_quad() .rect(x, y, w, h) - .blend(hwr2::Draw2dBlend::kAlphaTransparent) + .blend(hwr2::BlendMode::kAlphaTransparent) .color(r, g, b, a) .done(); } @@ -1332,7 +1333,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U float g; float b; float a; - hwr2::Draw2dBlend blendmode; + hwr2::BlendMode blendmode; if (color & 0xFF00) { @@ -1345,7 +1346,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U b = std::clamp((fstrength - (2.f / 3.f)) * 3.f, 0.f, 1.f); a = 1; - blendmode = hwr2::Draw2dBlend::kReverseSubtractive; + blendmode = hwr2::BlendMode::kReverseSubtractive; } else { @@ -1356,7 +1357,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U g = bc.green / 255.f; b = bc.blue / 255.f; a = softwaretranstohwr[std::clamp(static_cast(strength), 0, 10)] / 255.f; - blendmode = hwr2::Draw2dBlend::kAlphaTransparent; + blendmode = hwr2::BlendMode::kAlphaTransparent; } g_2d.begin_quad() @@ -1529,7 +1530,7 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength) float g; float b; float a; - hwr2::Draw2dBlend blendmode; + hwr2::BlendMode blendmode; if (color & 0xFF00) { @@ -1542,7 +1543,7 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength) b = std::clamp((fstrength - (2.f / 3.f)) * 3.f, 0.f, 1.f); a = 1; - blendmode = hwr2::Draw2dBlend::kReverseSubtractive; + blendmode = hwr2::BlendMode::kReverseSubtractive; } else { @@ -1553,7 +1554,7 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength) g = bc.green / 255.f; b = bc.blue / 255.f; a = softwaretranstohwr[std::clamp(static_cast(strength), 0, 10)] / 255.f; - blendmode = hwr2::Draw2dBlend::kAlphaTransparent; + blendmode = hwr2::BlendMode::kAlphaTransparent; } g_2d.begin_quad() @@ -1629,7 +1630,7 @@ void V_DrawFadeConsBack(INT32 plines) float a = 0.5f; g_2d.begin_quad() .rect(0, 0, vid.width, plines) - .blend(hwr2::Draw2dBlend::kAlphaTransparent) + .blend(hwr2::BlendMode::kAlphaTransparent) .color(r, g, b, a) .done(); } @@ -1649,7 +1650,7 @@ void V_EncoreInvertScreen(void) #endif g_2d.begin_quad() - .blend(hwr2::Draw2dBlend::kInvertDest) + .blend(hwr2::BlendMode::kInvertDest) .color(1, 1, 1, 1) .rect(0, 0, vid.width, vid.height) .done();