summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2018-11-07 00:11:49 -0800
committerGravatar GitHub2018-11-07 00:11:49 -0800
commit74bce4d68f72c64d73dd05d9c30e0e3010f69759 (patch)
tree00caaaad110530578ef271ee5d24f8dbac8ad085
parentMerge pull request #1653 from degasus/profiler (diff)
parentAdd support to color mask to avoid issues in blending caused by wrong values ... (diff)
downloadyuzu-74bce4d68f72c64d73dd05d9c30e0e3010f69759.tar.gz
yuzu-74bce4d68f72c64d73dd05d9c30e0e3010f69759.tar.xz
yuzu-74bce4d68f72c64d73dd05d9c30e0e3010f69759.zip
Merge pull request #1635 from Tinob/master
Implement multi-target viewports and blending
-rw-r--r--src/video_core/engines/maxwell_3d.cpp16
-rw-r--r--src/video_core/engines/maxwell_3d.h37
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp118
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h8
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp252
-rw-r--r--src/video_core/renderer_opengl/gl_state.h60
6 files changed, 338 insertions, 153 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index d79c50919..2cd595f26 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -37,6 +37,22 @@ void Maxwell3D::InitializeRegisterDefaults() {
37 regs.viewport[viewport].depth_range_near = 0.0f; 37 regs.viewport[viewport].depth_range_near = 0.0f;
38 regs.viewport[viewport].depth_range_far = 1.0f; 38 regs.viewport[viewport].depth_range_far = 1.0f;
39 } 39 }
40 // Doom and Bomberman seems to use the uninitialized registers and just enable blend
41 // so initialize blend registers with sane values
42 regs.blend.equation_rgb = Regs::Blend::Equation::Add;
43 regs.blend.factor_source_rgb = Regs::Blend::Factor::One;
44 regs.blend.factor_dest_rgb = Regs::Blend::Factor::Zero;
45 regs.blend.equation_a = Regs::Blend::Equation::Add;
46 regs.blend.factor_source_a = Regs::Blend::Factor::One;
47 regs.blend.factor_dest_a = Regs::Blend::Factor::Zero;
48 for (std::size_t blend_index = 0; blend_index < Regs::NumRenderTargets; blend_index++) {
49 regs.independent_blend[blend_index].equation_rgb = Regs::Blend::Equation::Add;
50 regs.independent_blend[blend_index].factor_source_rgb = Regs::Blend::Factor::One;
51 regs.independent_blend[blend_index].factor_dest_rgb = Regs::Blend::Factor::Zero;
52 regs.independent_blend[blend_index].equation_a = Regs::Blend::Equation::Add;
53 regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One;
54 regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero;
55 }
40} 56}
41 57
42void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { 58void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 50873813e..0509ba3a2 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -462,6 +462,16 @@ public:
462 } 462 }
463 }; 463 };
464 464
465 struct ColorMask {
466 union {
467 u32 raw;
468 BitField<0, 4, u32> R;
469 BitField<4, 4, u32> G;
470 BitField<8, 4, u32> B;
471 BitField<12, 4, u32> A;
472 };
473 };
474
465 bool IsShaderConfigEnabled(std::size_t index) const { 475 bool IsShaderConfigEnabled(std::size_t index) const {
466 // The VertexB is always enabled. 476 // The VertexB is always enabled.
467 if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) { 477 if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
@@ -571,7 +581,11 @@ public:
571 u32 stencil_back_mask; 581 u32 stencil_back_mask;
572 u32 stencil_back_func_mask; 582 u32 stencil_back_func_mask;
573 583
574 INSERT_PADDING_WORDS(0x13); 584 INSERT_PADDING_WORDS(0xC);
585
586 u32 color_mask_common;
587
588 INSERT_PADDING_WORDS(0x6);
575 589
576 u32 rt_separate_frag_data; 590 u32 rt_separate_frag_data;
577 591
@@ -646,8 +660,14 @@ public:
646 ComparisonOp depth_test_func; 660 ComparisonOp depth_test_func;
647 float alpha_test_ref; 661 float alpha_test_ref;
648 ComparisonOp alpha_test_func; 662 ComparisonOp alpha_test_func;
649 663 u32 draw_tfb_stride;
650 INSERT_PADDING_WORDS(0x9); 664 struct {
665 float r;
666 float g;
667 float b;
668 float a;
669 } blend_color;
670 INSERT_PADDING_WORDS(0x4);
651 671
652 struct { 672 struct {
653 u32 separate_alpha; 673 u32 separate_alpha;
@@ -841,8 +861,9 @@ public:
841 BitField<6, 4, u32> RT; 861 BitField<6, 4, u32> RT;
842 BitField<10, 11, u32> layer; 862 BitField<10, 11, u32> layer;
843 } clear_buffers; 863 } clear_buffers;
844 864 INSERT_PADDING_WORDS(0xB);
845 INSERT_PADDING_WORDS(0x4B); 865 std::array<ColorMask, NumRenderTargets> color_mask;
866 INSERT_PADDING_WORDS(0x38);
846 867
847 struct { 868 struct {
848 u32 query_address_high; 869 u32 query_address_high;
@@ -1075,6 +1096,7 @@ ASSERT_REG_POSITION(scissor_test, 0x380);
1075ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); 1096ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
1076ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); 1097ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
1077ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); 1098ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
1099ASSERT_REG_POSITION(color_mask_common, 0x3E4);
1078ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); 1100ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
1079ASSERT_REG_POSITION(zeta, 0x3F8); 1101ASSERT_REG_POSITION(zeta, 0x3F8);
1080ASSERT_REG_POSITION(vertex_attrib_format, 0x458); 1102ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
@@ -1087,6 +1109,10 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
1087ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB); 1109ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB);
1088ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); 1110ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
1089ASSERT_REG_POSITION(depth_test_func, 0x4C3); 1111ASSERT_REG_POSITION(depth_test_func, 0x4C3);
1112ASSERT_REG_POSITION(alpha_test_ref, 0x4C4);
1113ASSERT_REG_POSITION(alpha_test_func, 0x4C5);
1114ASSERT_REG_POSITION(draw_tfb_stride, 0x4C6);
1115ASSERT_REG_POSITION(blend_color, 0x4C7);
1090ASSERT_REG_POSITION(blend, 0x4CF); 1116ASSERT_REG_POSITION(blend, 0x4CF);
1091ASSERT_REG_POSITION(stencil_enable, 0x4E0); 1117ASSERT_REG_POSITION(stencil_enable, 0x4E0);
1092ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1); 1118ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1);
@@ -1117,6 +1143,7 @@ ASSERT_REG_POSITION(instanced_arrays, 0x620);
1117ASSERT_REG_POSITION(cull, 0x646); 1143ASSERT_REG_POSITION(cull, 0x646);
1118ASSERT_REG_POSITION(logic_op, 0x671); 1144ASSERT_REG_POSITION(logic_op, 0x671);
1119ASSERT_REG_POSITION(clear_buffers, 0x674); 1145ASSERT_REG_POSITION(clear_buffers, 0x674);
1146ASSERT_REG_POSITION(color_mask, 0x680);
1120ASSERT_REG_POSITION(query, 0x6C0); 1147ASSERT_REG_POSITION(query, 0x6C0);
1121ASSERT_REG_POSITION(vertex_array[0], 0x700); 1148ASSERT_REG_POSITION(vertex_array[0], 0x700);
1122ASSERT_REG_POSITION(independent_blend, 0x780); 1149ASSERT_REG_POSITION(independent_blend, 0x780);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index a0527fe57..bb263b6aa 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -511,10 +511,10 @@ void RasterizerOpenGL::Clear() {
511 511
512 OpenGLState clear_state; 512 OpenGLState clear_state;
513 clear_state.draw.draw_framebuffer = framebuffer.handle; 513 clear_state.draw.draw_framebuffer = framebuffer.handle;
514 clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; 514 clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
515 clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; 515 clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
516 clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; 516 clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
517 clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; 517 clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
518 518
519 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || 519 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
520 regs.clear_buffers.A) { 520 regs.clear_buffers.A) {
@@ -573,14 +573,13 @@ void RasterizerOpenGL::DrawArrays() {
573 ScopeAcquireGLContext acquire_context{emu_window}; 573 ScopeAcquireGLContext acquire_context{emu_window};
574 574
575 ConfigureFramebuffers(); 575 ConfigureFramebuffers();
576 576 SyncColorMask();
577 SyncDepthTestState(); 577 SyncDepthTestState();
578 SyncStencilTestState(); 578 SyncStencilTestState();
579 SyncBlendState(); 579 SyncBlendState();
580 SyncLogicOpState(); 580 SyncLogicOpState();
581 SyncCullMode(); 581 SyncCullMode();
582 SyncPrimitiveRestart(); 582 SyncPrimitiveRestart();
583 SyncDepthRange();
584 SyncScissorTest(); 583 SyncScissorTest();
585 // Alpha Testing is synced on shaders. 584 // Alpha Testing is synced on shaders.
586 SyncTransformFeedback(); 585 SyncTransformFeedback();
@@ -899,12 +898,16 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
899 898
900void RasterizerOpenGL::SyncViewport() { 899void RasterizerOpenGL::SyncViewport() {
901 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 900 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
902 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; 901 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
903 902 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
904 state.viewport.x = viewport_rect.left; 903 auto& viewport = state.viewports[i];
905 state.viewport.y = viewport_rect.bottom; 904 viewport.x = viewport_rect.left;
906 state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); 905 viewport.y = viewport_rect.bottom;
907 state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); 906 viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth());
907 viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight());
908 viewport.depth_range_far = regs.viewport[i].depth_range_far;
909 viewport.depth_range_near = regs.viewport[i].depth_range_near;
910 }
908} 911}
909 912
910void RasterizerOpenGL::SyncClipEnabled() { 913void RasterizerOpenGL::SyncClipEnabled() {
@@ -946,13 +949,6 @@ void RasterizerOpenGL::SyncPrimitiveRestart() {
946 state.primitive_restart.index = regs.primitive_restart.index; 949 state.primitive_restart.index = regs.primitive_restart.index;
947} 950}
948 951
949void RasterizerOpenGL::SyncDepthRange() {
950 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
951
952 state.depth.depth_range_near = regs.viewport->depth_range_near;
953 state.depth.depth_range_far = regs.viewport->depth_range_far;
954}
955
956void RasterizerOpenGL::SyncDepthTestState() { 952void RasterizerOpenGL::SyncDepthTestState() {
957 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 953 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
958 954
@@ -993,26 +989,60 @@ void RasterizerOpenGL::SyncStencilTestState() {
993 state.stencil.back.write_mask = regs.stencil_back_mask; 989 state.stencil.back.write_mask = regs.stencil_back_mask;
994} 990}
995 991
996void RasterizerOpenGL::SyncBlendState() { 992void RasterizerOpenGL::SyncColorMask() {
997 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 993 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
994 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
995 const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i];
996 auto& dest = state.color_mask[i];
997 dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE;
998 dest.green_enabled = (source.G == 0) ? GL_FALSE : GL_TRUE;
999 dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE;
1000 dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE;
1001 }
1002}
998 1003
999 // TODO(Subv): Support more than just render target 0. 1004void RasterizerOpenGL::SyncBlendState() {
1000 state.blend.enabled = regs.blend.enable[0] != 0; 1005 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1001 1006
1002 if (!state.blend.enabled) 1007 state.blend_color.red = regs.blend_color.r;
1008 state.blend_color.green = regs.blend_color.g;
1009 state.blend_color.blue = regs.blend_color.b;
1010 state.blend_color.alpha = regs.blend_color.a;
1011
1012 state.independant_blend.enabled = regs.independent_blend_enable;
1013 if (!state.independant_blend.enabled) {
1014 auto& blend = state.blend[0];
1015 blend.enabled = regs.blend.enable[0] != 0;
1016 blend.separate_alpha = regs.blend.separate_alpha;
1017 blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
1018 blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
1019 blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
1020 if (blend.separate_alpha) {
1021 blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
1022 blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
1023 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
1024 }
1025 for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1026 state.blend[i].enabled = false;
1027 }
1003 return; 1028 return;
1029 }
1004 1030
1005 ASSERT_MSG(regs.logic_op.enable == 0, 1031 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1006 "Blending and logic op can't be enabled at the same time."); 1032 auto& blend = state.blend[i];
1007 1033 blend.enabled = regs.blend.enable[i] != 0;
1008 ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); 1034 if (!blend.enabled)
1009 ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); 1035 continue;
1010 state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); 1036 blend.separate_alpha = regs.independent_blend[i].separate_alpha;
1011 state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb); 1037 blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb);
1012 state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_rgb); 1038 blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb);
1013 state.blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_a); 1039 blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb);
1014 state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a); 1040 if (blend.separate_alpha) {
1015 state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a); 1041 blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a);
1042 blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_a);
1043 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_a);
1044 }
1045 }
1016} 1046}
1017 1047
1018void RasterizerOpenGL::SyncLogicOpState() { 1048void RasterizerOpenGL::SyncLogicOpState() {
@@ -1031,19 +1061,19 @@ void RasterizerOpenGL::SyncLogicOpState() {
1031} 1061}
1032 1062
1033void RasterizerOpenGL::SyncScissorTest() { 1063void RasterizerOpenGL::SyncScissorTest() {
1064 // TODO: what is the correct behavior here, a single scissor for all targets
1065 // or scissor disabled for the rest of the targets?
1034 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1066 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1035
1036 state.scissor.enabled = (regs.scissor_test.enable != 0); 1067 state.scissor.enabled = (regs.scissor_test.enable != 0);
1037 // TODO(Blinkhawk): Figure if the hardware supports scissor testing per viewport and how it's 1068 if (regs.scissor_test.enable == 0) {
1038 // implemented. 1069 return;
1039 if (regs.scissor_test.enable != 0) {
1040 const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
1041 const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
1042 state.scissor.x = regs.scissor_test.min_x;
1043 state.scissor.y = regs.scissor_test.min_y;
1044 state.scissor.width = width;
1045 state.scissor.height = height;
1046 } 1070 }
1071 const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
1072 const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
1073 state.scissor.x = regs.scissor_test.min_x;
1074 state.scissor.y = regs.scissor_test.min_y;
1075 state.scissor.width = width;
1076 state.scissor.height = height;
1047} 1077}
1048 1078
1049void RasterizerOpenGL::SyncTransformFeedback() { 1079void RasterizerOpenGL::SyncTransformFeedback() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 47097c569..60e783803 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -133,7 +133,7 @@ private:
133 u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, 133 u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
134 GLenum primitive_mode, u32 current_unit); 134 GLenum primitive_mode, u32 current_unit);
135 135
136 /// Syncs the viewport to match the guest state 136 /// Syncs the viewport and depth range to match the guest state
137 void SyncViewport(); 137 void SyncViewport();
138 138
139 /// Syncs the clip enabled status to match the guest state 139 /// Syncs the clip enabled status to match the guest state
@@ -148,9 +148,6 @@ private:
148 /// Syncs the primitve restart to match the guest state 148 /// Syncs the primitve restart to match the guest state
149 void SyncPrimitiveRestart(); 149 void SyncPrimitiveRestart();
150 150
151 /// Syncs the depth range to match the guest state
152 void SyncDepthRange();
153
154 /// Syncs the depth test state to match the guest state 151 /// Syncs the depth test state to match the guest state
155 void SyncDepthTestState(); 152 void SyncDepthTestState();
156 153
@@ -172,6 +169,9 @@ private:
172 /// Syncs the point state to match the guest state 169 /// Syncs the point state to match the guest state
173 void SyncPointState(); 170 void SyncPointState();
174 171
172 /// Syncs Color Mask
173 void SyncColorMask();
174
175 /// Check asserts for alpha testing. 175 /// Check asserts for alpha testing.
176 void CheckAlphaTests(); 176 void CheckAlphaTests();
177 177
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index b6b426f34..9517285e5 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -22,17 +22,15 @@ OpenGLState::OpenGLState() {
22 depth.test_enabled = false; 22 depth.test_enabled = false;
23 depth.test_func = GL_LESS; 23 depth.test_func = GL_LESS;
24 depth.write_mask = GL_TRUE; 24 depth.write_mask = GL_TRUE;
25 depth.depth_range_near = 0.0f;
26 depth.depth_range_far = 1.0f;
27 25
28 primitive_restart.enabled = false; 26 primitive_restart.enabled = false;
29 primitive_restart.index = 0; 27 primitive_restart.index = 0;
30 28 for (auto& item : color_mask) {
31 color_mask.red_enabled = GL_TRUE; 29 item.red_enabled = GL_TRUE;
32 color_mask.green_enabled = GL_TRUE; 30 item.green_enabled = GL_TRUE;
33 color_mask.blue_enabled = GL_TRUE; 31 item.blue_enabled = GL_TRUE;
34 color_mask.alpha_enabled = GL_TRUE; 32 item.alpha_enabled = GL_TRUE;
35 33 }
36 stencil.test_enabled = false; 34 stencil.test_enabled = false;
37 auto reset_stencil = [](auto& config) { 35 auto reset_stencil = [](auto& config) {
38 config.test_func = GL_ALWAYS; 36 config.test_func = GL_ALWAYS;
@@ -45,19 +43,33 @@ OpenGLState::OpenGLState() {
45 }; 43 };
46 reset_stencil(stencil.front); 44 reset_stencil(stencil.front);
47 reset_stencil(stencil.back); 45 reset_stencil(stencil.back);
48 46 for (auto& item : viewports) {
49 blend.enabled = true; 47 item.x = 0;
50 blend.rgb_equation = GL_FUNC_ADD; 48 item.y = 0;
51 blend.a_equation = GL_FUNC_ADD; 49 item.width = 0;
52 blend.src_rgb_func = GL_ONE; 50 item.height = 0;
53 blend.dst_rgb_func = GL_ZERO; 51 item.depth_range_near = 0.0f;
54 blend.src_a_func = GL_ONE; 52 item.depth_range_far = 1.0f;
55 blend.dst_a_func = GL_ZERO; 53 }
56 blend.color.red = 0.0f; 54 scissor.enabled = false;
57 blend.color.green = 0.0f; 55 scissor.x = 0;
58 blend.color.blue = 0.0f; 56 scissor.y = 0;
59 blend.color.alpha = 0.0f; 57 scissor.width = 0;
60 58 scissor.height = 0;
59 for (auto& item : blend) {
60 item.enabled = true;
61 item.rgb_equation = GL_FUNC_ADD;
62 item.a_equation = GL_FUNC_ADD;
63 item.src_rgb_func = GL_ONE;
64 item.dst_rgb_func = GL_ZERO;
65 item.src_a_func = GL_ONE;
66 item.dst_a_func = GL_ZERO;
67 }
68 independant_blend.enabled = false;
69 blend_color.red = 0.0f;
70 blend_color.green = 0.0f;
71 blend_color.blue = 0.0f;
72 blend_color.alpha = 0.0f;
61 logic_op.enabled = false; 73 logic_op.enabled = false;
62 logic_op.operation = GL_COPY; 74 logic_op.operation = GL_COPY;
63 75
@@ -73,17 +85,6 @@ OpenGLState::OpenGLState() {
73 draw.shader_program = 0; 85 draw.shader_program = 0;
74 draw.program_pipeline = 0; 86 draw.program_pipeline = 0;
75 87
76 scissor.enabled = false;
77 scissor.x = 0;
78 scissor.y = 0;
79 scissor.width = 0;
80 scissor.height = 0;
81
82 viewport.x = 0;
83 viewport.y = 0;
84 viewport.width = 0;
85 viewport.height = 0;
86
87 clip_distance = {}; 88 clip_distance = {};
88 89
89 point.size = 1; 90 point.size = 1;
@@ -134,6 +135,32 @@ void OpenGLState::ApplyCulling() const {
134 } 135 }
135} 136}
136 137
138void OpenGLState::ApplyColorMask() const {
139 if (GLAD_GL_ARB_viewport_array) {
140 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
141 const auto& updated = color_mask[i];
142 const auto& current = cur_state.color_mask[i];
143 if (updated.red_enabled != current.red_enabled ||
144 updated.green_enabled != current.green_enabled ||
145 updated.blue_enabled != current.blue_enabled ||
146 updated.alpha_enabled != current.alpha_enabled) {
147 glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled,
148 updated.blue_enabled, updated.alpha_enabled);
149 }
150 }
151 } else {
152 const auto& updated = color_mask[0];
153 const auto& current = cur_state.color_mask[0];
154 if (updated.red_enabled != current.red_enabled ||
155 updated.green_enabled != current.green_enabled ||
156 updated.blue_enabled != current.blue_enabled ||
157 updated.alpha_enabled != current.alpha_enabled) {
158 glColorMask(updated.red_enabled, updated.green_enabled, updated.blue_enabled,
159 updated.alpha_enabled);
160 }
161 }
162}
163
137void OpenGLState::ApplyDepth() const { 164void OpenGLState::ApplyDepth() const {
138 // Depth test 165 // Depth test
139 const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled; 166 const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
@@ -152,11 +179,6 @@ void OpenGLState::ApplyDepth() const {
152 if (depth.write_mask != cur_state.depth.write_mask) { 179 if (depth.write_mask != cur_state.depth.write_mask) {
153 glDepthMask(depth.write_mask); 180 glDepthMask(depth.write_mask);
154 } 181 }
155 // Depth range
156 if (depth.depth_range_near != cur_state.depth.depth_range_near ||
157 depth.depth_range_far != cur_state.depth.depth_range_far) {
158 glDepthRange(depth.depth_range_near, depth.depth_range_far);
159 }
160} 182}
161 183
162void OpenGLState::ApplyPrimitiveRestart() const { 184void OpenGLState::ApplyPrimitiveRestart() const {
@@ -208,7 +230,7 @@ void OpenGLState::ApplyStencilTest() const {
208 } 230 }
209} 231}
210 232
211void OpenGLState::ApplyScissorTest() const { 233void OpenGLState::ApplyScissor() const {
212 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled; 234 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
213 if (scissor_changed) { 235 if (scissor_changed) {
214 if (scissor.enabled) { 236 if (scissor.enabled) {
@@ -217,51 +239,141 @@ void OpenGLState::ApplyScissorTest() const {
217 glDisable(GL_SCISSOR_TEST); 239 glDisable(GL_SCISSOR_TEST);
218 } 240 }
219 } 241 }
220 if (scissor_changed || scissor_changed || scissor.x != cur_state.scissor.x || 242 if (scissor.enabled &&
221 scissor.y != cur_state.scissor.y || scissor.width != cur_state.scissor.width || 243 (scissor_changed || scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
222 scissor.height != cur_state.scissor.height) { 244 scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height)) {
223 glScissor(scissor.x, scissor.y, scissor.width, scissor.height); 245 glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
224 } 246 }
225} 247}
226 248
227void OpenGLState::ApplyBlending() const { 249void OpenGLState::ApplyViewport() const {
228 const bool blend_changed = blend.enabled != cur_state.blend.enabled; 250 if (GLAD_GL_ARB_viewport_array) {
251 for (GLuint i = 0;
252 i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) {
253 const auto& current = cur_state.viewports[i];
254 const auto& updated = viewports[i];
255 if (updated.x != current.x || updated.y != current.y ||
256 updated.width != current.width || updated.height != current.height) {
257 glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height);
258 }
259 if (updated.depth_range_near != current.depth_range_near ||
260 updated.depth_range_far != current.depth_range_far) {
261 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
262 }
263 }
264 } else {
265 const auto& current = cur_state.viewports[0];
266 const auto& updated = viewports[0];
267 if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
268 updated.height != current.height) {
269 glViewport(updated.x, updated.y, updated.width, updated.height);
270 }
271 if (updated.depth_range_near != current.depth_range_near ||
272 updated.depth_range_far != current.depth_range_far) {
273 glDepthRange(updated.depth_range_near, updated.depth_range_far);
274 }
275 }
276}
277
278void OpenGLState::ApplyGlobalBlending() const {
279 const Blend& current = cur_state.blend[0];
280 const Blend& updated = blend[0];
281 const bool blend_changed = updated.enabled != current.enabled;
229 if (blend_changed) { 282 if (blend_changed) {
230 if (blend.enabled) { 283 if (updated.enabled) {
231 ASSERT(!logic_op.enabled);
232 glEnable(GL_BLEND); 284 glEnable(GL_BLEND);
233 } else { 285 } else {
234 glDisable(GL_BLEND); 286 glDisable(GL_BLEND);
235 } 287 }
236 } 288 }
237 if (blend.enabled) { 289 if (!updated.enabled) {
238 if (blend_changed || blend.color.red != cur_state.blend.color.red || 290 return;
239 blend.color.green != cur_state.blend.color.green || 291 }
240 blend.color.blue != cur_state.blend.color.blue || 292 if (updated.separate_alpha) {
241 blend.color.alpha != cur_state.blend.color.alpha) { 293 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
242 glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); 294 updated.dst_rgb_func != current.dst_rgb_func ||
295 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
296 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
297 updated.dst_a_func);
243 } 298 }
244 299
245 if (blend_changed || blend.src_rgb_func != cur_state.blend.src_rgb_func || 300 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
246 blend.dst_rgb_func != cur_state.blend.dst_rgb_func || 301 updated.a_equation != current.a_equation) {
247 blend.src_a_func != cur_state.blend.src_a_func || 302 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
248 blend.dst_a_func != cur_state.blend.dst_a_func) { 303 }
249 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, 304 } else {
250 blend.dst_a_func); 305 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
306 updated.dst_rgb_func != current.dst_rgb_func) {
307 glBlendFunc(updated.src_rgb_func, updated.dst_rgb_func);
251 } 308 }
252 309
253 if (blend_changed || blend.rgb_equation != cur_state.blend.rgb_equation || 310 if (blend_changed || updated.rgb_equation != current.rgb_equation) {
254 blend.a_equation != cur_state.blend.a_equation) { 311 glBlendEquation(updated.rgb_equation);
255 glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
256 } 312 }
257 } 313 }
258} 314}
259 315
316void OpenGLState::ApplyTargetBlending(int target, bool force) const {
317 const Blend& updated = blend[target];
318 const Blend& current = cur_state.blend[target];
319 const bool blend_changed = updated.enabled != current.enabled || force;
320 if (blend_changed) {
321 if (updated.enabled) {
322 glEnablei(GL_BLEND, static_cast<GLuint>(target));
323 } else {
324 glDisablei(GL_BLEND, static_cast<GLuint>(target));
325 }
326 }
327 if (!updated.enabled) {
328 return;
329 }
330 if (updated.separate_alpha) {
331 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
332 updated.dst_rgb_func != current.dst_rgb_func ||
333 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
334 glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func,
335 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
336 }
337
338 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
339 updated.a_equation != current.a_equation) {
340 glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
341 updated.a_equation);
342 }
343 } else {
344 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
345 updated.dst_rgb_func != current.dst_rgb_func) {
346 glBlendFunciARB(static_cast<GLuint>(target), updated.src_rgb_func,
347 updated.dst_rgb_func);
348 }
349
350 if (blend_changed || updated.rgb_equation != current.rgb_equation) {
351 glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation);
352 }
353 }
354}
355
356void OpenGLState::ApplyBlending() const {
357 if (independant_blend.enabled) {
358 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
359 ApplyTargetBlending(i,
360 independant_blend.enabled != cur_state.independant_blend.enabled);
361 }
362 } else {
363 ApplyGlobalBlending();
364 }
365 if (blend_color.red != cur_state.blend_color.red ||
366 blend_color.green != cur_state.blend_color.green ||
367 blend_color.blue != cur_state.blend_color.blue ||
368 blend_color.alpha != cur_state.blend_color.alpha) {
369 glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha);
370 }
371}
372
260void OpenGLState::ApplyLogicOp() const { 373void OpenGLState::ApplyLogicOp() const {
261 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled; 374 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
262 if (logic_op_changed) { 375 if (logic_op_changed) {
263 if (logic_op.enabled) { 376 if (logic_op.enabled) {
264 ASSERT(!blend.enabled);
265 glEnable(GL_COLOR_LOGIC_OP); 377 glEnable(GL_COLOR_LOGIC_OP);
266 } else { 378 } else {
267 glDisable(GL_COLOR_LOGIC_OP); 379 glDisable(GL_COLOR_LOGIC_OP);
@@ -348,12 +460,6 @@ void OpenGLState::Apply() const {
348 if (draw.program_pipeline != cur_state.draw.program_pipeline) { 460 if (draw.program_pipeline != cur_state.draw.program_pipeline) {
349 glBindProgramPipeline(draw.program_pipeline); 461 glBindProgramPipeline(draw.program_pipeline);
350 } 462 }
351 // Viewport
352 if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
353 viewport.width != cur_state.viewport.width ||
354 viewport.height != cur_state.viewport.height) {
355 glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
356 }
357 // Clip distance 463 // Clip distance
358 for (std::size_t i = 0; i < clip_distance.size(); ++i) { 464 for (std::size_t i = 0; i < clip_distance.size(); ++i) {
359 if (clip_distance[i] != cur_state.clip_distance[i]) { 465 if (clip_distance[i] != cur_state.clip_distance[i]) {
@@ -364,19 +470,13 @@ void OpenGLState::Apply() const {
364 } 470 }
365 } 471 }
366 } 472 }
367 // Color mask
368 if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
369 color_mask.green_enabled != cur_state.color_mask.green_enabled ||
370 color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
371 color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
372 glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
373 color_mask.alpha_enabled);
374 }
375 // Point 473 // Point
376 if (point.size != cur_state.point.size) { 474 if (point.size != cur_state.point.size) {
377 glPointSize(point.size); 475 glPointSize(point.size);
378 } 476 }
379 ApplyScissorTest(); 477 ApplyColorMask();
478 ApplyViewport();
479 ApplyScissor();
380 ApplyStencilTest(); 480 ApplyStencilTest();
381 ApplySRgb(); 481 ApplySRgb();
382 ApplyCulling(); 482 ApplyCulling();
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index fe648aff6..b8cf1f637 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -46,11 +46,9 @@ public:
46 } cull; 46 } cull;
47 47
48 struct { 48 struct {
49 bool test_enabled; // GL_DEPTH_TEST 49 bool test_enabled; // GL_DEPTH_TEST
50 GLenum test_func; // GL_DEPTH_FUNC 50 GLenum test_func; // GL_DEPTH_FUNC
51 GLboolean write_mask; // GL_DEPTH_WRITEMASK 51 GLboolean write_mask; // GL_DEPTH_WRITEMASK
52 GLfloat depth_range_near; // GL_DEPTH_RANGE
53 GLfloat depth_range_far; // GL_DEPTH_RANGE
54 } depth; 52 } depth;
55 53
56 struct { 54 struct {
@@ -58,13 +56,14 @@ public:
58 GLuint index; 56 GLuint index;
59 } primitive_restart; // GL_PRIMITIVE_RESTART 57 } primitive_restart; // GL_PRIMITIVE_RESTART
60 58
61 struct { 59 struct ColorMask {
62 GLboolean red_enabled; 60 GLboolean red_enabled;
63 GLboolean green_enabled; 61 GLboolean green_enabled;
64 GLboolean blue_enabled; 62 GLboolean blue_enabled;
65 GLboolean alpha_enabled; 63 GLboolean alpha_enabled;
66 } color_mask; // GL_COLOR_WRITEMASK 64 };
67 65 std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets>
66 color_mask; // GL_COLOR_WRITEMASK
68 struct { 67 struct {
69 bool test_enabled; // GL_STENCIL_TEST 68 bool test_enabled; // GL_STENCIL_TEST
70 struct { 69 struct {
@@ -78,22 +77,28 @@ public:
78 } front, back; 77 } front, back;
79 } stencil; 78 } stencil;
80 79
81 struct { 80 struct Blend {
82 bool enabled; // GL_BLEND 81 bool enabled; // GL_BLEND
82 bool separate_alpha; // Independent blend enabled
83 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB 83 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
84 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA 84 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
85 GLenum src_rgb_func; // GL_BLEND_SRC_RGB 85 GLenum src_rgb_func; // GL_BLEND_SRC_RGB
86 GLenum dst_rgb_func; // GL_BLEND_DST_RGB 86 GLenum dst_rgb_func; // GL_BLEND_DST_RGB
87 GLenum src_a_func; // GL_BLEND_SRC_ALPHA 87 GLenum src_a_func; // GL_BLEND_SRC_ALPHA
88 GLenum dst_a_func; // GL_BLEND_DST_ALPHA 88 GLenum dst_a_func; // GL_BLEND_DST_ALPHA
89 };
90 std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend;
89 91
90 struct { 92 struct {
91 GLclampf red; 93 bool enabled;
92 GLclampf green; 94 } independant_blend;
93 GLclampf blue; 95
94 GLclampf alpha; 96 struct {
95 } color; // GL_BLEND_COLOR 97 GLclampf red;
96 } blend; 98 GLclampf green;
99 GLclampf blue;
100 GLclampf alpha;
101 } blend_color; // GL_BLEND_COLOR
97 102
98 struct { 103 struct {
99 bool enabled; // GL_LOGIC_OP_MODE 104 bool enabled; // GL_LOGIC_OP_MODE
@@ -138,6 +143,16 @@ public:
138 GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING 143 GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
139 } draw; 144 } draw;
140 145
146 struct viewport {
147 GLfloat x;
148 GLfloat y;
149 GLfloat width;
150 GLfloat height;
151 GLfloat depth_range_near; // GL_DEPTH_RANGE
152 GLfloat depth_range_far; // GL_DEPTH_RANGE
153 };
154 std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports;
155
141 struct { 156 struct {
142 bool enabled; // GL_SCISSOR_TEST 157 bool enabled; // GL_SCISSOR_TEST
143 GLint x; 158 GLint x;
@@ -147,13 +162,6 @@ public:
147 } scissor; 162 } scissor;
148 163
149 struct { 164 struct {
150 GLint x;
151 GLint y;
152 GLsizei width;
153 GLsizei height;
154 } viewport;
155
156 struct {
157 float size; // GL_POINT_SIZE 165 float size; // GL_POINT_SIZE
158 } point; 166 } point;
159 167
@@ -191,14 +199,18 @@ private:
191 static bool s_rgb_used; 199 static bool s_rgb_used;
192 void ApplySRgb() const; 200 void ApplySRgb() const;
193 void ApplyCulling() const; 201 void ApplyCulling() const;
202 void ApplyColorMask() const;
194 void ApplyDepth() const; 203 void ApplyDepth() const;
195 void ApplyPrimitiveRestart() const; 204 void ApplyPrimitiveRestart() const;
196 void ApplyStencilTest() const; 205 void ApplyStencilTest() const;
197 void ApplyScissorTest() const; 206 void ApplyViewport() const;
207 void ApplyTargetBlending(int target, bool force) const;
208 void ApplyGlobalBlending() const;
198 void ApplyBlending() const; 209 void ApplyBlending() const;
199 void ApplyLogicOp() const; 210 void ApplyLogicOp() const;
200 void ApplyTextures() const; 211 void ApplyTextures() const;
201 void ApplySamplers() const; 212 void ApplySamplers() const;
213 void ApplyScissor() const;
202}; 214};
203 215
204} // namespace OpenGL 216} // namespace OpenGL