Add more D3D11 buffer usages.

Works around performance regressions when index and vertex buffer bind flags are used on the same buffer.

Change-Id: I28bc0d3147c6bd70cec507f20e41d97ec4cc45a5
Reviewed-on: https://chromium-review.googlesource.com/181911
Tested-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
diff --git a/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp b/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp
index 839905b..e6798ee 100644
--- a/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp
+++ b/src/libGLESv2/renderer/d3d11/BufferStorage11.cpp
@@ -42,9 +42,9 @@
         mResolvedData = NULL;
     }
 
-    for (size_t bufferIndex = 0; bufferIndex < mDirectBuffers.size(); bufferIndex++)
+    for (auto it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
     {
-        SafeDelete(mDirectBuffers[bufferIndex]);
+        SafeDelete(it->second);
     }
 }
 
@@ -170,9 +170,9 @@
         context->Unmap(mStagingBuffer, 0);
     }
 
-    for (size_t bufferIndex = 0; bufferIndex < mDirectBuffers.size(); bufferIndex++)
+    for (auto it = mDirectBuffers.begin(); it != mDirectBuffers.end(); it++)
     {
-        mDirectBuffers[bufferIndex]->markDirty();
+        it->second->markDirty();
     }
 
     mSize = std::max(mSize, requiredStagingBufferSize);
@@ -234,42 +234,45 @@
     }
 }
 
-ID3D11Buffer *BufferStorage11::getBuffer(bool isConstantBufferUsage)
+ID3D11Buffer *BufferStorage11::getBuffer(BufferUsage usage)
 {
     markBufferUsage();
 
-    for (size_t bufferIndex = 0; bufferIndex < mDirectBuffers.size(); bufferIndex++)
+    DirectBufferStorage11 *directBuffer = NULL;
+    auto directBufferIt = mDirectBuffers.find(usage);
+    if (directBufferIt != mDirectBuffers.end())
     {
-        DirectBufferStorage11 *directBuffer = mDirectBuffers[bufferIndex];
-
-        if (directBuffer->isConstantBufferUsage() == isConstantBufferUsage)
-        {
-            if (directBuffer->isDirty())
-            {
-                // if updateFromStagingBuffer returns true, the D3D buffer has been recreated
-                // and we should update our serial
-                if (directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0))
-                {
-                    updateSerial();
-                }
-            }
-            return directBuffer->getD3DBuffer();
-        }
+        directBuffer = directBufferIt->second;
     }
 
-    // buffer is not allocated, create it
-    DirectBufferStorage11 *directBuffer = new DirectBufferStorage11(mRenderer, isConstantBufferUsage);
-    directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0);
+    if (directBuffer)
+    {
+        if (directBuffer->isDirty())
+        {
+            // if updateFromStagingBuffer returns true, the D3D buffer has been recreated
+            // and we should update our serial
+            if (directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0))
+            {
+                updateSerial();
+            }
+        }
+    }
+    else
+    {
+        // buffer is not allocated, create it
+        directBuffer = new DirectBufferStorage11(mRenderer, usage);
+        directBuffer->updateFromStagingBuffer(mStagingBuffer, mSize, 0);
 
-    mDirectBuffers.push_back(directBuffer);
-    updateSerial();
+        mDirectBuffers.insert(std::make_pair(usage, directBuffer));
+        updateSerial();
+    }
 
     return directBuffer->getD3DBuffer();
 }
 
 ID3D11ShaderResourceView *BufferStorage11::getSRV(DXGI_FORMAT srvFormat)
 {
-    ID3D11Buffer *buffer = getBuffer(false);
+    ID3D11Buffer *buffer = getBuffer(BUFFER_USAGE_PIXEL);
 
     auto bufferSRVIt = mBufferResourceViews.find(srvFormat);
 
@@ -303,9 +306,9 @@
     return bufferSRV;
 }
 
-DirectBufferStorage11::DirectBufferStorage11(Renderer11 *renderer, bool isConstantBufferUsage)
+DirectBufferStorage11::DirectBufferStorage11(Renderer11 *renderer, BufferUsage usage)
     : mRenderer(renderer),
-      mIsConstantBufferUsage(isConstantBufferUsage),
+      mUsage(usage),
       mDirectBuffer(NULL),
       mBufferSize(0),
       mDirty(false)
@@ -317,9 +320,9 @@
     SafeRelease(mDirectBuffer);
 }
 
-bool DirectBufferStorage11::isConstantBufferUsage() const
+BufferUsage DirectBufferStorage11::getUsage() const
 {
-    return mIsConstantBufferUsage;
+    return mUsage;
 }
 
 // Returns true if it recreates the direct buffer
@@ -338,7 +341,7 @@
     if (createBuffer)
     {
         D3D11_BUFFER_DESC bufferDesc;
-        fillBufferDesc(&bufferDesc, requiredBufferSize);
+        fillBufferDesc(&bufferDesc, mRenderer, mUsage, requiredBufferSize);
 
         ID3D11Buffer *newBuffer;
         HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
@@ -371,20 +374,33 @@
     return createBuffer;
 }
 
-void DirectBufferStorage11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, unsigned int bufferSize)
+void DirectBufferStorage11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize)
 {
     bufferDesc->ByteWidth = bufferSize;
     bufferDesc->MiscFlags = 0;
     bufferDesc->StructureByteStride = 0;
 
-    if (!mIsConstantBufferUsage)
+    switch (usage)
     {
+      case BUFFER_USAGE_VERTEX:
         bufferDesc->Usage = D3D11_USAGE_DEFAULT;
-        bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_SHADER_RESOURCE;
+        bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER;
         bufferDesc->CPUAccessFlags = 0;
-    }
-    else
-    {
+        break;
+
+      case BUFFER_USAGE_INDEX:
+        bufferDesc->Usage = D3D11_USAGE_DEFAULT;
+        bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER;
+        bufferDesc->CPUAccessFlags = 0;
+        break;
+
+      case BUFFER_USAGE_PIXEL:
+        bufferDesc->Usage = D3D11_USAGE_DEFAULT;
+        bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE;
+        bufferDesc->CPUAccessFlags = 0;
+        break;
+
+      case BUFFER_USAGE_UNIFORM:
         bufferDesc->Usage = D3D11_USAGE_DYNAMIC;
         bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER;
         bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
@@ -392,7 +408,11 @@
         // Constant buffers must be of a limited size, and aligned to 16 byte boundaries
         // For our purposes we ignore any buffer data past the maximum constant buffer size
         bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u);
-        bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, mRenderer->getMaxUniformBufferSize());
+        bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, renderer->getMaxUniformBufferSize());
+        break;
+
+    default:
+        UNREACHABLE();
     }
 }
 
diff --git a/src/libGLESv2/renderer/d3d11/BufferStorage11.h b/src/libGLESv2/renderer/d3d11/BufferStorage11.h
index 689e413..be6a00c 100644
--- a/src/libGLESv2/renderer/d3d11/BufferStorage11.h
+++ b/src/libGLESv2/renderer/d3d11/BufferStorage11.h
@@ -13,9 +13,18 @@
 
 namespace rx
 {
+class Renderer;
 class Renderer11;
 class DirectBufferStorage11;
 
+enum BufferUsage
+{
+    BUFFER_USAGE_VERTEX,
+    BUFFER_USAGE_INDEX,
+    BUFFER_USAGE_PIXEL,
+    BUFFER_USAGE_UNIFORM,
+};
+
 class BufferStorage11 : public BufferStorage
 {
   public:
@@ -32,7 +41,7 @@
     virtual unsigned int getSize() const;
     virtual bool supportsDirectBinding() const;
 
-    ID3D11Buffer *getBuffer(bool isConstantBufferUsage);
+    ID3D11Buffer *getBuffer(BufferUsage usage);
     ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat);
 
   private:
@@ -41,7 +50,7 @@
     ID3D11Buffer *mStagingBuffer;
     unsigned int mStagingBufferSize;
 
-    std::vector<DirectBufferStorage11*> mDirectBuffers;
+    std::map<BufferUsage, DirectBufferStorage11*> mDirectBuffers;
 
     typedef std::pair<ID3D11Buffer *, ID3D11ShaderResourceView *> BufferSRVPair;
     std::map<DXGI_FORMAT, BufferSRVPair> mBufferResourceViews;
@@ -65,10 +74,10 @@
 class DirectBufferStorage11
 {
   public:
-    DirectBufferStorage11(Renderer11 *renderer, bool isConstantBufferUsage);
+    DirectBufferStorage11(Renderer11 *renderer, BufferUsage usage);
     ~DirectBufferStorage11();
 
-    bool isConstantBufferUsage() const;
+    BufferUsage getUsage() const;
     bool updateFromStagingBuffer(ID3D11Buffer *stagingBuffer, size_t size, size_t offset);
 
     ID3D11Buffer *getD3DBuffer() { return mDirectBuffer; }
@@ -77,12 +86,12 @@
 
   private:
     Renderer11 *mRenderer;
-    const bool mIsConstantBufferUsage;
+    const BufferUsage mUsage;
     ID3D11Buffer *mDirectBuffer;
     size_t mBufferSize;
     bool mDirty;
 
-    void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, unsigned int bufferSize);
+    static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize);
 };
 
 }
diff --git a/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp b/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp
index 5e9ac56..75f74d6 100644
--- a/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp
+++ b/src/libGLESv2/renderer/d3d11/InputLayoutCache.cpp
@@ -117,7 +117,7 @@
             ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor;
             ilKey.elementCount++;
 
-            vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer(false) : vertexBuffer->getBuffer();
+            vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX) : vertexBuffer->getBuffer();
             vertexBufferSerials[i] = bufferStorage ? bufferStorage->getSerial() : vertexBuffer->getSerial();
             vertexStrides[i] = attributes[i].stride;
             vertexOffsets[i] = attributes[i].offset;
diff --git a/src/libGLESv2/renderer/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
index 28a7ae6..72fbe0e 100644
--- a/src/libGLESv2/renderer/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d11/Renderer11.cpp
@@ -658,7 +658,7 @@
         if (uniformBuffer)
         {
             BufferStorage11 *bufferStorage = BufferStorage11::makeBufferStorage11(uniformBuffer->getStorage());
-            ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(true);
+            ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM);
 
             if (!constantBuffer)
             {
@@ -680,7 +680,7 @@
         if (uniformBuffer)
         {
             BufferStorage11 *bufferStorage = BufferStorage11::makeBufferStorage11(uniformBuffer->getStorage());
-            ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(true);
+            ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM);
 
             if (!constantBuffer)
             {
@@ -1114,7 +1114,7 @@
                 BufferStorage11 *storage = BufferStorage11::makeBufferStorage11(indexInfo->storage);
                 IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer);
 
-                mDeviceContext->IASetIndexBuffer(storage->getBuffer(false), indexBuffer->getIndexFormat(), indexInfo->startOffset);
+                mDeviceContext->IASetIndexBuffer(storage->getBuffer(BUFFER_USAGE_INDEX), indexBuffer->getIndexFormat(), indexInfo->startOffset);
 
                 mAppliedIBSerial = 0;
                 mAppliedStorageIBSerial = storage->getSerial();