summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Rodolfo Bogado2018-11-02 00:21:25 -0300
committerGravatar Rodolfo Bogado2018-11-04 20:49:48 -0300
commit145ae369639af6f91a59b8217c5e9ba42b0c5f0b (patch)
treebd90ca5b095233fe18fc6f4470d2a44d4a0ad969
parentMerge pull request #1625 from FernandoS27/astc (diff)
downloadyuzu-145ae369639af6f91a59b8217c5e9ba42b0c5f0b.tar.gz
yuzu-145ae369639af6f91a59b8217c5e9ba42b0c5f0b.tar.xz
yuzu-145ae369639af6f91a59b8217c5e9ba42b0c5f0b.zip
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.h14
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp95
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h5
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp205
-rw-r--r--src/video_core/renderer_opengl/gl_state.h52
6 files changed, 259 insertions, 128 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..33eb57360 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -646,8 +646,14 @@ public:
646 ComparisonOp depth_test_func; 646 ComparisonOp depth_test_func;
647 float alpha_test_ref; 647 float alpha_test_ref;
648 ComparisonOp alpha_test_func; 648 ComparisonOp alpha_test_func;
649 649 u32 draw_tfb_stride;
650 INSERT_PADDING_WORDS(0x9); 650 struct {
651 float r;
652 float g;
653 float b;
654 float a;
655 } blend_color;
656 INSERT_PADDING_WORDS(0x4);
651 657
652 struct { 658 struct {
653 u32 separate_alpha; 659 u32 separate_alpha;
@@ -1087,6 +1093,10 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
1087ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB); 1093ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB);
1088ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); 1094ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
1089ASSERT_REG_POSITION(depth_test_func, 0x4C3); 1095ASSERT_REG_POSITION(depth_test_func, 0x4C3);
1096ASSERT_REG_POSITION(alpha_test_ref, 0x4C4);
1097ASSERT_REG_POSITION(alpha_test_func, 0x4C5);
1098ASSERT_REG_POSITION(draw_tfb_stride, 0x4C6);
1099ASSERT_REG_POSITION(blend_color, 0x4C7);
1090ASSERT_REG_POSITION(blend, 0x4CF); 1100ASSERT_REG_POSITION(blend, 0x4CF);
1091ASSERT_REG_POSITION(stencil_enable, 0x4E0); 1101ASSERT_REG_POSITION(stencil_enable, 0x4E0);
1092ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1); 1102ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index a0527fe57..73770ff69 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -580,7 +580,6 @@ void RasterizerOpenGL::DrawArrays() {
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
@@ -996,23 +992,44 @@ void RasterizerOpenGL::SyncStencilTestState() {
996void RasterizerOpenGL::SyncBlendState() { 992void RasterizerOpenGL::SyncBlendState() {
997 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 993 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
998 994
999 // TODO(Subv): Support more than just render target 0. 995 state.blend_color.red = regs.blend_color.r;
1000 state.blend.enabled = regs.blend.enable[0] != 0; 996 state.blend_color.green = regs.blend_color.g;
1001 997 state.blend_color.blue = regs.blend_color.b;
1002 if (!state.blend.enabled) 998 state.blend_color.alpha = regs.blend_color.a;
999
1000 state.independant_blend.enabled = regs.independent_blend_enable;
1001 if (!state.independant_blend.enabled) {
1002 auto& blend = state.blend[0];
1003 blend.separate_alpha = regs.blend.separate_alpha;
1004 blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
1005 blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
1006 blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
1007 if (blend.separate_alpha) {
1008 blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
1009 blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
1010 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
1011 }
1012 for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1013 state.blend[i].enabled = false;
1014 }
1003 return; 1015 return;
1016 }
1004 1017
1005 ASSERT_MSG(regs.logic_op.enable == 0, 1018 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."); 1019 auto& blend = state.blend[i];
1007 1020 blend.enabled = regs.blend.enable[i] != 0;
1008 ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); 1021 if (!blend.enabled)
1009 ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); 1022 continue;
1010 state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); 1023 blend.separate_alpha = regs.independent_blend[i].separate_alpha;
1011 state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb); 1024 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); 1025 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); 1026 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); 1027 if (blend.separate_alpha) {
1015 state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a); 1028 blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a);
1029 blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_a);
1030 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_a);
1031 }
1032 }
1016} 1033}
1017 1034
1018void RasterizerOpenGL::SyncLogicOpState() { 1035void RasterizerOpenGL::SyncLogicOpState() {
@@ -1031,19 +1048,19 @@ void RasterizerOpenGL::SyncLogicOpState() {
1031} 1048}
1032 1049
1033void RasterizerOpenGL::SyncScissorTest() { 1050void RasterizerOpenGL::SyncScissorTest() {
1051 // TODO: what is the correct behavior here, a single scissor for all targets
1052 // or scissor disabled for the rest of the targets?
1034 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1053 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1035
1036 state.scissor.enabled = (regs.scissor_test.enable != 0); 1054 state.scissor.enabled = (regs.scissor_test.enable != 0);
1037 // TODO(Blinkhawk): Figure if the hardware supports scissor testing per viewport and how it's 1055 if (regs.scissor_test.enable == 0) {
1038 // implemented. 1056 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 } 1057 }
1058 const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
1059 const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
1060 state.scissor.x = regs.scissor_test.min_x;
1061 state.scissor.y = regs.scissor_test.min_y;
1062 state.scissor.width = width;
1063 state.scissor.height = height;
1047} 1064}
1048 1065
1049void RasterizerOpenGL::SyncTransformFeedback() { 1066void RasterizerOpenGL::SyncTransformFeedback() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 47097c569..8ec22df8d 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
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index b6b426f34..2e1f81e26 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -22,8 +22,6 @@ 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;
@@ -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;
@@ -152,11 +153,6 @@ void OpenGLState::ApplyDepth() const {
152 if (depth.write_mask != cur_state.depth.write_mask) { 153 if (depth.write_mask != cur_state.depth.write_mask) {
153 glDepthMask(depth.write_mask); 154 glDepthMask(depth.write_mask);
154 } 155 }
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} 156}
161 157
162void OpenGLState::ApplyPrimitiveRestart() const { 158void OpenGLState::ApplyPrimitiveRestart() const {
@@ -208,7 +204,7 @@ void OpenGLState::ApplyStencilTest() const {
208 } 204 }
209} 205}
210 206
211void OpenGLState::ApplyScissorTest() const { 207void OpenGLState::ApplyScissor() const {
212 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled; 208 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
213 if (scissor_changed) { 209 if (scissor_changed) {
214 if (scissor.enabled) { 210 if (scissor.enabled) {
@@ -217,43 +213,134 @@ void OpenGLState::ApplyScissorTest() const {
217 glDisable(GL_SCISSOR_TEST); 213 glDisable(GL_SCISSOR_TEST);
218 } 214 }
219 } 215 }
220 if (scissor_changed || scissor_changed || scissor.x != cur_state.scissor.x || 216 if (scissor.enabled &&
221 scissor.y != cur_state.scissor.y || scissor.width != cur_state.scissor.width || 217 (scissor_changed || scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
222 scissor.height != cur_state.scissor.height) { 218 scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height)) {
223 glScissor(scissor.x, scissor.y, scissor.width, scissor.height); 219 glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
224 } 220 }
225} 221}
226 222
227void OpenGLState::ApplyBlending() const { 223void OpenGLState::ApplyViewport() const {
228 const bool blend_changed = blend.enabled != cur_state.blend.enabled; 224 if (GLAD_GL_ARB_viewport_array) {
225 for (GLuint i = 0;
226 i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) {
227 const auto& current = cur_state.viewports[i];
228 const auto& updated = viewports[i];
229 if (updated.x != current.x || updated.y != current.y ||
230 updated.width != current.width || updated.height != current.height) {
231 glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height);
232 }
233 if (updated.depth_range_near != current.depth_range_near ||
234 updated.depth_range_far != current.depth_range_far) {
235 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
236 }
237 }
238 } else {
239 const auto& current = cur_state.viewports[0];
240 const auto& updated = viewports[0];
241 if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
242 updated.height != current.height) {
243 glViewport(updated.x, updated.y, updated.width, updated.height);
244 }
245 if (updated.depth_range_near != current.depth_range_near ||
246 updated.depth_range_far != current.depth_range_far) {
247 glDepthRange(updated.depth_range_near, updated.depth_range_far);
248 }
249 }
250}
251
252void OpenGLState::ApplyGlobalBlending() const {
253 const Blend& current = cur_state.blend[0];
254 const Blend& updated = blend[0];
255 const bool blend_changed = updated.enabled != current.enabled;
229 if (blend_changed) { 256 if (blend_changed) {
230 if (blend.enabled) { 257 if (updated.enabled) {
231 ASSERT(!logic_op.enabled);
232 glEnable(GL_BLEND); 258 glEnable(GL_BLEND);
233 } else { 259 } else {
234 glDisable(GL_BLEND); 260 glDisable(GL_BLEND);
235 } 261 }
236 } 262 }
237 if (blend.enabled) { 263 if (!updated.enabled) {
238 if (blend_changed || blend.color.red != cur_state.blend.color.red || 264 return;
239 blend.color.green != cur_state.blend.color.green || 265 }
240 blend.color.blue != cur_state.blend.color.blue || 266 if (updated.separate_alpha) {
241 blend.color.alpha != cur_state.blend.color.alpha) { 267 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); 268 updated.dst_rgb_func != current.dst_rgb_func ||
269 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
270 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
271 updated.dst_a_func);
272 }
273
274 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
275 updated.a_equation != current.a_equation) {
276 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
277 }
278 } else {
279 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
280 updated.dst_rgb_func != current.dst_rgb_func) {
281 glBlendFunc(updated.src_rgb_func, updated.dst_rgb_func);
282 }
283
284 if (blend_changed || updated.rgb_equation != current.rgb_equation) {
285 glBlendEquation(updated.rgb_equation);
286 }
287 }
288}
289
290void OpenGLState::ApplyTargetBlending(int target, bool force) const {
291 const Blend& updated = blend[target];
292 const Blend& current = cur_state.blend[target];
293 const bool blend_changed = updated.enabled != current.enabled || force;
294 if (blend_changed) {
295 if (updated.enabled) {
296 glEnablei(GL_BLEND, static_cast<GLuint>(target));
297 } else {
298 glDisablei(GL_BLEND, static_cast<GLuint>(target));
299 }
300 }
301 if (!updated.enabled) {
302 return;
303 }
304 if (updated.separate_alpha) {
305 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
306 updated.dst_rgb_func != current.dst_rgb_func ||
307 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
308 glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func,
309 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
310 }
311
312 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
313 updated.a_equation != current.a_equation) {
314 glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
315 updated.a_equation);
316 }
317 } else {
318 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
319 updated.dst_rgb_func != current.dst_rgb_func) {
320 glBlendFunciARB(static_cast<GLuint>(target), updated.src_rgb_func,
321 updated.dst_rgb_func);
243 } 322 }
244 323
245 if (blend_changed || blend.src_rgb_func != cur_state.blend.src_rgb_func || 324 if (blend_changed || updated.rgb_equation != current.rgb_equation) {
246 blend.dst_rgb_func != cur_state.blend.dst_rgb_func || 325 glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation);
247 blend.src_a_func != cur_state.blend.src_a_func ||
248 blend.dst_a_func != cur_state.blend.dst_a_func) {
249 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
250 blend.dst_a_func);
251 } 326 }
327 }
328}
252 329
253 if (blend_changed || blend.rgb_equation != cur_state.blend.rgb_equation || 330void OpenGLState::ApplyBlending() const {
254 blend.a_equation != cur_state.blend.a_equation) { 331 if (independant_blend.enabled) {
255 glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); 332 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
333 ApplyTargetBlending(i,
334 independant_blend.enabled != cur_state.independant_blend.enabled);
256 } 335 }
336 } else {
337 ApplyGlobalBlending();
338 }
339 if (blend_color.red != cur_state.blend_color.red ||
340 blend_color.green != cur_state.blend_color.green ||
341 blend_color.blue != cur_state.blend_color.blue ||
342 blend_color.alpha != cur_state.blend_color.alpha) {
343 glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha);
257 } 344 }
258} 345}
259 346
@@ -261,7 +348,6 @@ void OpenGLState::ApplyLogicOp() const {
261 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled; 348 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
262 if (logic_op_changed) { 349 if (logic_op_changed) {
263 if (logic_op.enabled) { 350 if (logic_op.enabled) {
264 ASSERT(!blend.enabled);
265 glEnable(GL_COLOR_LOGIC_OP); 351 glEnable(GL_COLOR_LOGIC_OP);
266 } else { 352 } else {
267 glDisable(GL_COLOR_LOGIC_OP); 353 glDisable(GL_COLOR_LOGIC_OP);
@@ -348,12 +434,6 @@ void OpenGLState::Apply() const {
348 if (draw.program_pipeline != cur_state.draw.program_pipeline) { 434 if (draw.program_pipeline != cur_state.draw.program_pipeline) {
349 glBindProgramPipeline(draw.program_pipeline); 435 glBindProgramPipeline(draw.program_pipeline);
350 } 436 }
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 437 // Clip distance
358 for (std::size_t i = 0; i < clip_distance.size(); ++i) { 438 for (std::size_t i = 0; i < clip_distance.size(); ++i) {
359 if (clip_distance[i] != cur_state.clip_distance[i]) { 439 if (clip_distance[i] != cur_state.clip_distance[i]) {
@@ -376,7 +456,8 @@ void OpenGLState::Apply() const {
376 if (point.size != cur_state.point.size) { 456 if (point.size != cur_state.point.size) {
377 glPointSize(point.size); 457 glPointSize(point.size);
378 } 458 }
379 ApplyScissorTest(); 459 ApplyViewport();
460 ApplyScissor();
380 ApplyStencilTest(); 461 ApplyStencilTest();
381 ApplySRgb(); 462 ApplySRgb();
382 ApplyCulling(); 463 ApplyCulling();
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index fe648aff6..a027ca33c 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 {
@@ -78,22 +76,28 @@ public:
78 } front, back; 76 } front, back;
79 } stencil; 77 } stencil;
80 78
81 struct { 79 struct Blend {
82 bool enabled; // GL_BLEND 80 bool enabled; // GL_BLEND
81 bool separate_alpha; // Independent blend enabled
83 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB 82 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
84 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA 83 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
85 GLenum src_rgb_func; // GL_BLEND_SRC_RGB 84 GLenum src_rgb_func; // GL_BLEND_SRC_RGB
86 GLenum dst_rgb_func; // GL_BLEND_DST_RGB 85 GLenum dst_rgb_func; // GL_BLEND_DST_RGB
87 GLenum src_a_func; // GL_BLEND_SRC_ALPHA 86 GLenum src_a_func; // GL_BLEND_SRC_ALPHA
88 GLenum dst_a_func; // GL_BLEND_DST_ALPHA 87 GLenum dst_a_func; // GL_BLEND_DST_ALPHA
88 };
89 std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend;
89 90
90 struct { 91 struct {
91 GLclampf red; 92 bool enabled;
92 GLclampf green; 93 } independant_blend;
93 GLclampf blue; 94
94 GLclampf alpha; 95 struct {
95 } color; // GL_BLEND_COLOR 96 GLclampf red;
96 } blend; 97 GLclampf green;
98 GLclampf blue;
99 GLclampf alpha;
100 } blend_color; // GL_BLEND_COLOR
97 101
98 struct { 102 struct {
99 bool enabled; // GL_LOGIC_OP_MODE 103 bool enabled; // GL_LOGIC_OP_MODE
@@ -138,6 +142,16 @@ public:
138 GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING 142 GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
139 } draw; 143 } draw;
140 144
145 struct viewport {
146 GLfloat x;
147 GLfloat y;
148 GLfloat width;
149 GLfloat height;
150 GLfloat depth_range_near; // GL_DEPTH_RANGE
151 GLfloat depth_range_far; // GL_DEPTH_RANGE
152 };
153 std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports;
154
141 struct { 155 struct {
142 bool enabled; // GL_SCISSOR_TEST 156 bool enabled; // GL_SCISSOR_TEST
143 GLint x; 157 GLint x;
@@ -147,13 +161,6 @@ public:
147 } scissor; 161 } scissor;
148 162
149 struct { 163 struct {
150 GLint x;
151 GLint y;
152 GLsizei width;
153 GLsizei height;
154 } viewport;
155
156 struct {
157 float size; // GL_POINT_SIZE 164 float size; // GL_POINT_SIZE
158 } point; 165 } point;
159 166
@@ -194,11 +201,14 @@ private:
194 void ApplyDepth() const; 201 void ApplyDepth() const;
195 void ApplyPrimitiveRestart() const; 202 void ApplyPrimitiveRestart() const;
196 void ApplyStencilTest() const; 203 void ApplyStencilTest() const;
197 void ApplyScissorTest() const; 204 void ApplyViewport() const;
205 void ApplyTargetBlending(int target, bool force) const;
206 void ApplyGlobalBlending() const;
198 void ApplyBlending() const; 207 void ApplyBlending() const;
199 void ApplyLogicOp() const; 208 void ApplyLogicOp() const;
200 void ApplyTextures() const; 209 void ApplyTextures() const;
201 void ApplySamplers() const; 210 void ApplySamplers() const;
211 void ApplyScissor() const;
202}; 212};
203 213
204} // namespace OpenGL 214} // namespace OpenGL