From 016f0f0dd51511f98d0bf398d99199d7dec1543c Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 12 Jan 2022 22:24:54 +0200 Subject: [PATCH] Store simpler states by value in PipelineState Since these are also stored by value in various objects, a pointer comparison is not enough to tell if state needs to be changed. There's no guarantee that the object behind the pointer stays alive, so comparing values through the pointer is hazardous. --- .../backends/opengl/pipelinestate_backend.cpp | 63 ++++---- source/backends/vulkan/commands_backend.cpp | 26 ++-- source/backends/vulkan/commands_backend.h | 4 +- .../backends/vulkan/pipelinestate_backend.cpp | 144 +++++++----------- source/core/blend.h | 9 ++ source/core/depthtest.h | 8 + source/core/framebuffer.h | 2 + source/core/pipelinestate.cpp | 12 +- source/core/pipelinestate.h | 32 ++-- source/core/rect.h | 37 +++++ source/core/stenciltest.h | 9 ++ source/render/renderer.cpp | 9 +- 12 files changed, 195 insertions(+), 160 deletions(-) diff --git a/source/backends/opengl/pipelinestate_backend.cpp b/source/backends/opengl/pipelinestate_backend.cpp index fb802995..08edc5e7 100644 --- a/source/backends/opengl/pipelinestate_backend.cpp +++ b/source/backends/opengl/pipelinestate_backend.cpp @@ -66,24 +66,27 @@ void OpenGLPipelineState::apply() const } } - if(mask&(PipelineState::VIEWPORT|PipelineState::FRAMEBUFFER)) - { - if(const Rect *viewport = self.viewport) - glViewport(viewport->left, viewport->bottom, viewport->width, viewport->height); - else if(const Framebuffer *framebuffer = self.framebuffer) - glViewport(0, 0, framebuffer->get_width(), framebuffer->get_height()); - } - - if(mask&PipelineState::SCISSOR) - { - if(const Rect *scissor = self.scissor) + if(mask&(PipelineState::VIEWPORT|PipelineState::SCISSOR|PipelineState::FRAMEBUFFER)) + if(const Framebuffer *framebuffer = self.framebuffer) { - glEnable(GL_SCISSOR_TEST); - glScissor(scissor->left, scissor->bottom, scissor->width, scissor->height); + Rect fb_rect = framebuffer->get_rect(); + if(mask&(PipelineState::VIEWPORT|PipelineState::FRAMEBUFFER)) + { + Rect viewport = fb_rect.intersect(self.viewport); + glViewport(viewport.left, viewport.bottom, viewport.width, viewport.height); + } + if(mask&(PipelineState::SCISSOR|PipelineState::FRAMEBUFFER)) + { + Rect scissor = fb_rect.intersect(self.scissor); + if(scissor!=fb_rect) + { + glEnable(GL_SCISSOR_TEST); + glScissor(scissor.left, scissor.bottom, scissor.width, scissor.height); + } + else + glDisable(GL_SCISSOR_TEST); + } } - else - glDisable(GL_SCISSOR_TEST); - } if(mask&PipelineState::SHPROG) { @@ -189,26 +192,26 @@ void OpenGLPipelineState::apply() const if(mask&PipelineState::DEPTH_TEST) { - const DepthTest *depth_test = self.depth_test; - if(depth_test && depth_test->enabled) + const DepthTest &depth_test = self.depth_test; + if(depth_test.enabled) { glEnable(GL_DEPTH_TEST); - glDepthFunc(get_gl_predicate(depth_test->compare)); + glDepthFunc(get_gl_predicate(depth_test.compare)); } else glDisable(GL_DEPTH_TEST); - glDepthMask(!depth_test || depth_test->write); + glDepthMask(depth_test.write); } if(mask&PipelineState::STENCIL_TEST) { - const StencilTest *stencil_test = self.stencil_test; - if(stencil_test && stencil_test->enabled) + const StencilTest &stencil_test = self.stencil_test; + if(stencil_test.enabled) { glEnable(GL_STENCIL_TEST); - glStencilFunc(get_gl_predicate(stencil_test->compare), stencil_test->reference, 0xFFFFFFFF); - glStencilOp(get_gl_stencil_op(stencil_test->stencil_fail_op), get_gl_stencil_op(stencil_test->depth_fail_op), get_gl_stencil_op(stencil_test->depth_pass_op)); + glStencilFunc(get_gl_predicate(stencil_test.compare), stencil_test.reference, 0xFFFFFFFF); + glStencilOp(get_gl_stencil_op(stencil_test.stencil_fail_op), get_gl_stencil_op(stencil_test.depth_fail_op), get_gl_stencil_op(stencil_test.depth_pass_op)); } else glDisable(GL_STENCIL_TEST); @@ -216,14 +219,14 @@ void OpenGLPipelineState::apply() const if(mask&PipelineState::BLEND) { - const Blend *blend = self.blend; - if(blend && blend->enabled) + const Blend &blend = self.blend; + if(blend.enabled) { glEnable(GL_BLEND); - glBlendEquation(get_gl_blend_equation(blend->equation)); - glBlendFunc(get_gl_blend_factor(blend->src_factor), get_gl_blend_factor(blend->dst_factor)); - glBlendColor(blend->constant.r, blend->constant.g, blend->constant.b, blend->constant.a); - ColorWriteMask cw = blend->write_mask; + glBlendEquation(get_gl_blend_equation(blend.equation)); + glBlendFunc(get_gl_blend_factor(blend.src_factor), get_gl_blend_factor(blend.dst_factor)); + glBlendColor(blend.constant.r, blend.constant.g, blend.constant.b, blend.constant.a); + ColorWriteMask cw = blend.write_mask; glColorMask((cw&WRITE_RED)!=0, (cw&WRITE_GREEN)!=0, (cw&WRITE_BLUE)!=0, (cw&WRITE_ALPHA)!=0); } else diff --git a/source/backends/vulkan/commands_backend.cpp b/source/backends/vulkan/commands_backend.cpp index bf8ee3f1..d655134d 100644 --- a/source/backends/vulkan/commands_backend.cpp +++ b/source/backends/vulkan/commands_backend.cpp @@ -97,11 +97,15 @@ void VulkanCommands::begin_render_pass(bool clear, const ClearValue *clear_value if(dynamic_cast(framebuffer->get_attachment(i))) fb_is_swapchain = true; - discard_fb_contents = (clear && !viewport); + Rect fb_rect = framebuffer->get_rect(); + Rect render_area = fb_rect.intersect(viewport); + bool full_viewport = render_area==fb_rect; + discard_fb_contents = (clear && full_viewport); framebuffer->refresh(); - VkRenderPass render_pass = device.get_pipeline_cache().get_render_pass(framebuffer->get_format(), clear, (!clear_values && !viewport), fb_is_swapchain); + VkRenderPass render_pass = device.get_pipeline_cache().get_render_pass(framebuffer->get_format(), + clear, (!clear_values && full_viewport), fb_is_swapchain); begin_buffer(render_pass); StructureBuilder sb(pass_begin_info, 2); @@ -112,18 +116,10 @@ void VulkanCommands::begin_render_pass(bool clear, const ClearValue *clear_value begin_info->renderPass = handle_cast<::VkRenderPass>(render_pass); begin_info->framebuffer = handle_cast<::VkFramebuffer>(framebuffer->handle); - if(viewport) - { - begin_info->renderArea.offset.x = viewport->left; - begin_info->renderArea.offset.y = viewport->bottom; - begin_info->renderArea.extent.width = viewport->width; - begin_info->renderArea.extent.height = viewport->height; - } - else - { - begin_info->renderArea.extent.width = framebuffer->get_width(); - begin_info->renderArea.extent.height = framebuffer->get_height(); - } + begin_info->renderArea.offset.x = render_area.left; + begin_info->renderArea.offset.y = render_area.bottom; + begin_info->renderArea.extent.width = render_area.width; + begin_info->renderArea.extent.height = render_area.height; if(clear_values) { @@ -169,7 +165,7 @@ void VulkanCommands::end_render_pass() vk.CmdEndRenderPass(primary_buffer); framebuffer = 0; - viewport = 0; + viewport = Rect::max(); pass_buffer = 0; } diff --git a/source/backends/vulkan/commands_backend.h b/source/backends/vulkan/commands_backend.h index 5fcae882..00e492f2 100644 --- a/source/backends/vulkan/commands_backend.h +++ b/source/backends/vulkan/commands_backend.h @@ -4,6 +4,7 @@ #include #include "fence.h" #include "handles.h" +#include "rect.h" namespace Msp { namespace GL { @@ -14,7 +15,6 @@ class Device; class Framebuffer; class PipelineState; class QueryPool; -struct Rect; class Semaphore; class SwapChain; @@ -48,7 +48,7 @@ protected: VkCommandBuffer pass_buffer = 0; const PipelineState *pipeline_state = 0; const Framebuffer *framebuffer = 0; - const Rect *viewport = 0; + Rect viewport = Rect::max(); bool fb_is_swapchain = false; bool discard_fb_contents = false; std::vector pass_begin_info; diff --git a/source/backends/vulkan/pipelinestate_backend.cpp b/source/backends/vulkan/pipelinestate_backend.cpp index 84609ab0..efa08a86 100644 --- a/source/backends/vulkan/pipelinestate_backend.cpp +++ b/source/backends/vulkan/pipelinestate_backend.cpp @@ -94,31 +94,28 @@ uint64_t VulkanPipelineState::compute_hash() const result = hash_round<64>(result, format.get_samples()); - if(const DepthTest *depth_test = self.depth_test) - if(depth_test->enabled) - { - result = hash_round<64>(result, depth_test->compare); - result = hash_update<64>(result, depth_test->write); - } + if(self.depth_test.enabled) + { + result = hash_round<64>(result, self.depth_test.compare); + result = hash_update<64>(result, self.depth_test.write); + } - if(const StencilTest *stencil_test = self.stencil_test) - if(stencil_test->enabled) - { - result = hash_round<64>(result, stencil_test->compare); - result = hash_round<64>(result, stencil_test->stencil_fail_op); - result = hash_round<64>(result, stencil_test->depth_fail_op); - result = hash_round<64>(result, stencil_test->depth_pass_op); - result = hash_update<64>(result, stencil_test->reference); - } + if(self.stencil_test.enabled) + { + result = hash_round<64>(result, self.stencil_test.compare); + result = hash_round<64>(result, self.stencil_test.stencil_fail_op); + result = hash_round<64>(result, self.stencil_test.depth_fail_op); + result = hash_round<64>(result, self.stencil_test.depth_pass_op); + result = hash_update<64>(result, self.stencil_test.reference); + } - if(const Blend *blend = self.blend) - if(blend->enabled) - { - result = hash_round<64>(result, blend->equation); - result = hash_round<64>(result, blend->src_factor); - result = hash_round<64>(result, blend->dst_factor); - result = hash_round<64>(result, blend->write_mask); - } + if(self.blend.enabled) + { + result = hash_round<64>(result, self.blend.equation); + result = hash_round<64>(result, self.blend.src_factor); + result = hash_round<64>(result, self.blend.dst_factor); + result = hash_round<64>(result, self.blend.write_mask); + } for(FrameAttachment a: format) result = hash_update<64>(result, a); @@ -192,44 +189,31 @@ void VulkanPipelineState::fill_creation_info(vector &buffer) const multisample_info->alphaToOneEnable = VK_FALSE; depth_stencil_info->sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - if(const DepthTest *depth_test = self.depth_test) - { - depth_stencil_info->depthTestEnable = depth_test->enabled; - depth_stencil_info->depthWriteEnable = depth_test->write; - depth_stencil_info->depthCompareOp = static_cast(get_vulkan_predicate(depth_test->compare)); - depth_stencil_info->depthBoundsTestEnable = VK_FALSE; - } - if(const StencilTest *stencil_test = self.stencil_test) + depth_stencil_info->depthTestEnable = self.depth_test.enabled; + depth_stencil_info->depthWriteEnable = self.depth_test.write; + depth_stencil_info->depthCompareOp = static_cast(get_vulkan_predicate(self.depth_test.compare)); + depth_stencil_info->depthBoundsTestEnable = VK_FALSE; + + depth_stencil_info->stencilTestEnable = self.stencil_test.enabled; + depth_stencil_info->front.failOp = static_cast(get_vulkan_stencil_op(self.stencil_test.stencil_fail_op)); + depth_stencil_info->front.passOp = static_cast(get_vulkan_stencil_op(self.stencil_test.depth_pass_op)); + depth_stencil_info->front.depthFailOp = static_cast(get_vulkan_stencil_op(self.stencil_test.depth_fail_op)); + depth_stencil_info->front.compareOp = static_cast(get_vulkan_predicate(self.stencil_test.compare)); + depth_stencil_info->front.compareMask = 0xFFFFFFFFU; + depth_stencil_info->front.writeMask = 0xFFFFFFFFU; + depth_stencil_info->front.reference = self.stencil_test.reference; + depth_stencil_info->back = depth_stencil_info->front; + + for(unsigned i=0; istencilTestEnable = stencil_test->enabled; - depth_stencil_info->front.failOp = static_cast(get_vulkan_stencil_op(stencil_test->stencil_fail_op)); - depth_stencil_info->front.passOp = static_cast(get_vulkan_stencil_op(stencil_test->depth_pass_op)); - depth_stencil_info->front.depthFailOp = static_cast(get_vulkan_stencil_op(stencil_test->depth_fail_op)); - depth_stencil_info->front.compareOp = static_cast(get_vulkan_predicate(stencil_test->compare)); - depth_stencil_info->front.compareMask = 0xFFFFFFFFU; - depth_stencil_info->front.writeMask = 0xFFFFFFFFU; - depth_stencil_info->front.reference = stencil_test->reference; - depth_stencil_info->back = depth_stencil_info->front; - } - - if(const Blend *blend = self.blend) - { - for(unsigned i=0; ienabled; - blend_attachments[i].srcColorBlendFactor = static_cast(get_vulkan_blend_factor(blend->src_factor)); - blend_attachments[i].dstColorBlendFactor = static_cast(get_vulkan_blend_factor(blend->dst_factor)); - blend_attachments[i].colorBlendOp = static_cast(get_vulkan_blend_equation(blend->equation)); - blend_attachments[i].srcAlphaBlendFactor = blend_attachments[i].srcColorBlendFactor; - blend_attachments[i].dstAlphaBlendFactor = blend_attachments[i].dstColorBlendFactor; - blend_attachments[i].alphaBlendOp = blend_attachments[i].colorBlendOp; - blend_attachments[i].colorWriteMask = get_vulkan_color_mask(blend->write_mask); - } - } - else - { - for(unsigned i=0; i(get_vulkan_blend_factor(self.blend.src_factor)); + blend_attachments[i].dstColorBlendFactor = static_cast(get_vulkan_blend_factor(self.blend.dst_factor)); + blend_attachments[i].colorBlendOp = static_cast(get_vulkan_blend_equation(self.blend.equation)); + blend_attachments[i].srcAlphaBlendFactor = blend_attachments[i].srcColorBlendFactor; + blend_attachments[i].dstAlphaBlendFactor = blend_attachments[i].dstColorBlendFactor; + blend_attachments[i].alphaBlendOp = blend_attachments[i].colorBlendOp; + blend_attachments[i].colorWriteMask = get_vulkan_color_mask(self.blend.write_mask); } blend_info->sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; @@ -400,21 +384,14 @@ void VulkanPipelineState::apply(VkCommandBuffer command_buffer, unsigned frame, 0, descriptor_set_handles.size(), descriptor_set_handles.data(), dynamic_offsets.size(), dynamic_offsets.data()); } + Rect fb_rect = self.framebuffer->get_rect(); + + Rect viewport_rect = fb_rect.intersect(self.viewport); VkViewport viewport = { }; - if(self.viewport) - { - viewport.x = self.viewport->left; - viewport.y = self.viewport->bottom; - viewport.width = self.viewport->width; - viewport.height = self.viewport->height; - } - else - { - viewport.x = 0; - viewport.y = 0; - viewport.width = self.framebuffer->get_width(); - viewport.height = self.framebuffer->get_height(); - } + viewport.x = viewport_rect.left; + viewport.y = viewport_rect.bottom; + viewport.width = viewport_rect.width; + viewport.height = viewport_rect.height; if(negative_viewport) { viewport.y += viewport.height; @@ -424,21 +401,12 @@ void VulkanPipelineState::apply(VkCommandBuffer command_buffer, unsigned frame, viewport.maxDepth = 1.0f; vk.CmdSetViewport(command_buffer, 0, 1, &viewport); + Rect scissor_rect = fb_rect.intersect(self.scissor); VkRect2D scissor = { }; - if(self.scissor) - { - scissor.offset.x = self.scissor->left; - scissor.offset.y = self.scissor->bottom; - scissor.extent.width = self.scissor->width; - scissor.extent.height = self.scissor->height; - } - else - { - scissor.offset.x = 0; - scissor.offset.y = 0; - scissor.extent.width = self.framebuffer->get_width(); - scissor.extent.height = self.framebuffer->get_height(); - } + scissor.offset.x = scissor_rect.left; + scissor.offset.y = scissor_rect.bottom; + scissor.extent.width = scissor_rect.width; + scissor.extent.height = scissor_rect.height; vk.CmdSetScissor(command_buffer, 0, 1, &scissor); } diff --git a/source/core/blend.h b/source/core/blend.h index 50ea13bd..3edebc8c 100644 --- a/source/core/blend.h +++ b/source/core/blend.h @@ -71,8 +71,17 @@ struct Blend Blend() = default; Blend(BlendFactor, BlendFactor); Blend(BlendEquation, BlendFactor, BlendFactor); + + bool operator==(const Blend &) const; + bool operator!=(const Blend &b) const { return !operator==(b); } }; +inline bool Blend::operator==(const Blend &other) const +{ + return enabled==other.enabled && equation==other.equation && src_factor==other.src_factor && + dst_factor==other.dst_factor && constant==other.constant && write_mask==other.write_mask; +} + inline ColorWriteMask operator|(ColorWriteMask m1, ColorWriteMask m2) { return static_cast(static_cast(m1)|static_cast(m2)); } diff --git a/source/core/depthtest.h b/source/core/depthtest.h index e6f1349a..76602269 100644 --- a/source/core/depthtest.h +++ b/source/core/depthtest.h @@ -28,8 +28,16 @@ struct DepthTest DepthTest() = default; DepthTest(Predicate, bool = true); + + bool operator==(const DepthTest &) const; + bool operator!=(const DepthTest &d) const { return !operator==(d); } }; +inline bool DepthTest::operator==(const DepthTest &other) const +{ + return enabled==other.enabled && compare==other.compare && write==other.write; +} + } // namespace GL } // namespace Msp diff --git a/source/core/framebuffer.h b/source/core/framebuffer.h index 1a13ca5b..54765963 100644 --- a/source/core/framebuffer.h +++ b/source/core/framebuffer.h @@ -5,6 +5,7 @@ #include "color.h" #include "framebuffer_backend.h" #include "frameformat.h" +#include "rect.h" #include "texturecube.h" namespace Msp { @@ -72,6 +73,7 @@ public: unsigned get_width() const { return width; } unsigned get_height() const { return height; } + Rect get_rect() const { return Rect(0, 0, width, height); } unsigned get_layers() const { return layers; } protected: diff --git a/source/core/pipelinestate.cpp b/source/core/pipelinestate.cpp index feb429a6..8d59a316 100644 --- a/source/core/pipelinestate.cpp +++ b/source/core/pipelinestate.cpp @@ -10,7 +10,7 @@ namespace Msp { namespace GL { template -void PipelineState::set(T &target, T value, unsigned flag) +void PipelineState::set(T &target, const T &value, unsigned flag) { if(value!=target) { @@ -24,12 +24,12 @@ void PipelineState::set_framebuffer(const Framebuffer *f) set(framebuffer, f, FRAMEBUFFER); } -void PipelineState::set_viewport(const Rect *v) +void PipelineState::set_viewport(const Rect &v) { set(viewport, v, VIEWPORT); } -void PipelineState::set_scissor(const Rect *s) +void PipelineState::set_scissor(const Rect &s) { set(scissor, s, SCISSOR); } @@ -101,17 +101,17 @@ void PipelineState::set_face_cull(CullMode c) set(face_cull, c, FACE_CULL); } -void PipelineState::set_depth_test(const DepthTest *dt) +void PipelineState::set_depth_test(const DepthTest &dt) { set(depth_test, dt, DEPTH_TEST); } -void PipelineState::set_stencil_test(const StencilTest *st) +void PipelineState::set_stencil_test(const StencilTest &st) { set(stencil_test, st, STENCIL_TEST); } -void PipelineState::set_blend(const Blend *b) +void PipelineState::set_blend(const Blend &b) { set(blend, b, BLEND); } diff --git a/source/core/pipelinestate.h b/source/core/pipelinestate.h index bc6087c7..28624ed7 100644 --- a/source/core/pipelinestate.h +++ b/source/core/pipelinestate.h @@ -3,21 +3,21 @@ #include #include +#include "blend.h" #include "cullface.h" +#include "depthtest.h" #include "pipelinestate_backend.h" #include "primitivetype.h" +#include "rect.h" +#include "stenciltest.h" namespace Msp { namespace GL { -class Blend; class Buffer; -class DepthTest; class Framebuffer; class Program; -class Rect; class Sampler; -class StencilTest; class Texture; class UniformBlock; class VertexSetup; @@ -72,8 +72,8 @@ private: }; const Framebuffer *framebuffer = 0; - const Rect *viewport = 0; - const Rect *scissor = 0; + Rect viewport = Rect::max(); + Rect scissor = Rect::max(); const Program *shprog = 0; std::vector uniform_blocks; std::vector textures; @@ -81,16 +81,16 @@ private: PrimitiveType primitive_type = TRIANGLES; FaceWinding front_face = COUNTERCLOCKWISE; CullMode face_cull = NO_CULL; - const DepthTest *depth_test = 0; - const StencilTest *stencil_test = 0; - const Blend *blend = 0; + DepthTest depth_test; + StencilTest stencil_test; + Blend blend; template - void set(T &, T, unsigned); + void set(T &, const T &, unsigned); public: void set_framebuffer(const Framebuffer *); - void set_viewport(const Rect *); - void set_scissor(const Rect *); + void set_viewport(const Rect &); + void set_scissor(const Rect &); void set_shader_program(const Program *); void set_uniform_block(int, const UniformBlock *); void set_texture(unsigned, const Texture *, const Sampler *); @@ -99,12 +99,12 @@ public: void set_primitive_type(PrimitiveType); void set_front_face(FaceWinding); void set_face_cull(CullMode); - void set_depth_test(const DepthTest *); - void set_stencil_test(const StencilTest *); - void set_blend(const Blend *); + void set_depth_test(const DepthTest &); + void set_stencil_test(const StencilTest &); + void set_blend(const Blend &); const Framebuffer *get_framebuffer() const { return framebuffer; } - const Rect *get_viewport() const { return viewport; } + const Rect &get_viewport() const { return viewport; } const Program *get_shader_program() const { return shprog; } const VertexSetup *get_vertex_setup() const { return vertex_setup; } FaceWinding get_front_face() const { return front_face; } diff --git a/source/core/rect.h b/source/core/rect.h index 4f6bd6bd..e118b39b 100644 --- a/source/core/rect.h +++ b/source/core/rect.h @@ -1,6 +1,9 @@ #ifndef MSP_GL_RECT_H_ #define MSP_GL_RECT_H_ +#include +#include + namespace Msp { namespace GL { @@ -13,8 +16,42 @@ struct Rect Rect() = default; Rect(int l, int b, unsigned w, unsigned h): left(l), bottom(b), width(w), height(h) { } + + static Rect max() { unsigned s = std::numeric_limits::max(); return Rect(0, 0, s, s); } + + bool operator==(const Rect &) const; + bool operator!=(const Rect &r) const { return !operator==(r); } + + Rect intersect(const Rect &) const; }; +inline bool Rect::operator==(const Rect &other) const +{ + return left==other.left && bottom==other.bottom && width==other.width && height==other.height; +} + +inline Rect Rect::intersect(const Rect &other) const +{ + auto intersect_axis = [](int &s1, unsigned &z1, int s2, unsigned z2){ + if(s2>s1) + { + unsigned d = s2-s1; + z1 = (d>z1 ? 0 : std::min(z1-d, z2)); + s1 = s2; + } + else + { + unsigned d = s1-s2; + z1 = (d>z2 ? 0 : std::min(z2-d, z1)); + } + }; + + Rect result = *this; + intersect_axis(result.left, result.width, other.left, other.width); + intersect_axis(result.bottom, result.height, other.bottom, other.height); + return result; +} + } // namespace GL } // namespace Msp diff --git a/source/core/stenciltest.h b/source/core/stenciltest.h index 09f1d278..2a4338f2 100644 --- a/source/core/stenciltest.h +++ b/source/core/stenciltest.h @@ -43,8 +43,17 @@ struct StencilTest StencilOp depth_fail_op = KEEP; StencilOp depth_pass_op = KEEP; unsigned reference = 0; + + bool operator==(const StencilTest &) const; + bool operator!=(const StencilTest &s) const { return !operator==(s); } }; +inline bool StencilTest::operator==(const StencilTest &other) const +{ + return enabled==other.enabled && compare==other.compare && stencil_fail_op==other.stencil_fail_op && + depth_fail_op==other.depth_fail_op && depth_pass_op==other.depth_pass_op && reference==other.reference; +} + void operator>>(const LexicalConverter &, StencilOp &); void operator<<(LexicalConverter &, StencilOp); diff --git a/source/render/renderer.cpp b/source/render/renderer.cpp index a235a42b..0c5bf774 100644 --- a/source/render/renderer.cpp +++ b/source/render/renderer.cpp @@ -363,9 +363,12 @@ void Renderer::apply_state() pipeline_state.set_texture(t.binding, t.texture, t.level, t.sampler); } - pipeline_state.set_depth_test(state.depth_test); - pipeline_state.set_stencil_test(state.stencil_test); - pipeline_state.set_blend(state.blend); + static const DepthTest default_depth_test; + pipeline_state.set_depth_test(state.depth_test ? *state.depth_test : default_depth_test); + static const StencilTest default_stencil_test; + pipeline_state.set_stencil_test(state.stencil_test ? *state.stencil_test : default_stencil_test); + static const Blend default_blend; + pipeline_state.set_blend(state.blend ? *state.blend : default_blend); } -- 2.43.0