summaryrefslogtreecommitdiffstats
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp92
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.h102
2 files changed, 194 insertions, 0 deletions
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<u32>(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 <set>
#include <string>
#include <tuple>
+#include <vector>
+#include <glad/glad.h>
+
+#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<u64, std::set<ShaderDiskCacheUsage>> transferable;
};
} // namespace OpenGL \ No newline at end of file