]> git.tdb.fi Git - libs/gl.git/commitdiff
Store simpler states by value in PipelineState
authorMikko Rasa <tdb@tdb.fi>
Wed, 12 Jan 2022 20:24:54 +0000 (22:24 +0200)
committerMikko Rasa <tdb@tdb.fi>
Wed, 12 Jan 2022 20:24:54 +0000 (22:24 +0200)
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.

12 files changed:
source/backends/opengl/pipelinestate_backend.cpp
source/backends/vulkan/commands_backend.cpp
source/backends/vulkan/commands_backend.h
source/backends/vulkan/pipelinestate_backend.cpp
source/core/blend.h
source/core/depthtest.h
source/core/framebuffer.h
source/core/pipelinestate.cpp
source/core/pipelinestate.h
source/core/rect.h
source/core/stenciltest.h
source/render/renderer.cpp

index fb802995f6355e46a6794f07e6f4ec5d1b4e7593..08edc5e71a05d4a04a9932fbac0ff2de4f5e8144 100644 (file)
@@ -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
index bf8ee3f13d5652c21a14db09ff1e077e016740cc..d655134d032fdf95cf05fe6a5d7941868cd2c341 100644 (file)
@@ -97,11 +97,15 @@ void VulkanCommands::begin_render_pass(bool clear, const ClearValue *clear_value
                if(dynamic_cast<const SwapChainTexture *>(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;
 }
 
index 5fcae882a26a7c053ff72595c35521d32735d1bc..00e492f2542c2fa9fada9c0929480503cb842f25 100644 (file)
@@ -4,6 +4,7 @@
 #include <vector>
 #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<char> pass_begin_info;
index 84609ab03666370a0ce0793f3e6bdc4e9961daaf..efa08a8634ecf15b755b459121f629a2682da529 100644 (file)
@@ -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<char> &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<VkCompareOp>(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<VkCompareOp>(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<VkStencilOp>(get_vulkan_stencil_op(self.stencil_test.stencil_fail_op));
+       depth_stencil_info->front.passOp = static_cast<VkStencilOp>(get_vulkan_stencil_op(self.stencil_test.depth_pass_op));
+       depth_stencil_info->front.depthFailOp = static_cast<VkStencilOp>(get_vulkan_stencil_op(self.stencil_test.depth_fail_op));
+       depth_stencil_info->front.compareOp = static_cast<VkCompareOp>(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; i<n_color_attachments; ++i)
        {
-               depth_stencil_info->stencilTestEnable = stencil_test->enabled;
-               depth_stencil_info->front.failOp = static_cast<VkStencilOp>(get_vulkan_stencil_op(stencil_test->stencil_fail_op));
-               depth_stencil_info->front.passOp = static_cast<VkStencilOp>(get_vulkan_stencil_op(stencil_test->depth_pass_op));
-               depth_stencil_info->front.depthFailOp = static_cast<VkStencilOp>(get_vulkan_stencil_op(stencil_test->depth_fail_op));
-               depth_stencil_info->front.compareOp = static_cast<VkCompareOp>(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; i<n_color_attachments; ++i)
-               {
-                       blend_attachments[i].blendEnable = blend->enabled;
-                       blend_attachments[i].srcColorBlendFactor = static_cast<VkBlendFactor>(get_vulkan_blend_factor(blend->src_factor));
-                       blend_attachments[i].dstColorBlendFactor = static_cast<VkBlendFactor>(get_vulkan_blend_factor(blend->dst_factor));
-                       blend_attachments[i].colorBlendOp = static_cast<VkBlendOp>(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<n_color_attachments; ++i)
-                       blend_attachments[i].colorWriteMask = VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT;
+               blend_attachments[i].blendEnable = self.blend.enabled;
+               blend_attachments[i].srcColorBlendFactor = static_cast<VkBlendFactor>(get_vulkan_blend_factor(self.blend.src_factor));
+               blend_attachments[i].dstColorBlendFactor = static_cast<VkBlendFactor>(get_vulkan_blend_factor(self.blend.dst_factor));
+               blend_attachments[i].colorBlendOp = static_cast<VkBlendOp>(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);
 }
 
index 50ea13bd28a897bd6bc3fa491baffaeb66cb8ab4..3edebc8c7f4bdde90e8d7aa14c2ab87cc300ff04 100644 (file)
@@ -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<ColorWriteMask>(static_cast<int>(m1)|static_cast<int>(m2)); }
index e6f1349a7816ff20594cfb22a4c1017a93d1f193..76602269a137848fc7a3b5cc6f84199c28d6358e 100644 (file)
@@ -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
 
index 1a13ca5bc9dbc979fa4d9bbcfcee47a1eed9e831..5476596317000dbecd53eca3146adce3dcc4407c 100644 (file)
@@ -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:
index feb429a6eb126cc851f600c6e74144c698bcd5d9..8d59a31624eddc823e23cd7260ed444c4efc9129 100644 (file)
@@ -10,7 +10,7 @@ namespace Msp {
 namespace GL {
 
 template<typename T>
-void PipelineState::set(T &target, 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);
 }
index bc6087c780ea625d029bc5752c6fc80c3b4bdba0..28624ed7ca64a5a0e5bba111cf45b27477bb11e5 100644 (file)
@@ -3,21 +3,21 @@
 
 #include <vector>
 #include <msp/core/noncopyable.h>
+#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<BoundUniformBlock> uniform_blocks;
        std::vector<BoundTexture> 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<typename T>
-       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; }
index 4f6bd6bd43e266486d30844716475f9555119cef..e118b39b8c82d7da4d7b35cb00544a7ad487b71c 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef MSP_GL_RECT_H_
 #define MSP_GL_RECT_H_
 
+#include <algorithm>
+#include <limits>
+
 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<unsigned>::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
 
index 09f1d2784e0e0686a71633985febfd0ec069bf6a..2a4338f2012afef716c7f2b91494e32d7abeb7cd 100644 (file)
@@ -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);
 
index a235a42b416e3b6a20429062e44b0aadf7135226..0c5bf77454ed25c32151f2a44ed189723234a192 100644 (file)
@@ -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);
 }