From f7a726e452432c9a39490365103adfcb9a160b00 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Wed, 31 Aug 2022 14:45:55 +0100 Subject: [PATCH] Allow attempting to write to buffers without passing a GPU copy callback Constructing the GPU copy callback in `ConstantBuffers::Load()` ended up taking a fair amount of time despite it almost never being used in practice. By making it optional it can be skipped most of the time and only done when it's actually neccessary by calling `Write()` again if the initial call returned true. --- app/src/main/cpp/skyline/gpu/buffer.cpp | 15 +++++++++++---- app/src/main/cpp/skyline/gpu/buffer.h | 5 +++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/buffer.cpp b/app/src/main/cpp/skyline/gpu/buffer.cpp index 5db282d6..693fe230 100644 --- a/app/src/main/cpp/skyline/gpu/buffer.cpp +++ b/app/src/main/cpp/skyline/gpu/buffer.cpp @@ -223,7 +223,7 @@ namespace skyline::gpu { std::memcpy(data.data(), mirror.data() + offset, data.size()); } - void Buffer::Write(bool isFirstUsage, const std::function &flushHostCallback, const std::function &gpuCopyCallback, span data, vk::DeviceSize offset) { + bool Buffer::Write(bool isFirstUsage, const std::function &flushHostCallback, span data, vk::DeviceSize offset, const std::function &gpuCopyCallback) { AdvanceSequence(); // We are modifying GPU backing contents so advance to the next sequence everHadInlineUpdate = true; @@ -238,12 +238,19 @@ namespace skyline::gpu { std::memcpy(mirror.data() + offset, data.data(), data.size()); // Always copy to mirror since any CPU side reads will need the up-to-date contents - if (!SequencedCpuBackingWritesBlocked() && PollFence()) + if (!SequencedCpuBackingWritesBlocked() && PollFence()) { // We can write directly to the backing as long as this resource isn't being actively used by a past workload (in the current context or another) std::memcpy(backing.data() + offset, data.data(), data.size()); - else + } else { // If this buffer is host immutable, perform a GPU-side inline update for the buffer contents since we can't directly modify the backing - gpuCopyCallback(); + // If no copy callback is supplied, return true to indicate that the caller should repeat the write with an appropriate callback + if (gpuCopyCallback) + gpuCopyCallback(); + else + return true; + } + + return false; } BufferView Buffer::GetView(vk::DeviceSize offset, vk::DeviceSize size) { diff --git a/app/src/main/cpp/skyline/gpu/buffer.h b/app/src/main/cpp/skyline/gpu/buffer.h index f8742882..00074463 100644 --- a/app/src/main/cpp/skyline/gpu/buffer.h +++ b/app/src/main/cpp/skyline/gpu/buffer.h @@ -245,9 +245,10 @@ namespace skyline::gpu { * @brief Writes data at the specified offset in the buffer, falling back to GPU side copies if the buffer is host immutable * @param isFirstUsage If this is the first usage of this resource in the context as returned from LockWithTag(...) * @param flushHostCallback Callback to flush and execute all pending GPU work to allow for synchronisation of GPU dirty buffers - * @param gpuCopyCallback Callback to perform a GPU-side copy for this Write + * @param gpuCopyCallback Optional callback to perform a GPU-side copy for this Write if necessary, if such a copy is needed and this is not supplied `true` will be returned to indicate that the write needs to be repeated with the callback present + * @return Whether the write needs to be repeated with `gpuCopyCallback` provided, always false if `gpuCopyCallback` is provided */ - void Write(bool isFirstUsage, const std::function &flushHostCallback, const std::function &gpuCopyCallback, span data, vk::DeviceSize offset); + bool Write(bool isFirstUsage, const std::function &flushHostCallback, span data, vk::DeviceSize offset, const std::function &gpuCopyCallback = {}); /** * @return A view into this buffer with the supplied attributes