Internal Framebuffer detached from Swapchain.

This commit is contained in:
Anish Bhobe 2024-07-24 21:45:23 +02:00
parent cd49d5b869
commit 6e14b74244
5 changed files with 149 additions and 40 deletions

View File

@ -15,6 +15,12 @@ ToExtent2D(const vk::Extent3D &extent)
return {extent.width, extent.height}; return {extent.width, extent.height};
} }
[[nodiscard]] inline vk::Extent3D
ToExtent3D(const vk::Extent2D &extent, const u32 depth)
{
return {extent.width, extent.height, depth};
}
[[nodiscard]] inline vk::Offset2D [[nodiscard]] inline vk::Offset2D
ToOffset2D(const vk::Extent3D &extent) ToOffset2D(const vk::Extent3D &extent)
{ {

View File

@ -10,11 +10,13 @@
#include "swapchain.h" #include "swapchain.h"
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount) Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
: m_FrameIdx(0) : m_FrameIdx(frameCount)
, m_ImageIdx(0) , m_ImageIdx(0)
{ {
m_Device = device; m_Device = device;
eastl::fixed_string<char, 50, false> name = "Frame ";
name += Cast<char>('0' + frameCount);
const vk::CommandPoolCreateInfo commandPoolCreateInfo = { const vk::CommandPoolCreateInfo commandPoolCreateInfo = {
.flags = vk::CommandPoolCreateFlagBits::eTransient, .flags = vk::CommandPoolCreateFlagBits::eTransient,
.queueFamilyIndex = queueFamilyIndex, .queueFamilyIndex = queueFamilyIndex,
@ -40,6 +42,12 @@ Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCo
AbortIfFailed(m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &m_CommandBuffer)); AbortIfFailed(m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &m_CommandBuffer));
device->SetName(m_Pool, name.c_str());
device->SetName(m_FrameAvailableFence, name.c_str());
device->SetName(m_ImageAcquireSem, name.c_str());
device->SetName(m_RenderFinishSem, name.c_str());
device->SetName(m_CommandBuffer, name.c_str());
DEBUG("Frame {} created successfully.", frameCount); DEBUG("Frame {} created successfully.", frameCount);
} }

View File

@ -162,7 +162,7 @@ EndBuild()
} }
void void
Draw(const vk::CommandBuffer commandBuffer, const AttachmentImage *attachmentImage) Draw(const vk::CommandBuffer commandBuffer, const vk::Extent2D extent, const vk::ImageView view)
{ {
// OPTICK_EVENT(); // OPTICK_EVENT();
@ -172,7 +172,7 @@ Draw(const vk::CommandBuffer commandBuffer, const AttachmentImage *attachmentIma
}; };
commandBuffer.beginDebugUtilsLabelEXT(&label); commandBuffer.beginDebugUtilsLabelEXT(&label);
vk::RenderingAttachmentInfo attachmentInfo = { vk::RenderingAttachmentInfo attachmentInfo = {
.imageView = attachmentImage->m_View, .imageView = view,
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal, .imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
.resolveMode = vk::ResolveModeFlagBits::eNone, .resolveMode = vk::ResolveModeFlagBits::eNone,
.loadOp = vk::AttachmentLoadOp::eLoad, .loadOp = vk::AttachmentLoadOp::eLoad,
@ -181,7 +181,7 @@ Draw(const vk::CommandBuffer commandBuffer, const AttachmentImage *attachmentIma
}; };
const vk::RenderingInfo renderingInfo = { const vk::RenderingInfo renderingInfo = {
.renderArea = {.extent = ToExtent2D(attachmentImage->m_Extent)}, .renderArea = {.extent = extent},
.layerCount = 1, .layerCount = 1,
.colorAttachmentCount = 1, .colorAttachmentCount = 1,
.pColorAttachments = &attachmentInfo, .pColorAttachments = &attachmentInfo,

View File

@ -25,7 +25,7 @@ void Destroy(const Device *device);
void Recreate(); void Recreate();
void StartBuild(); void StartBuild();
void EndBuild(); void EndBuild();
void Draw(vk::CommandBuffer commandBuffer, const AttachmentImage *attachmentImage); void Draw(vk::CommandBuffer commandBuffer, vk::Extent2D extent, vk::ImageView view);
void PushDisable(); void PushDisable();
void PopDisable(); void PopDisable();

View File

@ -35,7 +35,8 @@ struct Camera
{ {
mat4 m_View; mat4 m_View;
mat4 m_Perspective; mat4 m_Perspective;
vec4 m_Position; vec3 m_Position;
f32 m_AspectRatio;
}; };
int int
@ -66,7 +67,11 @@ main(int, char **)
.descriptorBindingPartiallyBound = true, .descriptorBindingPartiallyBound = true,
.runtimeDescriptorArray = true, .runtimeDescriptorArray = true,
}, },
.m_Vulkan13Features = {.dynamicRendering = true}, .m_Vulkan13Features =
{
.synchronization2 = true,
.dynamicRendering = true,
},
}; };
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse); QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
@ -83,13 +88,6 @@ main(int, char **)
vk::Format attachmentFormat = vk::Format::eR8G8B8A8Srgb; vk::Format attachmentFormat = vk::Format::eR8G8B8A8Srgb;
Pipeline pipeline = CreatePipeline(&device, attachmentFormat, &resourceManager); Pipeline pipeline = CreatePipeline(&device, attachmentFormat, &resourceManager);
Camera camera = {
.m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)),
.m_Perspective = glm::perspective(
70_deg, Cast<f32>(swapchain.m_Extent.width) / Cast<f32>(swapchain.m_Extent.height), 0.1f, 100.0f),
.m_Position = vec4{0.0f, 2.0f, 2.0f, 1.0f},
};
lightManager.AddDirectional(vec3(0.0f, -1.0f, 0.0f), {0.0f, 0.7f, 0.0f}); lightManager.AddDirectional(vec3(0.0f, -1.0f, 0.0f), {0.0f, 0.7f, 0.0f});
lightManager.AddPoint(vec3{2.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 15.0f); lightManager.AddPoint(vec3{2.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 15.0f);
lightManager.AddPoint(vec3{-2.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, 15.0f); lightManager.AddPoint(vec3{-2.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, 15.0f);
@ -119,6 +117,16 @@ main(int, char **)
AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet)); AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet));
} }
vk::Extent2D internalResolution = {1920, 1080};
Camera camera = {
.m_View = lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)),
.m_Perspective = glm::perspective(
70_deg, Cast<f32>(internalResolution.width) / Cast<f32>(internalResolution.height), 0.1f, 100.0f),
.m_Position = vec4{0.0f, 2.0f, 2.0f, 1.0f},
.m_AspectRatio = Cast<f32>(internalResolution.width) / Cast<f32>(internalResolution.height),
};
UniformBuffer ubo; UniformBuffer ubo;
ubo.Init(&device, sizeof camera, "Camera UBO"); ubo.Init(&device, sizeof camera, "Camera UBO");
ubo.Write(&device, 0, sizeof camera, &camera); ubo.Write(&device, 0, sizeof camera, &camera);
@ -144,16 +152,16 @@ main(int, char **)
// Persistent variables // Persistent variables
vk::Viewport viewport = { vk::Viewport viewport = {
.x = 0, .x = 0,
.y = Cast<f32>(swapchain.m_Extent.height), .y = Cast<f32>(internalResolution.height),
.width = Cast<f32>(swapchain.m_Extent.width), .width = Cast<f32>(internalResolution.width),
.height = -Cast<f32>(swapchain.m_Extent.height), .height = -Cast<f32>(internalResolution.height),
.minDepth = 0.0, .minDepth = 0.0,
.maxDepth = 1.0, .maxDepth = 1.0,
}; };
vk::Rect2D scissor = { vk::Rect2D scissor = {
.offset = {0, 0}, .offset = {0, 0},
.extent = swapchain.m_Extent, .extent = internalResolution,
}; };
vk::ImageSubresourceRange subresourceRange = { vk::ImageSubresourceRange subresourceRange = {
@ -163,21 +171,39 @@ main(int, char **)
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
}; };
vk::ImageMemoryBarrier topOfThePipeBarrier = {
vk::ImageMemoryBarrier2 preRenderBarrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe,
.srcAccessMask = vk::AccessFlagBits2::eNone,
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
.oldLayout = vk::ImageLayout::eUndefined, .oldLayout = vk::ImageLayout::eUndefined,
.newLayout = vk::ImageLayout::eColorAttachmentOptimal, .newLayout = vk::ImageLayout::eColorAttachmentOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family, .srcQueueFamilyIndex = queueAllocation.m_Family,
.dstQueueFamilyIndex = queueAllocation.m_Family, .dstQueueFamilyIndex = queueAllocation.m_Family,
.subresourceRange = subresourceRange, .subresourceRange = subresourceRange,
}; };
vk::ImageMemoryBarrier renderToTransferSrcBarrier = { vk::DependencyInfo preRenderDependencies = {
.imageMemoryBarrierCount = 1,
.pImageMemoryBarriers = &preRenderBarrier,
};
vk::ImageMemoryBarrier2 renderToBlitBarrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal, .oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
.newLayout = vk::ImageLayout::eTransferSrcOptimal, .newLayout = vk::ImageLayout::eTransferSrcOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family, .srcQueueFamilyIndex = queueAllocation.m_Family,
.dstQueueFamilyIndex = queueAllocation.m_Family, .dstQueueFamilyIndex = queueAllocation.m_Family,
.subresourceRange = subresourceRange, .subresourceRange = subresourceRange,
}; };
vk::ImageMemoryBarrier acquireToTransferDstBarrier = { vk::ImageMemoryBarrier2 acquireToTransferDstBarrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe,
.srcAccessMask = vk::AccessFlagBits2::eNone,
.dstStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
.oldLayout = vk::ImageLayout::eUndefined, .oldLayout = vk::ImageLayout::eUndefined,
.newLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family, .srcQueueFamilyIndex = queueAllocation.m_Family,
@ -185,16 +211,45 @@ main(int, char **)
.subresourceRange = subresourceRange, .subresourceRange = subresourceRange,
}; };
eastl::array postRenderBarriers = { eastl::array postRenderBarriers = {
renderToTransferSrcBarrier, renderToBlitBarrier,
acquireToTransferDstBarrier, acquireToTransferDstBarrier,
}; };
vk::ImageMemoryBarrier transferDstToPresentBarrier = { vk::DependencyInfo postRenderDependencies = {
.imageMemoryBarrierCount = Cast<u32>(postRenderBarriers.size()),
.pImageMemoryBarriers = postRenderBarriers.data(),
};
vk::ImageMemoryBarrier2 transferDstToGuiRenderBarrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eAllTransfer,
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
.oldLayout = vk::ImageLayout::eTransferDstOptimal, .oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family,
.dstQueueFamilyIndex = queueAllocation.m_Family,
.subresourceRange = subresourceRange,
};
vk::DependencyInfo preGuiDependencies = {
.imageMemoryBarrierCount = 1,
.pImageMemoryBarriers = &transferDstToGuiRenderBarrier,
};
vk::ImageMemoryBarrier2 prePresentBarrier = {
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
.dstAccessMask = vk::AccessFlagBits2::eNone,
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
.newLayout = vk::ImageLayout::ePresentSrcKHR, .newLayout = vk::ImageLayout::ePresentSrcKHR,
.srcQueueFamilyIndex = queueAllocation.m_Family, .srcQueueFamilyIndex = queueAllocation.m_Family,
.dstQueueFamilyIndex = queueAllocation.m_Family, .dstQueueFamilyIndex = queueAllocation.m_Family,
.subresourceRange = subresourceRange, .subresourceRange = subresourceRange,
}; };
vk::DependencyInfo prePresentDependencies = {
.imageMemoryBarrierCount = 1,
.pImageMemoryBarriers = &prePresentBarrier,
};
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT}; FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight); eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight);
@ -205,19 +260,20 @@ main(int, char **)
for (u32 index = 0; index < frameManager.m_FramesInFlight; ++index) for (u32 index = 0; index < frameManager.m_FramesInFlight; ++index)
{ {
auto name = fmt::format("Depth Frame{}", index); auto name = fmt::format("Depth Frame{}", index);
depthIter->Init(&device, swapchain.m_Extent, name.c_str()); depthIter->Init(&device, internalResolution, name.c_str());
name = fmt::format("Attachment0 Frame{}", index); name = fmt::format("Attachment0 Frame{}", index);
attachmentIter->Init(&device, swapchain.m_Extent, attachmentFormat, name.c_str()); attachmentIter->Init(&device, internalResolution, attachmentFormat, name.c_str());
++depthIter; ++depthIter;
++attachmentIter; ++attachmentIter;
} }
} }
gui::Init(&context, &device, &window, attachmentFormat, frameManager.m_FramesInFlight, queueAllocation.m_Family, gui::Init(&context, &device, &window, swapchain.m_Format, Cast<u32>(swapchain.m_ImageViews.size()),
commandQueue); queueAllocation.m_Family, commandQueue);
bool rotating = false; bool rotating = false;
i32 currentInternalResolution[2] = {Cast<i32>(internalResolution.width), Cast<i32>(internalResolution.height)};
Time::Init(); Time::Init();
@ -229,6 +285,31 @@ main(int, char **)
gui::StartBuild(); gui::StartBuild();
gui::Begin("Settings"); gui::Begin("Settings");
gui::Text("Window Resolution: %udx%ud", swapchain.m_Extent.width, swapchain.m_Extent.height);
gui::Text("FrameBuffer Resolution %dx%d", currentInternalResolution[0], currentInternalResolution[1]);
gui::InputInt("FrameBuffer Height", &currentInternalResolution[1], 1, 10);
camera.m_AspectRatio = Cast<f32>(swapchain.m_Extent.width) / Cast<f32>(swapchain.m_Extent.height);
currentInternalResolution[0] = Cast<i32>(camera.m_AspectRatio * currentInternalResolution[1]);
for (i32 &val : currentInternalResolution)
{
val = eastl::clamp(val, 64, 7680);
}
camera.m_Perspective = glm::perspective(70_deg, camera.m_AspectRatio, 0.1f, 100.0f);
if (gui::Button("Change Resolution"))
{
if (currentInternalResolution[0] != internalResolution.width ||
currentInternalResolution[1] != internalResolution.height)
{
internalResolution =
vk::Extent2D{}.setWidth(currentInternalResolution[0]).setHeight(currentInternalResolution[1]);
viewport.width = Cast<f32>(internalResolution.width);
viewport.height = -Cast<f32>(internalResolution.height);
viewport.y = Cast<f32>(internalResolution.height);
scissor.extent = internalResolution;
}
}
gui::Text("Delta: %0.6f ms", 1000.0f * Time::m_Delta); gui::Text("Delta: %0.6f ms", 1000.0f * Time::m_Delta);
gui::Text("FPS: %0.6f", 1.0f / Time::m_Delta); gui::Text("FPS: %0.6f", 1.0f / Time::m_Delta);
gui::Checkbox("Rotate", &rotating); gui::Checkbox("Rotate", &rotating);
@ -252,23 +333,38 @@ main(int, char **)
u32 imageIndex = currentFrame->m_ImageIdx; u32 imageIndex = currentFrame->m_ImageIdx;
vk::Image currentSwapchainImage = swapchain.m_Images[imageIndex]; vk::Image currentSwapchainImage = swapchain.m_Images[imageIndex];
vk::ImageView currentSwapchainImageView = swapchain.m_ImageViews[imageIndex];
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer; vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx].m_View;
AttachmentImage *currentAttachment = &attachmentImages[currentFrame->m_ImageIdx]; DepthImage *currentDepthImage = &depthImages[currentFrame->m_FrameIdx];
AttachmentImage *currentAttachment = &attachmentImages[currentFrame->m_FrameIdx];
if (currentAttachment->m_Extent.width != internalResolution.width ||
currentAttachment->m_Extent.height != internalResolution.height)
{
auto name = fmt::format("Depth Frame{}", currentFrame->m_FrameIdx);
currentDepthImage->Destroy(&device);
currentDepthImage->Init(&device, internalResolution, name.c_str());
name = fmt::format("Attachment0 Frame{}", currentFrame->m_FrameIdx);
currentAttachment->Destroy(&device);
currentAttachment->Init(&device, internalResolution, attachmentFormat, name.c_str());
}
vk::ImageView currentDepthImageView = currentDepthImage->m_View;
vk::Image currentImage = currentAttachment->m_Image; vk::Image currentImage = currentAttachment->m_Image;
vk::ImageView currentImageView = currentAttachment->m_View; vk::ImageView currentImageView = currentAttachment->m_View;
topOfThePipeBarrier.image = currentImage; preRenderBarrier.image = currentImage;
postRenderBarriers[0].image = currentImage; postRenderBarriers[0].image = currentImage;
postRenderBarriers[1].image = currentSwapchainImage; postRenderBarriers[1].image = currentSwapchainImage;
transferDstToPresentBarrier.image = currentSwapchainImage; transferDstToGuiRenderBarrier.image = currentSwapchainImage;
prePresentBarrier.image = currentSwapchainImage;
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
AbortIfFailed(cmd.begin(&beginInfo)); AbortIfFailed(cmd.begin(&beginInfo));
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput, cmd.pipelineBarrier2(&preRenderDependencies);
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
// Render // Render
eastl::array attachmentInfos = { eastl::array attachmentInfos = {
@ -332,11 +428,7 @@ main(int, char **)
cmd.endRendering(); cmd.endRendering();
gui::Draw(cmd, currentAttachment); cmd.pipelineBarrier2(&postRenderDependencies);
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eAllCommands,
{}, 0, nullptr, 0, nullptr, Cast<u32>(postRenderBarriers.size()),
postRenderBarriers.data());
vk::ImageBlit blitRegion = { vk::ImageBlit blitRegion = {
.srcSubresource = .srcSubresource =
@ -367,8 +459,11 @@ main(int, char **)
cmd.blitImage(currentImage, postRenderBarriers[0].newLayout, currentSwapchainImage, cmd.blitImage(currentImage, postRenderBarriers[0].newLayout, currentSwapchainImage,
postRenderBarriers[1].newLayout, 1, &blitRegion, vk::Filter::eLinear); postRenderBarriers[1].newLayout, 1, &blitRegion, vk::Filter::eLinear);
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands, {}, 0, cmd.pipelineBarrier2(&preGuiDependencies);
nullptr, 0, nullptr, 1, &transferDstToPresentBarrier);
gui::Draw(cmd, swapchain.m_Extent, currentSwapchainImageView);
cmd.pipelineBarrier2(&prePresentDependencies);
AbortIfFailed(cmd.end()); AbortIfFailed(cmd.end());