summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/engines/maxwell_3d.cpp82
-rw-r--r--src/video_core/engines/maxwell_3d.h10
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp86
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp22
-rw-r--r--src/video_core/renderer_opengl/gl_state.h37
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp6
6 files changed, 199 insertions, 44 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7d3a550f8..cfa98f528 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -159,6 +159,88 @@ void Maxwell3D::InitDirtySettings() {
159 sizeof(regs.shader_config[0]) * Regs::MaxShaderProgram / sizeof(u32); 159 sizeof(regs.shader_config[0]) * Regs::MaxShaderProgram / sizeof(u32);
160 set_block(MAXWELL3D_REG_INDEX(shader_config[0]), shader_registers_count, 160 set_block(MAXWELL3D_REG_INDEX(shader_config[0]), shader_registers_count,
161 DIRTY_REGS_POS(shaders)); 161 DIRTY_REGS_POS(shaders));
162
163 // State
164
165 // Viewport
166 constexpr u32 viewport_dirty_reg = DIRTY_REGS_POS(viewport);
167 constexpr u32 viewport_start = MAXWELL3D_REG_INDEX(viewports);
168 constexpr u32 viewport_size = sizeof(regs.viewports) / sizeof(u32);
169 set_block(viewport_start, viewport_size, viewport_dirty_reg);
170 constexpr u32 view_volume_start = MAXWELL3D_REG_INDEX(view_volume_clip_control);
171 constexpr u32 view_volume_size = sizeof(regs.view_volume_clip_control) / sizeof(u32);
172 set_block(view_volume_start, view_volume_size, viewport_dirty_reg);
173
174 // Viewport transformation
175 constexpr u32 viewport_trans_start = MAXWELL3D_REG_INDEX(viewport_transform);
176 constexpr u32 viewport_trans_size = sizeof(regs.viewport_transform) / sizeof(u32);
177 set_block(viewport_trans_start, viewport_trans_size, DIRTY_REGS_POS(viewport_transform));
178
179 // Cullmode
180 constexpr u32 cull_mode_start = MAXWELL3D_REG_INDEX(cull);
181 constexpr u32 cull_mode_size = sizeof(regs.cull) / sizeof(u32);
182 set_block(cull_mode_start, cull_mode_size, DIRTY_REGS_POS(cull_mode));
183
184 // Screen y control
185 dirty_pointers[MAXWELL3D_REG_INDEX(screen_y_control)] = DIRTY_REGS_POS(screen_y_control);
186
187 // Primitive Restart
188 constexpr u32 primitive_restart_start = MAXWELL3D_REG_INDEX(primitive_restart);
189 constexpr u32 primitive_restart_size = sizeof(regs.primitive_restart) / sizeof(u32);
190 set_block(primitive_restart_start, primitive_restart_size, DIRTY_REGS_POS(primitive_restart));
191
192 // Depth Test
193 constexpr u32 depth_test_dirty_reg = DIRTY_REGS_POS(depth_test);
194 dirty_pointers[MAXWELL3D_REG_INDEX(depth_test_enable)] = depth_test_dirty_reg;
195 dirty_pointers[MAXWELL3D_REG_INDEX(depth_write_enabled)] = depth_test_dirty_reg;
196 dirty_pointers[MAXWELL3D_REG_INDEX(depth_test_func)] = depth_test_dirty_reg;
197
198 // Stencil Test
199 constexpr u32 stencil_test_dirty_reg = DIRTY_REGS_POS(stencil_test);
200 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_enable)] = stencil_test_dirty_reg;
201 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_func_func)] = stencil_test_dirty_reg;
202 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_func_ref)] = stencil_test_dirty_reg;
203 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_func_mask)] = stencil_test_dirty_reg;
204 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_op_fail)] = stencil_test_dirty_reg;
205 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_op_zfail)] = stencil_test_dirty_reg;
206 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_op_zpass)] = stencil_test_dirty_reg;
207 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_mask)] = stencil_test_dirty_reg;
208 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_two_side_enable)] = stencil_test_dirty_reg;
209 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_func_func)] = stencil_test_dirty_reg;
210 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_func_ref)] = stencil_test_dirty_reg;
211 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_func_mask)] = stencil_test_dirty_reg;
212 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_op_fail)] = stencil_test_dirty_reg;
213 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_op_zfail)] = stencil_test_dirty_reg;
214 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_op_zpass)] = stencil_test_dirty_reg;
215 dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_mask)] = stencil_test_dirty_reg;
216
217 // Color Mask
218 constexpr u32 color_mask_dirty_reg = DIRTY_REGS_POS(color_mask);
219 dirty_pointers[MAXWELL3D_REG_INDEX(color_mask_common)] = color_mask_dirty_reg;
220 set_block(MAXWELL3D_REG_INDEX(color_mask), sizeof(regs.color_mask) / sizeof(u32),
221 color_mask_dirty_reg);
222 // Blend State
223 constexpr u32 blend_state_dirty_reg = DIRTY_REGS_POS(blend_state);
224 set_block(MAXWELL3D_REG_INDEX(blend_color), sizeof(regs.blend_color) / sizeof(u32),
225 blend_state_dirty_reg);
226 dirty_pointers[MAXWELL3D_REG_INDEX(independent_blend_enable)] = blend_state_dirty_reg;
227 set_block(MAXWELL3D_REG_INDEX(blend), sizeof(regs.blend) / sizeof(u32), blend_state_dirty_reg);
228 set_block(MAXWELL3D_REG_INDEX(independent_blend), sizeof(regs.independent_blend) / sizeof(u32),
229 blend_state_dirty_reg);
230
231 // Scissor State
232 constexpr u32 scissor_test_dirty_reg = DIRTY_REGS_POS(scissor_test);
233 set_block(MAXWELL3D_REG_INDEX(scissor_test), sizeof(regs.scissor_test) / sizeof(u32),
234 scissor_test_dirty_reg);
235
236 // Polygon Offset
237 constexpr u32 polygon_offset_dirty_reg = DIRTY_REGS_POS(polygon_offset);
238 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_fill_enable)] = polygon_offset_dirty_reg;
239 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_line_enable)] = polygon_offset_dirty_reg;
240 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_point_enable)] = polygon_offset_dirty_reg;
241 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_units)] = polygon_offset_dirty_reg;
242 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_factor)] = polygon_offset_dirty_reg;
243 dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_clamp)] = polygon_offset_dirty_reg;
162} 244}
163 245
164void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { 246void 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 318078f36..abc69cc65 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -1148,22 +1148,20 @@ public:
1148 bool shaders; 1148 bool shaders;
1149 // State 1149 // State
1150 bool viewport; 1150 bool viewport;
1151 bool clip_enabled;
1152 bool clip_coefficient; 1151 bool clip_coefficient;
1153 bool cull_mode; 1152 bool cull_mode;
1154 bool primitive_restart; 1153 bool primitive_restart;
1155 bool depth_test; 1154 bool depth_test;
1156 bool stencil_test; 1155 bool stencil_test;
1157 bool blend_state; 1156 bool blend_state;
1158 bool logic_op;
1159 bool fragment_color_clamp;
1160 bool multi_sample;
1161 bool scissor_test; 1157 bool scissor_test;
1162 bool transform_feedback; 1158 bool transform_feedback;
1163 bool point;
1164 bool color_mask; 1159 bool color_mask;
1165 bool polygon_offset; 1160 bool polygon_offset;
1166 bool alpha_test; 1161
1162 // Complementary
1163 bool viewport_transform;
1164 bool screen_y_control;
1167 1165
1168 bool memory_general; 1166 bool memory_general;
1169 }; 1167 };
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index c2b5cbff4..76f0f98eb 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -936,56 +936,53 @@ void RasterizerOpenGL::SyncClipCoef() {
936} 936}
937 937
938void RasterizerOpenGL::SyncCullMode() { 938void RasterizerOpenGL::SyncCullMode() {
939 const auto& regs = system.GPU().Maxwell3D().regs; 939 auto& maxwell3d = system.GPU().Maxwell3D();
940 940
941 state.cull.enabled = regs.cull.enabled != 0; 941 const auto& regs = maxwell3d.regs;
942 942
943 if (state.cull.enabled) { 943 state.cull.enabled = regs.cull.enabled != 0;
944 state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face); 944 state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face);
945 state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face); 945 state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face);
946 946
947 const bool flip_triangles{regs.screen_y_control.triangle_rast_flip == 0 || 947 const bool flip_triangles{regs.screen_y_control.triangle_rast_flip == 0 ||
948 regs.viewport_transform[0].scale_y < 0.0f}; 948 regs.viewport_transform[0].scale_y < 0.0f};
949 949
950 // If the GPU is configured to flip the rasterized triangles, then we need to flip the 950 // If the GPU is configured to flip the rasterized triangles, then we need to flip the
951 // notion of front and back. Note: We flip the triangles when the value of the register is 0 951 // notion of front and back. Note: We flip the triangles when the value of the register is 0
952 // because OpenGL already does it for us. 952 // because OpenGL already does it for us.
953 if (flip_triangles) { 953 if (flip_triangles) {
954 if (state.cull.front_face == GL_CCW) 954 if (state.cull.front_face == GL_CCW)
955 state.cull.front_face = GL_CW; 955 state.cull.front_face = GL_CW;
956 else if (state.cull.front_face == GL_CW) 956 else if (state.cull.front_face == GL_CW)
957 state.cull.front_face = GL_CCW; 957 state.cull.front_face = GL_CCW;
958 }
959 } 958 }
960} 959}
961 960
962void RasterizerOpenGL::SyncPrimitiveRestart() { 961void RasterizerOpenGL::SyncPrimitiveRestart() {
963 const auto& regs = system.GPU().Maxwell3D().regs; 962 auto& maxwell3d = system.GPU().Maxwell3D();
963 const auto& regs = maxwell3d.regs;
964 964
965 state.primitive_restart.enabled = regs.primitive_restart.enabled; 965 state.primitive_restart.enabled = regs.primitive_restart.enabled;
966 state.primitive_restart.index = regs.primitive_restart.index; 966 state.primitive_restart.index = regs.primitive_restart.index;
967} 967}
968 968
969void RasterizerOpenGL::SyncDepthTestState() { 969void RasterizerOpenGL::SyncDepthTestState() {
970 const auto& regs = system.GPU().Maxwell3D().regs; 970 auto& maxwell3d = system.GPU().Maxwell3D();
971 const auto& regs = maxwell3d.regs;
971 972
972 state.depth.test_enabled = regs.depth_test_enable != 0; 973 state.depth.test_enabled = regs.depth_test_enable != 0;
973 state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE; 974 state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE;
974
975 if (!state.depth.test_enabled)
976 return;
977
978 state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func); 975 state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func);
979} 976}
980 977
981void RasterizerOpenGL::SyncStencilTestState() { 978void RasterizerOpenGL::SyncStencilTestState() {
982 const auto& regs = system.GPU().Maxwell3D().regs; 979 auto& maxwell3d = system.GPU().Maxwell3D();
983 state.stencil.test_enabled = regs.stencil_enable != 0; 980 if (!maxwell3d.dirty.stencil_test) {
984
985 if (!regs.stencil_enable) {
986 return; 981 return;
987 } 982 }
983 const auto& regs = maxwell3d.regs;
988 984
985 state.stencil.test_enabled = regs.stencil_enable != 0;
989 state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func); 986 state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func);
990 state.stencil.front.test_ref = regs.stencil_front_func_ref; 987 state.stencil.front.test_ref = regs.stencil_front_func_ref;
991 state.stencil.front.test_mask = regs.stencil_front_func_mask; 988 state.stencil.front.test_mask = regs.stencil_front_func_mask;
@@ -1010,10 +1007,17 @@ void RasterizerOpenGL::SyncStencilTestState() {
1010 state.stencil.back.action_depth_fail = GL_KEEP; 1007 state.stencil.back.action_depth_fail = GL_KEEP;
1011 state.stencil.back.action_depth_pass = GL_KEEP; 1008 state.stencil.back.action_depth_pass = GL_KEEP;
1012 } 1009 }
1010 state.MarkDirtyStencilState(true);
1011 maxwell3d.dirty.stencil_test = false;
1013} 1012}
1014 1013
1015void RasterizerOpenGL::SyncColorMask() { 1014void RasterizerOpenGL::SyncColorMask() {
1016 const auto& regs = system.GPU().Maxwell3D().regs; 1015 auto& maxwell3d = system.GPU().Maxwell3D();
1016 if (!maxwell3d.dirty.color_mask) {
1017 return;
1018 }
1019 const auto& regs = maxwell3d.regs;
1020
1017 const std::size_t count = 1021 const std::size_t count =
1018 regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1; 1022 regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1;
1019 for (std::size_t i = 0; i < count; i++) { 1023 for (std::size_t i = 0; i < count; i++) {
@@ -1024,6 +1028,9 @@ void RasterizerOpenGL::SyncColorMask() {
1024 dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE; 1028 dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE;
1025 dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE; 1029 dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE;
1026 } 1030 }
1031
1032 state.MarkDirtyColorMask(true);
1033 maxwell3d.dirty.color_mask = false;
1027} 1034}
1028 1035
1029void RasterizerOpenGL::SyncMultiSampleState() { 1036void RasterizerOpenGL::SyncMultiSampleState() {
@@ -1038,7 +1045,11 @@ void RasterizerOpenGL::SyncFragmentColorClampState() {
1038} 1045}
1039 1046
1040void RasterizerOpenGL::SyncBlendState() { 1047void RasterizerOpenGL::SyncBlendState() {
1041 const auto& regs = system.GPU().Maxwell3D().regs; 1048 auto& maxwell3d = system.GPU().Maxwell3D();
1049 if (!maxwell3d.dirty.blend_state) {
1050 return;
1051 }
1052 const auto& regs = maxwell3d.regs;
1042 1053
1043 state.blend_color.red = regs.blend_color.r; 1054 state.blend_color.red = regs.blend_color.r;
1044 state.blend_color.green = regs.blend_color.g; 1055 state.blend_color.green = regs.blend_color.g;
@@ -1061,6 +1072,8 @@ void RasterizerOpenGL::SyncBlendState() {
1061 for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { 1072 for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1062 state.blend[i].enabled = false; 1073 state.blend[i].enabled = false;
1063 } 1074 }
1075 maxwell3d.dirty.blend_state = false;
1076 state.MarkDirtyBlendState(true);
1064 return; 1077 return;
1065 } 1078 }
1066 1079
@@ -1077,6 +1090,9 @@ void RasterizerOpenGL::SyncBlendState() {
1077 blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a); 1090 blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a);
1078 blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a); 1091 blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a);
1079 } 1092 }
1093
1094 state.MarkDirtyBlendState(true);
1095 maxwell3d.dirty.blend_state = false;
1080} 1096}
1081 1097
1082void RasterizerOpenGL::SyncLogicOpState() { 1098void RasterizerOpenGL::SyncLogicOpState() {
@@ -1128,13 +1144,21 @@ void RasterizerOpenGL::SyncPointState() {
1128} 1144}
1129 1145
1130void RasterizerOpenGL::SyncPolygonOffset() { 1146void RasterizerOpenGL::SyncPolygonOffset() {
1131 const auto& regs = system.GPU().Maxwell3D().regs; 1147 auto& maxwell3d = system.GPU().Maxwell3D();
1148 if (!maxwell3d.dirty.polygon_offset) {
1149 return;
1150 }
1151 const auto& regs = maxwell3d.regs;
1152
1132 state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0; 1153 state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0;
1133 state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0; 1154 state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0;
1134 state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0; 1155 state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0;
1135 state.polygon_offset.units = regs.polygon_offset_units; 1156 state.polygon_offset.units = regs.polygon_offset_units;
1136 state.polygon_offset.factor = regs.polygon_offset_factor; 1157 state.polygon_offset.factor = regs.polygon_offset_factor;
1137 state.polygon_offset.clamp = regs.polygon_offset_clamp; 1158 state.polygon_offset.clamp = regs.polygon_offset_clamp;
1159
1160 state.MarkDirtyPolygonOffset(true);
1161 maxwell3d.dirty.polygon_offset = false;
1138} 1162}
1139 1163
1140void RasterizerOpenGL::SyncAlphaTest() { 1164void RasterizerOpenGL::SyncAlphaTest() {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 0eae98afe..cac03dc31 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -526,7 +526,7 @@ void OpenGLState::ApplySamplers() const {
526 } 526 }
527} 527}
528 528
529void OpenGLState::Apply() const { 529void OpenGLState::Apply() {
530 MICROPROFILE_SCOPE(OpenGL_State); 530 MICROPROFILE_SCOPE(OpenGL_State);
531 ApplyFramebufferState(); 531 ApplyFramebufferState();
532 ApplyVertexArrayState(); 532 ApplyVertexArrayState();
@@ -536,19 +536,31 @@ void OpenGLState::Apply() const {
536 ApplyPointSize(); 536 ApplyPointSize();
537 ApplyFragmentColorClamp(); 537 ApplyFragmentColorClamp();
538 ApplyMultisample(); 538 ApplyMultisample();
539 if (dirty.color_mask) {
540 ApplyColorMask();
541 dirty.color_mask = false;
542 }
539 ApplyDepthClamp(); 543 ApplyDepthClamp();
540 ApplyColorMask();
541 ApplyViewport(); 544 ApplyViewport();
542 ApplyStencilTest(); 545 if (dirty.stencil_state) {
546 ApplyStencilTest();
547 dirty.stencil_state = false;
548 }
543 ApplySRgb(); 549 ApplySRgb();
544 ApplyCulling(); 550 ApplyCulling();
545 ApplyDepth(); 551 ApplyDepth();
546 ApplyPrimitiveRestart(); 552 ApplyPrimitiveRestart();
547 ApplyBlending(); 553 if (dirty.blend_state) {
554 ApplyBlending();
555 dirty.blend_state = false;
556 }
548 ApplyLogicOp(); 557 ApplyLogicOp();
549 ApplyTextures(); 558 ApplyTextures();
550 ApplySamplers(); 559 ApplySamplers();
551 ApplyPolygonOffset(); 560 if (dirty.polygon_offset) {
561 ApplyPolygonOffset();
562 dirty.polygon_offset = false;
563 }
552 ApplyAlphaTest(); 564 ApplyAlphaTest();
553} 565}
554 566
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index b0140495d..3d0f6747f 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -196,7 +196,7 @@ public:
196 } 196 }
197 197
198 /// Apply this state as the current OpenGL state 198 /// Apply this state as the current OpenGL state
199 void Apply() const; 199 void Apply();
200 200
201 void ApplyFramebufferState() const; 201 void ApplyFramebufferState() const;
202 void ApplyVertexArrayState() const; 202 void ApplyVertexArrayState() const;
@@ -237,11 +237,46 @@ public:
237 /// Viewport does not affects glClearBuffer so emulate viewport using scissor test 237 /// Viewport does not affects glClearBuffer so emulate viewport using scissor test
238 void EmulateViewportWithScissor(); 238 void EmulateViewportWithScissor();
239 239
240 void MarkDirtyBlendState(const bool is_dirty) {
241 dirty.blend_state = is_dirty;
242 }
243
244 void MarkDirtyStencilState(const bool is_dirty) {
245 dirty.stencil_state = is_dirty;
246 }
247
248 void MarkDirtyViewportState(const bool is_dirty) {
249 dirty.viewport_state = is_dirty;
250 }
251
252 void MarkDirtyPolygonOffset(const bool is_dirty) {
253 dirty.polygon_offset = is_dirty;
254 }
255
256 void MarkDirtyColorMask(const bool is_dirty) {
257 dirty.color_mask = is_dirty;
258 }
259
260 void AllDirty() {
261 dirty.blend_state = true;
262 dirty.stencil_state = true;
263 dirty.viewport_state = true;
264 dirty.polygon_offset = true;
265 dirty.color_mask = true;
266 }
267
240private: 268private:
241 static OpenGLState cur_state; 269 static OpenGLState cur_state;
242 270
243 // Workaround for sRGB problems caused by QT not supporting srgb output 271 // Workaround for sRGB problems caused by QT not supporting srgb output
244 static bool s_rgb_used; 272 static bool s_rgb_used;
273 struct {
274 bool blend_state;
275 bool stencil_state;
276 bool viewport_state;
277 bool polygon_offset;
278 bool color_mask;
279 } dirty{};
245}; 280};
246 281
247} // namespace OpenGL 282} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index b1f6bc7c2..8fcd39a69 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -485,11 +485,15 @@ void TextureCacheOpenGL::ImageBlit(View& src_view, View& dst_view,
485 const auto& dst_params{dst_view->GetSurfaceParams()}; 485 const auto& dst_params{dst_view->GetSurfaceParams()};
486 486
487 OpenGLState prev_state{OpenGLState::GetCurState()}; 487 OpenGLState prev_state{OpenGLState::GetCurState()};
488 SCOPE_EXIT({ prev_state.Apply(); }); 488 SCOPE_EXIT({
489 prev_state.AllDirty();
490 prev_state.Apply();
491 });
489 492
490 OpenGLState state; 493 OpenGLState state;
491 state.draw.read_framebuffer = src_framebuffer.handle; 494 state.draw.read_framebuffer = src_framebuffer.handle;
492 state.draw.draw_framebuffer = dst_framebuffer.handle; 495 state.draw.draw_framebuffer = dst_framebuffer.handle;
496 state.AllDirty();
493 state.Apply(); 497 state.Apply();
494 498
495 u32 buffers{}; 499 u32 buffers{};