summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
authorGravatar bunnei2019-06-05 18:02:30 -0400
committerGravatar GitHub2019-06-05 18:02:30 -0400
commit0bcc305797924b4265106423d035fa3ce81c066c (patch)
treebf531abd52abd7124ad06f24ca5b995c6675cfee /src/video_core
parentMerge pull request #2526 from lioncash/global (diff)
parentgl_shader_decompiler: Use an if based cbuf indexing for broken drivers (diff)
downloadyuzu-0bcc305797924b4265106423d035fa3ce81c066c.tar.gz
yuzu-0bcc305797924b4265106423d035fa3ce81c066c.tar.xz
yuzu-0bcc305797924b4265106423d035fa3ce81c066c.zip
Merge pull request #2512 from ReinUsesLisp/comp-indexing
gl_shader_decompiler: Pessimize uniform buffer access on AMD's prorpietary driver
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp54
-rw-r--r--src/video_core/renderer_opengl/gl_device.h6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp23
3 files changed, 80 insertions, 3 deletions
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 1d1581f49..65a88b06c 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -2,11 +2,14 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
5#include <cstddef> 6#include <cstddef>
6#include <glad/glad.h> 7#include <glad/glad.h>
7 8
8#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/scope_exit.h"
9#include "video_core/renderer_opengl/gl_device.h" 11#include "video_core/renderer_opengl/gl_device.h"
12#include "video_core/renderer_opengl/gl_resource_manager.h"
10 13
11namespace OpenGL { 14namespace OpenGL {
12 15
@@ -24,6 +27,7 @@ Device::Device() {
24 max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); 27 max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
25 max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS); 28 max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
26 has_variable_aoffi = TestVariableAoffi(); 29 has_variable_aoffi = TestVariableAoffi();
30 has_component_indexing_bug = TestComponentIndexingBug();
27} 31}
28 32
29Device::Device(std::nullptr_t) { 33Device::Device(std::nullptr_t) {
@@ -31,6 +35,7 @@ Device::Device(std::nullptr_t) {
31 max_vertex_attributes = 16; 35 max_vertex_attributes = 16;
32 max_varyings = 15; 36 max_varyings = 15;
33 has_variable_aoffi = true; 37 has_variable_aoffi = true;
38 has_component_indexing_bug = false;
34} 39}
35 40
36bool Device::TestVariableAoffi() { 41bool Device::TestVariableAoffi() {
@@ -52,4 +57,53 @@ void main() {
52 return supported; 57 return supported;
53} 58}
54 59
60bool Device::TestComponentIndexingBug() {
61 constexpr char log_message[] = "Renderer_ComponentIndexingBug: {}";
62 const GLchar* COMPONENT_TEST = R"(#version 430 core
63layout (std430, binding = 0) buffer OutputBuffer {
64 uint output_value;
65};
66layout (std140, binding = 0) uniform InputBuffer {
67 uvec4 input_value[4096];
68};
69layout (location = 0) uniform uint idx;
70void main() {
71 output_value = input_value[idx >> 2][idx & 3];
72})";
73 const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &COMPONENT_TEST)};
74 SCOPE_EXIT({ glDeleteProgram(shader); });
75 glUseProgram(shader);
76
77 OGLVertexArray vao;
78 vao.Create();
79 glBindVertexArray(vao.handle);
80
81 constexpr std::array<GLuint, 8> values{0, 0, 0, 0, 0x1236327, 0x985482, 0x872753, 0x2378432};
82 OGLBuffer ubo;
83 ubo.Create();
84 glNamedBufferData(ubo.handle, sizeof(values), values.data(), GL_STATIC_DRAW);
85 glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo.handle);
86
87 OGLBuffer ssbo;
88 ssbo.Create();
89 glNamedBufferStorage(ssbo.handle, sizeof(GLuint), nullptr, GL_CLIENT_STORAGE_BIT);
90
91 for (GLuint index = 4; index < 8; ++index) {
92 glInvalidateBufferData(ssbo.handle);
93 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo.handle);
94
95 glProgramUniform1ui(shader, 0, index);
96 glDrawArrays(GL_POINTS, 0, 1);
97
98 GLuint result;
99 glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result);
100 if (result != values.at(index)) {
101 LOG_INFO(Render_OpenGL, log_message, true);
102 return true;
103 }
104 }
105 LOG_INFO(Render_OpenGL, log_message, false);
106 return false;
107}
108
55} // namespace OpenGL 109} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h
index de8490682..8c8c93760 100644
--- a/src/video_core/renderer_opengl/gl_device.h
+++ b/src/video_core/renderer_opengl/gl_device.h
@@ -30,13 +30,19 @@ public:
30 return has_variable_aoffi; 30 return has_variable_aoffi;
31 } 31 }
32 32
33 bool HasComponentIndexingBug() const {
34 return has_component_indexing_bug;
35 }
36
33private: 37private:
34 static bool TestVariableAoffi(); 38 static bool TestVariableAoffi();
39 static bool TestComponentIndexingBug();
35 40
36 std::size_t uniform_buffer_alignment{}; 41 std::size_t uniform_buffer_alignment{};
37 u32 max_vertex_attributes{}; 42 u32 max_vertex_attributes{};
38 u32 max_varyings{}; 43 u32 max_varyings{};
39 bool has_variable_aoffi{}; 44 bool has_variable_aoffi{};
45 bool has_component_indexing_bug{};
40}; 46};
41 47
42} // namespace OpenGL 48} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index e9f8d40db..3b61bf77f 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -577,9 +577,26 @@ private:
577 if (std::holds_alternative<OperationNode>(*offset)) { 577 if (std::holds_alternative<OperationNode>(*offset)) {
578 // Indirect access 578 // Indirect access
579 const std::string final_offset = code.GenerateTemporary(); 579 const std::string final_offset = code.GenerateTemporary();
580 code.AddLine("uint {} = (ftou({}) / 4);", final_offset, Visit(offset)); 580 code.AddLine("uint {} = ftou({}) >> 2;", final_offset, Visit(offset));
581 return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), 581
582 final_offset, final_offset); 582 if (!device.HasComponentIndexingBug()) {
583 return fmt::format("{}[{} >> 2][{} & 3]", GetConstBuffer(cbuf->GetIndex()),
584 final_offset, final_offset);
585 }
586
587 // AMD's proprietary GLSL compiler emits ill code for variable component access.
588 // To bypass this driver bug generate 4 ifs, one per each component.
589 const std::string pack = code.GenerateTemporary();
590 code.AddLine("vec4 {} = {}[{} >> 2];", pack, GetConstBuffer(cbuf->GetIndex()),
591 final_offset);
592
593 const std::string result = code.GenerateTemporary();
594 code.AddLine("float {};", result);
595 for (u32 swizzle = 0; swizzle < 4; ++swizzle) {
596 code.AddLine("if (({} & 3) == {}) {} = {}{};", final_offset, swizzle, result,
597 pack, GetSwizzle(swizzle));
598 }
599 return result;
583 } 600 }
584 601
585 UNREACHABLE_MSG("Unmanaged offset node type"); 602 UNREACHABLE_MSG("Unmanaged offset node type");