diff options
| author | 2018-10-23 10:21:30 -0400 | |
|---|---|---|
| committer | 2018-10-23 10:21:30 -0400 | |
| commit | 75d807788ccaf64a478fdc48aecdb841baecc34e (patch) | |
| tree | 4fc8a09dcc0f1ad915ba7d65154fafd43ae684a2 /src | |
| parent | Merge pull request #1512 from ReinUsesLisp/brk (diff) | |
| parent | Assert that multiple render targets are not set while alpha testing (diff) | |
| download | yuzu-75d807788ccaf64a478fdc48aecdb841baecc34e.tar.gz yuzu-75d807788ccaf64a478fdc48aecdb841baecc34e.tar.xz yuzu-75d807788ccaf64a478fdc48aecdb841baecc34e.zip | |
Merge pull request #1470 from FernandoS27/alpha_testing
Implemented Alpha Test using Shader Emulation
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 25 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 24 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 29 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.cpp | 11 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.h | 8 |
7 files changed, 87 insertions, 20 deletions
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index c8af1c6b6..0e09a7ee5 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -643,8 +643,10 @@ public: | |||
| 643 | u32 d3d_cull_mode; | 643 | u32 d3d_cull_mode; |
| 644 | 644 | ||
| 645 | ComparisonOp depth_test_func; | 645 | ComparisonOp depth_test_func; |
| 646 | float alpha_test_ref; | ||
| 647 | ComparisonOp alpha_test_func; | ||
| 646 | 648 | ||
| 647 | INSERT_PADDING_WORDS(0xB); | 649 | INSERT_PADDING_WORDS(0x9); |
| 648 | 650 | ||
| 649 | struct { | 651 | struct { |
| 650 | u32 separate_alpha; | 652 | u32 separate_alpha; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 3daccf82f..be51c5215 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -570,10 +570,11 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 570 | SyncBlendState(); | 570 | SyncBlendState(); |
| 571 | SyncLogicOpState(); | 571 | SyncLogicOpState(); |
| 572 | SyncCullMode(); | 572 | SyncCullMode(); |
| 573 | SyncAlphaTest(); | ||
| 574 | SyncScissorTest(); | 573 | SyncScissorTest(); |
| 574 | // Alpha Testing is synced on shaders. | ||
| 575 | SyncTransformFeedback(); | 575 | SyncTransformFeedback(); |
| 576 | SyncPointState(); | 576 | SyncPointState(); |
| 577 | CheckAlphaTests(); | ||
| 577 | 578 | ||
| 578 | // TODO(bunnei): Sync framebuffer_scale uniform here | 579 | // TODO(bunnei): Sync framebuffer_scale uniform here |
| 579 | // TODO(bunnei): Sync scissorbox uniform(s) here | 580 | // TODO(bunnei): Sync scissorbox uniform(s) here |
| @@ -1007,17 +1008,6 @@ void RasterizerOpenGL::SyncLogicOpState() { | |||
| 1007 | state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); | 1008 | state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); |
| 1008 | } | 1009 | } |
| 1009 | 1010 | ||
| 1010 | void RasterizerOpenGL::SyncAlphaTest() { | ||
| 1011 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 1012 | |||
| 1013 | // TODO(Rodrigo): Alpha testing is a legacy OpenGL feature, but it can be | ||
| 1014 | // implemented with a test+discard in fragment shaders. | ||
| 1015 | if (regs.alpha_test_enabled != 0) { | ||
| 1016 | LOG_CRITICAL(Render_OpenGL, "Alpha testing is not implemented"); | ||
| 1017 | UNREACHABLE(); | ||
| 1018 | } | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | void RasterizerOpenGL::SyncScissorTest() { | 1011 | void RasterizerOpenGL::SyncScissorTest() { |
| 1022 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1012 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 1023 | 1013 | ||
| @@ -1052,4 +1042,15 @@ void RasterizerOpenGL::SyncPointState() { | |||
| 1052 | state.point.size = regs.point_size == 0 ? 1 : regs.point_size; | 1042 | state.point.size = regs.point_size == 0 ? 1 : regs.point_size; |
| 1053 | } | 1043 | } |
| 1054 | 1044 | ||
| 1045 | void RasterizerOpenGL::CheckAlphaTests() { | ||
| 1046 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 1047 | |||
| 1048 | if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) { | ||
| 1049 | LOG_CRITICAL( | ||
| 1050 | Render_OpenGL, | ||
| 1051 | "Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined."); | ||
| 1052 | UNREACHABLE(); | ||
| 1053 | } | ||
| 1054 | } | ||
| 1055 | |||
| 1055 | } // namespace OpenGL | 1056 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index b1f7ccc7e..0e90a31f5 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -162,9 +162,6 @@ private: | |||
| 162 | /// Syncs the LogicOp state to match the guest state | 162 | /// Syncs the LogicOp state to match the guest state |
| 163 | void SyncLogicOpState(); | 163 | void SyncLogicOpState(); |
| 164 | 164 | ||
| 165 | /// Syncs the alpha test state to match the guest state | ||
| 166 | void SyncAlphaTest(); | ||
| 167 | |||
| 168 | /// Syncs the scissor test state to match the guest state | 165 | /// Syncs the scissor test state to match the guest state |
| 169 | void SyncScissorTest(); | 166 | void SyncScissorTest(); |
| 170 | 167 | ||
| @@ -174,6 +171,9 @@ private: | |||
| 174 | /// Syncs the point state to match the guest state | 171 | /// Syncs the point state to match the guest state |
| 175 | void SyncPointState(); | 172 | void SyncPointState(); |
| 176 | 173 | ||
| 174 | /// Check asserts for alpha testing. | ||
| 175 | void CheckAlphaTests(); | ||
| 176 | |||
| 177 | bool has_ARB_direct_state_access = false; | 177 | bool has_ARB_direct_state_access = false; |
| 178 | bool has_ARB_multi_bind = false; | 178 | bool has_ARB_multi_bind = false; |
| 179 | bool has_ARB_separate_shader_objects = false; | 179 | bool has_ARB_separate_shader_objects = false; |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index d36f190b7..7a019fc86 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -1266,9 +1266,29 @@ private: | |||
| 1266 | 1266 | ||
| 1267 | ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented"); | 1267 | ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented"); |
| 1268 | 1268 | ||
| 1269 | shader.AddLine("if (alpha_test[0] != 0) {"); | ||
| 1270 | ++shader.scope; | ||
| 1271 | // We start on the register containing the alpha value in the first RT. | ||
| 1272 | u32 current_reg = 3; | ||
| 1273 | for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets; | ||
| 1274 | ++render_target) { | ||
| 1275 | // TODO(Blinkhawk): verify the behavior of alpha testing on hardware when | ||
| 1276 | // multiple render targets are used. | ||
| 1277 | if (header.ps.IsColorComponentOutputEnabled(render_target, 0) || | ||
| 1278 | header.ps.IsColorComponentOutputEnabled(render_target, 1) || | ||
| 1279 | header.ps.IsColorComponentOutputEnabled(render_target, 2) || | ||
| 1280 | header.ps.IsColorComponentOutputEnabled(render_target, 3)) { | ||
| 1281 | shader.AddLine(fmt::format("if (!AlphaFunc({})) discard;", | ||
| 1282 | regs.GetRegisterAsFloat(current_reg))); | ||
| 1283 | current_reg += 4; | ||
| 1284 | } | ||
| 1285 | } | ||
| 1286 | --shader.scope; | ||
| 1287 | shader.AddLine('}'); | ||
| 1288 | |||
| 1269 | // Write the color outputs using the data in the shader registers, disabled | 1289 | // Write the color outputs using the data in the shader registers, disabled |
| 1270 | // rendertargets/components are skipped in the register assignment. | 1290 | // rendertargets/components are skipped in the register assignment. |
| 1271 | u32 current_reg = 0; | 1291 | current_reg = 0; |
| 1272 | for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets; | 1292 | for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets; |
| 1273 | ++render_target) { | 1293 | ++render_target) { |
| 1274 | // TODO(Subv): Figure out how dual-source blending is configured in the Switch. | 1294 | // TODO(Subv): Figure out how dual-source blending is configured in the Switch. |
| @@ -3516,7 +3536,7 @@ private: | |||
| 3516 | 3536 | ||
| 3517 | // Declarations | 3537 | // Declarations |
| 3518 | std::set<std::string> declr_predicates; | 3538 | std::set<std::string> declr_predicates; |
| 3519 | }; // namespace Decompiler | 3539 | }; // namespace OpenGL::GLShader::Decompiler |
| 3520 | 3540 | ||
| 3521 | std::string GetCommonDeclarations() { | 3541 | std::string GetCommonDeclarations() { |
| 3522 | return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n", | 3542 | return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n", |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index ecbc9d8ed..e883ffb1d 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -29,6 +29,7 @@ layout(std140) uniform vs_config { | |||
| 29 | vec4 viewport_flip; | 29 | vec4 viewport_flip; |
| 30 | uvec4 instance_id; | 30 | uvec4 instance_id; |
| 31 | uvec4 flip_stage; | 31 | uvec4 flip_stage; |
| 32 | uvec4 alpha_test; | ||
| 32 | }; | 33 | }; |
| 33 | )"; | 34 | )"; |
| 34 | 35 | ||
| @@ -105,6 +106,7 @@ layout (std140) uniform gs_config { | |||
| 105 | vec4 viewport_flip; | 106 | vec4 viewport_flip; |
| 106 | uvec4 instance_id; | 107 | uvec4 instance_id; |
| 107 | uvec4 flip_stage; | 108 | uvec4 flip_stage; |
| 109 | uvec4 alpha_test; | ||
| 108 | }; | 110 | }; |
| 109 | 111 | ||
| 110 | void main() { | 112 | void main() { |
| @@ -142,8 +144,33 @@ layout (std140) uniform fs_config { | |||
| 142 | vec4 viewport_flip; | 144 | vec4 viewport_flip; |
| 143 | uvec4 instance_id; | 145 | uvec4 instance_id; |
| 144 | uvec4 flip_stage; | 146 | uvec4 flip_stage; |
| 147 | uvec4 alpha_test; | ||
| 145 | }; | 148 | }; |
| 146 | 149 | ||
| 150 | bool AlphaFunc(in float value) { | ||
| 151 | float ref = uintBitsToFloat(alpha_test[2]); | ||
| 152 | switch (alpha_test[1]) { | ||
| 153 | case 1: | ||
| 154 | return false; | ||
| 155 | case 2: | ||
| 156 | return value < ref; | ||
| 157 | case 3: | ||
| 158 | return value == ref; | ||
| 159 | case 4: | ||
| 160 | return value <= ref; | ||
| 161 | case 5: | ||
| 162 | return value > ref; | ||
| 163 | case 6: | ||
| 164 | return value != ref; | ||
| 165 | case 7: | ||
| 166 | return value >= ref; | ||
| 167 | case 8: | ||
| 168 | return true; | ||
| 169 | default: | ||
| 170 | return false; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 147 | void main() { | 174 | void main() { |
| 148 | exec_fragment(); | 175 | exec_fragment(); |
| 149 | } | 176 | } |
| @@ -152,4 +179,4 @@ void main() { | |||
| 152 | out += program.first; | 179 | out += program.first; |
| 153 | return {out, program.second}; | 180 | return {out, program.second}; |
| 154 | } | 181 | } |
| 155 | } // namespace OpenGL::GLShader \ No newline at end of file | 182 | } // namespace OpenGL::GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 010857ec6..8b8869ecb 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp | |||
| @@ -16,6 +16,17 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh | |||
| 16 | viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f; | 16 | viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f; |
| 17 | viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f; | 17 | viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f; |
| 18 | 18 | ||
| 19 | u32 func = static_cast<u32>(regs.alpha_test_func); | ||
| 20 | // Normalize the gl variants of opCompare to be the same as the normal variants | ||
| 21 | u32 op_gl_variant_base = static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never); | ||
| 22 | if (func >= op_gl_variant_base) { | ||
| 23 | func = func - op_gl_variant_base + 1U; | ||
| 24 | } | ||
| 25 | |||
| 26 | alpha_test.enabled = regs.alpha_test_enabled; | ||
| 27 | alpha_test.func = func; | ||
| 28 | alpha_test.ref = regs.alpha_test_ref; | ||
| 29 | |||
| 19 | // We only assign the instance to the first component of the vector, the rest is just padding. | 30 | // We only assign the instance to the first component of the vector, the rest is just padding. |
| 20 | instance_id[0] = state.current_instance; | 31 | instance_id[0] = state.current_instance; |
| 21 | 32 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index b3a191cf2..36fe1f04c 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -22,8 +22,14 @@ struct MaxwellUniformData { | |||
| 22 | alignas(16) GLvec4 viewport_flip; | 22 | alignas(16) GLvec4 viewport_flip; |
| 23 | alignas(16) GLuvec4 instance_id; | 23 | alignas(16) GLuvec4 instance_id; |
| 24 | alignas(16) GLuvec4 flip_stage; | 24 | alignas(16) GLuvec4 flip_stage; |
| 25 | struct alignas(16) { | ||
| 26 | GLuint enabled; | ||
| 27 | GLuint func; | ||
| 28 | GLfloat ref; | ||
| 29 | GLuint padding; | ||
| 30 | } alpha_test; | ||
| 25 | }; | 31 | }; |
| 26 | static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect"); | 32 | static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect"); |
| 27 | static_assert(sizeof(MaxwellUniformData) < 16384, | 33 | static_assert(sizeof(MaxwellUniformData) < 16384, |
| 28 | "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); | 34 | "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); |
| 29 | 35 | ||