diff options
| author | 2018-11-11 08:28:20 -0800 | |
|---|---|---|
| committer | 2018-11-11 08:28:20 -0800 | |
| commit | eaee73f95d4785c36a7e81f1f087e0be52de7e17 (patch) | |
| tree | 7350b90238e7fc2325bb8ca1eeab34858c2b595b /src | |
| parent | Merge pull request #1663 from lioncash/raster (diff) | |
| parent | gl_shader_decompiler: Guard out of bound geometry shader input reads (diff) | |
| download | yuzu-eaee73f95d4785c36a7e81f1f087e0be52de7e17.tar.gz yuzu-eaee73f95d4785c36a7e81f1f087e0be52de7e17.tar.xz yuzu-eaee73f95d4785c36a7e81f1f087e0be52de7e17.zip | |
Merge pull request #1669 from ReinUsesLisp/fixup-gs
gl_shader_decompiler: Guard out of bound geometry shader input reads
Diffstat (limited to '')
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 d7fb50a85..a85a7c0c5 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 | ||
| 123 | GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program, | 123 | GLuint 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 016ab18f9..ffbf21831 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h | |||
| @@ -48,22 +48,23 @@ public: | |||
| 48 | } | 48 | } |
| 49 | switch (primitive_mode) { | 49 | switch (primitive_mode) { |
| 50 | case GL_POINTS: | 50 | case GL_POINTS: |
| 51 | return LazyGeometryProgram(geometry_programs.points, "points", "ShaderPoints"); | 51 | return LazyGeometryProgram(geometry_programs.points, "points", 1, "ShaderPoints"); |
| 52 | case GL_LINES: | 52 | case GL_LINES: |
| 53 | case GL_LINE_STRIP: | 53 | case GL_LINE_STRIP: |
| 54 | return LazyGeometryProgram(geometry_programs.lines, "lines", "ShaderLines"); | 54 | return LazyGeometryProgram(geometry_programs.lines, "lines", 2, "ShaderLines"); |
| 55 | case GL_LINES_ADJACENCY: | 55 | case GL_LINES_ADJACENCY: |
| 56 | case GL_LINE_STRIP_ADJACENCY: | 56 | case GL_LINE_STRIP_ADJACENCY: |
| 57 | return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", | 57 | return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", 4, |
| 58 | "ShaderLinesAdjacency"); | 58 | "ShaderLinesAdjacency"); |
| 59 | case GL_TRIANGLES: | 59 | case GL_TRIANGLES: |
| 60 | case GL_TRIANGLE_STRIP: | 60 | case GL_TRIANGLE_STRIP: |
| 61 | case GL_TRIANGLE_FAN: | 61 | case GL_TRIANGLE_FAN: |
| 62 | return LazyGeometryProgram(geometry_programs.triangles, "triangles", "ShaderTriangles"); | 62 | return LazyGeometryProgram(geometry_programs.triangles, "triangles", 3, |
| 63 | "ShaderTriangles"); | ||
| 63 | case GL_TRIANGLES_ADJACENCY: | 64 | case GL_TRIANGLES_ADJACENCY: |
| 64 | case GL_TRIANGLE_STRIP_ADJACENCY: | 65 | case GL_TRIANGLE_STRIP_ADJACENCY: |
| 65 | return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency", | 66 | return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency", |
| 66 | "ShaderLines"); | 67 | 6, "ShaderTrianglesAdjacency"); |
| 67 | default: | 68 | default: |
| 68 | UNREACHABLE_MSG("Unknown primitive mode."); | 69 | UNREACHABLE_MSG("Unknown primitive mode."); |
| 69 | } | 70 | } |
| @@ -78,7 +79,7 @@ public: | |||
| 78 | private: | 79 | private: |
| 79 | /// Generates a geometry shader or returns one that already exists. | 80 | /// Generates a geometry shader or returns one that already exists. |
| 80 | GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology, | 81 | GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology, |
| 81 | const std::string& debug_name); | 82 | u32 max_vertices, const std::string& debug_name); |
| 82 | 83 | ||
| 83 | VAddr addr; | 84 | VAddr addr; |
| 84 | Maxwell::ShaderProgram program_type; | 85 | 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 f6a879a7b..5fde22ad4 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 | ||
| 84 | ProgramResult GenerateGeometryShader(const ShaderSetup& setup) { | 84 | ProgramResult 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 | ||