summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-10-30 00:23:09 -0300
committerGravatar ReinUsesLisp2019-11-07 01:52:18 -0300
commitf019817f8f6452dec784d8217ef102231319d26c (patch)
treed49542f0b9b4c26c651d1a3263b3a165c6a8b24b
parentMerge pull request #3078 from bunnei/azure-rename-partial (diff)
downloadyuzu-f019817f8f6452dec784d8217ef102231319d26c.tar.gz
yuzu-f019817f8f6452dec784d8217ef102231319d26c.tar.xz
yuzu-f019817f8f6452dec784d8217ef102231319d26c.zip
gl_rasterizer: Emulate viewport flipping with ARB_clip_control
Emulates negative y viewports with ARB_clip_control. This allows us to more easily emulated pipelines with tessellation and/or geometry shader stages. It also avoids corrupting games with transform feedbacks and negative viewports (gl_Position.y was being modified).
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp50
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp24
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp19
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h15
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_state.h5
-rw-r--r--src/yuzu/main.cpp3
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp2
9 files changed, 57 insertions, 76 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index e560d70d5..53ee754ff 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -257,10 +257,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
257 continue; 257 continue;
258 } 258 }
259 259
260 const std::size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5
261
262 GLShader::MaxwellUniformData ubo{}; 260 GLShader::MaxwellUniformData ubo{};
263 ubo.SetFromRegs(gpu, stage); 261 ubo.SetFromRegs(gpu);
264 const auto [buffer, offset] = 262 const auto [buffer, offset] =
265 buffer_cache.UploadHostMemory(&ubo, sizeof(ubo), device.GetUniformBufferAlignment()); 263 buffer_cache.UploadHostMemory(&ubo, sizeof(ubo), device.GetUniformBufferAlignment());
266 264
@@ -269,10 +267,11 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
269 267
270 Shader shader{shader_cache.GetStageProgram(program)}; 268 Shader shader{shader_cache.GetStageProgram(program)};
271 269
272 const auto stage_enum = static_cast<Maxwell::ShaderStage>(stage); 270 // Stage indices are 0 - 5
273 SetupDrawConstBuffers(stage_enum, shader); 271 const auto stage = static_cast<Maxwell::ShaderStage>(index == 0 ? 0 : index - 1);
274 SetupDrawGlobalMemory(stage_enum, shader); 272 SetupDrawConstBuffers(stage, shader);
275 const auto texture_buffer_usage{SetupDrawTextures(stage_enum, shader, base_bindings)}; 273 SetupDrawGlobalMemory(stage, shader);
274 const auto texture_buffer_usage{SetupDrawTextures(stage, shader, base_bindings)};
276 275
277 const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage}; 276 const ProgramVariant variant{base_bindings, primitive_mode, texture_buffer_usage};
278 const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant); 277 const auto [program_handle, next_bindings] = shader->GetProgramHandle(variant);
@@ -1055,6 +1054,15 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
1055 } 1054 }
1056 state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0; 1055 state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0;
1057 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0; 1056 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
1057
1058 bool flip_y = false;
1059 if (regs.viewport_transform[0].scale_y < 0.0) {
1060 flip_y = !flip_y;
1061 }
1062 if (regs.screen_y_control.y_negate != 0) {
1063 flip_y = !flip_y;
1064 }
1065 state.clip_control.origin = flip_y ? GL_UPPER_LEFT : GL_LOWER_LEFT;
1058} 1066}
1059 1067
1060void RasterizerOpenGL::SyncClipEnabled( 1068void RasterizerOpenGL::SyncClipEnabled(
@@ -1077,26 +1085,24 @@ void RasterizerOpenGL::SyncClipCoef() {
1077} 1085}
1078 1086
1079void RasterizerOpenGL::SyncCullMode() { 1087void RasterizerOpenGL::SyncCullMode() {
1080 auto& maxwell3d = system.GPU().Maxwell3D(); 1088 const auto& regs = system.GPU().Maxwell3D().regs;
1081
1082 const auto& regs = maxwell3d.regs;
1083 1089
1084 state.cull.enabled = regs.cull.enabled != 0; 1090 state.cull.enabled = regs.cull.enabled != 0;
1085 if (state.cull.enabled) { 1091 if (state.cull.enabled) {
1086 state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face);
1087 state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face); 1092 state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face);
1093 }
1094
1095 state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face);
1088 1096
1089 const bool flip_triangles{regs.screen_y_control.triangle_rast_flip == 0 || 1097 // If the GPU is configured to flip the rasterized triangles, then we need to flip the
1090 regs.viewport_transform[0].scale_y < 0.0f}; 1098 // notion of front and back.
1091 1099 const bool flip_triangles{regs.screen_y_control.triangle_rast_flip != 0 &&
1092 // If the GPU is configured to flip the rasterized triangles, then we need to flip the 1100 regs.viewport_transform[0].scale_y > 0.0f};
1093 // notion of front and back. Note: We flip the triangles when the value of the register is 0 1101 if (flip_triangles) {
1094 // because OpenGL already does it for us. 1102 if (state.cull.front_face == GL_CCW) {
1095 if (flip_triangles) { 1103 state.cull.front_face = GL_CW;
1096 if (state.cull.front_face == GL_CCW) 1104 } else if (state.cull.front_face == GL_CW) {
1097 state.cull.front_face = GL_CW; 1105 state.cull.front_face = GL_CCW;
1098 else if (state.cull.front_face == GL_CW)
1099 state.cull.front_face = GL_CCW;
1100 } 1106 }
1101 } 1107 }
1102} 1108}
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 92ee8459e..8dcbeefc0 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1872,10 +1872,6 @@ private:
1872 Expression EmitVertex(Operation operation) { 1872 Expression EmitVertex(Operation operation) {
1873 ASSERT_MSG(stage == ProgramType::Geometry, 1873 ASSERT_MSG(stage == ProgramType::Geometry,
1874 "EmitVertex is expected to be used in a geometry shader."); 1874 "EmitVertex is expected to be used in a geometry shader.");
1875
1876 // If a geometry shader is attached, it will always flip (it's the last stage before
1877 // fragment). For more info about flipping, refer to gl_shader_gen.cpp.
1878 code.AddLine("gl_Position.xy *= viewport_flip.xy;");
1879 code.AddLine("EmitVertex();"); 1875 code.AddLine("EmitVertex();");
1880 return {}; 1876 return {};
1881 } 1877 }
@@ -1883,14 +1879,12 @@ private:
1883 Expression EndPrimitive(Operation operation) { 1879 Expression EndPrimitive(Operation operation) {
1884 ASSERT_MSG(stage == ProgramType::Geometry, 1880 ASSERT_MSG(stage == ProgramType::Geometry,
1885 "EndPrimitive is expected to be used in a geometry shader."); 1881 "EndPrimitive is expected to be used in a geometry shader.");
1886
1887 code.AddLine("EndPrimitive();"); 1882 code.AddLine("EndPrimitive();");
1888 return {}; 1883 return {};
1889 } 1884 }
1890 1885
1891 Expression YNegate(Operation operation) { 1886 Expression YNegate(Operation operation) {
1892 // Config pack's third value is Y_NEGATE's state. 1887 return {"y_negate", Type::Float};
1893 return {"config_pack[2]", Type::Uint};
1894 } 1888 }
1895 1889
1896 template <u32 element> 1890 template <u32 element>
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 0e22eede9..af17216bd 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -20,8 +20,7 @@ std::string GenerateVertexShader(const Device& device, const ShaderIR& ir, const
20 std::string out = GetCommonDeclarations(); 20 std::string out = GetCommonDeclarations();
21 out += R"( 21 out += R"(
22layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { 22layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config {
23 vec4 viewport_flip; 23 float y_direction;
24 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
25}; 24};
26 25
27)"; 26)";
@@ -35,23 +34,10 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config {
35void main() { 34void main() {
36 execute_vertex(); 35 execute_vertex();
37)"; 36)";
38
39 if (ir_b) { 37 if (ir_b) {
40 out += " execute_vertex_b();"; 38 out += " execute_vertex_b();";
41 } 39 }
42 40 out += "}\n";
43 out += R"(
44
45 // Set Position Y direction
46 gl_Position.y *= utof(config_pack[2]);
47 // Check if the flip stage is VertexB
48 // Config pack's second value is flip_stage
49 if (config_pack[1] == 1) {
50 // Viewport can be flipped, which is unsupported by glViewport
51 gl_Position.xy *= viewport_flip.xy;
52 }
53}
54)";
55 return out; 41 return out;
56} 42}
57 43
@@ -59,8 +45,7 @@ std::string GenerateGeometryShader(const Device& device, const ShaderIR& ir) {
59 std::string out = GetCommonDeclarations(); 45 std::string out = GetCommonDeclarations();
60 out += R"( 46 out += R"(
61layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { 47layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config {
62 vec4 viewport_flip; 48 float y_direction;
63 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
64}; 49};
65 50
66)"; 51)";
@@ -87,8 +72,7 @@ layout (location = 6) out vec4 FragColor6;
87layout (location = 7) out vec4 FragColor7; 72layout (location = 7) out vec4 FragColor7;
88 73
89layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { 74layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config {
90 vec4 viewport_flip; 75 float y_direction;
91 uvec4 config_pack; // instance_id, flip_stage, y_direction, padding
92}; 76};
93 77
94)"; 78)";
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index b05f90f20..cd729d978 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -40,27 +40,12 @@ void ProgramManager::UpdatePipeline() {
40 old_state = current_state; 40 old_state = current_state;
41} 41}
42 42
43void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell, std::size_t shader_stage) { 43void MaxwellUniformData::SetFromRegs(const Maxwell3D& maxwell) {
44 const auto& regs = maxwell.regs; 44 const auto& regs = maxwell.regs;
45 const auto& state = maxwell.state; 45 const auto& state = maxwell.state;
46 46
47 // TODO(bunnei): Support more than one viewport
48 viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f;
49 viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f;
50
51 instance_id = state.current_instance;
52
53 // Assign in which stage the position has to be flipped
54 // (the last stage before the fragment shader).
55 constexpr u32 geometry_index = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry);
56 if (maxwell.regs.shader_config[geometry_index].enable) {
57 flip_stage = geometry_index;
58 } else {
59 flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB);
60 }
61
62 // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value. 47 // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value.
63 y_direction = regs.screen_y_control.y_negate == 0 ? 1.f : -1.f; 48 y_direction = regs.screen_y_control.y_negate == 0 ? 1.0f : -1.0f;
64} 49}
65 50
66} // namespace OpenGL::GLShader 51} // namespace OpenGL::GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 6961e702a..3703e7018 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -18,17 +18,12 @@ namespace OpenGL::GLShader {
18/// @note Always keep a vec4 at the end. The GL spec is not clear whether the alignment at 18/// @note Always keep a vec4 at the end. The GL spec is not clear whether the alignment at
19/// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not. 19/// the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not.
20/// Not following that rule will cause problems on some AMD drivers. 20/// Not following that rule will cause problems on some AMD drivers.
21struct MaxwellUniformData { 21struct alignas(16) MaxwellUniformData {
22 void SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell, std::size_t shader_stage); 22 void SetFromRegs(const Tegra::Engines::Maxwell3D& maxwell);
23 23
24 alignas(16) GLvec4 viewport_flip; 24 GLfloat y_direction;
25 struct alignas(16) {
26 GLuint instance_id;
27 GLuint flip_stage;
28 GLfloat y_direction;
29 };
30}; 25};
31static_assert(sizeof(MaxwellUniformData) == 32, "MaxwellUniformData structure size is incorrect"); 26static_assert(sizeof(MaxwellUniformData) == 16, "MaxwellUniformData structure size is incorrect");
32static_assert(sizeof(MaxwellUniformData) < 16384, 27static_assert(sizeof(MaxwellUniformData) < 16384,
33 "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); 28 "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
34 29
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index f25148362..ccbe5912e 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -410,6 +410,12 @@ void OpenGLState::ApplyAlphaTest() {
410 } 410 }
411} 411}
412 412
413void OpenGLState::ApplyClipControl() {
414 if (UpdateValue(cur_state.clip_control.origin, clip_control.origin)) {
415 glClipControl(clip_control.origin, GL_NEGATIVE_ONE_TO_ONE);
416 }
417}
418
413void OpenGLState::ApplyTextures() { 419void OpenGLState::ApplyTextures() {
414 if (const auto update = UpdateArray(cur_state.textures, textures)) { 420 if (const auto update = UpdateArray(cur_state.textures, textures)) {
415 glBindTextures(update->first, update->second, textures.data() + update->first); 421 glBindTextures(update->first, update->second, textures.data() + update->first);
@@ -453,6 +459,7 @@ void OpenGLState::Apply() {
453 ApplyImages(); 459 ApplyImages();
454 ApplyPolygonOffset(); 460 ApplyPolygonOffset();
455 ApplyAlphaTest(); 461 ApplyAlphaTest();
462 ApplyClipControl();
456} 463}
457 464
458void OpenGLState::EmulateViewportWithScissor() { 465void OpenGLState::EmulateViewportWithScissor() {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index cca25206b..eaff22bda 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -146,6 +146,10 @@ public:
146 146
147 std::array<bool, 8> clip_distance = {}; // GL_CLIP_DISTANCE 147 std::array<bool, 8> clip_distance = {}; // GL_CLIP_DISTANCE
148 148
149 struct {
150 GLenum origin = GL_LOWER_LEFT;
151 } clip_control;
152
149 OpenGLState(); 153 OpenGLState();
150 154
151 /// Get the currently active OpenGL state 155 /// Get the currently active OpenGL state
@@ -182,6 +186,7 @@ public:
182 void ApplyDepthClamp(); 186 void ApplyDepthClamp();
183 void ApplyPolygonOffset(); 187 void ApplyPolygonOffset();
184 void ApplyAlphaTest(); 188 void ApplyAlphaTest();
189 void ApplyClipControl();
185 190
186 /// Resets any references to the given resource 191 /// Resets any references to the given resource
187 OpenGLState& UnbindTexture(GLuint handle); 192 OpenGLState& UnbindTexture(GLuint handle);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 160613ee1..867f8e913 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -817,6 +817,9 @@ QStringList GMainWindow::GetUnsupportedGLExtensions() {
817 if (!GLAD_GL_ARB_multi_bind) { 817 if (!GLAD_GL_ARB_multi_bind) {
818 unsupported_ext.append(QStringLiteral("ARB_multi_bind")); 818 unsupported_ext.append(QStringLiteral("ARB_multi_bind"));
819 } 819 }
820 if (!GLAD_GL_ARB_clip_control) {
821 unsupported_ext.append(QStringLiteral("ARB_clip_control"));
822 }
820 823
821 // Extensions required to support some texture formats. 824 // Extensions required to support some texture formats.
822 if (!GLAD_GL_EXT_texture_compression_s3tc) { 825 if (!GLAD_GL_EXT_texture_compression_s3tc) {
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index f91b071bf..075a7074f 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -62,6 +62,8 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
62 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); 62 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge");
63 if (!GLAD_GL_ARB_multi_bind) 63 if (!GLAD_GL_ARB_multi_bind)
64 unsupported_ext.push_back("ARB_multi_bind"); 64 unsupported_ext.push_back("ARB_multi_bind");
65 if (!GLAD_GL_ARB_clip_control)
66 unsupported_ext.push_back("ARB_clip_control");
65 67
66 // Extensions required to support some texture formats. 68 // Extensions required to support some texture formats.
67 if (!GLAD_GL_EXT_texture_compression_s3tc) 69 if (!GLAD_GL_EXT_texture_compression_s3tc)