mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-18 23:07:07 -05:00
perf(agc): load the pipeline cache file only on the windowed device and save without re-reading an unchanged file
The headless device is replaced by the windowed one at window attach and then only lingers for in-flight workers, but it parsed its own full copy of the cache file. It now starts empty (it still merges what it compiles into the file). Load reuses the file buffer as the initial data instead of copying it, and save() writes the live data directly when the file still carries the header this object loaded or wrote, skipping the read-back and the merge cache.
This commit is contained in:
1 parent
8dc92ae290
commit
d65cc07a1b
4 files changed
+35
-11
No files matched your search
@@ -1839,7 +1839,7 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
|
||||
Graphics::PrepareImportWatch(graphicsContext());
|
||||
state->bufferPool = std::make_shared<Graphics::BufferPool>(graphicsContext());
|
||||
state->emptyBuffer = std::make_unique<Graphics::Buffer>(graphicsContext(), Graphics::EmptyBufferBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
||||
state->pipelineCache = std::make_unique<Graphics::PipelineCache>(graphicsContext(), state->properties);
|
||||
state->pipelineCache = std::make_unique<Graphics::PipelineCache>(graphicsContext(), state->properties, window != nullptr || compileOnly);
|
||||
state->detiler = std::make_unique<Graphics::TextureDetiler>(graphicsContext());
|
||||
state->textureCache = std::make_unique<Graphics::TextureCache>(graphicsContext());
|
||||
state->colorTransfer = std::make_unique<Graphics::GpuColorTransfer>(graphicsContext());
|
||||
|
||||
@@ -18,7 +18,7 @@ class PipelineCache {
|
||||
public:
|
||||
static constexpr int SaveIntervalSeconds = 10;
|
||||
|
||||
PipelineCache(const Context& context, const VkPhysicalDeviceProperties& properties);
|
||||
PipelineCache(const Context& context, const VkPhysicalDeviceProperties& properties, bool loadFromFile = true);
|
||||
~PipelineCache();
|
||||
|
||||
PipelineCache(const PipelineCache&) = delete;
|
||||
|
||||
@@ -35,7 +35,7 @@ std::mutex& pathMutex(const std::filesystem::path& path) {
|
||||
|
||||
}
|
||||
|
||||
PipelineCache::PipelineCache(const Context& context, const VkPhysicalDeviceProperties& properties) : context(context), properties(properties) {
|
||||
PipelineCache::PipelineCache(const Context& context, const VkPhysicalDeviceProperties& properties, bool loadFromFile) : context(context), properties(properties) {
|
||||
static_assert(sizeof(FileHeader) == 24);
|
||||
const auto directory = ShaderRecompiler::ShaderCacheDirectory();
|
||||
if (!directory.empty()) {
|
||||
@@ -52,7 +52,7 @@ PipelineCache::PipelineCache(const Context& context, const VkPhysicalDevicePrope
|
||||
std::vector<std::byte> initialData;
|
||||
if (!path.empty()) {
|
||||
std::lock_guard pathLock(pathMutex(path));
|
||||
load(initialData);
|
||||
if (loadFromFile) load(initialData);
|
||||
}
|
||||
VkPipelineCacheCreateInfo info{VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO};
|
||||
info.initialDataSize = initialData.size();
|
||||
@@ -145,7 +145,7 @@ std::optional<PipelineCache::FileHeader> PipelineCache::readHeader() const {
|
||||
}
|
||||
|
||||
void PipelineCache::load(std::vector<std::byte>& initialData) {
|
||||
const auto file = readFile();
|
||||
auto file = readFile();
|
||||
if (file.state == FileState::Missing) return;
|
||||
if (file.state == FileState::Unreadable) {
|
||||
std::fprintf(stderr, "[pipeline-cache] cannot read %s; starting empty\n", path.string().c_str());
|
||||
@@ -155,8 +155,8 @@ void PipelineCache::load(std::vector<std::byte>& initialData) {
|
||||
std::fprintf(stderr, "[pipeline-cache] ignoring %s: %s\n", path.string().c_str(), file.invalidReason);
|
||||
return;
|
||||
}
|
||||
const auto data = file.Payload();
|
||||
initialData.assign(data.begin(), data.end());
|
||||
initialData = std::move(file.contents);
|
||||
initialData.erase(initialData.begin(), initialData.begin() + sizeof(FileHeader));
|
||||
loadedBytes = initialData.size();
|
||||
settledBytes = initialData.size();
|
||||
settledFile = file.header;
|
||||
@@ -171,20 +171,22 @@ void PipelineCache::save(bool final) {
|
||||
auto synchronizationLock = synchronization.LockForSnapshot();
|
||||
if (getData(context.device, cache, &liveBytes, nullptr) != VK_SUCCESS || liveBytes == 0) return;
|
||||
}
|
||||
if (liveBytes == settledBytes && readHeader() == settledFile) return;
|
||||
const auto onDisk = readHeader();
|
||||
if (liveBytes == settledBytes && onDisk == settledFile) return;
|
||||
const bool fileUnchanged = settledFile.has_value() && onDisk == settledFile;
|
||||
const auto started = std::chrono::steady_clock::now();
|
||||
const auto settle = [&](const std::optional<FileHeader>& file) {
|
||||
settledBytes = liveBytes;
|
||||
settledFile = file;
|
||||
};
|
||||
const auto disk = readFile();
|
||||
const auto disk = fileUnchanged ? File{} : readFile();
|
||||
if (disk.state == FileState::Unreadable) {
|
||||
std::fprintf(stderr, "[pipeline-cache] cannot read %s; not saving over it\n", path.string().c_str());
|
||||
settle(readHeader());
|
||||
return;
|
||||
}
|
||||
if (disk.state == FileState::Invalid) std::fprintf(stderr, "[pipeline-cache] replacing %s: %s\n", path.string().c_str(), disk.invalidReason);
|
||||
std::size_t floor = 0;
|
||||
std::size_t floor = fileUnchanged ? std::max<std::size_t>(loadedBytes, settledFile->dataBytes) : 0;
|
||||
VkPipelineCache merged = VK_NULL_HANDLE;
|
||||
struct DestroyMerged {
|
||||
const Context& context;
|
||||
@@ -231,7 +233,7 @@ void PipelineCache::save(bool final) {
|
||||
}
|
||||
if (size < floor) {
|
||||
std::fprintf(stderr, "[pipeline-cache] keeping %s: the merged cache has %.1f KiB, less than the %.1f KiB on disk or loaded at start\n", path.string().c_str(), static_cast<double>(size) / 1024.0, static_cast<double>(floor) / 1024.0);
|
||||
settle(disk.header);
|
||||
settle(fileUnchanged ? *settledFile : disk.header);
|
||||
return;
|
||||
}
|
||||
const FileHeader header{FileMagic, FileFormat, size, ShaderRecompiler::HashBytes(std::span(file).subspan(sizeof(FileHeader)))};
|
||||
|
||||
@@ -7429,6 +7429,28 @@ int pipelineCacheFileTests(const Device& device) {
|
||||
PipelineCache idle(context, properties);
|
||||
}
|
||||
Require(contents(path) == stored, "an object that added no pipelines rewrote the cache file");
|
||||
{
|
||||
PipelineCache unseeded(context, properties, false);
|
||||
Require(!holds(unseeded.Handle(), 0), "a cache created without the file already held a pipeline of the file");
|
||||
}
|
||||
{
|
||||
PipelineCache reloaded(context, properties);
|
||||
Require(holds(reloaded.Handle(), 0) && holds(reloaded.Handle(), 1), "an unseeded cache dropped pipelines from the cache file when it saved");
|
||||
}
|
||||
std::filesystem::remove_all(directory);
|
||||
{
|
||||
PipelineCache writer(context, properties);
|
||||
build(writer.Handle(), 0);
|
||||
}
|
||||
{
|
||||
PipelineCache extender(context, properties);
|
||||
Require(holds(extender.Handle(), 0), "the cache file lost a pipeline");
|
||||
build(extender.Handle(), 1);
|
||||
}
|
||||
{
|
||||
PipelineCache reloaded(context, properties);
|
||||
Require(holds(reloaded.Handle(), 0) && holds(reloaded.Handle(), 1), "a cache that saved over an unchanged file lost pipelines");
|
||||
}
|
||||
{
|
||||
std::ofstream corrupt(path, std::ios::binary | std::ios::trunc);
|
||||
corrupt << "not a pipeline cache";
|
||||
|
||||
Reference in new issue
Block a user