Commit 65ec0b2e by Xinghua Cao Committed by Commit Bot

ES31: Add support for bindImageTexture on GL backend

This patch refers to https://chromium-review.googlesource.com/c/380636/ BUG=angleproject:1987 Change-Id: If621eed6ecaa7298214843a2a133801ca1487b03 Reviewed-on: https://chromium-review.googlesource.com/462088 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 7a20b973
...@@ -1066,6 +1066,18 @@ void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle) ...@@ -1066,6 +1066,18 @@ void Context::bindSampler(GLuint textureUnit, GLuint samplerHandle)
mGLState.setSamplerBinding(this, textureUnit, sampler); mGLState.setSamplerBinding(this, textureUnit, sampler);
} }
void Context::bindImageTexture(GLuint unit,
GLuint texture,
GLint level,
GLboolean layered,
GLint layer,
GLenum access,
GLenum format)
{
Texture *tex = mState.mTextures->getTexture(texture);
mGLState.setImageUnit(this, unit, tex, level, layered, layer, access, format);
}
void Context::bindGenericUniformBuffer(GLuint bufferHandle) void Context::bindGenericUniformBuffer(GLuint bufferHandle)
{ {
Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle); Buffer *buffer = mState.mBuffers->checkBufferAllocation(mImplementation.get(), bufferHandle);
......
...@@ -136,6 +136,13 @@ class Context final : public ValidationContext ...@@ -136,6 +136,13 @@ class Context final : public ValidationContext
GLintptr offset, GLintptr offset,
GLsizei stride); GLsizei stride);
void bindSampler(GLuint textureUnit, GLuint samplerHandle); void bindSampler(GLuint textureUnit, GLuint samplerHandle);
void bindImageTexture(GLuint unit,
GLuint texture,
GLint level,
GLboolean layered,
GLint layer,
GLenum access,
GLenum format);
void bindGenericUniformBuffer(GLuint bufferHandle); void bindGenericUniformBuffer(GLuint bufferHandle);
void bindIndexedUniformBuffer(GLuint bufferHandle, void bindIndexedUniformBuffer(GLuint bufferHandle,
GLuint index, GLuint index,
......
...@@ -198,10 +198,9 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -198,10 +198,9 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
"All bits of DrawBufferMask can be contained in an uint32_t"); "All bits of DrawBufferMask can be contained in an uint32_t");
state->mActiveOutputVariables = stream.readInt<uint32_t>(); state->mActiveOutputVariables = stream.readInt<uint32_t>();
unsigned int low = stream.readInt<unsigned int>(); unsigned int samplerRangeLow = stream.readInt<unsigned int>();
unsigned int high = stream.readInt<unsigned int>(); unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
state->mSamplerUniformRange = RangeUI(low, high); state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
unsigned int samplerCount = stream.readInt<unsigned int>(); unsigned int samplerCount = stream.readInt<unsigned int>();
for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex) for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
{ {
...@@ -210,6 +209,17 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -210,6 +209,17 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
state->mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount)); state->mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
} }
unsigned int imageRangeLow = stream.readInt<unsigned int>();
unsigned int imageRangeHigh = stream.readInt<unsigned int>();
state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
unsigned int imageCount = stream.readInt<unsigned int>();
for (unsigned int imageIndex = 0; imageIndex < imageCount; ++imageIndex)
{
GLuint boundImageUnit = stream.readInt<unsigned int>();
size_t elementCount = stream.readInt<size_t>();
state->mImageBindings.emplace_back(ImageBinding(boundImageUnit, elementCount));
}
return program->getImplementation()->load(context, infoLog, &stream); return program->getImplementation()->load(context, infoLog, &stream);
} }
...@@ -343,6 +353,16 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -343,6 +353,16 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeInt(samplerBinding.boundTextureUnits.size()); stream.writeInt(samplerBinding.boundTextureUnits.size());
} }
stream.writeInt(state.getImageUniformRange().low());
stream.writeInt(state.getImageUniformRange().high());
stream.writeInt(state.getImageBindings().size());
for (const auto &imageBinding : state.getImageBindings())
{
stream.writeInt(imageBinding.boundImageUnit);
stream.writeInt(imageBinding.elementCount);
}
program->getImplementation()->save(&stream); program->getImplementation()->save(&stream);
ASSERT(binaryOut); ASSERT(binaryOut);
......
...@@ -1736,17 +1736,43 @@ bool Program::linkUniforms(const Context *context, ...@@ -1736,17 +1736,43 @@ bool Program::linkUniforms(const Context *context,
linker.getResults(&mState.mUniforms, &mState.mUniformLocations); linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
linkSamplerBindings(); linkSamplerAndImageBindings();
return true; return true;
} }
void Program::linkSamplerBindings() void Program::linkSamplerAndImageBindings()
{ {
unsigned int high = static_cast<unsigned int>(mState.mUniforms.size()); unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
unsigned int low = high; unsigned int low = high;
for (auto samplerIter = mState.mUniforms.rbegin(); for (auto imageIter = mState.mUniforms.rbegin();
imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
{
--low;
}
mState.mImageUniformRange = RangeUI(low, high);
// If uniform is a image type, insert it into the mImageBindings array.
for (unsigned int imageIndex : mState.mImageUniformRange)
{
// ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v}
// commands cannot load values into a uniform defined as an image,
// if declare without a binding qualifier, the image variable is
// initially bound to unit zero.
auto &imageUniform = mState.mUniforms[imageIndex];
if (imageUniform.binding == -1)
{
imageUniform.binding = 0;
}
mState.mImageBindings.emplace_back(
ImageBinding(imageUniform.binding, imageUniform.elementCount()));
}
high = low;
for (auto samplerIter = mState.mUniforms.rbegin() + mState.mImageUniformRange.length();
samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter) samplerIter != mState.mUniforms.rend() && samplerIter->isSampler(); ++samplerIter)
{ {
--low; --low;
......
...@@ -197,6 +197,14 @@ struct TransformFeedbackVarying : public sh::Varying ...@@ -197,6 +197,14 @@ struct TransformFeedbackVarying : public sh::Varying
GLuint arrayIndex; GLuint arrayIndex;
}; };
struct ImageBinding
{
ImageBinding(GLuint imageUnit, size_t count) : boundImageUnit(imageUnit), elementCount(count) {}
GLuint boundImageUnit;
size_t elementCount;
};
class ProgramState final : angle::NonCopyable class ProgramState final : angle::NonCopyable
{ {
public: public:
...@@ -234,8 +242,10 @@ class ProgramState final : angle::NonCopyable ...@@ -234,8 +242,10 @@ class ProgramState final : angle::NonCopyable
const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; } const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; }
const std::vector<UniformBlock> &getUniformBlocks() const { return mUniformBlocks; } const std::vector<UniformBlock> &getUniformBlocks() const { return mUniformBlocks; }
const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; } const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; }
const std::vector<ImageBinding> &getImageBindings() const { return mImageBindings; }
const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; } const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; } const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; }
const RangeUI &getImageUniformRange() const { return mImageUniformRange; }
const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const
{ {
...@@ -281,10 +291,14 @@ class ProgramState final : angle::NonCopyable ...@@ -281,10 +291,14 @@ class ProgramState final : angle::NonCopyable
std::vector<VariableLocation> mUniformLocations; std::vector<VariableLocation> mUniformLocations;
std::vector<UniformBlock> mUniformBlocks; std::vector<UniformBlock> mUniformBlocks;
RangeUI mSamplerUniformRange; RangeUI mSamplerUniformRange;
RangeUI mImageUniformRange;
// An array of the samplers that are used by the program // An array of the samplers that are used by the program
std::vector<gl::SamplerBinding> mSamplerBindings; std::vector<gl::SamplerBinding> mSamplerBindings;
// An array of the images that are used by the program
std::vector<gl::ImageBinding> mImageBindings;
std::vector<sh::OutputVariable> mOutputVariables; std::vector<sh::OutputVariable> mOutputVariables;
// TODO(jmadill): use unordered/hash map when available // TODO(jmadill): use unordered/hash map when available
std::map<int, VariableLocation> mOutputLocations; std::map<int, VariableLocation> mOutputLocations;
...@@ -460,6 +474,9 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -460,6 +474,9 @@ class Program final : angle::NonCopyable, public LabeledObject
{ {
return mState.mSamplerBindings; return mState.mSamplerBindings;
} }
const std::vector<ImageBinding> &getImageBindings() const { return mState.mImageBindings; }
const ProgramState &getState() const { return mState; } const ProgramState &getState() const { return mState; }
static bool linkValidateVariablesBase(InfoLog &infoLog, static bool linkValidateVariablesBase(InfoLog &infoLog,
...@@ -519,7 +536,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -519,7 +536,7 @@ class Program final : angle::NonCopyable, public LabeledObject
bool linkUniforms(const Context *context, bool linkUniforms(const Context *context,
InfoLog &infoLog, InfoLog &infoLog,
const Bindings &uniformLocationBindings); const Bindings &uniformLocationBindings);
void linkSamplerBindings(); void linkSamplerAndImageBindings();
bool areMatchingInterfaceBlocks(InfoLog &infoLog, bool areMatchingInterfaceBlocks(InfoLog &infoLog,
const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &vertexInterfaceBlock,
......
...@@ -146,6 +146,7 @@ void State::initialize(const Context *context, ...@@ -146,6 +146,7 @@ void State::initialize(const Context *context,
mAtomicCounterBuffers.resize(caps.maxAtomicCounterBufferBindings); mAtomicCounterBuffers.resize(caps.maxAtomicCounterBufferBindings);
mShaderStorageBuffers.resize(caps.maxShaderStorageBufferBindings); mShaderStorageBuffers.resize(caps.maxShaderStorageBufferBindings);
mImageUnits.resize(caps.maxImageUnits);
} }
if (extensions.eglImageExternal || extensions.eglStreamConsumerExternal) if (extensions.eglImageExternal || extensions.eglStreamConsumerExternal)
{ {
...@@ -202,6 +203,16 @@ void State::reset(const Context *context) ...@@ -202,6 +203,16 @@ void State::reset(const Context *context)
mSamplers[samplerIdx].set(context, nullptr); mSamplers[samplerIdx].set(context, nullptr);
} }
for (auto &imageUnit : mImageUnits)
{
imageUnit.texture.set(context, nullptr);
imageUnit.level = 0;
imageUnit.layered = false;
imageUnit.layer = 0;
imageUnit.access = GL_READ_ONLY;
imageUnit.format = GL_R32UI;
}
mArrayBuffer.set(context, nullptr); mArrayBuffer.set(context, nullptr);
mDrawIndirectBuffer.set(context, nullptr); mDrawIndirectBuffer.set(context, nullptr);
mRenderbuffer.set(context, nullptr); mRenderbuffer.set(context, nullptr);
...@@ -794,6 +805,20 @@ void State::detachTexture(const Context *context, const TextureMap &zeroTextures ...@@ -794,6 +805,20 @@ void State::detachTexture(const Context *context, const TextureMap &zeroTextures
} }
} }
for (auto &bindingImageUnit : mImageUnits)
{
if (bindingImageUnit.texture.id() == texture)
{
bindingImageUnit.texture.set(context, nullptr);
bindingImageUnit.level = 0;
bindingImageUnit.layered = false;
bindingImageUnit.layer = 0;
bindingImageUnit.access = GL_READ_ONLY;
bindingImageUnit.format = GL_R32UI;
break;
}
}
// [OpenGL ES 2.0.24] section 4.4 page 112: // [OpenGL ES 2.0.24] section 4.4 page 112:
// If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is
// as if Texture2DAttachment had been called, with a texture of 0, for each attachment point to which this // as if Texture2DAttachment had been called, with a texture of 0, for each attachment point to which this
...@@ -2174,4 +2199,26 @@ void State::setObjectDirty(GLenum target) ...@@ -2174,4 +2199,26 @@ void State::setObjectDirty(GLenum target)
} }
} }
void State::setImageUnit(const Context *context,
GLuint unit,
Texture *texture,
GLint level,
GLboolean layered,
GLint layer,
GLenum access,
GLenum format)
{
mImageUnits[unit].texture.set(context, texture);
mImageUnits[unit].level = level;
mImageUnits[unit].layered = layered;
mImageUnits[unit].layer = layer;
mImageUnits[unit].access = access;
mImageUnits[unit].format = format;
}
const ImageUnit &State::getImageUnit(GLuint unit) const
{
return mImageUnits[unit];
}
} // namespace gl } // namespace gl
...@@ -456,6 +456,17 @@ class State : angle::NonCopyable ...@@ -456,6 +456,17 @@ class State : angle::NonCopyable
void syncDirtyObject(const Context *context, GLenum target); void syncDirtyObject(const Context *context, GLenum target);
void setObjectDirty(GLenum target); void setObjectDirty(GLenum target);
void setImageUnit(const Context *context,
GLuint unit,
Texture *texture,
GLint level,
GLboolean layered,
GLint layer,
GLenum access,
GLenum format);
const ImageUnit &getImageUnit(GLuint unit) const;
private: private:
// Cached values from Context's caps // Cached values from Context's caps
GLuint mMaxDrawBuffers; GLuint mMaxDrawBuffers;
...@@ -512,6 +523,9 @@ class State : angle::NonCopyable ...@@ -512,6 +523,9 @@ class State : angle::NonCopyable
typedef std::vector<BindingPointer<Sampler>> SamplerBindingVector; typedef std::vector<BindingPointer<Sampler>> SamplerBindingVector;
SamplerBindingVector mSamplers; SamplerBindingVector mSamplers;
typedef std::vector<ImageUnit> ImageUnitVector;
ImageUnitVector mImageUnits;
typedef std::map<GLenum, BindingPointer<Query>> ActiveQueryMap; typedef std::map<GLenum, BindingPointer<Query>> ActiveQueryMap;
ActiveQueryMap mActiveQueries; ActiveQueryMap mActiveQueries;
......
...@@ -325,35 +325,45 @@ bool UniformLinker::flattenUniformsAndCheckCapsForShader( ...@@ -325,35 +325,45 @@ bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Shader *shader, Shader *shader,
GLuint maxUniformComponents, GLuint maxUniformComponents,
GLuint maxTextureImageUnits, GLuint maxTextureImageUnits,
GLuint maxImageUnits,
const std::string &componentsErrorMessage, const std::string &componentsErrorMessage,
const std::string &samplerErrorMessage, const std::string &samplerErrorMessage,
const std::string &imageErrorMessage,
std::vector<LinkedUniform> &samplerUniforms, std::vector<LinkedUniform> &samplerUniforms,
std::vector<LinkedUniform> &imageUniforms,
InfoLog &infoLog) InfoLog &infoLog)
{ {
VectorAndSamplerCount vasCount; ShaderUniformCount shaderUniformCount;
for (const sh::Uniform &uniform : shader->getUniforms(context)) for (const sh::Uniform &uniform : shader->getUniforms(context))
{ {
vasCount += flattenUniform(uniform, &samplerUniforms); shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms);
} }
if (vasCount.vectorCount > maxUniformComponents) if (shaderUniformCount.vectorCount > maxUniformComponents)
{ {
infoLog << componentsErrorMessage << maxUniformComponents << ")."; infoLog << componentsErrorMessage << maxUniformComponents << ").";
return false; return false;
} }
if (vasCount.samplerCount > maxTextureImageUnits) if (shaderUniformCount.samplerCount > maxTextureImageUnits)
{ {
infoLog << samplerErrorMessage << maxTextureImageUnits << ")."; infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
return false; return false;
} }
if (shaderUniformCount.imageCount > maxImageUnits)
{
infoLog << imageErrorMessage << maxImageUnits << ").";
return false;
}
return true; return true;
} }
bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog) bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
{ {
std::vector<LinkedUniform> samplerUniforms; std::vector<LinkedUniform> samplerUniforms;
std::vector<LinkedUniform> imageUniforms;
const Caps &caps = context->getCaps(); const Caps &caps = context->getCaps();
...@@ -364,10 +374,11 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog ...@@ -364,10 +374,11 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog
// TODO (mradev): check whether we need finer-grained component counting // TODO (mradev): check whether we need finer-grained component counting
if (!flattenUniformsAndCheckCapsForShader( if (!flattenUniformsAndCheckCapsForShader(
context, computeShader, caps.maxComputeUniformComponents / 4, context, computeShader, caps.maxComputeUniformComponents / 4,
caps.maxComputeTextureImageUnits, caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
"Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (", "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
"Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (", "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
samplerUniforms, infoLog)) "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (", samplerUniforms,
imageUniforms, infoLog))
{ {
return false; return false;
} }
...@@ -378,10 +389,11 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog ...@@ -378,10 +389,11 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog
if (!flattenUniformsAndCheckCapsForShader( if (!flattenUniformsAndCheckCapsForShader(
context, vertexShader, caps.maxVertexUniformVectors, context, vertexShader, caps.maxVertexUniformVectors,
caps.maxVertexTextureImageUnits, caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
"Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (", "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
"Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (", "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
samplerUniforms, infoLog)) "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (", samplerUniforms,
imageUniforms, infoLog))
{ {
return false; return false;
} }
...@@ -390,42 +402,48 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog ...@@ -390,42 +402,48 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog
if (!flattenUniformsAndCheckCapsForShader( if (!flattenUniformsAndCheckCapsForShader(
context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits, context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
caps.maxFragmentImageUniforms,
"Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (", "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
"Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (", samplerUniforms, "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
infoLog)) "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
samplerUniforms, imageUniforms, infoLog))
{ {
return false; return false;
} }
} }
mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end()); mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
return true; return true;
} }
UniformLinker::VectorAndSamplerCount UniformLinker::flattenUniform( UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
const sh::Uniform &uniform, const sh::Uniform &uniform,
std::vector<LinkedUniform> *samplerUniforms) std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms)
{ {
int location = uniform.location; int location = uniform.location;
VectorAndSamplerCount uniformVasCount = flattenUniformImpl( ShaderUniformCount shaderUniformCount =
uniform, uniform.name, samplerUniforms, uniform.staticUse, uniform.binding, &location); flattenUniformImpl(uniform, uniform.name, samplerUniforms, imageUniforms, uniform.staticUse,
uniform.binding, &location);
if (uniform.staticUse) if (uniform.staticUse)
{ {
return uniformVasCount; return shaderUniformCount;
} }
return VectorAndSamplerCount(); return ShaderUniformCount();
} }
UniformLinker::VectorAndSamplerCount UniformLinker::flattenUniformImpl( UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
const sh::ShaderVariable &uniform, const sh::ShaderVariable &uniform,
const std::string &fullName, const std::string &fullName,
std::vector<LinkedUniform> *samplerUniforms, std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
bool markStaticUse, bool markStaticUse,
int binding, int binding,
int *location) int *location)
{ {
ASSERT(location); ASSERT(location);
VectorAndSamplerCount vectorAndSamplerCount; ShaderUniformCount shaderUniformCount;
if (uniform.isStruct()) if (uniform.isStruct())
{ {
...@@ -438,22 +456,28 @@ UniformLinker::VectorAndSamplerCount UniformLinker::flattenUniformImpl( ...@@ -438,22 +456,28 @@ UniformLinker::VectorAndSamplerCount UniformLinker::flattenUniformImpl(
const sh::ShaderVariable &field = uniform.fields[fieldIndex]; const sh::ShaderVariable &field = uniform.fields[fieldIndex];
const std::string &fieldFullName = (fullName + elementString + "." + field.name); const std::string &fieldFullName = (fullName + elementString + "." + field.name);
vectorAndSamplerCount += flattenUniformImpl(field, fieldFullName, samplerUniforms, shaderUniformCount +=
markStaticUse, -1, location); flattenUniformImpl(field, fieldFullName, samplerUniforms, imageUniforms,
markStaticUse, -1, location);
} }
} }
return vectorAndSamplerCount; return shaderUniformCount;
} }
// Not a struct // Not a struct
bool isSampler = IsSamplerType(uniform.type); bool isSampler = IsSamplerType(uniform.type);
bool isImage = IsImageType(uniform.type);
std::vector<gl::LinkedUniform> *uniformList = &mUniforms; std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
if (isSampler) if (isSampler)
{ {
// Store sampler uniforms separately, so we'll append them to the end of the list. // Store sampler uniforms separately, so we'll append them to the end of the list.
uniformList = samplerUniforms; uniformList = samplerUniforms;
} }
else if (isImage)
{
uniformList = imageUniforms;
}
LinkedUniform *existingUniform = FindUniform(*uniformList, fullName); LinkedUniform *existingUniform = FindUniform(*uniformList, fullName);
if (existingUniform) if (existingUniform)
{ {
...@@ -481,18 +505,19 @@ UniformLinker::VectorAndSamplerCount UniformLinker::flattenUniformImpl( ...@@ -481,18 +505,19 @@ UniformLinker::VectorAndSamplerCount UniformLinker::flattenUniformImpl(
unsigned int elementCount = uniform.elementCount(); unsigned int elementCount = uniform.elementCount();
// Samplers aren't "real" uniforms, so they don't count towards register usage. // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
// Likewise, don't count "real" uniforms towards sampler count. // Likewise, don't count "real" uniforms towards sampler and image count.
vectorAndSamplerCount.vectorCount = shaderUniformCount.vectorCount =
(isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount)); ((isSampler || isImage) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0); shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
shaderUniformCount.imageCount = (isImage ? elementCount : 0);
if (*location != -1) if (*location != -1)
{ {
*location += elementCount; *location += elementCount;
} }
return vectorAndSamplerCount; return shaderUniformCount;
} }
} // namespace gl } // namespace gl
...@@ -30,21 +30,23 @@ class UniformLinker ...@@ -30,21 +30,23 @@ class UniformLinker
std::vector<VariableLocation> *uniformLocations); std::vector<VariableLocation> *uniformLocations);
private: private:
struct VectorAndSamplerCount struct ShaderUniformCount
{ {
VectorAndSamplerCount() : vectorCount(0), samplerCount(0) {} ShaderUniformCount() : vectorCount(0), samplerCount(0), imageCount(0) {}
VectorAndSamplerCount(const VectorAndSamplerCount &other) = default; ShaderUniformCount(const ShaderUniformCount &other) = default;
VectorAndSamplerCount &operator=(const VectorAndSamplerCount &other) = default; ShaderUniformCount &operator=(const ShaderUniformCount &other) = default;
VectorAndSamplerCount &operator+=(const VectorAndSamplerCount &other) ShaderUniformCount &operator+=(const ShaderUniformCount &other)
{ {
vectorCount += other.vectorCount; vectorCount += other.vectorCount;
samplerCount += other.samplerCount; samplerCount += other.samplerCount;
imageCount += other.imageCount;
return *this; return *this;
} }
unsigned int vectorCount; unsigned int vectorCount;
unsigned int samplerCount; unsigned int samplerCount;
unsigned int imageCount;
}; };
bool validateVertexAndFragmentUniforms(const Context *context, InfoLog &infoLog) const; bool validateVertexAndFragmentUniforms(const Context *context, InfoLog &infoLog) const;
...@@ -58,23 +60,29 @@ class UniformLinker ...@@ -58,23 +60,29 @@ class UniformLinker
Shader *shader, Shader *shader,
GLuint maxUniformComponents, GLuint maxUniformComponents,
GLuint maxTextureImageUnits, GLuint maxTextureImageUnits,
GLuint maxImageUnits,
const std::string &componentsErrorMessage, const std::string &componentsErrorMessage,
const std::string &samplerErrorMessage, const std::string &samplerErrorMessage,
const std::string &imageErrorMessage,
std::vector<LinkedUniform> &samplerUniforms, std::vector<LinkedUniform> &samplerUniforms,
std::vector<LinkedUniform> &imageUniforms,
InfoLog &infoLog); InfoLog &infoLog);
bool flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog); bool flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog);
VectorAndSamplerCount flattenUniform(const sh::Uniform &uniform, ShaderUniformCount flattenUniform(const sh::Uniform &uniform,
std::vector<LinkedUniform> *samplerUniforms); std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms);
// markStaticUse is given as a separate parameter because it is tracked here at struct // markStaticUse is given as a separate parameter because it is tracked here at struct
// granularity. // granularity.
VectorAndSamplerCount flattenUniformImpl(const sh::ShaderVariable &uniform, ShaderUniformCount flattenUniformImpl(const sh::ShaderVariable &uniform,
const std::string &fullName, const std::string &fullName,
std::vector<LinkedUniform> *samplerUniforms, std::vector<LinkedUniform> *samplerUniforms,
bool markStaticUse, std::vector<LinkedUniform> *imageUniforms,
int binding, bool markStaticUse,
int *location); int binding,
int *location);
bool indexUniforms(InfoLog &infoLog, const Program::Bindings &uniformLocationBindings); bool indexUniforms(InfoLog &infoLog, const Program::Bindings &uniformLocationBindings);
bool gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog, bool gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog,
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
namespace gl namespace gl
{ {
class Buffer; class Buffer;
class Texture;
enum PrimitiveType enum PrimitiveType
{ {
...@@ -237,6 +238,21 @@ struct DrawElementsIndirectCommand ...@@ -237,6 +238,21 @@ struct DrawElementsIndirectCommand
static_assert(sizeof(DrawElementsIndirectCommand) == 20, static_assert(sizeof(DrawElementsIndirectCommand) == 20,
"Unexpected size of DrawElementsIndirectCommand"); "Unexpected size of DrawElementsIndirectCommand");
struct ImageUnit
{
ImageUnit()
: texture(), level(0), layered(false), layer(0), access(GL_READ_ONLY), format(GL_R32UI)
{
}
BindingPointer<Texture> texture;
GLint level;
GLboolean layered;
GLint layer;
GLenum access;
GLenum format;
};
struct PixelStoreStateBase : private angle::NonCopyable struct PixelStoreStateBase : private angle::NonCopyable
{ {
BindingPointer<Buffer> pixelBuffer; BindingPointer<Buffer> pixelBuffer;
......
...@@ -50,6 +50,7 @@ StateManagerGL::StateManagerGL(const FunctionsGL *functions, const gl::Caps &ren ...@@ -50,6 +50,7 @@ StateManagerGL::StateManagerGL(const FunctionsGL *functions, const gl::Caps &ren
mTextureUnitIndex(0), mTextureUnitIndex(0),
mTextures(), mTextures(),
mSamplers(rendererCaps.maxCombinedTextureImageUnits, 0), mSamplers(rendererCaps.maxCombinedTextureImageUnits, 0),
mImages(rendererCaps.maxImageUnits, ImageUnitBinding()),
mTransformFeedback(0), mTransformFeedback(0),
mQueries(), mQueries(),
mPrevDrawTransformFeedback(nullptr), mPrevDrawTransformFeedback(nullptr),
...@@ -206,6 +207,15 @@ void StateManagerGL::deleteTexture(GLuint texture) ...@@ -206,6 +207,15 @@ void StateManagerGL::deleteTexture(GLuint texture)
} }
} }
for (size_t imageUnitIndex = 0; imageUnitIndex < mImages.size(); imageUnitIndex++)
{
if (mImages[imageUnitIndex].texture == texture)
{
bindImageTexture(static_cast<GLuint>(imageUnitIndex), 0, 0, false, 0, GL_READ_ONLY,
GL_R32UI);
}
}
mFunctions->deleteTextures(1, &texture); mFunctions->deleteTextures(1, &texture);
} }
} }
...@@ -407,6 +417,28 @@ void StateManagerGL::bindSampler(size_t unit, GLuint sampler) ...@@ -407,6 +417,28 @@ void StateManagerGL::bindSampler(size_t unit, GLuint sampler)
} }
} }
void StateManagerGL::bindImageTexture(GLuint unit,
GLuint texture,
GLint level,
GLboolean layered,
GLint layer,
GLenum access,
GLenum format)
{
auto &binding = mImages[unit];
if (binding.texture != texture || binding.level != level || binding.layered != layered ||
binding.layer != layer || binding.access != access || binding.format != format)
{
binding.texture = texture;
binding.level = level;
binding.layered = layered;
binding.layer = layer;
binding.access = access;
binding.format = format;
mFunctions->bindImageTexture(unit, texture, level, layered, layer, access, format);
}
}
void StateManagerGL::setPixelUnpackState(const gl::PixelUnpackState &unpack) void StateManagerGL::setPixelUnpackState(const gl::PixelUnpackState &unpack)
{ {
GLuint unpackBufferID = 0; GLuint unpackBufferID = 0;
...@@ -845,6 +877,32 @@ void StateManagerGL::setGenericShaderState(const gl::Context *context) ...@@ -845,6 +877,32 @@ void StateManagerGL::setGenericShaderState(const gl::Context *context)
} }
} }
} }
// TODO(xinghua.cao@intel.com): Track image units state with dirty bits to
// avoid update every draw call.
ASSERT(context->getClientVersion() >= gl::ES_3_1 || program->getImageBindings().size() == 0);
for (const gl::ImageBinding &imageUniform : program->getImageBindings())
{
for (size_t imageUnitIndex = 0; imageUnitIndex < imageUniform.elementCount;
imageUnitIndex++)
{
const gl::ImageUnit &imageUnit = glState.getImageUnit(
imageUniform.boundImageUnit + static_cast<GLuint>(imageUnitIndex));
const TextureGL *textureGL = SafeGetImplAs<TextureGL>(imageUnit.texture.get());
if (textureGL)
{
bindImageTexture(imageUniform.boundImageUnit + static_cast<GLuint>(imageUnitIndex),
textureGL->getTextureID(), imageUnit.level, imageUnit.layered,
imageUnit.layer, imageUnit.access, imageUnit.format);
}
else
{
bindImageTexture(imageUniform.boundImageUnit + static_cast<GLuint>(imageUnitIndex),
0, imageUnit.level, imageUnit.layered, imageUnit.layer,
imageUnit.access, imageUnit.format);
}
}
}
} }
gl::Error StateManagerGL::setGenericDrawState(const gl::Context *context) gl::Error StateManagerGL::setGenericDrawState(const gl::Context *context)
......
...@@ -56,6 +56,13 @@ class StateManagerGL final : angle::NonCopyable ...@@ -56,6 +56,13 @@ class StateManagerGL final : angle::NonCopyable
void activeTexture(size_t unit); void activeTexture(size_t unit);
void bindTexture(GLenum type, GLuint texture); void bindTexture(GLenum type, GLuint texture);
void bindSampler(size_t unit, GLuint sampler); void bindSampler(size_t unit, GLuint sampler);
void bindImageTexture(GLuint unit,
GLuint texture,
GLint level,
GLboolean layered,
GLint layer,
GLenum access,
GLenum format);
void bindFramebuffer(GLenum type, GLuint framebuffer); void bindFramebuffer(GLenum type, GLuint framebuffer);
void bindRenderbuffer(GLenum type, GLuint renderbuffer); void bindRenderbuffer(GLenum type, GLuint renderbuffer);
void bindTransformFeedback(GLenum type, GLuint transformFeedback); void bindTransformFeedback(GLenum type, GLuint transformFeedback);
...@@ -196,6 +203,22 @@ class StateManagerGL final : angle::NonCopyable ...@@ -196,6 +203,22 @@ class StateManagerGL final : angle::NonCopyable
std::map<GLenum, std::vector<GLuint>> mTextures; std::map<GLenum, std::vector<GLuint>> mTextures;
std::vector<GLuint> mSamplers; std::vector<GLuint> mSamplers;
struct ImageUnitBinding
{
ImageUnitBinding()
: texture(0), level(0), layered(false), layer(0), access(GL_READ_ONLY), format(GL_R32UI)
{
}
GLuint texture;
GLint level;
GLboolean layered;
GLint layer;
GLenum access;
GLenum format;
};
std::vector<ImageUnitBinding> mImages;
GLuint mTransformFeedback; GLuint mTransformFeedback;
std::map<GLenum, GLuint> mQueries; std::map<GLenum, GLuint> mQueries;
......
...@@ -816,4 +816,83 @@ bool ValidateDispatchCompute(Context *context, ...@@ -816,4 +816,83 @@ bool ValidateDispatchCompute(Context *context,
return true; return true;
} }
bool ValidateBindImageTexture(Context *context,
GLuint unit,
GLuint texture,
GLint level,
GLboolean layered,
GLint layer,
GLenum access,
GLenum format)
{
GLuint maxImageUnits = context->getCaps().maxImageUnits;
if (unit >= maxImageUnits)
{
context->handleError(InvalidValue()
<< "unit cannot be greater than or equal than MAX_IMAGE_UNITS = "
<< maxImageUnits);
return false;
}
if (level < 0)
{
context->handleError(InvalidValue() << "level is negative.");
return false;
}
if (layer < 0)
{
context->handleError(InvalidValue() << "layer is negative.");
return false;
}
if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE)
{
context->handleError(InvalidEnum() << "access is not one of the supported tokens.");
return false;
}
switch (format)
{
case GL_RGBA32F:
case GL_RGBA16F:
case GL_R32F:
case GL_RGBA32UI:
case GL_RGBA16UI:
case GL_RGBA8UI:
case GL_R32UI:
case GL_RGBA32I:
case GL_RGBA16I:
case GL_RGBA8I:
case GL_R32I:
case GL_RGBA8:
case GL_RGBA8_SNORM:
break;
default:
context->handleError(InvalidValue()
<< "format is not one of supported image unit formats.");
return false;
}
if (texture != 0)
{
Texture *tex = context->getTexture(texture);
if (tex == nullptr)
{
context->handleError(InvalidValue()
<< "texture is not the name of an existing texture object.");
return false;
}
if (!tex->getImmutableFormat())
{
context->handleError(InvalidOperation()
<< "texture is not the name of an immutable texture object.");
return false;
}
}
return true;
}
} // namespace gl } // namespace gl
...@@ -87,6 +87,15 @@ bool ValidateDispatchCompute(Context *context, ...@@ -87,6 +87,15 @@ bool ValidateDispatchCompute(Context *context,
GLuint numGroupsY, GLuint numGroupsY,
GLuint numGroupsZ); GLuint numGroupsZ);
bool ValidateBindImageTexture(Context *context,
GLuint unit,
GLuint texture,
GLint level,
GLboolean layered,
GLint layer,
GLenum access,
GLenum format);
} // namespace gl } // namespace gl
#endif // LIBANGLE_VALIDATION_ES31_H_ #endif // LIBANGLE_VALIDATION_ES31_H_
...@@ -964,11 +964,13 @@ void GL_APIENTRY BindImageTexture(GLuint unit, ...@@ -964,11 +964,13 @@ void GL_APIENTRY BindImageTexture(GLuint unit,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (texture != 0) if (!context->skipValidation() && !ValidateBindImageTexture(context, unit, texture, level,
layered, layer, access, format))
{ {
// Binding non-zero image textures is not implemented yet. return;
UNIMPLEMENTED();
} }
context->bindImageTexture(unit, texture, level, layered, layer, access, format);
} }
} }
......
...@@ -243,6 +243,79 @@ TEST_P(ComputeShaderTest, DispatchCompute) ...@@ -243,6 +243,79 @@ TEST_P(ComputeShaderTest, DispatchCompute)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Use image uniform to write texture in compute shader, and verify the content is expected.
TEST_P(ComputeShaderTest, BindImageTexture)
{
if (IsD3D11())
{
std::cout << "Test skipped on D3D11 because it is not implemented yet." << std::endl;
return;
}
GLTexture mTexture[2];
GLFramebuffer mFramebuffer;
const std::string csSource =
"#version 310 es\n"
"layout(local_size_x=2, local_size_y=2, local_size_z=1) in;\n"
"layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];"
"void main()\n"
"{\n"
" imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
"0, 0));"
" imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
"0, 0));"
"}\n";
ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
glUseProgram(program.get());
int width = 4, height = 2;
GLuint inputValues[] = {200, 200, 200, 200, 200, 200, 200, 200};
glBindTexture(GL_TEXTURE_2D, mTexture[0]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
inputValues);
EXPECT_GL_NO_ERROR();
glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
EXPECT_GL_NO_ERROR();
glBindTexture(GL_TEXTURE_2D, mTexture[1]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
inputValues);
EXPECT_GL_NO_ERROR();
glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
EXPECT_GL_NO_ERROR();
glDispatchCompute(2, 1, 1);
EXPECT_GL_NO_ERROR();
glUseProgram(0);
GLuint outputValues[2][8];
GLuint expectedValue = 100;
glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[0],
0);
EXPECT_GL_NO_ERROR();
glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[0]);
EXPECT_GL_NO_ERROR();
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[1],
0);
EXPECT_GL_NO_ERROR();
glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[1]);
EXPECT_GL_NO_ERROR();
for (int i = 0; i < width * height; i++)
{
EXPECT_EQ(expectedValue, outputValues[0][i]);
EXPECT_EQ(expectedValue, outputValues[1][i]);
}
}
// Check that it is not possible to create a compute shader when the context does not support ES // Check that it is not possible to create a compute shader when the context does not support ES
// 3.10 // 3.10
TEST_P(ComputeShaderTestES3, NotSupported) TEST_P(ComputeShaderTestES3, NotSupported)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment