283 lines
8.6 KiB
C
283 lines
8.6 KiB
C
/*
|
|
* Copyright (c) 2017-2019 Collabora Ltd.
|
|
* Copyright (c) 2024 mittorn
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sub license, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the
|
|
* next paragraph) shall be included in all copies or substantial portions
|
|
* of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
|
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
|
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#ifndef VULKAN_FRAMEBUFFER_UTL_H
|
|
#define VULKAN_FRAMEBUFFER_UTL_H
|
|
#include "vulkan_utl.h"
|
|
struct VulkanFramebuffer
|
|
{
|
|
VkDevice device = NULL;
|
|
struct
|
|
{
|
|
VkImage image;
|
|
VkDeviceMemory mem;
|
|
VkImageView view;
|
|
VkFormat format;
|
|
bool allocated = false;
|
|
} depth = {};
|
|
|
|
|
|
VkImageView color_view = NULL;
|
|
|
|
uint32_t width, height;
|
|
VkFramebuffer frame_buffer = NULL;
|
|
VkRenderPass render_pass = NULL;
|
|
void Create(VkDevice d)
|
|
{
|
|
device = d;
|
|
}
|
|
void Destroy()
|
|
{
|
|
if(!device)
|
|
return;
|
|
if(color_view)
|
|
vkDestroyImageView(device, color_view, NULL);
|
|
color_view = NULL;
|
|
if(depth.view)
|
|
vkDestroyImageView(device, depth.view, NULL);
|
|
depth.view = NULL;
|
|
if(depth.allocated)
|
|
{
|
|
if(depth.image)
|
|
vkDestroyImage(device, depth.image, NULL);
|
|
depth.image = NULL;
|
|
vkFreeMemory(device, depth.mem, NULL);
|
|
depth.mem = NULL;
|
|
depth.allocated = false;
|
|
}
|
|
|
|
if(frame_buffer)
|
|
vkDestroyFramebuffer(device, frame_buffer, NULL);
|
|
frame_buffer = NULL;
|
|
|
|
if(render_pass)
|
|
vkDestroyRenderPass(device, render_pass, NULL);
|
|
render_pass = NULL;
|
|
}
|
|
void ImportDepthAttachment(VkImage image, VkFormat format)
|
|
{
|
|
depth.image = image;
|
|
VkImageViewCreateInfo image_view = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
.image = depth.image,
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
.format = format,
|
|
.subresourceRange =
|
|
{
|
|
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
};
|
|
|
|
VK_CHECK_RESULT(vkCreateImageView(device, &image_view, NULL, &depth.view));
|
|
}
|
|
|
|
void CreateDepthAttachment(VulkanDevice &dev, VkFormat format, uint32_t w, uint32_t h)
|
|
{
|
|
depth.format = format;
|
|
|
|
VkImageCreateInfo image = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
|
.format = format,
|
|
.extent = { .width = w, .height = h, .depth = 1 },
|
|
.mipLevels = 1,
|
|
.arrayLayers = 1,
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
};
|
|
VkImage dimage;
|
|
VK_CHECK_RESULT(vkCreateImage(device, &image, NULL, &dimage));
|
|
|
|
VkMemoryRequirements mem_reqs;
|
|
vkGetImageMemoryRequirements(device, dimage, &mem_reqs);
|
|
|
|
VkMemoryAllocateInfo mem_alloc = {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
.allocationSize = mem_reqs.size,
|
|
};
|
|
|
|
if (!dev.GetMemoryType(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
&mem_alloc.memoryTypeIndex))
|
|
printf("Could not find memory type.\n");
|
|
|
|
VK_CHECK_RESULT(vkAllocateMemory(device, &mem_alloc, NULL, &depth.mem));
|
|
VK_CHECK_RESULT(vkBindImageMemory(device, dimage, depth.mem, 0));
|
|
ImportDepthAttachment(dimage, format);
|
|
depth.allocated = true;
|
|
}
|
|
|
|
|
|
void Init(VkImage color_image, VkFormat color_format, uint32_t w, uint32_t h)
|
|
{
|
|
width = w;
|
|
height = h;
|
|
|
|
// Set up separate renderpass with references to the color and depth
|
|
// attachments
|
|
VkAttachmentDescription attachmentDescs[2];
|
|
|
|
// Init attachment properties
|
|
for (uint32_t i = 0; i < 2; ++i) {
|
|
attachmentDescs[i].flags = 0;
|
|
attachmentDescs[i].samples = VK_SAMPLE_COUNT_1_BIT;
|
|
attachmentDescs[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
attachmentDescs[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
attachmentDescs[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
attachmentDescs[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
if (i == 1) {
|
|
attachmentDescs[i].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
attachmentDescs[i].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
|
} else {
|
|
attachmentDescs[i].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
attachmentDescs[i].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
}
|
|
}
|
|
|
|
// Formats
|
|
attachmentDescs[0].format = color_format;
|
|
attachmentDescs[1].format = depth.format;
|
|
|
|
VkAttachmentReference colorReferences[1] = {
|
|
{ .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }
|
|
};
|
|
|
|
VkAttachmentReference depthReference = {
|
|
.attachment = 1,
|
|
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
|
};
|
|
|
|
VkSubpassDescription subpass = {
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
.colorAttachmentCount = ARRAY_SIZE(colorReferences),
|
|
.pColorAttachments = colorReferences,
|
|
.pDepthStencilAttachment = &depthReference,
|
|
};
|
|
|
|
// Use subpass dependencies for attachment layput transitions
|
|
VkSubpassDependency dependencies[2] = {
|
|
VkSubpassDependency{
|
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
.dstSubpass = 0,
|
|
.srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
|
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT,
|
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
|
|
},
|
|
VkSubpassDependency{
|
|
.srcSubpass = 0,
|
|
.dstSubpass = VK_SUBPASS_EXTERNAL,
|
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
|
|
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
|
|
}
|
|
};
|
|
|
|
VkRenderPassCreateInfo renderPassInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
.attachmentCount = 2,
|
|
.pAttachments = attachmentDescs,
|
|
.subpassCount = 1,
|
|
.pSubpasses = &subpass,
|
|
.dependencyCount = 2,
|
|
.pDependencies = dependencies,
|
|
};
|
|
|
|
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, NULL, &render_pass));
|
|
|
|
VkImageViewCreateInfo imageView = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
.image = color_image,
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
.format = color_format,
|
|
.subresourceRange = {
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1,
|
|
},
|
|
};
|
|
|
|
VK_CHECK_RESULT(vkCreateImageView(device, &imageView, NULL, &color_view));
|
|
|
|
VkImageView attachments[2] = { color_view, depth.view };
|
|
|
|
VkFramebufferCreateInfo fbufCreateInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
.renderPass = render_pass,
|
|
.attachmentCount = ARRAY_SIZE(attachments),
|
|
.pAttachments = attachments,
|
|
.width = width,
|
|
.height = height,
|
|
.layers = 1,
|
|
};
|
|
|
|
VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, NULL, &frame_buffer));
|
|
}
|
|
|
|
void BeginRenderPass(VkCommandBuffer cmdBuffer)
|
|
{
|
|
VkClearValue clearValues[2] = { { .color = { { 0.0f, 0.0f, 0.0f, 0.0f } } },
|
|
{ .depthStencil = { 1.0f, 0 } } };
|
|
|
|
VkRenderPassBeginInfo renderPassBeginInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
.renderPass = render_pass,
|
|
.framebuffer = frame_buffer,
|
|
.renderArea = { .extent = { .width = width,
|
|
.height = height } },
|
|
.clearValueCount = ARRAY_SIZE(clearValues),
|
|
.pClearValues = clearValues,
|
|
};
|
|
|
|
vkCmdBeginRenderPass(cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
}
|
|
void SetViewportAndScissor(VkCommandBuffer cmdBuffer)
|
|
{
|
|
VkViewport viewport = { .width = (float)width,
|
|
.height = (float)height,
|
|
.minDepth = 0.0f,
|
|
.maxDepth = 1.0f };
|
|
vkCmdSetViewport(cmdBuffer, 0, 1, &viewport);
|
|
|
|
VkRect2D scissor = { .offset = { .x = 0, .y = 0 },
|
|
.extent = { .width = width,
|
|
.height = height } };
|
|
vkCmdSetScissor(cmdBuffer, 0, 1, &scissor);
|
|
}
|
|
|
|
~VulkanFramebuffer()
|
|
{
|
|
Destroy();
|
|
}
|
|
};
|
|
#endif // VULKAN_FRAMEBUFFER_UTL_H
|