Replaced switches in Renderer::readPixels with calls to color reading and writing functions.

TRAC #23256

Signed-off-by: Jamie Madill
Signed-off-by: Shannon Woods
Author: Geoff Lang
diff --git a/src/libGLESv2/renderer/Renderer11.cpp b/src/libGLESv2/renderer/Renderer11.cpp
index 15aed65..6a380cf 100644
--- a/src/libGLESv2/renderer/Renderer11.cpp
+++ b/src/libGLESv2/renderer/Renderer11.cpp
@@ -3483,249 +3483,6 @@
     return new TextureStorage11_2DArray(this, levels, internalformat, usage, width, height, depth);
 }
 
-static inline unsigned int getFastPixelCopySize(DXGI_FORMAT sourceFormat, GLenum destFormat, GLenum destType, GLuint clientVersion)
-{
-    GLint sourceInternalFormat = d3d11_gl::GetInternalFormat(sourceFormat);
-    GLenum sourceGLFormat = gl::GetFormat(sourceInternalFormat, clientVersion);
-    GLenum sourceGLType = gl::GetType(sourceInternalFormat, clientVersion);
-
-    if (sourceGLFormat == destFormat && sourceGLType == destType)
-    {
-        return gl::GetPixelBytes(sourceInternalFormat, clientVersion);
-    }
-    else
-    {
-        return 0;
-    }
-}
-
-static inline void readPixelColor(const unsigned char *data, DXGI_FORMAT format, unsigned int x,
-                                  unsigned int y, int inputPitch, gl::ColorF *outColor)
-{
-    switch (format)
-    {
-      case DXGI_FORMAT_R8G8B8A8_UNORM:
-      case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
-        {
-            unsigned int rgba = *reinterpret_cast<const unsigned int*>(data + 4 * x + y * inputPitch);
-            outColor->red =   (rgba & 0x000000FF) * (1.0f / 0x000000FF);
-            outColor->green = (rgba & 0x0000FF00) * (1.0f / 0x0000FF00);
-            outColor->blue =  (rgba & 0x00FF0000) * (1.0f / 0x00FF0000);
-            outColor->alpha = (rgba & 0xFF000000) * (1.0f / 0xFF000000);
-        }
-        break;
-
-      case DXGI_FORMAT_A8_UNORM:
-        {
-            outColor->red =   0.0f;
-            outColor->green = 0.0f;
-            outColor->blue =  0.0f;
-            outColor->alpha = *(data + x + y * inputPitch) / 255.0f;
-        }
-        break;
-
-      case DXGI_FORMAT_R32G32B32A32_FLOAT:
-        {
-            outColor->red =   *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 0);
-            outColor->green = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 1);
-            outColor->blue =  *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 2);
-            outColor->alpha = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 3);
-        }
-        break;
-
-      case DXGI_FORMAT_R32G32B32_FLOAT:
-        {
-            outColor->red =   *(reinterpret_cast<const float*>(data + 12 * x + y * inputPitch) + 0);
-            outColor->green = *(reinterpret_cast<const float*>(data + 12 * x + y * inputPitch) + 1);
-            outColor->blue =  *(reinterpret_cast<const float*>(data + 12 * x + y * inputPitch) + 2);
-            outColor->alpha = 1.0f;
-        }
-        break;
-
-      case DXGI_FORMAT_R16G16B16A16_FLOAT:
-        {
-            outColor->red =   gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 0));
-            outColor->green = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 1));
-            outColor->blue =  gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 2));
-            outColor->alpha = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 3));
-        }
-        break;
-
-      case DXGI_FORMAT_B8G8R8A8_UNORM:
-        {
-            unsigned int bgra = *reinterpret_cast<const unsigned int*>(data + 4 * x + y * inputPitch);
-            outColor->red =   (bgra & 0x00FF0000) * (1.0f / 0x00FF0000);
-            outColor->blue =  (bgra & 0x000000FF) * (1.0f / 0x000000FF);
-            outColor->green = (bgra & 0x0000FF00) * (1.0f / 0x0000FF00);
-            outColor->alpha = (bgra & 0xFF000000) * (1.0f / 0xFF000000);
-        }
-        break;
-
-      case DXGI_FORMAT_R8_UNORM:
-        {
-            outColor->red =   *(data + x + y * inputPitch) / 255.0f;
-            outColor->green = 0.0f;
-            outColor->blue =  0.0f;
-            outColor->alpha = 1.0f;
-        }
-        break;
-
-      case DXGI_FORMAT_R8G8_UNORM:
-        {
-            unsigned short rg = *reinterpret_cast<const unsigned short*>(data + 2 * x + y * inputPitch);
-
-            outColor->red =   (rg & 0xFF00) * (1.0f / 0xFF00);
-            outColor->green = (rg & 0x00FF) * (1.0f / 0x00FF);
-            outColor->blue =  0.0f;
-            outColor->alpha = 1.0f;
-        }
-        break;
-
-      case DXGI_FORMAT_R16_FLOAT:
-        {
-            outColor->red =   gl::float16ToFloat32(*reinterpret_cast<const unsigned short*>(data + 2 * x + y * inputPitch));
-            outColor->green = 0.0f;
-            outColor->blue =  0.0f;
-            outColor->alpha = 1.0f;
-        }
-        break;
-
-      case DXGI_FORMAT_R16G16_FLOAT:
-        {
-            outColor->red =   gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 4 * x + y * inputPitch) + 0));
-            outColor->green = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 4 * x + y * inputPitch) + 1));
-            outColor->blue =  0.0f;
-            outColor->alpha = 1.0f;
-        }
-        break;
-
-      case DXGI_FORMAT_R10G10B10A2_UNORM:
-        {
-            unsigned int rgba = *reinterpret_cast<const unsigned int*>(data + 4 * x + y * inputPitch);
-            outColor->red =   (rgba & 0x000003FF) * (1.0f / 0x000003FF);
-            outColor->green = (rgba & 0x000FFC00) * (1.0f / 0x000FFC00);
-            outColor->blue =  (rgba & 0x3FF00000) * (1.0f / 0x3FF00000);
-            outColor->alpha = (rgba & 0xC0000000) * (1.0f / 0xC0000000);
-        }
-        break;
-
-      default:
-        ERR("ReadPixelColor not implemented for DXGI format %u.", format);
-        UNIMPLEMENTED();
-        break;
-    }
-}
-
-static inline void writePixelColor(const gl::ColorF &color, GLenum format, GLenum type, unsigned int x,
-                                   unsigned int y, int outputPitch, void *outData)
-{
-    unsigned char* byteData = reinterpret_cast<unsigned char*>(outData);
-    unsigned short* shortData = reinterpret_cast<unsigned short*>(outData);
-    unsigned int* intData = reinterpret_cast<unsigned int*>(outData);
-
-    switch (format)
-    {
-      case GL_RGBA:
-        switch (type)
-        {
-          case GL_UNSIGNED_BYTE:
-            byteData[4 * x + y * outputPitch + 0] = static_cast<unsigned char>(255 * color.red   + 0.5f);
-            byteData[4 * x + y * outputPitch + 1] = static_cast<unsigned char>(255 * color.green + 0.5f);
-            byteData[4 * x + y * outputPitch + 2] = static_cast<unsigned char>(255 * color.blue  + 0.5f);
-            byteData[4 * x + y * outputPitch + 3] = static_cast<unsigned char>(255 * color.alpha + 0.5f);
-            break;
-
-          case GL_UNSIGNED_INT_2_10_10_10_REV:
-            intData[x + y * outputPitch / sizeof(unsigned int)] = (static_cast<unsigned int>(   3 * color.alpha) << 30) |
-                                                                  (static_cast<unsigned int>(1023 * color.red  ) << 20) |
-                                                                  (static_cast<unsigned int>(1023 * color.green) << 10) |
-                                                                  (static_cast<unsigned int>(1023 * color.blue ) <<  0);
-            break;
-
-          default:
-            ERR("WritePixelColor not implemented for format GL_RGBA and type 0x%X.", type);
-            UNIMPLEMENTED();
-            break;
-        }
-        break;
-
-      case GL_BGRA_EXT:
-        switch (type)
-        {
-          case GL_UNSIGNED_BYTE:
-            byteData[4 * x + y * outputPitch + 0] = static_cast<unsigned char>(255 * color.blue  + 0.5f);
-            byteData[4 * x + y * outputPitch + 1] = static_cast<unsigned char>(255 * color.green + 0.5f);
-            byteData[4 * x + y * outputPitch + 2] = static_cast<unsigned char>(255 * color.red   + 0.5f);
-            byteData[4 * x + y * outputPitch + 3] = static_cast<unsigned char>(255 * color.alpha + 0.5f);
-            break;
-
-          case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
-            // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
-            // this type is packed as follows:
-            //   15   14   13   12   11   10    9    8    7    6    5    4    3    2    1    0
-            //  --------------------------------------------------------------------------------
-            // |       4th         |        3rd         |        2nd        |   1st component   |
-            //  --------------------------------------------------------------------------------
-            // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
-            shortData[x + y * outputPitch / sizeof(unsigned short)] =
-                (static_cast<unsigned short>(15 * color.alpha + 0.5f) << 12) |
-                (static_cast<unsigned short>(15 * color.red   + 0.5f) <<  8) |
-                (static_cast<unsigned short>(15 * color.green + 0.5f) <<  4) |
-                (static_cast<unsigned short>(15 * color.blue  + 0.5f) <<  0);
-            break;
-
-          case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
-            // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
-            // this type is packed as follows:
-            //   15   14   13   12   11   10    9    8    7    6    5    4    3    2    1    0
-            //  --------------------------------------------------------------------------------
-            // | 4th |          3rd           |           2nd          |      1st component     |
-            //  --------------------------------------------------------------------------------
-            // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
-            shortData[x + y * outputPitch / sizeof(unsigned short)] =
-                (static_cast<unsigned short>(     color.alpha + 0.5f) << 15) |
-                (static_cast<unsigned short>(31 * color.red   + 0.5f) << 10) |
-                (static_cast<unsigned short>(31 * color.green + 0.5f) <<  5) |
-                (static_cast<unsigned short>(31 * color.blue  + 0.5f) <<  0);
-            break;
-
-          default:
-            ERR("WritePixelColor not implemented for format GL_BGRA_EXT and type 0x%X.", type);
-            UNIMPLEMENTED();
-            break;
-        }
-        break;
-
-      case GL_RGB:
-        switch (type)
-        {
-          case GL_UNSIGNED_SHORT_5_6_5:
-            shortData[x + y * outputPitch / sizeof(unsigned short)] =
-                (static_cast<unsigned short>(31 * color.blue  + 0.5f) <<  0) |
-                (static_cast<unsigned short>(63 * color.green + 0.5f) <<  5) |
-                (static_cast<unsigned short>(31 * color.red   + 0.5f) << 11);
-            break;
-
-          case GL_UNSIGNED_BYTE:
-            byteData[3 * x + y * outputPitch + 0] = static_cast<unsigned char>(255 * color.red +   0.5f);
-            byteData[3 * x + y * outputPitch + 1] = static_cast<unsigned char>(255 * color.green + 0.5f);
-            byteData[3 * x + y * outputPitch + 2] = static_cast<unsigned char>(255 * color.blue +  0.5f);
-            break;
-
-          default:
-            ERR("WritePixelColor not implemented for format GL_RGB and type 0x%X.", type);
-            UNIMPLEMENTED();
-            break;
-        }
-        break;
-
-      default:
-        ERR("WritePixelColor not implemented for format 0x%X.", format);
-        UNIMPLEMENTED();
-        break;
-    }
-}
-
 void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area,
                                  GLenum format, GLenum type, GLsizei outputPitch, bool packReverseRowOrder,
                                  GLint packAlignment, void *pixels)
@@ -3816,43 +3573,65 @@
         inputPitch = static_cast<int>(mapping.RowPitch);
     }
 
-    unsigned int fastPixelSize = getFastPixelCopySize(textureDesc.Format, format, type, getCurrentClientVersion());
-    if (fastPixelSize != 0)
-    {
-        unsigned char *dest = static_cast<unsigned char*>(pixels);
-        for (int j = 0; j < area.height; j++)
-        {
-            memcpy(dest + j * outputPitch, source + j * inputPitch, area.width * fastPixelSize);
-        }
-    }
-    else if (textureDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM &&
-             format == GL_RGBA &&
-             type == GL_UNSIGNED_BYTE)
-    {
-        // Fast path for swapping red with blue
-        unsigned char *dest = static_cast<unsigned char*>(pixels);
+    GLuint clientVersion = getCurrentClientVersion();
 
-        for (int j = 0; j < area.height; j++)
+    GLint sourceInternalFormat = d3d11_gl::GetInternalFormat(textureDesc.Format);
+    GLenum sourceFormat = gl::GetFormat(sourceInternalFormat, clientVersion);
+    GLenum sourceType = gl::GetType(sourceInternalFormat, clientVersion);
+
+    GLuint sourcePixelSize = gl::GetPixelBytes(sourceInternalFormat, clientVersion);
+
+    if (sourceFormat == format && sourceType == type)
+    {
+        // Direct copy possible
+        unsigned char *dest = static_cast<unsigned char*>(pixels);
+        for (int y = 0; y < area.height; y++)
         {
-            for (int i = 0; i < area.width; i++)
-            {
-                unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
-                *(unsigned int*)(dest + 4 * i + j * outputPitch) =
-                    (argb & 0xFF00FF00) |       // Keep alpha and green
-                    (argb & 0x00FF0000) >> 16 | // Move red to blue
-                    (argb & 0x000000FF) << 16;  // Move blue to red
-            }
+            memcpy(dest + y * outputPitch, source + y * inputPitch, area.width * sourcePixelSize);
         }
     }
     else
     {
-        gl::ColorF pixelColor;
-        for (int j = 0; j < area.height; j++)
+        GLint destInternalFormat = gl::GetSizedInternalFormat(format, type, clientVersion);
+        GLuint destPixelSize = gl::GetPixelBytes(destInternalFormat, clientVersion);
+
+        ColorCopyFunction fastCopyFunc = d3d11::GetFastCopyFunction(textureDesc.Format, format, type, getCurrentClientVersion());
+        if (fastCopyFunc)
         {
-            for (int i = 0; i < area.width; i++)
+            // Fast copy is possible through some special function
+            for (int y = 0; y < area.height; y++)
             {
-                readPixelColor(source, textureDesc.Format, i, j, inputPitch, &pixelColor);
-                writePixelColor(pixelColor, format, type, i, j, outputPitch, pixels);
+                for (int x = 0; x < area.width; x++)
+                {
+                    void *dest = static_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize;
+                    void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize;
+
+                    fastCopyFunc(src, dest);
+                }
+            }
+        }
+        else
+        {
+            ColorReadFunction readFunc = d3d11::GetColorReadFunction(textureDesc.Format);
+            ColorWriteFunction writeFunc = gl::GetColorWriteFunction(format, type, clientVersion);
+
+            unsigned char temp[16]; // Maximum size of any Color<T> type used.
+            META_ASSERT(sizeof(temp) >= sizeof(gl::ColorF)  &&
+                        sizeof(temp) >= sizeof(gl::ColorUI) &&
+                        sizeof(temp) >= sizeof(gl::ColorI));
+
+            for (int y = 0; y < area.height; y++)
+            {
+                for (int x = 0; x < area.width; x++)
+                {
+                    void *dest = static_cast<unsigned char*>(pixels) + y * outputPitch + x * destPixelSize;
+                    void *src = static_cast<unsigned char*>(source) + y * inputPitch + x * sourcePixelSize;
+
+                    // readFunc and writeFunc will be using the same type of color, CopyTexImage
+                    // will not allow the copy otherwise.
+                    readFunc(src, temp);
+                    writeFunc(temp, dest);
+                }
             }
         }
     }