mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
A graphics pipeline the store builds or a compute pipeline a dispatch builds is appended to pipelines.journal next to the shader cache entries, as the materialized result of each stage (the specialized SPIR-V, bindings and push constants) plus the recipe the pipeline was built from: the stages' identities, vertex input layout, descriptor set layout keys and the state fields the Pipeline constructor reads. When a VulkanDevice is created with a window (a headless device waits for its first draw or dispatch, since the window's device usually replaces it first) the journal is loaded and its pipelines are built on a pool of threads while the title loads, so the first draw or dispatch of a configuration seen on an earlier run finds its pipeline resident instead of compiling it on the queue worker. The pipeline stores key on RecompileResult::Identity, a hash of the module words, specialization constants, subgroup width and bindings that is the same on every run (SharedSpirv::ContentHash, computed once per shared module), rather than on the process-lifetime variant ids; a generated stage is keyed like any other. CachedPipeline builds outside the store's mutex and the library parts and link are built outside the library store's mutex, so replay threads and queue workers build in parallel; a concurrent build of the same key keeps the first inserted. A replayed pipeline enters the store at its least recently used end and a full store takes none, and its optimized relink waits for the first draw that binds it, so the title's own pipelines come first in both. The compute pipeline creation moves into VulkanDevice::createComputePipeline, shared by dispatches and the replay. The store key also covers the color component mapping, the depth target's sample count and a depth bias clamp, which the constructor reads. The file names the device it was written for (the properties the driver's pipeline cache file is named by) and starts over for another; a torn tail is cut at a record boundary; two runs sharing the directory take turns on a lock file and keep each other's records; a read failure never starts the file over. A device cancels its replay before it is replaced or destroyed, and a replaced device destroys its pipelines then rather than at the driver's stop. APS5_NO_PIPELINE_JOURNAL=1 disables it; APS5_PIPELINE_JOURNAL_THREADS, APS5_PIPELINE_JOURNAL_ENTRIES (the first recorded), APS5_PIPELINE_STORE_ENTRIES and APS5_PIPELINE_JOURNAL_MAX_MIB bound it; APS5_PROFILE_DRAW prints a [pipeline-journal] summary. APS5_VERIFY_SET_LAYOUTS=1 now also checks a dispatch's set layout against the one described from its shader. The lavapipe test suite, which shares one cache directory, runs with the journal off except for the journal's own tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P6hw3kRAuQdfcU9YCZgaoK
81 lines
3.1 KiB
C++
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, std::shared_ptr<const void> owner = nullptr);
|
|
|
|
[[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
|