mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-22 05:15:51 +12:00
Allocate and present separate top/bottom screen framebuffer images
Instead of operating directly on the swapchain images, we have our own top/bottom framebuffer images that will be rendered to independent of having an available swapchain. The images are blitted into the swapchain images, allowing for resizing too!
This commit is contained in:
parent
d0832ca558
commit
e3699fe8f8
5 changed files with 354 additions and 15 deletions
|
@ -1,12 +1,14 @@
|
|||
#include "renderer_vk/renderer_vk.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <ranges>
|
||||
#include <span>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "SDL_vulkan.h"
|
||||
#include "helpers.hpp"
|
||||
#include "renderer_vk/vk_debug.hpp"
|
||||
#include "renderer_vk/vk_memory.hpp"
|
||||
|
||||
// Finds the first queue family that satisfies `queueMask` and excludes `queueExcludeMask` bits
|
||||
// Returns -1 if not found
|
||||
|
@ -221,15 +223,27 @@ void RendererVK::display() {
|
|||
|
||||
Vulkan::DebugLabelScope debugScope(frameCommandBuffer.get(), frameScopeColor, "Frame");
|
||||
|
||||
// Prepare for color-clear
|
||||
if (swapchainImageIndex != swapchainImageInvalid) {
|
||||
// Prepare images for color-clear
|
||||
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::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::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eTransferDstOptimal, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
topScreenImages[frameBufferingIndex].get(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)
|
||||
),
|
||||
vk::ImageMemoryBarrier(
|
||||
vk::AccessFlagBits::eMemoryRead, vk::AccessFlagBits::eTransferWrite, vk::ImageLayout::eUndefined,
|
||||
vk::ImageLayout::eTransferDstOptimal, 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}};
|
||||
|
@ -238,6 +252,56 @@ void RendererVK::display() {
|
|||
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(), {}, {},
|
||||
|
@ -555,14 +619,74 @@ void RendererVK::initGraphicsContext(SDL_Window* window) {
|
|||
swapImageFreeSemaphore.resize(frameBufferingCount);
|
||||
renderFinishedSemaphore.resize(frameBufferingCount);
|
||||
frameFinishedFences.resize(frameBufferingCount);
|
||||
vk::Extent2D swapchainExtent;
|
||||
{
|
||||
int windowWidth, windowHeight;
|
||||
SDL_Vulkan_GetDrawableSize(window, &windowWidth, &windowHeight);
|
||||
swapchainExtent.width = windowWidth;
|
||||
swapchainExtent.height = windowHeight;
|
||||
|
||||
vk::ImageCreateInfo topScreenInfo = {};
|
||||
topScreenInfo.setImageType(vk::ImageType::e2D);
|
||||
topScreenInfo.setFormat(vk::Format::eR8G8B8A8Unorm);
|
||||
topScreenInfo.setExtent(vk::Extent3D(400, 240, 1));
|
||||
topScreenInfo.setMipLevels(1);
|
||||
topScreenInfo.setArrayLayers(2); // Two image layers, for 3D mode
|
||||
topScreenInfo.setSamples(vk::SampleCountFlagBits::e1);
|
||||
topScreenInfo.setTiling(vk::ImageTiling::eOptimal);
|
||||
topScreenInfo.setUsage(
|
||||
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eInputAttachment | vk::ImageUsageFlagBits::eTransferSrc |
|
||||
vk::ImageUsageFlagBits::eTransferDst
|
||||
);
|
||||
topScreenInfo.setSharingMode(vk::SharingMode::eExclusive);
|
||||
topScreenInfo.setInitialLayout(vk::ImageLayout::eUndefined);
|
||||
|
||||
vk::ImageCreateInfo bottomScreenInfo = topScreenInfo;
|
||||
bottomScreenInfo.setExtent(vk::Extent3D(320, 240, 1));
|
||||
bottomScreenInfo.setArrayLayers(1);
|
||||
|
||||
topScreenImages.resize(frameBufferingCount);
|
||||
bottomScreenImages.resize(frameBufferingCount);
|
||||
|
||||
for (usize i = 0; i < frameBufferingCount; i++) {
|
||||
if (auto createResult = device->createSemaphoreUnique(semaphoreInfo); createResult.result == vk::Result::eSuccess) {
|
||||
swapImageFreeSemaphore[i] = std::move(createResult.value);
|
||||
} else {
|
||||
Helpers::panic("Error creating 'present-ready' semaphore: %s\n", vk::to_string(createResult.result).c_str());
|
||||
}
|
||||
|
||||
if (auto createResult = device->createSemaphoreUnique(semaphoreInfo); createResult.result == vk::Result::eSuccess) {
|
||||
renderFinishedSemaphore[i] = std::move(createResult.value);
|
||||
} else {
|
||||
Helpers::panic("Error creating 'post-render' semaphore: %s\n", vk::to_string(createResult.result).c_str());
|
||||
}
|
||||
|
||||
if (auto createResult = device->createFenceUnique(fenceInfo); createResult.result == vk::Result::eSuccess) {
|
||||
frameFinishedFences[i] = std::move(createResult.value);
|
||||
} else {
|
||||
Helpers::panic("Error creating 'present-ready' semaphore: %s\n", vk::to_string(createResult.result).c_str());
|
||||
}
|
||||
|
||||
if (auto createResult = device->createImageUnique(topScreenInfo); createResult.result == vk::Result::eSuccess) {
|
||||
topScreenImages[i] = std::move(createResult.value);
|
||||
} else {
|
||||
Helpers::panic("Error creating top-screen image: %s\n", vk::to_string(createResult.result).c_str());
|
||||
}
|
||||
|
||||
if (auto createResult = device->createImageUnique(bottomScreenInfo); createResult.result == vk::Result::eSuccess) {
|
||||
bottomScreenImages[i] = std::move(createResult.value);
|
||||
} else {
|
||||
Helpers::panic("Error creating bottom-screen image: %s\n", vk::to_string(createResult.result).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Commit memory to all of our images
|
||||
{
|
||||
const auto getImage = [](const vk::UniqueImage& image) -> vk::Image { return image.get(); };
|
||||
std::vector<vk::Image> images;
|
||||
std::ranges::transform(topScreenImages, std::back_inserter(images), getImage);
|
||||
std::ranges::transform(bottomScreenImages, std::back_inserter(images), getImage);
|
||||
|
||||
if (auto [result, imageMemory] = Vulkan::commitImageHeap(device.get(), physicalDevice, images); result == vk::Result::eSuccess) {
|
||||
framebufferMemory = std::move(imageMemory);
|
||||
} else {
|
||||
Helpers::panic("Error allocating framebuffer memory: %s\n", vk::to_string(result).c_str());
|
||||
}
|
||||
}
|
||||
recreateSwapchain(surface.get(), swapchainExtent);
|
||||
}
|
||||
|
||||
void RendererVK::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue