diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index bf8ac4223..8942c3f5d 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -217,7 +217,7 @@ void RendererVulkan::RenderToMailbox(const Layout::FramebufferLayout& layout, DrawScreens(frame, layout, flipped); - scheduler.Flush(frame->render_ready, nullptr, &frame->is_submitted); + scheduler.Flush(&frame->is_submitted, frame->render_ready); mailbox->Present(frame); } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 261e000e6..951e0d672 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -210,10 +210,17 @@ void RasterizerVulkan::SetupVertexArray() { const PAddr data_addr = base_address + loader.data_offset + (vs_input_index_min * loader.byte_count); const u32 vertex_num = vs_input_index_max - vs_input_index_min + 1; - const u32 data_size = loader.byte_count * vertex_num; + u32 data_size = loader.byte_count * vertex_num; res_cache.FlushRegion(data_addr, data_size); - const u8* src_ptr = memory.GetPhysicalPointer(data_addr); + const MemoryRef src_ref = memory.GetPhysicalRef(data_addr); + if (src_ref.GetSize() < data_size) { + LOG_ERROR(Render_Vulkan, + "Vertex buffer size {} exceeds available space {} at address {:#016X}", + data_size, src_ref.GetSize(), data_addr); + } + + const u8* src_ptr = src_ref.GetPtr(); u8* dst_ptr = array_ptr + buffer_offset; // Align stride up if required by Vulkan implementation. diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index e45a30376..85d1fad84 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -42,65 +42,7 @@ Scheduler::Scheduler(const Instance& instance, RenderpassCache& renderpass_cache Scheduler::~Scheduler() = default; -void Scheduler::Finish(vk::Semaphore signal, vk::Semaphore wait) { - const u64 presubmit_tick = CurrentTick(); - std::atomic_bool submit_done{false}; - - Flush(signal, wait, &submit_done); - if (use_worker_thread) { - MICROPROFILE_SCOPE(Vulkan_WaitForWorker); - submit_done.wait(false); - } - Wait(presubmit_tick); -} - -void Scheduler::DispatchWork() { - if (!use_worker_thread || chunk->Empty()) { - return; - } - - { - std::scoped_lock lock{work_mutex}; - work_queue.push(std::move(chunk)); - } - - work_cv.notify_one(); - AcquireNewChunk(); -} - -void Scheduler::WorkerThread(std::stop_token stop_token) { - Common::SetCurrentThreadName("VulkanWorker"); - do { - std::unique_ptr work; - { - std::unique_lock lock{work_mutex}; - Common::CondvarWait(work_cv, lock, stop_token, [&] { return !work_queue.empty(); }); - if (stop_token.stop_requested()) { - continue; - } - work = std::move(work_queue.front()); - work_queue.pop(); - } - const bool has_submit = work->HasSubmit(); - work->ExecuteAll(current_cmdbuf); - if (has_submit) { - AllocateWorkerCommandBuffers(); - } - std::scoped_lock reserve_lock{reserve_mutex}; - chunk_reserve.push_back(std::move(work)); - } while (!stop_token.stop_requested()); -} - -void Scheduler::AllocateWorkerCommandBuffers() { - const vk::CommandBufferBeginInfo begin_info = { - .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit, - }; - - current_cmdbuf = command_pool.Commit(); - current_cmdbuf.begin(begin_info); -} - -void Scheduler::Flush(vk::Semaphore signal, vk::Semaphore wait, std::atomic_bool* submit_done) { +void Scheduler::Flush(std::atomic_bool* submit_done, vk::Semaphore signal, vk::Semaphore wait) { const vk::Semaphore handle = master_semaphore.Handle(); const u64 signal_value = master_semaphore.NextTick(); state = StateFlags::AllDirty; @@ -163,6 +105,72 @@ void Scheduler::Flush(vk::Semaphore signal, vk::Semaphore wait, std::atomic_bool } } +void Scheduler::Finish(vk::Semaphore signal, vk::Semaphore wait) { + const u64 presubmit_tick = CurrentTick(); + std::atomic_bool submit_done{false}; + + Flush(&submit_done, signal, wait); + if (use_worker_thread) { + MICROPROFILE_SCOPE(Vulkan_WaitForWorker); + submit_done.wait(false); + } + Wait(presubmit_tick); +} + +void Scheduler::Wait(u64 tick) { + if (tick >= master_semaphore.CurrentTick()) { + // Make sure we are not waiting for the current tick without signalling + Flush(); + } + master_semaphore.Wait(tick); +} + +void Scheduler::DispatchWork() { + if (!use_worker_thread || chunk->Empty()) { + return; + } + + { + std::scoped_lock lock{work_mutex}; + work_queue.push(std::move(chunk)); + } + + work_cv.notify_one(); + AcquireNewChunk(); +} + +void Scheduler::WorkerThread(std::stop_token stop_token) { + Common::SetCurrentThreadName("VulkanWorker"); + do { + std::unique_ptr work; + { + std::unique_lock lock{work_mutex}; + Common::CondvarWait(work_cv, lock, stop_token, [&] { return !work_queue.empty(); }); + if (stop_token.stop_requested()) { + continue; + } + work = std::move(work_queue.front()); + work_queue.pop(); + } + const bool has_submit = work->HasSubmit(); + work->ExecuteAll(current_cmdbuf); + if (has_submit) { + AllocateWorkerCommandBuffers(); + } + std::scoped_lock reserve_lock{reserve_mutex}; + chunk_reserve.push_back(std::move(work)); + } while (!stop_token.stop_requested()); +} + +void Scheduler::AllocateWorkerCommandBuffers() { + const vk::CommandBufferBeginInfo begin_info = { + .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit, + }; + + current_cmdbuf = command_pool.Commit(); + current_cmdbuf.begin(begin_info); +} + void Scheduler::AcquireNewChunk() { std::scoped_lock lock{reserve_mutex}; if (chunk_reserve.empty()) { diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index aede27be7..742001fd0 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -39,12 +39,15 @@ public: ~Scheduler(); /// Sends the current execution context to the GPU. - void Flush(vk::Semaphore signal = nullptr, vk::Semaphore wait = nullptr, - std::atomic_bool* submit_done = nullptr); + void Flush(std::atomic_bool* submit_done = nullptr, vk::Semaphore signal = nullptr, + vk::Semaphore wait = nullptr); /// Sends the current execution context to the GPU and waits for it to complete. void Finish(vk::Semaphore signal = nullptr, vk::Semaphore wait = nullptr); + /// Waits for the given tick to trigger on the GPU. + void Wait(u64 tick); + /// Sends currently recorded work to the worker thread. void DispatchWork(); @@ -93,16 +96,6 @@ public: return master_semaphore.IsFree(tick); } - /// Waits for the given tick to trigger on the GPU. - void Wait(u64 tick) { - if (tick >= master_semaphore.CurrentTick()) { - // Make sure we are not waiting for the current tick without signalling - LOG_WARNING(Render_Vulkan, "Flushing current tick"); - Flush(); - } - master_semaphore.Wait(tick); - } - /// Returns the master timeline semaphore. [[nodiscard]] MasterSemaphore& GetMasterSemaphore() noexcept { return master_semaphore;