Refactor the fast path for pixel unpack buffers, and fix a few validation gaps with texture completeness.

TRAC #23997

Signed-off-by: Geoff Lang
Signed-off-by: Shannon Woods
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index dc2e2d1..3b56717 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -223,8 +223,13 @@
     }
 }
 
+bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLint sizedInternalFormat)
+{
+    return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
+}
+
 bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
-                               GLenum sizedInternalFormat, GLenum type, GLint level)
+                               GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
 {
     if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
     {
@@ -233,16 +238,11 @@
 
     // In order to perform the fast copy through the shader, we must have the right format, and be able
     // to create a render target.
-    if (mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat))
-    {
-        unsigned int offset = reinterpret_cast<unsigned int>(pixels);
-        rx::RenderTarget *destRenderTarget = getStorage(true)->getStorageInstance()->getRenderTarget(level);
+    ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
 
-        return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
-    }
+    unsigned int offset = reinterpret_cast<unsigned int>(pixels);
 
-    // Return false if we do not support fast unpack
-    return false;
+    return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
 }
 
 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
@@ -435,15 +435,25 @@
                                                                                      : GetSizedInternalFormat(format, type, clientVersion);
     redefineImage(level, sizedInternalFormat, width, height);
 
+    bool fastUnpacked = false;
+
     // Attempt a fast gpu copy of the pixel data to the surface
-    //   If we want to support rendering (which is necessary for GPU unpack buffers), level 0 must be complete
-    Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
-    if (unpack.pixelBuffer.id() != 0 && isLevelComplete(0) && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, level))
+    if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
     {
-        // Ensure we don't overwrite our newly initialized data
-        mImageArray[level]->markClean();
+        // Will try to create RT storage if it does not exist
+        rx::RenderTarget *destRenderTarget = getRenderTarget(level);
+        Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
+
+        if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
+        {
+            // Ensure we don't overwrite our newly initialized data
+            mImageArray[level]->markClean();
+
+            fastUnpacked = true;
+        }
     }
-    else
+
+    if (!fastUnpacked)
     {
         Texture::setImage(unpack, type, pixels, mImageArray[level]);
     }
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
index 34dfe52..b7e51e9 100644
--- a/src/libGLESv2/Texture.h
+++ b/src/libGLESv2/Texture.h
@@ -118,8 +118,9 @@
     void setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image);
     bool subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                             GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image);
+    bool isFastUnpackable(const PixelUnpackState &unpack, GLint sizedInternalFormat);
     bool fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
-                          GLenum sizedInternalFormat, GLenum type, GLint level);
+                          GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget);
 
     GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const;
     GLint creationLevels(GLsizei width, GLsizei height) const;