Added Vulkan framebuffer class
This commit is contained in:
parent
8d7450dbf6
commit
2c663a6c45
1 changed files with 210 additions and 0 deletions
210
base/vulkanframebuffer.hpp
Normal file
210
base/vulkanframebuffer.hpp
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Vulkan framebuffer class
|
||||
*
|
||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include "vulkan/vulkan.h"
|
||||
#include "vulkandevice.hpp"
|
||||
#include "vulkantools.h"
|
||||
|
||||
namespace vk
|
||||
{
|
||||
/**
|
||||
* @brief Encapsulates a single frame buffer attachment
|
||||
*/
|
||||
struct FramebufferAttachment
|
||||
{
|
||||
VkImage image;
|
||||
VkDeviceMemory memory;
|
||||
VkImageView view;
|
||||
VkFormat format;
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the attachment has a depth component
|
||||
*/
|
||||
bool hasDepth()
|
||||
{
|
||||
std::vector<VkFormat> formats =
|
||||
{
|
||||
VK_FORMAT_D16_UNORM,
|
||||
VK_FORMAT_X8_D24_UNORM_PACK32,
|
||||
VK_FORMAT_D32_SFLOAT,
|
||||
VK_FORMAT_D16_UNORM_S8_UINT,
|
||||
VK_FORMAT_D24_UNORM_S8_UINT,
|
||||
VK_FORMAT_D32_SFLOAT_S8_UINT,
|
||||
};
|
||||
return std::find(formats.begin(), formats.end(), format) != std::end(formats);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the attachment has a stencil component
|
||||
*/
|
||||
bool hasStencil()
|
||||
{
|
||||
std::vector<VkFormat> formats =
|
||||
{
|
||||
VK_FORMAT_S8_UINT,
|
||||
VK_FORMAT_D16_UNORM_S8_UINT,
|
||||
VK_FORMAT_D24_UNORM_S8_UINT,
|
||||
VK_FORMAT_D32_SFLOAT_S8_UINT,
|
||||
};
|
||||
return std::find(formats.begin(), formats.end(), format) != std::end(formats);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Describes the attributes of a framebuffer to be created
|
||||
*/
|
||||
struct FramebufferCreateInfo
|
||||
{
|
||||
uint32_t width, height;
|
||||
uint32_t layerCount;
|
||||
VkFormat format;
|
||||
// todo: could be derived from format
|
||||
VkImageUsageFlags usage;
|
||||
// todo: rename
|
||||
bool sample;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Encaspulates a complete Vulkan framebuffer with an arbitrary number and combination of attachments
|
||||
*/
|
||||
struct Framebuffer
|
||||
{
|
||||
private:
|
||||
vk::VulkanDevice *vulkanDevice;
|
||||
public:
|
||||
uint32_t width, height;
|
||||
VkFramebuffer framebuffer;
|
||||
VkRenderPass renderPass;
|
||||
VkSampler sampler;
|
||||
std::vector<vk::FramebufferAttachment> attachments;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param vulkanDevice Pointer to a valid VulkanDevice
|
||||
*/
|
||||
Framebuffer(vk::VulkanDevice *vulkanDevice)
|
||||
{
|
||||
assert(vulkanDevice);
|
||||
this->vulkanDevice = vulkanDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy and free resources used for the framebuffer and all of it's attachments
|
||||
*/
|
||||
void FreeResources(VkDevice device)
|
||||
{
|
||||
for (auto attachment : attachments)
|
||||
{
|
||||
vkDestroyImage(device, attachment.image, nullptr);
|
||||
vkDestroyImageView(device, attachment.view, nullptr);
|
||||
vkFreeMemory(device, attachment.memory, nullptr);
|
||||
}
|
||||
vkDestroySampler(device, sampler, nullptr);
|
||||
vkDestroyRenderPass(device, renderPass, nullptr);
|
||||
vkDestroyFramebuffer(device, framebuffer, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new attachment described by createinfo to the framebuffer's attachment list
|
||||
*
|
||||
* @param createinfo Structure that specifices the framebuffer to be constructed
|
||||
* @param layoutCmd A valid and active command buffer used for the initial layout transitions
|
||||
*
|
||||
* @return Index of the new attachment
|
||||
*/
|
||||
uint32_t addAttachment(vk::FramebufferCreateInfo createinfo, VkCommandBuffer layoutCmd)
|
||||
{
|
||||
vk::FramebufferAttachment attachment;
|
||||
|
||||
attachment.format = createinfo.format;
|
||||
|
||||
VkImageAspectFlags aspectMask = VK_FLAGS_NONE;
|
||||
VkImageLayout imageLayout;
|
||||
|
||||
// Select aspect mask and layout depending on usage
|
||||
if (createinfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
||||
{
|
||||
aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageLayout = createinfo.sample ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
if (createinfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
{
|
||||
if (attachment.hasDepth())
|
||||
{
|
||||
aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
if (attachment.hasStencil())
|
||||
{
|
||||
aspectMask = aspectMask | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
imageLayout = createinfo.sample ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
assert(aspectMask > 0);
|
||||
|
||||
VkImageCreateInfo image = vkTools::initializers::imageCreateInfo();
|
||||
image.imageType = VK_IMAGE_TYPE_2D;
|
||||
image.format = createinfo.format;
|
||||
image.extent.width = createinfo.width;
|
||||
image.extent.height = createinfo.height;
|
||||
image.extent.depth = 1;
|
||||
image.mipLevels = 1;
|
||||
image.arrayLayers = createinfo.layerCount;
|
||||
image.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image.usage = createinfo.usage;
|
||||
|
||||
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
|
||||
VkMemoryRequirements memReqs;
|
||||
|
||||
// Create image for this attachment
|
||||
VK_CHECK_RESULT(vkCreateImage(vulkanDevice->device, &image, nullptr, &attachment.image));
|
||||
vkGetImageMemoryRequirements(vulkanDevice->device, attachment.image, &memReqs);
|
||||
memAlloc.allocationSize = memReqs.size;
|
||||
memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_CHECK_RESULT(vkAllocateMemory(vulkanDevice->device, &memAlloc, nullptr, &attachment.memory));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(vulkanDevice->device, attachment.image, attachment.memory, 0));
|
||||
|
||||
attachment.subresourceRange = {};
|
||||
attachment.subresourceRange.aspectMask = aspectMask;
|
||||
attachment.subresourceRange.levelCount = 1;
|
||||
attachment.subresourceRange.layerCount = createinfo.layerCount;
|
||||
|
||||
// Set the initial layout to shader read instead of attachment
|
||||
// Note that the render loop has to take care of the transition from read to attachment
|
||||
vkTools::setImageLayout(
|
||||
layoutCmd,
|
||||
attachment.image,
|
||||
aspectMask,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
imageLayout,
|
||||
attachment.subresourceRange);
|
||||
|
||||
VkImageViewCreateInfo imageView = vkTools::initializers::imageViewCreateInfo();
|
||||
imageView.viewType = (createinfo.layerCount == 1) ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
imageView.format = createinfo.format;
|
||||
imageView.subresourceRange = attachment.subresourceRange;
|
||||
//todo: workaround for depth+stencil attachments
|
||||
imageView.subresourceRange.aspectMask = (attachment.hasDepth()) ? VK_IMAGE_ASPECT_DEPTH_BIT : aspectMask;
|
||||
imageView.image = attachment.image;
|
||||
VK_CHECK_RESULT(vkCreateImageView(vulkanDevice->device, &imageView, nullptr, &attachment.view));
|
||||
|
||||
attachments.push_back(attachment);
|
||||
|
||||
return static_cast<uint32_t>(attachments.size() - 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue