ES31: Support bindImageTexture on Texture2D for compute shaders on D3D
BUG=angleproject:1987
TEST=angle_end2end_tests
Change-Id: I3b0afb441a41dbd7f204b1d1bba7884c8d203ce1
Reviewed-on: https://chromium-review.googlesource.com/749004
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index cb3eab1..9699e7e 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -23,7 +23,6 @@
#include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/d3d/DynamicHLSL.h"
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
-#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/ShaderD3D.h"
#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h"
@@ -53,7 +52,7 @@
{
GLenum componentType = gl::VariableComponentType(transposedType);
GLuint components = static_cast<GLuint>(gl::VariableColumnCount(transposedType));
- bool pureInt = (componentType != GL_FLOAT);
+ bool pureInt = (componentType != GL_FLOAT);
gl::VertexFormatType defaultType =
gl::GetVertexFormatType(componentType, GL_FALSE, components, pureInt);
@@ -111,8 +110,8 @@
{
constexpr int targetWidth = 4;
constexpr int targetHeight = rows;
- constexpr int srcWidth = cols;
- constexpr int srcHeight = rows;
+ constexpr int srcWidth = cols;
+ constexpr int srcHeight = rows;
constexpr int copyWidth = std::min(targetWidth, srcWidth);
constexpr int copyHeight = std::min(targetHeight, srcHeight);
@@ -295,6 +294,7 @@
// D3DUniform Implementation
D3DUniform::D3DUniform(GLenum type,
+ HLSLRegisterType reg,
const std::string &nameIn,
const std::vector<unsigned int> &arraySizesIn,
bool defaultBlock)
@@ -304,6 +304,7 @@
vsData(nullptr),
psData(nullptr),
csData(nullptr),
+ regType(reg),
vsRegisterIndex(GL_INVALID_INDEX),
psRegisterIndex(GL_INVALID_INDEX),
csRegisterIndex(GL_INVALID_INDEX),
@@ -347,6 +348,11 @@
return typeInfo.isSampler;
}
+bool D3DUniform::isImage() const
+{
+ return typeInfo.isImageType;
+}
+
bool D3DUniform::isReferencedByVertexShader() const
{
return vsRegisterIndex != GL_INVALID_INDEX;
@@ -557,7 +563,7 @@
if ((conversionType & VERTEX_CONVERT_GPU) == 0)
continue;
- GLenum componentType = renderer->getVertexComponentType(vertexFormatType);
+ GLenum componentType = renderer->getVertexComponentType(vertexFormatType);
(*signatureOut)[index] = GetAttribType(componentType);
}
}
@@ -592,6 +598,10 @@
{
}
+ProgramD3D::Image::Image() : active(false), logicalImageUnit(0)
+{
+}
+
unsigned int ProgramD3D::mCurrentSerial = 1;
ProgramD3D::ProgramD3D(const gl::ProgramState &state, RendererD3D *renderer)
@@ -609,6 +619,8 @@
mUsedPixelSamplerRange(0),
mUsedComputeSamplerRange(0),
mDirtySamplerMapping(true),
+ mUsedComputeImageRange(0),
+ mUsedComputeReadonlyImageRange(0),
mSerial(issueSerial()),
mVertexUniformsDirty(true),
mFragmentUniformsDirty(true),
@@ -803,6 +815,52 @@
return SamplerMapping::WasDirty;
}
+GLint ProgramD3D::getImageMapping(gl::ShaderType type,
+ unsigned int imageIndex,
+ bool readonly,
+ const gl::Caps &caps) const
+{
+ GLint logicalImageUnit = -1;
+ ASSERT(imageIndex < caps.maxImageUnits);
+ switch (type)
+ {
+ case gl::SHADER_COMPUTE:
+ if (readonly && imageIndex < mReadonlyImagesCS.size() &&
+ mReadonlyImagesCS[imageIndex].active)
+ {
+ logicalImageUnit = mReadonlyImagesCS[imageIndex].logicalImageUnit;
+ }
+ else if (imageIndex < mImagesCS.size() && mImagesCS[imageIndex].active)
+ {
+ logicalImageUnit = mImagesCS[imageIndex].logicalImageUnit;
+ }
+ break;
+ // TODO(xinghua.cao@intel.com): add image mapping for vertex shader and pixel shader.
+ default:
+ UNREACHABLE();
+ }
+
+ if (logicalImageUnit >= 0 && logicalImageUnit < static_cast<GLint>(caps.maxImageUnits))
+ {
+ return logicalImageUnit;
+ }
+
+ return -1;
+}
+
+GLuint ProgramD3D::getUsedImageRange(gl::ShaderType type, bool readonly) const
+{
+ switch (type)
+ {
+ case gl::SHADER_COMPUTE:
+ return readonly ? mUsedComputeReadonlyImageRange : mUsedComputeImageRange;
+ // TODO(xinghua.cao@intel.com): add image range of vertex shader and pixel shader.
+ default:
+ UNREACHABLE();
+ return 0u;
+ }
+}
+
gl::LinkResult ProgramD3D::load(const gl::Context *context,
gl::InfoLog &infoLog,
gl::BinaryInputStream *stream)
@@ -863,9 +921,29 @@
mSamplersCS.push_back(sampler);
}
+ const unsigned int csImageCount = stream->readInt<unsigned int>();
+ for (unsigned int i = 0; i < csImageCount; ++i)
+ {
+ Image image;
+ stream->readBool(&image.active);
+ stream->readInt(&image.logicalImageUnit);
+ mImagesCS.push_back(image);
+ }
+
+ const unsigned int csReadonlyImageCount = stream->readInt<unsigned int>();
+ for (unsigned int i = 0; i < csReadonlyImageCount; ++i)
+ {
+ Image image;
+ stream->readBool(&image.active);
+ stream->readInt(&image.logicalImageUnit);
+ mReadonlyImagesCS.push_back(image);
+ }
+
stream->readInt(&mUsedVertexSamplerRange);
stream->readInt(&mUsedPixelSamplerRange);
stream->readInt(&mUsedComputeSamplerRange);
+ stream->readInt(&mUsedComputeImageRange);
+ stream->readInt(&mUsedComputeReadonlyImageRange);
const unsigned int uniformCount = stream->readInt<unsigned int>();
if (stream->error())
@@ -881,8 +959,9 @@
const gl::LinkedUniform &linkedUniform = linkedUniforms[uniformIndex];
D3DUniform *d3dUniform =
- new D3DUniform(linkedUniform.type, linkedUniform.name, linkedUniform.arraySizes,
- linkedUniform.isInDefaultBlock());
+ new D3DUniform(linkedUniform.type, HLSLRegisterType::None, linkedUniform.name,
+ linkedUniform.arraySizes, linkedUniform.isInDefaultBlock());
+ stream->readInt<HLSLRegisterType>(&d3dUniform->regType);
stream->readInt(&d3dUniform->psRegisterIndex);
stream->readInt(&d3dUniform->vsRegisterIndex);
stream->readInt(&d3dUniform->csRegisterIndex);
@@ -1110,14 +1189,31 @@
stream->writeInt(mSamplersCS[i].textureType);
}
+ stream->writeInt(mImagesCS.size());
+ for (unsigned int i = 0; i < mImagesCS.size(); ++i)
+ {
+ stream->writeInt(mImagesCS[i].active);
+ stream->writeInt(mImagesCS[i].logicalImageUnit);
+ }
+
+ stream->writeInt(mReadonlyImagesCS.size());
+ for (unsigned int i = 0; i < mReadonlyImagesCS.size(); ++i)
+ {
+ stream->writeInt(mReadonlyImagesCS[i].active);
+ stream->writeInt(mReadonlyImagesCS[i].logicalImageUnit);
+ }
+
stream->writeInt(mUsedVertexSamplerRange);
stream->writeInt(mUsedPixelSamplerRange);
stream->writeInt(mUsedComputeSamplerRange);
+ stream->writeInt(mUsedComputeImageRange);
+ stream->writeInt(mUsedComputeReadonlyImageRange);
stream->writeInt(mD3DUniforms.size());
for (const D3DUniform *uniform : mD3DUniforms)
{
// Type, name and arraySize are redundant, so aren't stored in the binary.
+ stream->writeInt(static_cast<unsigned int>(uniform->regType));
stream->writeIntOrNegOne(uniform->psRegisterIndex);
stream->writeIntOrNegOne(uniform->vsRegisterIndex);
stream->writeIntOrNegOne(uniform->csRegisterIndex);
@@ -1584,6 +1680,8 @@
if (computeShader)
{
mSamplersCS.resize(data.getCaps().maxComputeTextureImageUnits);
+ mImagesCS.resize(data.getCaps().maxImageUnits);
+ mReadonlyImagesCS.resize(data.getCaps().maxImageUnits);
defineUniformsAndAssignRegisters(context);
@@ -1640,7 +1738,7 @@
mUsesPointSize = vertexShaderD3D->usesPointSize();
mDynamicHLSL->getPixelShaderOutputKey(data, mState, metadata, &mPixelShaderKey);
- mUsesFragDepth = metadata.usesFragDepth();
+ mUsesFragDepth = metadata.usesFragDepth();
mUsesViewID = metadata.usesViewID();
mHasANGLEMultiviewEnabled = metadata.hasANGLEMultiviewEnabled();
@@ -2070,6 +2168,7 @@
}
assignAllSamplerRegisters();
+ assignAllImageRegisters();
initializeUniformStorage();
}
@@ -2077,21 +2176,44 @@
const sh::Uniform &uniform,
D3DUniformMap *uniformMap)
{
- // Samplers get their registers assigned in assignAllSamplerRegisters.
- if (uniform.isBuiltIn() || gl::IsSamplerType(uniform.type))
+ // Samplers get their registers assigned in assignAllSamplerRegisters, and images get their
+ // registers assigned in assignAllImageRegisters.
+ if (gl::IsSamplerType(uniform.type))
{
- defineUniform(shader->getType(), uniform, uniform.name, nullptr, uniformMap);
+ defineUniform(shader->getType(), uniform, uniform.name, HLSLRegisterType::Texture, nullptr,
+ uniformMap);
+ return;
+ }
+ else if (gl::IsImageType(uniform.type))
+ {
+ if (uniform.readonly)
+ {
+ defineUniform(shader->getType(), uniform, uniform.name, HLSLRegisterType::Texture,
+ nullptr, uniformMap);
+ }
+ else
+ {
+ defineUniform(shader->getType(), uniform, uniform.name,
+ HLSLRegisterType::UnorderedAccessView, nullptr, uniformMap);
+ }
+ mImageBindingMap[uniform.name] = uniform.binding;
+ return;
+ }
+ else if (uniform.isBuiltIn())
+ {
+ defineUniform(shader->getType(), uniform, uniform.name, HLSLRegisterType::None, nullptr,
+ uniformMap);
return;
}
const ShaderD3D *shaderD3D = GetImplAs<ShaderD3D>(shader);
-
unsigned int startRegister = shaderD3D->getUniformRegister(uniform.name);
- ShShaderOutput outputType = shaderD3D->getCompilerOutputType();
+ ShShaderOutput outputType = shaderD3D->getCompilerOutputType();
sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType), true);
encoder.skipRegisters(startRegister);
- defineUniform(shader->getType(), uniform, uniform.name, &encoder, uniformMap);
+ defineUniform(shader->getType(), uniform, uniform.name, HLSLRegisterType::None, &encoder,
+ uniformMap);
}
D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name)
@@ -2110,6 +2232,7 @@
void ProgramD3D::defineStructUniformFields(GLenum shaderType,
const std::vector<sh::ShaderVariable> &fields,
const std::string &namePrefix,
+ const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap)
{
@@ -2126,11 +2249,11 @@
// extracted out of the struct by the shader translator.
if (gl::IsSamplerType(field.type))
{
- defineUniform(shaderType, field, fieldFullName, nullptr, uniformMap);
+ defineUniform(shaderType, field, fieldFullName, regType, nullptr, uniformMap);
}
else
{
- defineUniform(shaderType, field, fieldFullName, encoder, uniformMap);
+ defineUniform(shaderType, field, fieldFullName, regType, encoder, uniformMap);
}
}
@@ -2142,6 +2265,7 @@
const sh::ShaderVariable &uniform,
unsigned int arrayNestingIndex,
const std::string &prefix,
+ const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap)
{
@@ -2154,11 +2278,11 @@
if (arrayNestingIndex + 1u < uniform.arraySizes.size())
{
defineArrayOfStructsUniformFields(shaderType, uniform, arrayNestingIndex + 1u,
- elementString, encoder, uniformMap);
+ elementString, regType, encoder, uniformMap);
}
else
{
- defineStructUniformFields(shaderType, uniform.fields, elementString, encoder,
+ defineStructUniformFields(shaderType, uniform.fields, elementString, regType, encoder,
uniformMap);
}
}
@@ -2167,6 +2291,7 @@
void ProgramD3D::defineArrayUniformElements(GLenum shaderType,
const sh::ShaderVariable &uniform,
const std::string &fullName,
+ const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap)
{
@@ -2178,7 +2303,7 @@
for (unsigned int arrayIndex = 0u; arrayIndex < uniform.getOutermostArraySize(); ++arrayIndex)
{
std::string elementFullName = fullName + ArrayString(arrayIndex);
- defineUniform(shaderType, uniformElement, elementFullName, encoder, uniformMap);
+ defineUniform(shaderType, uniformElement, elementFullName, regType, encoder, uniformMap);
}
if (encoder)
@@ -2188,6 +2313,7 @@
void ProgramD3D::defineUniform(GLenum shaderType,
const sh::ShaderVariable &uniform,
const std::string &fullName,
+ const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap)
{
@@ -2195,18 +2321,19 @@
{
if (uniform.isArray())
{
- defineArrayOfStructsUniformFields(shaderType, uniform, 0u, fullName, encoder,
+ defineArrayOfStructsUniformFields(shaderType, uniform, 0u, fullName, regType, encoder,
uniformMap);
}
else
{
- defineStructUniformFields(shaderType, uniform.fields, fullName, encoder, uniformMap);
+ defineStructUniformFields(shaderType, uniform.fields, fullName, regType, encoder,
+ uniformMap);
}
return;
}
if (uniform.isArrayOfArrays())
{
- defineArrayUniformElements(shaderType, uniform, fullName, encoder, uniformMap);
+ defineArrayUniformElements(shaderType, uniform, fullName, regType, encoder, uniformMap);
return;
}
@@ -2230,7 +2357,7 @@
}
else
{
- d3dUniform = new D3DUniform(uniform.type, fullName, uniform.arraySizes, true);
+ d3dUniform = new D3DUniform(uniform.type, regType, fullName, uniform.arraySizes, true);
(*uniformMap)[fullName] = d3dUniform;
}
@@ -2490,13 +2617,102 @@
ASSERT(samplerIndex < outSamplers.size());
Sampler *sampler = &outSamplers[samplerIndex];
sampler->active = true;
- sampler->textureType = typeInfo.samplerTextureType;
+ sampler->textureType = typeInfo.textureType;
sampler->logicalTextureUnit = 0;
*outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
samplerIndex++;
} while (samplerIndex < startSamplerIndex + samplerCount);
}
+void ProgramD3D::assignAllImageRegisters()
+{
+ for (size_t uniformIndex = 0; uniformIndex < mD3DUniforms.size(); ++uniformIndex)
+ {
+ if (mD3DUniforms[uniformIndex]->isImage())
+ {
+ assignImageRegisters(uniformIndex);
+ }
+ }
+}
+
+void ProgramD3D::assignImageRegisters(size_t uniformIndex)
+{
+ D3DUniform *d3dUniform = mD3DUniforms[uniformIndex];
+ ASSERT(d3dUniform->isImage());
+ // If the uniform is an array of arrays, then we have separate entries for each inner array in
+ // mD3DUniforms. However, the image register info is stored in the shader only for the
+ // outermost array.
+ std::vector<unsigned int> subscripts;
+ const std::string baseName = gl::ParseResourceName(d3dUniform->name, &subscripts);
+ unsigned int registerOffset = mState.getUniforms()[uniformIndex].flattenedOffsetInParentArrays *
+ d3dUniform->getArraySizeProduct();
+
+ const gl::Shader *computeShader = mState.getAttachedComputeShader();
+ if (computeShader)
+ {
+ const ShaderD3D *computeShaderD3D = GetImplAs<ShaderD3D>(mState.getAttachedComputeShader());
+ ASSERT(computeShaderD3D->hasUniform(baseName));
+ d3dUniform->csRegisterIndex =
+ computeShaderD3D->getUniformRegister(baseName) + registerOffset;
+ ASSERT(d3dUniform->csRegisterIndex != GL_INVALID_INDEX);
+ auto bindingIter = mImageBindingMap.find(baseName);
+ ASSERT(bindingIter != mImageBindingMap.end());
+ if (d3dUniform->regType == HLSLRegisterType::Texture)
+ {
+ AssignImages(d3dUniform->csRegisterIndex, bindingIter->second,
+ d3dUniform->getArraySizeProduct(), mReadonlyImagesCS,
+ &mUsedComputeReadonlyImageRange);
+ }
+ else if (d3dUniform->regType == HLSLRegisterType::UnorderedAccessView)
+ {
+ AssignImages(d3dUniform->csRegisterIndex, bindingIter->second,
+ d3dUniform->getArraySizeProduct(), mImagesCS, &mUsedComputeImageRange);
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ // TODO(xinghua.cao@intel.com): Implement image variables in vertex shader and pixel shader.
+ UNIMPLEMENTED();
+ }
+}
+
+// static
+void ProgramD3D::AssignImages(unsigned int startImageIndex,
+ int startLogicalImageUnit,
+ unsigned int imageCount,
+ std::vector<Image> &outImages,
+ GLuint *outUsedRange)
+{
+ unsigned int imageIndex = startImageIndex;
+ // If declare without a binding qualifier, any uniform image variable (include all elements of
+ // unbound image array) shoud be bound to unit zero.
+ if (startLogicalImageUnit == -1)
+ {
+ ASSERT(imageIndex < outImages.size());
+ Image *image = &outImages[imageIndex];
+ image->active = true;
+ image->logicalImageUnit = 0;
+ *outUsedRange = std::max(imageIndex + 1, *outUsedRange);
+ return;
+ }
+
+ unsigned int logcalImageUnit = startLogicalImageUnit;
+ do
+ {
+ ASSERT(imageIndex < outImages.size());
+ Image *image = &outImages[imageIndex];
+ image->active = true;
+ image->logicalImageUnit = logcalImageUnit;
+ *outUsedRange = std::max(imageIndex + 1, *outUsedRange);
+ imageIndex++;
+ logcalImageUnit++;
+ } while (imageIndex < startImageIndex + imageCount);
+}
+
void ProgramD3D::reset()
{
mVertexExecutables.clear();
@@ -2513,12 +2729,12 @@
mVertexWorkarounds = angle::CompilerWorkaroundsD3D();
mPixelHLSL.clear();
- mPixelWorkarounds = angle::CompilerWorkaroundsD3D();
- mUsesFragDepth = false;
+ mPixelWorkarounds = angle::CompilerWorkaroundsD3D();
+ mUsesFragDepth = false;
mHasANGLEMultiviewEnabled = false;
mUsesViewID = false;
mPixelShaderKey.clear();
- mUsesPointSize = false;
+ mUsesPointSize = false;
mUsesFlatInterpolation = false;
SafeDeleteContainer(mD3DUniforms);
@@ -2531,11 +2747,15 @@
mSamplersPS.clear();
mSamplersVS.clear();
mSamplersCS.clear();
+ mImagesCS.clear();
+ mReadonlyImagesCS.clear();
- mUsedVertexSamplerRange = 0;
- mUsedPixelSamplerRange = 0;
- mUsedComputeSamplerRange = 0;
- mDirtySamplerMapping = true;
+ mUsedVertexSamplerRange = 0;
+ mUsedPixelSamplerRange = 0;
+ mUsedComputeSamplerRange = 0;
+ mDirtySamplerMapping = true;
+ mUsedComputeImageRange = 0;
+ mUsedComputeReadonlyImageRange = 0;
mAttribLocationToD3DSemantic.fill(-1);