ES31: Support shader storage buffer in D3D-API side.

Bug: angleproject:1951
Test: angle_end2end_tests

Change-Id: I0d8a4f8cf00fc7fd2d85315138e2b7457fd0b90c
Reviewed-on: https://chromium-review.googlesource.com/1242846
Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 13f2910..62e0431 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -815,6 +815,24 @@
     mUsedComputeReadonlyImageRange =
         gl::RangeUI(computeReadonlyImageRangeLow, computeReadonlyImageRangeHigh);
 
+    const unsigned int shaderStorageBlockCount = stream->readInt<unsigned int>();
+    if (stream->error())
+    {
+        infoLog << "Invalid program binary.";
+        return false;
+    }
+
+    ASSERT(mD3DShaderStorageBlocks.empty());
+    for (unsigned int blockIndex = 0; blockIndex < shaderStorageBlockCount; ++blockIndex)
+    {
+        D3DInterfaceBlock shaderStorageBlock;
+        for (gl::ShaderType shaderType : gl::AllShaderTypes())
+        {
+            stream->readInt(&shaderStorageBlock.mShaderRegisterIndexes[shaderType]);
+        }
+        mD3DShaderStorageBlocks.push_back(shaderStorageBlock);
+    }
+
     const unsigned int uniformCount = stream->readInt<unsigned int>();
     if (stream->error())
     {
@@ -852,7 +870,7 @@
     ASSERT(mD3DUniformBlocks.empty());
     for (unsigned int blockIndex = 0; blockIndex < blockCount; ++blockIndex)
     {
-        D3DUniformBlock uniformBlock;
+        D3DInterfaceBlock uniformBlock;
         for (gl::ShaderType shaderType : gl::AllShaderTypes())
         {
             stream->readInt(&uniformBlock.mShaderRegisterIndexes[shaderType]);
@@ -1072,6 +1090,15 @@
     stream->writeInt(mUsedComputeReadonlyImageRange.low());
     stream->writeInt(mUsedComputeReadonlyImageRange.high());
 
+    stream->writeInt(mD3DShaderStorageBlocks.size());
+    for (const D3DInterfaceBlock &shaderStorageBlock : mD3DShaderStorageBlocks)
+    {
+        for (gl::ShaderType shaderType : gl::AllShaderTypes())
+        {
+            stream->writeIntOrNegOne(shaderStorageBlock.mShaderRegisterIndexes[shaderType]);
+        }
+    }
+
     stream->writeInt(mD3DUniforms.size());
     for (const D3DUniform *uniform : mD3DUniforms)
     {
@@ -1086,7 +1113,7 @@
     }
 
     stream->writeInt(mD3DUniformBlocks.size());
-    for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks)
+    for (const D3DInterfaceBlock &uniformBlock : mD3DUniformBlocks)
     {
         for (gl::ShaderType shaderType : gl::AllShaderTypes())
         {
@@ -1719,6 +1746,45 @@
     return GL_TRUE;
 }
 
+void ProgramD3D::initializeShaderStorageBlocks()
+{
+    if (mState.getShaderStorageBlocks().empty())
+    {
+        return;
+    }
+
+    ASSERT(mD3DShaderStorageBlocks.empty());
+
+    // Assign registers and update sizes.
+    gl::ShaderMap<const ShaderD3D *> shadersD3D = {};
+    for (gl::ShaderType shaderType : gl::AllShaderTypes())
+    {
+        shadersD3D[shaderType] = SafeGetImplAs<ShaderD3D>(mState.getAttachedShader(shaderType));
+    }
+
+    for (const gl::InterfaceBlock &shaderStorageBlock : mState.getShaderStorageBlocks())
+    {
+        unsigned int shaderStorageBlockElement =
+            shaderStorageBlock.isArray ? shaderStorageBlock.arrayElement : 0;
+
+        D3DInterfaceBlock d3dShaderStorageBlock;
+
+        for (gl::ShaderType shaderType : gl::AllShaderTypes())
+        {
+            if (shaderStorageBlock.isActive(shaderType))
+            {
+                ASSERT(shadersD3D[shaderType]);
+                unsigned int baseRegister =
+                    shadersD3D[shaderType]->getShaderStorageBlockRegister(shaderStorageBlock.name);
+                d3dShaderStorageBlock.mShaderRegisterIndexes[shaderType] =
+                    baseRegister + shaderStorageBlockElement;
+            }
+        }
+
+        mD3DShaderStorageBlocks.push_back(d3dShaderStorageBlock);
+    }
+}
+
 void ProgramD3D::initializeUniformBlocks()
 {
     if (mState.getUniformBlocks().empty())
@@ -1739,7 +1805,7 @@
     {
         unsigned int uniformBlockElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0;
 
-        D3DUniformBlock d3dUniformBlock;
+        D3DInterfaceBlock d3dUniformBlock;
 
         for (gl::ShaderType shaderType : gl::AllShaderTypes())
         {
@@ -1826,7 +1892,7 @@
     for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mD3DUniformBlocks.size();
          uniformBlockIndex++)
     {
-        const D3DUniformBlock &uniformBlock = mD3DUniformBlocks[uniformBlockIndex];
+        const D3DInterfaceBlock &uniformBlock = mD3DUniformBlocks[uniformBlockIndex];
         GLuint blockBinding                 = mState.getUniformBlockBinding(uniformBlockIndex);
 
         // Unnecessary to apply an unreferenced standard or shared UBO
@@ -1853,6 +1919,12 @@
     }
 }
 
+unsigned int ProgramD3D::getShaderStorageBufferRegisterIndex(GLuint blockIndex,
+                                                             gl::ShaderType shaderType) const
+{
+    return mD3DShaderStorageBlocks[blockIndex].mShaderRegisterIndexes[shaderType];
+}
+
 const std::vector<GLint> &ProgramD3D::getShaderUniformBufferCache(gl::ShaderType shaderType) const
 {
     return mShaderUBOCaches[shaderType];
@@ -2561,6 +2633,7 @@
 
     SafeDeleteContainer(mD3DUniforms);
     mD3DUniformBlocks.clear();
+    mD3DShaderStorageBlocks.clear();
 
     for (gl::ShaderType shaderType : gl::AllShaderTypes())
     {
@@ -2880,6 +2953,7 @@
 
     resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
                                                   getShaderStorageBlockMemberInfo);
+    initializeShaderStorageBlocks();
 }
 
 }  // namespace rx
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index c7e3b37..7a4b4c4 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -82,9 +82,9 @@
     std::vector<GLint> mSamplerData;
 };
 
-struct D3DUniformBlock
+struct D3DInterfaceBlock
 {
-    D3DUniformBlock() { mShaderRegisterIndexes.fill(GL_INVALID_INDEX); }
+    D3DInterfaceBlock() { mShaderRegisterIndexes.fill(GL_INVALID_INDEX); }
 
     bool activeInShader(gl::ShaderType shaderType) const
     {
@@ -208,6 +208,9 @@
 
     void updateUniformBufferCache(const gl::Caps &caps,
                                   const gl::ShaderMap<unsigned int> &reservedShaderRegisterIndexes);
+
+    unsigned int getShaderStorageBufferRegisterIndex(GLuint blockIndex,
+                                                     gl::ShaderType shaderType) const;
     const std::vector<GLint> &getShaderUniformBufferCache(gl::ShaderType shaderType) const;
 
     void dirtyAllUniforms();
@@ -464,6 +467,7 @@
 
     void reset();
     void initializeUniformBlocks();
+    void initializeShaderStorageBlocks();
 
     void updateCachedInputLayoutFromShader();
     void updateCachedOutputLayoutFromShader();
@@ -524,7 +528,8 @@
     std::vector<D3DVarying> mStreamOutVaryings;
     std::vector<D3DUniform *> mD3DUniforms;
     std::map<std::string, int> mImageBindingMap;
-    std::vector<D3DUniformBlock> mD3DUniformBlocks;
+    std::vector<D3DInterfaceBlock> mD3DUniformBlocks;
+    std::vector<D3DInterfaceBlock> mD3DShaderStorageBlocks;
 
     gl::ShaderBitSet mShaderUniformsDirty;
 
diff --git a/src/libANGLE/renderer/d3d/ShaderD3D.cpp b/src/libANGLE/renderer/d3d/ShaderD3D.cpp
index ff50019..5672829 100644
--- a/src/libANGLE/renderer/d3d/ShaderD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ShaderD3D.cpp
@@ -132,6 +132,12 @@
     return mUniformBlockRegisterMap.find(blockName)->second;
 }
 
+unsigned int ShaderD3D::getShaderStorageBlockRegister(const std::string &blockName) const
+{
+    ASSERT(mShaderStorageBlockRegisterMap.count(blockName) > 0);
+    return mShaderStorageBlockRegisterMap.find(blockName)->second;
+}
+
 ShShaderOutput ShaderD3D::getCompilerOutputType() const
 {
     return mCompilerOutputType;
@@ -216,6 +222,19 @@
         }
     }
 
+    for (const sh::InterfaceBlock &interfaceBlock : mData.getShaderStorageBlocks())
+    {
+        if (interfaceBlock.active)
+        {
+            unsigned int index = static_cast<unsigned int>(-1);
+            bool blockRegisterResult =
+                sh::GetShaderStorageBlockRegister(compilerHandle, interfaceBlock.name, &index);
+            ASSERT(blockRegisterResult);
+
+            mShaderStorageBlockRegisterMap[interfaceBlock.name] = index;
+        }
+    }
+
     mDebugInfo +=
         std::string("// ") + gl::GetShaderTypeString(mData.getShaderType()) + " SHADER BEGIN\n";
     mDebugInfo += "\n// GLSL BEGIN\n\n" + mData.getSource() + "\n\n// GLSL END\n\n\n";
diff --git a/src/libANGLE/renderer/d3d/ShaderD3D.h b/src/libANGLE/renderer/d3d/ShaderD3D.h
index 2e357e3..fab0f10 100644
--- a/src/libANGLE/renderer/d3d/ShaderD3D.h
+++ b/src/libANGLE/renderer/d3d/ShaderD3D.h
@@ -55,6 +55,7 @@
     unsigned int getUniformRegister(const std::string &uniformName) const;
 
     unsigned int getUniformBlockRegister(const std::string &blockName) const;
+    unsigned int getShaderStorageBlockRegister(const std::string &blockName) const;
     void appendDebugInfo(const std::string &info) const { mDebugInfo += info; }
 
     void generateWorkarounds(angle::CompilerWorkaroundsD3D *workarounds) const;
@@ -93,6 +94,7 @@
     mutable std::string mDebugInfo;
     std::map<std::string, unsigned int> mUniformRegisterMap;
     std::map<std::string, unsigned int> mUniformBlockRegisterMap;
+    std::map<std::string, unsigned int> mShaderStorageBlockRegisterMap;
     ShCompileOptions mAdditionalOptions;
 };
 }  // namespace rx
diff --git a/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
index 6eea492..918f778 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
@@ -177,6 +177,7 @@
     angle::Result getSRVForFormat(const gl::Context *context,
                                   DXGI_FORMAT srvFormat,
                                   const d3d11::ShaderResourceView **srvOut);
+    angle::Result getRawUAV(const gl::Context *context, d3d11::UnorderedAccessView **uavOut);
 
   private:
     static void FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc,
@@ -188,6 +189,7 @@
     d3d11::Buffer mBuffer;
     const angle::Subject *mOnStorageChanged;
     std::map<DXGI_FORMAT, d3d11::ShaderResourceView> mBufferResourceViews;
+    d3d11::UnorderedAccessView mBufferRawUAV;
 };
 
 // A emulated indexed buffer storage represents an underlying D3D11 buffer for data
@@ -691,6 +693,13 @@
     return angle::Result::Continue();
 }
 
+angle::Result Buffer11::getRawUAV(const gl::Context *context, d3d11::UnorderedAccessView **uavOut)
+{
+    NativeStorage *nativeStorage = nullptr;
+    ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_RAW_UAV, &nativeStorage));
+    return nativeStorage->getRawUAV(context, uavOut);
+}
+
 angle::Result Buffer11::getSRV(const gl::Context *context,
                                DXGI_FORMAT srvFormat,
                                const d3d11::ShaderResourceView **srvOut)
@@ -1180,6 +1189,13 @@
                                static_cast<UINT>(renderer->getNativeCaps().maxUniformBlockSize));
             break;
 
+        case BUFFER_USAGE_RAW_UAV:
+            bufferDesc->MiscFlags      = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
+            bufferDesc->BindFlags      = D3D11_BIND_UNORDERED_ACCESS;
+            bufferDesc->Usage          = D3D11_USAGE_DEFAULT;
+            bufferDesc->CPUAccessFlags = 0;
+            break;
+
         default:
             UNREACHABLE();
     }
@@ -1238,6 +1254,30 @@
     return angle::Result::Continue();
 }
 
+angle::Result Buffer11::NativeStorage::getRawUAV(const gl::Context *context,
+                                                 d3d11::UnorderedAccessView **uavOut)
+{
+    if (mBufferRawUAV.get())
+    {
+        *uavOut = &mBufferRawUAV;
+        return angle::Result::Continue();
+    }
+
+    D3D11_UNORDERED_ACCESS_VIEW_DESC bufferUAVDesc;
+    bufferUAVDesc.Buffer.FirstElement = 0;
+    bufferUAVDesc.Buffer.NumElements  = mBufferSize / 4;
+    bufferUAVDesc.Buffer.Flags        = D3D11_BUFFER_UAV_FLAG_RAW;
+    bufferUAVDesc.Format = DXGI_FORMAT_R32_TYPELESS;  // Format must be DXGI_FORMAT_R32_TYPELESS,
+                                                      // when creating Raw Unordered Access View
+    bufferUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
+
+    ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferUAVDesc,
+                                          mBuffer.get(), &mBufferRawUAV));
+
+    *uavOut = &mBufferRawUAV;
+    return angle::Result::Continue();
+}
+
 void Buffer11::NativeStorage::clearSRVs()
 {
     mBufferResourceViews.clear();
diff --git a/src/libANGLE/renderer/d3d/d3d11/Buffer11.h b/src/libANGLE/renderer/d3d/d3d11/Buffer11.h
index 8d9e713..1175409 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Buffer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Buffer11.h
@@ -35,12 +35,12 @@
     BUFFER_USAGE_STAGING,
     BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK,
     BUFFER_USAGE_INDEX,
-    // TODO: possibly share this buffer type with shader storage buffers.
     BUFFER_USAGE_INDIRECT,
     BUFFER_USAGE_PIXEL_UNPACK,
     BUFFER_USAGE_PIXEL_PACK,
     BUFFER_USAGE_UNIFORM,
     BUFFER_USAGE_EMULATED_INDEXED_VERTEX,
+    BUFFER_USAGE_RAW_UAV,
 
     BUFFER_USAGE_COUNT,
 };
@@ -70,6 +70,7 @@
     angle::Result getSRV(const gl::Context *context,
                          DXGI_FORMAT srvFormat,
                          const d3d11::ShaderResourceView **srvOut);
+    angle::Result getRawUAV(const gl::Context *context, d3d11::UnorderedAccessView **uavOut);
     bool isMapped() const { return mMappedStorage != nullptr; }
     angle::Result packPixels(const gl::Context *context,
                              const gl::FramebufferAttachment &readAttachment,
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
index a5fa6c3..e6f90d7 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -3093,7 +3093,7 @@
 angle::Result StateManager11::generateSwizzlesForShader(const gl::Context *context,
                                                         gl::ShaderType type)
 {
-    const gl::State &glState  = context->getGLState();
+    const gl::State &glState       = context->getGLState();
     const gl::RangeUI samplerRange = mProgramD3D->getUsedSamplerRange(type);
 
     for (unsigned int i = samplerRange.low(); i < samplerRange.high(); i++)
@@ -3449,6 +3449,59 @@
     return angle::Result::Continue();
 }
 
+angle::Result StateManager11::syncShaderStorageBuffersForShader(const gl::Context *context,
+                                                                gl::ShaderType shaderType)
+{
+    const gl::State &glState   = context->getGLState();
+    const gl::Program *program = glState.getProgram();
+    for (size_t blockIndex = 0; blockIndex < program->getActiveShaderStorageBlockCount();
+         blockIndex++)
+    {
+        GLuint binding = program->getShaderStorageBlockBinding(static_cast<GLuint>(blockIndex));
+        const auto &shaderStorageBuffer = glState.getIndexedShaderStorageBuffer(binding);
+        if (shaderStorageBuffer.get() == nullptr)
+        {
+            continue;
+        }
+
+        Buffer11 *bufferStorage            = GetImplAs<Buffer11>(shaderStorageBuffer.get());
+        d3d11::UnorderedAccessView *uavPtr = nullptr;
+        // TODO(jiajia.qin@intel.com): add buffer offset support. http://anglebug.com/1951
+        ANGLE_TRY(bufferStorage->getRawUAV(context, &uavPtr));
+
+        // We need to make sure that resource being set to UnorderedAccessView slot |registerIndex|
+        // is not bound on SRV.
+        if (uavPtr && unsetConflictingView(uavPtr->get()))
+        {
+            mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE);
+        }
+
+        const unsigned int registerIndex = mProgramD3D->getShaderStorageBufferRegisterIndex(
+            static_cast<GLuint>(blockIndex), shaderType);
+        switch (shaderType)
+        {
+            case gl::ShaderType::Compute:
+            {
+                ID3D11UnorderedAccessView *uav = uavPtr->get();
+                auto deviceContext             = mRenderer->getDeviceContext();
+                deviceContext->CSSetUnorderedAccessViews(registerIndex, 1, &uav, nullptr);
+                break;
+            }
+
+            case gl::ShaderType::Vertex:
+            case gl::ShaderType::Fragment:
+            case gl::ShaderType::Geometry:
+                UNIMPLEMENTED();
+                break;
+
+            default:
+                UNREACHABLE();
+        }
+    }
+
+    return angle::Result::Continue();
+}
+
 angle::Result StateManager11::syncUniformBuffers(const gl::Context *context)
 {
     gl::ShaderMap<unsigned int> shaderReservedUBOs = mRenderer->getReservedShaderUniformBuffers();
@@ -3479,7 +3532,11 @@
 
 angle::Result StateManager11::syncShaderStorageBuffers(const gl::Context *context)
 {
-    // TODO(jie.a.chen@intel.com): http://anglebug.com/1951
+    if (mProgramD3D->hasShaderStage(gl::ShaderType::Compute))
+    {
+        ANGLE_TRY(syncShaderStorageBuffersForShader(context, gl::ShaderType::Compute));
+    }
+
     return angle::Result::Continue();
 }
 
@@ -3556,13 +3613,13 @@
             break;
         }
         case gl::PrimitiveMode::Lines:
-            primitiveTopology        = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
+            primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
             break;
         case gl::PrimitiveMode::LineLoop:
-            primitiveTopology        = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
+            primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
             break;
         case gl::PrimitiveMode::LineStrip:
-            primitiveTopology        = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
+            primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
             break;
         case gl::PrimitiveMode::Triangles:
             primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
index b8d7bdc..210aad9 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
@@ -329,6 +329,9 @@
     angle::Result applyUniforms(const gl::Context *context);
     angle::Result applyUniformsForShader(const gl::Context *context, gl::ShaderType shaderType);
 
+    angle::Result syncShaderStorageBuffersForShader(const gl::Context *context,
+                                                    gl::ShaderType shaderType);
+
     angle::Result syncUniformBuffers(const gl::Context *context);
     angle::Result syncUniformBuffersForShader(const gl::Context *context,
                                               gl::ShaderType shaderType);