From d455b61d5ed6c5baf027b8a788a6a67e798aa6ac Mon Sep 17 00:00:00 2001
From: Connor McLaughlin <stenzek@gmail.com>
Date: Fri, 5 Feb 2021 02:16:45 +1000
Subject: [PATCH] OpenGLHostDisplay: Fix interlaced software renderer output

---
 src/frontend-common/opengl_host_display.cpp | 26 ++++++++++++++++++++-
 src/frontend-common/opengl_host_display.h   |  1 +
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/src/frontend-common/opengl_host_display.cpp b/src/frontend-common/opengl_host_display.cpp
index eab67f865..be4a7c0a2 100644
--- a/src/frontend-common/opengl_host_display.cpp
+++ b/src/frontend-common/opengl_host_display.cpp
@@ -2,6 +2,7 @@
 #include "common/align.h"
 #include "common/assert.h"
 #include "common/log.h"
+#include "common/string_util.h"
 #include "imgui.h"
 #include "imgui_impl_opengl3.h"
 #include "postprocessing_shadergen.h"
@@ -238,8 +239,31 @@ bool OpenGLHostDisplay::SetDisplayPixels(HostDisplayPixelFormat format, u32 widt
   }
 
   const auto [gl_internal_format, gl_format, gl_type] = s_display_pixel_format_mapping[static_cast<u32>(format)];
+  const u32 pixel_size = GetDisplayPixelFormatSize(format);
+  const bool is_packed_tightly = (pitch == (pixel_size * width));
 
-  glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, buffer);
+  // If we have GLES3, we can set row_length.
+  if (!m_use_gles2_draw_path || is_packed_tightly)
+  {
+    if (!is_packed_tightly)
+      glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / pixel_size);
+
+    glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, buffer);
+
+    if (!is_packed_tightly)
+      glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+  }
+  else
+  {
+    // Otherwise, we need to repack the image.
+    const u32 packed_pitch = width * pixel_size;
+    const u32 repack_size = packed_pitch * height;
+    if (m_gles2_pixels_repack_buffer.size() < repack_size)
+      m_gles2_pixels_repack_buffer.resize(repack_size);
+    StringUtil::StrideMemCpy(m_gles2_pixels_repack_buffer.data(), packed_pitch, buffer, pitch, packed_pitch, height);
+    glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type,
+                 m_gles2_pixels_repack_buffer.data());
+  }
 
   glBindTexture(GL_TEXTURE_2D, 0);
 
diff --git a/src/frontend-common/opengl_host_display.h b/src/frontend-common/opengl_host_display.h
index 34b9b6c07..17a9cd3a2 100644
--- a/src/frontend-common/opengl_host_display.h
+++ b/src/frontend-common/opengl_host_display.h
@@ -117,6 +117,7 @@ protected:
   std::vector<PostProcessingStage> m_post_processing_stages;
 
   bool m_use_gles2_draw_path = false;
+  std::vector<u8> m_gles2_pixels_repack_buffer;
 };
 
 } // namespace FrontendCommon
\ No newline at end of file