mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2026-04-10 19:31:31 -06:00
video_core: Fixes to vulkan disk cache (#1748)
This commit is contained in:
parent
5d4aef81fe
commit
c43f24e489
@ -1254,20 +1254,19 @@ static std::size_t pread(int fd, void* buf, std::size_t count, uint64_t offset)
|
||||
#define pread ::pread
|
||||
#endif
|
||||
|
||||
std::size_t IOFile::ReadAtImpl(void* data, std::size_t length, std::size_t data_size,
|
||||
std::size_t offset) {
|
||||
std::size_t IOFile::ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) {
|
||||
if (!IsOpen()) {
|
||||
m_good = false;
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
if (byte_count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_ASSERT(data != nullptr);
|
||||
|
||||
return pread(fileno(m_file), data, data_size * length, offset);
|
||||
return pread(fileno(m_file), data, byte_count, offset);
|
||||
}
|
||||
|
||||
std::size_t IOFile::WriteImpl(const void* data, std::size_t length, std::size_t data_size) {
|
||||
@ -1315,19 +1314,19 @@ struct CryptoIOFileImpl {
|
||||
std::size_t res = f.IOFile::ReadImpl(data, length, data_size);
|
||||
if (res != std::numeric_limits<std::size_t>::max() && res != 0) {
|
||||
d.ProcessData(reinterpret_cast<CryptoPP::byte*>(data),
|
||||
reinterpret_cast<CryptoPP::byte*>(data), length * data_size);
|
||||
reinterpret_cast<CryptoPP::byte*>(data), res * data_size);
|
||||
e.Seek(f.IOFile::Tell());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::size_t ReadAtImpl(CryptoIOFile& f, void* data, std::size_t length, std::size_t data_size,
|
||||
std::size_t ReadAtImpl(CryptoIOFile& f, void* data, std::size_t byte_count,
|
||||
std::size_t offset) {
|
||||
std::size_t res = f.IOFile::ReadAtImpl(data, length, data_size, offset);
|
||||
std::size_t res = f.IOFile::ReadAtImpl(data, byte_count, offset);
|
||||
if (res != std::numeric_limits<std::size_t>::max() && res != 0) {
|
||||
d.Seek(offset);
|
||||
d.ProcessData(reinterpret_cast<CryptoPP::byte*>(data),
|
||||
reinterpret_cast<CryptoPP::byte*>(data), length * data_size);
|
||||
reinterpret_cast<CryptoPP::byte*>(data), res);
|
||||
e.Seek(f.IOFile::Tell());
|
||||
}
|
||||
return res;
|
||||
@ -1378,9 +1377,8 @@ std::size_t CryptoIOFile::ReadImpl(void* data, std::size_t length, std::size_t d
|
||||
return impl->ReadImpl(*this, data, length, data_size);
|
||||
}
|
||||
|
||||
std::size_t CryptoIOFile::ReadAtImpl(void* data, std::size_t length, std::size_t data_size,
|
||||
std::size_t offset) {
|
||||
return impl->ReadAtImpl(*this, data, length, data_size, offset);
|
||||
std::size_t CryptoIOFile::ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) {
|
||||
return impl->ReadAtImpl(*this, data, byte_count, offset);
|
||||
}
|
||||
|
||||
std::size_t CryptoIOFile::WriteImpl(const void* data, std::size_t length, std::size_t data_size) {
|
||||
|
||||
@ -302,6 +302,7 @@ public:
|
||||
|
||||
virtual bool Close();
|
||||
|
||||
/// Returns the amount of T items read
|
||||
template <typename T>
|
||||
std::size_t ReadArray(T* data, std::size_t length) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
@ -314,16 +315,18 @@ public:
|
||||
return items_read;
|
||||
}
|
||||
|
||||
/// Returns the amount of bytes read
|
||||
template <typename T>
|
||||
std::size_t ReadAtArray(T* data, std::size_t length, std::size_t offset) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"Given array does not consist of trivially copyable objects");
|
||||
|
||||
std::size_t items_read = ReadAtImpl(data, length, sizeof(T), offset);
|
||||
if (items_read != length)
|
||||
const size_t bytes = length * sizeof(T);
|
||||
std::size_t size_read = ReadAtImpl(data, bytes, offset);
|
||||
if (size_read != bytes)
|
||||
m_good = false;
|
||||
|
||||
return items_read;
|
||||
return size_read;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -466,8 +469,7 @@ protected:
|
||||
virtual bool Open();
|
||||
|
||||
virtual std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size);
|
||||
virtual std::size_t ReadAtImpl(void* data, std::size_t length, std::size_t data_size,
|
||||
std::size_t offset);
|
||||
virtual std::size_t ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset);
|
||||
virtual std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size);
|
||||
|
||||
virtual bool SeekImpl(s64 off, int origin);
|
||||
@ -520,8 +522,7 @@ private:
|
||||
std::unique_ptr<CryptoIOFileImpl> impl;
|
||||
|
||||
std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size) override;
|
||||
std::size_t ReadAtImpl(void* data, std::size_t length, std::size_t data_size,
|
||||
std::size_t offset) override;
|
||||
std::size_t ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) override;
|
||||
std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size) override;
|
||||
|
||||
bool SeekImpl(s64 off, int origin) override;
|
||||
|
||||
@ -357,8 +357,7 @@ std::size_t Z3DSWriteIOFile::ReadImpl(void* data, std::size_t length, std::size_
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t Z3DSWriteIOFile::ReadAtImpl(void* data, std::size_t length, std::size_t data_size,
|
||||
std::size_t offset) {
|
||||
std::size_t Z3DSWriteIOFile::ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) {
|
||||
// Stubbed
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
@ -619,12 +618,12 @@ bool Z3DSReadIOFile::Open() {
|
||||
}
|
||||
|
||||
std::size_t Z3DSReadIOFile::ReadImpl(void* data, std::size_t length, std::size_t data_size) {
|
||||
return impl->Read(data, length * data_size);
|
||||
size_t res = impl->Read(data, length * data_size);
|
||||
return res == std::numeric_limits<size_t>::max() ? res : (res / data_size);
|
||||
}
|
||||
|
||||
std::size_t Z3DSReadIOFile::ReadAtImpl(void* data, std::size_t length, std::size_t data_size,
|
||||
std::size_t offset) {
|
||||
return impl->ReadAt(data, length * data_size, offset);
|
||||
std::size_t Z3DSReadIOFile::ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) {
|
||||
return impl->ReadAt(data, byte_count, offset);
|
||||
}
|
||||
|
||||
std::size_t Z3DSReadIOFile::WriteImpl(const void* data, std::size_t length, std::size_t data_size) {
|
||||
|
||||
@ -183,8 +183,7 @@ private:
|
||||
bool Open() override;
|
||||
|
||||
std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size) override;
|
||||
std::size_t ReadAtImpl(void* data, std::size_t length, std::size_t data_size,
|
||||
std::size_t offset) override;
|
||||
std::size_t ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) override;
|
||||
std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size) override;
|
||||
|
||||
bool SeekImpl(s64 off, int origin) override;
|
||||
@ -250,8 +249,7 @@ private:
|
||||
bool Open() override;
|
||||
|
||||
std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size) override;
|
||||
std::size_t ReadAtImpl(void* data, std::size_t length, std::size_t data_size,
|
||||
std::size_t offset) override;
|
||||
std::size_t ReadAtImpl(void* data, std::size_t byte_count, std::size_t offset) override;
|
||||
std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size) override;
|
||||
|
||||
bool SeekImpl(s64 off, int origin) override;
|
||||
|
||||
@ -168,7 +168,6 @@ Loader::ResultStatus NCCHContainer::LoadHeader() {
|
||||
ASSERT(Loader::MakeMagic('N', 'C', 'S', 'D') == ncsd_header.magic);
|
||||
ASSERT(partition < 8);
|
||||
ncch_offset = ncsd_header.partitions[partition].offset * kBlockSize;
|
||||
LOG_ERROR(Service_FS, "{}", ncch_offset);
|
||||
file->Seek(ncch_offset, SEEK_SET);
|
||||
file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
|
||||
}
|
||||
|
||||
@ -144,24 +144,59 @@ void PipelineCache::BuildLayout() {
|
||||
}
|
||||
|
||||
PipelineCache::~PipelineCache() {
|
||||
SaveDiskCache();
|
||||
workers.WaitForRequests();
|
||||
SaveDriverPipelineDiskCache();
|
||||
}
|
||||
|
||||
void PipelineCache::LoadPipelineDiskCache(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
void PipelineCache::LoadCache(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
LoadDriverPipelineDiskCache(stop_loading, callback);
|
||||
LoadDiskCache(stop_loading, callback);
|
||||
}
|
||||
|
||||
void PipelineCache::SwitchCache(u64 title_id, const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
if (GetProgramID() == title_id) {
|
||||
LOG_DEBUG(Render_Vulkan,
|
||||
"Skipping pipeline cache switch - already using cache for title_id={:016X}",
|
||||
title_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we have a valid pipeline cache before switching
|
||||
if (!driver_pipeline_cache) {
|
||||
vk::PipelineCacheCreateInfo cache_info{};
|
||||
try {
|
||||
driver_pipeline_cache = instance.GetDevice().createPipelineCacheUnique(cache_info);
|
||||
} catch (const vk::SystemError& err) {
|
||||
LOG_ERROR(Render_Vulkan, "Failed to create pipeline cache: {}", err.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO(Render_Vulkan, "Switching pipeline cache to title_id={:016X}", title_id);
|
||||
|
||||
// Save current driver cache, update program ID and load the new driver cache
|
||||
SaveDriverPipelineDiskCache();
|
||||
SetProgramID(title_id);
|
||||
LoadDriverPipelineDiskCache(stop_loading, nullptr);
|
||||
|
||||
// Switch the disk shader cache after driver cache is switched
|
||||
SwitchDiskCache(title_id, stop_loading, callback);
|
||||
}
|
||||
|
||||
void PipelineCache::LoadDriverPipelineDiskCache(
|
||||
const std::atomic_bool& stop_loading, const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
vk::PipelineCacheCreateInfo cache_info{};
|
||||
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Prepare, 0, 0, "");
|
||||
}
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Build, 0, 1, "Driver Pipeline Cache");
|
||||
}
|
||||
|
||||
auto load_cache = [this, &cache_info](bool allow_fallback) {
|
||||
auto load_cache = [this, &cache_info, &callback](bool allow_fallback) {
|
||||
const vk::Device device = instance.GetDevice();
|
||||
try {
|
||||
pipeline_cache = device.createPipelineCacheUnique(cache_info);
|
||||
driver_pipeline_cache = device.createPipelineCacheUnique(cache_info);
|
||||
} catch (const vk::SystemError& err) {
|
||||
LOG_ERROR(Render_Vulkan, "Failed to create pipeline cache: {}", err.what());
|
||||
if (allow_fallback) {
|
||||
@ -169,13 +204,16 @@ void PipelineCache::LoadPipelineDiskCache(const std::atomic_bool& stop_loading,
|
||||
cache_info.initialDataSize = 0;
|
||||
cache_info.pInitialData = nullptr;
|
||||
try {
|
||||
pipeline_cache = device.createPipelineCacheUnique(cache_info);
|
||||
driver_pipeline_cache = device.createPipelineCacheUnique(cache_info);
|
||||
} catch (const vk::SystemError& err) {
|
||||
LOG_ERROR(Render_Vulkan, "Failed to create fallback pipeline cache: {}",
|
||||
err.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Build, 1, 1, "Driver Pipeline Cache");
|
||||
}
|
||||
};
|
||||
|
||||
// Try to load existing pipeline cache if disk cache is enabled and directories exist
|
||||
@ -226,19 +264,9 @@ void PipelineCache::LoadPipelineDiskCache(const std::atomic_bool& stop_loading,
|
||||
load_cache(true);
|
||||
}
|
||||
|
||||
void PipelineCache::LoadDiskCache(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
|
||||
disk_caches.clear();
|
||||
curr_disk_cache =
|
||||
disk_caches.emplace_back(std::make_shared<ShaderDiskCache>(*this, GetProgramID()));
|
||||
|
||||
curr_disk_cache->Init(stop_loading, callback);
|
||||
}
|
||||
|
||||
void PipelineCache::SaveDiskCache() {
|
||||
void PipelineCache::SaveDriverPipelineDiskCache() {
|
||||
// Save Vulkan pipeline cache
|
||||
if (!Settings::values.use_disk_shader_cache || !pipeline_cache) {
|
||||
if (!Settings::values.use_disk_shader_cache || !driver_pipeline_cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -258,13 +286,81 @@ void PipelineCache::SaveDiskCache() {
|
||||
}
|
||||
|
||||
const vk::Device device = instance.GetDevice();
|
||||
const auto cache_data = device.getPipelineCacheData(*pipeline_cache);
|
||||
const auto cache_data = device.getPipelineCacheData(*driver_pipeline_cache);
|
||||
if (cache_file.WriteBytes(cache_data.data(), cache_data.size()) != cache_data.size()) {
|
||||
LOG_ERROR(Render_Vulkan, "Error during pipeline cache write");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PipelineCache::LoadDiskCache(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
|
||||
disk_caches.clear();
|
||||
curr_disk_cache =
|
||||
disk_caches.emplace_back(std::make_shared<ShaderDiskCache>(*this, GetProgramID()));
|
||||
|
||||
curr_disk_cache->Init(stop_loading, callback);
|
||||
}
|
||||
|
||||
void PipelineCache::SwitchDiskCache(u64 title_id, const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
// NOTE: curr_disk_cache can be null if emulation restarted without calling
|
||||
// LoadDefaultDiskResources
|
||||
|
||||
// Check if the current cache is for the specified TID.
|
||||
if (curr_disk_cache && curr_disk_cache->GetProgramID() == title_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for an existing manager
|
||||
size_t new_pos = 0;
|
||||
for (new_pos = 0; new_pos < disk_caches.size(); new_pos++) {
|
||||
if (disk_caches[new_pos]->GetProgramID() == title_id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Manager does not exist, create it and append to the end
|
||||
if (new_pos >= disk_caches.size()) {
|
||||
new_pos = disk_caches.size();
|
||||
auto& new_manager =
|
||||
disk_caches.emplace_back(std::make_shared<ShaderDiskCache>(*this, title_id));
|
||||
|
||||
new_manager->Init(stop_loading, callback);
|
||||
}
|
||||
|
||||
auto is_applet = [](u64 tid) {
|
||||
constexpr u32 APPLET_TID_HIGH = 0x00040030;
|
||||
return static_cast<u32>(tid >> 32) == APPLET_TID_HIGH;
|
||||
};
|
||||
|
||||
bool prev_applet = curr_disk_cache ? is_applet(curr_disk_cache->GetProgramID()) : false;
|
||||
bool new_applet = is_applet(disk_caches[new_pos]->GetProgramID());
|
||||
curr_disk_cache = disk_caches[new_pos];
|
||||
|
||||
if (prev_applet) {
|
||||
// If we came from an applet, clean up all other applets
|
||||
for (auto it = disk_caches.begin(); it != disk_caches.end();) {
|
||||
if (it == disk_caches.begin() || *it == curr_disk_cache ||
|
||||
!is_applet((*it)->GetProgramID())) {
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
it = disk_caches.erase(it);
|
||||
}
|
||||
}
|
||||
if (!new_applet) {
|
||||
// If we are going into a non-applet, clean up everything
|
||||
for (auto it = disk_caches.begin(); it != disk_caches.end();) {
|
||||
if (it == disk_caches.begin() || *it == curr_disk_cache) {
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
it = disk_caches.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PipelineCache::BindPipeline(PipelineInfo& info, bool wait_built) {
|
||||
MICROPROFILE_SCOPE(Vulkan_Bind);
|
||||
|
||||
@ -551,112 +647,4 @@ std::string PipelineCache::GetTransferableDir() const {
|
||||
return GetVulkanDir() + DIR_SEP + "transferable";
|
||||
}
|
||||
|
||||
void PipelineCache::SwitchPipelineCache(u64 title_id, const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
if (!Settings::values.use_disk_shader_cache || GetProgramID() == title_id) {
|
||||
LOG_DEBUG(Render_Vulkan,
|
||||
"Skipping pipeline cache switch - already using cache for title_id={:016X}",
|
||||
title_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Prepare, 0, 0, "");
|
||||
}
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Build, 0, 1, "Driver Pipeline Cache");
|
||||
}
|
||||
|
||||
// Make sure we have a valid pipeline cache before switching
|
||||
if (!pipeline_cache) {
|
||||
vk::PipelineCacheCreateInfo cache_info{};
|
||||
try {
|
||||
pipeline_cache = instance.GetDevice().createPipelineCacheUnique(cache_info);
|
||||
} catch (const vk::SystemError& err) {
|
||||
LOG_ERROR(Render_Vulkan, "Failed to create pipeline cache: {}", err.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO(Render_Vulkan, "Switching pipeline cache to title_id={:016X}", title_id);
|
||||
|
||||
// Save current cache before switching
|
||||
SaveDiskCache();
|
||||
|
||||
// Update program ID and load the new pipeline cache
|
||||
SetProgramID(title_id);
|
||||
LoadPipelineDiskCache(stop_loading, nullptr);
|
||||
SwitchDiskCache(title_id, stop_loading, callback);
|
||||
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Complete, 0, 0, "");
|
||||
}
|
||||
}
|
||||
|
||||
void PipelineCache::SwitchDiskCache(u64 title_id, const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
// NOTE: curr_disk_cache can be null if emulation restarted without calling
|
||||
// LoadDefaultDiskResources
|
||||
|
||||
// Check if the current cache is for the specified TID.
|
||||
if (curr_disk_cache && curr_disk_cache->GetProgramID() == title_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for an existing manager
|
||||
size_t new_pos = 0;
|
||||
for (new_pos = 0; new_pos < disk_caches.size(); new_pos++) {
|
||||
if (disk_caches[new_pos]->GetProgramID() == title_id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Manager does not exist, create it and append to the end
|
||||
if (new_pos >= disk_caches.size()) {
|
||||
new_pos = disk_caches.size();
|
||||
auto& new_manager =
|
||||
disk_caches.emplace_back(std::make_shared<ShaderDiskCache>(*this, title_id));
|
||||
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Prepare, 0, 0, "");
|
||||
}
|
||||
|
||||
new_manager->Init(stop_loading, callback);
|
||||
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Complete, 0, 0, "");
|
||||
}
|
||||
}
|
||||
|
||||
auto is_applet = [](u64 tid) {
|
||||
constexpr u32 APPLET_TID_HIGH = 0x00040030;
|
||||
return static_cast<u32>(tid >> 32) == APPLET_TID_HIGH;
|
||||
};
|
||||
|
||||
bool prev_applet = curr_disk_cache ? is_applet(curr_disk_cache->GetProgramID()) : false;
|
||||
bool new_applet = is_applet(disk_caches[new_pos]->GetProgramID());
|
||||
curr_disk_cache = disk_caches[new_pos];
|
||||
|
||||
if (prev_applet) {
|
||||
// If we came from an applet, clean up all other applets
|
||||
for (auto it = disk_caches.begin(); it != disk_caches.end();) {
|
||||
if (it == disk_caches.begin() || *it == curr_disk_cache ||
|
||||
!is_applet((*it)->GetProgramID())) {
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
it = disk_caches.erase(it);
|
||||
}
|
||||
}
|
||||
if (!new_applet) {
|
||||
// If we are going into a non-applet, clean up everything
|
||||
for (auto it = disk_caches.begin(); it != disk_caches.end();) {
|
||||
if (it == disk_caches.begin() || *it == curr_disk_cache) {
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
it = disk_caches.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@ -58,15 +58,13 @@ public:
|
||||
offsets[binding] = offset;
|
||||
}
|
||||
|
||||
/// Loads the pipeline cache stored to disk
|
||||
void LoadPipelineDiskCache(const std::atomic_bool& stop_loading = std::atomic_bool{false},
|
||||
const VideoCore::DiskResourceLoadCallback& callback = {});
|
||||
/// Loads the driver pipeline cache and the disk shader cache
|
||||
void LoadCache(const std::atomic_bool& stop_loading = std::atomic_bool{false},
|
||||
const VideoCore::DiskResourceLoadCallback& callback = {});
|
||||
|
||||
void LoadDiskCache(const std::atomic_bool& stop_loading = std::atomic_bool{false},
|
||||
const VideoCore::DiskResourceLoadCallback& callback = {});
|
||||
|
||||
/// Stores the generated pipeline cache to disk
|
||||
void SaveDiskCache();
|
||||
/// Switches the driver pipeline cache and the shader disk cache to the specified title
|
||||
void SwitchCache(u64 title_id, const std::atomic_bool& stop_loading = std::atomic_bool{false},
|
||||
const VideoCore::DiskResourceLoadCallback& callback = {});
|
||||
|
||||
/// Binds a pipeline using the provided information
|
||||
bool BindPipeline(PipelineInfo& info, bool wait_built = false);
|
||||
@ -90,11 +88,6 @@ public:
|
||||
/// Binds a fragment shader generated from PICA state
|
||||
void UseFragmentShader(const Pica::RegsInternal& regs, const Pica::Shader::UserConfig& user);
|
||||
|
||||
/// Switches the shader disk cache to the specified title
|
||||
void SwitchPipelineCache(u64 title_id,
|
||||
const std::atomic_bool& stop_loading = std::atomic_bool{false},
|
||||
const VideoCore::DiskResourceLoadCallback& callback = {});
|
||||
|
||||
/// Gets the current program ID
|
||||
u64 GetProgramID() const {
|
||||
return current_program_id;
|
||||
@ -111,6 +104,17 @@ public:
|
||||
private:
|
||||
friend ShaderDiskCache;
|
||||
|
||||
/// Loads the driver pipeline cache
|
||||
void LoadDriverPipelineDiskCache(const std::atomic_bool& stop_loading = std::atomic_bool{false},
|
||||
const VideoCore::DiskResourceLoadCallback& callback = {});
|
||||
|
||||
/// Stores the generated pipeline cache
|
||||
void SaveDriverPipelineDiskCache();
|
||||
|
||||
/// Loads the shader disk cache
|
||||
void LoadDiskCache(const std::atomic_bool& stop_loading = std::atomic_bool{false},
|
||||
const VideoCore::DiskResourceLoadCallback& callback = {});
|
||||
|
||||
/// Switches the disk cache at runtime to use a different title ID
|
||||
void SwitchDiskCache(u64 title_id, const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback);
|
||||
@ -140,7 +144,7 @@ private:
|
||||
DescriptorUpdateQueue& update_queue;
|
||||
|
||||
Pica::Shader::Profile profile{};
|
||||
vk::UniquePipelineCache pipeline_cache;
|
||||
vk::UniquePipelineCache driver_pipeline_cache;
|
||||
vk::UniquePipelineLayout pipeline_layout;
|
||||
std::size_t num_worker_threads;
|
||||
Common::ThreadWorker workers;
|
||||
|
||||
@ -152,10 +152,13 @@ void RasterizerVulkan::LoadDefaultDiskResources(
|
||||
program_id = 0;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Prepare, 0, 0, "");
|
||||
}
|
||||
|
||||
pipeline_cache.SetProgramID(program_id);
|
||||
pipeline_cache.SetAccurateMul(accurate_mul);
|
||||
pipeline_cache.LoadPipelineDiskCache(stop_loading, callback);
|
||||
pipeline_cache.LoadDiskCache(stop_loading, callback);
|
||||
pipeline_cache.LoadCache(stop_loading, callback);
|
||||
|
||||
if (callback) {
|
||||
callback(VideoCore::LoadCallbackStage::Complete, 0, 0, "");
|
||||
@ -985,8 +988,17 @@ void RasterizerVulkan::UploadUniforms(bool accelerate_draw) {
|
||||
|
||||
void RasterizerVulkan::SwitchDiskResources(u64 title_id) {
|
||||
std::atomic_bool stop_loading = false;
|
||||
|
||||
if (switch_disk_resources_callback) {
|
||||
switch_disk_resources_callback(VideoCore::LoadCallbackStage::Prepare, 0, 0, "");
|
||||
}
|
||||
|
||||
pipeline_cache.SetAccurateMul(accurate_mul);
|
||||
pipeline_cache.SwitchPipelineCache(title_id, stop_loading, switch_disk_resources_callback);
|
||||
pipeline_cache.SwitchCache(title_id, stop_loading, switch_disk_resources_callback);
|
||||
|
||||
if (switch_disk_resources_callback) {
|
||||
switch_disk_resources_callback(VideoCore::LoadCallbackStage::Complete, 0, 0, "");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@ -59,6 +59,9 @@ static VideoCore::DiskResourceLoadCallback MakeThrottledCallback(
|
||||
void ShaderDiskCache::Init(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
|
||||
if (!Settings::values.use_disk_shader_cache)
|
||||
return;
|
||||
|
||||
auto new_callback = MakeThrottledCallback(callback);
|
||||
|
||||
if (!stop_loading && !InitVSCache(stop_loading, new_callback)) {
|
||||
@ -248,7 +251,7 @@ GraphicsPipeline* ShaderDiskCache::GetPipeline(const PipelineInfo& info) {
|
||||
parent.UseTrivialGeometryShader();
|
||||
}
|
||||
it.value() = std::make_unique<GraphicsPipeline>(
|
||||
parent.instance, parent.renderpass_cache, info, *parent.pipeline_cache,
|
||||
parent.instance, parent.renderpass_cache, info, *parent.driver_pipeline_cache,
|
||||
*parent.pipeline_layout, parent.current_shaders, &parent.workers);
|
||||
}
|
||||
|
||||
@ -339,86 +342,129 @@ ShaderDiskCache::CacheEntry ShaderDiskCache::CacheFile::ReadAt(size_t position)
|
||||
}
|
||||
|
||||
size_t ShaderDiskCache::CacheFile::GetTotalEntries() {
|
||||
if (biggest_entry_id != SIZE_MAX) {
|
||||
return biggest_entry_id + 1;
|
||||
if (!file.IsGood()) {
|
||||
next_entry_id = SIZE_MAX;
|
||||
return next_entry_id;
|
||||
}
|
||||
|
||||
if (next_entry_id != SIZE_MAX) {
|
||||
return next_entry_id;
|
||||
}
|
||||
|
||||
const size_t file_size = file.GetSize();
|
||||
if (file_size == 0) {
|
||||
next_entry_id = 0;
|
||||
return next_entry_id;
|
||||
}
|
||||
|
||||
CacheEntry::CacheEntryFooter footer{};
|
||||
|
||||
if (file.ReadAtArray(&footer, 1, file_size - sizeof(footer)) == sizeof(footer) &&
|
||||
footer.version == CacheEntry::CacheEntryFooter::ENTRY_VERSION) {
|
||||
biggest_entry_id = footer.entry_id;
|
||||
next_entry_id = footer.entry_id + 1;
|
||||
} else {
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
return biggest_entry_id + 1;
|
||||
return next_entry_id;
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::CacheFile::Append(CacheEntryType type, u64 id, std::span<const u8> data,
|
||||
void ShaderDiskCache::CacheFile::Append(CacheEntryType type, u64 id, std::span<const u8> data,
|
||||
bool compress) {
|
||||
std::scoped_lock lock(mutex);
|
||||
|
||||
std::span<const u8> data_final;
|
||||
std::vector<u8> data_compress;
|
||||
|
||||
CacheEntry::CacheEntryHeader header{};
|
||||
CacheEntry::CacheEntryFooter footer{};
|
||||
|
||||
constexpr u32 headers_size =
|
||||
sizeof(CacheEntry::CacheEntryHeader) + sizeof(CacheEntry::CacheEntryFooter);
|
||||
|
||||
if (compress) {
|
||||
data_compress = Common::Compression::CompressDataZSTDDefault(data);
|
||||
data_final = data_compress;
|
||||
header.zstd_compressed.Assign(true);
|
||||
} else {
|
||||
data_final = data;
|
||||
if (curr_mode != CacheOpMode::APPEND) {
|
||||
return;
|
||||
}
|
||||
header.entry_version = CacheEntry::CacheEntryHeader::ENTRY_VERSION;
|
||||
footer.version.Assign(CacheEntry::CacheEntryFooter::ENTRY_VERSION);
|
||||
header.entry_size = footer.entry_size = data_final.size() + headers_size;
|
||||
footer.entry_id.Assign(biggest_entry_id++);
|
||||
|
||||
header.type = type;
|
||||
header.id = id;
|
||||
std::vector<u8> copy_data(data.begin(), data.end());
|
||||
|
||||
std::vector<u8> out_data(data_final.size() + headers_size);
|
||||
memcpy(out_data.data(), &header, sizeof(header));
|
||||
memcpy(out_data.data() + sizeof(header), data_final.data(), data_final.size());
|
||||
memcpy(out_data.data() + sizeof(header) + data_final.size(), &footer, sizeof(footer));
|
||||
append_worker.QueueWork([this, type, id, compress, data = std::move(copy_data)]() {
|
||||
if (next_entry_id == SIZE_MAX || !file.IsGood()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return file.WriteBytes(out_data.data(), out_data.size()) == out_data.size();
|
||||
std::span<const u8> data_final;
|
||||
std::vector<u8> data_compress;
|
||||
|
||||
CacheEntry::CacheEntryHeader header{};
|
||||
CacheEntry::CacheEntryFooter footer{};
|
||||
|
||||
constexpr u32 headers_size =
|
||||
sizeof(CacheEntry::CacheEntryHeader) + sizeof(CacheEntry::CacheEntryFooter);
|
||||
|
||||
if (compress) {
|
||||
data_compress = Common::Compression::CompressDataZSTDDefault(data);
|
||||
data_final = data_compress;
|
||||
header.zstd_compressed.Assign(true);
|
||||
} else {
|
||||
data_final = data;
|
||||
}
|
||||
header.entry_version = CacheEntry::CacheEntryHeader::ENTRY_VERSION;
|
||||
footer.version.Assign(CacheEntry::CacheEntryFooter::ENTRY_VERSION);
|
||||
header.entry_size = footer.entry_size = data_final.size() + headers_size;
|
||||
footer.entry_id.Assign(next_entry_id++);
|
||||
|
||||
header.type = type;
|
||||
header.id = id;
|
||||
|
||||
std::vector<u8> out_data(data_final.size() + headers_size);
|
||||
memcpy(out_data.data(), &header, sizeof(header));
|
||||
memcpy(out_data.data() + sizeof(header), data_final.data(), data_final.size());
|
||||
memcpy(out_data.data() + sizeof(header) + data_final.size(), &footer, sizeof(footer));
|
||||
|
||||
file.WriteBytes(out_data.data(), out_data.size());
|
||||
if (file.IsGood()) {
|
||||
file.Flush();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::CacheFile::SwitchMode(CacheOpMode mode) {
|
||||
if (curr_mode == mode) {
|
||||
return true;
|
||||
}
|
||||
if (curr_mode == CacheOpMode::APPEND) {
|
||||
append_worker.WaitForRequests();
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CacheOpMode::READ: {
|
||||
next_entry_id = SIZE_MAX; // Force reading entries agains
|
||||
file = FileUtil::IOFile(filepath, "rb");
|
||||
bool is_open = file.IsOpen();
|
||||
bool is_open = file.IsGood();
|
||||
if (is_open) {
|
||||
GetTotalEntries();
|
||||
}
|
||||
curr_mode = mode;
|
||||
return is_open;
|
||||
}
|
||||
case CacheOpMode::APPEND: {
|
||||
GetTotalEntries();
|
||||
if (!SwitchMode(CacheOpMode::READ)) {
|
||||
curr_mode = mode;
|
||||
return false;
|
||||
}
|
||||
file.Close();
|
||||
if (biggest_entry_id == SIZE_MAX) {
|
||||
curr_mode = mode;
|
||||
if (next_entry_id == SIZE_MAX) {
|
||||
// Cannot append if getting total items fails
|
||||
return false;
|
||||
}
|
||||
|
||||
file = FileUtil::IOFile(filepath, "ab");
|
||||
return file.IsOpen();
|
||||
return file.IsGood();
|
||||
}
|
||||
case CacheOpMode::DELETE: {
|
||||
biggest_entry_id = 0;
|
||||
next_entry_id = SIZE_MAX;
|
||||
file.Close();
|
||||
FileUtil::Delete(filepath);
|
||||
return true;
|
||||
curr_mode = mode;
|
||||
return FileUtil::Delete(filepath);
|
||||
}
|
||||
case CacheOpMode::RECREATE: {
|
||||
SwitchMode(CacheOpMode::DELETE);
|
||||
if (!SwitchMode(CacheOpMode::DELETE)) {
|
||||
return false;
|
||||
}
|
||||
if (!FileUtil::CreateEmptyFile(filepath)) {
|
||||
return false;
|
||||
}
|
||||
return SwitchMode(CacheOpMode::APPEND);
|
||||
}
|
||||
default:
|
||||
@ -827,8 +873,7 @@ bool ShaderDiskCache::InitVSCache(const std::atomic_bool& stop_loading,
|
||||
}
|
||||
|
||||
// Switch to append mode to receive new entries.
|
||||
vs_cache.SwitchMode(CacheFile::CacheOpMode::APPEND);
|
||||
return true;
|
||||
return vs_cache.SwitchMode(CacheFile::CacheOpMode::APPEND);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::InitFSCache(const std::atomic_bool& stop_loading,
|
||||
@ -1045,8 +1090,7 @@ bool ShaderDiskCache::InitFSCache(const std::atomic_bool& stop_loading,
|
||||
}
|
||||
|
||||
// Switch to append mode to receive new entries.
|
||||
fs_cache.SwitchMode(CacheFile::CacheOpMode::APPEND);
|
||||
return true;
|
||||
return fs_cache.SwitchMode(CacheFile::CacheOpMode::APPEND);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::InitGSCache(const std::atomic_bool& stop_loading,
|
||||
@ -1272,8 +1316,7 @@ bool ShaderDiskCache::InitGSCache(const std::atomic_bool& stop_loading,
|
||||
}
|
||||
|
||||
// Switch to append mode to receive new entries.
|
||||
gs_cache.SwitchMode(CacheFile::CacheOpMode::APPEND);
|
||||
return true;
|
||||
return gs_cache.SwitchMode(CacheFile::CacheOpMode::APPEND);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::InitPLCache(const std::atomic_bool& stop_loading,
|
||||
@ -1400,7 +1443,7 @@ bool ShaderDiskCache::InitPLCache(const std::atomic_bool& stop_loading,
|
||||
|
||||
auto [it_pl, _] = graphics_pipelines.try_emplace(pl_hash_opt);
|
||||
it_pl.value() = std::make_unique<GraphicsPipeline>(
|
||||
parent.instance, parent.renderpass_cache, info, *parent.pipeline_cache,
|
||||
parent.instance, parent.renderpass_cache, info, *parent.driver_pipeline_cache,
|
||||
*parent.pipeline_layout, shaders, &parent.workers);
|
||||
|
||||
it_pl.value()->TryBuild(false);
|
||||
@ -1413,11 +1456,10 @@ bool ShaderDiskCache::InitPLCache(const std::atomic_bool& stop_loading,
|
||||
}
|
||||
|
||||
// Switch to append mode to receive new entries.
|
||||
pl_cache.SwitchMode(CacheFile::CacheOpMode::APPEND);
|
||||
return true;
|
||||
return pl_cache.SwitchMode(CacheFile::CacheOpMode::APPEND);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::AppendVSConfigProgram(CacheFile& file,
|
||||
void ShaderDiskCache::AppendVSConfigProgram(CacheFile& file,
|
||||
const Pica::Shader::Generator::PicaVSConfig& config,
|
||||
const Pica::ShaderSetup& setup, u64 config_id,
|
||||
u64 spirv_id) {
|
||||
@ -1430,7 +1472,6 @@ bool ShaderDiskCache::AppendVSConfigProgram(CacheFile& file,
|
||||
Common::HashCombine(config.state.program_hash, config.state.swizzle_hash);
|
||||
|
||||
bool new_entry = known_vertex_programs.emplace(entry.program_entry_id).second;
|
||||
bool prog_res = true;
|
||||
if (new_entry) {
|
||||
std::unique_ptr<VSProgramEntry> prog_entry = std::make_unique<VSProgramEntry>();
|
||||
prog_entry->version = VSProgramEntry::EXPECTED_VERSION;
|
||||
@ -1439,49 +1480,46 @@ bool ShaderDiskCache::AppendVSConfigProgram(CacheFile& file,
|
||||
prog_entry->swizzle_len = setup.GetBiggestSwizzleSize();
|
||||
prog_entry->swizzle_code = setup.GetSwizzleData();
|
||||
|
||||
prog_res = AppendVSProgram(file, *prog_entry, entry.program_entry_id);
|
||||
AppendVSProgram(file, *prog_entry, entry.program_entry_id);
|
||||
}
|
||||
|
||||
return AppendVSConfig(file, entry, config_id) && prog_res;
|
||||
AppendVSConfig(file, entry, config_id);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::AppendVSProgram(CacheFile& file, const VSProgramEntry& entry,
|
||||
void ShaderDiskCache::AppendVSProgram(CacheFile& file, const VSProgramEntry& entry,
|
||||
u64 program_id) {
|
||||
return file.Append(CacheEntryType::VS_PROGRAM, program_id, entry, true);
|
||||
file.Append(CacheEntryType::VS_PROGRAM, program_id, entry, true);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::AppendVSConfig(CacheFile& file, const VSConfigEntry& entry, u64 config_id) {
|
||||
return file.Append(CacheEntryType::VS_CONFIG, config_id, entry, true);
|
||||
void ShaderDiskCache::AppendVSConfig(CacheFile& file, const VSConfigEntry& entry, u64 config_id) {
|
||||
file.Append(CacheEntryType::VS_CONFIG, config_id, entry, true);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::AppendVSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id) {
|
||||
return file.Append(CacheEntryType::VS_SPIRV, program_id,
|
||||
{reinterpret_cast<const u8*>(program.data()), program.size() * sizeof(u32)},
|
||||
true);
|
||||
void ShaderDiskCache::AppendVSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id) {
|
||||
file.Append(CacheEntryType::VS_SPIRV, program_id,
|
||||
{reinterpret_cast<const u8*>(program.data()), program.size() * sizeof(u32)}, true);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::AppendFSConfig(CacheFile& file, const FSConfigEntry& entry, u64 config_id) {
|
||||
return file.Append(CacheEntryType::FS_CONFIG, config_id, entry, true);
|
||||
void ShaderDiskCache::AppendFSConfig(CacheFile& file, const FSConfigEntry& entry, u64 config_id) {
|
||||
file.Append(CacheEntryType::FS_CONFIG, config_id, entry, true);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::AppendFSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id) {
|
||||
return file.Append(CacheEntryType::FS_SPIRV, program_id,
|
||||
{reinterpret_cast<const u8*>(program.data()), program.size() * sizeof(u32)},
|
||||
true);
|
||||
void ShaderDiskCache::AppendFSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id) {
|
||||
file.Append(CacheEntryType::FS_SPIRV, program_id,
|
||||
{reinterpret_cast<const u8*>(program.data()), program.size() * sizeof(u32)}, true);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::AppendGSConfig(CacheFile& file, const GSConfigEntry& entry, u64 config_id) {
|
||||
return file.Append(CacheEntryType::GS_CONFIG, config_id, entry, true);
|
||||
void ShaderDiskCache::AppendGSConfig(CacheFile& file, const GSConfigEntry& entry, u64 config_id) {
|
||||
file.Append(CacheEntryType::GS_CONFIG, config_id, entry, true);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::AppendGSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id) {
|
||||
return file.Append(CacheEntryType::GS_SPIRV, program_id,
|
||||
{reinterpret_cast<const u8*>(program.data()), program.size() * sizeof(u32)},
|
||||
true);
|
||||
void ShaderDiskCache::AppendGSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id) {
|
||||
file.Append(CacheEntryType::GS_SPIRV, program_id,
|
||||
{reinterpret_cast<const u8*>(program.data()), program.size() * sizeof(u32)}, true);
|
||||
}
|
||||
|
||||
bool ShaderDiskCache::AppendPLConfig(CacheFile& file, const PLConfigEntry& entry, u64 config_id) {
|
||||
return file.Append(CacheEntryType::PL_CONFIG, config_id, entry, true);
|
||||
void ShaderDiskCache::AppendPLConfig(CacheFile& file, const PLConfigEntry& entry, u64 config_id) {
|
||||
file.Append(CacheEntryType::PL_CONFIG, config_id, entry, true);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/thread_worker.h"
|
||||
#include "video_core/pica/shader_setup.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
||||
@ -241,6 +242,7 @@ private:
|
||||
class CacheFile {
|
||||
public:
|
||||
enum class CacheOpMode {
|
||||
NONE = 0,
|
||||
READ,
|
||||
APPEND,
|
||||
DELETE,
|
||||
@ -249,6 +251,9 @@ private:
|
||||
|
||||
CacheFile() = default;
|
||||
CacheFile(const std::string& _filepath) : filepath(_filepath) {}
|
||||
~CacheFile() {
|
||||
append_worker.WaitForRequests();
|
||||
}
|
||||
|
||||
void SetFilePath(const std::string& path) {
|
||||
filepath = path;
|
||||
@ -268,24 +273,25 @@ private:
|
||||
size_t GetTotalEntries();
|
||||
|
||||
template <typename T>
|
||||
bool Append(CacheEntryType type, u64 id, const T& object, bool compress) {
|
||||
void Append(CacheEntryType type, u64 id, const T& object, bool compress) {
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
|
||||
auto bytes = std::as_bytes(std::span{&object, 1});
|
||||
auto u8_span =
|
||||
std::span<const u8>(reinterpret_cast<const u8*>(bytes.data()), bytes.size());
|
||||
return Append(type, id, u8_span, compress);
|
||||
Append(type, id, u8_span, compress);
|
||||
}
|
||||
|
||||
bool Append(CacheEntryType type, u64 id, std::span<const u8> data, bool compress);
|
||||
void Append(CacheEntryType type, u64 id, std::span<const u8> data, bool compress);
|
||||
|
||||
bool SwitchMode(CacheOpMode mode);
|
||||
|
||||
private:
|
||||
CacheOpMode curr_mode = CacheOpMode::NONE;
|
||||
std::string filepath;
|
||||
std::mutex mutex;
|
||||
FileUtil::IOFile file{};
|
||||
size_t biggest_entry_id = SIZE_MAX;
|
||||
std::atomic<size_t> next_entry_id = SIZE_MAX;
|
||||
Common::ThreadWorker append_worker{1, "Disk Shader Cache Append Worker"};
|
||||
};
|
||||
|
||||
std::string GetVSFile(u64 title_id, bool is_temp) const;
|
||||
@ -307,19 +313,19 @@ private:
|
||||
bool InitPLCache(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback);
|
||||
|
||||
bool AppendVSConfigProgram(CacheFile& file, const Pica::Shader::Generator::PicaVSConfig& config,
|
||||
void AppendVSConfigProgram(CacheFile& file, const Pica::Shader::Generator::PicaVSConfig& config,
|
||||
const Pica::ShaderSetup& setup, u64 config_id, u64 program_id);
|
||||
bool AppendVSProgram(CacheFile& file, const VSProgramEntry& entry, u64 program_id);
|
||||
bool AppendVSConfig(CacheFile& file, const VSConfigEntry& entry, u64 config_id);
|
||||
bool AppendVSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id);
|
||||
void AppendVSProgram(CacheFile& file, const VSProgramEntry& entry, u64 program_id);
|
||||
void AppendVSConfig(CacheFile& file, const VSConfigEntry& entry, u64 config_id);
|
||||
void AppendVSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id);
|
||||
|
||||
bool AppendFSConfig(CacheFile& file, const FSConfigEntry& entry, u64 config_id);
|
||||
bool AppendFSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id);
|
||||
void AppendFSConfig(CacheFile& file, const FSConfigEntry& entry, u64 config_id);
|
||||
void AppendFSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id);
|
||||
|
||||
bool AppendGSConfig(CacheFile& file, const GSConfigEntry& entry, u64 config_id);
|
||||
bool AppendGSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id);
|
||||
void AppendGSConfig(CacheFile& file, const GSConfigEntry& entry, u64 config_id);
|
||||
void AppendGSSPIRV(CacheFile& file, std::span<const u32> program, u64 program_id);
|
||||
|
||||
bool AppendPLConfig(CacheFile& file, const PLConfigEntry& entry, u64 config_id);
|
||||
void AppendPLConfig(CacheFile& file, const PLConfigEntry& entry, u64 config_id);
|
||||
|
||||
CacheFile vs_cache;
|
||||
CacheFile fs_cache;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user