Commit 29fba5e0 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Prepare for variable-stage pipelines

Compute (single-stage pipeline) is upcoming, but this change prepares GlslangWrapper to handle any number of stages (mostly). Additionally, this change binds each resource to each stage based on whether it's active, so that we don't hit the per-stage limit of resources by binding every resource to every stage. Bug: angleproject:3633 Bug: angleproject:3562 Change-Id: Ifebf691482846e0371c6e314f514226a4cfee258 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1689330Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent a1754dc8
...@@ -722,6 +722,18 @@ void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block) ...@@ -722,6 +722,18 @@ void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block)
LoadShaderVariableBuffer(stream, block); LoadShaderVariableBuffer(stream, block);
} }
size_t CountUniqueBlocks(const std::vector<InterfaceBlock> &blocks)
{
size_t count = 0;
for (const InterfaceBlock &block : blocks)
{
if (!block.isArray || block.arrayElement == 0)
{
++count;
}
}
return count;
}
} // anonymous namespace } // anonymous namespace
// Saves the linking context for later use in resolveLink(). // Saves the linking context for later use in resolveLink().
...@@ -955,7 +967,7 @@ ImageBinding::~ImageBinding() = default; ...@@ -955,7 +967,7 @@ ImageBinding::~ImageBinding() = default;
// ProgramState implementation. // ProgramState implementation.
ProgramState::ProgramState() ProgramState::ProgramState()
: mLabel(), : mLabel(),
mAttachedShaders({}), mAttachedShaders{},
mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS), mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
mMaxActiveAttribLocation(0), mMaxActiveAttribLocation(0),
mSamplerUniformRange(0, 0), mSamplerUniformRange(0, 0),
...@@ -991,6 +1003,16 @@ Shader *ProgramState::getAttachedShader(ShaderType shaderType) const ...@@ -991,6 +1003,16 @@ Shader *ProgramState::getAttachedShader(ShaderType shaderType) const
return mAttachedShaders[shaderType]; return mAttachedShaders[shaderType];
} }
size_t ProgramState::getUniqueUniformBlockCount() const
{
return CountUniqueBlocks(mUniformBlocks);
}
size_t ProgramState::getUniqueStorageBlockCount() const
{
return CountUniqueBlocks(mShaderStorageBlocks);
}
GLuint ProgramState::getUniformIndexFromName(const std::string &name) const GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
{ {
return GetResourceIndexFromName(mUniforms, name); return GetResourceIndexFromName(mUniforms, name);
...@@ -1029,6 +1051,12 @@ GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const ...@@ -1029,6 +1051,12 @@ GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
return uniformIndex - mSamplerUniformRange.low(); return uniformIndex - mSamplerUniformRange.low();
} }
GLuint ProgramState::getUniformIndexFromSamplerIndex(GLuint samplerIndex) const
{
ASSERT(samplerIndex < mSamplerUniformRange.length());
return samplerIndex + mSamplerUniformRange.low();
}
bool ProgramState::isImageUniformIndex(GLuint index) const bool ProgramState::isImageUniformIndex(GLuint index) const
{ {
return mImageUniformRange.contains(index); return mImageUniformRange.contains(index);
...@@ -1040,6 +1068,12 @@ GLuint ProgramState::getImageIndexFromUniformIndex(GLuint uniformIndex) const ...@@ -1040,6 +1068,12 @@ GLuint ProgramState::getImageIndexFromUniformIndex(GLuint uniformIndex) const
return uniformIndex - mImageUniformRange.low(); return uniformIndex - mImageUniformRange.low();
} }
GLuint ProgramState::getUniformIndexFromImageIndex(GLuint imageIndex) const
{
ASSERT(imageIndex < mImageUniformRange.length());
return imageIndex + mImageUniformRange.low();
}
GLuint ProgramState::getAttributeLocation(const std::string &name) const GLuint ProgramState::getAttributeLocation(const std::string &name) const
{ {
for (const sh::Attribute &attribute : mAttributes) for (const sh::Attribute &attribute : mAttributes)
...@@ -1433,6 +1467,8 @@ angle::Result Program::link(const Context *context) ...@@ -1433,6 +1467,8 @@ angle::Result Program::link(const Context *context)
mState.updateTransformFeedbackStrides(); mState.updateTransformFeedbackStrides();
} }
updateLinkedShaderStages();
mLinkingState.reset(new LinkingState()); mLinkingState.reset(new LinkingState());
mLinkingState->context = context; mLinkingState->context = context;
mLinkingState->linkingFromBinary = false; mLinkingState->linkingFromBinary = false;
...@@ -1474,7 +1510,6 @@ void Program::resolveLinkImpl(const Context *context) ...@@ -1474,7 +1510,6 @@ void Program::resolveLinkImpl(const Context *context)
// According to GLES 3.0/3.1 spec for LinkProgram and UseProgram, // According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
// Only successfully linked program can replace the executables. // Only successfully linked program can replace the executables.
ASSERT(mLinked); ASSERT(mLinked);
updateLinkedShaderStages();
// Mark implementation-specific unreferenced uniforms as ignored. // Mark implementation-specific unreferenced uniforms as ignored.
mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings, mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings,
......
...@@ -359,13 +359,19 @@ class ProgramState final : angle::NonCopyable ...@@ -359,13 +359,19 @@ class ProgramState final : angle::NonCopyable
return mAtomicCounterBuffers; return mAtomicCounterBuffers;
} }
// Count the number of uniform and storage buffer declarations, counting arrays as one.
size_t getUniqueUniformBlockCount() const;
size_t getUniqueStorageBlockCount() const;
GLuint getUniformIndexFromName(const std::string &name) const; GLuint getUniformIndexFromName(const std::string &name) const;
GLuint getUniformIndexFromLocation(GLint location) const; GLuint getUniformIndexFromLocation(GLint location) const;
Optional<GLuint> getSamplerIndex(GLint location) const; Optional<GLuint> getSamplerIndex(GLint location) const;
bool isSamplerUniformIndex(GLuint index) const; bool isSamplerUniformIndex(GLuint index) const;
GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const; GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const;
GLuint getUniformIndexFromSamplerIndex(GLuint samplerIndex) const;
bool isImageUniformIndex(GLuint index) const; bool isImageUniformIndex(GLuint index) const;
GLuint getImageIndexFromUniformIndex(GLuint uniformIndex) const; GLuint getImageIndexFromUniformIndex(GLuint uniformIndex) const;
GLuint getUniformIndexFromImageIndex(GLuint imageIndex) const;
GLuint getAttributeLocation(const std::string &name) const; GLuint getAttributeLocation(const std::string &name) const;
GLuint getBufferVariableIndexFromName(const std::string &name) const; GLuint getBufferVariableIndexFromName(const std::string &name) const;
...@@ -374,6 +380,11 @@ class ProgramState final : angle::NonCopyable ...@@ -374,6 +380,11 @@ class ProgramState final : angle::NonCopyable
bool usesMultiview() const { return mNumViews != -1; } bool usesMultiview() const { return mNumViews != -1; }
const ShaderBitSet &getLinkedShaderStages() const { return mLinkedShaderStages; } const ShaderBitSet &getLinkedShaderStages() const { return mLinkedShaderStages; }
bool hasLinkedShaderStage(ShaderType shaderType) const
{
return mLinkedShaderStages.test(shaderType);
}
size_t getLinkedShaderStageCount() const { return mLinkedShaderStages.count(); }
bool hasAttachedShader() const; bool hasAttachedShader() const;
......
...@@ -410,7 +410,7 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor ...@@ -410,7 +410,7 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor
bool isSampler = IsSamplerType(variable.type); bool isSampler = IsSamplerType(variable.type);
bool isImage = IsImageType(variable.type); bool isImage = IsImageType(variable.type);
bool isAtomicCounter = IsAtomicCounterType(variable.type); bool isAtomicCounter = IsAtomicCounterType(variable.type);
std::vector<gl::LinkedUniform> *uniformList = mUniforms; std::vector<LinkedUniform> *uniformList = mUniforms;
if (isSampler) if (isSampler)
{ {
uniformList = mSamplerUniforms; uniformList = mSamplerUniforms;
...@@ -618,7 +618,7 @@ bool InterfaceBlockInfo::getBlockSize(const std::string &name, ...@@ -618,7 +618,7 @@ bool InterfaceBlockInfo::getBlockSize(const std::string &name,
size_t *sizeOut) size_t *sizeOut)
{ {
size_t nameLengthWithoutArrayIndex; size_t nameLengthWithoutArrayIndex;
gl::ParseArrayIndex(name, &nameLengthWithoutArrayIndex); ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex); std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
auto sizeIter = mBlockSizes.find(baseName); auto sizeIter = mBlockSizes.find(baseName);
if (sizeIter == mBlockSizes.end()) if (sizeIter == mBlockSizes.end())
...@@ -699,7 +699,7 @@ bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const ...@@ -699,7 +699,7 @@ bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
// Check that uniforms defined in the graphics shaders are identical // Check that uniforms defined in the graphics shaders are identical
std::map<std::string, ShaderUniform> linkedUniforms; std::map<std::string, ShaderUniform> linkedUniforms;
for (ShaderType shaderType : kAllGraphicsShaderTypes) for (const ShaderType shaderType : kAllGraphicsShaderTypes)
{ {
Shader *currentShader = mState.getAttachedShader(shaderType); Shader *currentShader = mState.getAttachedShader(shaderType);
if (currentShader) if (currentShader)
...@@ -988,7 +988,7 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoL ...@@ -988,7 +988,7 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoL
std::vector<LinkedUniform> atomicCounterUniforms; std::vector<LinkedUniform> atomicCounterUniforms;
std::vector<UnusedUniform> unusedUniforms; std::vector<UnusedUniform> unusedUniforms;
for (ShaderType shaderType : AllShaderTypes()) for (const ShaderType shaderType : AllShaderTypes())
{ {
Shader *shader = mState.getAttachedShader(shaderType); Shader *shader = mState.getAttachedShader(shaderType);
if (!shader) if (!shader)
...@@ -1050,7 +1050,7 @@ void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize, ...@@ -1050,7 +1050,7 @@ void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
std::set<std::string> visitedList; std::set<std::string> visitedList;
for (ShaderType shaderType : AllShaderTypes()) for (const ShaderType shaderType : AllShaderTypes())
{ {
if (!mShaderBlocks[shaderType]) if (!mShaderBlocks[shaderType])
{ {
...@@ -1242,14 +1242,14 @@ ProgramLinkedResources::ProgramLinkedResources( ...@@ -1242,14 +1242,14 @@ ProgramLinkedResources::ProgramLinkedResources(
ProgramLinkedResources::~ProgramLinkedResources() = default; ProgramLinkedResources::~ProgramLinkedResources() = default;
void ProgramLinkedResourcesLinker::linkResources(const gl::ProgramState &programState, void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
const gl::ProgramLinkedResources &resources) const const ProgramLinkedResources &resources) const
{ {
// Gather uniform interface block info. // Gather uniform interface block info.
InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory); InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory);
for (gl::ShaderType shaderType : gl::AllShaderTypes()) for (const ShaderType shaderType : AllShaderTypes())
{ {
gl::Shader *shader = programState.getAttachedShader(shaderType); Shader *shader = programState.getAttachedShader(shaderType);
if (shader) if (shader)
{ {
uniformBlockInfo.getShaderBlockInfo(shader->getUniformBlocks()); uniformBlockInfo.getShaderBlockInfo(shader->getUniformBlocks());
...@@ -1272,9 +1272,9 @@ void ProgramLinkedResourcesLinker::linkResources(const gl::ProgramState &program ...@@ -1272,9 +1272,9 @@ void ProgramLinkedResourcesLinker::linkResources(const gl::ProgramState &program
// Gather storage bufer interface block info. // Gather storage bufer interface block info.
InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory); InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory);
for (gl::ShaderType shaderType : gl::AllShaderTypes()) for (const ShaderType shaderType : AllShaderTypes())
{ {
gl::Shader *shader = programState.getAttachedShader(shaderType); Shader *shader = programState.getAttachedShader(shaderType);
if (shader) if (shader)
{ {
shaderStorageBlockInfo.getShaderBlockInfo(shader->getShaderStorageBlocks()); shaderStorageBlockInfo.getShaderBlockInfo(shader->getShaderStorageBlocks());
...@@ -1303,12 +1303,12 @@ void ProgramLinkedResourcesLinker::linkResources(const gl::ProgramState &program ...@@ -1303,12 +1303,12 @@ void ProgramLinkedResourcesLinker::linkResources(const gl::ProgramState &program
} }
void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap( void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
const gl::ProgramState &programState, const ProgramState &programState,
std::map<int, unsigned int> &sizeMapOut) const std::map<int, unsigned int> &sizeMapOut) const
{ {
for (unsigned int index : programState.getAtomicCounterUniformRange()) for (unsigned int index : programState.getAtomicCounterUniformRange())
{ {
const gl::LinkedUniform &glUniform = programState.getUniforms()[index]; const LinkedUniform &glUniform = programState.getUniforms()[index];
auto &bufferDataSize = sizeMapOut[glUniform.binding]; auto &bufferDataSize = sizeMapOut[glUniform.binding];
......
...@@ -232,11 +232,11 @@ class ProgramLinkedResourcesLinker final : angle::NonCopyable ...@@ -232,11 +232,11 @@ class ProgramLinkedResourcesLinker final : angle::NonCopyable
: mCustomEncoderFactory(customEncoderFactory) : mCustomEncoderFactory(customEncoderFactory)
{} {}
void linkResources(const gl::ProgramState &programState, void linkResources(const ProgramState &programState,
const gl::ProgramLinkedResources &resources) const; const ProgramLinkedResources &resources) const;
private: private:
void getAtomicCounterBufferSizeMap(const gl::ProgramState &programState, void getAtomicCounterBufferSizeMap(const ProgramState &programState,
std::map<int, unsigned int> &sizeMapOut) const; std::map<int, unsigned int> &sizeMapOut) const;
CustomBlockLayoutEncoderFactory *mCustomEncoderFactory; CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
......
...@@ -26,12 +26,6 @@ void ActiveVariable::setActive(ShaderType shaderType, bool used) ...@@ -26,12 +26,6 @@ void ActiveVariable::setActive(ShaderType shaderType, bool used)
mActiveUseBits.set(shaderType, used); mActiveUseBits.set(shaderType, used);
} }
bool ActiveVariable::isActive(ShaderType shaderType) const
{
ASSERT(shaderType != ShaderType::InvalidEnum);
return mActiveUseBits[shaderType];
}
void ActiveVariable::unionReferencesWith(const ActiveVariable &other) void ActiveVariable::unionReferencesWith(const ActiveVariable &other)
{ {
mActiveUseBits |= other.mActiveUseBits; mActiveUseBits |= other.mActiveUseBits;
......
...@@ -31,7 +31,12 @@ struct ActiveVariable ...@@ -31,7 +31,12 @@ struct ActiveVariable
ShaderType getFirstShaderTypeWhereActive() const; ShaderType getFirstShaderTypeWhereActive() const;
void setActive(ShaderType shaderType, bool used); void setActive(ShaderType shaderType, bool used);
void unionReferencesWith(const ActiveVariable &other); void unionReferencesWith(const ActiveVariable &other);
bool isActive(ShaderType shaderType) const; bool isActive(ShaderType shaderType) const
{
ASSERT(shaderType != ShaderType::InvalidEnum);
return mActiveUseBits[shaderType];
}
ShaderBitSet activeShaders() const { return mActiveUseBits; }
GLuint activeShaderCount() const; GLuint activeShaderCount() const;
private: private:
......
...@@ -444,6 +444,11 @@ constexpr size_t kCubeFaceCount = 6; ...@@ -444,6 +444,11 @@ constexpr size_t kCubeFaceCount = 6;
using TextureMap = angle::PackedEnumMap<TextureType, BindingPointer<Texture>>; using TextureMap = angle::PackedEnumMap<TextureType, BindingPointer<Texture>>;
// ShaderVector can contain one item per shader. It differs from ShaderMap in that the values are
// not indexed by ShaderType.
template <typename T>
using ShaderVector = angle::FixedVector<T, static_cast<size_t>(ShaderType::EnumCount)>;
template <typename T> template <typename T>
using AttachmentArray = std::array<T, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>; using AttachmentArray = std::array<T, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>;
......
...@@ -44,6 +44,8 @@ constexpr char kParamsBegin = '('; ...@@ -44,6 +44,8 @@ constexpr char kParamsBegin = '(';
constexpr char kParamsEnd = ')'; constexpr char kParamsEnd = ')';
constexpr char kUniformQualifier[] = "uniform"; constexpr char kUniformQualifier[] = "uniform";
constexpr char kSSBOQualifier[] = "buffer"; constexpr char kSSBOQualifier[] = "buffer";
constexpr char kUnusedBlockSubstitution[] = "struct";
constexpr char kUnusedUniformSubstitution[] = "// ";
constexpr char kVersionDefine[] = "#version 450 core\n"; constexpr char kVersionDefine[] = "#version 450 core\n";
constexpr char kLineRasterDefine[] = R"(#version 450 core constexpr char kLineRasterDefine[] = R"(#version 450 core
...@@ -489,6 +491,8 @@ void GenerateTransformFeedbackOutputs(const gl::ProgramState &programState, ...@@ -489,6 +491,8 @@ void GenerateTransformFeedbackOutputs(const gl::ProgramState &programState,
void AssignAttributeLocations(const gl::ProgramState &programState, void AssignAttributeLocations(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource) IntermediateShaderSource *vertexSource)
{ {
ASSERT(vertexSource != nullptr);
// Parse attribute locations and replace them in the vertex shader. // Parse attribute locations and replace them in the vertex shader.
// See corresponding code in OutputVulkanGLSL.cpp. // See corresponding code in OutputVulkanGLSL.cpp.
for (const sh::Attribute &attribute : programState.getAttributes()) for (const sh::Attribute &attribute : programState.getAttributes())
...@@ -506,6 +510,8 @@ void AssignAttributeLocations(const gl::ProgramState &programState, ...@@ -506,6 +510,8 @@ void AssignAttributeLocations(const gl::ProgramState &programState,
void AssignOutputLocations(const gl::ProgramState &programState, void AssignOutputLocations(const gl::ProgramState &programState,
IntermediateShaderSource *fragmentSource) IntermediateShaderSource *fragmentSource)
{ {
ASSERT(fragmentSource != nullptr);
// Parse output locations and replace them in the fragment shader. // Parse output locations and replace them in the fragment shader.
// See corresponding code in OutputVulkanGLSL.cpp. // See corresponding code in OutputVulkanGLSL.cpp.
// TODO(syoussefi): Add support for EXT_blend_func_extended. http://anglebug.com/3385 // TODO(syoussefi): Add support for EXT_blend_func_extended. http://anglebug.com/3385
...@@ -540,8 +546,8 @@ void AssignOutputLocations(const gl::ProgramState &programState, ...@@ -540,8 +546,8 @@ void AssignOutputLocations(const gl::ProgramState &programState,
} }
void AssignVaryingLocations(const gl::ProgramLinkedResources &resources, void AssignVaryingLocations(const gl::ProgramLinkedResources &resources,
IntermediateShaderSource *vertexSource, IntermediateShaderSource *outStageSource,
IntermediateShaderSource *fragmentSource) IntermediateShaderSource *inStageSource)
{ {
// Assign varying locations. // Assign varying locations.
for (const gl::PackedVaryingRegister &varyingReg : resources.varyingPacking.getRegisterList()) for (const gl::PackedVaryingRegister &varyingReg : resources.varyingPacking.getRegisterList())
...@@ -579,28 +585,28 @@ void AssignVaryingLocations(const gl::ProgramLinkedResources &resources, ...@@ -579,28 +585,28 @@ void AssignVaryingLocations(const gl::ProgramLinkedResources &resources,
const std::string &name = const std::string &name =
varying.isStructField() ? varying.parentStructName : varying.varying->name; varying.isStructField() ? varying.parentStructName : varying.varying->name;
vertexSource->insertLayoutSpecifier(name, locationString); outStageSource->insertLayoutSpecifier(name, locationString);
fragmentSource->insertLayoutSpecifier(name, locationString); inStageSource->insertLayoutSpecifier(name, locationString);
const char *vsQualifier = "out"; const char *outQualifier = "out";
const char *fsQualifier = "in"; const char *inQualifier = "in";
switch (varying.interpolation) switch (varying.interpolation)
{ {
case sh::INTERPOLATION_SMOOTH: case sh::INTERPOLATION_SMOOTH:
break; break;
case sh::INTERPOLATION_CENTROID: case sh::INTERPOLATION_CENTROID:
vsQualifier = "centroid out"; outQualifier = "centroid out";
fsQualifier = "centroid in"; inQualifier = "centroid in";
break; break;
case sh::INTERPOLATION_FLAT: case sh::INTERPOLATION_FLAT:
vsQualifier = "flat out"; outQualifier = "flat out";
fsQualifier = "flat in"; inQualifier = "flat in";
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
vertexSource->insertQualifierSpecifier(name, vsQualifier); outStageSource->insertQualifierSpecifier(name, outQualifier);
fragmentSource->insertQualifierSpecifier(name, fsQualifier); inStageSource->insertQualifierSpecifier(name, inQualifier);
} }
// Substitute layout and qualifier strings for the position varying. Use the first free // Substitute layout and qualifier strings for the position varying. Use the first free
...@@ -610,125 +616,152 @@ void AssignVaryingLocations(const gl::ProgramLinkedResources &resources, ...@@ -610,125 +616,152 @@ void AssignVaryingLocations(const gl::ProgramLinkedResources &resources,
layoutStream << "location = " << (resources.varyingPacking.getMaxSemanticIndex() + 1); layoutStream << "location = " << (resources.varyingPacking.getMaxSemanticIndex() + 1);
const std::string layout = layoutStream.str(); const std::string layout = layoutStream.str();
vertexSource->insertLayoutSpecifier(kVaryingName, layout); outStageSource->insertLayoutSpecifier(kVaryingName, layout);
fragmentSource->insertLayoutSpecifier(kVaryingName, layout); inStageSource->insertLayoutSpecifier(kVaryingName, layout);
vertexSource->insertQualifierSpecifier(kVaryingName, "out"); outStageSource->insertQualifierSpecifier(kVaryingName, "out");
fragmentSource->insertQualifierSpecifier(kVaryingName, "in"); inStageSource->insertQualifierSpecifier(kVaryingName, "in");
} }
void AssignUniformLocations(IntermediateShaderSource *vertexSource, void AssignUniformBindings(const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
IntermediateShaderSource *fragmentSource)
{ {
// Bind the default uniforms for vertex and fragment shaders. // Bind the default uniforms for vertex and fragment shaders.
// See corresponding code in OutputVulkanGLSL.cpp. // See corresponding code in OutputVulkanGLSL.cpp.
const std::string driverUniformsDescriptorSet =
"set = " + Str(kDriverUniformsDescriptorSetIndex);
const std::string uniformsDescriptorSet = "set = " + Str(kUniformsAndXfbDescriptorSetIndex); const std::string uniformsDescriptorSet = "set = " + Str(kUniformsAndXfbDescriptorSetIndex);
std::string vertexDefaultUniformsBinding =
uniformsDescriptorSet + ", binding = " + Str(kVertexUniformsBindingIndex);
std::string fragmentDefaultUniformsBinding =
uniformsDescriptorSet + ", binding = " + Str(kFragmentUniformsBindingIndex);
constexpr char kDefaultUniformsBlockName[] = "defaultUniforms"; constexpr char kDefaultUniformsBlockName[] = "defaultUniforms";
vertexSource->insertLayoutSpecifier(kDefaultUniformsBlockName, vertexDefaultUniformsBinding); size_t bindingIndex = 0;
fragmentSource->insertLayoutSpecifier(kDefaultUniformsBlockName, for (IntermediateShaderSource *shaderSource : shaderSources)
fragmentDefaultUniformsBinding); {
if (shaderSource)
{
std::string defaultUniformsBinding =
uniformsDescriptorSet + ", binding = " + Str(bindingIndex++);
shaderSource->insertLayoutSpecifier(kDefaultUniformsBlockName, defaultUniformsBinding);
}
}
if (shaderSources[gl::ShaderType::Compute] != nullptr)
{
// Compute doesn't need driver uniforms.
return;
}
// Substitute layout and qualifier strings for the driver uniforms block. // Substitute layout and qualifier strings for the driver uniforms block.
const std::string driverBlockLayoutString = driverUniformsDescriptorSet + ", binding = 0"; const std::string driverBlockLayoutString =
"set = " + Str(kDriverUniformsDescriptorSetIndex) + ", binding = 0";
constexpr char kDriverBlockName[] = "ANGLEUniformBlock"; constexpr char kDriverBlockName[] = "ANGLEUniformBlock";
vertexSource->insertLayoutSpecifier(kDriverBlockName, driverBlockLayoutString);
fragmentSource->insertLayoutSpecifier(kDriverBlockName, driverBlockLayoutString);
vertexSource->insertQualifierSpecifier(kDriverBlockName, kUniformQualifier); for (IntermediateShaderSource *shaderSource : shaderSources)
fragmentSource->insertQualifierSpecifier(kDriverBlockName, kUniformQualifier); {
if (shaderSource)
{
shaderSource->insertLayoutSpecifier(kDriverBlockName, driverBlockLayoutString);
shaderSource->insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
}
}
} }
void AssignInterfaceBlockLocations(const std::vector<gl::InterfaceBlock> &blocks, // Helper to go through shader stages and substitute layout and qualifier macros.
uint32_t bindingStart, void AssignResourceBinding(gl::ShaderBitSet activeShaders,
const std::string &name,
const std::string &bindingString,
const char *qualifier, const char *qualifier,
IntermediateShaderSource *vertexSource, const char *unusedSubstitution,
IntermediateShaderSource *fragmentSource) const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
{
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
IntermediateShaderSource *shaderSource = shaderSources[shaderType];
if (shaderSource)
{
if (activeShaders[shaderType])
{
shaderSource->insertLayoutSpecifier(name, bindingString);
shaderSource->insertQualifierSpecifier(name, qualifier);
}
else
{
shaderSource->eraseLayoutAndQualifierSpecifiers(name, unusedSubstitution);
}
}
}
}
uint32_t AssignInterfaceBlockBindings(
const std::vector<gl::InterfaceBlock> &blocks,
const char *qualifier,
uint32_t bindingStart,
const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
{ {
const std::string buffersDescriptorSet = "set = " + Str(kBufferDescriptorSetIndex); const std::string buffersDescriptorSet = "set = " + Str(kBufferDescriptorSetIndex);
uint32_t uniformBlockBinding = bindingStart; uint32_t bindingIndex = bindingStart;
for (const gl::InterfaceBlock &block : blocks) for (const gl::InterfaceBlock &block : blocks)
{ {
const std::string setBindingString = if (!block.isArray || block.arrayElement == 0)
buffersDescriptorSet + ", binding = " + Str(uniformBlockBinding); {
const std::string bindingString =
vertexSource->insertLayoutSpecifier(block.name, setBindingString); buffersDescriptorSet + ", binding = " + Str(bindingIndex++);
fragmentSource->insertLayoutSpecifier(block.name, setBindingString);
vertexSource->insertQualifierSpecifier(block.name, qualifier);
fragmentSource->insertQualifierSpecifier(block.name, qualifier);
++uniformBlockBinding; AssignResourceBinding(block.activeShaders(), block.name, bindingString, qualifier,
kUnusedBlockSubstitution, shaderSources);
}
} }
}
void AssignUniformBufferLocations(const gl::ProgramState &programState, return bindingIndex;
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
{
AssignInterfaceBlockLocations(programState.getUniformBlocks(), 0, kUniformQualifier,
vertexSource, fragmentSource);
} }
void AssignStorageBufferLocations(const gl::ProgramState &programState, void AssignBufferBindings(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource, const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
IntermediateShaderSource *fragmentSource)
{ {
AssignInterfaceBlockLocations(programState.getShaderStorageBlocks(), uint32_t bindingStart = 0;
static_cast<uint32_t>(programState.getUniformBlocks().size()),
kSSBOQualifier, vertexSource, fragmentSource); const std::vector<gl::InterfaceBlock> &uniformBlocks = programState.getUniformBlocks();
bindingStart =
AssignInterfaceBlockBindings(uniformBlocks, kUniformQualifier, bindingStart, shaderSources);
const std::vector<gl::InterfaceBlock> &storageBlocks = programState.getShaderStorageBlocks();
// Note: this pattern of accumulating the bindingStart and assigning the next
// resource will be used to append atomic counter buffers and images to this set.
bindingStart =
AssignInterfaceBlockBindings(storageBlocks, kSSBOQualifier, bindingStart, shaderSources);
} }
void AssignTextureLocations(const gl::ProgramState &programState, void AssignTextureBindings(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource, const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
IntermediateShaderSource *fragmentSource)
{ {
const std::string texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex); const std::string texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex);
// Assign textures to a descriptor set and binding. // Assign textures to a descriptor set and binding.
uint32_t textureBinding = 0; uint32_t bindingIndex = 0;
const auto &uniforms = programState.getUniforms(); const std::vector<gl::LinkedUniform> &uniforms = programState.getUniforms();
for (unsigned int uniformIndex : programState.getSamplerUniformRange()) for (unsigned int uniformIndex : programState.getSamplerUniformRange())
{ {
const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex]; const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
const std::string setBindingString = const std::string bindingString =
texturesDescriptorSet + ", binding = " + Str(textureBinding); texturesDescriptorSet + ", binding = " + Str(bindingIndex++);
// Samplers in structs are extracted and renamed. // Samplers in structs are extracted and renamed.
const std::string samplerName = GetMappedSamplerName(samplerUniform.name); const std::string samplerName = GetMappedSamplerName(samplerUniform.name);
ASSERT(samplerUniform.isActive(gl::ShaderType::Vertex) || AssignResourceBinding(samplerUniform.activeShaders(), samplerName, bindingString,
samplerUniform.isActive(gl::ShaderType::Fragment)); kUniformQualifier, kUnusedUniformSubstitution, shaderSources);
if (samplerUniform.isActive(gl::ShaderType::Vertex))
{
vertexSource->insertLayoutSpecifier(samplerName, setBindingString);
}
vertexSource->insertQualifierSpecifier(samplerName, kUniformQualifier);
if (samplerUniform.isActive(gl::ShaderType::Fragment))
{
fragmentSource->insertLayoutSpecifier(samplerName, setBindingString);
}
fragmentSource->insertQualifierSpecifier(samplerName, kUniformQualifier);
textureBinding++;
} }
} }
void CleanupUnusedEntities(const gl::ProgramState &programState, void CleanupUnusedEntities(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::Shader *glVertexShader, gl::Shader *glVertexShader,
IntermediateShaderSource *vertexSource, const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
IntermediateShaderSource *fragmentSource)
{ {
IntermediateShaderSource *vertexSource = shaderSources[gl::ShaderType::Vertex];
if (vertexSource)
{
ASSERT(glVertexShader != nullptr);
// The attributes in the programState could have been filled with active attributes only // The attributes in the programState could have been filled with active attributes only
// depending on the shader version. If there is inactive attributes left, we have to remove // depending on the shader version. If there is inactive attributes left, we have to remove
// their @@ QUALIFIER and @@ LAYOUT markers. // their @@ QUALIFIER and @@ LAYOUT markers.
...@@ -741,53 +774,47 @@ void CleanupUnusedEntities(const gl::ProgramState &programState, ...@@ -741,53 +774,47 @@ void CleanupUnusedEntities(const gl::ProgramState &programState,
vertexSource->eraseLayoutAndQualifierSpecifiers(attribute.name, ""); vertexSource->eraseLayoutAndQualifierSpecifiers(attribute.name, "");
} }
}
// Remove all the markers for unused varyings. // Remove all the markers for unused varyings.
for (const std::string &varyingName : resources.varyingPacking.getInactiveVaryingNames()) for (const std::string &varyingName : resources.varyingPacking.getInactiveVaryingNames())
{ {
vertexSource->eraseLayoutAndQualifierSpecifiers(varyingName, ""); for (IntermediateShaderSource *shaderSource : shaderSources)
fragmentSource->eraseLayoutAndQualifierSpecifiers(varyingName, ""); {
if (shaderSource)
{
shaderSource->eraseLayoutAndQualifierSpecifiers(varyingName, "");
}
}
} }
// Remove all the markers for unused interface blocks, and replace them with |struct|. // Remove all the markers for unused interface blocks, and replace them with |struct|.
for (const std::string &unusedInterfaceBlock : resources.unusedInterfaceBlocks) for (const std::string &unusedInterfaceBlock : resources.unusedInterfaceBlocks)
{ {
vertexSource->eraseLayoutAndQualifierSpecifiers(unusedInterfaceBlock, "struct"); for (IntermediateShaderSource *shaderSource : shaderSources)
fragmentSource->eraseLayoutAndQualifierSpecifiers(unusedInterfaceBlock, "struct"); {
if (shaderSource)
{
shaderSource->eraseLayoutAndQualifierSpecifiers(unusedInterfaceBlock,
kUnusedBlockSubstitution);
}
}
} }
// Place the unused uniforms in the driver uniforms descriptor set, which has a fixed number of // Comment out unused uniforms. This relies on the fact that the shader compiler outputs
// bindings. This avoids any possible index collision between uniform bindings set in the // uniforms to a single line.
// shader and the ones assigned here to the unused ones.
constexpr int kBaseUnusedSamplerBinding = kReservedDriverUniformBindingCount;
int unusedSamplerBinding = kBaseUnusedSamplerBinding;
const std::string driverUniformsDescriptorSet =
"set = " + Str(kDriverUniformsDescriptorSetIndex);
for (const gl::UnusedUniform &unusedUniform : resources.unusedUniforms) for (const gl::UnusedUniform &unusedUniform : resources.unusedUniforms)
{ {
if (unusedUniform.isSampler) std::string uniformName =
{ unusedUniform.isSampler ? GetMappedSamplerName(unusedUniform.name) : unusedUniform.name;
// Samplers in structs are extracted and renamed.
std::string uniformName = GetMappedSamplerName(unusedUniform.name);
std::stringstream layoutStringStream;
layoutStringStream << driverUniformsDescriptorSet + ", binding = " for (IntermediateShaderSource *shaderSource : shaderSources)
<< unusedSamplerBinding++;
std::string layoutString = layoutStringStream.str();
vertexSource->insertLayoutSpecifier(uniformName, layoutString);
fragmentSource->insertLayoutSpecifier(uniformName, layoutString);
vertexSource->insertQualifierSpecifier(uniformName, kUniformQualifier);
fragmentSource->insertQualifierSpecifier(uniformName, kUniformQualifier);
}
else
{ {
vertexSource->eraseLayoutAndQualifierSpecifiers(unusedUniform.name, ""); if (shaderSource)
fragmentSource->eraseLayoutAndQualifierSpecifiers(unusedUniform.name, ""); {
shaderSource->eraseLayoutAndQualifierSpecifiers(uniformName,
kUnusedUniformSubstitution);
}
} }
} }
} }
...@@ -819,15 +846,20 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState, ...@@ -819,15 +846,20 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
IntermediateShaderSource vertexSource(glVertexShader->getTranslatedSource()); IntermediateShaderSource vertexSource(glVertexShader->getTranslatedSource());
IntermediateShaderSource fragmentSource(glFragmentShader->getTranslatedSource()); IntermediateShaderSource fragmentSource(glFragmentShader->getTranslatedSource());
AssignAttributeLocations(programState, &vertexSource); gl::ShaderMap<IntermediateShaderSource *> shaderSources{};
AssignOutputLocations(programState, &fragmentSource);
AssignVaryingLocations(resources, &vertexSource, &fragmentSource); shaderSources[gl::ShaderType::Vertex] = &vertexSource;
AssignUniformLocations(&vertexSource, &fragmentSource); shaderSources[gl::ShaderType::Fragment] = &fragmentSource;
AssignUniformBufferLocations(programState, &vertexSource, &fragmentSource);
AssignStorageBufferLocations(programState, &vertexSource, &fragmentSource); AssignAttributeLocations(programState, shaderSources[gl::ShaderType::Vertex]);
AssignTextureLocations(programState, &vertexSource, &fragmentSource); AssignOutputLocations(programState, shaderSources[gl::ShaderType::Fragment]);
AssignVaryingLocations(resources, shaderSources[gl::ShaderType::Vertex],
shaderSources[gl::ShaderType::Fragment]);
AssignUniformBindings(shaderSources);
AssignBufferBindings(programState, shaderSources);
AssignTextureBindings(programState, shaderSources);
CleanupUnusedEntities(programState, resources, glVertexShader, &vertexSource, &fragmentSource); CleanupUnusedEntities(programState, resources, glVertexShader, shaderSources);
// Write transform feedback output code. // Write transform feedback output code.
if (programState.getLinkedTransformFeedbackVaryings().empty()) if (programState.getLinkedTransformFeedbackVaryings().empty())
......
...@@ -26,7 +26,6 @@ namespace ...@@ -26,7 +26,6 @@ namespace
constexpr size_t kUniformBlockDynamicBufferMinSize = 256 * 128; constexpr size_t kUniformBlockDynamicBufferMinSize = 256 * 128;
void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms, void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms,
gl::Shader *shader,
sh::BlockLayoutMap *blockLayoutMapOut, sh::BlockLayoutMap *blockLayoutMapOut,
size_t *blockSizeOut) size_t *blockSizeOut)
{ {
...@@ -169,14 +168,17 @@ void AddInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> &b ...@@ -169,14 +168,17 @@ void AddInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> &b
VkDescriptorType descType, VkDescriptorType descType,
vk::DescriptorSetLayoutDesc *descOut) vk::DescriptorSetLayoutDesc *descOut)
{ {
uint32_t bindingIndex = 0;
for (uint32_t bufferIndex = 0; bufferIndex < blocks.size();) for (uint32_t bufferIndex = 0; bufferIndex < blocks.size();)
{ {
const uint32_t arraySize = GetInterfaceBlockArraySize(blocks, bufferIndex); const uint32_t arraySize = GetInterfaceBlockArraySize(blocks, bufferIndex);
VkShaderStageFlags activeStages =
gl_vk::GetShaderStageFlags(blocks[bufferIndex].activeShaders());
descOut->update(bindingStart + bufferIndex, descType, arraySize, descOut->update(bindingStart + bindingIndex, descType, arraySize, activeStages);
VK_SHADER_STAGE_ALL_GRAPHICS);
bufferIndex += arraySize; bufferIndex += arraySize;
++bindingIndex;
} }
} }
...@@ -219,7 +221,7 @@ angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk, ...@@ -219,7 +221,7 @@ angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk,
angle::Result ProgramVk::loadShaderSource(ContextVk *contextVk, gl::BinaryInputStream *stream) angle::Result ProgramVk::loadShaderSource(ContextVk *contextVk, gl::BinaryInputStream *stream)
{ {
// Read in shader sources for all shader types // Read in shader sources for all shader types
for (gl::ShaderType shaderType : gl::AllShaderTypes()) for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{ {
mShaderSource[shaderType] = stream->readString(); mShaderSource[shaderType] = stream->readString();
} }
...@@ -230,7 +232,7 @@ angle::Result ProgramVk::loadShaderSource(ContextVk *contextVk, gl::BinaryInputS ...@@ -230,7 +232,7 @@ angle::Result ProgramVk::loadShaderSource(ContextVk *contextVk, gl::BinaryInputS
void ProgramVk::saveShaderSource(gl::BinaryOutputStream *stream) void ProgramVk::saveShaderSource(gl::BinaryOutputStream *stream)
{ {
// Write out shader sources for all shader types // Write out shader sources for all shader types
for (gl::ShaderType shaderType : gl::AllShaderTypes()) for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{ {
stream->writeString(mShaderSource[shaderType]); stream->writeString(mShaderSource[shaderType]);
} }
...@@ -251,7 +253,9 @@ ProgramVk::DefaultUniformBlock::DefaultUniformBlock() {} ...@@ -251,7 +253,9 @@ ProgramVk::DefaultUniformBlock::DefaultUniformBlock() {}
ProgramVk::DefaultUniformBlock::~DefaultUniformBlock() = default; ProgramVk::DefaultUniformBlock::~DefaultUniformBlock() = default;
ProgramVk::ProgramVk(const gl::ProgramState &state) : ProgramImpl(state), mDynamicBufferOffsets{} {} ProgramVk::ProgramVk(const gl::ProgramState &state)
: ProgramImpl(state), mDynamicBufferOffsets{}, mStorageBlockBindingsOffset(0)
{}
ProgramVk::~ProgramVk() = default; ProgramVk::~ProgramVk() = default;
...@@ -350,19 +354,24 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf ...@@ -350,19 +354,24 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback(); gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
reset(contextVk); reset(contextVk);
updateBindingOffsets();
ANGLE_TRY(initDefaultUniformBlocks(glContext)); ANGLE_TRY(initDefaultUniformBlocks(glContext));
// Store a reference to the pipeline and descriptor set layouts. This will create them if they // Store a reference to the pipeline and descriptor set layouts. This will create them if they
// don't already exist in the cache. // don't already exist in the cache.
// Default uniforms and transform feedback:
vk::DescriptorSetLayoutDesc uniformsAndXfbSetDesc; vk::DescriptorSetLayoutDesc uniformsAndXfbSetDesc;
uniformsAndXfbSetDesc.update(kVertexUniformsBindingIndex, uint32_t uniformBindingIndex = 0;
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
VK_SHADER_STAGE_VERTEX_BIT); {
uniformsAndXfbSetDesc.update(kFragmentUniformsBindingIndex, uniformsAndXfbSetDesc.update(uniformBindingIndex++,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
VK_SHADER_STAGE_FRAGMENT_BIT); gl_vk::kShaderStageMap[shaderType]);
if (transformFeedback && !mState.getLinkedTransformFeedbackVaryings().empty()) }
if (mState.hasLinkedShaderStage(gl::ShaderType::Vertex) && transformFeedback &&
!mState.getLinkedTransformFeedbackVaryings().empty())
{ {
vk::GetImpl(transformFeedback)->updateDescriptorSetLayout(mState, &uniformsAndXfbSetDesc); vk::GetImpl(transformFeedback)->updateDescriptorSetLayout(mState, &uniformsAndXfbSetDesc);
} }
...@@ -371,17 +380,19 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf ...@@ -371,17 +380,19 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
contextVk, uniformsAndXfbSetDesc, contextVk, uniformsAndXfbSetDesc,
&mDescriptorSetLayouts[kUniformsAndXfbDescriptorSetIndex])); &mDescriptorSetLayouts[kUniformsAndXfbDescriptorSetIndex]));
// Uniform and storage buffers:
vk::DescriptorSetLayoutDesc buffersSetDesc; vk::DescriptorSetLayoutDesc buffersSetDesc;
AddInterfaceBlockDescriptorSetDesc(mState.getUniformBlocks(), getUniformBuffersBindingStart(), AddInterfaceBlockDescriptorSetDesc(mState.getUniformBlocks(), getUniformBlockBindingsOffset(),
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &buffersSetDesc); VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &buffersSetDesc);
AddInterfaceBlockDescriptorSetDesc(mState.getShaderStorageBlocks(), AddInterfaceBlockDescriptorSetDesc(mState.getShaderStorageBlocks(),
getStorageBuffersBindingStart(), getStorageBlockBindingsOffset(),
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &buffersSetDesc); VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &buffersSetDesc);
ANGLE_TRY(renderer->getDescriptorSetLayout(contextVk, buffersSetDesc, ANGLE_TRY(renderer->getDescriptorSetLayout(contextVk, buffersSetDesc,
&mDescriptorSetLayouts[kBufferDescriptorSetIndex])); &mDescriptorSetLayouts[kBufferDescriptorSetIndex]));
// Textures:
vk::DescriptorSetLayoutDesc texturesSetDesc; vk::DescriptorSetLayoutDesc texturesSetDesc;
for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size(); for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size();
...@@ -389,10 +400,16 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf ...@@ -389,10 +400,16 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
{ {
const gl::SamplerBinding &samplerBinding = mState.getSamplerBindings()[textureIndex]; const gl::SamplerBinding &samplerBinding = mState.getSamplerBindings()[textureIndex];
uint32_t uniformIndex = mState.getUniformIndexFromSamplerIndex(textureIndex);
const gl::LinkedUniform &samplerUniform = mState.getUniforms()[uniformIndex];
// The front-end always binds array sampler units sequentially. // The front-end always binds array sampler units sequentially.
const uint32_t count = static_cast<uint32_t>(samplerBinding.boundTextureUnits.size()); const uint32_t arraySize = static_cast<uint32_t>(samplerBinding.boundTextureUnits.size());
texturesSetDesc.update(textureIndex, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, count, VkShaderStageFlags activeStages =
VK_SHADER_STAGE_ALL_GRAPHICS); gl_vk::GetShaderStageFlags(samplerUniform.activeShaders());
texturesSetDesc.update(textureIndex, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, arraySize,
activeStages);
} }
ANGLE_TRY(renderer->getDescriptorSetLayout(contextVk, texturesSetDesc, ANGLE_TRY(renderer->getDescriptorSetLayout(contextVk, texturesSetDesc,
...@@ -415,26 +432,58 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf ...@@ -415,26 +432,58 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
ANGLE_TRY(renderer->getPipelineLayout(contextVk, pipelineLayoutDesc, mDescriptorSetLayouts, ANGLE_TRY(renderer->getPipelineLayout(contextVk, pipelineLayoutDesc, mDescriptorSetLayouts,
&mPipelineLayout)); &mPipelineLayout));
// Note that this may reserve more sets than strictly necessary for a particular layout.
// TODO(jmadill): Optimize descriptor counts. http://anglebug.com/3117
std::array<VkDescriptorPoolSize, 2> uniformAndXfbSetSize = { std::array<VkDescriptorPoolSize, 2> uniformAndXfbSetSize = {
{{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, GetUniformBufferDescriptorCount()}, {{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
static_cast<uint32_t>(mState.getLinkedShaderStageCount())},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS}}}; {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS}}};
std::array<VkDescriptorPoolSize, 2> bufferSetSize = {
{{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, renderer->getMaxUniformBlocks()}, uint32_t uniformBlockCount = static_cast<uint32_t>(mState.getUniformBlocks().size());
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, renderer->getMaxStorageBlocks()}}}; uint32_t storageBlockCount = static_cast<uint32_t>(mState.getShaderStorageBlocks().size());
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, uint32_t textureCount = static_cast<uint32_t>(mState.getSamplerBindings().size());
renderer->getMaxActiveTextures()};
if (renderer->getFeatures().bindEmptyForUnusedDescriptorSets.enabled)
{
// For this workaround, we have to create an empty descriptor set for each descriptor set
// index, so make sure their pools are initialized.
uniformBlockCount = std::max(uniformBlockCount, 1u);
textureCount = std::max(textureCount, 1u);
}
angle::FixedVector<VkDescriptorPoolSize, 2> bufferSetSize;
if (uniformBlockCount > 0)
{
bufferSetSize.push_back({VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniformBlockCount});
}
if (storageBlockCount > 0)
{
bufferSetSize.push_back({VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, storageBlockCount});
}
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, textureCount};
ANGLE_TRY(mDynamicDescriptorPools[kUniformsAndXfbDescriptorSetIndex].init( ANGLE_TRY(mDynamicDescriptorPools[kUniformsAndXfbDescriptorSetIndex].init(
contextVk, uniformAndXfbSetSize.data(), uniformAndXfbSetSize.size())); contextVk, uniformAndXfbSetSize.data(), uniformAndXfbSetSize.size()));
if (bufferSetSize.size() > 0)
{
ANGLE_TRY(mDynamicDescriptorPools[kBufferDescriptorSetIndex].init( ANGLE_TRY(mDynamicDescriptorPools[kBufferDescriptorSetIndex].init(
contextVk, bufferSetSize.data(), bufferSetSize.size())); contextVk, bufferSetSize.data(), bufferSetSize.size()));
ANGLE_TRY( }
mDynamicDescriptorPools[kTextureDescriptorSetIndex].init(contextVk, &textureSetSize, 1)); if (textureCount > 0)
{
ANGLE_TRY(mDynamicDescriptorPools[kTextureDescriptorSetIndex].init(contextVk,
&textureSetSize, 1));
}
mDynamicBufferOffsets.resize(mState.getLinkedShaderStageCount());
return angle::Result::Continue; return angle::Result::Continue;
} }
void ProgramVk::updateBindingOffsets()
{
mStorageBlockBindingsOffset = mState.getUniqueUniformBlockCount();
}
void ProgramVk::linkResources(const gl::ProgramLinkedResources &resources) void ProgramVk::linkResources(const gl::ProgramLinkedResources &resources)
{ {
Std140BlockLayoutEncoderFactory std140EncoderFactory; Std140BlockLayoutEncoderFactory std140EncoderFactory;
...@@ -453,13 +502,14 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext) ...@@ -453,13 +502,14 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
gl::ShaderMap<size_t> requiredBufferSize; gl::ShaderMap<size_t> requiredBufferSize;
requiredBufferSize.fill(0); requiredBufferSize.fill(0);
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
gl::Shader *shader = mState.getAttachedShader(shaderType); gl::Shader *shader = mState.getAttachedShader(shaderType);
if (shader) if (shader)
{ {
const std::vector<sh::Uniform> &uniforms = shader->getUniforms(); const std::vector<sh::Uniform> &uniforms = shader->getUniforms();
InitDefaultUniformBlock(uniforms, shader, &layoutMap[shaderType], InitDefaultUniformBlock(uniforms, &layoutMap[shaderType],
&requiredBufferSize[shaderType]); &requiredBufferSize[shaderType]);
} }
} }
...@@ -484,7 +534,7 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext) ...@@ -484,7 +534,7 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
bool found = false; bool found = false;
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
auto it = layoutMap[shaderType].find(uniformName); auto it = layoutMap[shaderType].find(uniformName);
if (it != layoutMap[shaderType].end()) if (it != layoutMap[shaderType].end())
...@@ -498,13 +548,13 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext) ...@@ -498,13 +548,13 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
} }
} }
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]); mDefaultUniformBlocks[shaderType].uniformLayout.push_back(layoutInfo[shaderType]);
} }
} }
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
if (requiredBufferSize[shaderType] > 0) if (requiredBufferSize[shaderType] > 0)
{ {
...@@ -569,7 +619,7 @@ void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum ...@@ -569,7 +619,7 @@ void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum
if (linkedUniform.typeInfo->type == entryPointType) if (linkedUniform.typeInfo->type == entryPointType)
{ {
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
...@@ -588,7 +638,7 @@ void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum ...@@ -588,7 +638,7 @@ void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum
} }
else else
{ {
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
...@@ -722,7 +772,7 @@ void ProgramVk::setUniformMatrixfv(GLint location, ...@@ -722,7 +772,7 @@ void ProgramVk::setUniformMatrixfv(GLint location,
const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location]; const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index]; const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location]; const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
...@@ -875,15 +925,16 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk) ...@@ -875,15 +925,16 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
ASSERT(dirtyUniforms()); ASSERT(dirtyUniforms());
bool anyNewBufferAllocated = false; bool anyNewBufferAllocated = false;
uint32_t offsetIndex = 0;
// Update buffer memory by immediate mapping. This immediate update only works once. // Update buffer memory by immediate mapping. This immediate update only works once.
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) for (gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
if (mDefaultUniformBlocksDirty[shaderType]) if (mDefaultUniformBlocksDirty[shaderType])
{ {
bool bufferModified = false; bool bufferModified = false;
uint32_t offsetIndex = static_cast<uint32_t>(shaderType) - kShaderTypeMin;
ANGLE_TRY( ANGLE_TRY(
SyncDefaultUniformBlock(contextVk, &uniformBlock.storage, uniformBlock.uniformData, SyncDefaultUniformBlock(contextVk, &uniformBlock.storage, uniformBlock.uniformData,
&mDynamicBufferOffsets[offsetIndex], &bufferModified)); &mDynamicBufferOffsets[offsetIndex], &bufferModified));
...@@ -894,6 +945,8 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk) ...@@ -894,6 +945,8 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
anyNewBufferAllocated = true; anyNewBufferAllocated = true;
} }
} }
++offsetIndex;
} }
if (anyNewBufferAllocated) if (anyNewBufferAllocated)
...@@ -910,15 +963,19 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk) ...@@ -910,15 +963,19 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk) void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
{ {
gl::ShaderMap<VkDescriptorBufferInfo> descriptorBufferInfo; size_t shaderStageCount = mState.getLinkedShaderStageCount();
gl::ShaderMap<VkWriteDescriptorSet> writeDescriptorInfo;
gl::ShaderVector<VkDescriptorBufferInfo> descriptorBufferInfo(shaderStageCount);
gl::ShaderVector<VkWriteDescriptorSet> writeDescriptorInfo(shaderStageCount);
uint32_t bindingIndex = 0;
// Write default uniforms for each shader type. // Write default uniforms for each shader type.
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes()) for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{ {
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType]; DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[shaderType]; VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[bindingIndex];
VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[shaderType]; VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[bindingIndex];
if (!uniformBlock.uniformData.empty()) if (!uniformBlock.uniformData.empty())
{ {
...@@ -936,18 +993,23 @@ void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk) ...@@ -936,18 +993,23 @@ void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfo.pNext = nullptr; writeInfo.pNext = nullptr;
writeInfo.dstSet = mDescriptorSets[kUniformsAndXfbDescriptorSetIndex]; writeInfo.dstSet = mDescriptorSets[kUniformsAndXfbDescriptorSetIndex];
writeInfo.dstBinding = static_cast<uint32_t>(shaderType); writeInfo.dstBinding = bindingIndex;
writeInfo.dstArrayElement = 0; writeInfo.dstArrayElement = 0;
writeInfo.descriptorCount = 1; writeInfo.descriptorCount = 1;
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
writeInfo.pImageInfo = nullptr; writeInfo.pImageInfo = nullptr;
writeInfo.pBufferInfo = &bufferInfo; writeInfo.pBufferInfo = &bufferInfo;
writeInfo.pTexelBufferView = nullptr; writeInfo.pTexelBufferView = nullptr;
++bindingIndex;
} }
VkDevice device = contextVk->getDevice(); VkDevice device = contextVk->getDevice();
vkUpdateDescriptorSets(device, kShaderTypeCount, writeDescriptorInfo.data(), 0, nullptr); ASSERT(bindingIndex == shaderStageCount);
ASSERT(shaderStageCount <= kReservedDefaultUniformBindingCount);
vkUpdateDescriptorSets(device, shaderStageCount, writeDescriptorInfo.data(), 0, nullptr);
} }
void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk, void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
...@@ -961,16 +1023,19 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk, ...@@ -961,16 +1023,19 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
const bool isStorageBuffer = descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; const bool isStorageBuffer = descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
const uint32_t bindingStart = const uint32_t bindingStart =
isStorageBuffer ? getStorageBuffersBindingStart() : getUniformBuffersBindingStart(); isStorageBuffer ? getStorageBlockBindingsOffset() : getUniformBlockBindingsOffset();
static_assert( static_assert(
gl::IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS >= gl::IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS >=
gl::IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS, gl::IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS,
"The descriptor arrays here would have inadequate size for uniform buffer objects"); "The descriptor arrays here would have inadequate size for uniform buffer objects");
gl::StorageBuffersArray<VkDescriptorBufferInfo> descriptorBufferInfo; gl::StorageBuffersArray<VkDescriptorBufferInfo> descriptorBufferInfo;
gl::StorageBuffersArray<VkWriteDescriptorSet> writeDescriptorInfo; gl::StorageBuffersArray<VkWriteDescriptorSet> writeDescriptorInfo;
uint32_t writeCount = 0; uint32_t writeCount = 0;
uint32_t currentBinding = 0; // The binding is incremented every time arrayElement 0 is encountered, which means there will
// be an increment right at the start. Start from -1 to get 0 as the first binding.
int32_t currentBinding = -1;
// Write uniform or storage buffers. // Write uniform or storage buffers.
const gl::State &glState = contextVk->getState(); const gl::State &glState = contextVk->getState();
...@@ -981,6 +1046,13 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk, ...@@ -981,6 +1046,13 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
isStorageBuffer ? glState.getIndexedShaderStorageBuffer(block.binding) isStorageBuffer ? glState.getIndexedShaderStorageBuffer(block.binding)
: glState.getIndexedUniformBuffer(block.binding); : glState.getIndexedUniformBuffer(block.binding);
if (!block.isArray || block.arrayElement == 0)
{
// Array indices of the same buffer binding are placed sequentially in `blocks`.
// Thus, the block binding is updated only when array index 0 is encountered.
++currentBinding;
}
if (bufferBinding.get() == nullptr) if (bufferBinding.get() == nullptr)
{ {
continue; continue;
...@@ -1022,13 +1094,6 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk, ...@@ -1022,13 +1094,6 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
bufferInfo.offset = offset; bufferInfo.offset = offset;
bufferInfo.range = size; bufferInfo.range = size;
if (!block.isArray || block.arrayElement == 0)
{
// Array indices of the same buffer binding are placed sequentially in `blocks`.
// Thus, the block binding is updated only when array index 0 is encountered.
currentBinding = bufferIndex;
}
VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[writeCount]; VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[writeCount];
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
...@@ -1094,8 +1159,8 @@ void ProgramVk::updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk) ...@@ -1094,8 +1159,8 @@ void ProgramVk::updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk)
} }
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(glState.getCurrentTransformFeedback()); TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(glState.getCurrentTransformFeedback());
transformFeedbackVk->updateDescriptorSet( transformFeedbackVk->updateDescriptorSet(contextVk, mState,
contextVk, mState, mDescriptorSets[kUniformsAndXfbDescriptorSetIndex], kShaderTypeCount); mDescriptorSets[kUniformsAndXfbDescriptorSetIndex]);
} }
angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk, angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk,
...@@ -1163,13 +1228,14 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk, ...@@ -1163,13 +1228,14 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk,
writeInfo.pBufferInfo = nullptr; writeInfo.pBufferInfo = nullptr;
writeInfo.pTexelBufferView = nullptr; writeInfo.pTexelBufferView = nullptr;
writeCount++; ++writeCount;
} }
} }
VkDevice device = contextVk->getDevice(); VkDevice device = contextVk->getDevice();
ASSERT(writeCount > 0); ASSERT(writeCount > 0);
vkUpdateDescriptorSets(device, writeCount, writeDescriptorInfo.data(), 0, nullptr); vkUpdateDescriptorSets(device, writeCount, writeDescriptorInfo.data(), 0, nullptr);
mTextureDescriptorsCache.emplace(texturesDesc, descriptorSet); mTextureDescriptorsCache.emplace(texturesDesc, descriptorSet);
...@@ -1236,11 +1302,12 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk, ...@@ -1236,11 +1302,12 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
// through dynamic uniform buffers (requiring dynamic offsets). No other descriptor // through dynamic uniform buffers (requiring dynamic offsets). No other descriptor
// requires a dynamic offset. // requires a dynamic offset.
const uint32_t uniformBlockOffsetCount = const uint32_t uniformBlockOffsetCount =
descriptorSetIndex == kUniformsAndXfbDescriptorSetIndex ? kShaderTypeCount : 0; descriptorSetIndex == kUniformsAndXfbDescriptorSetIndex ? mDynamicBufferOffsets.size()
: 0;
commandBuffer->bindGraphicsDescriptorSets(mPipelineLayout.get(), descriptorSetIndex, 1, commandBuffer->bindGraphicsDescriptorSets(mPipelineLayout.get(), descriptorSetIndex, 1,
&descSet, uniformBlockOffsetCount, &descSet, uniformBlockOffsetCount,
mDynamicBufferOffsets.data() + kShaderTypeMin); mDynamicBufferOffsets.data());
} }
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -182,11 +182,9 @@ class ProgramVk : public ProgramImpl ...@@ -182,11 +182,9 @@ class ProgramVk : public ProgramImpl
angle::Result linkImpl(const gl::Context *glContext, gl::InfoLog &infoLog); angle::Result linkImpl(const gl::Context *glContext, gl::InfoLog &infoLog);
void linkResources(const gl::ProgramLinkedResources &resources); void linkResources(const gl::ProgramLinkedResources &resources);
uint32_t getUniformBuffersBindingStart() const { return 0; } void updateBindingOffsets();
uint32_t getStorageBuffersBindingStart() const uint32_t getUniformBlockBindingsOffset() const { return 0; }
{ uint32_t getStorageBlockBindingsOffset() const { return mStorageBlockBindingsOffset; }
return static_cast<uint32_t>(mState.getUniformBlocks().size());
}
ANGLE_INLINE angle::Result initShaders(ContextVk *contextVk, ANGLE_INLINE angle::Result initShaders(ContextVk *contextVk,
gl::PrimitiveMode mode, gl::PrimitiveMode mode,
...@@ -233,10 +231,7 @@ class ProgramVk : public ProgramImpl ...@@ -233,10 +231,7 @@ class ProgramVk : public ProgramImpl
gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks; gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks;
gl::ShaderBitSet mDefaultUniformBlocksDirty; gl::ShaderBitSet mDefaultUniformBlocksDirty;
static constexpr uint32_t kShaderTypeMin = static_cast<uint32_t>(gl::kGLES2ShaderTypeMin); gl::ShaderVector<uint32_t> mDynamicBufferOffsets;
static constexpr uint32_t kShaderTypeMax = static_cast<uint32_t>(gl::kGLES2ShaderTypeMax);
static constexpr uint32_t kShaderTypeCount = kShaderTypeMax - kShaderTypeMin + 1;
std::array<uint32_t, kShaderTypeCount> mDynamicBufferOffsets;
// This is a special "empty" placeholder buffer for when a shader has no uniforms. // This is a special "empty" placeholder buffer for when a shader has no uniforms.
// It is necessary because we want to keep a compatible pipeline layout in all cases, // It is necessary because we want to keep a compatible pipeline layout in all cases,
...@@ -285,6 +280,10 @@ class ProgramVk : public ProgramImpl ...@@ -285,6 +280,10 @@ class ProgramVk : public ProgramImpl
// We keep the translated linked shader sources to use with shader draw call patching. // We keep the translated linked shader sources to use with shader draw call patching.
gl::ShaderMap<std::string> mShaderSource; gl::ShaderMap<std::string> mShaderSource;
// Storage buffers are placed after uniform buffers in their descriptor set. This cached value
// contains the offset where storage buffer bindings start.
uint32_t mStorageBlockBindingsOffset;
// Store descriptor pools here. We store the descriptors in the Program to facilitate descriptor // Store descriptor pools here. We store the descriptors in the Program to facilitate descriptor
// cache management. It can also allow fewer descriptors for shaders which use fewer // cache management. It can also allow fewer descriptors for shaders which use fewer
// textures/buffers. // textures/buffers.
......
...@@ -47,9 +47,6 @@ namespace rx ...@@ -47,9 +47,6 @@ namespace rx
namespace namespace
{ {
// We currently only allocate 2 uniform buffer per descriptor set, one for the fragment shader and
// one for the vertex shader.
constexpr size_t kUniformBufferDescriptorsPerDescriptorSet = 2;
// Update the pipeline cache every this many swaps (if 60fps, this means every 10 minutes) // Update the pipeline cache every this many swaps (if 60fps, this means every 10 minutes)
constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60; constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60;
// Wait a maximum of 10s. If that times out, we declare it a failure. // Wait a maximum of 10s. If that times out, we declare it a failure.
...@@ -1322,25 +1319,6 @@ const gl::Limitations &RendererVk::getNativeLimitations() const ...@@ -1322,25 +1319,6 @@ const gl::Limitations &RendererVk::getNativeLimitations() const
return mNativeLimitations; return mNativeLimitations;
} }
uint32_t RendererVk::getMaxUniformBlocks() const
{
return std::min<uint32_t>(mPhysicalDeviceProperties.limits.maxDescriptorSetUniformBuffers,
gl::IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS);
}
uint32_t RendererVk::getMaxStorageBlocks() const
{
return std::min<uint32_t>(mPhysicalDeviceProperties.limits.maxDescriptorSetStorageBuffers,
gl::IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
}
uint32_t RendererVk::getMaxActiveTextures() const
{
// TODO(lucferron): expose this limitation to GL in Context Caps
return std::min<uint32_t>(mPhysicalDeviceProperties.limits.maxDescriptorSetSamplers,
gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES);
}
angle::Result RendererVk::getDescriptorSetLayout( angle::Result RendererVk::getDescriptorSetLayout(
vk::Context *context, vk::Context *context,
const vk::DescriptorSetLayoutDesc &desc, const vk::DescriptorSetLayoutDesc &desc,
...@@ -1575,9 +1553,4 @@ angle::Result RendererVk::cleanupGarbage(vk::Context *context, bool block) ...@@ -1575,9 +1553,4 @@ angle::Result RendererVk::cleanupGarbage(vk::Context *context, bool block)
return angle::Result::Continue; return angle::Result::Continue;
} }
uint32_t GetUniformBufferDescriptorCount()
{
return kUniformBufferDescriptorsPerDescriptorSet;
}
} // namespace rx } // namespace rx
...@@ -85,9 +85,6 @@ class RendererVk : angle::NonCopyable ...@@ -85,9 +85,6 @@ class RendererVk : angle::NonCopyable
const gl::TextureCapsMap &getNativeTextureCaps() const; const gl::TextureCapsMap &getNativeTextureCaps() const;
const gl::Extensions &getNativeExtensions() const; const gl::Extensions &getNativeExtensions() const;
const gl::Limitations &getNativeLimitations() const; const gl::Limitations &getNativeLimitations() const;
uint32_t getMaxUniformBlocks() const;
uint32_t getMaxStorageBlocks() const;
uint32_t getMaxActiveTextures() const;
uint32_t getQueueFamilyIndex() const { return mCurrentQueueFamilyIndex; } uint32_t getQueueFamilyIndex() const { return mCurrentQueueFamilyIndex; }
...@@ -233,8 +230,6 @@ class RendererVk : angle::NonCopyable ...@@ -233,8 +230,6 @@ class RendererVk : angle::NonCopyable
DescriptorSetLayoutCache mDescriptorSetLayoutCache; DescriptorSetLayoutCache mDescriptorSetLayoutCache;
}; };
uint32_t GetUniformBufferDescriptorCount();
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_ #endif // LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
...@@ -135,8 +135,7 @@ void TransformFeedbackVk::addFramebufferDependency(ContextVk *contextVk, ...@@ -135,8 +135,7 @@ void TransformFeedbackVk::addFramebufferDependency(ContextVk *contextVk,
void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk, void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
const gl::ProgramState &programState, const gl::ProgramState &programState,
VkDescriptorSet descSet, VkDescriptorSet descSet) const
uint32_t bindingOffset) const
{ {
const std::vector<gl::OffsetBindingPointer<gl::Buffer>> &xfbBuffers = const std::vector<gl::OffsetBindingPointer<gl::Buffer>> &xfbBuffers =
mState.getIndexedBuffers(); mState.getIndexedBuffers();
...@@ -171,7 +170,7 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk, ...@@ -171,7 +170,7 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
VkWriteDescriptorSet writeDescriptorInfo = {}; VkWriteDescriptorSet writeDescriptorInfo = {};
writeDescriptorInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptorInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorInfo.dstSet = descSet; writeDescriptorInfo.dstSet = descSet;
writeDescriptorInfo.dstBinding = bindingOffset; writeDescriptorInfo.dstBinding = kXfbBindingIndexStart;
writeDescriptorInfo.dstArrayElement = 0; writeDescriptorInfo.dstArrayElement = 0;
writeDescriptorInfo.descriptorCount = xfbBufferCount; writeDescriptorInfo.descriptorCount = xfbBufferCount;
writeDescriptorInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; writeDescriptorInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
......
...@@ -47,8 +47,7 @@ class TransformFeedbackVk : public TransformFeedbackImpl ...@@ -47,8 +47,7 @@ class TransformFeedbackVk : public TransformFeedbackImpl
vk::FramebufferHelper *framebuffer) const; vk::FramebufferHelper *framebuffer) const;
void updateDescriptorSet(ContextVk *contextVk, void updateDescriptorSet(ContextVk *contextVk,
const gl::ProgramState &programState, const gl::ProgramState &programState,
VkDescriptorSet descSet, VkDescriptorSet descSet) const;
uint32_t bindingOffset) const;
void getBufferOffsets(ContextVk *contextVk, void getBufferOffsets(ContextVk *contextVk,
const gl::ProgramState &programState, const gl::ProgramState &programState,
GLint drawCallFirstVertex, GLint drawCallFirstVertex,
......
...@@ -1429,7 +1429,7 @@ void PipelineLayoutDesc::updatePushConstantRange(gl::ShaderType shaderType, ...@@ -1429,7 +1429,7 @@ void PipelineLayoutDesc::updatePushConstantRange(gl::ShaderType shaderType,
{ {
ASSERT(shaderType == gl::ShaderType::Vertex || shaderType == gl::ShaderType::Fragment || ASSERT(shaderType == gl::ShaderType::Vertex || shaderType == gl::ShaderType::Fragment ||
shaderType == gl::ShaderType::Compute); shaderType == gl::ShaderType::Compute);
PackedPushConstantRange &packed = mPushConstantRanges[static_cast<size_t>(shaderType)]; PackedPushConstantRange &packed = mPushConstantRanges[shaderType];
packed.offset = offset; packed.offset = offset;
packed.size = size; packed.size = size;
} }
...@@ -1770,30 +1770,22 @@ angle::Result PipelineLayoutCache::getPipelineLayout( ...@@ -1770,30 +1770,22 @@ angle::Result PipelineLayoutCache::getPipelineLayout(
} }
} }
angle::FixedVector<VkPushConstantRange, vk::kMaxPushConstantRanges> pushConstantRanges;
const vk::PushConstantRangeArray<vk::PackedPushConstantRange> &descPushConstantRanges = const vk::PushConstantRangeArray<vk::PackedPushConstantRange> &descPushConstantRanges =
desc.getPushConstantRanges(); desc.getPushConstantRanges();
for (size_t shaderIndex = 0; shaderIndex < descPushConstantRanges.size(); ++shaderIndex)
gl::ShaderVector<VkPushConstantRange> pushConstantRanges;
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{ {
const vk::PackedPushConstantRange &pushConstantDesc = descPushConstantRanges[shaderIndex]; const vk::PackedPushConstantRange &pushConstantDesc = descPushConstantRanges[shaderType];
if (pushConstantDesc.size > 0) if (pushConstantDesc.size > 0)
{ {
static constexpr VkShaderStageFlagBits kShaderStages[vk::kMaxPushConstantRanges] = { VkPushConstantRange range;
VK_SHADER_STAGE_VERTEX_BIT, range.stageFlags = gl_vk::kShaderStageMap[shaderType];
VK_SHADER_STAGE_FRAGMENT_BIT, range.offset = pushConstantDesc.offset;
VK_SHADER_STAGE_GEOMETRY_BIT, range.size = pushConstantDesc.size;
VK_SHADER_STAGE_COMPUTE_BIT,
}; pushConstantRanges.push_back(range);
static_assert(static_cast<uint32_t>(gl::ShaderType::Vertex) == 0, "Fix this table");
static_assert(static_cast<uint32_t>(gl::ShaderType::Fragment) == 1, "Fix this table");
static_assert(static_cast<uint32_t>(gl::ShaderType::Geometry) == 2, "Fix this table");
static_assert(static_cast<uint32_t>(gl::ShaderType::Compute) == 3, "Fix this table");
VkPushConstantRange pushConstantRange = {};
pushConstantRange.stageFlags = kShaderStages[shaderIndex];
pushConstantRange.offset = pushConstantDesc.offset;
pushConstantRange.size = pushConstantDesc.size;
pushConstantRanges.push_back(pushConstantRange);
} }
} }
...@@ -1803,7 +1795,7 @@ angle::Result PipelineLayoutCache::getPipelineLayout( ...@@ -1803,7 +1795,7 @@ angle::Result PipelineLayoutCache::getPipelineLayout(
createInfo.flags = 0; createInfo.flags = 0;
createInfo.setLayoutCount = static_cast<uint32_t>(setLayoutHandles.size()); createInfo.setLayoutCount = static_cast<uint32_t>(setLayoutHandles.size());
createInfo.pSetLayouts = setLayoutHandles.data(); createInfo.pSetLayouts = setLayoutHandles.data();
createInfo.pushConstantRangeCount = static_cast<uint32_t>(pushConstantRanges.size()); createInfo.pushConstantRangeCount = pushConstantRanges.size();
createInfo.pPushConstantRanges = pushConstantRanges.data(); createInfo.pPushConstantRanges = pushConstantRanges.data();
vk::PipelineLayout newLayout; vk::PipelineLayout newLayout;
......
...@@ -532,10 +532,9 @@ class DescriptorSetLayoutDesc final ...@@ -532,10 +532,9 @@ class DescriptorSetLayoutDesc final
mPackedDescriptorSetLayout; mPackedDescriptorSetLayout;
}; };
// The following are for caching descriptor set layouts. Limited to max four descriptor set layouts // The following are for caching descriptor set layouts. Limited to max four descriptor set layouts.
// and one push constant per shader stage. This can be extended in the future. // This can be extended in the future.
constexpr size_t kMaxDescriptorSetLayouts = 4; constexpr size_t kMaxDescriptorSetLayouts = 4;
constexpr size_t kMaxPushConstantRanges = angle::EnumSize<gl::ShaderType>();
struct PackedPushConstantRange struct PackedPushConstantRange
{ {
...@@ -548,7 +547,7 @@ using DescriptorSetLayoutArray = std::array<T, kMaxDescriptorSetLayouts>; ...@@ -548,7 +547,7 @@ using DescriptorSetLayoutArray = std::array<T, kMaxDescriptorSetLayouts>;
using DescriptorSetLayoutPointerArray = using DescriptorSetLayoutPointerArray =
DescriptorSetLayoutArray<BindingPointer<DescriptorSetLayout>>; DescriptorSetLayoutArray<BindingPointer<DescriptorSetLayout>>;
template <typename T> template <typename T>
using PushConstantRangeArray = std::array<T, kMaxPushConstantRanges>; using PushConstantRangeArray = gl::ShaderMap<T>;
class PipelineLayoutDesc final class PipelineLayoutDesc final
{ {
...@@ -575,14 +574,14 @@ class PipelineLayoutDesc final ...@@ -575,14 +574,14 @@ class PipelineLayoutDesc final
(sizeof(DescriptorSetLayoutDesc) * kMaxDescriptorSetLayouts), (sizeof(DescriptorSetLayoutDesc) * kMaxDescriptorSetLayouts),
"Unexpected size"); "Unexpected size");
static_assert(sizeof(decltype(mPushConstantRanges)) == static_assert(sizeof(decltype(mPushConstantRanges)) ==
(sizeof(PackedPushConstantRange) * kMaxPushConstantRanges), (sizeof(PackedPushConstantRange) * angle::EnumSize<gl::ShaderType>()),
"Unexpected size"); "Unexpected size");
}; };
// Verify the structure is properly packed. // Verify the structure is properly packed.
static_assert(sizeof(PipelineLayoutDesc) == static_assert(sizeof(PipelineLayoutDesc) ==
(sizeof(DescriptorSetLayoutArray<DescriptorSetLayoutDesc>) + (sizeof(DescriptorSetLayoutArray<DescriptorSetLayoutDesc>) +
sizeof(std::array<PackedPushConstantRange, kMaxPushConstantRanges>)), sizeof(gl::ShaderMap<PackedPushConstantRange>)),
"Unexpected Size"); "Unexpected Size");
// Disable warnings about struct padding. // Disable warnings about struct padding.
...@@ -911,12 +910,12 @@ constexpr uint32_t kDriverUniformsDescriptorSetIndex = 3; ...@@ -911,12 +910,12 @@ constexpr uint32_t kDriverUniformsDescriptorSetIndex = 3;
// Only 1 driver uniform binding is used. // Only 1 driver uniform binding is used.
constexpr uint32_t kReservedDriverUniformBindingCount = 1; constexpr uint32_t kReservedDriverUniformBindingCount = 1;
// Binding index for default uniforms in the vertex shader: // There is 1 default uniform binding used per stage. Currently, a maxium of two stages are
constexpr uint32_t kVertexUniformsBindingIndex = 0; // supported.
// Binding index for default uniforms in the fragment shader: constexpr uint32_t kReservedPerStageDefaultUniformBindingCount = 1;
constexpr uint32_t kFragmentUniformsBindingIndex = 1; constexpr uint32_t kReservedDefaultUniformBindingCount = 2;
// Binding index start for transform feedback buffers: // Binding index start for transform feedback buffers:
constexpr uint32_t kXfbBindingIndexStart = 2; constexpr uint32_t kXfbBindingIndexStart = kReservedDefaultUniformBindingCount;
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_ #endif // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
...@@ -176,12 +176,13 @@ void RendererVk::ensureCapsInitialized() const ...@@ -176,12 +176,13 @@ void RendererVk::ensureCapsInitialized() const
// we'll defer the implementation until we tackle the next version. // we'll defer the implementation until we tackle the next version.
// mNativeCaps.maxServerWaitTimeout // mNativeCaps.maxServerWaitTimeout
GLuint maxUniformVectors = mPhysicalDeviceProperties.limits.maxUniformBufferRange / GLuint maxUniformBlockSize = mPhysicalDeviceProperties.limits.maxUniformBufferRange;
(sizeof(GLfloat) * kComponentsPerVector);
// Clamp the maxUniformVectors to 1024u, on AMD the maxUniformBufferRange is way too high. // Clamp the maxUniformBlockSize to 64KB (majority of devices support up to this size
maxUniformVectors = std::min(1024u, maxUniformVectors); // currently), on AMD the maxUniformBufferRange is near uint32_t max.
maxUniformBlockSize = std::min(0x10000u, maxUniformBlockSize);
const GLuint maxUniformVectors = maxUniformBlockSize / (sizeof(GLfloat) * kComponentsPerVector);
const GLuint maxUniformComponents = maxUniformVectors * kComponentsPerVector; const GLuint maxUniformComponents = maxUniformVectors * kComponentsPerVector;
// Uniforms are implemented using a uniform buffer, so the max number of uniforms we can // Uniforms are implemented using a uniform buffer, so the max number of uniforms we can
...@@ -191,30 +192,49 @@ void RendererVk::ensureCapsInitialized() const ...@@ -191,30 +192,49 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.maxFragmentUniformVectors = maxUniformVectors; mNativeCaps.maxFragmentUniformVectors = maxUniformVectors;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxUniformComponents; mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxUniformComponents;
// We use the same bindings on each stage, so the texture, UBO and SSBO limitations are the same // Every stage has 1 reserved uniform buffer for the default uniforms, and 1 for the driver
// as the per-stage limits. // uniforms.
constexpr uint32_t kTotalReservedPerStageUniformBuffers =
kReservedDriverUniformBindingCount + kReservedPerStageDefaultUniformBindingCount;
constexpr uint32_t kTotalReservedUniformBuffers =
kReservedDriverUniformBindingCount + kReservedDefaultUniformBindingCount;
const uint32_t maxPerStageUniformBuffers = const uint32_t maxPerStageUniformBuffers =
mPhysicalDeviceProperties.limits.maxPerStageDescriptorUniformBuffers; mPhysicalDeviceProperties.limits.maxPerStageDescriptorUniformBuffers -
kTotalReservedPerStageUniformBuffers;
const uint32_t maxCombinedUniformBuffers =
mPhysicalDeviceProperties.limits.maxDescriptorSetUniformBuffers -
kTotalReservedUniformBuffers;
mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Vertex] = maxPerStageUniformBuffers; mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Vertex] = maxPerStageUniformBuffers;
mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Fragment] = maxPerStageUniformBuffers; mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Fragment] = maxPerStageUniformBuffers;
mNativeCaps.maxCombinedUniformBlocks = maxPerStageUniformBuffers; mNativeCaps.maxCombinedUniformBlocks = maxCombinedUniformBuffers;
mNativeCaps.maxUniformBufferBindings = maxCombinedUniformBuffers;
mNativeCaps.maxUniformBlockSize = maxUniformBlockSize;
mNativeCaps.uniformBufferOffsetAlignment =
static_cast<GLuint>(mPhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment);
// Note that Vulkan currently implements textures as combined image+samplers, so the limit is // Note that Vulkan currently implements textures as combined image+samplers, so the limit is
// the minimum of supported samplers and sampled images. // the minimum of supported samplers and sampled images.
const uint32_t maxPerStageTextures = const uint32_t maxPerStageTextures =
std::min(mPhysicalDeviceProperties.limits.maxPerStageDescriptorSamplers, std::min(mPhysicalDeviceProperties.limits.maxPerStageDescriptorSamplers,
mPhysicalDeviceProperties.limits.maxPerStageDescriptorSampledImages); mPhysicalDeviceProperties.limits.maxPerStageDescriptorSampledImages);
mNativeCaps.maxCombinedTextureImageUnits = maxPerStageTextures; const uint32_t maxCombinedTextures =
mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] = maxPerStageTextures; std::min(mPhysicalDeviceProperties.limits.maxDescriptorSetSamplers,
mPhysicalDeviceProperties.limits.maxDescriptorSetSampledImages);
mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex] = maxPerStageTextures; mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex] = maxPerStageTextures;
mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] = maxPerStageTextures;
mNativeCaps.maxCombinedTextureImageUnits = maxCombinedTextures;
const uint32_t maxPerStageStorageBuffers = const uint32_t maxPerStageStorageBuffers =
mPhysicalDeviceProperties.limits.maxPerStageDescriptorStorageBuffers; mPhysicalDeviceProperties.limits.maxPerStageDescriptorStorageBuffers;
const uint32_t maxCombinedStorageBuffers =
mPhysicalDeviceProperties.limits.maxDescriptorSetStorageBuffers;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] = mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] =
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics ? maxPerStageStorageBuffers : 0; mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics ? maxPerStageStorageBuffers : 0;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] = mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] =
mPhysicalDeviceFeatures.fragmentStoresAndAtomics ? maxPerStageStorageBuffers : 0; mPhysicalDeviceFeatures.fragmentStoresAndAtomics ? maxPerStageStorageBuffers : 0;
mNativeCaps.maxCombinedShaderStorageBlocks = maxPerStageStorageBuffers; mNativeCaps.maxCombinedShaderStorageBlocks = maxCombinedStorageBuffers;
// A number of storage buffer slots are used in the vertex shader to emulate transform feedback. // A number of storage buffer slots are used in the vertex shader to emulate transform feedback.
// Note that Vulkan requires maxPerStageDescriptorStorageBuffers to be at least 4 (i.e. the same // Note that Vulkan requires maxPerStageDescriptorStorageBuffers to be at least 4 (i.e. the same
...@@ -231,22 +251,21 @@ void RendererVk::ensureCapsInitialized() const ...@@ -231,22 +251,21 @@ void RendererVk::ensureCapsInitialized() const
ASSERT(maxPerStageStorageBuffers >= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); ASSERT(maxPerStageStorageBuffers >= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] -= mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] -=
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
mNativeCaps.maxCombinedShaderStorageBlocks -=
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
} }
// Fill in additional limits for UBOs and SSBOs. mNativeCaps.maxShaderStorageBufferBindings = maxCombinedStorageBuffers;
mNativeCaps.maxUniformBufferBindings = maxPerStageUniformBuffers;
mNativeCaps.maxUniformBlockSize = mPhysicalDeviceProperties.limits.maxUniformBufferRange;
mNativeCaps.uniformBufferOffsetAlignment =
static_cast<GLuint>(mPhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment);
mNativeCaps.maxShaderStorageBufferBindings = maxPerStageStorageBuffers;
mNativeCaps.maxShaderStorageBlockSize = mPhysicalDeviceProperties.limits.maxStorageBufferRange; mNativeCaps.maxShaderStorageBlockSize = mPhysicalDeviceProperties.limits.maxStorageBufferRange;
mNativeCaps.shaderStorageBufferOffsetAlignment = mNativeCaps.shaderStorageBufferOffsetAlignment =
static_cast<GLuint>(mPhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment); static_cast<GLuint>(mPhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment);
// There is no additional limit to the combined number of components. We can have up to a // There is no additional limit to the combined number of components. We can have up to a
// maximum number of uniform buffers, each having the maximum number of components. // maximum number of uniform buffers, each having the maximum number of components. Note that
const uint32_t maxCombinedUniformComponents = maxPerStageUniformBuffers * maxUniformComponents; // this limit includes both components in and out of uniform buffers.
const uint32_t maxCombinedUniformComponents =
(maxPerStageUniformBuffers + kReservedPerStageDefaultUniformBindingCount) *
maxUniformComponents;
for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes) for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
{ {
mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents; mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents;
......
...@@ -864,6 +864,16 @@ VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bo ...@@ -864,6 +864,16 @@ VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bo
(blue ? VK_COLOR_COMPONENT_B_BIT : 0) | (alpha ? VK_COLOR_COMPONENT_A_BIT : 0); (blue ? VK_COLOR_COMPONENT_B_BIT : 0) | (alpha ? VK_COLOR_COMPONENT_A_BIT : 0);
} }
VkShaderStageFlags GetShaderStageFlags(gl::ShaderBitSet activeShaders)
{
VkShaderStageFlags flags = 0;
for (const gl::ShaderType shaderType : activeShaders)
{
flags |= kShaderStageMap[shaderType];
}
return flags;
}
void GetViewport(const gl::Rectangle &viewport, void GetViewport(const gl::Rectangle &viewport,
float nearPlane, float nearPlane,
float farPlane, float farPlane,
......
...@@ -587,11 +587,19 @@ constexpr angle::PackedEnumMap<gl::DrawElementsType, VkIndexType> kIndexTypeMap ...@@ -587,11 +587,19 @@ constexpr angle::PackedEnumMap<gl::DrawElementsType, VkIndexType> kIndexTypeMap
{gl::DrawElementsType::UnsignedInt, VK_INDEX_TYPE_UINT32}, {gl::DrawElementsType::UnsignedInt, VK_INDEX_TYPE_UINT32},
}; };
constexpr gl::ShaderMap<VkShaderStageFlagBits> kShaderStageMap = {
{gl::ShaderType::Vertex, VK_SHADER_STAGE_VERTEX_BIT},
{gl::ShaderType::Fragment, VK_SHADER_STAGE_FRAGMENT_BIT},
{gl::ShaderType::Geometry, VK_SHADER_STAGE_GEOMETRY_BIT},
{gl::ShaderType::Compute, VK_SHADER_STAGE_COMPUTE_BIT},
};
void GetOffset(const gl::Offset &glOffset, VkOffset3D *vkOffset); void GetOffset(const gl::Offset &glOffset, VkOffset3D *vkOffset);
void GetExtent(const gl::Extents &glExtent, VkExtent3D *vkExtent); void GetExtent(const gl::Extents &glExtent, VkExtent3D *vkExtent);
VkImageType GetImageType(gl::TextureType textureType); VkImageType GetImageType(gl::TextureType textureType);
VkImageViewType GetImageViewType(gl::TextureType textureType); VkImageViewType GetImageViewType(gl::TextureType textureType);
VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bool alpha); VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bool alpha);
VkShaderStageFlags GetShaderStageFlags(gl::ShaderBitSet activeShaders);
void GetViewport(const gl::Rectangle &viewport, void GetViewport(const gl::Rectangle &viewport,
float nearPlane, float nearPlane,
......
...@@ -714,14 +714,20 @@ ...@@ -714,14 +714,20 @@
3520 VULKAN : dEQP-GLES31.functional.state_query.texture_level.texture_2d.compressed_integer = SKIP 3520 VULKAN : dEQP-GLES31.functional.state_query.texture_level.texture_2d.compressed_integer = SKIP
3520 VULKAN : dEQP-GLES31.functional.state_query.texture_level.texture_2d.compressed_float = SKIP 3520 VULKAN : dEQP-GLES31.functional.state_query.texture_level.texture_2d.compressed_float = SKIP
// Vulkan limits lower than GLES minimum:
3633 VULKAN : dEQP-GLES31.functional.state_query.integer.max_uniform_buffer_bindings_get* = FAIL
3633 VULKAN : dEQP-GLES31.functional.state_query.integer.max_combined_uniform_blocks_get* = FAIL
3633 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.20 = FAIL
3633 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.31 = FAIL
// column/row_major specified on struct member: // column/row_major specified on struct member:
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.2 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.9 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.12 = FAIL 3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.12 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.16 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.23 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.25 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.29 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_per_block_buffers.33 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_shared_buffer.3 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_shared_buffer.11 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_shared_buffer.25 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_shared_buffer.39 = FAIL
3443 VULKAN : dEQP-GLES31.functional.ubo.random.all_shared_buffer.45 = FAIL
// Validation errors: // Validation errors:
// Optimal tiling not supported for format: // Optimal tiling not supported for format:
......
...@@ -536,23 +536,8 @@ ...@@ -536,23 +536,8 @@
3676 VULKAN : dEQP-GLES3.functional.implementation_limits.max_fragment_input_components = FAIL 3676 VULKAN : dEQP-GLES3.functional.implementation_limits.max_fragment_input_components = FAIL
3676 VULKAN : dEQP-GLES3.functional.implementation_limits.max_program_texel_offset = FAIL 3676 VULKAN : dEQP-GLES3.functional.implementation_limits.max_program_texel_offset = FAIL
3676 VULKAN : dEQP-GLES3.functional.implementation_limits.min_program_texel_offset = FAIL 3676 VULKAN : dEQP-GLES3.functional.implementation_limits.min_program_texel_offset = FAIL
// MAX_FRAGMENT_INPUT_COMPONENTS is 0
// Vulkan limits lower than GLES minimum: 3676 VULKAN : dEQP-GLES3.functional.state_query.integers.max_fragment_input_components_get* = FAIL
3633 VULKAN : dEQP-GLES3.functional.implementation_limits.max_uniform_buffer_bindings = FAIL
3633 VULKAN : dEQP-GLES3.functional.implementation_limits.max_combined_uniform_blocks = FAIL
3633 VULKAN : dEQP-GLES3.functional.state_query.integers.max_uniform_buffer_bindings_getinteger64 = FAIL
3633 VULKAN : dEQP-GLES3.functional.state_query.integers.max_uniform_buffer_bindings_getfloat = FAIL
3633 VULKAN : dEQP-GLES3.functional.state_query.integers.max_combined_uniform_blocks_getinteger64 = FAIL
3633 VULKAN : dEQP-GLES3.functional.state_query.integers.max_combined_uniform_blocks_getfloat = FAIL
3633 VULKAN : dEQP-GLES3.functional.state_query.integers.max_fragment_input_components_get* = FAIL
3633 VULKAN : dEQP-GLES3.functional.state_query.integers64.max_combined_vertex_uniform_components_getinteger = FAIL
3633 VULKAN : dEQP-GLES3.functional.state_query.integers64.max_combined_vertex_uniform_components_getfloat = FAIL
3633 VULKAN : dEQP-GLES3.functional.state_query.integers64.max_combined_fragment_uniform_components_getinteger = FAIL
3633 VULKAN : dEQP-GLES3.functional.state_query.integers64.max_combined_fragment_uniform_components_getfloat = FAIL
3633 VULKAN : dEQP-GLES3.functional.ubo.random.all_shared_buffer.7 = FAIL
3633 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs_arrays_instance_arrays.18 = FAIL
3633 ANDROID VULKAN : dEQP-GLES3.functional.implementation_limits.max_combined_texture_image_units = FAIL
3633 ANDROID VULKAN : dEQP-GLES3.functional.state_query.integers.max_combined_texture_image_units_get* = FAIL
// 3D texture: // 3D texture:
3188 VULKAN : dEQP-GLES3.functional.fbo.completeness.layer.3d* = SKIP 3188 VULKAN : dEQP-GLES3.functional.fbo.completeness.layer.3d* = SKIP
...@@ -667,7 +652,29 @@ ...@@ -667,7 +652,29 @@
// Shader support: // Shader support:
3219 VULKAN : dEQP-GLES3.functional.negative_api.shader.link_program = FAIL 3219 VULKAN : dEQP-GLES3.functional.negative_api.shader.link_program = FAIL
3219 VULKAN : dEQP-GLES3.functional.negative_api.shader.use_program = FAIL 3219 VULKAN : dEQP-GLES3.functional.negative_api.shader.use_program = FAIL
// column/row_major specified on struct member:
3443 VULKAN : dEQP-GLES3.functional.ubo.random.basic_arrays.10 = FAIL 3443 VULKAN : dEQP-GLES3.functional.ubo.random.basic_arrays.10 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.all_per_block_buffers.8 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.all_per_block_buffers.17 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.all_per_block_buffers.25 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.all_per_block_buffers.49 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.all_shared_buffer.11 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.all_shared_buffer.48 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.basic_arrays.18 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.basic_arrays.20 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.basic_arrays.23 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.basic_arrays.8 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.basic_instance_arrays.13 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs.12 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs.17 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs.5 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs_arrays.2 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs_arrays.3 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs_arrays.4 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs_instance_arrays.12 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs_instance_arrays.18 = FAIL
3443 VULKAN : dEQP-GLES3.functional.ubo.random.nested_structs_instance_arrays.24 = FAIL
// New vertex attribute formats: // New vertex attribute formats:
3193 VULKAN : dEQP-GLES3.functional.vertex_arrays.single_attribute.*.int2_10_10_10.* = SKIP 3193 VULKAN : dEQP-GLES3.functional.vertex_arrays.single_attribute.*.int2_10_10_10.* = SKIP
......
...@@ -39,9 +39,6 @@ ...@@ -39,9 +39,6 @@
// GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set. // GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set.
3605 VULKAN : KHR-GLES31.core.texture_gather* = FAIL 3605 VULKAN : KHR-GLES31.core.texture_gather* = FAIL
// Vulkan limits lower than GLES minimum:
3633 VULKAN : KHR-GLES31.core.layout_binding.block_layout_binding_block_FragmentShader = FAIL
// Compute shaders // Compute shaders
3562 VULKAN : KHR-GLES31.core.constant_expressions.* = SKIP 3562 VULKAN : KHR-GLES31.core.constant_expressions.* = SKIP
3520 VULKAN : KHR-GLES31.core.compute_shader* = SKIP 3520 VULKAN : KHR-GLES31.core.compute_shader* = SKIP
......
...@@ -31,9 +31,6 @@ ...@@ -31,9 +31,6 @@
// For now we only log Vulkan test expectations. More back-ends can follow as we need them. // For now we only log Vulkan test expectations. More back-ends can follow as we need them.
// Vulkan limits lower than GLES minimum:
3633 VULKAN : KHR-GLES3.shaders.uniform_block.random.all_shared_buffer.1 = FAIL
// Crashes trying to load non-existent texture load function. // Crashes trying to load non-existent texture load function.
3455 VULKAN : KHR-GLES3.copy_tex_image_conversions.forbidden.* = SKIP 3455 VULKAN : KHR-GLES3.copy_tex_image_conversions.forbidden.* = SKIP
3455 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.renderbuffer_* = SKIP 3455 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.renderbuffer_* = SKIP
...@@ -50,5 +47,17 @@ ...@@ -50,5 +47,17 @@
// CopyTexImage conversion missing 2D Array and 3D texture support. // CopyTexImage conversion missing 2D Array and 3D texture support.
3458 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.* = SKIP 3458 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.* = SKIP
// column/row_major specified on struct member:
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.all_per_block_buffers.16 = FAIL
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.all_per_block_buffers.3 = FAIL
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.all_per_block_buffers.5 = FAIL
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.all_per_block_buffers.7 = FAIL
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.all_shared_buffer.0 = FAIL
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.basic_instance_arrays.0 = FAIL
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.basic_instance_arrays.4 = FAIL
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.basic_instance_arrays.5 = FAIL
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.nested_structs_arrays.7 = FAIL
3443 VULKAN : KHR-GLES3.shaders.uniform_block.random.nested_structs_arrays_instance_arrays.3 = FAIL
// Require 3D textures. // Require 3D textures.
3188 VULKAN : KHR-GLES3.packed_pixels.varied_rectangle.* = SKIP 3188 VULKAN : KHR-GLES3.packed_pixels.varied_rectangle.* = SKIP
...@@ -66,14 +66,20 @@ class VulkanUniformUpdatesTest : public ANGLETest ...@@ -66,14 +66,20 @@ class VulkanUniformUpdatesTest : public ANGLETest
programVk->getDynamicDescriptorPool(rx::kUniformsAndXfbDescriptorSetIndex); programVk->getDynamicDescriptorPool(rx::kUniformsAndXfbDescriptorSetIndex);
uniformPool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting); uniformPool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
rx::GetUniformBufferDescriptorCount()}; rx::kReservedDefaultUniformBindingCount};
(void)uniformPool->init(contextVk, &uniformSetSize, 1); (void)uniformPool->init(contextVk, &uniformSetSize, 1);
uint32_t textureCount =
static_cast<uint32_t>(programVk->getState().getSamplerBindings().size());
// To support the bindEmptyForUnusedDescriptorSets workaround.
textureCount = std::max(textureCount, 1u);
rx::vk::DynamicDescriptorPool *texturePool = rx::vk::DynamicDescriptorPool *texturePool =
programVk->getDynamicDescriptorPool(rx::kTextureDescriptorSetIndex); programVk->getDynamicDescriptorPool(rx::kTextureDescriptorSetIndex);
texturePool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting); texturePool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
contextVk->getRenderer()->getMaxActiveTextures()}; textureCount};
(void)texturePool->init(contextVk, &textureSetSize, 1); (void)texturePool->init(contextVk, &textureSetSize, 1);
} }
......
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