mirror of
https://github.com/yuzu-mirror/yuzu
synced 2024-12-22 09:43:10 +00:00
gl_rasterizer: Track texture buffer usage
This commit is contained in:
parent
58c0d37422
commit
007ffbef1c
6 changed files with 119 additions and 74 deletions
|
@ -29,8 +29,10 @@
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
using PixelFormat = VideoCore::Surface::PixelFormat;
|
|
||||||
using SurfaceType = VideoCore::Surface::SurfaceType;
|
using VideoCore::Surface::PixelFormat;
|
||||||
|
using VideoCore::Surface::SurfaceTarget;
|
||||||
|
using VideoCore::Surface::SurfaceType;
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192));
|
MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192));
|
||||||
MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192));
|
MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192));
|
||||||
|
@ -281,8 +283,14 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
||||||
static_cast<GLsizeiptr>(sizeof(ubo)));
|
static_cast<GLsizeiptr>(sizeof(ubo)));
|
||||||
|
|
||||||
Shader shader{shader_cache.GetStageProgram(program)};
|
Shader shader{shader_cache.GetStageProgram(program)};
|
||||||
const auto [program_handle, next_bindings] =
|
|
||||||
shader->GetProgramHandle(primitive_mode, base_bindings);
|
const auto stage_enum{static_cast<Maxwell::ShaderStage>(stage)};
|
||||||
|
SetupDrawConstBuffers(stage_enum, shader);
|
||||||
|
SetupGlobalRegions(stage_enum, shader);
|
||||||
|
const auto texture_buffer_usage{SetupTextures(stage_enum, shader, base_bindings)};
|
||||||
|
|
||||||
|
const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage};
|
||||||
|
const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant);
|
||||||
|
|
||||||
switch (program) {
|
switch (program) {
|
||||||
case Maxwell::ShaderProgram::VertexA:
|
case Maxwell::ShaderProgram::VertexA:
|
||||||
|
@ -300,11 +308,6 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
||||||
shader_config.enable.Value(), shader_config.offset);
|
shader_config.enable.Value(), shader_config.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage);
|
|
||||||
SetupDrawConstBuffers(stage_enum, shader);
|
|
||||||
SetupGlobalRegions(stage_enum, shader);
|
|
||||||
SetupTextures(stage_enum, shader, base_bindings);
|
|
||||||
|
|
||||||
// Workaround for Intel drivers.
|
// Workaround for Intel drivers.
|
||||||
// When a clip distance is enabled but not set in the shader it crops parts of the screen
|
// When a clip distance is enabled but not set in the shader it crops parts of the screen
|
||||||
// (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
|
// (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
|
||||||
|
@ -791,7 +794,7 @@ void RasterizerOpenGL::SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::Shade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader,
|
TextureBufferUsage RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& shader,
|
||||||
BaseBindings base_bindings) {
|
BaseBindings base_bindings) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_Texture);
|
MICROPROFILE_SCOPE(OpenGL_Texture);
|
||||||
const auto& gpu = system.GPU();
|
const auto& gpu = system.GPU();
|
||||||
|
@ -801,6 +804,8 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
|
||||||
ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units),
|
ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.texture_units),
|
||||||
"Exceeded the number of active textures.");
|
"Exceeded the number of active textures.");
|
||||||
|
|
||||||
|
TextureBufferUsage texture_buffer_usage{0};
|
||||||
|
|
||||||
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
|
||||||
const auto& entry = entries[bindpoint];
|
const auto& entry = entries[bindpoint];
|
||||||
Tegra::Texture::FullTextureInfo texture;
|
Tegra::Texture::FullTextureInfo texture;
|
||||||
|
@ -814,7 +819,8 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
|
||||||
}
|
}
|
||||||
const u32 current_bindpoint = base_bindings.sampler + bindpoint;
|
const u32 current_bindpoint = base_bindings.sampler + bindpoint;
|
||||||
|
|
||||||
state.texture_units[current_bindpoint].sampler = sampler_cache.GetSampler(texture.tsc);
|
auto& unit{state.texture_units[current_bindpoint]};
|
||||||
|
unit.sampler = sampler_cache.GetSampler(texture.tsc);
|
||||||
|
|
||||||
if (const auto view{texture_cache.GetTextureSurface(texture, entry)}; view) {
|
if (const auto view{texture_cache.GetTextureSurface(texture, entry)}; view) {
|
||||||
view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
|
view->ApplySwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
|
||||||
|
@ -822,9 +828,11 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
|
||||||
state.texture_units[current_bindpoint].texture = view->GetTexture();
|
state.texture_units[current_bindpoint].texture = view->GetTexture();
|
||||||
} else {
|
} else {
|
||||||
// Can occur when texture addr is null or its memory is unmapped/invalid
|
// Can occur when texture addr is null or its memory is unmapped/invalid
|
||||||
state.texture_units[current_bindpoint].texture = 0;
|
unit.texture = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return texture_buffer_usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
||||||
|
|
|
@ -126,9 +126,10 @@ private:
|
||||||
void SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
|
void SetupGlobalRegions(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
|
||||||
const Shader& shader);
|
const Shader& shader);
|
||||||
|
|
||||||
/// Configures the current textures to use for the draw command.
|
/// Configures the current textures to use for the draw command. Returns shaders texture buffer
|
||||||
void SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, const Shader& shader,
|
/// usage.
|
||||||
BaseBindings base_bindings);
|
TextureBufferUsage SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage,
|
||||||
|
const Shader& shader, BaseBindings base_bindings);
|
||||||
|
|
||||||
/// Syncs the viewport and depth range to match the guest state
|
/// Syncs the viewport and depth range to match the guest state
|
||||||
void SyncViewport(OpenGLState& current_state);
|
void SyncViewport(OpenGLState& current_state);
|
||||||
|
|
|
@ -168,8 +168,12 @@ GLShader::ProgramResult CreateProgram(const Device& device, Maxwell::ShaderProgr
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries,
|
CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries,
|
||||||
Maxwell::ShaderProgram program_type, BaseBindings base_bindings,
|
Maxwell::ShaderProgram program_type, const ProgramVariant& variant,
|
||||||
GLenum primitive_mode, bool hint_retrievable = false) {
|
bool hint_retrievable = false) {
|
||||||
|
auto base_bindings{variant.base_bindings};
|
||||||
|
const auto primitive_mode{variant.primitive_mode};
|
||||||
|
const auto texture_buffer_usage{variant.texture_buffer_usage};
|
||||||
|
|
||||||
std::string source = "#version 430 core\n"
|
std::string source = "#version 430 core\n"
|
||||||
"#extension GL_ARB_separate_shader_objects : enable\n\n";
|
"#extension GL_ARB_separate_shader_objects : enable\n\n";
|
||||||
source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++);
|
source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++);
|
||||||
|
@ -187,6 +191,14 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn
|
||||||
base_bindings.sampler++);
|
base_bindings.sampler++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform 1D textures to texture samplers by declaring its preprocessor macros.
|
||||||
|
for (std::size_t i = 0; i < texture_buffer_usage.size(); ++i) {
|
||||||
|
if (!texture_buffer_usage.test(i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
source += fmt::format("#define SAMPLER_{}_IS_BUFFER", i);
|
||||||
|
}
|
||||||
|
|
||||||
if (program_type == Maxwell::ShaderProgram::Geometry) {
|
if (program_type == Maxwell::ShaderProgram::Geometry) {
|
||||||
const auto [glsl_topology, debug_name, max_vertices] =
|
const auto [glsl_topology, debug_name, max_vertices] =
|
||||||
GetPrimitiveDescription(primitive_mode);
|
GetPrimitiveDescription(primitive_mode);
|
||||||
|
@ -261,20 +273,18 @@ CachedShader::CachedShader(VAddr cpu_addr, u64 unique_identifier,
|
||||||
shader_length = entries.shader_length;
|
shader_length = entries.shader_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive_mode,
|
std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVariant& variant) {
|
||||||
BaseBindings base_bindings) {
|
|
||||||
GLuint handle{};
|
GLuint handle{};
|
||||||
if (program_type == Maxwell::ShaderProgram::Geometry) {
|
if (program_type == Maxwell::ShaderProgram::Geometry) {
|
||||||
handle = GetGeometryShader(primitive_mode, base_bindings);
|
handle = GetGeometryShader(variant);
|
||||||
} else {
|
} else {
|
||||||
const auto [entry, is_cache_miss] = programs.try_emplace(base_bindings);
|
const auto [entry, is_cache_miss] = programs.try_emplace(variant);
|
||||||
auto& program = entry->second;
|
auto& program = entry->second;
|
||||||
if (is_cache_miss) {
|
if (is_cache_miss) {
|
||||||
program = TryLoadProgram(primitive_mode, base_bindings);
|
program = TryLoadProgram(variant);
|
||||||
if (!program) {
|
if (!program) {
|
||||||
program =
|
program = SpecializeShader(code, entries, program_type, variant);
|
||||||
SpecializeShader(code, entries, program_type, base_bindings, primitive_mode);
|
disk_cache.SaveUsage(GetUsage(variant));
|
||||||
disk_cache.SaveUsage(GetUsage(primitive_mode, base_bindings));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelGLObject(GL_PROGRAM, program->handle, cpu_addr);
|
LabelGLObject(GL_PROGRAM, program->handle, cpu_addr);
|
||||||
|
@ -283,6 +293,7 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive
|
||||||
handle = program->handle;
|
handle = program->handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto base_bindings{variant.base_bindings};
|
||||||
base_bindings.cbuf += static_cast<u32>(entries.const_buffers.size()) + RESERVED_UBOS;
|
base_bindings.cbuf += static_cast<u32>(entries.const_buffers.size()) + RESERVED_UBOS;
|
||||||
base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size());
|
base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size());
|
||||||
base_bindings.sampler += static_cast<u32>(entries.samplers.size());
|
base_bindings.sampler += static_cast<u32>(entries.samplers.size());
|
||||||
|
@ -290,43 +301,42 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive
|
||||||
return {handle, base_bindings};
|
return {handle, base_bindings};
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint CachedShader::GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings) {
|
GLuint CachedShader::GetGeometryShader(const ProgramVariant& variant) {
|
||||||
const auto [entry, is_cache_miss] = geometry_programs.try_emplace(base_bindings);
|
const auto [entry, is_cache_miss] = geometry_programs.try_emplace(variant);
|
||||||
auto& programs = entry->second;
|
auto& programs = entry->second;
|
||||||
|
|
||||||
switch (primitive_mode) {
|
switch (variant.primitive_mode) {
|
||||||
case GL_POINTS:
|
case GL_POINTS:
|
||||||
return LazyGeometryProgram(programs.points, base_bindings, primitive_mode);
|
return LazyGeometryProgram(programs.points, variant);
|
||||||
case GL_LINES:
|
case GL_LINES:
|
||||||
case GL_LINE_STRIP:
|
case GL_LINE_STRIP:
|
||||||
return LazyGeometryProgram(programs.lines, base_bindings, primitive_mode);
|
return LazyGeometryProgram(programs.lines, variant);
|
||||||
case GL_LINES_ADJACENCY:
|
case GL_LINES_ADJACENCY:
|
||||||
case GL_LINE_STRIP_ADJACENCY:
|
case GL_LINE_STRIP_ADJACENCY:
|
||||||
return LazyGeometryProgram(programs.lines_adjacency, base_bindings, primitive_mode);
|
return LazyGeometryProgram(programs.lines_adjacency, variant);
|
||||||
case GL_TRIANGLES:
|
case GL_TRIANGLES:
|
||||||
case GL_TRIANGLE_STRIP:
|
case GL_TRIANGLE_STRIP:
|
||||||
case GL_TRIANGLE_FAN:
|
case GL_TRIANGLE_FAN:
|
||||||
return LazyGeometryProgram(programs.triangles, base_bindings, primitive_mode);
|
return LazyGeometryProgram(programs.triangles, variant);
|
||||||
case GL_TRIANGLES_ADJACENCY:
|
case GL_TRIANGLES_ADJACENCY:
|
||||||
case GL_TRIANGLE_STRIP_ADJACENCY:
|
case GL_TRIANGLE_STRIP_ADJACENCY:
|
||||||
return LazyGeometryProgram(programs.triangles_adjacency, base_bindings, primitive_mode);
|
return LazyGeometryProgram(programs.triangles_adjacency, variant);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE_MSG("Unknown primitive mode.");
|
UNREACHABLE_MSG("Unknown primitive mode.");
|
||||||
return LazyGeometryProgram(programs.points, base_bindings, primitive_mode);
|
return LazyGeometryProgram(programs.points, variant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, BaseBindings base_bindings,
|
GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program,
|
||||||
GLenum primitive_mode) {
|
const ProgramVariant& variant) {
|
||||||
if (target_program) {
|
if (target_program) {
|
||||||
return target_program->handle;
|
return target_program->handle;
|
||||||
}
|
}
|
||||||
const auto [glsl_name, debug_name, vertices] = GetPrimitiveDescription(primitive_mode);
|
const auto [glsl_name, debug_name, vertices] = GetPrimitiveDescription(variant.primitive_mode);
|
||||||
target_program = TryLoadProgram(primitive_mode, base_bindings);
|
target_program = TryLoadProgram(variant);
|
||||||
if (!target_program) {
|
if (!target_program) {
|
||||||
target_program =
|
target_program = SpecializeShader(code, entries, program_type, variant);
|
||||||
SpecializeShader(code, entries, program_type, base_bindings, primitive_mode);
|
disk_cache.SaveUsage(GetUsage(variant));
|
||||||
disk_cache.SaveUsage(GetUsage(primitive_mode, base_bindings));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelGLObject(GL_PROGRAM, target_program->handle, cpu_addr, debug_name);
|
LabelGLObject(GL_PROGRAM, target_program->handle, cpu_addr, debug_name);
|
||||||
|
@ -334,18 +344,19 @@ GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, BaseBind
|
||||||
return target_program->handle;
|
return target_program->handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
CachedProgram CachedShader::TryLoadProgram(GLenum primitive_mode,
|
CachedProgram CachedShader::TryLoadProgram(const ProgramVariant& variant) const {
|
||||||
BaseBindings base_bindings) const {
|
const auto found = precompiled_programs.find(GetUsage(variant));
|
||||||
const auto found = precompiled_programs.find(GetUsage(primitive_mode, base_bindings));
|
|
||||||
if (found == precompiled_programs.end()) {
|
if (found == precompiled_programs.end()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode,
|
ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant) const {
|
||||||
BaseBindings base_bindings) const {
|
ShaderDiskCacheUsage usage;
|
||||||
return {unique_identifier, base_bindings, primitive_mode};
|
usage.unique_identifier = unique_identifier;
|
||||||
|
usage.variant = variant;
|
||||||
|
return usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
|
ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
|
||||||
|
@ -411,8 +422,7 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
|
||||||
}
|
}
|
||||||
if (!shader) {
|
if (!shader) {
|
||||||
shader = SpecializeShader(unspecialized.code, unspecialized.entries,
|
shader = SpecializeShader(unspecialized.code, unspecialized.entries,
|
||||||
unspecialized.program_type, usage.bindings,
|
unspecialized.program_type, usage.variant, true);
|
||||||
usage.primitive, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::scoped_lock lock(mutex);
|
std::scoped_lock lock(mutex);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <bitset>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
@ -67,8 +68,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the GL program handle for the shader
|
/// Gets the GL program handle for the shader
|
||||||
std::tuple<GLuint, BaseBindings> GetProgramHandle(GLenum primitive_mode,
|
std::tuple<GLuint, BaseBindings> GetProgramHandle(const ProgramVariant& variant);
|
||||||
BaseBindings base_bindings);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Geometry programs. These are needed because GLSL needs an input topology but it's not
|
// Geometry programs. These are needed because GLSL needs an input topology but it's not
|
||||||
|
@ -82,15 +82,14 @@ private:
|
||||||
CachedProgram triangles_adjacency;
|
CachedProgram triangles_adjacency;
|
||||||
};
|
};
|
||||||
|
|
||||||
GLuint GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings);
|
GLuint GetGeometryShader(const ProgramVariant& variant);
|
||||||
|
|
||||||
/// Generates a geometry shader or returns one that already exists.
|
/// Generates a geometry shader or returns one that already exists.
|
||||||
GLuint LazyGeometryProgram(CachedProgram& target_program, BaseBindings base_bindings,
|
GLuint LazyGeometryProgram(CachedProgram& target_program, const ProgramVariant& variant);
|
||||||
GLenum primitive_mode);
|
|
||||||
|
|
||||||
CachedProgram TryLoadProgram(GLenum primitive_mode, BaseBindings base_bindings) const;
|
CachedProgram TryLoadProgram(const ProgramVariant& variant) const;
|
||||||
|
|
||||||
ShaderDiskCacheUsage GetUsage(GLenum primitive_mode, BaseBindings base_bindings) const;
|
ShaderDiskCacheUsage GetUsage(const ProgramVariant& variant) const;
|
||||||
|
|
||||||
u8* host_ptr{};
|
u8* host_ptr{};
|
||||||
VAddr cpu_addr{};
|
VAddr cpu_addr{};
|
||||||
|
@ -104,8 +103,8 @@ private:
|
||||||
|
|
||||||
std::string code;
|
std::string code;
|
||||||
|
|
||||||
std::unordered_map<BaseBindings, CachedProgram> programs;
|
std::unordered_map<ProgramVariant, CachedProgram> programs;
|
||||||
std::unordered_map<BaseBindings, GeometryPrograms> geometry_programs;
|
std::unordered_map<ProgramVariant, GeometryPrograms> geometry_programs;
|
||||||
|
|
||||||
std::unordered_map<u32, GLuint> cbuf_resource_cache;
|
std::unordered_map<u32, GLuint> cbuf_resource_cache;
|
||||||
std::unordered_map<u32, GLuint> gmem_resource_cache;
|
std::unordered_map<u32, GLuint> gmem_resource_cache;
|
||||||
|
|
|
@ -34,11 +34,11 @@ enum class PrecompiledEntryKind : u32 {
|
||||||
Dump,
|
Dump,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr u32 NativeVersion = 1;
|
constexpr u32 NativeVersion = 2;
|
||||||
|
|
||||||
// Making sure sizes doesn't change by accident
|
// Making sure sizes doesn't change by accident
|
||||||
static_assert(sizeof(BaseBindings) == 12);
|
static_assert(sizeof(BaseBindings) == 12);
|
||||||
static_assert(sizeof(ShaderDiskCacheUsage) == 24);
|
static_assert(sizeof(ShaderDiskCacheUsage) == 32);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
|
@ -30,15 +30,17 @@ class IOFile;
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
using ProgramCode = std::vector<u64>;
|
|
||||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
|
||||||
|
|
||||||
struct ShaderDiskCacheUsage;
|
struct ShaderDiskCacheUsage;
|
||||||
struct ShaderDiskCacheDump;
|
struct ShaderDiskCacheDump;
|
||||||
|
|
||||||
using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>;
|
using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>;
|
||||||
|
|
||||||
/// Allocated bindings used by an OpenGL shader program
|
using ProgramCode = std::vector<u64>;
|
||||||
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
|
|
||||||
|
using TextureBufferUsage = std::bitset<64>;
|
||||||
|
|
||||||
|
/// Allocated bindings used by an OpenGL shader program.
|
||||||
struct BaseBindings {
|
struct BaseBindings {
|
||||||
u32 cbuf{};
|
u32 cbuf{};
|
||||||
u32 gmem{};
|
u32 gmem{};
|
||||||
|
@ -53,15 +55,29 @@ struct BaseBindings {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Describes how a shader is used
|
/// Describes the different variants a single program can be compiled.
|
||||||
|
struct ProgramVariant {
|
||||||
|
BaseBindings base_bindings;
|
||||||
|
GLenum primitive_mode{};
|
||||||
|
TextureBufferUsage texture_buffer_usage{};
|
||||||
|
|
||||||
|
bool operator==(const ProgramVariant& rhs) const {
|
||||||
|
return std::tie(base_bindings, primitive_mode, texture_buffer_usage) ==
|
||||||
|
std::tie(rhs.base_bindings, rhs.primitive_mode, rhs.texture_buffer_usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const ProgramVariant& rhs) const {
|
||||||
|
return !operator==(rhs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Describes how a shader is used.
|
||||||
struct ShaderDiskCacheUsage {
|
struct ShaderDiskCacheUsage {
|
||||||
u64 unique_identifier{};
|
u64 unique_identifier{};
|
||||||
BaseBindings bindings;
|
ProgramVariant variant;
|
||||||
GLenum primitive{};
|
|
||||||
|
|
||||||
bool operator==(const ShaderDiskCacheUsage& rhs) const {
|
bool operator==(const ShaderDiskCacheUsage& rhs) const {
|
||||||
return std::tie(unique_identifier, bindings, primitive) ==
|
return std::tie(unique_identifier, variant) == std::tie(rhs.unique_identifier, rhs.variant);
|
||||||
std::tie(rhs.unique_identifier, rhs.bindings, rhs.primitive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const ShaderDiskCacheUsage& rhs) const {
|
bool operator!=(const ShaderDiskCacheUsage& rhs) const {
|
||||||
|
@ -80,11 +96,20 @@ struct hash<OpenGL::BaseBindings> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<OpenGL::ProgramVariant> {
|
||||||
|
std::size_t operator()(const OpenGL::ProgramVariant& variant) const {
|
||||||
|
return std::hash<OpenGL::BaseBindings>()(variant.base_bindings) ^
|
||||||
|
std::hash<OpenGL::TextureBufferUsage>()(variant.texture_buffer_usage) ^
|
||||||
|
(static_cast<std::size_t>(variant.primitive_mode) << 6);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct hash<OpenGL::ShaderDiskCacheUsage> {
|
struct hash<OpenGL::ShaderDiskCacheUsage> {
|
||||||
std::size_t operator()(const OpenGL::ShaderDiskCacheUsage& usage) const noexcept {
|
std::size_t operator()(const OpenGL::ShaderDiskCacheUsage& usage) const noexcept {
|
||||||
return static_cast<std::size_t>(usage.unique_identifier) ^
|
return static_cast<std::size_t>(usage.unique_identifier) ^
|
||||||
std::hash<OpenGL::BaseBindings>()(usage.bindings) ^ usage.primitive << 16;
|
std::hash<OpenGL::ProgramVariant>()(usage.variant);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -288,13 +313,15 @@ private:
|
||||||
|
|
||||||
// Core system
|
// Core system
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
// Stored transferable shaders
|
// Stores whole precompiled cache which will be read from or saved to the precompiled chache
|
||||||
std::map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable;
|
// file
|
||||||
// Stores whole precompiled cache which will be read from/saved to the precompiled cache file
|
|
||||||
FileSys::VectorVfsFile precompiled_cache_virtual_file;
|
FileSys::VectorVfsFile precompiled_cache_virtual_file;
|
||||||
// Stores the current offset of the precompiled cache file for IO purposes
|
// Stores the current offset of the precompiled cache file for IO purposes
|
||||||
std::size_t precompiled_cache_virtual_file_offset = 0;
|
std::size_t precompiled_cache_virtual_file_offset = 0;
|
||||||
|
|
||||||
|
// Stored transferable shaders
|
||||||
|
std::unordered_map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable;
|
||||||
|
|
||||||
// The cache has been loaded at boot
|
// The cache has been loaded at boot
|
||||||
bool tried_to_load{};
|
bool tried_to_load{};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue