Support compressed textures with unpack buffers.

BUG=angle:792

Change-Id: I32f32422232bd4cb04c8a70005cb51482224bf3e
Reviewed-on: https://chromium-review.googlesource.com/224655
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libGLESv2/renderer/d3d/TextureD3D.cpp b/src/libGLESv2/renderer/d3d/TextureD3D.cpp
index 42fea65..51593b3 100644
--- a/src/libGLESv2/renderer/d3d/TextureD3D.cpp
+++ b/src/libGLESv2/renderer/d3d/TextureD3D.cpp
@@ -26,11 +26,43 @@
 namespace rx
 {
 
+namespace
+{
+
+gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const void *pixels, const uint8_t **pointerOut)
+{
+    if (unpack.pixelBuffer.id() != 0)
+    {
+        // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
+        gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
+        ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
+
+        // TODO: this is the only place outside of renderer that asks for a buffers raw data.
+        // This functionality should be moved into renderer and the getData method of BufferImpl removed.
+        const uint8_t *bufferData = NULL;
+        gl::Error error = pixelBuffer->getImplementation()->getData(&bufferData);
+        if (error.isError())
+        {
+            return error;
+        }
+
+        *pointerOut = bufferData + offset;
+    }
+    else
+    {
+        *pointerOut = static_cast<const uint8_t *>(pixels);
+    }
+
+    return gl::Error(GL_NO_ERROR);
+}
+
 bool IsRenderTargetUsage(GLenum usage)
 {
     return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
 }
 
+}
+
 TextureD3D::TextureD3D(Renderer *renderer)
     : mRenderer(renderer),
       mUsage(GL_NONE),
@@ -124,25 +156,10 @@
     // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
     // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
     const uint8_t *pixelData = NULL;
-
-    if (unpack.pixelBuffer.id() != 0)
+    gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
+    if (error.isError())
     {
-        // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
-        gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
-        ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
-        // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
-        // This functionality should be moved into renderer and the getData method of BufferImpl removed.
-        const uint8_t *bufferData = NULL;
-        gl::Error error = pixelBuffer->getImplementation()->getData(&bufferData);
-        if (error.isError())
-        {
-            return error;
-        }
-        pixelData = bufferData + offset;
-    }
-    else
-    {
-        pixelData = static_cast<const uint8_t *>(pixels);
+        return error;
     }
 
     if (pixelData != NULL)
@@ -172,22 +189,12 @@
 gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
 {
-    const uint8_t *pixelData = static_cast<const uint8_t *>(pixels);
-
     // CPU readback & copy where direct GPU copy is not supported
-    if (unpack.pixelBuffer.id() != 0)
+    const uint8_t *pixelData = NULL;
+    gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
+    if (error.isError())
     {
-        gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
-        uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
-        // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
-        // This functionality should be moved into renderer and the getData method of BufferImpl removed.
-        const uint8_t *bufferData = NULL;
-        gl::Error error = pixelBuffer->getImplementation()->getData(&bufferData);
-        if (error.isError())
-        {
-            return error;
-        }
-        pixelData = bufferData + offset;
+        return error;
     }
 
     if (pixelData != NULL)
@@ -220,11 +227,20 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
+gl::Error TextureD3D::setCompressedImage(const gl::PixelUnpackState &unpack, GLsizei imageSize, const void *pixels, Image *image)
 {
-    if (pixels != NULL)
+    // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
+    // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
+    const uint8_t *pixelData = NULL;
+    gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
+    if (error.isError())
     {
-        gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
+        return error;
+    }
+
+    if (pixelData != NULL)
+    {
+        gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixelData);
         if (error.isError())
         {
             return error;
@@ -237,11 +253,18 @@
 }
 
 gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
-                                 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
+                                         GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels, Image *image)
 {
-    if (pixels != NULL)
+    const uint8_t *pixelData = NULL;
+    gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
+    if (error.isError())
     {
-        gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
+        return error;
+    }
+
+    if (pixelData != NULL)
+    {
+        gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixelData);
         if (error.isError())
         {
             return error;
@@ -600,14 +623,14 @@
 
 gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
                                             GLsizei width, GLsizei height, GLsizei depth,
-                                            GLsizei imageSize, const void *pixels)
+                                            GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(target == GL_TEXTURE_2D && depth == 1);
 
     // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
     redefineImage(level, format, width, height);
 
-    return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
+    return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
 }
 
 gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
@@ -652,11 +675,11 @@
 
 gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                             GLsizei width, GLsizei height, GLsizei depth, GLenum format,
-                                            GLsizei imageSize, const void *pixels)
+                                            GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
 
-    gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
+    gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[level]);
     if (error.isError())
     {
         return error;
@@ -1157,7 +1180,7 @@
 
 gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
                                               GLsizei width, GLsizei height, GLsizei depth,
-                                              GLsizei imageSize, const void *pixels)
+                                              GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(depth == 1);
 
@@ -1166,7 +1189,7 @@
 
     redefineImage(faceIndex, level, format, width, height);
 
-    return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
+    return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[faceIndex][level]);
 }
 
 gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
@@ -1180,13 +1203,13 @@
 
 gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                               GLsizei width, GLsizei height, GLsizei depth, GLenum format,
-                                              GLsizei imageSize, const void *pixels)
+                                              GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(depth == 1 && zoffset == 0);
 
     gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
 
-    gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[index.layerIndex][level]);
+    gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[index.layerIndex][level]);
     if (error.isError())
     {
         return error;
@@ -1758,14 +1781,14 @@
 
 gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
                                             GLsizei width, GLsizei height,GLsizei depth,
-                                            GLsizei imageSize, const void *pixels)
+                                            GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(target == GL_TEXTURE_3D);
 
     // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
     redefineImage(level, format, width, height, depth);
 
-    return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
+    return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
 }
 
 gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
@@ -1812,12 +1835,12 @@
 
 gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                             GLsizei width, GLsizei height, GLsizei depth, GLenum format,
-                                            GLsizei imageSize, const void *pixels)
+                                            GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(target == GL_TEXTURE_3D);
 
     gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
-                                                     format, imageSize, pixels, mImageArray[level]);
+                                                     format, imageSize, unpack, pixels, mImageArray[level]);
     if (error.isError())
     {
         return error;
@@ -2279,7 +2302,7 @@
 
 gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
                                                  GLsizei width, GLsizei height, GLsizei depth,
-                                                 GLsizei imageSize, const void *pixels)
+                                                 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(target == GL_TEXTURE_2D_ARRAY);
 
@@ -2292,7 +2315,7 @@
     for (int i = 0; i < depth; i++)
     {
         const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
-        gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
+        gl::Error error = TextureD3D::setCompressedImage(unpack, imageSize, layerPixels, mImageArray[level][i]);
         if (error.isError())
         {
             return error;
@@ -2330,7 +2353,7 @@
 
 gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                                  GLsizei width, GLsizei height, GLsizei depth, GLenum format,
-                                                 GLsizei imageSize, const void *pixels)
+                                                 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(target == GL_TEXTURE_2D_ARRAY);
 
@@ -2342,7 +2365,7 @@
         int layer = zoffset + i;
         const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
 
-        gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
+        gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, unpack, layerPixels, mImageArray[level][layer]);
         if (error.isError())
         {
             return error;