Enable unpack buffer support for initializing 2D textures in TexImage2D.

TRAC #23843

Signed-off-by: Geoff Lang
Signed-off-by: Shannon Woods
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
index 9bfde17..fe213e8 100644
--- a/src/libGLESv2/Texture.cpp
+++ b/src/libGLESv2/Texture.cpp
@@ -21,6 +21,8 @@
 #include "libGLESv2/renderer/Renderer.h"
 #include "libGLESv2/renderer/TextureStorage.h"
 #include "libEGL/Surface.h"
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/renderer/BufferStorage.h"
 
 namespace gl
 {
@@ -273,13 +275,46 @@
 {
     // 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.
-    if (pixels != NULL)
+    const void *pixelData = pixels;
+
+    if (unpack.pixelBuffer.id() != 0)
     {
-        image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixels);
+        // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
+        Buffer *pixelBuffer = unpack.pixelBuffer.get();
+        ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
+        const void *bufferData = pixelBuffer->getStorage()->getData();
+        pixelData = static_cast<const unsigned char *>(bufferData) + offset;
+    }
+
+    if (pixelData != NULL)
+    {
+        image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
         mDirtyImages = true;
     }
 }
 
+bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
+                               GLenum sizedInternalFormat, GLenum type, GLint level)
+{
+    if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
+    {
+        return true;
+    }
+
+    // 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 (IsFastCopyBufferToTextureSupported(sizedInternalFormat, mRenderer->getCurrentClientVersion()))
+    {
+        unsigned int offset = reinterpret_cast<unsigned int>(pixels);
+        rx::RenderTarget *destRenderTarget = getStorage(true)->getStorageInstance()->getRenderTarget(level);
+
+        return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
+    }
+
+    // Return false if we do not support fast unpack
+    return false;
+}
+
 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
 {
     if (pixels != NULL)
@@ -470,7 +505,18 @@
                                                                                      : GetSizedInternalFormat(format, type, clientVersion);
     redefineImage(level, sizedInternalFormat, width, height);
 
-    Texture::setImage(unpack, type, pixels, mImageArray[level]);
+    // 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))
+    {
+        // Ensure we don't overwrite our newly initialized data
+        mImageArray[level]->markClean();
+    }
+    else
+    {
+        Texture::setImage(unpack, type, pixels, mImageArray[level]);
+    }
 }
 
 void Texture2D::bindTexImage(egl::Surface *surface)
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
index 345b60d..2d729f6 100644
--- a/src/libGLESv2/Texture.h
+++ b/src/libGLESv2/Texture.h
@@ -113,6 +113,8 @@
     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 fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
+                          GLenum sizedInternalFormat, GLenum type, GLint level);
 
     GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const;
     GLint creationLevels(GLsizei width, GLsizei height) const;