From b1efceec898b66ed1e940d887d376c5139272764 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 13 Jan 2019 23:29:24 -0300 Subject: [PATCH] gl_shader_disk_cache: Add transferable stores --- .../renderer_opengl/gl_shader_disk_cache.cpp | 92 ++++++++++++++++ .../renderer_opengl/gl_shader_disk_cache.h | 102 ++++++++++++++++++ 2 files changed, 194 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index de890676e..ef8cfffd6 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp @@ -20,8 +20,16 @@ namespace OpenGL { +enum class EntryKind : u32 { + Raw, + Usage, +}; + +constexpr u32 NativeVersion = 1; + // Making sure sizes doesn't change by accident static_assert(sizeof(BaseBindings) == 12); +static_assert(sizeof(ShaderDiskCacheUsage) == 24); namespace { std::string GetTitleID() { @@ -29,6 +37,90 @@ std::string GetTitleID() { } } // namespace +ShaderDiskCacheRaw::ShaderDiskCacheRaw(FileUtil::IOFile& file) { + file.ReadBytes(&unique_identifier, sizeof(u64)); + file.ReadBytes(&program_type, sizeof(u32)); + + u32 program_code_size{}, program_code_size_b{}; + file.ReadBytes(&program_code_size, sizeof(u32)); + file.ReadBytes(&program_code_size_b, sizeof(u32)); + + program_code.resize(program_code_size); + program_code_b.resize(program_code_size_b); + + file.ReadArray(program_code.data(), program_code_size); + if (HasProgramA()) { + file.ReadArray(program_code_b.data(), program_code_size_b); + } +} + +void ShaderDiskCacheRaw::Save(FileUtil::IOFile& file) const { + file.WriteObject(unique_identifier); + file.WriteObject(static_cast(program_type)); + file.WriteObject(program_code_size); + file.WriteObject(program_code_size_b); + + file.WriteArray(program_code.data(), program_code_size); + if (HasProgramA()) { + file.WriteArray(program_code_b.data(), program_code_size_b); + } +} + +void ShaderDiskCacheOpenGL::SaveRaw(const ShaderDiskCacheRaw& entry) { + const u64 id = entry.GetUniqueIdentifier(); + if (transferable.find(id) != transferable.end()) { + // The shader already exists + return; + } + + FileUtil::IOFile file = AppendTransferableFile(); + if (!file.IsOpen()) { + return; + } + file.WriteObject(EntryKind::Raw); + entry.Save(file); + + transferable.insert({id, {}}); +} + +void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) { + const auto it = transferable.find(usage.unique_identifier); + if (it == transferable.end()) { + LOG_CRITICAL(Render_OpenGL, "Saving shader usage without storing raw previously"); + UNREACHABLE(); + } + auto& usages{it->second}; + ASSERT(usages.find(usage) == usages.end()); + usages.insert(usage); + + FileUtil::IOFile file = AppendTransferableFile(); + if (!file.IsOpen()) { + return; + } + file.WriteObject(EntryKind::Usage); + file.WriteObject(usage); +} + +FileUtil::IOFile ShaderDiskCacheOpenGL::AppendTransferableFile() const { + if (!EnsureDirectories()) { + return {}; + } + + const auto transferable_path{GetTransferablePath()}; + const bool existed = FileUtil::Exists(transferable_path); + + FileUtil::IOFile file(transferable_path, "ab"); + if (!file.IsOpen()) { + LOG_ERROR(Render_OpenGL, "Failed to open transferable cache in path={}", transferable_path); + return {}; + } + if (!existed || file.GetSize() == 0) { + // If the file didn't exist, write its version + file.WriteObject(NativeVersion); + } + return file; +} + bool ShaderDiskCacheOpenGL::EnsureDirectories() const { const auto CreateDir = [](const std::string& dir) { if (!FileUtil::CreateDir(dir)) { diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.h b/src/video_core/renderer_opengl/gl_shader_disk_cache.h index 690c92cae..d4449c132 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h @@ -4,12 +4,18 @@ #pragma once +#include #include #include +#include +#include + +#include "common/assert.h" #include "common/common_types.h" #include "common/file_util.h" #include "video_core/engines/maxwell_3d.h" +#include "video_core/renderer_opengl/gl_shader_gen.h" namespace OpenGL { @@ -40,9 +46,102 @@ public: } }; +class ShaderDiskCacheRaw { +public: + explicit ShaderDiskCacheRaw(FileUtil::IOFile& file); + + explicit ShaderDiskCacheRaw(u64 unique_identifier, Maxwell::ShaderProgram program_type, + u32 program_code_size, u32 program_code_size_b, + ProgramCode program_code, ProgramCode program_code_b) + : unique_identifier{unique_identifier}, program_type{program_type}, + program_code_size{program_code_size}, program_code_size_b{program_code_size_b}, + program_code{std::move(program_code)}, program_code_b{std::move(program_code_b)} {} + + void Save(FileUtil::IOFile& file) const; + + u64 GetUniqueIdentifier() const { + return unique_identifier; + } + + bool HasProgramA() const { + return program_type == Maxwell::ShaderProgram::VertexA; + } + + Maxwell::ShaderProgram GetProgramType() const { + return program_type; + } + + Maxwell::ShaderStage GetProgramStage() const { + switch (program_type) { + case Maxwell::ShaderProgram::VertexA: + case Maxwell::ShaderProgram::VertexB: + return Maxwell::ShaderStage::Vertex; + case Maxwell::ShaderProgram::TesselationControl: + return Maxwell::ShaderStage::TesselationControl; + case Maxwell::ShaderProgram::TesselationEval: + return Maxwell::ShaderStage::TesselationEval; + case Maxwell::ShaderProgram::Geometry: + return Maxwell::ShaderStage::Geometry; + case Maxwell::ShaderProgram::Fragment: + return Maxwell::ShaderStage::Fragment; + } + UNREACHABLE(); + } + + const ProgramCode& GetProgramCode() const { + return program_code; + } + + const ProgramCode& GetProgramCodeB() const { + return program_code_b; + } + +private: + u64 unique_identifier{}; + Maxwell::ShaderProgram program_type{}; + u32 program_code_size{}; + u32 program_code_size_b{}; + + ProgramCode program_code; + ProgramCode program_code_b; +}; + +struct ShaderDiskCacheUsage { +private: + auto Tie() const { + return std::tie(unique_identifier, bindings, primitive); + } + +public: + u64 unique_identifier{}; + BaseBindings bindings; + GLenum primitive{}; + + bool operator<(const ShaderDiskCacheUsage& rhs) const { + return Tie() < rhs.Tie(); + } + + bool operator==(const ShaderDiskCacheUsage& rhs) const { + return Tie() == rhs.Tie(); + } + + bool operator!=(const ShaderDiskCacheUsage& rhs) const { + return !this->operator==(rhs); + } +}; + class ShaderDiskCacheOpenGL { public: + /// Saves a raw dump to the transferable file. Checks for collisions. + void SaveRaw(const ShaderDiskCacheRaw& entry); + + /// Saves shader usage to the transferable file. Does not check for collisions. + void SaveUsage(const ShaderDiskCacheUsage& usage); + private: + /// Opens current game's transferable file and write it's header if it doesn't exist + FileUtil::IOFile AppendTransferableFile() const; + /// Create shader disk cache directories. Returns true on success. bool EnsureDirectories() const; @@ -60,6 +159,9 @@ private: /// Get user's shader directory path std::string GetBaseDir() const; + + // Stored transferable shaders + std::map> transferable; }; } // namespace OpenGL \ No newline at end of file