vulkan-playground/vulkan_framebuffer_utl.h

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