summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-02-27 02:21:33 -0300
committerGravatar ReinUsesLisp2019-04-03 20:26:27 -0300
commit78bd66d03739a589e696ea58a1e696a2ee2e13c0 (patch)
tree77a14465c7a406ac4a1641a47054ac816f6195df
parentMerge pull request #2294 from lioncash/fatal (diff)
downloadyuzu-78bd66d03739a589e696ea58a1e696a2ee2e13c0.tar.gz
yuzu-78bd66d03739a589e696ea58a1e696a2ee2e13c0.tar.xz
yuzu-78bd66d03739a589e696ea58a1e696a2ee2e13c0.zip
gl_state: Rework to enable individual applies
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h1
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp610
-rw-r--r--src/video_core/renderer_opengl/gl_state.h52
3 files changed, 324 insertions, 339 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 4970aafed..316b47910 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -63,7 +63,6 @@ public:
63 UpdatePipeline(); 63 UpdatePipeline();
64 state.draw.shader_program = 0; 64 state.draw.shader_program = 0;
65 state.draw.program_pipeline = pipeline.handle; 65 state.draw.program_pipeline = pipeline.handle;
66 state.geometry_shaders.enabled = (gs != 0);
67 } 66 }
68 67
69private: 68private:
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 9419326a3..52d569a1b 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -10,16 +10,62 @@
10 10
11namespace OpenGL { 11namespace OpenGL {
12 12
13OpenGLState OpenGLState::cur_state; 13using Maxwell = Tegra::Engines::Maxwell3D::Regs;
14 14
15OpenGLState OpenGLState::cur_state;
15bool OpenGLState::s_rgb_used; 16bool OpenGLState::s_rgb_used;
16 17
18namespace {
19
20template <typename T>
21bool UpdateValue(T& current_value, const T new_value) {
22 const bool changed = current_value != new_value;
23 current_value = new_value;
24 return changed;
25}
26
27template <typename T1, typename T2>
28bool UpdateTie(T1 current_value, const T2 new_value) {
29 const bool changed = current_value != new_value;
30 current_value = new_value;
31 return changed;
32}
33
34void Enable(GLenum cap, bool enable) {
35 if (enable) {
36 glEnable(cap);
37 } else {
38 glDisable(cap);
39 }
40}
41
42void Enable(GLenum cap, GLuint index, bool enable) {
43 if (enable) {
44 glEnablei(cap, index);
45 } else {
46 glDisablei(cap, index);
47 }
48}
49
50void Enable(GLenum cap, bool& current_value, bool new_value) {
51 if (UpdateValue(current_value, new_value))
52 Enable(cap, new_value);
53}
54
55void Enable(GLenum cap, GLuint index, bool& current_value, bool new_value) {
56 if (UpdateValue(current_value, new_value))
57 Enable(cap, index, new_value);
58}
59
60} // namespace
61
17OpenGLState::OpenGLState() { 62OpenGLState::OpenGLState() {
18 // These all match default OpenGL values 63 // These all match default OpenGL values
19 geometry_shaders.enabled = false;
20 framebuffer_srgb.enabled = false; 64 framebuffer_srgb.enabled = false;
65
21 multisample_control.alpha_to_coverage = false; 66 multisample_control.alpha_to_coverage = false;
22 multisample_control.alpha_to_one = false; 67 multisample_control.alpha_to_one = false;
68
23 cull.enabled = false; 69 cull.enabled = false;
24 cull.mode = GL_BACK; 70 cull.mode = GL_BACK;
25 cull.front_face = GL_CCW; 71 cull.front_face = GL_CCW;
@@ -30,14 +76,15 @@ OpenGLState::OpenGLState() {
30 76
31 primitive_restart.enabled = false; 77 primitive_restart.enabled = false;
32 primitive_restart.index = 0; 78 primitive_restart.index = 0;
79
33 for (auto& item : color_mask) { 80 for (auto& item : color_mask) {
34 item.red_enabled = GL_TRUE; 81 item.red_enabled = GL_TRUE;
35 item.green_enabled = GL_TRUE; 82 item.green_enabled = GL_TRUE;
36 item.blue_enabled = GL_TRUE; 83 item.blue_enabled = GL_TRUE;
37 item.alpha_enabled = GL_TRUE; 84 item.alpha_enabled = GL_TRUE;
38 } 85 }
39 stencil.test_enabled = false; 86
40 auto reset_stencil = [](auto& config) { 87 const auto ResetStencil = [](auto& config) {
41 config.test_func = GL_ALWAYS; 88 config.test_func = GL_ALWAYS;
42 config.test_ref = 0; 89 config.test_ref = 0;
43 config.test_mask = 0xFFFFFFFF; 90 config.test_mask = 0xFFFFFFFF;
@@ -46,8 +93,10 @@ OpenGLState::OpenGLState() {
46 config.action_depth_pass = GL_KEEP; 93 config.action_depth_pass = GL_KEEP;
47 config.action_stencil_fail = GL_KEEP; 94 config.action_stencil_fail = GL_KEEP;
48 }; 95 };
49 reset_stencil(stencil.front); 96 stencil.test_enabled = false;
50 reset_stencil(stencil.back); 97 ResetStencil(stencil.front);
98 ResetStencil(stencil.back);
99
51 for (auto& item : viewports) { 100 for (auto& item : viewports) {
52 item.x = 0; 101 item.x = 0;
53 item.y = 0; 102 item.y = 0;
@@ -61,6 +110,7 @@ OpenGLState::OpenGLState() {
61 item.scissor.width = 0; 110 item.scissor.width = 0;
62 item.scissor.height = 0; 111 item.scissor.height = 0;
63 } 112 }
113
64 for (auto& item : blend) { 114 for (auto& item : blend) {
65 item.enabled = true; 115 item.enabled = true;
66 item.rgb_equation = GL_FUNC_ADD; 116 item.rgb_equation = GL_FUNC_ADD;
@@ -70,11 +120,14 @@ OpenGLState::OpenGLState() {
70 item.src_a_func = GL_ONE; 120 item.src_a_func = GL_ONE;
71 item.dst_a_func = GL_ZERO; 121 item.dst_a_func = GL_ZERO;
72 } 122 }
123
73 independant_blend.enabled = false; 124 independant_blend.enabled = false;
125
74 blend_color.red = 0.0f; 126 blend_color.red = 0.0f;
75 blend_color.green = 0.0f; 127 blend_color.green = 0.0f;
76 blend_color.blue = 0.0f; 128 blend_color.blue = 0.0f;
77 blend_color.alpha = 0.0f; 129 blend_color.alpha = 0.0f;
130
78 logic_op.enabled = false; 131 logic_op.enabled = false;
79 logic_op.operation = GL_COPY; 132 logic_op.operation = GL_COPY;
80 133
@@ -91,9 +144,12 @@ OpenGLState::OpenGLState() {
91 clip_distance = {}; 144 clip_distance = {};
92 145
93 point.size = 1; 146 point.size = 1;
147
94 fragment_color_clamp.enabled = false; 148 fragment_color_clamp.enabled = false;
149
95 depth_clamp.far_plane = false; 150 depth_clamp.far_plane = false;
96 depth_clamp.near_plane = false; 151 depth_clamp.near_plane = false;
152
97 polygon_offset.fill_enable = false; 153 polygon_offset.fill_enable = false;
98 polygon_offset.line_enable = false; 154 polygon_offset.line_enable = false;
99 polygon_offset.point_enable = false; 155 polygon_offset.point_enable = false;
@@ -103,260 +159,255 @@ OpenGLState::OpenGLState() {
103} 159}
104 160
105void OpenGLState::ApplyDefaultState() { 161void OpenGLState::ApplyDefaultState() {
162 glEnable(GL_BLEND);
106 glDisable(GL_FRAMEBUFFER_SRGB); 163 glDisable(GL_FRAMEBUFFER_SRGB);
107 glDisable(GL_CULL_FACE); 164 glDisable(GL_CULL_FACE);
108 glDisable(GL_DEPTH_TEST); 165 glDisable(GL_DEPTH_TEST);
109 glDisable(GL_PRIMITIVE_RESTART); 166 glDisable(GL_PRIMITIVE_RESTART);
110 glDisable(GL_STENCIL_TEST); 167 glDisable(GL_STENCIL_TEST);
111 glEnable(GL_BLEND);
112 glDisable(GL_COLOR_LOGIC_OP); 168 glDisable(GL_COLOR_LOGIC_OP);
113 glDisable(GL_SCISSOR_TEST); 169 glDisable(GL_SCISSOR_TEST);
114} 170}
115 171
172void OpenGLState::ApplyFramebufferState() const {
173 if (UpdateValue(cur_state.draw.read_framebuffer, draw.read_framebuffer)) {
174 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
175 }
176 if (UpdateValue(cur_state.draw.draw_framebuffer, draw.draw_framebuffer)) {
177 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer);
178 }
179}
180
181void OpenGLState::ApplyVertexArrayState() const {
182 if (UpdateValue(cur_state.draw.vertex_array, draw.vertex_array)) {
183 glBindVertexArray(draw.vertex_array);
184 }
185}
186
187void OpenGLState::ApplyShaderProgram() const {
188 if (UpdateValue(cur_state.draw.shader_program, draw.shader_program)) {
189 glUseProgram(draw.shader_program);
190 }
191}
192
193void OpenGLState::ApplyProgramPipeline() const {
194 if (UpdateValue(cur_state.draw.program_pipeline, draw.program_pipeline)) {
195 glBindProgramPipeline(draw.program_pipeline);
196 }
197}
198
199void OpenGLState::ApplyClipDistances() const {
200 for (std::size_t i = 0; i < clip_distance.size(); ++i) {
201 Enable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i), cur_state.clip_distance[i],
202 clip_distance[i]);
203 }
204}
205
206void OpenGLState::ApplyPointSize() const {
207 if (UpdateValue(cur_state.point.size, point.size)) {
208 glPointSize(point.size);
209 }
210}
211
212void OpenGLState::ApplyFragmentColorClamp() const {
213 if (UpdateValue(cur_state.fragment_color_clamp.enabled, fragment_color_clamp.enabled)) {
214 glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
215 fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE);
216 }
217}
218
219void OpenGLState::ApplyMultisample() const {
220 Enable(GL_SAMPLE_ALPHA_TO_COVERAGE, cur_state.multisample_control.alpha_to_coverage,
221 multisample_control.alpha_to_coverage);
222 Enable(GL_SAMPLE_ALPHA_TO_ONE, cur_state.multisample_control.alpha_to_one,
223 multisample_control.alpha_to_one);
224}
225
226void OpenGLState::ApplyDepthClamp() const {
227 if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane &&
228 depth_clamp.near_plane == cur_state.depth_clamp.near_plane) {
229 return;
230 }
231 cur_state.depth_clamp = depth_clamp;
232
233 UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane,
234 "Unimplemented Depth Clamp Separation!");
235
236 Enable(GL_DEPTH_CLAMP, depth_clamp.far_plane || depth_clamp.near_plane);
237}
238
116void OpenGLState::ApplySRgb() const { 239void OpenGLState::ApplySRgb() const {
117 if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) { 240 if (cur_state.framebuffer_srgb.enabled == framebuffer_srgb.enabled)
118 if (framebuffer_srgb.enabled) { 241 return;
119 // Track if sRGB is used 242 cur_state.framebuffer_srgb.enabled = framebuffer_srgb.enabled;
120 s_rgb_used = true; 243 if (framebuffer_srgb.enabled) {
121 glEnable(GL_FRAMEBUFFER_SRGB); 244 // Track if sRGB is used
122 } else { 245 s_rgb_used = true;
123 glDisable(GL_FRAMEBUFFER_SRGB); 246 glEnable(GL_FRAMEBUFFER_SRGB);
124 } 247 } else {
248 glDisable(GL_FRAMEBUFFER_SRGB);
125 } 249 }
126} 250}
127 251
128void OpenGLState::ApplyCulling() const { 252void OpenGLState::ApplyCulling() const {
129 if (cull.enabled != cur_state.cull.enabled) { 253 Enable(GL_CULL_FACE, cur_state.cull.enabled, cull.enabled);
130 if (cull.enabled) {
131 glEnable(GL_CULL_FACE);
132 } else {
133 glDisable(GL_CULL_FACE);
134 }
135 }
136 254
137 if (cull.mode != cur_state.cull.mode) { 255 if (UpdateValue(cur_state.cull.mode, cull.mode)) {
138 glCullFace(cull.mode); 256 glCullFace(cull.mode);
139 } 257 }
140 258
141 if (cull.front_face != cur_state.cull.front_face) { 259 if (UpdateValue(cur_state.cull.front_face, cull.front_face)) {
142 glFrontFace(cull.front_face); 260 glFrontFace(cull.front_face);
143 } 261 }
144} 262}
145 263
146void OpenGLState::ApplyColorMask() const { 264void OpenGLState::ApplyColorMask() const {
147 if (independant_blend.enabled) { 265 for (std::size_t i = 0; i < Maxwell::NumRenderTargets; ++i) {
148 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 266 const auto& updated = color_mask[i];
149 const auto& updated = color_mask[i]; 267 auto& current = cur_state.color_mask[i];
150 const auto& current = cur_state.color_mask[i];
151 if (updated.red_enabled != current.red_enabled ||
152 updated.green_enabled != current.green_enabled ||
153 updated.blue_enabled != current.blue_enabled ||
154 updated.alpha_enabled != current.alpha_enabled) {
155 glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled,
156 updated.blue_enabled, updated.alpha_enabled);
157 }
158 }
159 } else {
160 const auto& updated = color_mask[0];
161 const auto& current = cur_state.color_mask[0];
162 if (updated.red_enabled != current.red_enabled || 268 if (updated.red_enabled != current.red_enabled ||
163 updated.green_enabled != current.green_enabled || 269 updated.green_enabled != current.green_enabled ||
164 updated.blue_enabled != current.blue_enabled || 270 updated.blue_enabled != current.blue_enabled ||
165 updated.alpha_enabled != current.alpha_enabled) { 271 updated.alpha_enabled != current.alpha_enabled) {
166 glColorMask(updated.red_enabled, updated.green_enabled, updated.blue_enabled, 272 current = updated;
167 updated.alpha_enabled); 273 glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled,
274 updated.blue_enabled, updated.alpha_enabled);
168 } 275 }
169 } 276 }
170} 277}
171 278
172void OpenGLState::ApplyDepth() const { 279void OpenGLState::ApplyDepth() const {
173 if (depth.test_enabled != cur_state.depth.test_enabled) { 280 Enable(GL_DEPTH_TEST, cur_state.depth.test_enabled, depth.test_enabled);
174 if (depth.test_enabled) {
175 glEnable(GL_DEPTH_TEST);
176 } else {
177 glDisable(GL_DEPTH_TEST);
178 }
179 }
180 281
181 if (depth.test_func != cur_state.depth.test_func) { 282 if (cur_state.depth.test_func != depth.test_func) {
283 cur_state.depth.test_func = depth.test_func;
182 glDepthFunc(depth.test_func); 284 glDepthFunc(depth.test_func);
183 } 285 }
184 286
185 if (depth.write_mask != cur_state.depth.write_mask) { 287 if (cur_state.depth.write_mask != depth.write_mask) {
288 cur_state.depth.write_mask = depth.write_mask;
186 glDepthMask(depth.write_mask); 289 glDepthMask(depth.write_mask);
187 } 290 }
188} 291}
189 292
190void OpenGLState::ApplyPrimitiveRestart() const { 293void OpenGLState::ApplyPrimitiveRestart() const {
191 if (primitive_restart.enabled != cur_state.primitive_restart.enabled) { 294 Enable(GL_PRIMITIVE_RESTART, cur_state.primitive_restart.enabled, primitive_restart.enabled);
192 if (primitive_restart.enabled) {
193 glEnable(GL_PRIMITIVE_RESTART);
194 } else {
195 glDisable(GL_PRIMITIVE_RESTART);
196 }
197 }
198 295
199 if (primitive_restart.index != cur_state.primitive_restart.index) { 296 if (cur_state.primitive_restart.index != primitive_restart.index) {
297 cur_state.primitive_restart.index = primitive_restart.index;
200 glPrimitiveRestartIndex(primitive_restart.index); 298 glPrimitiveRestartIndex(primitive_restart.index);
201 } 299 }
202} 300}
203 301
204void OpenGLState::ApplyStencilTest() const { 302void OpenGLState::ApplyStencilTest() const {
205 if (stencil.test_enabled != cur_state.stencil.test_enabled) { 303 Enable(GL_STENCIL_TEST, cur_state.stencil.test_enabled, stencil.test_enabled);
206 if (stencil.test_enabled) { 304
207 glEnable(GL_STENCIL_TEST); 305 const auto ConfigStencil = [](GLenum face, const auto& config, auto& current) {
208 } else { 306 if (current.test_func != config.test_func || current.test_ref != config.test_ref ||
209 glDisable(GL_STENCIL_TEST); 307 current.test_mask != config.test_mask) {
210 } 308 current.test_func = config.test_func;
211 } 309 current.test_ref = config.test_ref;
212 310 current.test_mask = config.test_mask;
213 const auto ConfigStencil = [](GLenum face, const auto& config, const auto& prev_config) {
214 if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref ||
215 config.test_mask != prev_config.test_mask) {
216 glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); 311 glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
217 } 312 }
218 if (config.action_depth_fail != prev_config.action_depth_fail || 313 if (current.action_depth_fail != config.action_depth_fail ||
219 config.action_depth_pass != prev_config.action_depth_pass || 314 current.action_depth_pass != config.action_depth_pass ||
220 config.action_stencil_fail != prev_config.action_stencil_fail) { 315 current.action_stencil_fail != config.action_stencil_fail) {
316 current.action_depth_fail = config.action_depth_fail;
317 current.action_depth_pass = config.action_depth_pass;
318 current.action_stencil_fail = config.action_stencil_fail;
221 glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, 319 glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
222 config.action_depth_pass); 320 config.action_depth_pass);
223 } 321 }
224 if (config.write_mask != prev_config.write_mask) { 322 if (current.write_mask != config.write_mask) {
323 current.write_mask = config.write_mask;
225 glStencilMaskSeparate(face, config.write_mask); 324 glStencilMaskSeparate(face, config.write_mask);
226 } 325 }
227 }; 326 };
228 ConfigStencil(GL_FRONT, stencil.front, cur_state.stencil.front); 327 ConfigStencil(GL_FRONT, stencil.front, cur_state.stencil.front);
229 ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back); 328 ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back);
230} 329}
231// Viewport does not affects glClearBuffer so emulate viewport using scissor test
232void OpenGLState::EmulateViewportWithScissor() {
233 auto& current = viewports[0];
234 if (current.scissor.enabled) {
235 const GLint left = std::max(current.x, current.scissor.x);
236 const GLint right =
237 std::max(current.x + current.width, current.scissor.x + current.scissor.width);
238 const GLint bottom = std::max(current.y, current.scissor.y);
239 const GLint top =
240 std::max(current.y + current.height, current.scissor.y + current.scissor.height);
241 current.scissor.x = std::max(left, 0);
242 current.scissor.y = std::max(bottom, 0);
243 current.scissor.width = std::max(right - left, 0);
244 current.scissor.height = std::max(top - bottom, 0);
245 } else {
246 current.scissor.enabled = true;
247 current.scissor.x = current.x;
248 current.scissor.y = current.y;
249 current.scissor.width = current.width;
250 current.scissor.height = current.height;
251 }
252}
253 330
254void OpenGLState::ApplyViewport() const { 331void OpenGLState::ApplyViewport() const {
255 if (geometry_shaders.enabled) { 332 for (GLuint i = 0; i < static_cast<GLuint>(Maxwell::NumViewports); ++i) {
256 for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports); 333 const auto& updated = viewports[i];
257 i++) { 334 auto& current = cur_state.viewports[i];
258 const auto& current = cur_state.viewports[i]; 335
259 const auto& updated = viewports[i]; 336 if (current.x != updated.x || current.y != updated.y || current.width != updated.width ||
260 if (updated.x != current.x || updated.y != current.y || 337 current.height != updated.height) {
261 updated.width != current.width || updated.height != current.height) { 338 current.x = updated.x;
262 glViewportIndexedf( 339 current.y = updated.y;
263 i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y), 340 current.width = updated.width;
264 static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height)); 341 current.height = updated.height;
265 } 342 glViewportIndexedf(i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y),
266 if (updated.depth_range_near != current.depth_range_near || 343 static_cast<GLfloat>(updated.width),
267 updated.depth_range_far != current.depth_range_far) { 344 static_cast<GLfloat>(updated.height));
268 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
269 }
270
271 if (updated.scissor.enabled != current.scissor.enabled) {
272 if (updated.scissor.enabled) {
273 glEnablei(GL_SCISSOR_TEST, i);
274 } else {
275 glDisablei(GL_SCISSOR_TEST, i);
276 }
277 }
278
279 if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y ||
280 updated.scissor.width != current.scissor.width ||
281 updated.scissor.height != current.scissor.height) {
282 glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width,
283 updated.scissor.height);
284 }
285 }
286 } else {
287 const auto& current = cur_state.viewports[0];
288 const auto& updated = viewports[0];
289 if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
290 updated.height != current.height) {
291 glViewport(updated.x, updated.y, updated.width, updated.height);
292 }
293
294 if (updated.depth_range_near != current.depth_range_near ||
295 updated.depth_range_far != current.depth_range_far) {
296 glDepthRange(updated.depth_range_near, updated.depth_range_far);
297 } 345 }
298 346 if (current.depth_range_near != updated.depth_range_near ||
299 if (updated.scissor.enabled != current.scissor.enabled) { 347 current.depth_range_far != updated.depth_range_far) {
300 if (updated.scissor.enabled) { 348 current.depth_range_near = updated.depth_range_near;
301 glEnable(GL_SCISSOR_TEST); 349 current.depth_range_far = updated.depth_range_far;
302 } else { 350 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
303 glDisable(GL_SCISSOR_TEST);
304 }
305 } 351 }
306 352
307 if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y || 353 Enable(GL_SCISSOR_TEST, i, current.scissor.enabled, updated.scissor.enabled);
308 updated.scissor.width != current.scissor.width || 354
309 updated.scissor.height != current.scissor.height) { 355 if (current.scissor.x != updated.scissor.x || current.scissor.y != updated.scissor.y ||
310 glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width, 356 current.scissor.width != updated.scissor.width ||
311 updated.scissor.height); 357 current.scissor.height != updated.scissor.height) {
358 current.scissor.x = updated.scissor.x;
359 current.scissor.y = updated.scissor.y;
360 current.scissor.width = updated.scissor.width;
361 current.scissor.height = updated.scissor.height;
362 glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width,
363 updated.scissor.height);
312 } 364 }
313 } 365 }
314} 366}
315 367
316void OpenGLState::ApplyGlobalBlending() const { 368void OpenGLState::ApplyGlobalBlending() const {
317 const Blend& current = cur_state.blend[0];
318 const Blend& updated = blend[0]; 369 const Blend& updated = blend[0];
319 if (updated.enabled != current.enabled) { 370 Blend& current = cur_state.blend[0];
320 if (updated.enabled) { 371
321 glEnable(GL_BLEND); 372 Enable(GL_BLEND, current.enabled, updated.enabled);
322 } else { 373
323 glDisable(GL_BLEND); 374 if (current.src_rgb_func != updated.src_rgb_func ||
324 } 375 current.dst_rgb_func != updated.dst_rgb_func || current.src_a_func != updated.src_a_func ||
325 } 376 current.dst_a_func != updated.dst_a_func) {
326 if (!updated.enabled) { 377 current.src_rgb_func = updated.src_rgb_func;
327 return; 378 current.dst_rgb_func = updated.dst_rgb_func;
328 } 379 current.src_a_func = updated.src_a_func;
329 if (updated.src_rgb_func != current.src_rgb_func || 380 current.dst_a_func = updated.dst_a_func;
330 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func ||
331 updated.dst_a_func != current.dst_a_func) {
332 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, 381 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
333 updated.dst_a_func); 382 updated.dst_a_func);
334 } 383 }
335 384
336 if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) { 385 if (current.rgb_equation != updated.rgb_equation || current.a_equation != updated.a_equation) {
386 current.rgb_equation = updated.rgb_equation;
387 current.a_equation = updated.a_equation;
337 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); 388 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
338 } 389 }
339} 390}
340 391
341void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { 392void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
342 const Blend& updated = blend[target]; 393 const Blend& updated = blend[target];
343 const Blend& current = cur_state.blend[target]; 394 Blend& current = cur_state.blend[target];
344 if (updated.enabled != current.enabled || force) { 395
345 if (updated.enabled) { 396 if (current.enabled != updated.enabled || force) {
346 glEnablei(GL_BLEND, static_cast<GLuint>(target)); 397 current.enabled = updated.enabled;
347 } else { 398 Enable(GL_BLEND, static_cast<GLuint>(target), updated.enabled);
348 glDisablei(GL_BLEND, static_cast<GLuint>(target));
349 }
350 } 399 }
351 400
352 if (updated.src_rgb_func != current.src_rgb_func || 401 if (UpdateTie(std::tie(current.src_rgb_func, current.dst_rgb_func, current.src_a_func,
353 updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || 402 current.dst_a_func),
354 updated.dst_a_func != current.dst_a_func) { 403 std::tie(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
404 updated.dst_a_func))) {
355 glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func, 405 glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func,
356 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); 406 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
357 } 407 }
358 408
359 if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) { 409 if (UpdateTie(std::tie(current.rgb_equation, current.a_equation),
410 std::tie(updated.rgb_equation, updated.a_equation))) {
360 glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation, 411 glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation,
361 updated.a_equation); 412 updated.a_equation);
362 } 413 }
@@ -364,77 +415,48 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const {
364 415
365void OpenGLState::ApplyBlending() const { 416void OpenGLState::ApplyBlending() const {
366 if (independant_blend.enabled) { 417 if (independant_blend.enabled) {
367 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 418 const bool force = independant_blend.enabled != cur_state.independant_blend.enabled;
368 ApplyTargetBlending(i, 419 for (std::size_t target = 0; target < Maxwell::NumRenderTargets; ++target) {
369 independant_blend.enabled != cur_state.independant_blend.enabled); 420 ApplyTargetBlending(target, force);
370 } 421 }
371 } else { 422 } else {
372 ApplyGlobalBlending(); 423 ApplyGlobalBlending();
373 } 424 }
374 if (blend_color.red != cur_state.blend_color.red || 425 cur_state.independant_blend.enabled = independant_blend.enabled;
375 blend_color.green != cur_state.blend_color.green || 426
376 blend_color.blue != cur_state.blend_color.blue || 427 if (UpdateTie(
377 blend_color.alpha != cur_state.blend_color.alpha) { 428 std::tie(cur_state.blend_color.red, cur_state.blend_color.green,
429 cur_state.blend_color.blue, cur_state.blend_color.alpha),
430 std::tie(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha))) {
378 glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha); 431 glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha);
379 } 432 }
380} 433}
381 434
382void OpenGLState::ApplyLogicOp() const { 435void OpenGLState::ApplyLogicOp() const {
383 if (logic_op.enabled != cur_state.logic_op.enabled) { 436 Enable(GL_COLOR_LOGIC_OP, cur_state.logic_op.enabled, logic_op.enabled);
384 if (logic_op.enabled) {
385 glEnable(GL_COLOR_LOGIC_OP);
386 } else {
387 glDisable(GL_COLOR_LOGIC_OP);
388 }
389 }
390 437
391 if (logic_op.operation != cur_state.logic_op.operation) { 438 if (UpdateValue(cur_state.logic_op.operation, logic_op.operation)) {
392 glLogicOp(logic_op.operation); 439 glLogicOp(logic_op.operation);
393 } 440 }
394} 441}
395 442
396void OpenGLState::ApplyPolygonOffset() const { 443void OpenGLState::ApplyPolygonOffset() const {
397 const bool fill_enable_changed = 444 Enable(GL_POLYGON_OFFSET_FILL, cur_state.polygon_offset.fill_enable,
398 polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable; 445 polygon_offset.fill_enable);
399 const bool line_enable_changed = 446 Enable(GL_POLYGON_OFFSET_LINE, cur_state.polygon_offset.line_enable,
400 polygon_offset.line_enable != cur_state.polygon_offset.line_enable; 447 polygon_offset.line_enable);
401 const bool point_enable_changed = 448 Enable(GL_POLYGON_OFFSET_POINT, cur_state.polygon_offset.point_enable,
402 polygon_offset.point_enable != cur_state.polygon_offset.point_enable; 449 polygon_offset.point_enable);
403 const bool factor_changed = polygon_offset.factor != cur_state.polygon_offset.factor; 450
404 const bool units_changed = polygon_offset.units != cur_state.polygon_offset.units; 451 if (UpdateTie(std::tie(cur_state.polygon_offset.factor, cur_state.polygon_offset.units,
405 const bool clamp_changed = polygon_offset.clamp != cur_state.polygon_offset.clamp; 452 cur_state.polygon_offset.clamp),
406 453 std::tie(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp))) {
407 if (fill_enable_changed) {
408 if (polygon_offset.fill_enable) {
409 glEnable(GL_POLYGON_OFFSET_FILL);
410 } else {
411 glDisable(GL_POLYGON_OFFSET_FILL);
412 }
413 }
414
415 if (line_enable_changed) {
416 if (polygon_offset.line_enable) {
417 glEnable(GL_POLYGON_OFFSET_LINE);
418 } else {
419 glDisable(GL_POLYGON_OFFSET_LINE);
420 }
421 }
422
423 if (point_enable_changed) {
424 if (polygon_offset.point_enable) {
425 glEnable(GL_POLYGON_OFFSET_POINT);
426 } else {
427 glDisable(GL_POLYGON_OFFSET_POINT);
428 }
429 }
430
431 if (factor_changed || units_changed || clamp_changed) {
432 if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { 454 if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) {
433 glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); 455 glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp);
434 } else { 456 } else {
435 glPolygonOffset(polygon_offset.factor, polygon_offset.units);
436 UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0, 457 UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0,
437 "Unimplemented Depth polygon offset clamp."); 458 "Unimplemented Depth polygon offset clamp.");
459 glPolygonOffset(polygon_offset.factor, polygon_offset.units);
438 } 460 }
439 } 461 }
440} 462}
@@ -443,22 +465,21 @@ void OpenGLState::ApplyTextures() const {
443 bool has_delta{}; 465 bool has_delta{};
444 std::size_t first{}; 466 std::size_t first{};
445 std::size_t last{}; 467 std::size_t last{};
446 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures; 468 std::array<GLuint, Maxwell::NumTextureSamplers> textures;
447 469
448 for (std::size_t i = 0; i < std::size(texture_units); ++i) { 470 for (std::size_t i = 0; i < std::size(texture_units); ++i) {
449 const auto& texture_unit = texture_units[i]; 471 const auto& texture_unit = texture_units[i];
450 const auto& cur_state_texture_unit = cur_state.texture_units[i]; 472 auto& cur_state_texture_unit = cur_state.texture_units[i];
451 textures[i] = texture_unit.texture; 473 textures[i] = texture_unit.texture;
452 474 if (cur_state_texture_unit.texture == textures[i])
453 if (textures[i] != cur_state_texture_unit.texture) { 475 continue;
454 if (!has_delta) { 476 cur_state_texture_unit.texture = textures[i];
455 first = i; 477 if (!has_delta) {
456 has_delta = true; 478 first = i;
457 } 479 has_delta = true;
458 last = i;
459 } 480 }
481 last = i;
460 } 482 }
461
462 if (has_delta) { 483 if (has_delta) {
463 glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), 484 glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
464 textures.data() + first); 485 textures.data() + first);
@@ -469,16 +490,18 @@ void OpenGLState::ApplySamplers() const {
469 bool has_delta{}; 490 bool has_delta{};
470 std::size_t first{}; 491 std::size_t first{};
471 std::size_t last{}; 492 std::size_t last{};
472 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers; 493 std::array<GLuint, Maxwell::NumTextureSamplers> samplers;
494
473 for (std::size_t i = 0; i < std::size(samplers); ++i) { 495 for (std::size_t i = 0; i < std::size(samplers); ++i) {
496 if (cur_state.texture_units[i].sampler == texture_units[i].sampler)
497 continue;
498 cur_state.texture_units[i].sampler = texture_units[i].sampler;
474 samplers[i] = texture_units[i].sampler; 499 samplers[i] = texture_units[i].sampler;
475 if (samplers[i] != cur_state.texture_units[i].sampler) { 500 if (!has_delta) {
476 if (!has_delta) { 501 first = i;
477 first = i; 502 has_delta = true;
478 has_delta = true;
479 }
480 last = i;
481 } 503 }
504 last = i;
482 } 505 }
483 if (has_delta) { 506 if (has_delta) {
484 glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), 507 glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
@@ -486,81 +509,15 @@ void OpenGLState::ApplySamplers() const {
486 } 509 }
487} 510}
488 511
489void OpenGLState::ApplyFramebufferState() const {
490 if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
491 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
492 }
493 if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) {
494 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer);
495 }
496}
497
498void OpenGLState::ApplyVertexArrayState() const {
499 if (draw.vertex_array != cur_state.draw.vertex_array) {
500 glBindVertexArray(draw.vertex_array);
501 }
502}
503
504void OpenGLState::ApplyDepthClamp() const {
505 if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane &&
506 depth_clamp.near_plane == cur_state.depth_clamp.near_plane) {
507 return;
508 }
509 UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane,
510 "Unimplemented Depth Clamp Separation!");
511
512 if (depth_clamp.far_plane || depth_clamp.near_plane) {
513 glEnable(GL_DEPTH_CLAMP);
514 } else {
515 glDisable(GL_DEPTH_CLAMP);
516 }
517}
518
519void OpenGLState::Apply() const { 512void OpenGLState::Apply() const {
520 ApplyFramebufferState(); 513 ApplyFramebufferState();
521 ApplyVertexArrayState(); 514 ApplyVertexArrayState();
522 515 ApplyShaderProgram();
523 // Shader program 516 ApplyProgramPipeline();
524 if (draw.shader_program != cur_state.draw.shader_program) { 517 ApplyClipDistances();
525 glUseProgram(draw.shader_program); 518 ApplyPointSize();
526 } 519 ApplyFragmentColorClamp();
527 520 ApplyMultisample();
528 // Program pipeline
529 if (draw.program_pipeline != cur_state.draw.program_pipeline) {
530 glBindProgramPipeline(draw.program_pipeline);
531 }
532 // Clip distance
533 for (std::size_t i = 0; i < clip_distance.size(); ++i) {
534 if (clip_distance[i] != cur_state.clip_distance[i]) {
535 if (clip_distance[i]) {
536 glEnable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i));
537 } else {
538 glDisable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i));
539 }
540 }
541 }
542 // Point
543 if (point.size != cur_state.point.size) {
544 glPointSize(point.size);
545 }
546 if (fragment_color_clamp.enabled != cur_state.fragment_color_clamp.enabled) {
547 glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB,
548 fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE);
549 }
550 if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) {
551 if (multisample_control.alpha_to_coverage) {
552 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
553 } else {
554 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
555 }
556 }
557 if (multisample_control.alpha_to_one != cur_state.multisample_control.alpha_to_one) {
558 if (multisample_control.alpha_to_one) {
559 glEnable(GL_SAMPLE_ALPHA_TO_ONE);
560 } else {
561 glDisable(GL_SAMPLE_ALPHA_TO_ONE);
562 }
563 }
564 ApplyDepthClamp(); 521 ApplyDepthClamp();
565 ApplyColorMask(); 522 ApplyColorMask();
566 ApplyViewport(); 523 ApplyViewport();
@@ -574,7 +531,28 @@ void OpenGLState::Apply() const {
574 ApplyTextures(); 531 ApplyTextures();
575 ApplySamplers(); 532 ApplySamplers();
576 ApplyPolygonOffset(); 533 ApplyPolygonOffset();
577 cur_state = *this; 534}
535
536void OpenGLState::EmulateViewportWithScissor() {
537 auto& current = viewports[0];
538 if (current.scissor.enabled) {
539 const GLint left = std::max(current.x, current.scissor.x);
540 const GLint right =
541 std::max(current.x + current.width, current.scissor.x + current.scissor.width);
542 const GLint bottom = std::max(current.y, current.scissor.y);
543 const GLint top =
544 std::max(current.y + current.height, current.scissor.y + current.scissor.height);
545 current.scissor.x = std::max(left, 0);
546 current.scissor.y = std::max(bottom, 0);
547 current.scissor.width = std::max(right - left, 0);
548 current.scissor.height = std::max(top - bottom, 0);
549 } else {
550 current.scissor.enabled = true;
551 current.scissor.x = current.x;
552 current.scissor.y = current.y;
553 current.scissor.width = current.width;
554 current.scissor.height = current.height;
555 }
578} 556}
579 557
580OpenGLState& OpenGLState::UnbindTexture(GLuint handle) { 558OpenGLState& OpenGLState::UnbindTexture(GLuint handle) {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 9e1eda5b1..41418a7b8 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -54,10 +54,6 @@ public:
54 } depth_clamp; // GL_DEPTH_CLAMP 54 } depth_clamp; // GL_DEPTH_CLAMP
55 55
56 struct { 56 struct {
57 bool enabled; // viewports arrays are only supported when geometry shaders are enabled.
58 } geometry_shaders;
59
60 struct {
61 bool enabled; // GL_CULL_FACE 57 bool enabled; // GL_CULL_FACE
62 GLenum mode; // GL_CULL_FACE_MODE 58 GLenum mode; // GL_CULL_FACE_MODE
63 GLenum front_face; // GL_FRONT_FACE 59 GLenum front_face; // GL_FRONT_FACE
@@ -184,34 +180,26 @@ public:
184 static OpenGLState GetCurState() { 180 static OpenGLState GetCurState() {
185 return cur_state; 181 return cur_state;
186 } 182 }
183
187 static bool GetsRGBUsed() { 184 static bool GetsRGBUsed() {
188 return s_rgb_used; 185 return s_rgb_used;
189 } 186 }
187
190 static void ClearsRGBUsed() { 188 static void ClearsRGBUsed() {
191 s_rgb_used = false; 189 s_rgb_used = false;
192 } 190 }
191
193 /// Apply this state as the current OpenGL state 192 /// Apply this state as the current OpenGL state
194 void Apply() const; 193 void Apply() const;
195 /// Apply only the state affecting the framebuffer 194
196 void ApplyFramebufferState() const; 195 void ApplyFramebufferState() const;
197 /// Apply only the state affecting the vertex array
198 void ApplyVertexArrayState() const; 196 void ApplyVertexArrayState() const;
199 /// Set the initial OpenGL state 197 void ApplyShaderProgram() const;
200 static void ApplyDefaultState(); 198 void ApplyProgramPipeline() const;
201 /// Resets any references to the given resource 199 void ApplyClipDistances() const;
202 OpenGLState& UnbindTexture(GLuint handle); 200 void ApplyPointSize() const;
203 OpenGLState& ResetSampler(GLuint handle); 201 void ApplyFragmentColorClamp() const;
204 OpenGLState& ResetProgram(GLuint handle); 202 void ApplyMultisample() const;
205 OpenGLState& ResetPipeline(GLuint handle);
206 OpenGLState& ResetVertexArray(GLuint handle);
207 OpenGLState& ResetFramebuffer(GLuint handle);
208 void EmulateViewportWithScissor();
209
210private:
211 static OpenGLState cur_state;
212 // Workaround for sRGB problems caused by
213 // QT not supporting srgb output
214 static bool s_rgb_used;
215 void ApplySRgb() const; 203 void ApplySRgb() const;
216 void ApplyCulling() const; 204 void ApplyCulling() const;
217 void ApplyColorMask() const; 205 void ApplyColorMask() const;
@@ -227,6 +215,26 @@ private:
227 void ApplySamplers() const; 215 void ApplySamplers() const;
228 void ApplyDepthClamp() const; 216 void ApplyDepthClamp() const;
229 void ApplyPolygonOffset() const; 217 void ApplyPolygonOffset() const;
218
219 /// Set the initial OpenGL state
220 static void ApplyDefaultState();
221
222 /// Resets any references to the given resource
223 OpenGLState& UnbindTexture(GLuint handle);
224 OpenGLState& ResetSampler(GLuint handle);
225 OpenGLState& ResetProgram(GLuint handle);
226 OpenGLState& ResetPipeline(GLuint handle);
227 OpenGLState& ResetVertexArray(GLuint handle);
228 OpenGLState& ResetFramebuffer(GLuint handle);
229
230 /// Viewport does not affects glClearBuffer so emulate viewport using scissor test
231 void EmulateViewportWithScissor();
232
233private:
234 static OpenGLState cur_state;
235
236 // Workaround for sRGB problems caused by QT not supporting srgb output
237 static bool s_rgb_used;
230}; 238};
231 239
232} // namespace OpenGL 240} // namespace OpenGL