early-access version 3531

This commit is contained in:
pineappleEA 2023-04-24 14:40:50 +02:00
parent b31b4e3caa
commit 3549556abe
13 changed files with 209 additions and 223 deletions

View File

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 3528. This is the source code for early-access 3531.
## Legal Notice ## Legal Notice

View File

@ -179,6 +179,8 @@ add_library(video_core STATIC
renderer_vulkan/vk_master_semaphore.h renderer_vulkan/vk_master_semaphore.h
renderer_vulkan/vk_pipeline_cache.cpp renderer_vulkan/vk_pipeline_cache.cpp
renderer_vulkan/vk_pipeline_cache.h renderer_vulkan/vk_pipeline_cache.h
renderer_vulkan/vk_present_manager.cpp
renderer_vulkan/vk_present_manager.h
renderer_vulkan/vk_query_cache.cpp renderer_vulkan/vk_query_cache.cpp
renderer_vulkan/vk_query_cache.h renderer_vulkan/vk_query_cache.h
renderer_vulkan/vk_rasterizer.cpp renderer_vulkan/vk_rasterizer.cpp

View File

@ -423,7 +423,8 @@ public:
} }
/// Binds a counter to this query. /// Binds a counter to this query.
std::optional<u64> BindCounter(std::shared_ptr<HostCounter> counter_, std::optional<u64> timestamp_) { std::optional<u64> BindCounter(std::shared_ptr<HostCounter> counter_,
std::optional<u64> timestamp_) {
std::optional<u64> result{}; std::optional<u64> result{};
if (counter) { if (counter) {
// If there's an old counter set it means the query is being rewritten by the game. // If there's an old counter set it means the query is being rewritten by the game.

View File

@ -93,8 +93,9 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
state_tracker(), scheduler(device, state_tracker), state_tracker(), scheduler(device, state_tracker),
swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
render_window.GetFramebufferLayout().height, false), render_window.GetFramebufferLayout().height, false),
blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler, present_manager(render_window, device, memory_allocator, scheduler, swapchain),
screen_info), blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager,
scheduler, screen_info),
rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator, rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator,
state_tracker, scheduler) { state_tracker, scheduler) {
if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) { if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
@ -121,46 +122,19 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
return; return;
} }
// Update screen info if the framebuffer size has changed. // Update screen info if the framebuffer size has changed.
if (screen_info.width != framebuffer->width || screen_info.height != framebuffer->height) { screen_info.width = framebuffer->width;
screen_info.width = framebuffer->width; screen_info.height = framebuffer->height;
screen_info.height = framebuffer->height;
}
const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset;
const bool use_accelerated = const bool use_accelerated =
rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride);
const bool is_srgb = use_accelerated && screen_info.is_srgb; const bool is_srgb = use_accelerated && screen_info.is_srgb;
RenderScreenshot(*framebuffer, use_accelerated); RenderScreenshot(*framebuffer, use_accelerated);
bool has_been_recreated = false; Frame* frame = present_manager.GetRenderFrame();
const auto recreate_swapchain = [&](u32 width, u32 height) { blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb);
if (!has_been_recreated) { scheduler.Flush(*frame->render_ready);
has_been_recreated = true; scheduler.Record([this, frame](vk::CommandBuffer) { present_manager.PushFrame(frame); });
scheduler.Finish();
}
swapchain.Create(width, height, is_srgb);
};
const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
if (swapchain.NeedsRecreation(is_srgb) || swapchain.GetWidth() != layout.width ||
swapchain.GetHeight() != layout.height) {
recreate_swapchain(layout.width, layout.height);
}
bool is_outdated;
do {
swapchain.AcquireNextImage();
is_outdated = swapchain.IsOutDated();
if (is_outdated) {
recreate_swapchain(layout.width, layout.height);
}
} while (is_outdated);
if (has_been_recreated) {
blit_screen.Recreate();
}
const VkSemaphore render_semaphore = blit_screen.DrawToSwapchain(*framebuffer, use_accelerated);
const VkSemaphore present_semaphore = swapchain.CurrentPresentSemaphore();
scheduler.Flush(render_semaphore, present_semaphore);
scheduler.WaitWorker();
swapchain.Present(render_semaphore);
gpu.RendererFrameEndNotify(); gpu.RendererFrameEndNotify();
rasterizer.TickFrame(); rasterizer.TickFrame();
@ -246,8 +220,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
}); });
const VkExtent2D render_area{.width = layout.width, .height = layout.height}; const VkExtent2D render_area{.width = layout.width, .height = layout.height};
const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area); const vk::Framebuffer screenshot_fb = blit_screen.CreateFramebuffer(*dst_view, render_area);
// Since we're not rendering to the screen, ignore the render semaphore. blit_screen.Draw(framebuffer, *screenshot_fb, layout, render_area, use_accelerated);
void(blit_screen.Draw(framebuffer, *screenshot_fb, layout, render_area, use_accelerated));
const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4); const auto buffer_size = static_cast<VkDeviceSize>(layout.width * layout.height * 4);
const VkBufferCreateInfo dst_buffer_info{ const VkBufferCreateInfo dst_buffer_info{
@ -270,7 +243,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
.pNext = nullptr, .pNext = nullptr,
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,

View File

@ -9,6 +9,7 @@
#include "common/dynamic_library.h" #include "common/dynamic_library.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/vk_blit_screen.h" #include "video_core/renderer_vulkan/vk_blit_screen.h"
#include "video_core/renderer_vulkan/vk_present_manager.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_state_tracker.h"
@ -76,6 +77,7 @@ private:
StateTracker state_tracker; StateTracker state_tracker;
Scheduler scheduler; Scheduler scheduler;
Swapchain swapchain; Swapchain swapchain;
PresentManager present_manager;
BlitScreen blit_screen; BlitScreen blit_screen;
RasterizerVulkan rasterizer; RasterizerVulkan rasterizer;
std::optional<TurboMode> turbo_mode; std::optional<TurboMode> turbo_mode;

View File

@ -122,10 +122,12 @@ struct BlitScreen::BufferData {
BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWindow& render_window_, BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWindow& render_window_,
const Device& device_, MemoryAllocator& memory_allocator_, const Device& device_, MemoryAllocator& memory_allocator_,
Swapchain& swapchain_, Scheduler& scheduler_, const ScreenInfo& screen_info_) Swapchain& swapchain_, PresentManager& present_manager_,
Scheduler& scheduler_, const ScreenInfo& screen_info_)
: cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_}, : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_},
memory_allocator{memory_allocator_}, swapchain{swapchain_}, scheduler{scheduler_}, memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_},
image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_},
current_srgb{swapchain.IsSrgb()}, image_view_format{swapchain.GetImageViewFormat()} {
resource_ticks.resize(image_count); resource_ticks.resize(image_count);
CreateStaticResources(); CreateStaticResources();
@ -135,25 +137,20 @@ BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWin
BlitScreen::~BlitScreen() = default; BlitScreen::~BlitScreen() = default;
void BlitScreen::Recreate() { void BlitScreen::Recreate() {
present_manager.WaitPresent();
scheduler.Finish();
device.GetLogical().WaitIdle();
CreateDynamicResources(); CreateDynamicResources();
} }
VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
const VkFramebuffer& host_framebuffer, const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout,
const Layout::FramebufferLayout layout, VkExtent2D render_area, VkExtent2D render_area, bool use_accelerated) {
bool use_accelerated) {
RefreshResources(framebuffer); RefreshResources(framebuffer);
// Finish any pending renderpass // Finish any pending renderpass
scheduler.RequestOutsideRenderPassOperationContext(); scheduler.RequestOutsideRenderPassOperationContext();
if (const auto swapchain_images = swapchain.GetImageCount(); swapchain_images != image_count) {
image_count = swapchain_images;
Recreate();
}
const std::size_t image_index = swapchain.GetImageIndex();
scheduler.Wait(resource_ticks[image_index]); scheduler.Wait(resource_ticks[image_index]);
resource_ticks[image_index] = scheduler.CurrentTick(); resource_ticks[image_index] = scheduler.CurrentTick();
@ -169,7 +166,7 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
std::memcpy(mapped_span.data(), &data, sizeof(data)); std::memcpy(mapped_span.data(), &data, sizeof(data));
if (!use_accelerated) { if (!use_accelerated) {
const u64 image_offset = GetRawImageOffset(framebuffer, image_index); const u64 image_offset = GetRawImageOffset(framebuffer);
const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset; const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset;
const u8* const host_ptr = cpu_memory.GetPointer(framebuffer_addr); const u8* const host_ptr = cpu_memory.GetPointer(framebuffer_addr);
@ -204,8 +201,8 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
.depth = 1, .depth = 1,
}, },
}; };
scheduler.Record([this, copy, image_index](vk::CommandBuffer cmdbuf) { scheduler.Record([this, copy, index = image_index](vk::CommandBuffer cmdbuf) {
const VkImage image = *raw_images[image_index]; const VkImage image = *raw_images[index];
const VkImageMemoryBarrier base_barrier{ const VkImageMemoryBarrier base_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr, .pNext = nullptr,
@ -245,14 +242,15 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
const auto anti_alias_pass = Settings::values.anti_aliasing.GetValue(); const auto anti_alias_pass = Settings::values.anti_aliasing.GetValue();
if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Fxaa) { if (use_accelerated && anti_alias_pass == Settings::AntiAliasing::Fxaa) {
UpdateAADescriptorSet(image_index, source_image_view, false); UpdateAADescriptorSet(source_image_view, false);
const u32 up_scale = Settings::values.resolution_info.up_scale; const u32 up_scale = Settings::values.resolution_info.up_scale;
const u32 down_shift = Settings::values.resolution_info.down_shift; const u32 down_shift = Settings::values.resolution_info.down_shift;
VkExtent2D size{ VkExtent2D size{
.width = (up_scale * framebuffer.width) >> down_shift, .width = (up_scale * framebuffer.width) >> down_shift,
.height = (up_scale * framebuffer.height) >> down_shift, .height = (up_scale * framebuffer.height) >> down_shift,
}; };
scheduler.Record([this, image_index, size, anti_alias_pass](vk::CommandBuffer cmdbuf) { scheduler.Record([this, index = image_index, size,
anti_alias_pass](vk::CommandBuffer cmdbuf) {
const VkImageMemoryBarrier base_barrier{ const VkImageMemoryBarrier base_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr, .pNext = nullptr,
@ -326,7 +324,7 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices));
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline_layout, 0, cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *aa_pipeline_layout, 0,
aa_descriptor_sets[image_index], {}); aa_descriptor_sets[index], {});
cmdbuf.Draw(4, 1, 0, 0); cmdbuf.Draw(4, 1, 0, 0);
cmdbuf.EndRenderPass(); cmdbuf.EndRenderPass();
@ -369,81 +367,99 @@ VkSemaphore BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
}; };
VkImageView fsr_image_view = VkImageView fsr_image_view =
fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect); fsr->Draw(scheduler, image_index, source_image_view, fsr_input_size, crop_rect);
UpdateDescriptorSet(image_index, fsr_image_view, true); UpdateDescriptorSet(fsr_image_view, true);
} else { } else {
const bool is_nn = const bool is_nn =
Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::NearestNeighbor; Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::NearestNeighbor;
UpdateDescriptorSet(image_index, source_image_view, is_nn); UpdateDescriptorSet(source_image_view, is_nn);
} }
scheduler.Record( scheduler.Record([this, host_framebuffer, index = image_index,
[this, host_framebuffer, image_index, size = render_area](vk::CommandBuffer cmdbuf) { size = render_area](vk::CommandBuffer cmdbuf) {
const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f; const f32 bg_red = Settings::values.bg_red.GetValue() / 255.0f;
const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f; const f32 bg_green = Settings::values.bg_green.GetValue() / 255.0f;
const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f; const f32 bg_blue = Settings::values.bg_blue.GetValue() / 255.0f;
const VkClearValue clear_color{ const VkClearValue clear_color{
.color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}}, .color = {.float32 = {bg_red, bg_green, bg_blue, 1.0f}},
}; };
const VkRenderPassBeginInfo renderpass_bi{ const VkRenderPassBeginInfo renderpass_bi{
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.pNext = nullptr, .pNext = nullptr,
.renderPass = *renderpass, .renderPass = *renderpass,
.framebuffer = host_framebuffer, .framebuffer = host_framebuffer,
.renderArea = .renderArea =
{ {
.offset = {0, 0}, .offset = {0, 0},
.extent = size, .extent = size,
}, },
.clearValueCount = 1, .clearValueCount = 1,
.pClearValues = &clear_color, .pClearValues = &clear_color,
}; };
const VkViewport viewport{ const VkViewport viewport{
.x = 0.0f, .x = 0.0f,
.y = 0.0f, .y = 0.0f,
.width = static_cast<float>(size.width), .width = static_cast<float>(size.width),
.height = static_cast<float>(size.height), .height = static_cast<float>(size.height),
.minDepth = 0.0f, .minDepth = 0.0f,
.maxDepth = 1.0f, .maxDepth = 1.0f,
}; };
const VkRect2D scissor{ const VkRect2D scissor{
.offset = {0, 0}, .offset = {0, 0},
.extent = size, .extent = size,
}; };
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE); cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
auto graphics_pipeline = [this]() { auto graphics_pipeline = [this]() {
switch (Settings::values.scaling_filter.GetValue()) { switch (Settings::values.scaling_filter.GetValue()) {
case Settings::ScalingFilter::NearestNeighbor: case Settings::ScalingFilter::NearestNeighbor:
case Settings::ScalingFilter::Bilinear: case Settings::ScalingFilter::Bilinear:
return *bilinear_pipeline; return *bilinear_pipeline;
case Settings::ScalingFilter::Bicubic: case Settings::ScalingFilter::Bicubic:
return *bicubic_pipeline; return *bicubic_pipeline;
case Settings::ScalingFilter::Gaussian: case Settings::ScalingFilter::Gaussian:
return *gaussian_pipeline; return *gaussian_pipeline;
case Settings::ScalingFilter::ScaleForce: case Settings::ScalingFilter::ScaleForce:
return *scaleforce_pipeline; return *scaleforce_pipeline;
default: default:
return *bilinear_pipeline; return *bilinear_pipeline;
} }
}(); }();
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
cmdbuf.SetViewport(0, viewport); cmdbuf.SetViewport(0, viewport);
cmdbuf.SetScissor(0, scissor); cmdbuf.SetScissor(0, scissor);
cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices)); cmdbuf.BindVertexBuffer(0, *buffer, offsetof(BufferData, vertices));
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0, cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline_layout, 0,
descriptor_sets[image_index], {}); descriptor_sets[index], {});
cmdbuf.Draw(4, 1, 0, 0); cmdbuf.Draw(4, 1, 0, 0);
cmdbuf.EndRenderPass(); cmdbuf.EndRenderPass();
}); });
return *semaphores[image_index];
} }
VkSemaphore BlitScreen::DrawToSwapchain(const Tegra::FramebufferConfig& framebuffer, void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer,
bool use_accelerated) { bool use_accelerated, bool is_srgb) {
const std::size_t image_index = swapchain.GetImageIndex(); // Recreate dynamic resources if the the image count or colorspace changed
const VkExtent2D render_area = swapchain.GetSize(); if (const std::size_t swapchain_images = swapchain.GetImageCount();
swapchain_images != image_count || current_srgb != is_srgb) {
current_srgb = is_srgb;
image_view_format = current_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
image_count = swapchain_images;
Recreate();
}
// Recreate the presentation frame if the dimensions of the window changed
const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
return Draw(framebuffer, *framebuffers[image_index], layout, render_area, use_accelerated); if (layout.width != frame->width || layout.height != frame->height ||
is_srgb != frame->is_srgb) {
Recreate();
present_manager.RecreateFrame(frame, layout.width, layout.height, is_srgb,
image_view_format, *renderpass);
}
const VkExtent2D render_area{frame->width, frame->height};
Draw(framebuffer, *frame->framebuffer, layout, render_area, use_accelerated);
if (++image_index >= image_count) {
image_index = 0;
}
} }
vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) { vk::Framebuffer BlitScreen::CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent) {
@ -471,13 +487,11 @@ void BlitScreen::CreateStaticResources() {
} }
void BlitScreen::CreateDynamicResources() { void BlitScreen::CreateDynamicResources() {
CreateSemaphores();
CreateDescriptorPool(); CreateDescriptorPool();
CreateDescriptorSetLayout(); CreateDescriptorSetLayout();
CreateDescriptorSets(); CreateDescriptorSets();
CreatePipelineLayout(); CreatePipelineLayout();
CreateRenderPass(); CreateRenderPass();
CreateFramebuffers();
CreateGraphicsPipeline(); CreateGraphicsPipeline();
fsr.reset(); fsr.reset();
smaa.reset(); smaa.reset();
@ -525,11 +539,6 @@ void BlitScreen::CreateShaders() {
} }
} }
void BlitScreen::CreateSemaphores() {
semaphores.resize(image_count);
std::ranges::generate(semaphores, [this] { return device.GetLogical().CreateSemaphore(); });
}
void BlitScreen::CreateDescriptorPool() { void BlitScreen::CreateDescriptorPool() {
const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ const std::array<VkDescriptorPoolSize, 2> pool_sizes{{
{ {
@ -571,10 +580,10 @@ void BlitScreen::CreateDescriptorPool() {
} }
void BlitScreen::CreateRenderPass() { void BlitScreen::CreateRenderPass() {
renderpass = CreateRenderPassImpl(swapchain.GetImageViewFormat()); renderpass = CreateRenderPassImpl(image_view_format);
} }
vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format, bool is_present) { vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format) {
const VkAttachmentDescription color_attachment{ const VkAttachmentDescription color_attachment{
.flags = 0, .flags = 0,
.format = format, .format = format,
@ -584,7 +593,7 @@ vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format, bool is_present
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = is_present ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_GENERAL, .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
}; };
const VkAttachmentReference color_attachment_ref{ const VkAttachmentReference color_attachment_ref{
@ -1052,16 +1061,6 @@ void BlitScreen::CreateSampler() {
nn_sampler = device.GetLogical().CreateSampler(ci_nn); nn_sampler = device.GetLogical().CreateSampler(ci_nn);
} }
void BlitScreen::CreateFramebuffers() {
const VkExtent2D size{swapchain.GetSize()};
framebuffers.resize(image_count);
for (std::size_t i = 0; i < image_count; ++i) {
const VkImageView image_view{swapchain.GetImageViewIndex(i)};
framebuffers[i] = CreateFramebuffer(image_view, size, renderpass);
}
}
void BlitScreen::ReleaseRawImages() { void BlitScreen::ReleaseRawImages() {
for (const u64 tick : resource_ticks) { for (const u64 tick : resource_ticks) {
scheduler.Wait(tick); scheduler.Wait(tick);
@ -1175,7 +1174,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass); aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass);
return; return;
} }
aa_renderpass = CreateRenderPassImpl(GetFormat(framebuffer), false); aa_renderpass = CreateRenderPassImpl(GetFormat(framebuffer));
aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass); aa_framebuffer = CreateFramebuffer(*aa_image_view, size, aa_renderpass);
const std::array<VkPipelineShaderStageCreateInfo, 2> fxaa_shader_stages{{ const std::array<VkPipelineShaderStageCreateInfo, 2> fxaa_shader_stages{{
@ -1319,8 +1318,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
aa_pipeline = device.GetLogical().CreateGraphicsPipeline(fxaa_pipeline_ci); aa_pipeline = device.GetLogical().CreateGraphicsPipeline(fxaa_pipeline_ci);
} }
void BlitScreen::UpdateAADescriptorSet(std::size_t image_index, VkImageView image_view, void BlitScreen::UpdateAADescriptorSet(VkImageView image_view, bool nn) const {
bool nn) const {
const VkDescriptorImageInfo image_info{ const VkDescriptorImageInfo image_info{
.sampler = nn ? *nn_sampler : *sampler, .sampler = nn ? *nn_sampler : *sampler,
.imageView = image_view, .imageView = image_view,
@ -1356,8 +1354,7 @@ void BlitScreen::UpdateAADescriptorSet(std::size_t image_index, VkImageView imag
device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, sampler_write_2}, {}); device.GetLogical().UpdateDescriptorSets(std::array{sampler_write, sampler_write_2}, {});
} }
void BlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view, void BlitScreen::UpdateDescriptorSet(VkImageView image_view, bool nn) const {
bool nn) const {
const VkDescriptorBufferInfo buffer_info{ const VkDescriptorBufferInfo buffer_info{
.buffer = *buffer, .buffer = *buffer,
.offset = offsetof(BufferData, uniform), .offset = offsetof(BufferData, uniform),
@ -1480,8 +1477,7 @@ u64 BlitScreen::CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer)
return sizeof(BufferData) + GetSizeInBytes(framebuffer) * image_count; return sizeof(BufferData) + GetSizeInBytes(framebuffer) * image_count;
} }
u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, u64 BlitScreen::GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const {
std::size_t image_index) const {
constexpr auto first_image_offset = static_cast<u64>(sizeof(BufferData)); constexpr auto first_image_offset = static_cast<u64>(sizeof(BufferData));
return first_image_offset + GetSizeInBytes(framebuffer) * image_index; return first_image_offset + GetSizeInBytes(framebuffer) * image_index;
} }

View File

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include "core/frontend/framebuffer_layout.h"
#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
@ -42,6 +43,9 @@ class RasterizerVulkan;
class Scheduler; class Scheduler;
class SMAA; class SMAA;
class Swapchain; class Swapchain;
class PresentManager;
struct Frame;
struct ScreenInfo { struct ScreenInfo {
VkImage image{}; VkImage image{};
@ -55,18 +59,17 @@ class BlitScreen {
public: public:
explicit BlitScreen(Core::Memory::Memory& cpu_memory, Core::Frontend::EmuWindow& render_window, explicit BlitScreen(Core::Memory::Memory& cpu_memory, Core::Frontend::EmuWindow& render_window,
const Device& device, MemoryAllocator& memory_manager, Swapchain& swapchain, const Device& device, MemoryAllocator& memory_manager, Swapchain& swapchain,
Scheduler& scheduler, const ScreenInfo& screen_info); PresentManager& present_manager, Scheduler& scheduler,
const ScreenInfo& screen_info);
~BlitScreen(); ~BlitScreen();
void Recreate(); void Recreate();
[[nodiscard]] VkSemaphore Draw(const Tegra::FramebufferConfig& framebuffer, void Draw(const Tegra::FramebufferConfig& framebuffer, const VkFramebuffer& host_framebuffer,
const VkFramebuffer& host_framebuffer, const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated);
const Layout::FramebufferLayout layout, VkExtent2D render_area,
bool use_accelerated);
[[nodiscard]] VkSemaphore DrawToSwapchain(const Tegra::FramebufferConfig& framebuffer, void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer,
bool use_accelerated); bool use_accelerated, bool is_srgb);
[[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view,
VkExtent2D extent); VkExtent2D extent);
@ -79,10 +82,9 @@ private:
void CreateStaticResources(); void CreateStaticResources();
void CreateShaders(); void CreateShaders();
void CreateSemaphores();
void CreateDescriptorPool(); void CreateDescriptorPool();
void CreateRenderPass(); void CreateRenderPass();
vk::RenderPass CreateRenderPassImpl(VkFormat, bool is_present = true); vk::RenderPass CreateRenderPassImpl(VkFormat format);
void CreateDescriptorSetLayout(); void CreateDescriptorSetLayout();
void CreateDescriptorSets(); void CreateDescriptorSets();
void CreatePipelineLayout(); void CreatePipelineLayout();
@ -90,15 +92,14 @@ private:
void CreateSampler(); void CreateSampler();
void CreateDynamicResources(); void CreateDynamicResources();
void CreateFramebuffers();
void RefreshResources(const Tegra::FramebufferConfig& framebuffer); void RefreshResources(const Tegra::FramebufferConfig& framebuffer);
void ReleaseRawImages(); void ReleaseRawImages();
void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer); void CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer);
void CreateRawImages(const Tegra::FramebufferConfig& framebuffer); void CreateRawImages(const Tegra::FramebufferConfig& framebuffer);
void UpdateDescriptorSet(std::size_t image_index, VkImageView image_view, bool nn) const; void UpdateDescriptorSet(VkImageView image_view, bool nn) const;
void UpdateAADescriptorSet(std::size_t image_index, VkImageView image_view, bool nn) const; void UpdateAADescriptorSet(VkImageView image_view, bool nn) const;
void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const; void SetUniformData(BufferData& data, const Layout::FramebufferLayout layout) const;
void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer, void SetVertexData(BufferData& data, const Tegra::FramebufferConfig& framebuffer,
const Layout::FramebufferLayout layout) const; const Layout::FramebufferLayout layout) const;
@ -107,16 +108,17 @@ private:
void CreateFSR(); void CreateFSR();
u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const; u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const;
u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer, u64 GetRawImageOffset(const Tegra::FramebufferConfig& framebuffer) const;
std::size_t image_index) const;
Core::Memory::Memory& cpu_memory; Core::Memory::Memory& cpu_memory;
Core::Frontend::EmuWindow& render_window; Core::Frontend::EmuWindow& render_window;
const Device& device; const Device& device;
MemoryAllocator& memory_allocator; MemoryAllocator& memory_allocator;
Swapchain& swapchain; Swapchain& swapchain;
PresentManager& present_manager;
Scheduler& scheduler; Scheduler& scheduler;
std::size_t image_count; std::size_t image_count;
std::size_t image_index{};
const ScreenInfo& screen_info; const ScreenInfo& screen_info;
vk::ShaderModule vertex_shader; vk::ShaderModule vertex_shader;
@ -135,7 +137,6 @@ private:
vk::Pipeline gaussian_pipeline; vk::Pipeline gaussian_pipeline;
vk::Pipeline scaleforce_pipeline; vk::Pipeline scaleforce_pipeline;
vk::RenderPass renderpass; vk::RenderPass renderpass;
std::vector<vk::Framebuffer> framebuffers;
vk::DescriptorSets descriptor_sets; vk::DescriptorSets descriptor_sets;
vk::Sampler nn_sampler; vk::Sampler nn_sampler;
vk::Sampler sampler; vk::Sampler sampler;
@ -145,7 +146,6 @@ private:
std::vector<u64> resource_ticks; std::vector<u64> resource_ticks;
std::vector<vk::Semaphore> semaphores;
std::vector<vk::Image> raw_images; std::vector<vk::Image> raw_images;
std::vector<vk::ImageView> raw_image_views; std::vector<vk::ImageView> raw_image_views;
std::vector<MemoryCommit> raw_buffer_commits; std::vector<MemoryCommit> raw_buffer_commits;
@ -164,6 +164,8 @@ private:
u32 raw_width = 0; u32 raw_width = 0;
u32 raw_height = 0; u32 raw_height = 0;
Service::android::PixelFormat pixel_format{}; Service::android::PixelFormat pixel_format{};
bool current_srgb;
VkFormat image_view_format;
std::unique_ptr<FSR> fsr; std::unique_ptr<FSR> fsr;
std::unique_ptr<SMAA> smaa; std::unique_ptr<SMAA> smaa;

View File

@ -46,10 +46,11 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
Scheduler::~Scheduler() = default; Scheduler::~Scheduler() = default;
void Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
// When flushing, we only send data to the worker thread; no waiting is necessary. // When flushing, we only send data to the worker thread; no waiting is necessary.
SubmitExecution(signal_semaphore, wait_semaphore); const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore);
AllocateNewContext(); AllocateNewContext();
return signal_value;
} }
void Scheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { void Scheduler::Finish(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
@ -205,7 +206,7 @@ void Scheduler::AllocateWorkerCommandBuffer() {
}); });
} }
void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { u64 Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
EndPendingOperations(); EndPendingOperations();
InvalidateState(); InvalidateState();
@ -217,6 +218,7 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s
on_submit(); on_submit();
} }
std::scoped_lock lock{submit_mutex};
switch (const VkResult result = master_semaphore->SubmitQueue( switch (const VkResult result = master_semaphore->SubmitQueue(
cmdbuf, signal_semaphore, wait_semaphore, signal_value)) { cmdbuf, signal_semaphore, wait_semaphore, signal_value)) {
case VK_SUCCESS: case VK_SUCCESS:
@ -231,6 +233,7 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s
}); });
chunk->MarkSubmit(); chunk->MarkSubmit();
DispatchWork(); DispatchWork();
return signal_value;
} }
void Scheduler::AllocateNewContext() { void Scheduler::AllocateNewContext() {

View File

@ -34,7 +34,7 @@ public:
~Scheduler(); ~Scheduler();
/// Sends the current execution context to the GPU. /// Sends the current execution context to the GPU.
void Flush(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr); u64 Flush(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr);
/// Sends the current execution context to the GPU and waits for it to complete. /// Sends the current execution context to the GPU and waits for it to complete.
void Finish(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr); void Finish(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr);
@ -106,6 +106,8 @@ public:
return *master_semaphore; return *master_semaphore;
} }
std::mutex submit_mutex;
private: private:
class Command { class Command {
public: public:
@ -201,7 +203,7 @@ private:
void AllocateWorkerCommandBuffer(); void AllocateWorkerCommandBuffer();
void SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore); u64 SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore);
void AllocateNewContext(); void AllocateNewContext();

View File

@ -99,18 +99,16 @@ void Swapchain::Create(u32 width_, u32 height_, bool srgb) {
return; return;
} }
device.GetLogical().WaitIdle();
Destroy(); Destroy();
CreateSwapchain(capabilities, srgb); CreateSwapchain(capabilities, srgb);
CreateSemaphores(); CreateSemaphores();
CreateImageViews();
resource_ticks.clear(); resource_ticks.clear();
resource_ticks.resize(image_count); resource_ticks.resize(image_count);
} }
void Swapchain::AcquireNextImage() { bool Swapchain::AcquireNextImage() {
const VkResult result = device.GetLogical().AcquireNextImageKHR( const VkResult result = device.GetLogical().AcquireNextImageKHR(
*swapchain, std::numeric_limits<u64>::max(), *present_semaphores[frame_index], *swapchain, std::numeric_limits<u64>::max(), *present_semaphores[frame_index],
VK_NULL_HANDLE, &image_index); VK_NULL_HANDLE, &image_index);
@ -127,8 +125,11 @@ void Swapchain::AcquireNextImage() {
LOG_ERROR(Render_Vulkan, "vkAcquireNextImageKHR returned {}", vk::ToString(result)); LOG_ERROR(Render_Vulkan, "vkAcquireNextImageKHR returned {}", vk::ToString(result));
break; break;
} }
scheduler.Wait(resource_ticks[image_index]); scheduler.Wait(resource_ticks[image_index]);
resource_ticks[image_index] = scheduler.CurrentTick(); resource_ticks[image_index] = scheduler.CurrentTick();
return is_suboptimal || is_outdated;
} }
void Swapchain::Present(VkSemaphore render_semaphore) { void Swapchain::Present(VkSemaphore render_semaphore) {
@ -143,6 +144,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
.pImageIndices = &image_index, .pImageIndices = &image_index,
.pResults = nullptr, .pResults = nullptr,
}; };
std::scoped_lock lock{scheduler.submit_mutex};
switch (const VkResult result = present_queue.Present(present_info)) { switch (const VkResult result = present_queue.Present(present_info)) {
case VK_SUCCESS: case VK_SUCCESS:
break; break;
@ -168,7 +170,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo
const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)}; const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)};
const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)}; const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)};
const VkSurfaceFormatKHR surface_format{ChooseSwapSurfaceFormat(formats)}; surface_format = ChooseSwapSurfaceFormat(formats);
present_mode = ChooseSwapPresentMode(present_modes); present_mode = ChooseSwapPresentMode(present_modes);
u32 requested_image_count{capabilities.minImageCount + 1}; u32 requested_image_count{capabilities.minImageCount + 1};
@ -193,7 +195,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo
.imageColorSpace = surface_format.colorSpace, .imageColorSpace = surface_format.colorSpace,
.imageExtent = {}, .imageExtent = {},
.imageArrayLayers = 1, .imageArrayLayers = 1,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0, .queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr, .pQueueFamilyIndices = nullptr,
@ -241,45 +243,14 @@ void Swapchain::CreateSemaphores() {
present_semaphores.resize(image_count); present_semaphores.resize(image_count);
std::ranges::generate(present_semaphores, std::ranges::generate(present_semaphores,
[this] { return device.GetLogical().CreateSemaphore(); }); [this] { return device.GetLogical().CreateSemaphore(); });
} render_semaphores.resize(image_count);
std::ranges::generate(render_semaphores,
void Swapchain::CreateImageViews() { [this] { return device.GetLogical().CreateSemaphore(); });
VkImageViewCreateInfo ci{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.image = {},
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = image_view_format,
.components =
{
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
},
.subresourceRange =
{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
image_views.resize(image_count);
for (std::size_t i = 0; i < image_count; i++) {
ci.image = images[i];
image_views[i] = device.GetLogical().CreateImageView(ci);
}
} }
void Swapchain::Destroy() { void Swapchain::Destroy() {
frame_index = 0; frame_index = 0;
present_semaphores.clear(); present_semaphores.clear();
framebuffers.clear();
image_views.clear();
swapchain.reset(); swapchain.reset();
} }

View File

@ -27,7 +27,7 @@ public:
void Create(u32 width, u32 height, bool srgb); void Create(u32 width, u32 height, bool srgb);
/// Acquires the next image in the swapchain, waits as needed. /// Acquires the next image in the swapchain, waits as needed.
void AcquireNextImage(); bool AcquireNextImage();
/// Presents the rendered image to the swapchain. /// Presents the rendered image to the swapchain.
void Present(VkSemaphore render_semaphore); void Present(VkSemaphore render_semaphore);
@ -52,6 +52,11 @@ public:
return is_suboptimal; return is_suboptimal;
} }
/// Returns true when the swapchain format is in the srgb color space
bool IsSrgb() const {
return current_srgb;
}
VkExtent2D GetSize() const { VkExtent2D GetSize() const {
return extent; return extent;
} }
@ -64,22 +69,34 @@ public:
return image_index; return image_index;
} }
std::size_t GetFrameIndex() const {
return frame_index;
}
VkImage GetImageIndex(std::size_t index) const { VkImage GetImageIndex(std::size_t index) const {
return images[index]; return images[index];
} }
VkImageView GetImageViewIndex(std::size_t index) const { VkImage CurrentImage() const {
return *image_views[index]; return images[image_index];
} }
VkFormat GetImageViewFormat() const { VkFormat GetImageViewFormat() const {
return image_view_format; return image_view_format;
} }
VkFormat GetImageFormat() const {
return surface_format.format;
}
VkSemaphore CurrentPresentSemaphore() const { VkSemaphore CurrentPresentSemaphore() const {
return *present_semaphores[frame_index]; return *present_semaphores[frame_index];
} }
VkSemaphore CurrentRenderSemaphore() const {
return *render_semaphores[frame_index];
}
u32 GetWidth() const { u32 GetWidth() const {
return width; return width;
} }
@ -88,6 +105,10 @@ public:
return height; return height;
} }
VkExtent2D GetExtent() const {
return extent;
}
private: private:
void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb); void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb);
void CreateSemaphores(); void CreateSemaphores();
@ -107,10 +128,9 @@ private:
std::size_t image_count{}; std::size_t image_count{};
std::vector<VkImage> images; std::vector<VkImage> images;
std::vector<vk::ImageView> image_views;
std::vector<vk::Framebuffer> framebuffers;
std::vector<u64> resource_ticks; std::vector<u64> resource_ticks;
std::vector<vk::Semaphore> present_semaphores; std::vector<vk::Semaphore> present_semaphores;
std::vector<vk::Semaphore> render_semaphores;
u32 width; u32 width;
u32 height; u32 height;
@ -121,6 +141,7 @@ private:
VkFormat image_view_format{}; VkFormat image_view_format{};
VkExtent2D extent{}; VkExtent2D extent{};
VkPresentModeKHR present_mode{}; VkPresentModeKHR present_mode{};
VkSurfaceFormatKHR surface_format{};
bool current_srgb{}; bool current_srgb{};
bool current_fps_unlocked{}; bool current_fps_unlocked{};

View File

@ -14,13 +14,18 @@ namespace Vulkan {
UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_) UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_)
: device{device_}, scheduler{scheduler_} { : device{device_}, scheduler{scheduler_} {
payload_start = payload.data();
payload_cursor = payload.data(); payload_cursor = payload.data();
} }
UpdateDescriptorQueue::~UpdateDescriptorQueue() = default; UpdateDescriptorQueue::~UpdateDescriptorQueue() = default;
void UpdateDescriptorQueue::TickFrame() { void UpdateDescriptorQueue::TickFrame() {
payload_cursor = payload.data(); if (++frame_index >= FRAMES_IN_FLIGHT) {
frame_index = 0;
}
payload_start = payload.data() + frame_index * FRAME_PAYLOAD_SIZE;
payload_cursor = payload_start;
} }
void UpdateDescriptorQueue::Acquire() { void UpdateDescriptorQueue::Acquire() {
@ -28,10 +33,10 @@ void UpdateDescriptorQueue::Acquire() {
// This is the maximum number of entries a single draw call might use. // This is the maximum number of entries a single draw call might use.
static constexpr size_t MIN_ENTRIES = 0x400; static constexpr size_t MIN_ENTRIES = 0x400;
if (std::distance(payload.data(), payload_cursor) + MIN_ENTRIES >= payload.max_size()) { if (std::distance(payload_start, payload_cursor) + MIN_ENTRIES >= FRAME_PAYLOAD_SIZE) {
LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread"); LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread");
scheduler.WaitWorker(); scheduler.WaitWorker();
payload_cursor = payload.data(); payload_cursor = payload_start;
} }
upload_start = payload_cursor; upload_start = payload_cursor;
} }

View File

@ -29,6 +29,12 @@ struct DescriptorUpdateEntry {
}; };
class UpdateDescriptorQueue final { class UpdateDescriptorQueue final {
// This should be plenty for the vast majority of cases. Most desktop platforms only
// provide up to 3 swapchain images.
static constexpr size_t FRAMES_IN_FLIGHT = 5;
static constexpr size_t FRAME_PAYLOAD_SIZE = 0x10000;
static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT;
public: public:
explicit UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_); explicit UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_);
~UpdateDescriptorQueue(); ~UpdateDescriptorQueue();
@ -73,9 +79,11 @@ private:
const Device& device; const Device& device;
Scheduler& scheduler; Scheduler& scheduler;
size_t frame_index{0};
DescriptorUpdateEntry* payload_cursor = nullptr; DescriptorUpdateEntry* payload_cursor = nullptr;
DescriptorUpdateEntry* payload_start = nullptr;
const DescriptorUpdateEntry* upload_start = nullptr; const DescriptorUpdateEntry* upload_start = nullptr;
std::array<DescriptorUpdateEntry, 0x10000> payload; std::array<DescriptorUpdateEntry, PAYLOAD_SIZE> payload;
}; };
} // namespace Vulkan } // namespace Vulkan