diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index eff6abd55e..4f137e6938 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -631,7 +631,16 @@ public:
                     }
                 } zeta;
 
-                INSERT_PADDING_WORDS(0x5B);
+                INSERT_PADDING_WORDS(0x41);
+
+                union {
+                    BitField<0, 4, u32> stencil;
+                    BitField<4, 4, u32> unknown;
+                    BitField<8, 4, u32> scissor;
+                    BitField<12, 4, u32> viewport;
+                } clear_flags;
+
+                INSERT_PADDING_WORDS(0x19);
 
                 std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format;
 
@@ -1134,6 +1143,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
 ASSERT_REG_POSITION(color_mask_common, 0x3E4);
 ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
 ASSERT_REG_POSITION(zeta, 0x3F8);
+ASSERT_REG_POSITION(clear_flags, 0x43E);
 ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
 ASSERT_REG_POSITION(rt_control, 0x487);
 ASSERT_REG_POSITION(zeta_width, 0x48a);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index ae6aaee4c3..714330e806 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -542,6 +542,30 @@ void RasterizerOpenGL::Clear() {
         ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
         use_stencil = true;
         clear_state.stencil.test_enabled = true;
+        if (regs.clear_flags.stencil) {
+            // Stencil affects the clear so fill it with the used masks
+            clear_state.stencil.front.test_func = GL_ALWAYS;
+            clear_state.stencil.front.test_mask = regs.stencil_front_func_mask;
+            clear_state.stencil.front.action_stencil_fail = GL_KEEP;
+            clear_state.stencil.front.action_depth_fail = GL_KEEP;
+            clear_state.stencil.front.action_depth_pass = GL_KEEP;
+            clear_state.stencil.front.write_mask = regs.stencil_front_mask;
+            if (regs.stencil_two_side_enable) {
+                clear_state.stencil.back.test_func = GL_ALWAYS;
+                clear_state.stencil.back.test_mask = regs.stencil_back_func_mask;
+                clear_state.stencil.back.action_stencil_fail = GL_KEEP;
+                clear_state.stencil.back.action_depth_fail = GL_KEEP;
+                clear_state.stencil.back.action_depth_pass = GL_KEEP;
+                clear_state.stencil.back.write_mask = regs.stencil_back_mask;
+            } else {
+                clear_state.stencil.back.test_func = GL_ALWAYS;
+                clear_state.stencil.back.test_mask = 0xFFFFFFFF;
+                clear_state.stencil.back.write_mask = 0xFFFFFFFF;
+                clear_state.stencil.back.action_stencil_fail = GL_KEEP;
+                clear_state.stencil.back.action_depth_fail = GL_KEEP;
+                clear_state.stencil.back.action_depth_pass = GL_KEEP;
+            }
+        }
     }
 
     if (!use_color && !use_depth && !use_stencil) {
@@ -553,6 +577,14 @@ void RasterizerOpenGL::Clear() {
 
     ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
                           regs.clear_buffers.RT.Value());
+    if (regs.clear_flags.scissor) {
+        SyncScissorTest(clear_state);
+    }
+
+    if (regs.clear_flags.viewport) {
+        clear_state.EmulateViewportWithScissor();
+    }
+
     clear_state.Apply();
 
     if (use_color) {
@@ -588,7 +620,7 @@ void RasterizerOpenGL::DrawArrays() {
     SyncLogicOpState();
     SyncCullMode();
     SyncPrimitiveRestart();
-    SyncScissorTest();
+    SyncScissorTest(state);
     // Alpha Testing is synced on shaders.
     SyncTransformFeedback();
     SyncPointState();
@@ -815,7 +847,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
     }
     const u32 bias = config.mip_lod_bias.Value();
     // Sign extend the 13-bit value.
-    const u32 mask = 1U << (13 - 1);
+    constexpr u32 mask = 1U << (13 - 1);
     const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f;
     if (lod_bias != bias_lod) {
         lod_bias = bias_lod;
@@ -947,8 +979,8 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
         auto& viewport = current_state.viewports[i];
         viewport.x = viewport_rect.left;
         viewport.y = viewport_rect.bottom;
-        viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
-        viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
+        viewport.width = viewport_rect.GetWidth();
+        viewport.height = viewport_rect.GetHeight();
         viewport.depth_range_far = regs.viewports[i].depth_range_far;
         viewport.depth_range_near = regs.viewports[i].depth_range_near;
     }
@@ -1120,11 +1152,11 @@ void RasterizerOpenGL::SyncLogicOpState() {
     state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
 }
 
-void RasterizerOpenGL::SyncScissorTest() {
+void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) {
     const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
     for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) {
         const auto& src = regs.scissor_test[i];
-        auto& dst = state.viewports[i].scissor;
+        auto& dst = current_state.viewports[i].scissor;
         dst.enabled = (src.enable != 0);
         if (dst.enabled == 0) {
             return;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 6e78ab4cd8..d3192c47df 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -91,19 +91,20 @@ private:
         void SyncWithConfig(const Tegra::Texture::TSCEntry& info);
 
     private:
-        Tegra::Texture::TextureFilter mag_filter;
-        Tegra::Texture::TextureFilter min_filter;
-        Tegra::Texture::TextureMipmapFilter mip_filter;
-        Tegra::Texture::WrapMode wrap_u;
-        Tegra::Texture::WrapMode wrap_v;
-        Tegra::Texture::WrapMode wrap_p;
-        bool uses_depth_compare;
-        Tegra::Texture::DepthCompareFunc depth_compare_func;
-        GLvec4 border_color;
-        float min_lod;
-        float max_lod;
-        float lod_bias;
-        float max_anisotropic;
+        Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest;
+        Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest;
+        Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None;
+        Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge;
+        Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge;
+        Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge;
+        bool uses_depth_compare = false;
+        Tegra::Texture::DepthCompareFunc depth_compare_func =
+            Tegra::Texture::DepthCompareFunc::Always;
+        GLvec4 border_color = {};
+        float min_lod = 0.0f;
+        float max_lod = 16.0f;
+        float lod_bias = 0.0f;
+        float max_anisotropic = 1.0f;
     };
 
     /**
@@ -171,7 +172,7 @@ private:
     void SyncMultiSampleState();
 
     /// Syncs the scissor test state to match the guest state
-    void SyncScissorTest();
+    void SyncScissorTest(OpenGLState& current_state);
 
     /// Syncs the transform feedback state to match the guest state
     void SyncTransformFeedback();
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index d9910c6e83..41beb176d5 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -233,6 +233,28 @@ void OpenGLState::ApplyStencilTest() const {
         config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
     }
 }
+// Viewport does not affects glClearBuffer so emulate viewport using scissor test
+void OpenGLState::EmulateViewportWithScissor() {
+    auto& current = viewports[0];
+    if (current.scissor.enabled) {
+        const GLint left = std::max(current.x, current.scissor.x);
+        const GLint right =
+            std::max(current.x + current.width, current.scissor.x + current.scissor.width);
+        const GLint bottom = std::max(current.y, current.scissor.y);
+        const GLint top =
+            std::max(current.y + current.height, current.scissor.y + current.scissor.height);
+        current.scissor.x = std::max(left, 0);
+        current.scissor.y = std::max(bottom, 0);
+        current.scissor.width = std::max(right - left, 0);
+        current.scissor.height = std::max(top - bottom, 0);
+    } else {
+        current.scissor.enabled = true;
+        current.scissor.x = current.x;
+        current.scissor.y = current.y;
+        current.scissor.width = current.width;
+        current.scissor.height = current.height;
+    }
+}
 
 void OpenGLState::ApplyViewport() const {
     if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) {
@@ -242,7 +264,9 @@ void OpenGLState::ApplyViewport() const {
             const auto& updated = viewports[i];
             if (updated.x != current.x || updated.y != current.y ||
                 updated.width != current.width || updated.height != current.height) {
-                glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height);
+                glViewportIndexedf(
+                    i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y),
+                    static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height));
             }
             if (updated.depth_range_near != current.depth_range_near ||
                 updated.depth_range_far != current.depth_range_far) {
@@ -270,8 +294,7 @@ void OpenGLState::ApplyViewport() const {
         const auto& updated = viewports[0];
         if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
             updated.height != current.height) {
-            glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y),
-                       static_cast<GLsizei>(updated.width), static_cast<GLsizei>(updated.height));
+            glViewport(updated.x, updated.y, updated.width, updated.height);
         }
         if (updated.depth_range_near != current.depth_range_near ||
             updated.depth_range_far != current.depth_range_far) {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index bdc743b0f0..032fc43f0d 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -156,10 +156,10 @@ public:
     } draw;
 
     struct viewport {
-        GLfloat x;
-        GLfloat y;
-        GLfloat width;
-        GLfloat height;
+        GLint x;
+        GLint y;
+        GLint width;
+        GLint height;
         GLfloat depth_range_near; // GL_DEPTH_RANGE
         GLfloat depth_range_far;  // GL_DEPTH_RANGE
         struct {
@@ -206,6 +206,7 @@ public:
     OpenGLState& ResetBuffer(GLuint handle);
     OpenGLState& ResetVertexArray(GLuint handle);
     OpenGLState& ResetFramebuffer(GLuint handle);
+    void EmulateViewportWithScissor();
 
 private:
     static OpenGLState cur_state;