diff options
| author | 2018-08-23 12:04:08 -0400 | |
|---|---|---|
| committer | 2018-08-23 12:04:08 -0400 | |
| commit | 3ed0115e36a8b563aa40b32cd645165e12b1ba81 (patch) | |
| tree | 37c8529b9f2037dfb2072a248e4d257edc6144d7 /src | |
| parent | Merge pull request #1157 from lioncash/vec (diff) | |
| parent | gl_rasterizer: Implement stencil test. (diff) | |
| download | yuzu-3ed0115e36a8b563aa40b32cd645165e12b1ba81.tar.gz yuzu-3ed0115e36a8b563aa40b32cd645165e12b1ba81.tar.xz yuzu-3ed0115e36a8b563aa40b32cd645165e12b1ba81.zip | |
Merge pull request #1153 from bunnei/stencil-clear
gl_rasterizer: Implement partial color clear, stencil clear, and stencil test.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 70 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 89 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 53 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 18 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/maxwell_to_gl.h | 24 |
6 files changed, 188 insertions, 69 deletions
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index d03bc1c0c..92bfda053 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -330,6 +330,17 @@ public: | |||
| 330 | Set = 0x150F, | 330 | Set = 0x150F, |
| 331 | }; | 331 | }; |
| 332 | 332 | ||
| 333 | enum class StencilOp : u32 { | ||
| 334 | Keep = 1, | ||
| 335 | Zero = 2, | ||
| 336 | Replace = 3, | ||
| 337 | Incr = 4, | ||
| 338 | Decr = 5, | ||
| 339 | Invert = 6, | ||
| 340 | IncrWrap = 7, | ||
| 341 | DecrWrap = 8, | ||
| 342 | }; | ||
| 343 | |||
| 333 | struct Cull { | 344 | struct Cull { |
| 334 | enum class FrontFace : u32 { | 345 | enum class FrontFace : u32 { |
| 335 | ClockWise = 0x0900, | 346 | ClockWise = 0x0900, |
| @@ -508,8 +519,16 @@ public: | |||
| 508 | 519 | ||
| 509 | float clear_color[4]; | 520 | float clear_color[4]; |
| 510 | float clear_depth; | 521 | float clear_depth; |
| 522 | INSERT_PADDING_WORDS(0x3); | ||
| 523 | s32 clear_stencil; | ||
| 524 | |||
| 525 | INSERT_PADDING_WORDS(0x6C); | ||
| 526 | |||
| 527 | s32 stencil_back_func_ref; | ||
| 528 | u32 stencil_back_mask; | ||
| 529 | u32 stencil_back_func_mask; | ||
| 511 | 530 | ||
| 512 | INSERT_PADDING_WORDS(0x93); | 531 | INSERT_PADDING_WORDS(0x20); |
| 513 | 532 | ||
| 514 | struct { | 533 | struct { |
| 515 | u32 address_high; | 534 | u32 address_high; |
| @@ -573,16 +592,14 @@ public: | |||
| 573 | u32 enable[NumRenderTargets]; | 592 | u32 enable[NumRenderTargets]; |
| 574 | } blend; | 593 | } blend; |
| 575 | 594 | ||
| 576 | struct { | 595 | u32 stencil_enable; |
| 577 | u32 enable; | 596 | StencilOp stencil_front_op_fail; |
| 578 | u32 front_op_fail; | 597 | StencilOp stencil_front_op_zfail; |
| 579 | u32 front_op_zfail; | 598 | StencilOp stencil_front_op_zpass; |
| 580 | u32 front_op_zpass; | 599 | ComparisonOp stencil_front_func_func; |
| 581 | u32 front_func_func; | 600 | s32 stencil_front_func_ref; |
| 582 | u32 front_func_ref; | 601 | u32 stencil_front_func_mask; |
| 583 | u32 front_func_mask; | 602 | u32 stencil_front_mask; |
| 584 | u32 front_mask; | ||
| 585 | } stencil; | ||
| 586 | 603 | ||
| 587 | INSERT_PADDING_WORDS(0x3); | 604 | INSERT_PADDING_WORDS(0x3); |
| 588 | 605 | ||
| @@ -626,13 +643,11 @@ public: | |||
| 626 | 643 | ||
| 627 | INSERT_PADDING_WORDS(0x5); | 644 | INSERT_PADDING_WORDS(0x5); |
| 628 | 645 | ||
| 629 | struct { | 646 | u32 stencil_two_side_enable; |
| 630 | u32 enable; | 647 | StencilOp stencil_back_op_fail; |
| 631 | u32 back_op_fail; | 648 | StencilOp stencil_back_op_zfail; |
| 632 | u32 back_op_zfail; | 649 | StencilOp stencil_back_op_zpass; |
| 633 | u32 back_op_zpass; | 650 | ComparisonOp stencil_back_func_func; |
| 634 | u32 back_func_func; | ||
| 635 | } stencil_two_side; | ||
| 636 | 651 | ||
| 637 | INSERT_PADDING_WORDS(0x17); | 652 | INSERT_PADDING_WORDS(0x17); |
| 638 | 653 | ||
| @@ -944,6 +959,10 @@ ASSERT_REG_POSITION(viewport, 0x300); | |||
| 944 | ASSERT_REG_POSITION(vertex_buffer, 0x35D); | 959 | ASSERT_REG_POSITION(vertex_buffer, 0x35D); |
| 945 | ASSERT_REG_POSITION(clear_color[0], 0x360); | 960 | ASSERT_REG_POSITION(clear_color[0], 0x360); |
| 946 | ASSERT_REG_POSITION(clear_depth, 0x364); | 961 | ASSERT_REG_POSITION(clear_depth, 0x364); |
| 962 | ASSERT_REG_POSITION(clear_stencil, 0x368); | ||
| 963 | ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); | ||
| 964 | ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); | ||
| 965 | ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); | ||
| 947 | ASSERT_REG_POSITION(zeta, 0x3F8); | 966 | ASSERT_REG_POSITION(zeta, 0x3F8); |
| 948 | ASSERT_REG_POSITION(vertex_attrib_format[0], 0x458); | 967 | ASSERT_REG_POSITION(vertex_attrib_format[0], 0x458); |
| 949 | ASSERT_REG_POSITION(rt_control, 0x487); | 968 | ASSERT_REG_POSITION(rt_control, 0x487); |
| @@ -955,13 +974,24 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA); | |||
| 955 | ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); | 974 | ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); |
| 956 | ASSERT_REG_POSITION(depth_test_func, 0x4C3); | 975 | ASSERT_REG_POSITION(depth_test_func, 0x4C3); |
| 957 | ASSERT_REG_POSITION(blend, 0x4CF); | 976 | ASSERT_REG_POSITION(blend, 0x4CF); |
| 958 | ASSERT_REG_POSITION(stencil, 0x4E0); | 977 | ASSERT_REG_POSITION(stencil_enable, 0x4E0); |
| 978 | ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1); | ||
| 979 | ASSERT_REG_POSITION(stencil_front_op_zfail, 0x4E2); | ||
| 980 | ASSERT_REG_POSITION(stencil_front_op_zpass, 0x4E3); | ||
| 981 | ASSERT_REG_POSITION(stencil_front_func_func, 0x4E4); | ||
| 982 | ASSERT_REG_POSITION(stencil_front_func_ref, 0x4E5); | ||
| 983 | ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6); | ||
| 984 | ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); | ||
| 959 | ASSERT_REG_POSITION(screen_y_control, 0x4EB); | 985 | ASSERT_REG_POSITION(screen_y_control, 0x4EB); |
| 960 | ASSERT_REG_POSITION(vb_element_base, 0x50D); | 986 | ASSERT_REG_POSITION(vb_element_base, 0x50D); |
| 961 | ASSERT_REG_POSITION(zeta_enable, 0x54E); | 987 | ASSERT_REG_POSITION(zeta_enable, 0x54E); |
| 962 | ASSERT_REG_POSITION(tsc, 0x557); | 988 | ASSERT_REG_POSITION(tsc, 0x557); |
| 963 | ASSERT_REG_POSITION(tic, 0x55D); | 989 | ASSERT_REG_POSITION(tic, 0x55D); |
| 964 | ASSERT_REG_POSITION(stencil_two_side, 0x565); | 990 | ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); |
| 991 | ASSERT_REG_POSITION(stencil_back_op_fail, 0x566); | ||
| 992 | ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567); | ||
| 993 | ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); | ||
| 994 | ASSERT_REG_POSITION(stencil_back_func_func, 0x569); | ||
| 965 | ASSERT_REG_POSITION(point_coord_replace, 0x581); | 995 | ASSERT_REG_POSITION(point_coord_replace, 0x581); |
| 966 | ASSERT_REG_POSITION(code_address, 0x582); | 996 | ASSERT_REG_POSITION(code_address, 0x582); |
| 967 | ASSERT_REG_POSITION(draw, 0x585); | 997 | ASSERT_REG_POSITION(draw, 0x585); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 516e1b50f..8bfa75b84 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| 15 | #include "common/math_util.h" | 15 | #include "common/math_util.h" |
| 16 | #include "common/microprofile.h" | 16 | #include "common/microprofile.h" |
| 17 | #include "common/scope_exit.h" | ||
| 17 | #include "core/core.h" | 18 | #include "core/core.h" |
| 18 | #include "core/frontend/emu_window.h" | 19 | #include "core/frontend/emu_window.h" |
| 19 | #include "core/hle/kernel/process.h" | 20 | #include "core/hle/kernel/process.h" |
| @@ -315,16 +316,14 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c | |||
| 315 | using_color_fb = false; | 316 | using_color_fb = false; |
| 316 | } | 317 | } |
| 317 | 318 | ||
| 318 | // TODO(bunnei): Implement this | 319 | const bool has_stencil = regs.stencil_enable; |
| 319 | const bool has_stencil = false; | ||
| 320 | |||
| 321 | const bool write_color_fb = | 320 | const bool write_color_fb = |
| 322 | state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || | 321 | state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || |
| 323 | state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE; | 322 | state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE; |
| 324 | 323 | ||
| 325 | const bool write_depth_fb = | 324 | const bool write_depth_fb = |
| 326 | (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) || | 325 | (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) || |
| 327 | (has_stencil && state.stencil.test_enabled && state.stencil.write_mask != 0); | 326 | (has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask)); |
| 328 | 327 | ||
| 329 | Surface color_surface; | 328 | Surface color_surface; |
| 330 | Surface depth_surface; | 329 | Surface depth_surface; |
| @@ -364,41 +363,70 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c | |||
| 364 | } | 363 | } |
| 365 | 364 | ||
| 366 | void RasterizerOpenGL::Clear() { | 365 | void RasterizerOpenGL::Clear() { |
| 367 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 366 | const auto prev_state{state}; |
| 367 | SCOPE_EXIT({ prev_state.Apply(); }); | ||
| 368 | 368 | ||
| 369 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 369 | bool use_color_fb = false; | 370 | bool use_color_fb = false; |
| 370 | bool use_depth_fb = false; | 371 | bool use_depth_fb = false; |
| 371 | 372 | ||
| 372 | GLbitfield clear_mask = 0; | 373 | OpenGLState clear_state; |
| 373 | if (regs.clear_buffers.R && regs.clear_buffers.G && regs.clear_buffers.B && | 374 | clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer; |
| 375 | clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; | ||
| 376 | clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; | ||
| 377 | clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; | ||
| 378 | clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; | ||
| 379 | |||
| 380 | GLbitfield clear_mask{}; | ||
| 381 | if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || | ||
| 374 | regs.clear_buffers.A) { | 382 | regs.clear_buffers.A) { |
| 375 | clear_mask |= GL_COLOR_BUFFER_BIT; | 383 | if (regs.clear_buffers.RT == 0) { |
| 376 | use_color_fb = true; | 384 | // We only support clearing the first color attachment for now |
| 385 | clear_mask |= GL_COLOR_BUFFER_BIT; | ||
| 386 | use_color_fb = true; | ||
| 387 | } else { | ||
| 388 | // TODO(subv): Add support for the other color attachments | ||
| 389 | LOG_CRITICAL(HW_GPU, "Clear unimplemented for RT {}", regs.clear_buffers.RT); | ||
| 390 | } | ||
| 377 | } | 391 | } |
| 378 | if (regs.clear_buffers.Z) { | 392 | if (regs.clear_buffers.Z) { |
| 393 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); | ||
| 394 | use_depth_fb = true; | ||
| 379 | clear_mask |= GL_DEPTH_BUFFER_BIT; | 395 | clear_mask |= GL_DEPTH_BUFFER_BIT; |
| 380 | use_depth_fb = regs.zeta_enable != 0; | ||
| 381 | 396 | ||
| 382 | // Always enable the depth write when clearing the depth buffer. The depth write mask is | 397 | // Always enable the depth write when clearing the depth buffer. The depth write mask is |
| 383 | // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. | 398 | // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. |
| 384 | state.depth.test_enabled = true; | 399 | clear_state.depth.test_enabled = true; |
| 385 | state.depth.write_mask = GL_TRUE; | 400 | clear_state.depth.test_func = GL_ALWAYS; |
| 386 | state.depth.test_func = GL_ALWAYS; | 401 | } |
| 387 | state.Apply(); | 402 | if (regs.clear_buffers.S) { |
| 403 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); | ||
| 404 | use_depth_fb = true; | ||
| 405 | clear_mask |= GL_STENCIL_BUFFER_BIT; | ||
| 406 | clear_state.stencil.test_enabled = true; | ||
| 388 | } | 407 | } |
| 389 | 408 | ||
| 390 | if (clear_mask == 0) | 409 | if (!use_color_fb && !use_depth_fb) { |
| 410 | // No color surface nor depth/stencil surface are enabled | ||
| 391 | return; | 411 | return; |
| 412 | } | ||
| 413 | |||
| 414 | if (clear_mask == 0) { | ||
| 415 | // No clear mask is enabled | ||
| 416 | return; | ||
| 417 | } | ||
| 392 | 418 | ||
| 393 | ScopeAcquireGLContext acquire_context{emu_window}; | 419 | ScopeAcquireGLContext acquire_context{emu_window}; |
| 394 | 420 | ||
| 395 | auto [dirty_color_surface, dirty_depth_surface] = | 421 | auto [dirty_color_surface, dirty_depth_surface] = |
| 396 | ConfigureFramebuffers(use_color_fb, use_depth_fb, false); | 422 | ConfigureFramebuffers(use_color_fb, use_depth_fb, false); |
| 397 | 423 | ||
| 398 | // TODO(Subv): Support clearing only partial colors. | 424 | clear_state.Apply(); |
| 425 | |||
| 399 | glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2], | 426 | glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2], |
| 400 | regs.clear_color[3]); | 427 | regs.clear_color[3]); |
| 401 | glClearDepth(regs.clear_depth); | 428 | glClearDepth(regs.clear_depth); |
| 429 | glClearStencil(regs.clear_stencil); | ||
| 402 | 430 | ||
| 403 | glClear(clear_mask); | 431 | glClear(clear_mask); |
| 404 | 432 | ||
| @@ -451,6 +479,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 451 | ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0, true); | 479 | ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0, true); |
| 452 | 480 | ||
| 453 | SyncDepthTestState(); | 481 | SyncDepthTestState(); |
| 482 | SyncStencilTestState(); | ||
| 454 | SyncBlendState(); | 483 | SyncBlendState(); |
| 455 | SyncLogicOpState(); | 484 | SyncLogicOpState(); |
| 456 | SyncCullMode(); | 485 | SyncCullMode(); |
| @@ -841,6 +870,34 @@ void RasterizerOpenGL::SyncDepthTestState() { | |||
| 841 | state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func); | 870 | state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func); |
| 842 | } | 871 | } |
| 843 | 872 | ||
| 873 | void RasterizerOpenGL::SyncStencilTestState() { | ||
| 874 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 875 | state.stencil.test_enabled = regs.stencil_enable != 0; | ||
| 876 | |||
| 877 | if (!regs.stencil_enable) { | ||
| 878 | return; | ||
| 879 | } | ||
| 880 | |||
| 881 | // TODO(bunnei): Verify behavior when this is not set | ||
| 882 | ASSERT(regs.stencil_two_side_enable); | ||
| 883 | |||
| 884 | state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func); | ||
| 885 | state.stencil.front.test_ref = regs.stencil_front_func_ref; | ||
| 886 | state.stencil.front.test_mask = regs.stencil_front_func_mask; | ||
| 887 | state.stencil.front.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_fail); | ||
| 888 | state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail); | ||
| 889 | state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass); | ||
| 890 | state.stencil.front.write_mask = regs.stencil_front_mask; | ||
| 891 | |||
| 892 | state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func); | ||
| 893 | state.stencil.back.test_ref = regs.stencil_back_func_ref; | ||
| 894 | state.stencil.back.test_mask = regs.stencil_back_func_mask; | ||
| 895 | state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail); | ||
| 896 | state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail); | ||
| 897 | state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass); | ||
| 898 | state.stencil.back.write_mask = regs.stencil_back_mask; | ||
| 899 | } | ||
| 900 | |||
| 844 | void RasterizerOpenGL::SyncBlendState() { | 901 | void RasterizerOpenGL::SyncBlendState() { |
| 845 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 902 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 846 | 903 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 59b727de0..531b04046 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -141,6 +141,9 @@ private: | |||
| 141 | /// Syncs the depth test state to match the guest state | 141 | /// Syncs the depth test state to match the guest state |
| 142 | void SyncDepthTestState(); | 142 | void SyncDepthTestState(); |
| 143 | 143 | ||
| 144 | /// Syncs the stencil test state to match the guest state | ||
| 145 | void SyncStencilTestState(); | ||
| 146 | |||
| 144 | /// Syncs the blend state to match the guest state | 147 | /// Syncs the blend state to match the guest state |
| 145 | void SyncBlendState(); | 148 | void SyncBlendState(); |
| 146 | 149 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index e1a887d67..60a4defd1 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -27,13 +27,17 @@ OpenGLState::OpenGLState() { | |||
| 27 | color_mask.alpha_enabled = GL_TRUE; | 27 | color_mask.alpha_enabled = GL_TRUE; |
| 28 | 28 | ||
| 29 | stencil.test_enabled = false; | 29 | stencil.test_enabled = false; |
| 30 | stencil.test_func = GL_ALWAYS; | 30 | auto reset_stencil = [](auto& config) { |
| 31 | stencil.test_ref = 0; | 31 | config.test_func = GL_ALWAYS; |
| 32 | stencil.test_mask = 0xFF; | 32 | config.test_ref = 0; |
| 33 | stencil.write_mask = 0xFF; | 33 | config.test_mask = 0xFFFFFFFF; |
| 34 | stencil.action_depth_fail = GL_KEEP; | 34 | config.write_mask = 0xFFFFFFFF; |
| 35 | stencil.action_depth_pass = GL_KEEP; | 35 | config.action_depth_fail = GL_KEEP; |
| 36 | stencil.action_stencil_fail = GL_KEEP; | 36 | config.action_depth_pass = GL_KEEP; |
| 37 | config.action_stencil_fail = GL_KEEP; | ||
| 38 | }; | ||
| 39 | reset_stencil(stencil.front); | ||
| 40 | reset_stencil(stencil.back); | ||
| 37 | 41 | ||
| 38 | blend.enabled = true; | 42 | blend.enabled = true; |
| 39 | blend.rgb_equation = GL_FUNC_ADD; | 43 | blend.rgb_equation = GL_FUNC_ADD; |
| @@ -129,24 +133,23 @@ void OpenGLState::Apply() const { | |||
| 129 | glDisable(GL_STENCIL_TEST); | 133 | glDisable(GL_STENCIL_TEST); |
| 130 | } | 134 | } |
| 131 | } | 135 | } |
| 132 | 136 | auto config_stencil = [](GLenum face, const auto& config, const auto& prev_config) { | |
| 133 | if (stencil.test_func != cur_state.stencil.test_func || | 137 | if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref || |
| 134 | stencil.test_ref != cur_state.stencil.test_ref || | 138 | config.test_mask != prev_config.test_mask) { |
| 135 | stencil.test_mask != cur_state.stencil.test_mask) { | 139 | glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); |
| 136 | glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); | 140 | } |
| 137 | } | 141 | if (config.action_depth_fail != prev_config.action_depth_fail || |
| 138 | 142 | config.action_depth_pass != prev_config.action_depth_pass || | |
| 139 | if (stencil.action_depth_fail != cur_state.stencil.action_depth_fail || | 143 | config.action_stencil_fail != prev_config.action_stencil_fail) { |
| 140 | stencil.action_depth_pass != cur_state.stencil.action_depth_pass || | 144 | glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, |
| 141 | stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) { | 145 | config.action_depth_pass); |
| 142 | glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, | 146 | } |
| 143 | stencil.action_depth_pass); | 147 | if (config.write_mask != prev_config.write_mask) { |
| 144 | } | 148 | glStencilMaskSeparate(face, config.write_mask); |
| 145 | 149 | } | |
| 146 | // Stencil mask | 150 | }; |
| 147 | if (stencil.write_mask != cur_state.stencil.write_mask) { | 151 | config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front); |
| 148 | glStencilMask(stencil.write_mask); | 152 | config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); |
| 149 | } | ||
| 150 | 153 | ||
| 151 | // Blending | 154 | // Blending |
| 152 | if (blend.enabled != cur_state.blend.enabled) { | 155 | if (blend.enabled != cur_state.blend.enabled) { |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 22b0b1e41..46e96a97d 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -58,14 +58,16 @@ public: | |||
| 58 | } color_mask; // GL_COLOR_WRITEMASK | 58 | } color_mask; // GL_COLOR_WRITEMASK |
| 59 | 59 | ||
| 60 | struct { | 60 | struct { |
| 61 | bool test_enabled; // GL_STENCIL_TEST | 61 | bool test_enabled; // GL_STENCIL_TEST |
| 62 | GLenum test_func; // GL_STENCIL_FUNC | 62 | struct { |
| 63 | GLint test_ref; // GL_STENCIL_REF | 63 | GLenum test_func; // GL_STENCIL_FUNC |
| 64 | GLuint test_mask; // GL_STENCIL_VALUE_MASK | 64 | GLint test_ref; // GL_STENCIL_REF |
| 65 | GLuint write_mask; // GL_STENCIL_WRITEMASK | 65 | GLuint test_mask; // GL_STENCIL_VALUE_MASK |
| 66 | GLenum action_stencil_fail; // GL_STENCIL_FAIL | 66 | GLuint write_mask; // GL_STENCIL_WRITEMASK |
| 67 | GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL | 67 | GLenum action_stencil_fail; // GL_STENCIL_FAIL |
| 68 | GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS | 68 | GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL |
| 69 | GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS | ||
| 70 | } front, back; | ||
| 69 | } stencil; | 71 | } stencil; |
| 70 | 72 | ||
| 71 | struct { | 73 | struct { |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 0343759a6..67273e164 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -295,6 +295,30 @@ inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) { | |||
| 295 | return {}; | 295 | return {}; |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | inline GLenum StencilOp(Maxwell::StencilOp stencil) { | ||
| 299 | switch (stencil) { | ||
| 300 | case Maxwell::StencilOp::Keep: | ||
| 301 | return GL_KEEP; | ||
| 302 | case Maxwell::StencilOp::Zero: | ||
| 303 | return GL_ZERO; | ||
| 304 | case Maxwell::StencilOp::Replace: | ||
| 305 | return GL_REPLACE; | ||
| 306 | case Maxwell::StencilOp::Incr: | ||
| 307 | return GL_INCR; | ||
| 308 | case Maxwell::StencilOp::Decr: | ||
| 309 | return GL_DECR; | ||
| 310 | case Maxwell::StencilOp::Invert: | ||
| 311 | return GL_INVERT; | ||
| 312 | case Maxwell::StencilOp::IncrWrap: | ||
| 313 | return GL_INCR_WRAP; | ||
| 314 | case Maxwell::StencilOp::DecrWrap: | ||
| 315 | return GL_DECR_WRAP; | ||
| 316 | } | ||
| 317 | LOG_CRITICAL(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil)); | ||
| 318 | UNREACHABLE(); | ||
| 319 | return {}; | ||
| 320 | } | ||
| 321 | |||
| 298 | inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { | 322 | inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) { |
| 299 | switch (front_face) { | 323 | switch (front_face) { |
| 300 | case Maxwell::Cull::FrontFace::ClockWise: | 324 | case Maxwell::Cull::FrontFace::ClockWise: |