summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-10-09 22:46:47 -0400
committerGravatar bunnei2015-10-21 21:58:59 -0400
commit240a3b80d970b56b4ed3671536489eb0e32532ae (patch)
tree487d5b0cda1965e8e80cd8e3c17b0cece3ad3cec /src
parentgl_shader_gen: Require explicit uniform locations. (diff)
downloadyuzu-240a3b80d970b56b4ed3671536489eb0e32532ae.tar.gz
yuzu-240a3b80d970b56b4ed3671536489eb0e32532ae.tar.xz
yuzu-240a3b80d970b56b4ed3671536489eb0e32532ae.zip
gl_rasterizer: Use MMH3 hash for shader cache hey.
- Includes a check to confirm no hash collisions.
Diffstat (limited to 'src')
-rw-r--r--src/common/common_funcs.h18
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h133
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h2
5 files changed, 63 insertions, 101 deletions
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 7a8dd39a0..ed20c3629 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -4,9 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8#include <functional>
9
10#include "common_types.h" 7#include "common_types.h"
11 8
12#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 9#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@@ -98,18 +95,3 @@ inline u64 _rotr64(u64 x, unsigned int shift){
98// This function might change the error code. 95// This function might change the error code.
99// Defined in Misc.cpp. 96// Defined in Misc.cpp.
100const char* GetLastErrorMsg(); 97const char* GetLastErrorMsg();
101
102template <typename T>
103inline std::size_t hash(const T& o) {
104 return std::hash<T>()(o);
105}
106
107template <typename T>
108inline std::size_t combine_hash(const T& o) {
109 return hash(o);
110}
111
112template <typename T, typename... Args>
113inline std::size_t combine_hash(const T& o, const Args&... args) {
114 return hash(o) * 3 + combine_hash(args...);
115}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 64639ed26..4ae42f226 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -461,7 +461,8 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
461} 461}
462 462
463void RasterizerOpenGL::SetShader() { 463void RasterizerOpenGL::SetShader() {
464 ShaderCacheKey config = ShaderCacheKey::CurrentConfig(); 464 PicaShaderConfig config = PicaShaderConfig::CurrentConfig();
465 std::unique_ptr<PicaShader> shader = Common::make_unique<PicaShader>();
465 466
466 // Find (or generate) the GLSL shader for the current TEV state 467 // Find (or generate) the GLSL shader for the current TEV state
467 auto cached_shader = shader_cache.find(config); 468 auto cached_shader = shader_cache.find(config);
@@ -471,9 +472,7 @@ void RasterizerOpenGL::SetShader() {
471 state.draw.shader_program = current_shader->shader.handle; 472 state.draw.shader_program = current_shader->shader.handle;
472 state.Apply(); 473 state.Apply();
473 } else { 474 } else {
474 LOG_DEBUG(Render_OpenGL, "Creating new shader: %08X", hash(config)); 475 LOG_DEBUG(Render_OpenGL, "Creating new shader");
475
476 std::unique_ptr<TEVShader> shader = Common::make_unique<TEVShader>();
477 476
478 shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); 477 shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str());
479 478
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 79c34944a..cf8df8d9c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -5,11 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <cstring>
8#include <memory> 9#include <memory>
9#include <vector> 10#include <vector>
10#include <unordered_map> 11#include <unordered_map>
11 12
12#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/hash.h"
13 15
14#include "video_core/pica.h" 16#include "video_core/pica.h"
15#include "video_core/hwrasterizer_base.h" 17#include "video_core/hwrasterizer_base.h"
@@ -25,97 +27,76 @@
25 * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) 27 * Pica state is not being captured in the shader cache key, thereby resulting in (what should be)
26 * two separate shaders sharing the same key. 28 * two separate shaders sharing the same key.
27 */ 29 */
28struct ShaderCacheKey { 30struct PicaShaderConfig {
29 using Regs = Pica::Regs; 31 /// Construct a PicaShaderConfig with the current Pica register configuration.
30 32 static PicaShaderConfig CurrentConfig() {
31 bool operator ==(const ShaderCacheKey& o) const { 33 PicaShaderConfig res;
32 return hash(*this) == hash(o);
33 };
34
35 Regs::CompareFunc alpha_test_func;
36 std::array<Regs::TevStageConfig, 6> tev_stages = {};
37 u8 combiner_buffer_input;
38
39 bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
40 return (stage_index < 4) && (combiner_buffer_input & (1 << stage_index));
41 }
42
43 bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
44 return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index));
45 }
46
47 /**
48 * This function is used to construct a ShaderCacheKey with the current Pica register
49 * configuration. Don't construct a ShaderCacheKey manually, instead call this function (and
50 * extend it as additional state needs to be captured to generate shaders).
51 */
52 static ShaderCacheKey CurrentConfig() {
53 const auto& regs = Pica::g_state.regs; 34 const auto& regs = Pica::g_state.regs;
54 ShaderCacheKey config;
55 35
56 config.alpha_test_func = regs.output_merger.alpha_test.enable ? 36 res.alpha_test_func = regs.output_merger.alpha_test.enable ?
57 regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; 37 regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always;
58 38
59 // Copy relevant TevStageConfig fields only. We're doing this manually (instead of calling 39 // Copy relevant TevStageConfig fields only. We're doing this manually (instead of calling
60 // the GetTevStages() function) because BitField explicitly disables copies. 40 // the GetTevStages() function) because BitField explicitly disables copies.
61 41
62 config.tev_stages[0].source_raw = regs.tev_stage0.source_raw; 42 res.tev_stages[0].sources_raw = regs.tev_stage0.sources_raw;
63 config.tev_stages[1].source_raw = regs.tev_stage1.source_raw; 43 res.tev_stages[1].sources_raw = regs.tev_stage1.sources_raw;
64 config.tev_stages[2].source_raw = regs.tev_stage2.source_raw; 44 res.tev_stages[2].sources_raw = regs.tev_stage2.sources_raw;
65 config.tev_stages[3].source_raw = regs.tev_stage3.source_raw; 45 res.tev_stages[3].sources_raw = regs.tev_stage3.sources_raw;
66 config.tev_stages[4].source_raw = regs.tev_stage4.source_raw; 46 res.tev_stages[4].sources_raw = regs.tev_stage4.sources_raw;
67 config.tev_stages[5].source_raw = regs.tev_stage5.source_raw; 47 res.tev_stages[5].sources_raw = regs.tev_stage5.sources_raw;
68 48
69 config.tev_stages[0].modifier_raw = regs.tev_stage0.modifier_raw; 49 res.tev_stages[0].modifiers_raw = regs.tev_stage0.modifiers_raw;
70 config.tev_stages[1].modifier_raw = regs.tev_stage1.modifier_raw; 50 res.tev_stages[1].modifiers_raw = regs.tev_stage1.modifiers_raw;
71 config.tev_stages[2].modifier_raw = regs.tev_stage2.modifier_raw; 51 res.tev_stages[2].modifiers_raw = regs.tev_stage2.modifiers_raw;
72 config.tev_stages[3].modifier_raw = regs.tev_stage3.modifier_raw; 52 res.tev_stages[3].modifiers_raw = regs.tev_stage3.modifiers_raw;
73 config.tev_stages[4].modifier_raw = regs.tev_stage4.modifier_raw; 53 res.tev_stages[4].modifiers_raw = regs.tev_stage4.modifiers_raw;
74 config.tev_stages[5].modifier_raw = regs.tev_stage5.modifier_raw; 54 res.tev_stages[5].modifiers_raw = regs.tev_stage5.modifiers_raw;
75 55
76 config.tev_stages[0].op_raw = regs.tev_stage0.op_raw; 56 res.tev_stages[0].ops_raw = regs.tev_stage0.ops_raw;
77 config.tev_stages[1].op_raw = regs.tev_stage1.op_raw; 57 res.tev_stages[1].ops_raw = regs.tev_stage1.ops_raw;
78 config.tev_stages[2].op_raw = regs.tev_stage2.op_raw; 58 res.tev_stages[2].ops_raw = regs.tev_stage2.ops_raw;
79 config.tev_stages[3].op_raw = regs.tev_stage3.op_raw; 59 res.tev_stages[3].ops_raw = regs.tev_stage3.ops_raw;
80 config.tev_stages[4].op_raw = regs.tev_stage4.op_raw; 60 res.tev_stages[4].ops_raw = regs.tev_stage4.ops_raw;
81 config.tev_stages[5].op_raw = regs.tev_stage5.op_raw; 61 res.tev_stages[5].ops_raw = regs.tev_stage5.ops_raw;
82 62
83 config.tev_stages[0].scale_raw = regs.tev_stage0.scale_raw; 63 res.tev_stages[0].scales_raw = regs.tev_stage0.scales_raw;
84 config.tev_stages[1].scale_raw = regs.tev_stage1.scale_raw; 64 res.tev_stages[1].scales_raw = regs.tev_stage1.scales_raw;
85 config.tev_stages[2].scale_raw = regs.tev_stage2.scale_raw; 65 res.tev_stages[2].scales_raw = regs.tev_stage2.scales_raw;
86 config.tev_stages[3].scale_raw = regs.tev_stage3.scale_raw; 66 res.tev_stages[3].scales_raw = regs.tev_stage3.scales_raw;
87 config.tev_stages[4].scale_raw = regs.tev_stage4.scale_raw; 67 res.tev_stages[4].scales_raw = regs.tev_stage4.scales_raw;
88 config.tev_stages[5].scale_raw = regs.tev_stage5.scale_raw; 68 res.tev_stages[5].scales_raw = regs.tev_stage5.scales_raw;
89 69
90 config.combiner_buffer_input = 70 res.combiner_buffer_input =
91 regs.tev_combiner_buffer_input.update_mask_rgb.Value() | 71 regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
92 regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; 72 regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
93 73
94 return config; 74 return res;
95 } 75 }
96};
97
98namespace std {
99 76
100template<> struct hash<::Pica::Regs::CompareFunc> { 77 bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
101 std::size_t operator()(const ::Pica::Regs::CompareFunc& o) { 78 return (stage_index < 4) && (combiner_buffer_input & (1 << stage_index));
102 return ::hash((unsigned)o);
103 } 79 }
104};
105 80
106template<> struct hash<::Pica::Regs::TevStageConfig> { 81 bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
107 std::size_t operator()(const ::Pica::Regs::TevStageConfig& o) { 82 return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index));
108 return ::combine_hash(
109 ::hash(o.source_raw), ::hash(o.modifier_raw),
110 ::hash(o.op_raw), ::hash(o.scale_raw));
111 } 83 }
84
85 bool operator ==(const PicaShaderConfig& o) const {
86 return std::memcmp(this, &o, sizeof(PicaShaderConfig)) == 0;
87 };
88
89 Pica::Regs::CompareFunc alpha_test_func;
90 std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {};
91 u8 combiner_buffer_input;
112}; 92};
113 93
114template<> struct hash<::ShaderCacheKey> { 94namespace std {
115 std::size_t operator()(const ::ShaderCacheKey& o) const { 95
116 return ::combine_hash(o.alpha_test_func, o.combiner_buffer_input, 96template <>
117 o.tev_stages[0], o.tev_stages[1], o.tev_stages[2], 97struct hash<PicaShaderConfig> {
118 o.tev_stages[3], o.tev_stages[4], o.tev_stages[5]); 98 std::size_t operator()(const PicaShaderConfig& k) const {
99 return Common::ComputeHash64(&k, sizeof(PicaShaderConfig));
119 } 100 }
120}; 101};
121 102
@@ -314,8 +295,8 @@ private:
314 TextureInfo fb_color_texture; 295 TextureInfo fb_color_texture;
315 DepthTextureInfo fb_depth_texture; 296 DepthTextureInfo fb_depth_texture;
316 297
317 std::unordered_map<ShaderCacheKey, std::unique_ptr<TEVShader>> shader_cache; 298 std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache;
318 const TEVShader* current_shader = nullptr; 299 const PicaShader* current_shader = nullptr;
319 300
320 OGLVertexArray vertex_array; 301 OGLVertexArray vertex_array;
321 OGLBuffer vertex_buffer; 302 OGLBuffer vertex_buffer;
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 50bb2e3cc..84883b483 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -278,7 +278,7 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
278} 278}
279 279
280/// Writes the code to emulate the specified TEV stage 280/// Writes the code to emulate the specified TEV stage
281static void WriteTevStage(std::string& out, const ShaderCacheKey& config, unsigned index) { 281static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
282 auto& stage = config.tev_stages[index]; 282 auto& stage = config.tev_stages[index];
283 if (!IsPassThroughTevStage(stage)) { 283 if (!IsPassThroughTevStage(stage)) {
284 std::string index_name = std::to_string(index); 284 std::string index_name = std::to_string(index);
@@ -319,7 +319,7 @@ static void WriteTevStage(std::string& out, const ShaderCacheKey& config, unsign
319 out += "g_combiner_buffer.a = g_last_tex_env_out.a;\n"; 319 out += "g_combiner_buffer.a = g_last_tex_env_out.a;\n";
320} 320}
321 321
322std::string GenerateFragmentShader(const ShaderCacheKey& config) { 322std::string GenerateFragmentShader(const PicaShaderConfig& config) {
323 std::string out = R"( 323 std::string out = R"(
324#version 330 324#version 330
325#extension GL_ARB_explicit_uniform_location : require 325#extension GL_ARB_explicit_uniform_location : require
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index c8295e9e0..0ca9d2879 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -22,6 +22,6 @@ std::string GenerateVertexShader();
22 * configuration (NOTE: Use state in this struct only, not the Pica registers!) 22 * configuration (NOTE: Use state in this struct only, not the Pica registers!)
23 * @returns String of the shader source code 23 * @returns String of the shader source code
24 */ 24 */
25std::string GenerateFragmentShader(const ShaderCacheKey& config); 25std::string GenerateFragmentShader(const PicaShaderConfig& config);
26 26
27} // namespace GLShader 27} // namespace GLShader