}
}
- 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)
{
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);
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
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);
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)
{
vk.CmdEndRenderPass(primary_buffer);
framebuffer = 0;
- viewport = 0;
+ viewport = Rect::max();
pass_buffer = 0;
}
#include <vector>
#include "fence.h"
#include "handles.h"
+#include "rect.h"
namespace Msp {
namespace GL {
class Framebuffer;
class PipelineState;
class QueryPool;
-struct Rect;
class Semaphore;
class SwapChain;
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;
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);
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;
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;
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);
}
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)); }
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
#include "color.h"
#include "framebuffer_backend.h"
#include "frameformat.h"
+#include "rect.h"
#include "texturecube.h"
namespace Msp {
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:
namespace GL {
template<typename T>
-void PipelineState::set(T &target, T value, unsigned flag)
+void PipelineState::set(T &target, const T &value, unsigned flag)
{
if(value!=target)
{
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);
}
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);
}
#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;
};
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;
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 *);
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; }
#ifndef MSP_GL_RECT_H_
#define MSP_GL_RECT_H_
+#include <algorithm>
+#include <limits>
+
namespace Msp {
namespace GL {
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
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);
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);
}