Commit b3545b42 by Tim Van Patten Committed by Commit Bot

Get storage buffers/images from ProgramExecutable

Update StateCache::updateActiveShaderStorageBufferIndices() and StateCache::updateActiveImageUnitIndices to get the storage buffers and image bindings from the ProgramExecutable, respectively. This requires updating the ProgramPipeline's ProgramExecutable to build up its vector of buffers/images from each Program's ProgramExecutable. Bug: angleproject:4869 Test: VertexAttributeTestES31.UsePpoComputeShaderToUpdateVertexBuffer Test: SimpleStateChangeTestES31.InvalidateThenStorageWriteThenBlendPpo Change-Id: I68b7d23eedda910c3dcbf5f9c50b74b5e80134d8 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2327701 Commit-Queue: Tim Van Patten <timvp@google.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com>
parent 50442fac
...@@ -5678,6 +5678,10 @@ void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGr ...@@ -5678,6 +5678,10 @@ void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGr
angle::Result result = angle::Result result =
mImplementation->dispatchCompute(this, numGroupsX, numGroupsY, numGroupsZ); mImplementation->dispatchCompute(this, numGroupsX, numGroupsY, numGroupsZ);
// This must be called before convertPpoToComputeOrDraw() so it uses the PPO's compute values
// before convertPpoToComputeOrDraw() reverts the PPO back to graphics.
MarkShaderStorageUsage(this);
// We always assume PPOs are used for draws, until they aren't. If we just executed a dispatch // We always assume PPOs are used for draws, until they aren't. If we just executed a dispatch
// with a PPO, we need to convert it back to a "draw"-type. // with a PPO, we need to convert it back to a "draw"-type.
convertPpoToComputeOrDraw(false); convertPpoToComputeOrDraw(false);
...@@ -5686,8 +5690,6 @@ void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGr ...@@ -5686,8 +5690,6 @@ void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGr
{ {
return; return;
} }
MarkShaderStorageUsage(this);
} }
void Context::convertPpoToComputeOrDraw(bool isCompute) void Context::convertPpoToComputeOrDraw(bool isCompute)
...@@ -5700,6 +5702,10 @@ void Context::convertPpoToComputeOrDraw(bool isCompute) ...@@ -5700,6 +5702,10 @@ void Context::convertPpoToComputeOrDraw(bool isCompute)
pipeline->setDirtyBit(ProgramPipeline::DirtyBitType::DIRTY_BIT_DRAW_DISPATCH_CHANGE); pipeline->setDirtyBit(ProgramPipeline::DirtyBitType::DIRTY_BIT_DRAW_DISPATCH_CHANGE);
mState.mDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_PIPELINE); mState.mDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_PIPELINE);
mState.mDirtyBits.set(State::DirtyBitType::DIRTY_BIT_PROGRAM_EXECUTABLE); mState.mDirtyBits.set(State::DirtyBitType::DIRTY_BIT_PROGRAM_EXECUTABLE);
// The PPO's isCompute() has changed, so its ProgramExecutable will produce different
// results for things like getShaderStorageBlocks() or getImageBindings().
mStateCache.onProgramExecutableChange(this);
} }
} }
...@@ -8826,10 +8832,10 @@ void StateCache::updateVertexAttribTypesValidation(Context *context) ...@@ -8826,10 +8832,10 @@ void StateCache::updateVertexAttribTypesValidation(Context *context)
void StateCache::updateActiveShaderStorageBufferIndices(Context *context) void StateCache::updateActiveShaderStorageBufferIndices(Context *context)
{ {
mCachedActiveShaderStorageBufferIndices.reset(); mCachedActiveShaderStorageBufferIndices.reset();
Program *program = context->getState().getProgram(); const ProgramExecutable *executable = context->getState().getProgramExecutable();
if (program) if (executable)
{ {
for (const InterfaceBlock &block : program->getState().getShaderStorageBlocks()) for (const InterfaceBlock &block : executable->getShaderStorageBlocks())
{ {
mCachedActiveShaderStorageBufferIndices.set(block.binding); mCachedActiveShaderStorageBufferIndices.set(block.binding);
} }
...@@ -8839,10 +8845,10 @@ void StateCache::updateActiveShaderStorageBufferIndices(Context *context) ...@@ -8839,10 +8845,10 @@ void StateCache::updateActiveShaderStorageBufferIndices(Context *context)
void StateCache::updateActiveImageUnitIndices(Context *context) void StateCache::updateActiveImageUnitIndices(Context *context)
{ {
mCachedActiveImageUnitIndices.reset(); mCachedActiveImageUnitIndices.reset();
Program *program = context->getState().getProgram(); const ProgramExecutable *executable = context->getState().getProgramExecutable();
if (program) if (executable)
{ {
for (const ImageBinding &imageBinding : program->getState().getImageBindings()) for (const ImageBinding &imageBinding : executable->getImageBindings())
{ {
if (imageBinding.unreferenced) if (imageBinding.unreferenced)
{ {
......
...@@ -1464,7 +1464,7 @@ angle::Result Program::linkImpl(const Context *context) ...@@ -1464,7 +1464,7 @@ angle::Result Program::linkImpl(const Context *context)
{ {
mState.mExecutable->mResources.reset(new ProgramLinkedResources( mState.mExecutable->mResources.reset(new ProgramLinkedResources(
0, PackMode::ANGLE_RELAXED, &mState.mExecutable->mUniformBlocks, 0, PackMode::ANGLE_RELAXED, &mState.mExecutable->mUniformBlocks,
&mState.mExecutable->mUniforms, &mState.mExecutable->mShaderStorageBlocks, &mState.mExecutable->mUniforms, &mState.mExecutable->mComputeShaderStorageBlocks,
&mState.mBufferVariables, &mState.mExecutable->mAtomicCounterBuffers)); &mState.mBufferVariables, &mState.mExecutable->mAtomicCounterBuffers));
GLuint combinedImageUniforms = 0u; GLuint combinedImageUniforms = 0u;
...@@ -1521,7 +1521,7 @@ angle::Result Program::linkImpl(const Context *context) ...@@ -1521,7 +1521,7 @@ angle::Result Program::linkImpl(const Context *context)
mState.mExecutable->mResources.reset(new ProgramLinkedResources( mState.mExecutable->mResources.reset(new ProgramLinkedResources(
static_cast<GLuint>(data.getCaps().maxVaryingVectors), packMode, static_cast<GLuint>(data.getCaps().maxVaryingVectors), packMode,
&mState.mExecutable->mUniformBlocks, &mState.mExecutable->mUniforms, &mState.mExecutable->mUniformBlocks, &mState.mExecutable->mUniforms,
&mState.mExecutable->mShaderStorageBlocks, &mState.mBufferVariables, &mState.mExecutable->mGraphicsShaderStorageBlocks, &mState.mBufferVariables,
&mState.mExecutable->mAtomicCounterBuffers)); &mState.mExecutable->mAtomicCounterBuffers));
if (!linkAttributes(context, infoLog)) if (!linkAttributes(context, infoLog))
...@@ -1649,9 +1649,9 @@ void Program::resolveLinkImpl(const Context *context) ...@@ -1649,9 +1649,9 @@ void Program::resolveLinkImpl(const Context *context)
ASSERT(mLinked); ASSERT(mLinked);
// Mark implementation-specific unreferenced uniforms as ignored. // Mark implementation-specific unreferenced uniforms as ignored.
std::vector<ImageBinding> *imageBindings = getExecutable().getImageBindings();
mProgram->markUnusedUniformLocations(&mState.mUniformLocations, mProgram->markUnusedUniformLocations(&mState.mUniformLocations,
&mState.mExecutable->mSamplerBindings, &mState.mExecutable->mSamplerBindings, imageBindings);
&mState.mExecutable->mImageBindings);
// Must be called after markUnusedUniformLocations. // Must be called after markUnusedUniformLocations.
postResolveLink(context); postResolveLink(context);
...@@ -2908,8 +2908,9 @@ GLuint Program::getImageUniformBinding(const VariableLocation &uniformLocation) ...@@ -2908,8 +2908,9 @@ GLuint Program::getImageUniformBinding(const VariableLocation &uniformLocation)
{ {
ASSERT(!mLinkingState); ASSERT(!mLinkingState);
GLuint imageIndex = mState.getImageIndexFromUniformIndex(uniformLocation.index); GLuint imageIndex = mState.getImageIndexFromUniformIndex(uniformLocation.index);
const std::vector<GLuint> &boundImageUnits =
mState.mExecutable->mImageBindings[imageIndex].boundImageUnits; const std::vector<ImageBinding> &imageBindings = getExecutable().getImageBindings();
const std::vector<GLuint> &boundImageUnits = imageBindings[imageIndex].boundImageUnits;
return boundImageUnits[uniformLocation.arrayIndex]; return boundImageUnits[uniformLocation.arrayIndex];
} }
...@@ -3698,6 +3699,11 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms) ...@@ -3698,6 +3699,11 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms)
mState.mExecutable->mImageUniformRange = RangeUI(low, high); mState.mExecutable->mImageUniformRange = RangeUI(low, high);
*combinedImageUniforms = 0u; *combinedImageUniforms = 0u;
// The Program is still linking, so getExecutable().isCompute() isn't accurate yet.
bool hasComputeShader = mState.mAttachedShaders[ShaderType::Compute] != nullptr;
std::vector<ImageBinding> &imageBindings = hasComputeShader
? mState.mExecutable->mComputeImageBindings
: mState.mExecutable->mGraphicsImageBindings;
// If uniform is a image type, insert it into the mImageBindings array. // If uniform is a image type, insert it into the mImageBindings array.
for (unsigned int imageIndex : mState.mExecutable->getImageUniformRange()) for (unsigned int imageIndex : mState.mExecutable->getImageUniformRange())
{ {
...@@ -3708,12 +3714,11 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms) ...@@ -3708,12 +3714,11 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms)
auto &imageUniform = mState.mExecutable->getUniforms()[imageIndex]; auto &imageUniform = mState.mExecutable->getUniforms()[imageIndex];
if (imageUniform.binding == -1) if (imageUniform.binding == -1)
{ {
mState.mExecutable->mImageBindings.emplace_back( imageBindings.emplace_back(ImageBinding(imageUniform.getBasicTypeElementCount()));
ImageBinding(imageUniform.getBasicTypeElementCount()));
} }
else else
{ {
mState.mExecutable->mImageBindings.emplace_back( imageBindings.emplace_back(
ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount(), false)); ImageBinding(imageUniform.binding, imageUniform.getBasicTypeElementCount(), false));
} }
...@@ -5110,6 +5115,8 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi ...@@ -5110,6 +5115,8 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
stream.writeInt(0); stream.writeInt(0);
} }
mState.mExecutable->save(&stream);
const auto &computeLocalSize = mState.getComputeShaderLocalSize(); const auto &computeLocalSize = mState.getComputeShaderLocalSize();
stream.writeInt(computeLocalSize[0]); stream.writeInt(computeLocalSize[0]);
...@@ -5270,8 +5277,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi ...@@ -5270,8 +5277,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
stream.writeInt(mState.getAtomicCounterUniformRange().low()); stream.writeInt(mState.getAtomicCounterUniformRange().low());
stream.writeInt(mState.getAtomicCounterUniformRange().high()); stream.writeInt(mState.getAtomicCounterUniformRange().high());
mState.mExecutable->save(&stream);
mProgram->save(context, &stream); mProgram->save(context, &stream);
ASSERT(binaryOut); ASSERT(binaryOut);
...@@ -5307,6 +5312,8 @@ angle::Result Program::deserialize(const Context *context, ...@@ -5307,6 +5312,8 @@ angle::Result Program::deserialize(const Context *context,
return angle::Result::Incomplete; return angle::Result::Incomplete;
} }
mState.mExecutable->load(&stream);
mState.mComputeShaderLocalSize[0] = stream.readInt<int>(); mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
mState.mComputeShaderLocalSize[1] = stream.readInt<int>(); mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
mState.mComputeShaderLocalSize[2] = stream.readInt<int>(); mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
...@@ -5393,7 +5400,14 @@ angle::Result Program::deserialize(const Context *context, ...@@ -5393,7 +5400,14 @@ angle::Result Program::deserialize(const Context *context,
{ {
InterfaceBlock shaderStorageBlock; InterfaceBlock shaderStorageBlock;
LoadInterfaceBlock(&stream, &shaderStorageBlock); LoadInterfaceBlock(&stream, &shaderStorageBlock);
mState.mExecutable->mShaderStorageBlocks.push_back(shaderStorageBlock); if (getExecutable().isCompute())
{
mState.mExecutable->mComputeShaderStorageBlocks.push_back(shaderStorageBlock);
}
else
{
mState.mExecutable->mGraphicsShaderStorageBlocks.push_back(shaderStorageBlock);
}
} }
unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>(); unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
...@@ -5509,7 +5523,14 @@ angle::Result Program::deserialize(const Context *context, ...@@ -5509,7 +5523,14 @@ angle::Result Program::deserialize(const Context *context,
{ {
imageBinding.boundImageUnits[i] = stream.readInt<unsigned int>(); imageBinding.boundImageUnits[i] = stream.readInt<unsigned int>();
} }
mState.mExecutable->mImageBindings.emplace_back(imageBinding); if (getExecutable().isCompute())
{
mState.mExecutable->mComputeImageBindings.emplace_back(imageBinding);
}
else
{
mState.mExecutable->mGraphicsImageBindings.emplace_back(imageBinding);
}
} }
unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>(); unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
...@@ -5524,8 +5545,6 @@ angle::Result Program::deserialize(const Context *context, ...@@ -5524,8 +5545,6 @@ angle::Result Program::deserialize(const Context *context,
mState.updateTransformFeedbackStrides(); mState.updateTransformFeedbackStrides();
} }
mState.mExecutable->load(&stream);
postResolveLink(context); postResolveLink(context);
mState.mExecutable->updateCanDrawWith(); mState.mExecutable->updateCanDrawWith();
......
...@@ -264,7 +264,7 @@ class ProgramState final : angle::NonCopyable ...@@ -264,7 +264,7 @@ class ProgramState final : angle::NonCopyable
} }
const std::vector<ImageBinding> &getImageBindings() const const std::vector<ImageBinding> &getImageBindings() const
{ {
return mExecutable->getImageBindings(); return getExecutable().getImageBindings();
} }
const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; } const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
const RangeUI &getDefaultUniformRange() const { return mExecutable->getDefaultUniformRange(); } const RangeUI &getDefaultUniformRange() const { return mExecutable->getDefaultUniformRange(); }
...@@ -740,7 +740,7 @@ class Program final : public LabeledObject, public angle::Subject ...@@ -740,7 +740,7 @@ class Program final : public LabeledObject, public angle::Subject
const std::vector<ImageBinding> &getImageBindings() const const std::vector<ImageBinding> &getImageBindings() const
{ {
ASSERT(!mLinkingState); ASSERT(!mLinkingState);
return mState.mExecutable->getImageBindings(); return getExecutable().getImageBindings();
} }
const sh::WorkGroupSize &getComputeShaderLocalSize() const; const sh::WorkGroupSize &getComputeShaderLocalSize() const;
PrimitiveMode getGeometryShaderInputPrimitiveType() const; PrimitiveMode getGeometryShaderInputPrimitiveType() const;
......
...@@ -72,7 +72,8 @@ ProgramExecutable::ProgramExecutable(const ProgramExecutable &other) ...@@ -72,7 +72,8 @@ ProgramExecutable::ProgramExecutable(const ProgramExecutable &other)
mUniformBlocks(other.mUniformBlocks), mUniformBlocks(other.mUniformBlocks),
mAtomicCounterBuffers(other.mAtomicCounterBuffers), mAtomicCounterBuffers(other.mAtomicCounterBuffers),
mImageUniformRange(other.mImageUniformRange), mImageUniformRange(other.mImageUniformRange),
mShaderStorageBlocks(other.mShaderStorageBlocks), mComputeShaderStorageBlocks(other.mComputeShaderStorageBlocks),
mGraphicsShaderStorageBlocks(other.mGraphicsShaderStorageBlocks),
mPipelineHasGraphicsUniformBuffers(other.mPipelineHasGraphicsUniformBuffers), mPipelineHasGraphicsUniformBuffers(other.mPipelineHasGraphicsUniformBuffers),
mPipelineHasComputeUniformBuffers(other.mPipelineHasComputeUniformBuffers), mPipelineHasComputeUniformBuffers(other.mPipelineHasComputeUniformBuffers),
mPipelineHasGraphicsStorageBuffers(other.mPipelineHasGraphicsStorageBuffers), mPipelineHasGraphicsStorageBuffers(other.mPipelineHasGraphicsStorageBuffers),
...@@ -111,12 +112,14 @@ void ProgramExecutable::reset() ...@@ -111,12 +112,14 @@ void ProgramExecutable::reset()
mLinkedTransformFeedbackVaryings.clear(); mLinkedTransformFeedbackVaryings.clear();
mUniforms.clear(); mUniforms.clear();
mUniformBlocks.clear(); mUniformBlocks.clear();
mShaderStorageBlocks.clear(); mComputeShaderStorageBlocks.clear();
mGraphicsShaderStorageBlocks.clear();
mAtomicCounterBuffers.clear(); mAtomicCounterBuffers.clear();
mOutputVariables.clear(); mOutputVariables.clear();
mOutputLocations.clear(); mOutputLocations.clear();
mSamplerBindings.clear(); mSamplerBindings.clear();
mImageBindings.clear(); mComputeImageBindings.clear();
mGraphicsImageBindings.clear();
mPipelineHasGraphicsUniformBuffers = false; mPipelineHasGraphicsUniformBuffers = false;
mPipelineHasComputeUniformBuffers = false; mPipelineHasComputeUniformBuffers = false;
...@@ -233,8 +236,17 @@ bool ProgramExecutable::hasUniformBuffers() const ...@@ -233,8 +236,17 @@ bool ProgramExecutable::hasUniformBuffers() const
bool ProgramExecutable::hasStorageBuffers() const bool ProgramExecutable::hasStorageBuffers() const
{ {
return !getShaderStorageBlocks().empty() || return (isCompute() ? hasComputeStorageBuffers() : hasGraphicsStorageBuffers());
(isCompute() ? mPipelineHasComputeStorageBuffers : mPipelineHasGraphicsStorageBuffers); }
bool ProgramExecutable::hasGraphicsStorageBuffers() const
{
return !mGraphicsShaderStorageBlocks.empty() || mPipelineHasGraphicsStorageBuffers;
}
bool ProgramExecutable::hasComputeStorageBuffers() const
{
return !mComputeShaderStorageBlocks.empty() || mPipelineHasComputeStorageBuffers;
} }
bool ProgramExecutable::hasAtomicCounterBuffers() const bool ProgramExecutable::hasAtomicCounterBuffers() const
...@@ -246,8 +258,17 @@ bool ProgramExecutable::hasAtomicCounterBuffers() const ...@@ -246,8 +258,17 @@ bool ProgramExecutable::hasAtomicCounterBuffers() const
bool ProgramExecutable::hasImages() const bool ProgramExecutable::hasImages() const
{ {
return !getImageBindings().empty() || return (isCompute() ? hasComputeImages() : hasGraphicsImages());
(isCompute() ? mPipelineHasComputeImages : mPipelineHasGraphicsImages); }
bool ProgramExecutable::hasGraphicsImages() const
{
return !mGraphicsImageBindings.empty() || mPipelineHasGraphicsImages;
}
bool ProgramExecutable::hasComputeImages() const
{
return !mComputeImageBindings.empty() || mPipelineHasComputeImages;
} }
GLuint ProgramExecutable::getUniformIndexFromImageIndex(GLuint imageIndex) const GLuint ProgramExecutable::getUniformIndexFromImageIndex(GLuint imageIndex) const
...@@ -295,9 +316,10 @@ void ProgramExecutable::updateActiveSamplers(const ProgramState &programState) ...@@ -295,9 +316,10 @@ void ProgramExecutable::updateActiveSamplers(const ProgramState &programState)
void ProgramExecutable::updateActiveImages(const ProgramExecutable &executable) void ProgramExecutable::updateActiveImages(const ProgramExecutable &executable)
{ {
for (uint32_t imageIndex = 0; imageIndex < mImageBindings.size(); ++imageIndex) const std::vector<ImageBinding> *imageBindings = getImageBindings();
for (uint32_t imageIndex = 0; imageIndex < imageBindings->size(); ++imageIndex)
{ {
const gl::ImageBinding &imageBinding = mImageBindings[imageIndex]; const gl::ImageBinding &imageBinding = imageBindings->at(imageIndex);
if (imageBinding.unreferenced) if (imageBinding.unreferenced)
{ {
continue; continue;
......
...@@ -194,8 +194,12 @@ class ProgramExecutable final : public angle::Subject ...@@ -194,8 +194,12 @@ class ProgramExecutable final : public angle::Subject
bool hasTextures() const; bool hasTextures() const;
bool hasUniformBuffers() const; bool hasUniformBuffers() const;
bool hasStorageBuffers() const; bool hasStorageBuffers() const;
bool hasGraphicsStorageBuffers() const;
bool hasComputeStorageBuffers() const;
bool hasAtomicCounterBuffers() const; bool hasAtomicCounterBuffers() const;
bool hasImages() const; bool hasImages() const;
bool hasGraphicsImages() const;
bool hasComputeImages() const;
bool hasTransformFeedbackOutput() const bool hasTransformFeedbackOutput() const
{ {
return !getLinkedTransformFeedbackVaryings().empty(); return !getLinkedTransformFeedbackVaryings().empty();
...@@ -216,7 +220,14 @@ class ProgramExecutable final : public angle::Subject ...@@ -216,7 +220,14 @@ class ProgramExecutable final : public angle::Subject
const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; } const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; } const std::vector<InterfaceBlock> &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 std::vector<ImageBinding> &getImageBindings() const
{
return isCompute() ? mComputeImageBindings : mGraphicsImageBindings;
}
std::vector<ImageBinding> *getImageBindings()
{
return isCompute() ? &mComputeImageBindings : &mGraphicsImageBindings;
}
const RangeUI &getDefaultUniformRange() const { return mDefaultUniformRange; } const RangeUI &getDefaultUniformRange() const { return mDefaultUniformRange; }
const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; } const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; }
const RangeUI &getImageUniformRange() const { return mImageUniformRange; } const RangeUI &getImageUniformRange() const { return mImageUniformRange; }
...@@ -232,8 +243,10 @@ class ProgramExecutable final : public angle::Subject ...@@ -232,8 +243,10 @@ class ProgramExecutable final : public angle::Subject
} }
GLuint getShaderStorageBlockBinding(GLuint blockIndex) const GLuint getShaderStorageBlockBinding(GLuint blockIndex) const
{ {
ASSERT(blockIndex < mShaderStorageBlocks.size()); ASSERT((isCompute() && (blockIndex < mComputeShaderStorageBlocks.size())) ||
return mShaderStorageBlocks[blockIndex].binding; (!isCompute() && (blockIndex < mGraphicsShaderStorageBlocks.size())));
return isCompute() ? mComputeShaderStorageBlocks[blockIndex].binding
: mGraphicsShaderStorageBlocks[blockIndex].binding;
} }
const std::vector<GLsizei> &getTransformFeedbackStrides() const const std::vector<GLsizei> &getTransformFeedbackStrides() const
{ {
...@@ -245,7 +258,7 @@ class ProgramExecutable final : public angle::Subject ...@@ -245,7 +258,7 @@ class ProgramExecutable final : public angle::Subject
} }
const std::vector<InterfaceBlock> &getShaderStorageBlocks() const const std::vector<InterfaceBlock> &getShaderStorageBlocks() const
{ {
return mShaderStorageBlocks; return isCompute() ? mComputeShaderStorageBlocks : mGraphicsShaderStorageBlocks;
} }
const LinkedUniform &getUniformByIndex(GLuint index) const const LinkedUniform &getUniformByIndex(GLuint index) const
{ {
...@@ -265,7 +278,9 @@ class ProgramExecutable final : public angle::Subject ...@@ -265,7 +278,9 @@ class ProgramExecutable final : public angle::Subject
ANGLE_INLINE GLuint getActiveShaderStorageBlockCount() const ANGLE_INLINE GLuint getActiveShaderStorageBlockCount() const
{ {
return static_cast<GLuint>(mShaderStorageBlocks.size()); size_t shaderStorageBlocksSize =
isCompute() ? mComputeShaderStorageBlocks.size() : mGraphicsShaderStorageBlocks.size();
return static_cast<GLuint>(shaderStorageBlocksSize);
} }
GLuint getUniformIndexFromImageIndex(GLuint imageIndex) const; GLuint getUniformIndexFromImageIndex(GLuint imageIndex) const;
...@@ -351,13 +366,15 @@ class ProgramExecutable final : public angle::Subject ...@@ -351,13 +366,15 @@ class ProgramExecutable final : public angle::Subject
std::vector<InterfaceBlock> mUniformBlocks; std::vector<InterfaceBlock> mUniformBlocks;
std::vector<AtomicCounterBuffer> mAtomicCounterBuffers; std::vector<AtomicCounterBuffer> mAtomicCounterBuffers;
RangeUI mImageUniformRange; RangeUI mImageUniformRange;
std::vector<InterfaceBlock> mShaderStorageBlocks; std::vector<InterfaceBlock> mComputeShaderStorageBlocks;
std::vector<InterfaceBlock> mGraphicsShaderStorageBlocks;
// An array of the samplers that are used by the program // An array of the samplers that are used by the program
std::vector<SamplerBinding> mSamplerBindings; std::vector<SamplerBinding> mSamplerBindings;
// An array of the images that are used by the program // An array of the images that are used by the program
std::vector<ImageBinding> mImageBindings; std::vector<ImageBinding> mComputeImageBindings;
std::vector<ImageBinding> mGraphicsImageBindings;
// TODO: http://anglebug.com/3570: Remove mPipelineHas*UniformBuffers once PPO's have valid data // TODO: http://anglebug.com/3570: Remove mPipelineHas*UniformBuffers once PPO's have valid data
// in mUniformBlocks // in mUniformBlocks
......
...@@ -263,6 +263,75 @@ void ProgramPipeline::updateTransformFeedbackMembers() ...@@ -263,6 +263,75 @@ void ProgramPipeline::updateTransformFeedbackMembers()
vertexExecutable.mLinkedTransformFeedbackVaryings; vertexExecutable.mLinkedTransformFeedbackVaryings;
} }
void ProgramPipeline::updateShaderStorageBlocks()
{
mState.mExecutable->mComputeShaderStorageBlocks.clear();
mState.mExecutable->mGraphicsShaderStorageBlocks.clear();
// Only copy the storage blocks from each Program in the PPO once, since each Program could
// contain multiple shader stages.
ShaderBitSet handledStages;
for (const gl::ShaderType shaderType : kAllGraphicsShaderTypes)
{
const Program *shaderProgram = getShaderProgram(shaderType);
if (shaderProgram && !handledStages.test(shaderType))
{
// Only add each Program's blocks once.
handledStages |= shaderProgram->getExecutable().getLinkedShaderStages();
for (const InterfaceBlock &block :
shaderProgram->getExecutable().getShaderStorageBlocks())
{
mState.mExecutable->mGraphicsShaderStorageBlocks.emplace_back(block);
}
}
}
const Program *computeProgram = getShaderProgram(ShaderType::Compute);
if (computeProgram)
{
for (const InterfaceBlock &block : computeProgram->getExecutable().getShaderStorageBlocks())
{
mState.mExecutable->mComputeShaderStorageBlocks.emplace_back(block);
}
}
}
void ProgramPipeline::updateImageBindings()
{
mState.mExecutable->mComputeImageBindings.clear();
mState.mExecutable->mGraphicsImageBindings.clear();
// Only copy the storage blocks from each Program in the PPO once, since each Program could
// contain multiple shader stages.
ShaderBitSet handledStages;
for (const gl::ShaderType shaderType : kAllGraphicsShaderTypes)
{
const Program *shaderProgram = getShaderProgram(shaderType);
if (shaderProgram && !handledStages.test(shaderType))
{
// Only add each Program's blocks once.
handledStages |= shaderProgram->getExecutable().getLinkedShaderStages();
for (const ImageBinding &imageBinding : shaderProgram->getState().getImageBindings())
{
mState.mExecutable->mGraphicsImageBindings.emplace_back(imageBinding);
}
}
}
const Program *computeProgram = getShaderProgram(ShaderType::Compute);
if (computeProgram)
{
for (const ImageBinding &imageBinding : computeProgram->getState().getImageBindings())
{
mState.mExecutable->mComputeImageBindings.emplace_back(imageBinding);
}
}
}
void ProgramPipeline::updateHasBooleans() void ProgramPipeline::updateHasBooleans()
{ {
// Need to check all of the shader stages, not just linked, so we handle Compute correctly. // Need to check all of the shader stages, not just linked, so we handle Compute correctly.
...@@ -277,7 +346,7 @@ void ProgramPipeline::updateHasBooleans() ...@@ -277,7 +346,7 @@ void ProgramPipeline::updateHasBooleans()
{ {
mState.mExecutable->mPipelineHasGraphicsUniformBuffers = true; mState.mExecutable->mPipelineHasGraphicsUniformBuffers = true;
} }
if (executable.hasStorageBuffers()) if (executable.hasGraphicsStorageBuffers())
{ {
mState.mExecutable->mPipelineHasGraphicsStorageBuffers = true; mState.mExecutable->mPipelineHasGraphicsStorageBuffers = true;
} }
...@@ -293,7 +362,7 @@ void ProgramPipeline::updateHasBooleans() ...@@ -293,7 +362,7 @@ void ProgramPipeline::updateHasBooleans()
{ {
mState.mExecutable->mPipelineHasGraphicsTextures = true; mState.mExecutable->mPipelineHasGraphicsTextures = true;
} }
if (executable.hasImages()) if (executable.hasGraphicsImages())
{ {
mState.mExecutable->mPipelineHasGraphicsImages = true; mState.mExecutable->mPipelineHasGraphicsImages = true;
} }
...@@ -309,7 +378,7 @@ void ProgramPipeline::updateHasBooleans() ...@@ -309,7 +378,7 @@ void ProgramPipeline::updateHasBooleans()
{ {
mState.mExecutable->mPipelineHasComputeUniformBuffers = true; mState.mExecutable->mPipelineHasComputeUniformBuffers = true;
} }
if (executable.hasStorageBuffers()) if (executable.hasComputeStorageBuffers())
{ {
mState.mExecutable->mPipelineHasComputeStorageBuffers = true; mState.mExecutable->mPipelineHasComputeStorageBuffers = true;
} }
...@@ -325,7 +394,7 @@ void ProgramPipeline::updateHasBooleans() ...@@ -325,7 +394,7 @@ void ProgramPipeline::updateHasBooleans()
{ {
mState.mExecutable->mPipelineHasComputeTextures = true; mState.mExecutable->mPipelineHasComputeTextures = true;
} }
if (executable.hasImages()) if (executable.hasComputeImages())
{ {
mState.mExecutable->mPipelineHasComputeImages = true; mState.mExecutable->mPipelineHasComputeImages = true;
} }
...@@ -339,9 +408,13 @@ void ProgramPipeline::updateExecutable() ...@@ -339,9 +408,13 @@ void ProgramPipeline::updateExecutable()
// Vertex Shader ProgramExecutable properties // Vertex Shader ProgramExecutable properties
updateExecutableAttributes(); updateExecutableAttributes();
updateTransformFeedbackMembers(); updateTransformFeedbackMembers();
updateShaderStorageBlocks();
updateImageBindings();
// All Shader ProgramExecutable properties // All Shader ProgramExecutable properties
mState.updateExecutableTextures(); mState.updateExecutableTextures();
// Must be last, since it queries things updated by earlier functions
updateHasBooleans(); updateHasBooleans();
} }
......
...@@ -161,6 +161,8 @@ class ProgramPipeline final : public RefCountObject<ProgramPipelineID>, ...@@ -161,6 +161,8 @@ class ProgramPipeline final : public RefCountObject<ProgramPipelineID>,
void updateLinkedShaderStages(); void updateLinkedShaderStages();
void updateExecutableAttributes(); void updateExecutableAttributes();
void updateTransformFeedbackMembers(); void updateTransformFeedbackMembers();
void updateShaderStorageBlocks();
void updateImageBindings();
void updateHasBooleans(); void updateHasBooleans();
void updateExecutable(); void updateExecutable();
......
...@@ -2803,6 +2803,70 @@ void main() ...@@ -2803,6 +2803,70 @@ void main()
blendAndVerifyColor(GLColor32F(1.0f, 0.0f, 0.0f, 0.5f), GLColor(127, 127, 127, 191)); blendAndVerifyColor(GLColor32F(1.0f, 0.0f, 0.0f, 0.5f), GLColor(127, 127, 127, 191));
} }
// Tests that invalidate then compute write works inside PPO
TEST_P(SimpleStateChangeTestES31, InvalidateThenStorageWriteThenBlendPpo)
{
// Fails on AMD OpenGL Windows. This configuration isn't maintained.
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsOpenGL());
// PPOs are only supported in the Vulkan backend
ANGLE_SKIP_TEST_IF(!isVulkanRenderer());
constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1) in;
layout (rgba8, binding = 1) writeonly uniform highp image2D dstImage;
void main()
{
imageStore(dstImage, ivec2(gl_GlobalInvocationID.xy), vec4(0.0f, 1.0f, 1.0f, 1.0f));
})";
GLProgramPipeline pipeline;
ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, program);
EXPECT_GL_NO_ERROR();
glBindProgramPipeline(pipeline);
EXPECT_GL_NO_ERROR();
glUseProgram(0);
// Create the framebuffer texture
GLTexture renderTarget;
glBindTexture(GL_TEXTURE_2D, renderTarget);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
glBindImageTexture(1, renderTarget, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
// Write to the texture with compute once. In the Vulkan backend, this will make sure the image
// is already created with STORAGE usage and avoids recreate later.
glDispatchCompute(1, 1, 1);
EXPECT_GL_NO_ERROR();
// Create the framebuffer that will be invalidated
GLFramebuffer drawFBO;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTarget,
0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
EXPECT_GL_NO_ERROR();
// Clear the framebuffer and invalidate it.
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLenum invalidateAttachment = GL_COLOR_ATTACHMENT0;
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &invalidateAttachment);
EXPECT_GL_NO_ERROR();
// Write to it with a compute shader
glDispatchCompute(1, 1, 1);
EXPECT_GL_NO_ERROR();
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
// Blend into the framebuffer, then verify that the framebuffer should have had cyan.
glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFBO);
blendAndVerifyColor(GLColor32F(1.0f, 0.0f, 0.0f, 0.5f), GLColor(127, 127, 127, 191));
}
// Tests that sub-invalidate then draw works. // Tests that sub-invalidate then draw works.
TEST_P(SimpleStateChangeTestES3, SubInvalidateThenDraw) TEST_P(SimpleStateChangeTestES3, SubInvalidateThenDraw)
{ {
......
...@@ -1846,6 +1846,152 @@ void main() ...@@ -1846,6 +1846,152 @@ void main()
checkPixelsUnEqual(); checkPixelsUnEqual();
} }
TEST_P(VertexAttributeTestES31, UsePpoComputeShaderToUpdateVertexBuffer)
{
// PPOs are only supported in the Vulkan backend
ANGLE_SKIP_TEST_IF(!isVulkanRenderer());
initTest();
constexpr char kComputeShader[] =
R"(#version 310 es
layout(local_size_x=24) in;
layout(std430, binding = 0) buffer buf {
uint outData[24];
};
void main()
{
outData[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
})";
glUseProgram(mProgram);
GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
GLuint hi = std::numeric_limits<GLuint>::max();
std::array<GLuint, kVertexCount> inputData = {
{0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
std::array<GLfloat, kVertexCount> expectedData;
for (size_t i = 0; i < kVertexCount; i++)
{
expectedData[i] = Normalize(inputData[i]);
}
// Normalized unsigned int attribute will be classified as translated static attribute.
TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
GLint typeSize = 4;
GLsizei dataSize = kVertexCount * TypeStride(data.type);
GLBuffer testBuffer;
glBindBuffer(GL_ARRAY_BUFFER, testBuffer);
glBufferData(GL_ARRAY_BUFFER, dataSize, data.inputData, GL_STATIC_DRAW);
glVertexAttribPointer(mTestAttrib, typeSize, data.type, data.normalized, 0,
reinterpret_cast<void *>(data.bufferOffset));
glEnableVertexAttribArray(mTestAttrib);
glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
glBufferData(GL_ARRAY_BUFFER, dataSize, data.expectedData, GL_STATIC_DRAW);
glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, nullptr);
// Draw twice to make sure that all static attributes dirty bits are synced.
glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
// Modify the testBuffer using a raw buffer
GLProgramPipeline pipeline;
ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
glProgramParameteri(computeProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, computeProgram);
EXPECT_GL_NO_ERROR();
glBindProgramPipeline(pipeline);
EXPECT_GL_NO_ERROR();
glUseProgram(0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
// Draw again to verify that testBuffer has been changed.
glUseProgram(mProgram);
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_GL_NO_ERROR();
checkPixelsUnEqual();
}
TEST_P(VertexAttributeTestES31, UseComputeShaderToUpdateVertexBufferSamePpo)
{
// PPOs are only supported in the Vulkan backend
ANGLE_SKIP_TEST_IF(!isVulkanRenderer());
initTest();
constexpr char kComputeShader[] =
R"(#version 310 es
layout(local_size_x=24) in;
layout(std430, binding = 0) buffer buf {
uint outData[24];
};
void main()
{
outData[gl_LocalInvocationIndex] = gl_LocalInvocationIndex;
})";
// Mark the program separable and re-link it so it can be bound to the PPO.
glProgramParameteri(mProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
glLinkProgram(mProgram);
mProgram = CheckLinkStatusAndReturnProgram(mProgram, true);
GLProgramPipeline pipeline;
EXPECT_GL_NO_ERROR();
glBindProgramPipeline(pipeline);
glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, mProgram);
EXPECT_GL_NO_ERROR();
glUseProgram(0);
GLuint mid = std::numeric_limits<GLuint>::max() >> 1;
GLuint hi = std::numeric_limits<GLuint>::max();
std::array<GLuint, kVertexCount> inputData = {
{0, 1, 2, 3, 254, 255, 256, mid - 1, mid, mid + 1, hi - 2, hi - 1, hi}};
std::array<GLfloat, kVertexCount> expectedData;
for (size_t i = 0; i < kVertexCount; i++)
{
expectedData[i] = Normalize(inputData[i]);
}
// Normalized unsigned int attribute will be classified as translated static attribute.
TestData data(GL_UNSIGNED_INT, GL_TRUE, Source::BUFFER, inputData.data(), expectedData.data());
GLint typeSize = 4;
GLsizei dataSize = kVertexCount * TypeStride(data.type);
GLBuffer testBuffer;
glBindBuffer(GL_ARRAY_BUFFER, testBuffer);
glBufferData(GL_ARRAY_BUFFER, dataSize, data.inputData, GL_STATIC_DRAW);
glVertexAttribPointer(mTestAttrib, typeSize, data.type, data.normalized, 0,
reinterpret_cast<void *>(data.bufferOffset));
glEnableVertexAttribArray(mTestAttrib);
glBindBuffer(GL_ARRAY_BUFFER, mExpectedBuffer);
glBufferData(GL_ARRAY_BUFFER, dataSize, data.expectedData, GL_STATIC_DRAW);
glVertexAttribPointer(mExpectedAttrib, typeSize, GL_FLOAT, GL_FALSE, 0, nullptr);
// Draw twice to make sure that all static attributes dirty bits are synced.
glDrawArrays(GL_TRIANGLES, 0, 6);
glDrawArrays(GL_TRIANGLES, 0, 6);
checkPixels();
// Modify the testBuffer using a raw buffer
ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kComputeShader);
glProgramParameteri(computeProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, computeProgram);
EXPECT_GL_NO_ERROR();
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
// Draw again to verify that testBuffer has been changed.
glUseProgram(mProgram);
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_GL_NO_ERROR();
checkPixelsUnEqual();
}
// Verify that using VertexAttribBinding after VertexAttribPointer won't mess up the draw. // Verify that using VertexAttribBinding after VertexAttribPointer won't mess up the draw.
TEST_P(VertexAttributeTestES31, ChangeAttribBindingAfterVertexAttribPointer) TEST_P(VertexAttributeTestES31, ChangeAttribBindingAfterVertexAttribPointer)
{ {
......
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