mirror of
https://git.eden-emu.dev/archive/citron
synced 2026-03-22 17:46:08 -04:00
Merge pull request 'fix(vulkan): Async Presentation & Shader Logic' (#135) from fix/async-shader into main
Reviewed-on: https://git.citron-emu.org/Citron/Emulator/pulls/135
This commit is contained in:
@@ -25,14 +25,14 @@ using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET;
|
||||
using Tegra::Texture::TexturePair;
|
||||
|
||||
ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipeline_cache_,
|
||||
DescriptorPool& descriptor_pool,
|
||||
std::mutex& pipeline_cache_mutex_, DescriptorPool& descriptor_pool,
|
||||
GuestDescriptorQueue& guest_descriptor_queue_,
|
||||
Common::ThreadWorker* thread_worker,
|
||||
PipelineStatistics* pipeline_statistics,
|
||||
VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_,
|
||||
vk::ShaderModule spv_module_)
|
||||
: device{device_},
|
||||
pipeline_cache(pipeline_cache_), guest_descriptor_queue{guest_descriptor_queue_}, info{info_},
|
||||
: device{device_}, pipeline_cache(pipeline_cache_), pipeline_cache_mutex(pipeline_cache_mutex_),
|
||||
guest_descriptor_queue{guest_descriptor_queue_}, info{info_},
|
||||
spv_module(std::move(spv_module_)) {
|
||||
if (shader_notify) {
|
||||
shader_notify->MarkShaderBuilding();
|
||||
@@ -58,6 +58,7 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel
|
||||
if (device.IsKhrPipelineExecutablePropertiesEnabled()) {
|
||||
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
|
||||
}
|
||||
std::scoped_lock cache_lock{pipeline_cache_mutex};
|
||||
pipeline = device.GetLogical().CreateComputePipeline(
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/thread_worker.h"
|
||||
#include "shader_recompiler/shader_info.h"
|
||||
@@ -29,7 +31,7 @@ class Scheduler;
|
||||
class ComputePipeline {
|
||||
public:
|
||||
explicit ComputePipeline(const Device& device, vk::PipelineCache& pipeline_cache,
|
||||
DescriptorPool& descriptor_pool,
|
||||
std::mutex& pipeline_cache_mutex, DescriptorPool& descriptor_pool,
|
||||
GuestDescriptorQueue& guest_descriptor_queue,
|
||||
Common::ThreadWorker* thread_worker,
|
||||
PipelineStatistics* pipeline_statistics,
|
||||
@@ -48,6 +50,7 @@ public:
|
||||
private:
|
||||
const Device& device;
|
||||
vk::PipelineCache& pipeline_cache;
|
||||
std::mutex& pipeline_cache_mutex;
|
||||
GuestDescriptorQueue& guest_descriptor_queue;
|
||||
Shader::Info info;
|
||||
|
||||
|
||||
@@ -88,7 +88,8 @@ bool SupportsPrimitiveRestart(VkPrimitiveTopology topology) {
|
||||
|
||||
bool IsLine(VkPrimitiveTopology topology) {
|
||||
static constexpr std::array line_topologies{
|
||||
VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
|
||||
VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
||||
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
|
||||
// VK_PRIMITIVE_TOPOLOGY_LINE_LOOP_EXT,
|
||||
};
|
||||
return std::ranges::find(line_topologies, topology) == line_topologies.end();
|
||||
@@ -237,15 +238,16 @@ ConfigureFuncPtr ConfigureFunc(const std::array<vk::ShaderModule, NUM_STAGES>& m
|
||||
|
||||
GraphicsPipeline::GraphicsPipeline(
|
||||
Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_,
|
||||
vk::PipelineCache& pipeline_cache_, VideoCore::ShaderNotify* shader_notify,
|
||||
const Device& device_, DescriptorPool& descriptor_pool,
|
||||
vk::PipelineCache& pipeline_cache_, std::mutex& pipeline_cache_mutex_,
|
||||
VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool,
|
||||
GuestDescriptorQueue& guest_descriptor_queue_, Common::ThreadWorker* worker_thread,
|
||||
PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
|
||||
const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
const std::array<const Shader::Info*, NUM_STAGES>& infos)
|
||||
: key{key_}, device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
|
||||
pipeline_cache(pipeline_cache_), scheduler{scheduler_},
|
||||
guest_descriptor_queue{guest_descriptor_queue_}, spv_modules{std::move(stages)} {
|
||||
pipeline_cache(pipeline_cache_), pipeline_cache_mutex(pipeline_cache_mutex_),
|
||||
scheduler{scheduler_}, guest_descriptor_queue{guest_descriptor_queue_},
|
||||
spv_modules{std::move(stages)} {
|
||||
if (shader_notify) {
|
||||
shader_notify->MarkShaderBuilding();
|
||||
}
|
||||
@@ -925,6 +927,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
if (device.IsKhrPipelineExecutablePropertiesEnabled()) {
|
||||
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
|
||||
}
|
||||
std::scoped_lock lock{pipeline_cache_mutex};
|
||||
pipeline = device.GetLogical().CreateGraphicsPipeline(
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
|
||||
@@ -71,11 +71,12 @@ class GraphicsPipeline {
|
||||
public:
|
||||
explicit GraphicsPipeline(
|
||||
Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache,
|
||||
vk::PipelineCache& pipeline_cache, VideoCore::ShaderNotify* shader_notify,
|
||||
const Device& device, DescriptorPool& descriptor_pool,
|
||||
GuestDescriptorQueue& guest_descriptor_queue, Common::ThreadWorker* worker_thread,
|
||||
PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
|
||||
const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
vk::PipelineCache& pipeline_cache, std::mutex& pipeline_cache_mutex,
|
||||
VideoCore::ShaderNotify* shader_notify, const Device& device,
|
||||
DescriptorPool& descriptor_pool, GuestDescriptorQueue& guest_descriptor_queue,
|
||||
Common::ThreadWorker* worker_thread, PipelineStatistics* pipeline_statistics,
|
||||
RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key,
|
||||
std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
const std::array<const Shader::Info*, NUM_STAGES>& infos);
|
||||
|
||||
GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;
|
||||
@@ -131,6 +132,7 @@ private:
|
||||
TextureCache& texture_cache;
|
||||
BufferCache& buffer_cache;
|
||||
vk::PipelineCache& pipeline_cache;
|
||||
std::mutex& pipeline_cache_mutex;
|
||||
Scheduler& scheduler;
|
||||
GuestDescriptorQueue& guest_descriptor_queue;
|
||||
|
||||
|
||||
@@ -677,11 +677,6 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const
|
||||
if (pipeline->IsBuilt()) {
|
||||
return pipeline;
|
||||
}
|
||||
if (!use_asynchronous_shaders) {
|
||||
return pipeline;
|
||||
}
|
||||
// When asynchronous shaders are enabled, avoid blocking the main thread completely.
|
||||
// Skip the draw until the pipeline is ready to prevent stutter.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -769,10 +764,11 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
previous_stage = &program;
|
||||
}
|
||||
Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
|
||||
return std::make_unique<GraphicsPipeline>(
|
||||
scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, &shader_notify, device,
|
||||
descriptor_pool, guest_descriptor_queue, thread_worker, statistics, render_pass_cache, key,
|
||||
std::move(modules), infos);
|
||||
auto pipeline{std::make_unique<GraphicsPipeline>(
|
||||
scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, pipeline_cache_mutex,
|
||||
&shader_notify, device, descriptor_pool, guest_descriptor_queue, thread_worker, statistics,
|
||||
render_pass_cache, key, std::move(modules), infos)};
|
||||
return pipeline;
|
||||
|
||||
} catch (const vk::Exception& exception) {
|
||||
if (exception.GetResult() == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
|
||||
@@ -804,6 +800,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() {
|
||||
GraphicsEnvironments environments;
|
||||
GetGraphicsEnvironments(environments, graphics_key.unique_hashes);
|
||||
|
||||
std::scoped_lock lock{pools_mutex};
|
||||
main_pools.ReleaseContents();
|
||||
auto pipeline{
|
||||
CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), nullptr, true)};
|
||||
@@ -830,6 +827,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
ComputeEnvironment env{*kepler_compute, *gpu_memory, program_base, qmd.program_start};
|
||||
env.SetCachedSize(shader->size_bytes);
|
||||
|
||||
std::scoped_lock lock{pools_mutex};
|
||||
main_pools.ReleaseContents();
|
||||
auto pipeline{CreateComputePipeline(main_pools, key, env, nullptr, true)};
|
||||
if (!pipeline || pipeline_cache_filename.empty()) {
|
||||
@@ -874,9 +872,10 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
spv_module.SetObjectNameEXT(name.c_str());
|
||||
}
|
||||
Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
|
||||
return std::make_unique<ComputePipeline>(device, vulkan_pipeline_cache, descriptor_pool,
|
||||
guest_descriptor_queue, thread_worker, statistics,
|
||||
&shader_notify, program.info, std::move(spv_module));
|
||||
return std::make_unique<ComputePipeline>(device, vulkan_pipeline_cache, pipeline_cache_mutex,
|
||||
descriptor_pool, guest_descriptor_queue, thread_worker,
|
||||
statistics, &shader_notify, program.info,
|
||||
std::move(spv_module));
|
||||
|
||||
} catch (const vk::Exception& exception) {
|
||||
if (exception.GetResult() == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
|
||||
@@ -904,6 +903,7 @@ void PipelineCache::SerializeVulkanPipelineCache(const std::filesystem::path& fi
|
||||
file.write(VULKAN_CACHE_MAGIC_NUMBER.data(), VULKAN_CACHE_MAGIC_NUMBER.size())
|
||||
.write(reinterpret_cast<const char*>(&cache_version), sizeof(cache_version));
|
||||
|
||||
std::scoped_lock lock{pipeline_cache_mutex};
|
||||
size_t cache_size = 0;
|
||||
std::vector<char> cache_data;
|
||||
if (pipeline_cache) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -176,6 +177,8 @@ public:
|
||||
static constexpr u64 MEMORY_PRESSURE_COOLDOWN = 300;
|
||||
|
||||
ShaderPools main_pools;
|
||||
std::mutex pools_mutex;
|
||||
std::mutex pipeline_cache_mutex;
|
||||
|
||||
Shader::Profile profile;
|
||||
Shader::HostTranslateInfo host_info;
|
||||
|
||||
@@ -64,35 +64,35 @@ static VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox,
|
||||
return mode;
|
||||
}
|
||||
switch (mode) {
|
||||
case Settings::VSyncMode::Fifo:
|
||||
case Settings::VSyncMode::FifoRelaxed:
|
||||
if (has_mailbox) {
|
||||
return Settings::VSyncMode::Mailbox;
|
||||
} else if (has_imm) {
|
||||
return Settings::VSyncMode::Immediate;
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
return mode;
|
||||
case Settings::VSyncMode::Fifo:
|
||||
case Settings::VSyncMode::FifoRelaxed:
|
||||
if (has_mailbox) {
|
||||
return Settings::VSyncMode::Mailbox;
|
||||
} else if (has_imm) {
|
||||
return Settings::VSyncMode::Immediate;
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
return mode;
|
||||
}
|
||||
}();
|
||||
if ((setting == Settings::VSyncMode::Mailbox && !has_mailbox) ||
|
||||
(setting == Settings::VSyncMode::Immediate && !has_imm) ||
|
||||
(setting == Settings::VSyncMode::FifoRelaxed && !has_fifo_relaxed)) {
|
||||
setting = Settings::VSyncMode::Fifo;
|
||||
}
|
||||
}
|
||||
|
||||
switch (setting) {
|
||||
case Settings::VSyncMode::Immediate:
|
||||
return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
case Settings::VSyncMode::Mailbox:
|
||||
return VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
case Settings::VSyncMode::Fifo:
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
case Settings::VSyncMode::FifoRelaxed:
|
||||
return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
default:
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
switch (setting) {
|
||||
case Settings::VSyncMode::Immediate:
|
||||
return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
case Settings::VSyncMode::Mailbox:
|
||||
return VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
case Settings::VSyncMode::Fifo:
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
case Settings::VSyncMode::FifoRelaxed:
|
||||
return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
default:
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ bool Swapchain::AcquireNextImage() {
|
||||
break;
|
||||
}
|
||||
|
||||
scheduler.Wait(resource_ticks[image_index]);
|
||||
scheduler.GetMasterSemaphore().Wait(resource_ticks[image_index]);
|
||||
resource_ticks[image_index] = scheduler.CurrentTick();
|
||||
|
||||
return is_suboptimal || is_outdated;
|
||||
|
||||
Reference in New Issue
Block a user