mirror of
https://github.com/citron-neo/emulator.git
synced 2026-07-05 15:21:57 -07:00
video_core: Implement thread-safe Vulkan renderer teardown
This commit is contained in:
@@ -41,7 +41,11 @@ struct GPU::Impl {
|
||||
shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_},
|
||||
gpu_thread{system_, is_async_}, scheduler{std::make_unique<Control::Scheduler>(gpu)} {}
|
||||
|
||||
~Impl() = default;
|
||||
~Impl() {
|
||||
if (rasterizer) {
|
||||
rasterizer->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Control::ChannelState> CreateChannel(s32 channel_id) {
|
||||
auto channel_state = std::make_shared<Tegra::Control::ChannelState>(channel_id);
|
||||
|
||||
@@ -38,6 +38,9 @@ class RasterizerInterface {
|
||||
public:
|
||||
virtual ~RasterizerInterface() = default;
|
||||
|
||||
/// Prepare the rasterizer for shutdown
|
||||
virtual void Shutdown() {}
|
||||
|
||||
/// Dispatches a draw invocation
|
||||
virtual void Draw(bool is_indexed, u32 instance_count) = 0;
|
||||
|
||||
|
||||
@@ -205,7 +205,12 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
|
||||
});
|
||||
}
|
||||
|
||||
RasterizerVulkan::~RasterizerVulkan() {
|
||||
void RasterizerVulkan::Shutdown() {
|
||||
if (is_shutting_down.exchange(true)) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock exclusive_guard{shutdown_mutex};
|
||||
|
||||
// 1. Tell the GPU to finish current work
|
||||
scheduler.Finish();
|
||||
|
||||
@@ -213,6 +218,10 @@ RasterizerVulkan::~RasterizerVulkan() {
|
||||
// This ensures VkBuffer/VkImage handles are gone before the memory they sit on is freed
|
||||
buffer_cache_runtime.Finish();
|
||||
texture_cache_runtime.Finish();
|
||||
}
|
||||
|
||||
RasterizerVulkan::~RasterizerVulkan() {
|
||||
Shutdown();
|
||||
|
||||
// 3. Clear the Staging Pool slabs
|
||||
staging_pool.TriggerCacheRelease(MemoryUsage::Upload);
|
||||
@@ -225,6 +234,11 @@ RasterizerVulkan::~RasterizerVulkan() {
|
||||
|
||||
template <typename Func>
|
||||
void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
||||
std::shared_lock shared_guard{shutdown_mutex};
|
||||
if (is_shutting_down) {
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPE_EXIT {
|
||||
gpu.TickWork();
|
||||
};
|
||||
@@ -500,6 +514,9 @@ void RasterizerVulkan::Clear(u32 layer_count) {
|
||||
}
|
||||
|
||||
void RasterizerVulkan::DispatchCompute() {
|
||||
std::shared_lock shared_guard{shutdown_mutex};
|
||||
if (is_shutting_down) return;
|
||||
|
||||
// Skip first 2 dispatches for Marvel Cosmic Invasion to fix boot issues
|
||||
if (program_id == UICommon::TitleID::MarvelCosmicInvasion) {
|
||||
static u32 dispatch_count = 0;
|
||||
@@ -564,6 +581,9 @@ void Vulkan::RasterizerVulkan::DisableGraphicsUniformBuffer(size_t stage, u32 in
|
||||
void RasterizerVulkan::FlushAll() {}
|
||||
|
||||
void RasterizerVulkan::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
|
||||
std::shared_lock shared_guard{shutdown_mutex};
|
||||
if (is_shutting_down) return;
|
||||
|
||||
if (addr == 0 || size == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -581,6 +601,9 @@ void RasterizerVulkan::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType
|
||||
}
|
||||
|
||||
bool RasterizerVulkan::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
|
||||
std::shared_lock shared_guard{shutdown_mutex};
|
||||
if (is_shutting_down) return false;
|
||||
|
||||
if ((True(which & VideoCommon::CacheType::BufferCache))) {
|
||||
std::scoped_lock lock{buffer_cache.mutex};
|
||||
if (buffer_cache.IsRegionGpuModified(addr, size)) {
|
||||
@@ -599,6 +622,15 @@ bool RasterizerVulkan::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheT
|
||||
}
|
||||
|
||||
VideoCore::RasterizerDownloadArea RasterizerVulkan::GetFlushArea(DAddr addr, u64 size) {
|
||||
std::shared_lock shared_guard{shutdown_mutex};
|
||||
if (is_shutting_down) {
|
||||
return {
|
||||
.start_address = Common::AlignDown(addr, Core::DEVICE_PAGESIZE),
|
||||
.end_address = Common::AlignUp(addr + size, Core::DEVICE_PAGESIZE),
|
||||
.preemtive = true,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
auto area = texture_cache.GetFlushArea(addr, size);
|
||||
@@ -615,6 +647,9 @@ VideoCore::RasterizerDownloadArea RasterizerVulkan::GetFlushArea(DAddr addr, u64
|
||||
}
|
||||
|
||||
void RasterizerVulkan::InvalidateRegion(DAddr addr, u64 size, VideoCommon::CacheType which) {
|
||||
std::shared_lock shared_guard{shutdown_mutex};
|
||||
if (is_shutting_down) return;
|
||||
|
||||
if (addr == 0 || size == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -849,6 +884,9 @@ u64 RasterizerVulkan::GetStagingMemoryUsage() const {
|
||||
}
|
||||
|
||||
void RasterizerVulkan::TriggerMemoryGC() {
|
||||
std::shared_lock shared_guard{shutdown_mutex};
|
||||
if (is_shutting_down) return;
|
||||
|
||||
std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex};
|
||||
texture_cache.TriggerGarbageCollection();
|
||||
buffer_cache.TriggerGarbageCollection();
|
||||
@@ -862,6 +900,9 @@ bool RasterizerVulkan::AccelerateConditionalRendering() {
|
||||
bool RasterizerVulkan::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
|
||||
const Tegra::Engines::Fermi2D::Surface& dst,
|
||||
const Tegra::Engines::Fermi2D::Config& copy_config) {
|
||||
std::shared_lock shared_guard{shutdown_mutex};
|
||||
if (is_shutting_down) return false;
|
||||
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
return texture_cache.BlitImage(dst, src, copy_config);
|
||||
}
|
||||
@@ -872,6 +913,9 @@ Tegra::Engines::AccelerateDMAInterface& RasterizerVulkan::AccessAccelerateDMA()
|
||||
|
||||
void RasterizerVulkan::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size,
|
||||
std::span<const u8> memory) {
|
||||
std::shared_lock shared_guard{shutdown_mutex};
|
||||
if (is_shutting_down) return;
|
||||
|
||||
auto cpu_addr = gpu_memory->GpuToCpuAddress(address);
|
||||
if (!cpu_addr) [[unlikely]] {
|
||||
gpu_memory->WriteBlock(address, memory.data(), copy_size);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
@@ -82,6 +84,8 @@ public:
|
||||
StateTracker& state_tracker_, Scheduler& scheduler_);
|
||||
~RasterizerVulkan() override;
|
||||
|
||||
void Shutdown() override;
|
||||
|
||||
void Draw(bool is_indexed, u32 instance_count) override;
|
||||
void DrawIndirect() override;
|
||||
void DrawTexture() override;
|
||||
@@ -223,6 +227,9 @@ private:
|
||||
boost::container::static_vector<VkSampler, MAX_TEXTURES> sampler_handles;
|
||||
|
||||
u32 draw_counter = 0;
|
||||
|
||||
std::shared_mutex shutdown_mutex;
|
||||
std::atomic_bool is_shutting_down{false};
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
Reference in New Issue
Block a user