rhi: Make some stencil state dynamic

The reference, compare mask and write mask for each face direction in
the stencil test is now dynamic pipeline state and are implicitly set to
default values when a pipeline is bound. This is implementable using
Vulkan dynamic pipeline state bits and so there is no reason not to
provide it.

In the OpenGL implementation of RHI, this requires tracking some stencil
state internally in the graphics context because the stencil state
functions require multiple inputs that do not cleanly map to the Vulkan
equivalents.
This commit is contained in:
Eidolon 2023-05-19 18:29:36 -05:00
parent 65511d6fdc
commit 20002f83c4
3 changed files with 106 additions and 9 deletions

View file

@ -1414,26 +1414,32 @@ void GlCoreRhi::bind_pipeline(Handle<GraphicsContext> ctx, Handle<Pipeline> 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 +1738,87 @@ void GlCoreRhi::read_pixels(Handle<GraphicsContext> 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<GraphicsContext> 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<GraphicsContext> 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<GraphicsContext> 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> texture)
{
SRB2_ASSERT(texture_slab_.is_valid(texture));

View file

@ -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<std::function<void()>> disposal_;
public:
@ -225,6 +232,9 @@ public:
virtual void draw_indexed(Handle<GraphicsContext> ctx, 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;
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 present() override;

View file

@ -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<GraphicsContext> ctx, 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;
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 present() = 0;