diff --git a/core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp b/core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp index 70d6251395..cedd235345 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp @@ -323,12 +323,14 @@ public: // the GPU copies out of an import (gpuCopy) notes its read itself when the copy is recorded. // For the recorder's read tracking (ShaderResources::MarkGpuWrites); nothing once committed. std::vector> InPlaceReads() const; + void InPlaceReads(std::vector>& out) const; struct SplitReads { std::shared_ptr>> space; std::vector> own; }; std::optional SplitInPlaceReads() const; std::vector> DeviceReads() const; + void DeviceReads(std::vector>& out) const; private: struct Region { diff --git a/core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp b/core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp index d9e51d4132..33918639b7 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp @@ -234,8 +234,10 @@ public: // ranges, the regions read in place, and the storage images with whether each is written. const std::vector>& GpuWrites() const { return guestMemory.Writes(); } std::vector> InPlaceReads() const { return guestMemory.InPlaceReads(); } + void InPlaceReads(std::vector>& out) const { guestMemory.InPlaceReads(out); } std::vector> StorageImages() const; std::vector> DeviceReads() const { return guestMemory.DeviceReads(); } + void DeviceReads(std::vector>& out) const { guestMemory.DeviceReads(out); } bool ReadsImage(const StorageTexture* image) const; bool HasCachedStorageImages() const; bool HoldsReleasedTexture() const; @@ -257,6 +259,7 @@ public: // (their count and size remain): a compute template then serves dispatches whose constants // differ, and the hit refreshes its data buffers with the dispatch's words (RefreshData). static std::vector ContentKey(const CompiledShader& shader, bool dataWords = true, bool movableBuffers = false); + static void AppendContentKey(const CompiledShader& shader, bool dataWords, bool movableBuffers, std::vector& key); static bool DiffContentKeys(std::span previous, std::span key, bool draw, ContentKeyDiff& diff); // Records the shader's ShaderData and FlattenedSrt words into this object's data buffers // (vkCmdUpdateBuffer, a transfer write the caller's pre-dispatch barrier makes visible; a diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp index b3fbaa3161..ed3dc00abd 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp @@ -18,6 +18,7 @@ #include "prx/libc/include/General.hpp" #include "prx/libc/include/GuestAllocations.hpp" #include "Optimization/include/Optimization/ShaderStageInputInfo.hpp" +#include "ThreadOwned.hpp" #include #include #include @@ -764,7 +765,9 @@ bool MovableBuffers() { } ResourceCache::Key DrawResourceKey(const Context& context, std::span shaders, const ColorTarget& target, std::uint32_t colorAttachments, std::uint64_t indexAddress, std::uint64_t indexBytes, bool ranges) { - ResourceCache::Key key{0xffffffffu}; + ResourceCache::Key key; + key.reserve(256); + key.push_back(0xffffffffu); const auto append64 = [&](std::uint64_t value) { key.push_back(static_cast(value)); key.push_back(static_cast(value >> 32u)); @@ -772,9 +775,10 @@ ResourceCache::Key DrawResourceKey(const Context& context, std::span(context.device)); key.push_back(static_cast(shaders.size())); for (const auto& shader : shaders) { - const auto part = ShaderResources::ContentKey(shader, true, MovableBuffers()); - key.push_back(static_cast(part.size())); - key.insert(key.end(), part.begin(), part.end()); + const auto at = key.size(); + key.push_back(0); + ShaderResources::AppendContentKey(shader, true, MovableBuffers(), key); + key[at] = static_cast(key.size() - at - 1); } key.push_back(colorAttachments); if (ranges) { @@ -1911,7 +1915,10 @@ void recordDraw(const Context& context, const State& state, const Pm4::DrawParam const bool capture = CaptureInputsEnabled(); const bool meshIndirect = state.stages.mesh && args != nullptr; const bool addressBased = resources.HoldsLease(); - auto passReads = addressBased ? std::vector>{} : resources.DeviceReads(); + thread_local std::vector>* passReadsSlot = nullptr; + auto& passReads = ShaderRecompiler::ThreadOwned(passReadsSlot); + passReads.clear(); + if (!addressBased) resources.DeviceReads(passReads); if (gpuIndirect) { passReads.emplace_back(args->arguments, args->arguments + args->RangeBytes()); if (args->countIndirect) passReads.emplace_back(args->countAddress, args->countAddress + 4); diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp index 1fdc3b7210..1bf8e41dc9 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp @@ -4965,9 +4965,9 @@ std::uint64_t GuestBufferMemory::inPlaceEnd(const Region& region) { return region.direct != nullptr && region.runCut ? std::min(region.end, region.direct->base + region.direct->bytes) : region.end; } -std::vector> GuestBufferMemory::InPlaceReads() const { - std::vector> result; - if (!uploaded || committed) return result; +void GuestBufferMemory::InPlaceReads(std::vector>& result) const { + result.clear(); + if (!uploaded || committed) return; if (space != nullptr) { for (const auto& region : space->base) { if (region.direct != nullptr) result.emplace_back(region.begin, region.end); @@ -4976,6 +4976,11 @@ std::vector> GuestBufferMemory::InPlaceR for (const auto& region : regions) { if (region.direct != nullptr) result.emplace_back(region.begin, inPlaceEnd(region)); } +} + +std::vector> GuestBufferMemory::InPlaceReads() const { + std::vector> result; + InPlaceReads(result); return result; } @@ -4988,9 +4993,9 @@ std::optional GuestBufferMemory::SplitInPlaceRead return split; } -std::vector> GuestBufferMemory::DeviceReads() const { - std::vector> result; - if (!uploaded || committed) return result; +void GuestBufferMemory::DeviceReads(std::vector>& result) const { + result.clear(); + if (!uploaded || committed) return; if (space != nullptr) { for (const auto& region : space->base) { if (region.direct != nullptr || region.mirror != nullptr) result.emplace_back(region.begin, region.end); @@ -4999,6 +5004,11 @@ std::vector> GuestBufferMemory::DeviceRe for (const auto& region : regions) { if (region.direct != nullptr || region.mirror != nullptr) result.emplace_back(region.begin, region.end); } +} + +std::vector> GuestBufferMemory::DeviceReads() const { + std::vector> result; + DeviceReads(result); return result; } diff --git a/core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp b/core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp index 85ec7d173e..7d3a64775f 100644 --- a/core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp +++ b/core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp @@ -2468,9 +2468,14 @@ void VisitContentKey(const CompiledShader& shader, bool dataWords, bool movableB } std::vector ShaderResources::ContentKey(const CompiledShader& shader, bool dataWords, bool movableBuffers) { - Require(shader.program != nullptr, "missing compiled shader"); std::vector key; - std::size_t words = 5; + AppendContentKey(shader, dataWords, movableBuffers, key); + return key; +} + +void ShaderResources::AppendContentKey(const CompiledShader& shader, bool dataWords, bool movableBuffers, std::vector& key) { + Require(shader.program != nullptr, "missing compiled shader"); + std::size_t words = key.size() + 5; const auto addWords = [&](std::size_t count) { if (count > key.max_size() - words) throw std::length_error("resource content key exceeds vector limits"); words += count; @@ -2484,7 +2489,6 @@ std::vector ShaderResources::ContentKey(const CompiledShader& sha } key.reserve(words); VisitContentKey(shader, dataWords, movableBuffers, [&](std::uint32_t word) { key.push_back(word); }); - return key; } namespace { @@ -5144,7 +5148,9 @@ std::size_t ShaderResources::DrawUploadLimit() { std::shared_ptr ShaderResources::PrepareDrawBindings(Recorder& recorder, std::span moved, bool movedOnly) const { if ((_set == VK_NULL_HANDLE && fragment.set == VK_NULL_HANDLE) || usesBda) return {}; - const auto reads = guestMemory.InPlaceReads(); + thread_local std::vector>* readsSlot = nullptr; + auto& reads = ShaderRecompiler::ThreadOwned(readsSlot); + guestMemory.InPlaceReads(reads); const auto maxSnapshotBytes = maxDrawSnapshotBytes; const auto uploadLimit = DrawUploadLimit(); std::size_t totalSnapshotBytes = 0; @@ -5236,35 +5242,43 @@ std::shared_ptr ShaderResources::PrepareDrawBindi } if (selected.empty()) return {}; Require(context.descriptorCache != nullptr, "draw snapshots require a descriptor cache"); - std::array, 2> descriptions; - std::array, 2> counts; + std::array described{}; + thread_local std::array, 2>* countsSlot = nullptr; + auto& counts = ShaderRecompiler::ThreadOwned(countsSlot); + for (auto& sizes : counts) sizes.clear(); for (const auto& binding : bindings) { const auto set = setOf(binding); - descriptions[set].push_back(binding.layout); - counts[set][binding.layout.descriptorType] += (binding.flags & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT) != 0 ? std::max(1u, static_cast(binding.imageAllocations.size())) : binding.layout.descriptorCount; + described[set] = true; + const auto count = (binding.flags & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT) != 0 ? std::max(1u, static_cast(binding.imageAllocations.size())) : binding.layout.descriptorCount; + if (count == 0) continue; + auto& sizes = counts[set]; + const auto held = std::find_if(sizes.begin(), sizes.end(), [&](const VkDescriptorPoolSize& entry) { return entry.type == binding.layout.descriptorType; }); + if (held != sizes.end()) held->descriptorCount += count; + else sizes.push_back({binding.layout.descriptorType, count}); } - const auto sizesOf = [&](std::size_t set) { - std::vector sizes; - for (const auto& [type, count] : counts[set]) { - if (count != 0) sizes.push_back({type, count}); - } - return sizes; - }; + for (auto& sizes : counts) std::sort(sizes.begin(), sizes.end(), [](const VkDescriptorPoolSize& a, const VkDescriptorPoolSize& b) { return a.type < b.type; }); + const auto sizesOf = [&](std::size_t set) { return std::span(counts[set]); }; const auto variableOf = [&](std::size_t set) { return tableBindings[set] != std::numeric_limits::max() ? std::optional(std::max(1u, static_cast(bindings[tableBindings[set]].imageAllocations.size()))) : std::nullopt; }; result->cache = context.descriptorCache; - if (!descriptions[0].empty() || splitSets) { + if (described[0] || splitSets) { result->allocation = result->cache->AllocateRewritten(_layout, sizesOf(0), updateAfterBind, variableOf(0)); result->layout = _layout; Require(result->allocation.set != VK_NULL_HANDLE, "draw snapshot descriptor allocation failed"); } - if (!descriptions[1].empty() || splitSets) { + if (described[1] || splitSets) { result->fragmentAllocation = result->cache->AllocateRewritten(fragment.layout, sizesOf(1), updateAfterBind, variableOf(1)); result->fragmentLayout = fragment.layout; Require(result->fragmentAllocation.set != VK_NULL_HANDLE, "draw snapshot descriptor allocation failed"); } - auto buffers = descriptorBuffers; - auto writes = descriptorWrites; - std::vector snapshotIndices(allocations.size(), selected.size()); + thread_local std::vector* buffersSlot = nullptr; + auto& buffers = ShaderRecompiler::ThreadOwned(buffersSlot); + buffers = descriptorBuffers; + thread_local std::vector* writesSlot = nullptr; + auto& writes = ShaderRecompiler::ThreadOwned(writesSlot); + writes = descriptorWrites; + thread_local std::vector* indicesSlot = nullptr; + auto& snapshotIndices = ShaderRecompiler::ThreadOwned(indicesSlot); + snapshotIndices.assign(allocations.size(), selected.size()); for (std::size_t index = 0; index < selected.size(); ++index) snapshotIndices[selected[index]] = index; auto nextWrite = writes.begin(); for (const auto& binding : bindings) {