From 3983b120869cb87da6dfef55a77b94bbb63008c0 Mon Sep 17 00:00:00 2001
From: liushuyu <liushuyu011@gmail.com>
Date: Tue, 12 Mar 2019 22:28:40 -0600
Subject: [PATCH] video_core: renderer_opengl: gles color fix

---
 .../renderer_opengl/gl_rasterizer_cache.cpp   | 42 ++++++++++++++++++-
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 44dd2e78f..911f059d0 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -175,6 +175,20 @@ static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) {
                 if (format == PixelFormat::D24S8) {
                     gl_ptr[0] = tile_ptr[3];
                     std::memcpy(gl_ptr + 1, tile_ptr, 3);
+                } else if (format == PixelFormat::RGBA8 && GLES) {
+                    // because GLES does not have BGR format
+                    // so we will do byteswapping here
+                    gl_ptr[0] = tile_ptr[3];
+                    gl_ptr[1] = tile_ptr[2];
+                    gl_ptr[2] = tile_ptr[1];
+                    gl_ptr[3] = tile_ptr[0];
+                } else if (format == PixelFormat::RGB8 && GLES) {
+                    // the last channel Alpha should keep the same
+                    // position as the original
+                    gl_ptr[0] = tile_ptr[2];
+                    gl_ptr[1] = tile_ptr[1];
+                    gl_ptr[2] = tile_ptr[0];
+                    gl_ptr[3] = tile_ptr[3];
                 } else {
                     std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel);
                 }
@@ -719,6 +733,9 @@ void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surfac
 MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
 void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
     ASSERT(type != SurfaceType::Fill);
+    // FIXME(liushuyu): not endianness-aware, assumed little-endian
+    bool need_swap =
+        GLES && (pixel_format == PixelFormat::RGBA8 || pixel_format == PixelFormat::RGB8);
 
     const u8* const texture_src_data = VideoCore::g_memory->GetPhysicalPointer(addr);
     if (texture_src_data == nullptr)
@@ -743,8 +760,28 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
 
     if (!is_tiled) {
         ASSERT(type == SurfaceType::Color);
-        std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset,
-                    load_end - load_start);
+        if (need_swap) {
+            // TODO(liushuyu): check if the byteswap here is 100% correct
+            // cannot fully test this
+            if (pixel_format == PixelFormat::RGBA8) {
+                for (size_t i = start_offset; i < load_end - addr; i += 4) {
+                    gl_buffer[i] = *(texture_src_data + start_offset + i + 3);
+                    gl_buffer[i + 1] = *(texture_src_data + start_offset + i + 2);
+                    gl_buffer[i + 2] = *(texture_src_data + start_offset + i + 1);
+                    gl_buffer[i + 3] = *(texture_src_data + start_offset + i);
+                }
+            } else if (pixel_format == PixelFormat::RGB8) {
+                for (size_t i = start_offset; i < load_end - addr; i += 4) {
+                    gl_buffer[i] = *(texture_src_data + start_offset + i + 2);
+                    gl_buffer[i + 1] = *(texture_src_data + start_offset + i + 1);
+                    gl_buffer[i + 2] = *(texture_src_data + start_offset + i);
+                    gl_buffer[i + 3] = *(texture_src_data + start_offset + i + 3);
+                }
+            }
+        } else {
+            std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset,
+                        load_end - load_start);
+        }
     } else {
         if (type == SurfaceType::Texture) {
             Pica::Texture::TextureInfo tex_info{};
@@ -764,6 +801,7 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
                         Pica::Texture::LookupTexture(texture_src_data, x, height - 1 - y, tex_info);
                     const std::size_t offset = (x + (width * y)) * 4;
                     std::memcpy(&gl_buffer[offset], vec4.AsArray(), 4);
+                    // TODO(liushuyu): byteswap textures
                 }
             }
         } else {