From ba7f21365517ce77dea49b12250629db88f720f3 Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 4 Dec 2016 05:15:33 -0800
Subject: [PATCH 1/4] OpenGL: Fix DisplayTransfer accel when input width !=
 output width

Fixes #2246, #2261
---
 src/video_core/renderer_opengl/gl_rasterizer.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 1b734aaa53..c2cd89e54b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -715,7 +715,11 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
 
     CachedSurface src_params;
     src_params.addr = config.GetPhysicalInputAddress();
-    src_params.width = config.output_width;
+    // It's important to use the correct source input width to properly skip over parts of the input
+    // image which will be cropped from the output but still affect the stride of the input image.
+    src_params.width = config.input_width;
+    // Using the output's height is fine because we don't read or skip over the remaining part of
+    // the image, and it allows for smaller texture cache lookup rectangles.
     src_params.height = config.output_height;
     src_params.is_tiled = !config.input_linear;
     src_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.input_format);
@@ -736,6 +740,11 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
         return false;
     }
 
+    // Adjust the source rectangle to take into account parts of the input lines being cropped
+    if (config.input_width > config.output_width) {
+        src_rect.right -= (config.input_width - config.output_width) * src_surface->res_scale_width;
+    }
+
     // Require destination surface to have same resolution scale as source to preserve scaling
     dst_params.res_scale_width = src_surface->res_scale_width;
     dst_params.res_scale_height = src_surface->res_scale_height;

From 2600633b895ad06efb316ed0e3205f8adcaa96da Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 4 Dec 2016 05:16:14 -0800
Subject: [PATCH 2/4] OpenGL: Ensure framebuffer binding is restored if
 completion check fails

---
 .../renderer_opengl/gl_rasterizer_cache.cpp     | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 5cbad9b432..9ee3bb2ac3 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -158,24 +158,21 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex,
         buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
     }
 
-    if (OpenGLState::CheckFBStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-        return false;
-    }
+    bool can_blit = OpenGLState::CheckFBStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE &&
+                    OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
 
-    if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-        return false;
+    if (can_blit) {
+        glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
+                          dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, buffers,
+                          buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
     }
 
-    glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
-                      dst_rect.top, dst_rect.right, dst_rect.bottom, buffers,
-                      buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
-
     // Restore previous framebuffer bindings
     cur_state.draw.read_framebuffer = old_fbs[0];
     cur_state.draw.draw_framebuffer = old_fbs[1];
     cur_state.Apply();
 
-    return true;
+    return can_blit;
 }
 
 bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface,

From 8a1f96011daa6e7b386d6f9f024a1ccf5eb95366 Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 4 Dec 2016 05:16:56 -0800
Subject: [PATCH 3/4] OpenGL: Non-zero stride only makes sense for linear
 buffers

---
 src/video_core/renderer_opengl/gl_rasterizer.cpp    |  2 +-
 .../renderer_opengl/gl_rasterizer_cache.cpp         | 13 ++++++++-----
 .../renderer_opengl/gl_rasterizer_cache.h           |  3 ++-
 3 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index c2cd89e54b..3f2255e064 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -947,7 +947,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
     src_params.addr = framebuffer_addr;
     src_params.width = config.width;
     src_params.height = config.height;
-    src_params.stride = pixel_stride;
+    src_params.pixel_stride = pixel_stride;
     src_params.is_tiled = false;
     src_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.color_format);
 
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 9ee3bb2ac3..61f6e767f4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -288,6 +288,9 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
 
     MICROPROFILE_SCOPE(OpenGL_SurfaceUpload);
 
+    // Stride only applies to linear images.
+    ASSERT(params.pixel_stride == 0 || !params.is_tiled);
+
     std::shared_ptr<CachedSurface> new_surface = std::make_shared<CachedSurface>();
 
     new_surface->addr = params.addr;
@@ -296,7 +299,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
     new_surface->texture.Create();
     new_surface->width = params.width;
     new_surface->height = params.height;
-    new_surface->stride = params.stride;
+    new_surface->pixel_stride = params.pixel_stride;
     new_surface->res_scale_width = params.res_scale_width;
     new_surface->res_scale_height = params.res_scale_height;
 
@@ -322,14 +325,15 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
         cur_state.Apply();
         glActiveTexture(GL_TEXTURE0);
 
-        glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)new_surface->stride);
         if (!new_surface->is_tiled) {
             // TODO: Ensure this will always be a color format, not a depth or other format
             ASSERT((size_t)new_surface->pixel_format < fb_format_tuples.size());
             const FormatTuple& tuple = fb_format_tuples[(unsigned int)params.pixel_format];
 
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)new_surface->pixel_stride);
             glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, 0,
                          tuple.format, tuple.type, texture_src_data);
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
         } else {
             SurfaceType type = CachedSurface::GetFormatType(new_surface->pixel_format);
             if (type != SurfaceType::Depth && type != SurfaceType::DepthStencil) {
@@ -388,7 +392,6 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
                              0, tuple.format, tuple.type, temp_fb_depth_buffer.data());
             }
         }
-        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 
         // If not 1x scale, blit 1x texture to a new scaled texture and replace texture in surface
         if (new_surface->res_scale_width != 1.f || new_surface->res_scale_height != 1.f) {
@@ -698,13 +701,14 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
     cur_state.Apply();
     glActiveTexture(GL_TEXTURE0);
 
-    glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)surface->stride);
     if (!surface->is_tiled) {
         // TODO: Ensure this will always be a color format, not a depth or other format
         ASSERT((size_t)surface->pixel_format < fb_format_tuples.size());
         const FormatTuple& tuple = fb_format_tuples[(unsigned int)surface->pixel_format];
 
+        glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)surface->pixel_stride);
         glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, dst_buffer);
+        glPixelStorei(GL_PACK_ROW_LENGTH, 0);
     } else {
         SurfaceType type = CachedSurface::GetFormatType(surface->pixel_format);
         if (type != SurfaceType::Depth && type != SurfaceType::DepthStencil) {
@@ -747,7 +751,6 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
                              false);
         }
     }
-    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
 
     surface->dirty = false;
 
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 849530d860..32abfbaf52 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -171,7 +171,8 @@ struct CachedSurface {
     OGLTexture texture;
     u32 width;
     u32 height;
-    u32 stride = 0;
+    /// Stride between lines, in pixels. Only valid for images in linear format.
+    u32 pixel_stride = 0;
     float res_scale_width = 1.f;
     float res_scale_height = 1.f;
 

From efc81797473e0288f23862942ea22b4b0d544693 Mon Sep 17 00:00:00 2001
From: Yuri Kunde Schlesner <yuriks@yuriks.net>
Date: Sun, 4 Dec 2016 05:19:10 -0800
Subject: [PATCH 4/4] GSP: Downgrade log severity of SetAxiConfigQoSMode

This function doesn't need to do anything for HLE and some games call it
quite often, spamming up the logs.
---
 src/core/hle/service/gsp_gpu.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 710e0e4857..78cb761beb 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -346,7 +346,7 @@ static void SetAxiConfigQoSMode(Service::Interface* self) {
 
     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 
-    LOG_WARNING(Service_GSP, "(STUBBED) called mode=0x%08X", mode);
+    LOG_DEBUG(Service_GSP, "(STUBBED) called mode=0x%08X", mode);
 }
 
 /**