Files
AnyPS5/core/shader/recompiler/ShaderDiskCache.hpp
T
4651980eba perf(agc): cheaper shader-memory captures per draw
The per-draw capture of a shader's memory (the SRT walk and the guest pages it reads) cost about
15 us per draw packet in GTA V Performance mode; it now costs about 6.6.

- The SRT evaluator memoizes per plan value in a thread's reused, stamped array instead of a hash
  table allocated and grown on every walk (evaluate 5.3 -> 3.6 us per capture).
- ExtractPlan also stores the plan's values as 32-byte records with argument ids, and the walk
  evaluates that compact copy: the IR walk spent most of its time in cache misses (3.6 -> 2.7 us).
  The evaluator is a template over the node view, so both walks share every opcode's semantics, memo,
  cycle and failure rules. A plan that cannot be expressed compactly keeps the IR walk.
  APS5_VERIFY_SRT_COMPACT=1 walks both and throws on any difference.
- ShaderMemory's valid/read/recent marks are arrays of 64-bit words scanned with countr_zero instead
  of bitsets tested bit by bit (about 1 us per draw packet).
- Captured pages come from a per-thread pool, are found through a short vector with a last-page
  shortcut, and a page no recorded GPU work writes gets the flush hook a whole-page read would make,
  then has each 64-byte block copied when a word of it is first read (about 0.3 us per packet).
  Pages with pending GPU writes and unmapped pages are read as before.
- APS5_PROFILE_DRAW splits the capture time into SRT evaluation and materialization, and prints the
  [capture] line once per 10 s instead of every 500 captures (it cost about 2 us per capture).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Co-Authored-By: Gjon Gojcevic <[email protected]>
2026-10-15 11:11:24 +02:00

81 lines
3.1 KiB
C++

#ifndef CORE_SHADER_RECOMPILER_SHADERDISKCACHE_HPP
#define CORE_SHADER_RECOMPILER_SHADERDISKCACHE_HPP
#include "CompiledVariant.hpp"
#include "IntermediateRepresentation/IrMetadata/ResourcePlan.hpp"
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <memory>
#include <span>
#include <string>
#include <vector>
namespace ShaderRecompiler::ShaderDiskCache {
inline constexpr std::uint32_t FormatVersion = 36;
enum class LoadStatus {
Loaded,
Absent,
KeyMismatch,
Rejected,
};
struct Counters {
std::uint64_t hits = 0;
std::uint64_t misses = 0;
std::uint64_t writes = 0;
std::uint64_t loadFailures = 0;
std::uint64_t writeFailures = 0;
std::uint64_t bytesRead = 0;
std::uint64_t bytesWritten = 0;
std::uint64_t planHits = 0;
std::uint64_t planMisses = 0;
std::uint64_t planWrites = 0;
std::uint64_t planLoadFailures = 0;
std::uint64_t prebuiltHits = 0;
std::uint64_t prebuiltMisses = 0;
std::uint64_t prebuiltRejected = 0;
std::uint64_t lookupNanoseconds = 0;
std::uint64_t readNanoseconds = 0;
std::uint64_t decodeNanoseconds = 0;
std::uint64_t loadNanoseconds = 0;
std::uint64_t maxLoadNanoseconds = 0;
std::uint64_t prebuiltBytesRead = 0;
std::uint64_t prebuiltLoadNanoseconds = 0;
};
[[nodiscard]] std::uint64_t SourceVersion();
void BuildKey(const RecompileRequest& request, std::uint32_t hostSubgroupSize, std::vector<std::byte>& key);
[[nodiscard]] std::string EntryName(std::span<const std::byte> key);
void EncodeResult(const RecompileResult& result, std::vector<std::byte>& out);
[[nodiscard]] bool DecodeResult(std::span<const std::byte> bytes, RecompileResult& result);
[[nodiscard]] std::vector<std::byte> EncodeEntry(std::span<const std::byte> key, const CompiledVariant& variant);
[[nodiscard]] LoadStatus DecodeEntry(std::span<const std::byte> file, std::span<const std::byte> key, CompiledVariant& variant, std::shared_ptr<const void> owner = nullptr);
void BuildPlanKey(const RecompileRequest& request, std::uint32_t hostSubgroupSize, std::vector<std::byte>& key);
[[nodiscard]] bool EncodePlan(const IrResourcePlan& plan, std::vector<std::byte>& out);
[[nodiscard]] bool DecodePlan(std::span<const std::byte> bytes, IrResourcePlan& plan);
[[nodiscard]] std::vector<std::byte> EncodePlanEntry(std::span<const std::byte> key, const IrResourcePlan& plan);
[[nodiscard]] LoadStatus DecodePlanEntry(std::span<const std::byte> file, std::span<const std::byte> key, IrResourcePlan& plan);
[[nodiscard]] bool Enabled();
[[nodiscard]] std::filesystem::path EntryDirectory();
[[nodiscard]] bool Load(std::span<const std::byte> key, CompiledVariant& variant);
void Store(std::vector<std::byte> key, std::shared_ptr<const CompiledVariant> variant);
[[nodiscard]] std::shared_ptr<const CompiledVariant> Persist(std::span<const std::byte> key, const CompiledVariant& variant);
[[nodiscard]] bool LoadPlan(std::span<const std::byte> key, IrResourcePlan& plan);
void StorePlan(std::vector<std::byte> key, std::shared_ptr<const IrResourcePlan> plan);
void Flush();
[[nodiscard]] Counters Totals();
}
#endif