Separate frame-work from presentation

This commit is contained in:
Wunkolo 2023-07-27 07:32:10 -07:00
parent 4976671ef0
commit d19b8cf364
2 changed files with 103 additions and 101 deletions

View file

@ -10,7 +10,7 @@ class RendererVK final : public Renderer {
vk::UniqueInstance instance = {}; vk::UniqueInstance instance = {};
vk::UniqueDebugUtilsMessengerEXT debugMessenger = {}; vk::UniqueDebugUtilsMessengerEXT debugMessenger = {};
vk::SurfaceKHR surface = {}; vk::SurfaceKHR swapchainSurface = {};
vk::PhysicalDevice physicalDevice = {}; vk::PhysicalDevice physicalDevice = {};

View file

@ -167,7 +167,7 @@ RendererVK::~RendererVK() {}
void RendererVK::reset() {} void RendererVK::reset() {}
void RendererVK::display() { void RendererVK::display() {
// Block, on the CPU, to ensure that this frame-buffering-frame is ready for more work // Block, on the CPU, to ensure that this buffered-frame is ready for more work
if (auto waitResult = device->waitForFences({frameFinishedFences[frameBufferingIndex].get()}, true, std::numeric_limits<u64>::max()); if (auto waitResult = device->waitForFences({frameFinishedFences[frameBufferingIndex].get()}, true, std::numeric_limits<u64>::max());
waitResult != vk::Result::eSuccess) { waitResult != vk::Result::eSuccess) {
Helpers::panic("Error waiting on swapchain fence: %s\n", vk::to_string(waitResult).c_str()); Helpers::panic("Error waiting on swapchain fence: %s\n", vk::to_string(waitResult).c_str());
@ -198,7 +198,7 @@ void RendererVK::display() {
swapchainExtent.width = windowWidth; swapchainExtent.width = windowWidth;
swapchainExtent.height = windowHeight; swapchainExtent.height = windowHeight;
} }
recreateSwapchain(surface, swapchainExtent); recreateSwapchain(swapchainSurface, swapchainExtent);
break; break;
} }
default: { default: {
@ -208,7 +208,7 @@ void RendererVK::display() {
} }
} }
vk::UniqueCommandBuffer& frameCommandBuffer = frameCommandBuffers.at(frameBufferingIndex); const vk::UniqueCommandBuffer& frameCommandBuffer = frameCommandBuffers[frameBufferingIndex];
vk::CommandBufferBeginInfo beginInfo = {}; vk::CommandBufferBeginInfo beginInfo = {};
beginInfo.flags = vk::CommandBufferUsageFlagBits::eSimultaneousUse; beginInfo.flags = vk::CommandBufferUsageFlagBits::eSimultaneousUse;
@ -217,100 +217,102 @@ void RendererVK::display() {
Helpers::panic("Error beginning command buffer recording: %s\n", vk::to_string(beginResult).c_str()); Helpers::panic("Error beginning command buffer recording: %s\n", vk::to_string(beginResult).c_str());
} }
//// Render Frame(Simulated - just clear the images to different colors for now)
{ {
static const std::array<float, 4> frameScopeColor = {{1.0f, 0.0f, 1.0f, 1.0f}}; static const std::array<float, 4> frameScopeColor = {{1.0f, 0.0f, 1.0f, 1.0f}};
Vulkan::DebugLabelScope debugScope(frameCommandBuffer.get(), frameScopeColor, "Frame"); Vulkan::DebugLabelScope debugScope(frameCommandBuffer.get(), frameScopeColor, "Frame");
if (swapchainImageIndex != swapchainImageInvalid) { // Prepare images for color-clear
// Prepare images for color-clear frameCommandBuffer->pipelineBarrier(
frameCommandBuffer->pipelineBarrier( vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags(), {}, {},
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags(), {}, {}, {
{ vk::ImageMemoryBarrier(
vk::ImageMemoryBarrier( vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined,
vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, swapchainImages[swapchainImageIndex], topScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1) ),
), vk::ImageMemoryBarrier(
vk::ImageMemoryBarrier( vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined,
vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, bottomScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
topScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1) ),
), }
vk::ImageMemoryBarrier( );
vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined, static const std::array<float, 4> topClearColor = {{1.0f, 0.0f, 0.0f, 1.0f}};
vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, static const std::array<float, 4> bottomClearColor = {{0.0f, 1.0f, 0.0f, 1.0f}};
bottomScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1) frameCommandBuffer->clearColorImage(
), topScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferDstOptimal, topClearColor,
} vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
); );
frameCommandBuffer->clearColorImage(
bottomScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferDstOptimal, bottomClearColor,
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
);
}
static const std::array<float, 4> clearColor = {{0.0f, 0.0f, 0.0f, 1.0f}}; //// Present
frameCommandBuffer->clearColorImage( if (swapchainImageIndex != swapchainImageInvalid) {
swapchainImages[swapchainImageIndex], vk::ImageLayout::eTransferDstOptimal, clearColor, static const std::array<float, 4> presentScopeColor = {{1.0f, 1.0f, 0.0f, 1.0f}};
Vulkan::DebugLabelScope debugScope(frameCommandBuffer.get(), presentScopeColor, "Present");
// Prepare swapchain image for color-clear/blit-dst, prepare top/bottom screen for blit-src
frameCommandBuffer->pipelineBarrier(
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags(), {}, {},
{
vk::ImageMemoryBarrier(
vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined,
vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, swapchainImages[swapchainImageIndex],
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
),
vk::ImageMemoryBarrier(
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eTransferSrcOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
topScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
),
vk::ImageMemoryBarrier(
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eTransferSrcOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
bottomScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
),
}
);
static const std::array<float, 4> clearColor = {{0.0f, 0.0f, 0.0f, 1.0f}};
frameCommandBuffer->clearColorImage(
swapchainImages[swapchainImageIndex], vk::ImageLayout::eTransferDstOptimal, clearColor,
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
);
// Blit top/bottom screen into swapchain image
static const vk::ImageBlit topScreenBlit(
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), {vk::Offset3D{}, vk::Offset3D{400, 240, 1}},
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), {vk::Offset3D{}, vk::Offset3D{400, 240, 1}}
);
static const vk::ImageBlit bottomScreenBlit(
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), {vk::Offset3D{}, vk::Offset3D{320, 240, 1}},
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1),
{vk::Offset3D{(400 / 2) - (320 / 2), 240, 0}, vk::Offset3D{(400 / 2) + (320 / 2), 240 + 240, 1}}
);
frameCommandBuffer->blitImage(
topScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferSrcOptimal, swapchainImages[swapchainImageIndex],
vk::ImageLayout::eTransferDstOptimal, {topScreenBlit}, vk::Filter::eNearest
);
frameCommandBuffer->blitImage(
bottomScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferSrcOptimal, swapchainImages[swapchainImageIndex],
vk::ImageLayout::eTransferDstOptimal, {bottomScreenBlit}, vk::Filter::eNearest
);
// Prepare swapchain image for present
frameCommandBuffer->pipelineBarrier(
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::DependencyFlags(), {}, {},
{vk::ImageMemoryBarrier(
vk::AccessFlagBits::eNone, vk::AccessFlagBits::eColorAttachmentWrite, vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::ePresentSrcKHR, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, swapchainImages[swapchainImageIndex],
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1) vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
); )}
);
//// Simulated rendering work, just clear the screens and get them ready to blit(transfer-src layout)
{
static const std::array<float, 4> topClearColor = {{1.0f, 0.0f, 0.0f, 1.0f}};
static const std::array<float, 4> bottomClearColor = {{0.0f, 1.0f, 0.0f, 1.0f}};
frameCommandBuffer->clearColorImage(
topScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferDstOptimal, topClearColor,
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
);
frameCommandBuffer->clearColorImage(
bottomScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferDstOptimal, bottomClearColor,
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
);
frameCommandBuffer->pipelineBarrier(
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags(), {}, {},
{
vk::ImageMemoryBarrier(
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eTransferSrcOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
topScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
),
vk::ImageMemoryBarrier(
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eTransferSrcOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
bottomScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
),
}
);
}
// Blip top/bottom screen onto swapchain image
{
static const vk::ImageBlit topScreenBlit(
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), {vk::Offset3D{}, vk::Offset3D{400, 240, 1}},
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), {vk::Offset3D{}, vk::Offset3D{400, 240, 1}}
);
static const vk::ImageBlit bottomScreenBlit(
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), {vk::Offset3D{}, vk::Offset3D{320, 240, 1}},
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1),
{vk::Offset3D{(400 / 2) - (320 / 2), 240, 0}, vk::Offset3D{(400 / 2) + (320 / 2), 240 + 240, 1}}
);
frameCommandBuffer->blitImage(
topScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferSrcOptimal, swapchainImages[swapchainImageIndex],
vk::ImageLayout::eTransferDstOptimal, {topScreenBlit}, vk::Filter::eNearest
);
frameCommandBuffer->blitImage(
bottomScreenImages[frameBufferingIndex].get(), vk::ImageLayout::eTransferSrcOptimal, swapchainImages[swapchainImageIndex],
vk::ImageLayout::eTransferDstOptimal, {bottomScreenBlit}, vk::Filter::eNearest
);
}
// Prepare for present
frameCommandBuffer->pipelineBarrier(
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::DependencyFlags(), {}, {},
{vk::ImageMemoryBarrier(
vk::AccessFlagBits::eNone, vk::AccessFlagBits::eColorAttachmentWrite, vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::ePresentSrcKHR, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, swapchainImages[swapchainImageIndex],
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
)}
);
}
} }
if (const vk::Result endResult = frameCommandBuffer->end(); endResult != vk::Result::eSuccess) { if (const vk::Result endResult = frameCommandBuffer->end(); endResult != vk::Result::eSuccess) {
@ -355,7 +357,7 @@ void RendererVK::display() {
swapchainExtent.width = windowWidth; swapchainExtent.width = windowWidth;
swapchainExtent.height = windowHeight; swapchainExtent.height = windowHeight;
} }
recreateSwapchain(surface, swapchainExtent); recreateSwapchain(swapchainSurface, swapchainExtent);
break; break;
} }
default: { default: {
@ -444,7 +446,7 @@ void RendererVK::initGraphicsContext(SDL_Window* window) {
// Create surface // Create surface
if (window) { if (window) {
if (VkSurfaceKHR newSurface; SDL_Vulkan_CreateSurface(window, instance.get(), &newSurface)) { if (VkSurfaceKHR newSurface; SDL_Vulkan_CreateSurface(window, instance.get(), &newSurface)) {
surface = newSurface; swapchainSurface = newSurface;
} else { } else {
Helpers::warn("Error creating Vulkan surface"); Helpers::warn("Error creating Vulkan surface");
} }
@ -456,11 +458,12 @@ void RendererVK::initGraphicsContext(SDL_Window* window) {
std::vector<vk::PhysicalDevice>::iterator partitionEnd = physicalDevices.end(); std::vector<vk::PhysicalDevice>::iterator partitionEnd = physicalDevices.end();
// Prefer GPUs that can access the surface // Prefer GPUs that can access the surface
if (surface) { if (swapchainSurface) {
const auto surfaceSupport = [this](const vk::PhysicalDevice& physicalDevice) -> bool { const auto surfaceSupport = [this](const vk::PhysicalDevice& physicalDevice) -> bool {
const usize queueCount = physicalDevice.getQueueFamilyProperties().size(); const usize queueCount = physicalDevice.getQueueFamilyProperties().size();
for (usize queueIndex = 0; queueIndex < queueCount; ++queueIndex) { for (usize queueIndex = 0; queueIndex < queueCount; ++queueIndex) {
if (auto supportResult = physicalDevice.getSurfaceSupportKHR(queueIndex, surface); supportResult.result == vk::Result::eSuccess) { if (auto supportResult = physicalDevice.getSurfaceSupportKHR(queueIndex, swapchainSurface);
supportResult.result == vk::Result::eSuccess) {
return supportResult.value; return supportResult.value;
} }
} }
@ -490,9 +493,9 @@ void RendererVK::initGraphicsContext(SDL_Window* window) {
const std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties(); const std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties();
std::unordered_set<u32> queueFamilyRequests; std::unordered_set<u32> queueFamilyRequests;
// Get present queue family // Get present queue family
if (surface) { if (swapchainSurface) {
for (usize queueFamilyIndex = 0; queueFamilyIndex < queueFamilyProperties.size(); ++queueFamilyIndex) { for (usize queueFamilyIndex = 0; queueFamilyIndex < queueFamilyProperties.size(); ++queueFamilyIndex) {
if (auto supportResult = physicalDevice.getSurfaceSupportKHR(queueFamilyIndex, surface); if (auto supportResult = physicalDevice.getSurfaceSupportKHR(queueFamilyIndex, swapchainSurface);
supportResult.result == vk::Result::eSuccess) { supportResult.result == vk::Result::eSuccess) {
if (supportResult.value) { if (supportResult.value) {
presentQueueFamily = queueFamilyIndex; presentQueueFamily = queueFamilyIndex;
@ -584,7 +587,7 @@ void RendererVK::initGraphicsContext(SDL_Window* window) {
} }
// Create swapchain // Create swapchain
if (targetWindow && surface) { if (targetWindow && swapchainSurface) {
vk::Extent2D swapchainExtent; vk::Extent2D swapchainExtent;
{ {
int windowWidth, windowHeight; int windowWidth, windowHeight;
@ -592,7 +595,7 @@ void RendererVK::initGraphicsContext(SDL_Window* window) {
swapchainExtent.width = windowWidth; swapchainExtent.width = windowWidth;
swapchainExtent.height = windowHeight; swapchainExtent.height = windowHeight;
} }
recreateSwapchain(surface, swapchainExtent); recreateSwapchain(swapchainSurface, swapchainExtent);
} }
// Create frame-buffering data // Create frame-buffering data
@ -623,7 +626,7 @@ void RendererVK::initGraphicsContext(SDL_Window* window) {
topScreenInfo.setFormat(vk::Format::eR8G8B8A8Unorm); topScreenInfo.setFormat(vk::Format::eR8G8B8A8Unorm);
topScreenInfo.setExtent(vk::Extent3D(400, 240, 1)); topScreenInfo.setExtent(vk::Extent3D(400, 240, 1));
topScreenInfo.setMipLevels(1); topScreenInfo.setMipLevels(1);
topScreenInfo.setArrayLayers(2); // Two image layers, for 3D mode topScreenInfo.setArrayLayers(1);
topScreenInfo.setSamples(vk::SampleCountFlagBits::e1); topScreenInfo.setSamples(vk::SampleCountFlagBits::e1);
topScreenInfo.setTiling(vk::ImageTiling::eOptimal); topScreenInfo.setTiling(vk::ImageTiling::eOptimal);
topScreenInfo.setUsage( topScreenInfo.setUsage(
@ -635,7 +638,6 @@ void RendererVK::initGraphicsContext(SDL_Window* window) {
vk::ImageCreateInfo bottomScreenInfo = topScreenInfo; vk::ImageCreateInfo bottomScreenInfo = topScreenInfo;
bottomScreenInfo.setExtent(vk::Extent3D(320, 240, 1)); bottomScreenInfo.setExtent(vk::Extent3D(320, 240, 1));
bottomScreenInfo.setArrayLayers(1);
topScreenImages.resize(frameBufferingCount); topScreenImages.resize(frameBufferingCount);
bottomScreenImages.resize(frameBufferingCount); bottomScreenImages.resize(frameBufferingCount);