#include "frameformat.h"
#include "pipelinestate.h"
#include "rect.h"
+#include "renderpass.h"
#include "semaphore.h"
-#include "structurebuilder.h"
#include "swapchaintexture.h"
#include "vulkan.h"
if(dynamic_cast<const SwapChainTexture *>(framebuffer->get_attachment(i)))
fb_is_swapchain = true;
- 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 && full_viewport), fb_is_swapchain);
- begin_buffer(render_pass);
-
- StructureBuilder sb(pass_begin_info, 2);
- VkRenderPassBeginInfo *const &begin_info = sb.add<VkRenderPassBeginInfo>(1);
- VkClearValue *const &vk_clear_values = sb.add<VkClearValue>(FrameFormat::MAX_ATTACHMENTS);
-
- begin_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- begin_info->renderPass = handle_cast<::VkRenderPass>(render_pass);
- begin_info->framebuffer = handle_cast<::VkFramebuffer>(framebuffer->handle);
+ RenderPass render_pass;
+ render_pass.framebuffer = framebuffer;
+ render_pass.render_area = viewport;
+ render_pass.clear = clear;
+ render_pass.clear_values = clear_values;
+ render_pass.to_present = fb_is_swapchain;
+ render_pass.update(device);
- 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;
+ discard_fb_contents = render_pass.discard_fb_contents;
- if(clear_values)
- {
- unsigned i = 0;
- for(FrameAttachment a: framebuffer->get_format())
- {
- if(get_attach_point(a)==get_attach_point(DEPTH_ATTACHMENT))
- vk_clear_values[i].depthStencil.depth = clear_values[i].depth_stencil.depth;
- else if(get_attach_point(a)==get_attach_point(STENCIL_ATTACHMENT))
- vk_clear_values[i].depthStencil.stencil = clear_values[i].depth_stencil.stencil;
- else
- {
- vk_clear_values[i].color.float32[0] = clear_values[i].color.r;
- vk_clear_values[i].color.float32[1] = clear_values[i].color.g;
- vk_clear_values[i].color.float32[2] = clear_values[i].color.b;
- vk_clear_values[i].color.float32[3] = clear_values[i].color.a;
- }
- ++i;
- }
-
- begin_info->clearValueCount = framebuffer->get_format().size();
- begin_info->pClearValues = vk_clear_values;
- }
+ begin_buffer(render_pass.handle);
+ render_pass.fill_begin_info(pass_begin_info);
}
void VulkanCommands::end_render_pass()
-#include <msp/core/hash.h>
#include "device.h"
-#include "framebuffer.h"
#include "pipelinecache.h"
#include "pipelinestate.h"
+#include "renderpass.h"
#include "vulkan.h"
using namespace std;
vk.DestroyPipeline(kvp.second);
}
-VkRenderPass PipelineCache::get_render_pass(const FrameFormat &format, bool clear, bool discard, bool to_present)
+VkRenderPass PipelineCache::get_render_pass(const RenderPass &rp)
{
+ uint64_t key = rp.compute_hash();
+ auto i = render_passes.find(key);
+ if(i!=render_passes.end())
+ return i->second;
+
const VulkanFunctions &vk = device.get_functions();
- uint64_t key = hash<64>(static_cast<uint8_t>(clear | (discard*2) | (to_present*4)));
- for(FrameAttachment a: format)
- key = hash_update<64>(key, a);
-
- auto j = render_passes.find(key);
- if(j!=render_passes.end())
- return j->second;
-
- VkAttachmentDescription attachments[FrameFormat::MAX_ATTACHMENTS] = { };
- VkAttachmentReference color_refs[FrameFormat::MAX_ATTACHMENTS] = { };
- VkAttachmentReference depth_stencil_ref = { };
- depth_stencil_ref.attachment = VK_ATTACHMENT_UNUSED;
-
- VkSampleCountFlagBits vk_samples = static_cast<VkSampleCountFlagBits>(get_vulkan_samples(format.get_samples()));
-
- unsigned i = 0;
- unsigned color_count = 0;
- for(FrameAttachment a: format)
- {
- VkImageLayout subpass_layout = static_cast<VkImageLayout>(get_vulkan_attachment_layout(get_components(get_attachment_pixelformat(a))));
- VkImageLayout external_layout = (to_present ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : subpass_layout);
-
- attachments[i].format = static_cast<VkFormat>(get_vulkan_pixelformat(get_attachment_pixelformat(a)));
- attachments[i].samples = vk_samples;
- attachments[i].loadOp = (clear ? discard ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD);
- attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
- attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
- attachments[i].initialLayout = ((clear && discard) ? VK_IMAGE_LAYOUT_UNDEFINED : external_layout);
- attachments[i].finalLayout = external_layout;
-
- if(subpass_layout==VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
- {
- color_refs[color_count].attachment = i;
- color_refs[color_count].layout = subpass_layout;
- ++color_count;
- }
- else
- {
- depth_stencil_ref.attachment = i;
- depth_stencil_ref.layout = subpass_layout;
- }
-
- ++i;
- }
-
- VkSubpassDescription subpass = { };
- subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass.colorAttachmentCount = color_count;
- subpass.pColorAttachments = color_refs;
- subpass.pDepthStencilAttachment = &depth_stencil_ref;
-
- VkSubpassDependency dependency = { };
- VkRenderPassCreateInfo render_pass_info = { };
- render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- render_pass_info.attachmentCount = format.size();
- render_pass_info.pAttachments = attachments;
- render_pass_info.subpassCount = 1;
- render_pass_info.pSubpasses = &subpass;
-
- if(to_present)
- {
- dependency.srcSubpass = 0;
- dependency.dstSubpass = VK_SUBPASS_EXTERNAL;
- dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
- dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
- dependency.dstAccessMask = 0;
-
- render_pass_info.dependencyCount = 1;
- render_pass_info.pDependencies = &dependency;
- }
+ vector<char> buffer;
+ rp.fill_creation_info(buffer);
+ const VkRenderPassCreateInfo *creation_info = reinterpret_cast<const VkRenderPassCreateInfo *>(buffer.data());
VkRenderPass render_pass;
- vk.CreateRenderPass(render_pass_info, render_pass);
+ vk.CreateRenderPass(*creation_info, render_pass);
render_passes.insert(make_pair(key, render_pass));
#include <cstdint>
#include <map>
-#include "frameformat.h"
#include "handles.h"
namespace Msp {
class Device;
class PipelineState;
+struct RenderPass;
class PipelineCache
{
PipelineCache(PipelineCache &&);
~PipelineCache();
- VkRenderPass get_render_pass(const FrameFormat &, bool, bool, bool);
+ VkRenderPass get_render_pass(const RenderPass &);
VkPipeline get_pipeline(const PipelineState &);
};
#include "pipelinestate_backend.h"
#include "program.h"
#include "rect.h"
+#include "renderpass.h"
#include "sampler.h"
#include "stenciltest.h"
#include "structurebuilder.h"
const PipelineState &self = *static_cast<const PipelineState *>(this);
const FrameFormat &format = self.framebuffer->get_format();
- VkRenderPass render_pass = device.get_pipeline_cache().get_render_pass(format, false, false, false);
+ RenderPass render_pass;
+ render_pass.framebuffer = self.framebuffer;
+ render_pass.update(device);
unsigned n_color_attachments = 0;
for(FrameAttachment a: format)
pipeline_info->pDepthStencilState = depth_stencil_info;
pipeline_info->pColorBlendState = blend_info;
pipeline_info->pDynamicState = dynamic_info;
- pipeline_info->renderPass = handle_cast<::VkRenderPass>(render_pass);
+ pipeline_info->renderPass = handle_cast<::VkRenderPass>(render_pass.handle);
pipeline_info->subpass = 0;
if(self.shprog)
--- /dev/null
+#include <msp/core/hash.h>
+#include "device.h"
+#include "framebuffer.h"
+#include "renderpass.h"
+#include "structurebuilder.h"
+#include "vulkan.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+void RenderPass::update(Device &device)
+{
+ Rect fb_rect = framebuffer->get_rect();
+ render_area = fb_rect.intersect(render_area);
+ discard_fb_contents = (clear && render_area==fb_rect);
+ handle = device.get_pipeline_cache().get_render_pass(*this);
+}
+
+uint64_t RenderPass::compute_hash() const
+{
+ bool discard = (!clear_values && discard_fb_contents);
+ uint64_t result = hash<64>(static_cast<uint8_t>(clear | (discard*2) | (to_present*4)));
+ for(FrameAttachment a: framebuffer->get_format())
+ result = hash_update<64>(result, a);
+
+ return result;
+}
+
+void RenderPass::fill_creation_info(vector<char> &buffer) const
+{
+ const FrameFormat &format = framebuffer->get_format();
+
+ bool discard = (!clear_values && discard_fb_contents);
+ bool has_depth = any_of(format.begin(), format.end(), [](FrameAttachment a){
+ return get_components(get_attachment_pixelformat(a))==DEPTH_COMPONENT;
+ });
+ unsigned color_count = format.size()-has_depth;
+
+ StructureBuilder sb(buffer, 6);
+ VkRenderPassCreateInfo *const &render_pass_info = sb.add<VkRenderPassCreateInfo>();
+ VkSubpassDescription *const &subpass = sb.add<VkSubpassDescription>();
+ VkAttachmentDescription *const &attachments = sb.add<VkAttachmentDescription>(format.size());
+ VkAttachmentReference *const &color_refs = sb.add<VkAttachmentReference>(color_count);
+ VkAttachmentReference *const &depth_stencil_ref = sb.add<VkAttachmentReference>(has_depth);
+ VkSubpassDependency *const &dependency = sb.add<VkSubpassDependency>(to_present);
+
+ VkSampleCountFlagBits vk_samples = static_cast<VkSampleCountFlagBits>(get_vulkan_samples(format.get_samples()));
+
+ VkAttachmentReference *color_ptr = color_refs;
+ unsigned i = 0;
+ for(FrameAttachment a: format)
+ {
+ VkImageLayout subpass_layout = static_cast<VkImageLayout>(get_vulkan_attachment_layout(get_components(get_attachment_pixelformat(a))));
+ VkImageLayout external_layout = (to_present ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : subpass_layout);
+
+ attachments[i].format = static_cast<VkFormat>(get_vulkan_pixelformat(get_attachment_pixelformat(a)));
+ attachments[i].samples = vk_samples;
+ attachments[i].loadOp = (clear ? discard ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD);
+ attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+ attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachments[i].initialLayout = ((clear && discard) ? VK_IMAGE_LAYOUT_UNDEFINED : external_layout);
+ attachments[i].finalLayout = external_layout;
+
+ if(subpass_layout==VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
+ {
+ color_ptr->attachment = i;
+ color_ptr->layout = subpass_layout;
+ ++color_ptr;
+ }
+ else
+ {
+ depth_stencil_ref->attachment = i;
+ depth_stencil_ref->layout = subpass_layout;
+ }
+
+ ++i;
+ }
+
+ subpass->pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass->colorAttachmentCount = color_count;
+ if(color_count)
+ subpass->pColorAttachments = color_refs;
+ if(has_depth)
+ subpass->pDepthStencilAttachment = depth_stencil_ref;
+
+ render_pass_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ render_pass_info->attachmentCount = format.size();
+ render_pass_info->pAttachments = attachments;
+ render_pass_info->subpassCount = 1;
+ render_pass_info->pSubpasses = subpass;
+
+ if(to_present)
+ {
+ dependency->srcSubpass = 0;
+ dependency->dstSubpass = VK_SUBPASS_EXTERNAL;
+ dependency->srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ dependency->srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
+ dependency->dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+ dependency->dstAccessMask = 0;
+
+ render_pass_info->dependencyCount = 1;
+ render_pass_info->pDependencies = dependency;
+ }
+}
+
+void RenderPass::fill_begin_info(vector<char> &buffer) const
+{
+ const FrameFormat &format = framebuffer->get_format();
+
+ StructureBuilder sb(buffer, 2);
+ VkRenderPassBeginInfo *const &begin_info = sb.add<VkRenderPassBeginInfo>(1);
+ VkClearValue *const &vk_clear_values = sb.add<VkClearValue>(format.size());
+
+ begin_info->sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ begin_info->renderPass = handle_cast<::VkRenderPass>(handle);
+ begin_info->framebuffer = handle_cast<::VkFramebuffer>(framebuffer->handle);
+
+ 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)
+ {
+ unsigned i = 0;
+ for(FrameAttachment a: format)
+ {
+ if(get_attach_point(a)==get_attach_point(DEPTH_ATTACHMENT))
+ vk_clear_values[i].depthStencil.depth = clear_values[i].depth_stencil.depth;
+ else if(get_attach_point(a)==get_attach_point(STENCIL_ATTACHMENT))
+ vk_clear_values[i].depthStencil.stencil = clear_values[i].depth_stencil.stencil;
+ else
+ {
+ vk_clear_values[i].color.float32[0] = clear_values[i].color.r;
+ vk_clear_values[i].color.float32[1] = clear_values[i].color.g;
+ vk_clear_values[i].color.float32[2] = clear_values[i].color.b;
+ vk_clear_values[i].color.float32[3] = clear_values[i].color.a;
+ }
+ ++i;
+ }
+
+ begin_info->clearValueCount = format.size();
+ begin_info->pClearValues = vk_clear_values;
+ }
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_RENDERPASS_H_
+#define MSP_GL_RENDERPASS_H_
+
+#include <vector>
+#include "handles.h"
+
+namespace Msp {
+namespace GL {
+
+class Device;
+class Framebuffer;
+union ClearValue;
+
+struct RenderPass
+{
+ const Framebuffer *framebuffer = 0;
+ Rect render_area;
+ bool clear = false;
+ const ClearValue *clear_values = 0;
+ bool to_present = false;
+ bool discard_fb_contents = false;
+ VkRenderPass handle = 0;
+
+ void update(Device &);
+
+ std::uint64_t compute_hash() const;
+ bool discards_framebuffer_contents() const;
+ void fill_creation_info(std::vector<char> &) const;
+ void fill_begin_info(std::vector<char> &) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif