ES31: Implement bindImageTexture binds a single layer on D3D backend
Dynamically generate image2D variables' declaration and function
definition in libANGLE.
Bug: angleproject:1987
TEST=angle_end2end_tests.ComputeShaderTest.*
Change-Id: Idacc756f7bd15f22eccb1d689e18e997f3e74159
Reviewed-on: https://chromium-review.googlesource.com/c/1142885
Commit-Queue: Xinghua Cao <xinghua.cao@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 0c0157d..2983c19 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -75,6 +75,31 @@
}
}
+void GetDefaultImage2DBindLayoutFromComputeShader(const std::vector<sh::Uniform> &image2DUniforms,
+ gl::ImageUnitTextureTypeMap *image2DBindLayout)
+{
+ image2DBindLayout->clear();
+
+ for (const sh::Uniform &image2D : image2DUniforms)
+ {
+ if (gl::IsImage2DType(image2D.type))
+ {
+ if (image2D.binding == -1)
+ {
+ image2DBindLayout->insert(std::make_pair(0, gl::TextureType::_2D));
+ }
+ else
+ {
+ for (unsigned int index = 0; index < image2D.getArraySizeProduct(); index++)
+ {
+ image2DBindLayout->insert(
+ std::make_pair(image2D.binding + index, gl::TextureType::_2D));
+ }
+ }
+ }
+ }
+}
+
gl::PrimitiveMode GetGeometryShaderTypeFromDrawMode(gl::PrimitiveMode drawMode)
{
switch (drawMode)
@@ -369,6 +394,11 @@
return typeInfo.isImageType;
}
+bool D3DUniform::isImage2D() const
+{
+ return gl::IsImage2DType(typeInfo.type);
+}
+
bool D3DUniform::isReferencedByShader(gl::ShaderType shaderType) const
{
return mShaderRegisterIndexes[shaderType] != GL_INVALID_INDEX;
@@ -598,6 +628,14 @@
SafeDelete(mShaderExecutable);
}
+ProgramD3D::ComputeExecutable::ComputeExecutable(
+ const gl::ImageUnitTextureTypeMap &signature,
+ std::unique_ptr<ShaderExecutableD3D> shaderExecutable)
+ : mSignature(signature), mShaderExecutable(std::move(shaderExecutable))
+{}
+
+ProgramD3D::ComputeExecutable::~ComputeExecutable() {}
+
ProgramD3D::Sampler::Sampler()
: active(false), logicalTextureUnit(0), textureType(gl::TextureType::_2D)
{}
@@ -610,7 +648,6 @@
: ProgramImpl(state),
mRenderer(renderer),
mDynamicHLSL(nullptr),
- mComputeExecutable(nullptr),
mUsesPointSize(false),
mUsesFlatInterpolation(false),
mUsedShaderSamplerRanges({}),
@@ -1072,9 +1109,22 @@
stream->skip(geometryShaderSize);
}
- unsigned int computeShaderSize = stream->readInt<unsigned int>();
- if (computeShaderSize > 0)
+ const size_t computeShaderCount = stream->readInt<unsigned int>();
+ for (size_t computeShaderIndex = 0; computeShaderIndex < computeShaderCount;
+ computeShaderIndex++)
{
+ const size_t signatureCount = stream->readInt<unsigned int>();
+ gl::ImageUnitTextureTypeMap signatures;
+ for (size_t signatureIndex = 0; signatureIndex < signatureCount; signatureIndex++)
+ {
+ unsigned int imageUint;
+ gl::TextureType textureType;
+ stream->readInt<unsigned int>(&imageUint);
+ stream->readInt<gl::TextureType>(&textureType);
+ signatures.insert(std::pair<unsigned int, gl::TextureType>(imageUint, textureType));
+ }
+
+ const size_t computeShaderSize = stream->readInt<unsigned int>();
const unsigned char *computeShaderFunction = binary + stream->offset();
ShaderExecutableD3D *computeExecutable = nullptr;
@@ -1088,7 +1138,18 @@
return angle::Result::Incomplete;
}
- mComputeExecutable.reset(computeExecutable);
+ // add new binary
+ mComputeExecutables.push_back(std::unique_ptr<ComputeExecutable>(new ComputeExecutable(
+ signatures, std::unique_ptr<ShaderExecutableD3D>(computeExecutable))));
+
+ stream->skip(computeShaderSize);
+ }
+
+ const size_t bindLayoutCount = stream->readInt<unsigned int>();
+ for (size_t bindLayoutIndex = 0; bindLayoutIndex < bindLayoutCount; bindLayoutIndex++)
+ {
+ mComputeShaderImage2DBindLayoutCache.insert(std::pair<unsigned int, gl::TextureType>(
+ stream->readInt<unsigned int>(), gl::TextureType::_2D));
}
initializeUniformStorage(mState.getLinkedShaderStages());
@@ -1268,15 +1329,31 @@
stream->writeBytes(geometryExecutable->getFunction(), geometryShaderSize);
}
- if (mComputeExecutable)
+ stream->writeInt(mComputeExecutables.size());
+ for (size_t computeExecutableIndex = 0; computeExecutableIndex < mComputeExecutables.size();
+ computeExecutableIndex++)
{
- size_t computeShaderSize = mComputeExecutable->getLength();
+ ComputeExecutable *computeExecutable = mComputeExecutables[computeExecutableIndex].get();
+
+ const gl::ImageUnitTextureTypeMap signatures = computeExecutable->signature();
+ stream->writeInt(signatures.size());
+ for (const auto &signature : signatures)
+ {
+ stream->writeInt(signature.first);
+ stream->writeInt(static_cast<unsigned int>(signature.second));
+ }
+
+ size_t computeShaderSize = computeExecutable->shaderExecutable()->getLength();
stream->writeInt(computeShaderSize);
- stream->writeBytes(mComputeExecutable->getFunction(), computeShaderSize);
+
+ const uint8_t *computeBlob = computeExecutable->shaderExecutable()->getFunction();
+ stream->writeBytes(computeBlob, computeShaderSize);
}
- else
+
+ stream->writeInt(mComputeShaderImage2DBindLayoutCache.size());
+ for (auto &image2DBindLayout : mComputeShaderImage2DBindLayoutCache)
{
- stream->writeInt(0);
+ stream->writeInt(image2DBindLayout.first);
}
}
@@ -1514,6 +1591,13 @@
updateCachedPixelExecutableIndex();
}
+void ProgramD3D::updateCachedImage2DBindLayoutFromComputeShader()
+{
+ GetDefaultImage2DBindLayoutFromComputeShader(mImage2DUniforms,
+ &mComputeShaderImage2DBindLayoutCache);
+ updateCachedComputeExecutableIndex();
+}
+
class ProgramD3D::GetGeometryExecutableTask : public ProgramD3D::GetExecutableTask
{
public:
@@ -1538,16 +1622,6 @@
const gl::Caps &mCaps;
};
-angle::Result ProgramD3D::getComputeExecutable(ShaderExecutableD3D **outExecutable)
-{
- if (outExecutable)
- {
- *outExecutable = mComputeExecutable.get();
- }
-
- return angle::Result::Continue;
-}
-
// The LinkEvent implementation for linking a rendering(VS, FS, GS) program.
class ProgramD3D::GraphicsProgramLinkEvent final : public LinkEvent
{
@@ -1687,34 +1761,59 @@
vertexShaderD3D, fragmentShaderD3D);
}
+angle::Result ProgramD3D::getComputeExecutableForImage2DBindLayout(
+ d3d::Context *context,
+ ShaderExecutableD3D **outExecutable,
+ gl::InfoLog *infoLog)
+{
+ if (mCachedComputeExecutableIndex.valid())
+ {
+ *outExecutable =
+ mComputeExecutables[mCachedComputeExecutableIndex.value()]->shaderExecutable();
+ return angle::Result::Continue;
+ }
+
+ std::string finalComputeHLSL = mDynamicHLSL->generateComputeShaderForImage2DBindSignature(
+ context, *this, mState, mImage2DUniforms, mComputeShaderImage2DBindLayoutCache);
+
+ // Generate new compute executable
+ ShaderExecutableD3D *computeExecutable = nullptr;
+
+ gl::InfoLog tempInfoLog;
+ gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog;
+
+ ANGLE_TRY(mRenderer->compileToExecutable(
+ context, *currentInfoLog, finalComputeHLSL, gl::ShaderType::Compute,
+ std::vector<D3DVarying>(), false, angle::CompilerWorkaroundsD3D(), &computeExecutable));
+
+ if (computeExecutable)
+ {
+ mComputeExecutables.push_back(std::unique_ptr<ComputeExecutable>(
+ new ComputeExecutable(mComputeShaderImage2DBindLayoutCache,
+ std::unique_ptr<ShaderExecutableD3D>(computeExecutable))));
+ mCachedComputeExecutableIndex = mComputeExecutables.size() - 1;
+ }
+ else if (!infoLog)
+ {
+ ERR() << "Error compiling dynamic compute executable:" << std::endl
+ << tempInfoLog.str() << std::endl;
+ }
+ *outExecutable = computeExecutable;
+
+ return angle::Result::Continue;
+}
+
angle::Result ProgramD3D::compileComputeExecutable(d3d::Context *context, gl::InfoLog &infoLog)
{
// Ensure the compiler is initialized to avoid race conditions.
ANGLE_TRY(mRenderer->ensureHLSLCompilerInitialized(context));
- gl::Shader *computeShaderGL = mState.getAttachedShader(gl::ShaderType::Compute);
- ASSERT(computeShaderGL);
- std::string computeShader = computeShaderGL->getTranslatedSource();
+ updateCachedImage2DBindLayoutFromComputeShader();
ShaderExecutableD3D *computeExecutable = nullptr;
- ANGLE_TRY(mRenderer->compileToExecutable(
- context, infoLog, computeShader, gl::ShaderType::Compute, std::vector<D3DVarying>(), false,
- angle::CompilerWorkaroundsD3D(), &computeExecutable));
+ ANGLE_TRY(getComputeExecutableForImage2DBindLayout(context, &computeExecutable, &infoLog));
- if (computeExecutable == nullptr)
- {
- ERR() << "Error compiling dynamic compute executable:" << std::endl
- << infoLog.str() << std::endl;
- }
- else
- {
- const ShaderD3D *computeShaderD3D =
- GetImplAs<ShaderD3D>(mState.getAttachedShader(gl::ShaderType::Compute));
- computeShaderD3D->appendDebugInfo(computeExecutable->getDebugInfo());
- mComputeExecutable.reset(computeExecutable);
- }
-
- return mComputeExecutable.get() ? angle::Result::Continue : angle::Result::Incomplete;
+ return computeExecutable ? angle::Result::Continue : angle::Result::Incomplete;
}
std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
@@ -1734,10 +1833,19 @@
mReadonlyImagesCS.resize(data.getCaps().maxImageUnits);
mShaderUniformsDirty.set(gl::ShaderType::Compute);
- defineUniformsAndAssignRegisters();
linkResources(resources);
+ for (const sh::Uniform &uniform : computeShader->getUniforms())
+ {
+ if (gl::IsImageType(uniform.type) && gl::IsImage2DType(uniform.type))
+ {
+ mImage2DUniforms.push_back(uniform);
+ }
+ }
+
+ defineUniformsAndAssignRegisters();
+
angle::Result result = compileComputeExecutable(GetImplAs<ContextD3D>(context), infoLog);
if (result != angle::Result::Continue)
{
@@ -2245,17 +2353,17 @@
sh::TraverseShaderVariable(uniform, false, &visitor);
}
-D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name)
+bool ProgramD3D::hasNamedUniform(const std::string &name)
{
for (D3DUniform *d3dUniform : mD3DUniforms)
{
if (d3dUniform->name == name)
{
- return d3dUniform;
+ return true;
}
}
- return nullptr;
+ return false;
}
// Assume count is already clamped.
@@ -2435,7 +2543,7 @@
{
for (size_t uniformIndex = 0; uniformIndex < mD3DUniforms.size(); ++uniformIndex)
{
- if (mD3DUniforms[uniformIndex]->isImage())
+ if (mD3DUniforms[uniformIndex]->isImage() && !mD3DUniforms[uniformIndex]->isImage2D())
{
assignImageRegisters(uniformIndex);
}
@@ -2532,18 +2640,32 @@
*outUsedRange = gl::RangeUI(low, high);
}
+void ProgramD3D::assignImage2DRegisters(unsigned int startImageIndex,
+ int startLogicalImageUnit,
+ bool readonly)
+{
+ if (readonly)
+ {
+ AssignImages(startImageIndex, startLogicalImageUnit, 1, mReadonlyImagesCS,
+ &mUsedComputeReadonlyImageRange);
+ }
+ else
+ {
+ AssignImages(startImageIndex, startLogicalImageUnit, 1, mImagesCS, &mUsedComputeImageRange);
+ }
+}
+
void ProgramD3D::reset()
{
mVertexExecutables.clear();
mPixelExecutables.clear();
+ mComputeExecutables.clear();
for (auto &geometryExecutable : mGeometryExecutables)
{
geometryExecutable.reset(nullptr);
}
- mComputeExecutable.reset(nullptr);
-
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
mShaderHLSL[shaderType].clear();
@@ -2677,6 +2799,25 @@
updateCachedPixelExecutableIndex();
}
+void ProgramD3D::updateCachedComputeImage2DBindLayout(const gl::Context *context)
+{
+ const auto &glState = context->getState();
+ for (auto &image2DBindLayout : mComputeShaderImage2DBindLayoutCache)
+ {
+ const gl::ImageUnit &imageUnit = glState.getImageUnit(image2DBindLayout.first);
+ if (imageUnit.texture.get())
+ {
+ image2DBindLayout.second = imageUnit.texture->getType();
+ }
+ else
+ {
+ image2DBindLayout.second = gl::TextureType::_2D;
+ }
+ }
+
+ updateCachedComputeExecutableIndex();
+}
+
void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyingPacking,
const BuiltinInfo &builtins)
{
@@ -2777,6 +2918,11 @@
return mCachedPixelExecutableIndex.valid();
}
+bool ProgramD3D::hasComputeExecutableForCachedImage2DBindLayout()
+{
+ return mCachedComputeExecutableIndex.valid();
+}
+
template <typename DestT>
void ProgramD3D::getUniformInternal(GLint location, DestT *dataOut) const
{
@@ -2837,6 +2983,21 @@
}
}
+void ProgramD3D::updateCachedComputeExecutableIndex()
+{
+ mCachedComputeExecutableIndex.reset();
+ for (size_t executableIndex = 0; executableIndex < mComputeExecutables.size();
+ executableIndex++)
+ {
+ if (mComputeExecutables[executableIndex]->matchesSignature(
+ mComputeShaderImage2DBindLayoutCache))
+ {
+ mCachedComputeExecutableIndex = executableIndex;
+ break;
+ }
+ }
+}
+
void ProgramD3D::linkResources(const gl::ProgramLinkedResources &resources)
{
InterfaceBlockInfo uniformBlockInfo;