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);