mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
fix(shader): key the device's capabilities and extensions by a digest
Every recompile cache key appended the target's capability list and each SPIR-V extension name one byte per 64-bit word, so on a device that enables a few dozen extensions most of every key was the same device description: built and compared on every dispatch and draw, and kept in every in-memory key and disk cache entry. The two lists now enter the key as a 128-bit digest over the capabilities and the length and bytes of each extension name, eight bytes per step. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
3b23d18360
commit
d7d9747e7d
2 files changed
+62
-2
No files matched your search
@@ -1713,6 +1713,41 @@ std::array<std::uint32_t, 8> TableSelected(const ShaderRecompiler::ImageTableSna
|
||||
return column.words.at(column.codes[0]).dwords;
|
||||
}
|
||||
|
||||
void verifyTargetFeatureKey() {
|
||||
using namespace ShaderRecompiler;
|
||||
static constexpr std::array<std::uint32_t, 1> code{0xbf810000u};
|
||||
RecompileRequest request{};
|
||||
request.shader = {ShaderStage::Compute, 0x10000u, code, 0, {}};
|
||||
request.context.waveSize = 64;
|
||||
const std::vector<std::uint32_t> capabilities{1u, 4448u, 5347u};
|
||||
const std::vector<std::string_view> extensions{"SPV_KHR_8bit_storage", "SPV_KHR_physical_storage_buffer"};
|
||||
const auto build = [&](std::span<const std::uint32_t> capabilityList, std::span<const std::string_view> extensionList) {
|
||||
auto keyed = request;
|
||||
keyed.target.supportedCapabilities = capabilityList;
|
||||
keyed.target.supportedExtensions = extensionList;
|
||||
std::vector<std::uint64_t> key;
|
||||
RecompileCacheKey::Build(keyed, key);
|
||||
return key;
|
||||
};
|
||||
const auto base = build(capabilities, extensions);
|
||||
const std::vector<std::uint32_t> capabilityCopy = capabilities;
|
||||
const std::vector<std::string> extensionStorage{"SPV_KHR_8bit_storage", "SPV_KHR_physical_storage_buffer"};
|
||||
const std::vector<std::string_view> extensionCopy{extensionStorage[0], extensionStorage[1]};
|
||||
require(build(capabilityCopy, extensionCopy) == base, "target feature key: equal capability and extension lists in other storage gave another key");
|
||||
auto renamed = extensionStorage;
|
||||
renamed[1].back() = 'X';
|
||||
const std::vector<std::string_view> renamedViews{renamed[0], renamed[1]};
|
||||
require(build(capabilities, renamedViews) != base, "target feature key: an extension name that differs in its last byte gave the same key");
|
||||
const std::vector<std::string_view> moved{"SPV_KHR_8bit_storageS", "PV_KHR_physical_storage_buffer"};
|
||||
require(build(capabilities, moved) != base, "target feature key: a byte moved between two extension names gave the same key");
|
||||
const std::vector<std::uint32_t> more{1u, 4448u, 5347u, 11u};
|
||||
require(build(more, extensions) != base, "target feature key: an added capability gave the same key");
|
||||
std::vector<std::string> many;
|
||||
for (std::uint32_t index = 0; index < 40u; ++index) many.push_back("SPV_EXT_descriptor_indexing_" + std::to_string(index));
|
||||
const std::vector<std::string_view> manyViews(many.begin(), many.end());
|
||||
require(build(capabilities, manyViews).size() == base.size(), "target feature key: the key grows with the device's extension names");
|
||||
}
|
||||
|
||||
void verifyImageTableKeys() {
|
||||
using namespace ShaderRecompiler;
|
||||
namespace Abi = ImageTableAbi;
|
||||
@@ -8377,6 +8412,7 @@ int main(int argc, char** argv) {
|
||||
verifyGuardedDescriptorSources();
|
||||
verifyLaneMaskGuardedDescriptorSources();
|
||||
verifySrtTape();
|
||||
verifyTargetFeatureKey();
|
||||
verifyImageTableKeys();
|
||||
verifyImageTables();
|
||||
verifyImageTableRegistration();
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
#include "Recompiler.hpp"
|
||||
#include "RdnaDecoder/RdnaDescriptorFormat.hpp"
|
||||
#include "prx/libc/include/HostThreadLocal.hpp"
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -275,13 +277,35 @@ private:
|
||||
append(key, value.maxEvaluationOutputComponents);
|
||||
}
|
||||
|
||||
static void appendFeatureDigest(std::vector<std::uint64_t>& key, std::span<const std::uint32_t> capabilities, std::span<const std::string_view> extensions) {
|
||||
std::uint64_t low = 0xcbf29ce484222325ull;
|
||||
std::uint64_t high = 0x6a09e667f3bcc909ull;
|
||||
const auto mix = [&](std::uint64_t value) {
|
||||
low = (low ^ value) * 0x100000001b3ull;
|
||||
high = (high ^ (value * 0x9e3779b97f4a7c15ull)) * 0xff51afd7ed558ccdull;
|
||||
high ^= high >> 29u;
|
||||
};
|
||||
mix(capabilities.size());
|
||||
for (const auto capability : capabilities) mix(capability);
|
||||
mix(extensions.size());
|
||||
for (const auto extension : extensions) {
|
||||
mix(extension.size());
|
||||
for (std::size_t offset = 0; offset < extension.size(); offset += sizeof(std::uint64_t)) {
|
||||
std::uint64_t chunk = 0;
|
||||
std::memcpy(&chunk, extension.data() + offset, std::min(sizeof(std::uint64_t), extension.size() - offset));
|
||||
mix(chunk);
|
||||
}
|
||||
}
|
||||
key.push_back(low);
|
||||
key.push_back(high);
|
||||
}
|
||||
|
||||
static void append(std::vector<std::uint64_t>& key, const SpirvTarget& value) {
|
||||
append(key, value.vulkanVersion);
|
||||
append(key, value.spirvVersion);
|
||||
append(key, value.subgroupSize);
|
||||
append(key, value.bdaAbiVersion);
|
||||
append(key, value.supportedCapabilities);
|
||||
append(key, value.supportedExtensions);
|
||||
appendFeatureDigest(key, value.supportedCapabilities, value.supportedExtensions);
|
||||
append(key, value.fragmentShaderBarycentricEnabled);
|
||||
append(key, value.maxWorkgroupSize);
|
||||
append(key, value.maxWorkgroupInvocations);
|
||||
|
||||
Reference in new issue
Block a user