summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2018-11-10 02:41:33 -0300
committerGravatar ReinUsesLisp2018-11-10 03:10:50 -0300
commit8d4bb10d443060dc56d6c6ddd9b84bbea00874d3 (patch)
treee171445255a669bf311468f0c005fe2045802627
parentgl_resource_manager: Amend clang-format discrepancies (diff)
downloadyuzu-8d4bb10d443060dc56d6c6ddd9b84bbea00874d3.tar.gz
yuzu-8d4bb10d443060dc56d6c6ddd9b84bbea00874d3.tar.xz
yuzu-8d4bb10d443060dc56d6c6ddd9b84bbea00874d3.zip
gl_shader_decompiler: Guard out of bound geometry shader input reads
Geometry shaders follow a pattern that results in out of bound reads. This pattern is: - VSETP to predicate - Use that predicate to conditionally set a register a big number - Use the register to access geometry shaders At the time of writing this commit I don't know what's the intent of this number. Some drivers argue about these out of bound reads. To avoid this issue, input reads are guarded limiting reads to the highest posible vertex input of the current topology (e.g. points to 1 and triangles to 3).
Diffstat (limited to '')
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h13
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp4
4 files changed, 24 insertions, 15 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 9522fd344..31ccf4ab8 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -121,12 +121,16 @@ GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) {
121} 121}
122 122
123GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, 123GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
124 const std::string& glsl_topology, 124 const std::string& glsl_topology, u32 max_vertices,
125 const std::string& debug_name) { 125 const std::string& debug_name) {
126 if (target_program.handle != 0) { 126 if (target_program.handle != 0) {
127 return target_program.handle; 127 return target_program.handle;
128 } 128 }
129 const std::string source{geometry_programs.code + "layout (" + glsl_topology + ") in;\n"}; 129 std::string source = "#version 430 core\n";
130 source += "layout (" + glsl_topology + ") in;\n";
131 source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n';
132 source += geometry_programs.code;
133
130 OGLShader shader; 134 OGLShader shader;
131 shader.Create(source.c_str(), GL_GEOMETRY_SHADER); 135 shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
132 target_program.Create(true, shader.handle); 136 target_program.Create(true, shader.handle);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index a210f1731..8fd0b7e88 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -46,22 +46,23 @@ public:
46 } 46 }
47 switch (primitive_mode) { 47 switch (primitive_mode) {
48 case GL_POINTS: 48 case GL_POINTS:
49 return LazyGeometryProgram(geometry_programs.points, "points", "ShaderPoints"); 49 return LazyGeometryProgram(geometry_programs.points, "points", 1, "ShaderPoints");
50 case GL_LINES: 50 case GL_LINES:
51 case GL_LINE_STRIP: 51 case GL_LINE_STRIP:
52 return LazyGeometryProgram(geometry_programs.lines, "lines", "ShaderLines"); 52 return LazyGeometryProgram(geometry_programs.lines, "lines", 2, "ShaderLines");
53 case GL_LINES_ADJACENCY: 53 case GL_LINES_ADJACENCY:
54 case GL_LINE_STRIP_ADJACENCY: 54 case GL_LINE_STRIP_ADJACENCY:
55 return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", 55 return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", 4,
56 "ShaderLinesAdjacency"); 56 "ShaderLinesAdjacency");
57 case GL_TRIANGLES: 57 case GL_TRIANGLES:
58 case GL_TRIANGLE_STRIP: 58 case GL_TRIANGLE_STRIP:
59 case GL_TRIANGLE_FAN: 59 case GL_TRIANGLE_FAN:
60 return LazyGeometryProgram(geometry_programs.triangles, "triangles", "ShaderTriangles"); 60 return LazyGeometryProgram(geometry_programs.triangles, "triangles", 3,
61 "ShaderTriangles");
61 case GL_TRIANGLES_ADJACENCY: 62 case GL_TRIANGLES_ADJACENCY:
62 case GL_TRIANGLE_STRIP_ADJACENCY: 63 case GL_TRIANGLE_STRIP_ADJACENCY:
63 return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency", 64 return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency",
64 "ShaderLines"); 65 6, "ShaderTrianglesAdjacency");
65 default: 66 default:
66 UNREACHABLE_MSG("Unknown primitive mode."); 67 UNREACHABLE_MSG("Unknown primitive mode.");
67 } 68 }
@@ -76,7 +77,7 @@ public:
76private: 77private:
77 /// Generates a geometry shader or returns one that already exists. 78 /// Generates a geometry shader or returns one that already exists.
78 GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology, 79 GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology,
79 const std::string& debug_name); 80 u32 max_vertices, const std::string& debug_name);
80 81
81 VAddr addr; 82 VAddr addr;
82 Maxwell::ShaderProgram program_type; 83 Maxwell::ShaderProgram program_type;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 09b003c59..bce7465b5 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -494,10 +494,10 @@ public:
494 // instruction for now. 494 // instruction for now.
495 if (stage == Maxwell3D::Regs::ShaderStage::Geometry) { 495 if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
496 // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry 496 // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
497 // shader. These instructions use a dirty register as buffer index. To avoid some 497 // shader. These instructions use a dirty register as buffer index, to avoid some
498 // drivers from complaining for the out of boundary writes, guard them. 498 // drivers from complaining about out of boundary writes, guard them.
499 const std::string buf_index{"min(" + GetRegisterAsInteger(buf_reg) + ", " + 499 const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " +
500 std::to_string(MAX_GEOMETRY_BUFFERS - 1) + ')'}; 500 std::to_string(MAX_GEOMETRY_BUFFERS) + ')'};
501 shader.AddLine("amem[" + buf_index + "][" + 501 shader.AddLine("amem[" + buf_index + "][" +
502 std::to_string(static_cast<u32>(attribute)) + ']' + 502 std::to_string(static_cast<u32>(attribute)) + ']' +
503 GetSwizzle(elem) + " = " + src + ';'); 503 GetSwizzle(elem) + " = " + src + ';');
@@ -811,7 +811,11 @@ private:
811 std::optional<Register> vertex = {}) { 811 std::optional<Register> vertex = {}) {
812 auto GeometryPass = [&](const std::string& name) { 812 auto GeometryPass = [&](const std::string& name) {
813 if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) { 813 if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) {
814 return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) + ']'; 814 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games set
815 // an 0x80000000 index for those and the shader fails to build. Find out why this
816 // happens and what's its intent.
817 return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) +
818 " % MAX_VERTEX_INPUT]";
815 } 819 }
816 return name; 820 return name;
817 }; 821 };
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 9d17edd63..eea090e52 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -82,8 +82,8 @@ void main() {
82} 82}
83 83
84ProgramResult GenerateGeometryShader(const ShaderSetup& setup) { 84ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
85 std::string out = "#version 430 core\n"; 85 // Version is intentionally skipped in shader generation, it's added by the lazy compilation.
86 out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; 86 std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n";
87 out += Decompiler::GetCommonDeclarations(); 87 out += Decompiler::GetCommonDeclarations();
88 out += "bool exec_geometry();\n"; 88 out += "bool exec_geometry();\n";
89 89