Add support for the "fast path" (GPU copy) pixel unpack buffers in TexImage2D.

TRAC #23844

Signed-off-by: Geoff Lang
Signed-off-by: Shannon Woods
diff --git a/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp b/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp
index 7397dbe..e4f7c78 100644
--- a/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp
+++ b/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp
@@ -10,6 +10,7 @@
 #include "libGLESv2/renderer/d3d11/BufferStorage11.h"
 #include "libGLESv2/main.h"
 #include "libGLESv2/renderer/d3d11/Renderer11.h"
+#include "libGLESv2/renderer/d3d11/formatutils11.h"
 
 namespace rx
 {
@@ -268,7 +269,38 @@
 
 ID3D11ShaderResourceView *BufferStorage11::getSRV(DXGI_FORMAT srvFormat)
 {
-    return NULL;
+    ID3D11Buffer *buffer = getBuffer(false);
+
+    auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
+
+    if (bufferSRVIt != mBufferResourceViews.end())
+    {
+        if (bufferSRVIt->second.first == buffer)
+        {
+            return bufferSRVIt->second.second;
+        }
+        else
+        {
+            // The underlying buffer has changed since the SRV was created: recreate the SRV.
+            SafeRelease(bufferSRVIt->second.second);
+        }
+    }
+
+    ID3D11Device *device = mRenderer->getDevice();
+    ID3D11ShaderResourceView *bufferSRV = NULL;
+
+    D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc;
+    bufferSRVDesc.Buffer.ElementOffset = 0;
+    bufferSRVDesc.Buffer.ElementWidth = mSize / d3d11::GetFormatPixelBytes(srvFormat, mRenderer->getCurrentClientVersion());
+    bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+    bufferSRVDesc.Format = srvFormat;
+
+    HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV);
+    ASSERT(SUCCEEDED(result));
+
+    mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV);
+
+    return bufferSRV;
 }
 
 DirectBufferStorage11::DirectBufferStorage11(Renderer11 *renderer, bool isConstantBufferUsage)
@@ -352,7 +384,7 @@
     if (!mIsConstantBufferUsage)
     {
         bufferDesc->Usage = D3D11_USAGE_DEFAULT;
-        bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER;
+        bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_SHADER_RESOURCE;
         bufferDesc->CPUAccessFlags = 0;
     }
     else
diff --git a/src/libGLESv2/renderer/d3d11/BufferStorage11.h b/src/libGLESv2/renderer/d3d11/BufferStorage11.h
index ee76c4a..689e413 100644
--- a/src/libGLESv2/renderer/d3d11/BufferStorage11.h
+++ b/src/libGLESv2/renderer/d3d11/BufferStorage11.h
@@ -42,6 +42,10 @@
     unsigned int mStagingBufferSize;
 
     std::vector<DirectBufferStorage11*> mDirectBuffers;
+
+    typedef std::pair<ID3D11Buffer *, ID3D11ShaderResourceView *> BufferSRVPair;
+    std::map<DXGI_FORMAT, BufferSRVPair> mBufferResourceViews;
+
     unsigned int mSize;
 
     void *mResolvedData;
diff --git a/src/libGLESv2/renderer/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
index 18ba51f..e9e13b3 100644
--- a/src/libGLESv2/renderer/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
@@ -2769,8 +2769,39 @@
 
 bool Renderer11::supportsFastCopyBufferToTexture(GLint internalFormat) const
 {
-    //TODO
-    return false;
+    int clientVersion = getCurrentClientVersion();
+
+    // We only support buffer to texture copies in ES3
+    if (clientVersion <= 2)
+    {
+        return false;
+    }
+
+    // sRGB formats do not work with D3D11 buffer SRVs
+    if (gl::GetColorEncoding(internalFormat, clientVersion) == GL_SRGB)
+    {
+        return false;
+    }
+
+    // We cannot support direct copies to non-color-renderable formats
+    if (!gl::IsColorRenderingSupported(internalFormat, this))
+    {
+        return false;
+    }
+
+    // We skip all 3-channel formats since sometimes format support is missing
+    if (gl::GetComponentCount(internalFormat, clientVersion) == 3)
+    {
+        return false;
+    }
+
+    // We don't support formats which we can't represent without conversion
+    if (getNativeTextureFormat(internalFormat) != internalFormat)
+    {
+        return false;
+    }
+
+    return true;
 }
 
 bool Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget,