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)
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
// Saves the linking context for later use in resolveLink().
......@@ -955,7 +967,7 @@ ImageBinding::~ImageBinding() = default;
// ProgramState implementation.
ProgramState::ProgramState()
: mLabel(),
mAttachedShaders({}),
mAttachedShaders{},
mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
mMaxActiveAttribLocation(0),
mSamplerUniformRange(0, 0),
......@@ -991,6 +1003,16 @@ Shader *ProgramState::getAttachedShader(ShaderType shaderType) const
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
{
return GetResourceIndexFromName(mUniforms, name);
......@@ -1029,6 +1051,12 @@ GLuint ProgramState::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
return uniformIndex - mSamplerUniformRange.low();
}
GLuint ProgramState::getUniformIndexFromSamplerIndex(GLuint samplerIndex) const
{
ASSERT(samplerIndex < mSamplerUniformRange.length());
return samplerIndex + mSamplerUniformRange.low();
}
bool ProgramState::isImageUniformIndex(GLuint index) const
{
return mImageUniformRange.contains(index);
......@@ -1040,6 +1068,12 @@ GLuint ProgramState::getImageIndexFromUniformIndex(GLuint uniformIndex) const
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
{
for (const sh::Attribute &attribute : mAttributes)
......@@ -1433,6 +1467,8 @@ angle::Result Program::link(const Context *context)
mState.updateTransformFeedbackStrides();
}
updateLinkedShaderStages();
mLinkingState.reset(new LinkingState());
mLinkingState->context = context;
mLinkingState->linkingFromBinary = false;
......@@ -1474,7 +1510,6 @@ void Program::resolveLinkImpl(const Context *context)
// According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
// Only successfully linked program can replace the executables.
ASSERT(mLinked);
updateLinkedShaderStages();
// Mark implementation-specific unreferenced uniforms as ignored.
mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings,
......
......@@ -359,13 +359,19 @@ class ProgramState final : angle::NonCopyable
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 getUniformIndexFromLocation(GLint location) const;
Optional<GLuint> getSamplerIndex(GLint location) const;
bool isSamplerUniformIndex(GLuint index) const;
GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const;
GLuint getUniformIndexFromSamplerIndex(GLuint samplerIndex) const;
bool isImageUniformIndex(GLuint index) const;
GLuint getImageIndexFromUniformIndex(GLuint uniformIndex) const;
GLuint getUniformIndexFromImageIndex(GLuint imageIndex) const;
GLuint getAttributeLocation(const std::string &name) const;
GLuint getBufferVariableIndexFromName(const std::string &name) const;
......@@ -374,6 +380,11 @@ class ProgramState final : angle::NonCopyable
bool usesMultiview() const { return mNumViews != -1; }
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;
......
......@@ -410,7 +410,7 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor
bool isSampler = IsSamplerType(variable.type);
bool isImage = IsImageType(variable.type);
bool isAtomicCounter = IsAtomicCounterType(variable.type);
std::vector<gl::LinkedUniform> *uniformList = mUniforms;
std::vector<LinkedUniform> *uniformList = mUniforms;
if (isSampler)
{
uniformList = mSamplerUniforms;
......@@ -618,7 +618,7 @@ bool InterfaceBlockInfo::getBlockSize(const std::string &name,
size_t *sizeOut)
{
size_t nameLengthWithoutArrayIndex;
gl::ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
auto sizeIter = mBlockSizes.find(baseName);
if (sizeIter == mBlockSizes.end())
......@@ -699,7 +699,7 @@ bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
// Check that uniforms defined in the graphics shaders are identical
std::map<std::string, ShaderUniform> linkedUniforms;
for (ShaderType shaderType : kAllGraphicsShaderTypes)
for (const ShaderType shaderType : kAllGraphicsShaderTypes)
{
Shader *currentShader = mState.getAttachedShader(shaderType);
if (currentShader)
......@@ -988,7 +988,7 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoL
std::vector<LinkedUniform> atomicCounterUniforms;
std::vector<UnusedUniform> unusedUniforms;
for (ShaderType shaderType : AllShaderTypes())
for (const ShaderType shaderType : AllShaderTypes())
{
Shader *shader = mState.getAttachedShader(shaderType);
if (!shader)
......@@ -1050,7 +1050,7 @@ void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
std::set<std::string> visitedList;
for (ShaderType shaderType : AllShaderTypes())
for (const ShaderType shaderType : AllShaderTypes())
{
if (!mShaderBlocks[shaderType])
{
......@@ -1242,14 +1242,14 @@ ProgramLinkedResources::ProgramLinkedResources(
ProgramLinkedResources::~ProgramLinkedResources() = default;
void ProgramLinkedResourcesLinker::linkResources(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources) const
void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
const ProgramLinkedResources &resources) const
{
// Gather uniform interface block info.
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)
{
uniformBlockInfo.getShaderBlockInfo(shader->getUniformBlocks());
......@@ -1272,9 +1272,9 @@ void ProgramLinkedResourcesLinker::linkResources(const gl::ProgramState &program
// Gather storage bufer interface block info.
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)
{
shaderStorageBlockInfo.getShaderBlockInfo(shader->getShaderStorageBlocks());
......@@ -1303,12 +1303,12 @@ void ProgramLinkedResourcesLinker::linkResources(const gl::ProgramState &program
}
void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
const gl::ProgramState &programState,
const ProgramState &programState,
std::map<int, unsigned int> &sizeMapOut) const
{
for (unsigned int index : programState.getAtomicCounterUniformRange())
{
const gl::LinkedUniform &glUniform = programState.getUniforms()[index];
const LinkedUniform &glUniform = programState.getUniforms()[index];
auto &bufferDataSize = sizeMapOut[glUniform.binding];
......
......@@ -232,11 +232,11 @@ class ProgramLinkedResourcesLinker final : angle::NonCopyable
: mCustomEncoderFactory(customEncoderFactory)
{}
void linkResources(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources) const;
void linkResources(const ProgramState &programState,
const ProgramLinkedResources &resources) const;
private:
void getAtomicCounterBufferSizeMap(const gl::ProgramState &programState,
void getAtomicCounterBufferSizeMap(const ProgramState &programState,
std::map<int, unsigned int> &sizeMapOut) const;
CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
......
......@@ -26,12 +26,6 @@ void ActiveVariable::setActive(ShaderType shaderType, bool used)
mActiveUseBits.set(shaderType, used);
}
bool ActiveVariable::isActive(ShaderType shaderType) const
{
ASSERT(shaderType != ShaderType::InvalidEnum);
return mActiveUseBits[shaderType];
}
void ActiveVariable::unionReferencesWith(const ActiveVariable &other)
{
mActiveUseBits |= other.mActiveUseBits;
......
......@@ -31,7 +31,12 @@ struct ActiveVariable
ShaderType getFirstShaderTypeWhereActive() const;
void setActive(ShaderType shaderType, bool used);
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;
private:
......
......@@ -444,6 +444,11 @@ constexpr size_t kCubeFaceCount = 6;
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>
using AttachmentArray = std::array<T, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>;
......
......@@ -34,18 +34,20 @@ namespace rx
{
namespace
{
constexpr char kMarkerStart[] = "@@ ";
constexpr char kQualifierMarkerBegin[] = "@@ QUALIFIER-";
constexpr char kLayoutMarkerBegin[] = "@@ LAYOUT-";
constexpr char kXfbDeclMarkerBegin[] = "@@ XFB-DECL";
constexpr char kXfbOutMarkerBegin[] = "@@ XFB-OUT";
constexpr char kMarkerEnd[] = " @@";
constexpr char kParamsBegin = '(';
constexpr char kParamsEnd = ')';
constexpr char kUniformQualifier[] = "uniform";
constexpr char kSSBOQualifier[] = "buffer";
constexpr char kVersionDefine[] = "#version 450 core\n";
constexpr char kLineRasterDefine[] = R"(#version 450 core
constexpr char kMarkerStart[] = "@@ ";
constexpr char kQualifierMarkerBegin[] = "@@ QUALIFIER-";
constexpr char kLayoutMarkerBegin[] = "@@ LAYOUT-";
constexpr char kXfbDeclMarkerBegin[] = "@@ XFB-DECL";
constexpr char kXfbOutMarkerBegin[] = "@@ XFB-OUT";
constexpr char kMarkerEnd[] = " @@";
constexpr char kParamsBegin = '(';
constexpr char kParamsEnd = ')';
constexpr char kUniformQualifier[] = "uniform";
constexpr char kSSBOQualifier[] = "buffer";
constexpr char kUnusedBlockSubstitution[] = "struct";
constexpr char kUnusedUniformSubstitution[] = "// ";
constexpr char kVersionDefine[] = "#version 450 core\n";
constexpr char kLineRasterDefine[] = R"(#version 450 core
#define ANGLE_ENABLE_LINE_SEGMENT_RASTERIZATION
)";
......@@ -489,6 +491,8 @@ void GenerateTransformFeedbackOutputs(const gl::ProgramState &programState,
void AssignAttributeLocations(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource)
{
ASSERT(vertexSource != nullptr);
// Parse attribute locations and replace them in the vertex shader.
// See corresponding code in OutputVulkanGLSL.cpp.
for (const sh::Attribute &attribute : programState.getAttributes())
......@@ -506,6 +510,8 @@ void AssignAttributeLocations(const gl::ProgramState &programState,
void AssignOutputLocations(const gl::ProgramState &programState,
IntermediateShaderSource *fragmentSource)
{
ASSERT(fragmentSource != nullptr);
// Parse output locations and replace them in the fragment shader.
// See corresponding code in OutputVulkanGLSL.cpp.
// TODO(syoussefi): Add support for EXT_blend_func_extended. http://anglebug.com/3385
......@@ -540,8 +546,8 @@ void AssignOutputLocations(const gl::ProgramState &programState,
}
void AssignVaryingLocations(const gl::ProgramLinkedResources &resources,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
IntermediateShaderSource *outStageSource,
IntermediateShaderSource *inStageSource)
{
// Assign varying locations.
for (const gl::PackedVaryingRegister &varyingReg : resources.varyingPacking.getRegisterList())
......@@ -579,28 +585,28 @@ void AssignVaryingLocations(const gl::ProgramLinkedResources &resources,
const std::string &name =
varying.isStructField() ? varying.parentStructName : varying.varying->name;
vertexSource->insertLayoutSpecifier(name, locationString);
fragmentSource->insertLayoutSpecifier(name, locationString);
outStageSource->insertLayoutSpecifier(name, locationString);
inStageSource->insertLayoutSpecifier(name, locationString);
const char *vsQualifier = "out";
const char *fsQualifier = "in";
const char *outQualifier = "out";
const char *inQualifier = "in";
switch (varying.interpolation)
{
case sh::INTERPOLATION_SMOOTH:
break;
case sh::INTERPOLATION_CENTROID:
vsQualifier = "centroid out";
fsQualifier = "centroid in";
outQualifier = "centroid out";
inQualifier = "centroid in";
break;
case sh::INTERPOLATION_FLAT:
vsQualifier = "flat out";
fsQualifier = "flat in";
outQualifier = "flat out";
inQualifier = "flat in";
break;
default:
UNREACHABLE();
}
vertexSource->insertQualifierSpecifier(name, vsQualifier);
fragmentSource->insertQualifierSpecifier(name, fsQualifier);
outStageSource->insertQualifierSpecifier(name, outQualifier);
inStageSource->insertQualifierSpecifier(name, inQualifier);
}
// Substitute layout and qualifier strings for the position varying. Use the first free
......@@ -610,184 +616,205 @@ void AssignVaryingLocations(const gl::ProgramLinkedResources &resources,
layoutStream << "location = " << (resources.varyingPacking.getMaxSemanticIndex() + 1);
const std::string layout = layoutStream.str();
vertexSource->insertLayoutSpecifier(kVaryingName, layout);
fragmentSource->insertLayoutSpecifier(kVaryingName, layout);
outStageSource->insertLayoutSpecifier(kVaryingName, layout);
inStageSource->insertLayoutSpecifier(kVaryingName, layout);
vertexSource->insertQualifierSpecifier(kVaryingName, "out");
fragmentSource->insertQualifierSpecifier(kVaryingName, "in");
outStageSource->insertQualifierSpecifier(kVaryingName, "out");
inStageSource->insertQualifierSpecifier(kVaryingName, "in");
}
void AssignUniformLocations(IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
void AssignUniformBindings(const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
{
// Bind the default uniforms for vertex and fragment shaders.
// See corresponding code in OutputVulkanGLSL.cpp.
const std::string driverUniformsDescriptorSet =
"set = " + Str(kDriverUniformsDescriptorSetIndex);
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";
vertexSource->insertLayoutSpecifier(kDefaultUniformsBlockName, vertexDefaultUniformsBinding);
fragmentSource->insertLayoutSpecifier(kDefaultUniformsBlockName,
fragmentDefaultUniformsBinding);
size_t bindingIndex = 0;
for (IntermediateShaderSource *shaderSource : shaderSources)
{
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.
const std::string driverBlockLayoutString = driverUniformsDescriptorSet + ", binding = 0";
constexpr char kDriverBlockName[] = "ANGLEUniformBlock";
vertexSource->insertLayoutSpecifier(kDriverBlockName, driverBlockLayoutString);
fragmentSource->insertLayoutSpecifier(kDriverBlockName, driverBlockLayoutString);
const std::string driverBlockLayoutString =
"set = " + Str(kDriverUniformsDescriptorSetIndex) + ", binding = 0";
constexpr char kDriverBlockName[] = "ANGLEUniformBlock";
for (IntermediateShaderSource *shaderSource : shaderSources)
{
if (shaderSource)
{
shaderSource->insertLayoutSpecifier(kDriverBlockName, driverBlockLayoutString);
shaderSource->insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
}
}
}
vertexSource->insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
fragmentSource->insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
// Helper to go through shader stages and substitute layout and qualifier macros.
void AssignResourceBinding(gl::ShaderBitSet activeShaders,
const std::string &name,
const std::string &bindingString,
const char *qualifier,
const char *unusedSubstitution,
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);
}
}
}
}
void AssignInterfaceBlockLocations(const std::vector<gl::InterfaceBlock> &blocks,
uint32_t bindingStart,
const char *qualifier,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
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);
uint32_t uniformBlockBinding = bindingStart;
uint32_t bindingIndex = bindingStart;
for (const gl::InterfaceBlock &block : blocks)
{
const std::string setBindingString =
buffersDescriptorSet + ", binding = " + Str(uniformBlockBinding);
vertexSource->insertLayoutSpecifier(block.name, setBindingString);
fragmentSource->insertLayoutSpecifier(block.name, setBindingString);
vertexSource->insertQualifierSpecifier(block.name, qualifier);
fragmentSource->insertQualifierSpecifier(block.name, qualifier);
if (!block.isArray || block.arrayElement == 0)
{
const std::string bindingString =
buffersDescriptorSet + ", binding = " + Str(bindingIndex++);
++uniformBlockBinding;
AssignResourceBinding(block.activeShaders(), block.name, bindingString, qualifier,
kUnusedBlockSubstitution, shaderSources);
}
}
}
void AssignUniformBufferLocations(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
{
AssignInterfaceBlockLocations(programState.getUniformBlocks(), 0, kUniformQualifier,
vertexSource, fragmentSource);
return bindingIndex;
}
void AssignStorageBufferLocations(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
void AssignBufferBindings(const gl::ProgramState &programState,
const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
{
AssignInterfaceBlockLocations(programState.getShaderStorageBlocks(),
static_cast<uint32_t>(programState.getUniformBlocks().size()),
kSSBOQualifier, vertexSource, fragmentSource);
uint32_t bindingStart = 0;
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,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
void AssignTextureBindings(const gl::ProgramState &programState,
const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
{
const std::string texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex);
// Assign textures to a descriptor set and binding.
uint32_t textureBinding = 0;
const auto &uniforms = programState.getUniforms();
uint32_t bindingIndex = 0;
const std::vector<gl::LinkedUniform> &uniforms = programState.getUniforms();
for (unsigned int uniformIndex : programState.getSamplerUniformRange())
{
const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
const std::string setBindingString =
texturesDescriptorSet + ", binding = " + Str(textureBinding);
const std::string bindingString =
texturesDescriptorSet + ", binding = " + Str(bindingIndex++);
// Samplers in structs are extracted and renamed.
const std::string samplerName = GetMappedSamplerName(samplerUniform.name);
ASSERT(samplerUniform.isActive(gl::ShaderType::Vertex) ||
samplerUniform.isActive(gl::ShaderType::Fragment));
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++;
AssignResourceBinding(samplerUniform.activeShaders(), samplerName, bindingString,
kUniformQualifier, kUnusedUniformSubstitution, shaderSources);
}
}
void CleanupUnusedEntities(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::Shader *glVertexShader,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
{
// 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
// their @@ QUALIFIER and @@ LAYOUT markers.
for (const sh::Attribute &attribute : glVertexShader->getAllAttributes())
IntermediateShaderSource *vertexSource = shaderSources[gl::ShaderType::Vertex];
if (vertexSource)
{
if (attribute.active)
ASSERT(glVertexShader != nullptr);
// 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
// their @@ QUALIFIER and @@ LAYOUT markers.
for (const sh::Attribute &attribute : glVertexShader->getAllAttributes())
{
continue;
}
if (attribute.active)
{
continue;
}
vertexSource->eraseLayoutAndQualifierSpecifiers(attribute.name, "");
vertexSource->eraseLayoutAndQualifierSpecifiers(attribute.name, "");
}
}
// Remove all the markers for unused varyings.
for (const std::string &varyingName : resources.varyingPacking.getInactiveVaryingNames())
{
vertexSource->eraseLayoutAndQualifierSpecifiers(varyingName, "");
fragmentSource->eraseLayoutAndQualifierSpecifiers(varyingName, "");
for (IntermediateShaderSource *shaderSource : shaderSources)
{
if (shaderSource)
{
shaderSource->eraseLayoutAndQualifierSpecifiers(varyingName, "");
}
}
}
// Remove all the markers for unused interface blocks, and replace them with |struct|.
for (const std::string &unusedInterfaceBlock : resources.unusedInterfaceBlocks)
{
vertexSource->eraseLayoutAndQualifierSpecifiers(unusedInterfaceBlock, "struct");
fragmentSource->eraseLayoutAndQualifierSpecifiers(unusedInterfaceBlock, "struct");
for (IntermediateShaderSource *shaderSource : shaderSources)
{
if (shaderSource)
{
shaderSource->eraseLayoutAndQualifierSpecifiers(unusedInterfaceBlock,
kUnusedBlockSubstitution);
}
}
}
// Place the unused uniforms in the driver uniforms descriptor set, which has a fixed number of
// bindings. This avoids any possible index collision between uniform bindings set in the
// shader and the ones assigned here to the unused ones.
constexpr int kBaseUnusedSamplerBinding = kReservedDriverUniformBindingCount;
int unusedSamplerBinding = kBaseUnusedSamplerBinding;
const std::string driverUniformsDescriptorSet =
"set = " + Str(kDriverUniformsDescriptorSetIndex);
// Comment out unused uniforms. This relies on the fact that the shader compiler outputs
// uniforms to a single line.
for (const gl::UnusedUniform &unusedUniform : resources.unusedUniforms)
{
if (unusedUniform.isSampler)
{
// Samplers in structs are extracted and renamed.
std::string uniformName = GetMappedSamplerName(unusedUniform.name);
std::stringstream layoutStringStream;
layoutStringStream << driverUniformsDescriptorSet + ", binding = "
<< unusedSamplerBinding++;
std::string uniformName =
unusedUniform.isSampler ? GetMappedSamplerName(unusedUniform.name) : unusedUniform.name;
std::string layoutString = layoutStringStream.str();
vertexSource->insertLayoutSpecifier(uniformName, layoutString);
fragmentSource->insertLayoutSpecifier(uniformName, layoutString);
vertexSource->insertQualifierSpecifier(uniformName, kUniformQualifier);
fragmentSource->insertQualifierSpecifier(uniformName, kUniformQualifier);
}
else
for (IntermediateShaderSource *shaderSource : shaderSources)
{
vertexSource->eraseLayoutAndQualifierSpecifiers(unusedUniform.name, "");
fragmentSource->eraseLayoutAndQualifierSpecifiers(unusedUniform.name, "");
if (shaderSource)
{
shaderSource->eraseLayoutAndQualifierSpecifiers(uniformName,
kUnusedUniformSubstitution);
}
}
}
}
......@@ -819,15 +846,20 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
IntermediateShaderSource vertexSource(glVertexShader->getTranslatedSource());
IntermediateShaderSource fragmentSource(glFragmentShader->getTranslatedSource());
AssignAttributeLocations(programState, &vertexSource);
AssignOutputLocations(programState, &fragmentSource);
AssignVaryingLocations(resources, &vertexSource, &fragmentSource);
AssignUniformLocations(&vertexSource, &fragmentSource);
AssignUniformBufferLocations(programState, &vertexSource, &fragmentSource);
AssignStorageBufferLocations(programState, &vertexSource, &fragmentSource);
AssignTextureLocations(programState, &vertexSource, &fragmentSource);
gl::ShaderMap<IntermediateShaderSource *> shaderSources{};
shaderSources[gl::ShaderType::Vertex] = &vertexSource;
shaderSources[gl::ShaderType::Fragment] = &fragmentSource;
AssignAttributeLocations(programState, shaderSources[gl::ShaderType::Vertex]);
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.
if (programState.getLinkedTransformFeedbackVaryings().empty())
......
......@@ -26,7 +26,6 @@ namespace
constexpr size_t kUniformBlockDynamicBufferMinSize = 256 * 128;
void InitDefaultUniformBlock(const std::vector<sh::Uniform> &uniforms,
gl::Shader *shader,
sh::BlockLayoutMap *blockLayoutMapOut,
size_t *blockSizeOut)
{
......@@ -169,14 +168,17 @@ void AddInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> &b
VkDescriptorType descType,
vk::DescriptorSetLayoutDesc *descOut)
{
uint32_t bindingIndex = 0;
for (uint32_t bufferIndex = 0; bufferIndex < blocks.size();)
{
const uint32_t arraySize = GetInterfaceBlockArraySize(blocks, bufferIndex);
VkShaderStageFlags activeStages =
gl_vk::GetShaderStageFlags(blocks[bufferIndex].activeShaders());
descOut->update(bindingStart + bufferIndex, descType, arraySize,
VK_SHADER_STAGE_ALL_GRAPHICS);
descOut->update(bindingStart + bindingIndex, descType, arraySize, activeStages);
bufferIndex += arraySize;
++bindingIndex;
}
}
......@@ -219,7 +221,7 @@ angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk,
angle::Result ProgramVk::loadShaderSource(ContextVk *contextVk, gl::BinaryInputStream *stream)
{
// 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();
}
......@@ -230,7 +232,7 @@ angle::Result ProgramVk::loadShaderSource(ContextVk *contextVk, gl::BinaryInputS
void ProgramVk::saveShaderSource(gl::BinaryOutputStream *stream)
{
// 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]);
}
......@@ -251,7 +253,9 @@ ProgramVk::DefaultUniformBlock::DefaultUniformBlock() {}
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;
......@@ -350,19 +354,24 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
reset(contextVk);
updateBindingOffsets();
ANGLE_TRY(initDefaultUniformBlocks(glContext));
// Store a reference to the pipeline and descriptor set layouts. This will create them if they
// don't already exist in the cache.
// Default uniforms and transform feedback:
vk::DescriptorSetLayoutDesc uniformsAndXfbSetDesc;
uniformsAndXfbSetDesc.update(kVertexUniformsBindingIndex,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
VK_SHADER_STAGE_VERTEX_BIT);
uniformsAndXfbSetDesc.update(kFragmentUniformsBindingIndex,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
VK_SHADER_STAGE_FRAGMENT_BIT);
if (transformFeedback && !mState.getLinkedTransformFeedbackVaryings().empty())
uint32_t uniformBindingIndex = 0;
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{
uniformsAndXfbSetDesc.update(uniformBindingIndex++,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
gl_vk::kShaderStageMap[shaderType]);
}
if (mState.hasLinkedShaderStage(gl::ShaderType::Vertex) && transformFeedback &&
!mState.getLinkedTransformFeedbackVaryings().empty())
{
vk::GetImpl(transformFeedback)->updateDescriptorSetLayout(mState, &uniformsAndXfbSetDesc);
}
......@@ -371,17 +380,19 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
contextVk, uniformsAndXfbSetDesc,
&mDescriptorSetLayouts[kUniformsAndXfbDescriptorSetIndex]));
// Uniform and storage buffers:
vk::DescriptorSetLayoutDesc buffersSetDesc;
AddInterfaceBlockDescriptorSetDesc(mState.getUniformBlocks(), getUniformBuffersBindingStart(),
AddInterfaceBlockDescriptorSetDesc(mState.getUniformBlocks(), getUniformBlockBindingsOffset(),
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &buffersSetDesc);
AddInterfaceBlockDescriptorSetDesc(mState.getShaderStorageBlocks(),
getStorageBuffersBindingStart(),
getStorageBlockBindingsOffset(),
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &buffersSetDesc);
ANGLE_TRY(renderer->getDescriptorSetLayout(contextVk, buffersSetDesc,
&mDescriptorSetLayouts[kBufferDescriptorSetIndex]));
// Textures:
vk::DescriptorSetLayoutDesc texturesSetDesc;
for (uint32_t textureIndex = 0; textureIndex < mState.getSamplerBindings().size();
......@@ -389,10 +400,16 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
{
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.
const uint32_t count = static_cast<uint32_t>(samplerBinding.boundTextureUnits.size());
texturesSetDesc.update(textureIndex, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, count,
VK_SHADER_STAGE_ALL_GRAPHICS);
const uint32_t arraySize = static_cast<uint32_t>(samplerBinding.boundTextureUnits.size());
VkShaderStageFlags activeStages =
gl_vk::GetShaderStageFlags(samplerUniform.activeShaders());
texturesSetDesc.update(textureIndex, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, arraySize,
activeStages);
}
ANGLE_TRY(renderer->getDescriptorSetLayout(contextVk, texturesSetDesc,
......@@ -415,26 +432,58 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
ANGLE_TRY(renderer->getPipelineLayout(contextVk, pipelineLayoutDesc, mDescriptorSetLayouts,
&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 = {
{{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}}};
std::array<VkDescriptorPoolSize, 2> bufferSetSize = {
{{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, renderer->getMaxUniformBlocks()},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, renderer->getMaxStorageBlocks()}}};
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
renderer->getMaxActiveTextures()};
uint32_t uniformBlockCount = static_cast<uint32_t>(mState.getUniformBlocks().size());
uint32_t storageBlockCount = static_cast<uint32_t>(mState.getShaderStorageBlocks().size());
uint32_t textureCount = static_cast<uint32_t>(mState.getSamplerBindings().size());
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(
contextVk, uniformAndXfbSetSize.data(), uniformAndXfbSetSize.size()));
ANGLE_TRY(mDynamicDescriptorPools[kBufferDescriptorSetIndex].init(
contextVk, bufferSetSize.data(), bufferSetSize.size()));
ANGLE_TRY(
mDynamicDescriptorPools[kTextureDescriptorSetIndex].init(contextVk, &textureSetSize, 1));
if (bufferSetSize.size() > 0)
{
ANGLE_TRY(mDynamicDescriptorPools[kBufferDescriptorSetIndex].init(
contextVk, bufferSetSize.data(), bufferSetSize.size()));
}
if (textureCount > 0)
{
ANGLE_TRY(mDynamicDescriptorPools[kTextureDescriptorSetIndex].init(contextVk,
&textureSetSize, 1));
}
mDynamicBufferOffsets.resize(mState.getLinkedShaderStageCount());
return angle::Result::Continue;
}
void ProgramVk::updateBindingOffsets()
{
mStorageBlockBindingsOffset = mState.getUniqueUniformBlockCount();
}
void ProgramVk::linkResources(const gl::ProgramLinkedResources &resources)
{
Std140BlockLayoutEncoderFactory std140EncoderFactory;
......@@ -453,13 +502,14 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
gl::ShaderMap<size_t> requiredBufferSize;
requiredBufferSize.fill(0);
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{
gl::Shader *shader = mState.getAttachedShader(shaderType);
if (shader)
{
const std::vector<sh::Uniform> &uniforms = shader->getUniforms();
InitDefaultUniformBlock(uniforms, shader, &layoutMap[shaderType],
InitDefaultUniformBlock(uniforms, &layoutMap[shaderType],
&requiredBufferSize[shaderType]);
}
}
......@@ -484,7 +534,7 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
bool found = false;
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{
auto it = layoutMap[shaderType].find(uniformName);
if (it != layoutMap[shaderType].end())
......@@ -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]);
}
}
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{
if (requiredBufferSize[shaderType] > 0)
{
......@@ -569,7 +619,7 @@ void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum
if (linkedUniform.typeInfo->type == entryPointType)
{
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
......@@ -588,7 +638,7 @@ void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum
}
else
{
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
......@@ -722,7 +772,7 @@ void ProgramVk::setUniformMatrixfv(GLint location,
const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
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];
const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
......@@ -875,15 +925,16 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
ASSERT(dirtyUniforms());
bool anyNewBufferAllocated = false;
uint32_t offsetIndex = 0;
// 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];
if (mDefaultUniformBlocksDirty[shaderType])
{
bool bufferModified = false;
uint32_t offsetIndex = static_cast<uint32_t>(shaderType) - kShaderTypeMin;
bool bufferModified = false;
ANGLE_TRY(
SyncDefaultUniformBlock(contextVk, &uniformBlock.storage, uniformBlock.uniformData,
&mDynamicBufferOffsets[offsetIndex], &bufferModified));
......@@ -894,6 +945,8 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
anyNewBufferAllocated = true;
}
}
++offsetIndex;
}
if (anyNewBufferAllocated)
......@@ -910,15 +963,19 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
{
gl::ShaderMap<VkDescriptorBufferInfo> descriptorBufferInfo;
gl::ShaderMap<VkWriteDescriptorSet> writeDescriptorInfo;
size_t shaderStageCount = mState.getLinkedShaderStageCount();
gl::ShaderVector<VkDescriptorBufferInfo> descriptorBufferInfo(shaderStageCount);
gl::ShaderVector<VkWriteDescriptorSet> writeDescriptorInfo(shaderStageCount);
uint32_t bindingIndex = 0;
// Write default uniforms for each shader type.
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
for (const gl::ShaderType shaderType : mState.getLinkedShaderStages())
{
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[shaderType];
VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[shaderType];
VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[bindingIndex];
VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[bindingIndex];
if (!uniformBlock.uniformData.empty())
{
......@@ -936,18 +993,23 @@ void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfo.pNext = nullptr;
writeInfo.dstSet = mDescriptorSets[kUniformsAndXfbDescriptorSetIndex];
writeInfo.dstBinding = static_cast<uint32_t>(shaderType);
writeInfo.dstBinding = bindingIndex;
writeInfo.dstArrayElement = 0;
writeInfo.descriptorCount = 1;
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
writeInfo.pImageInfo = nullptr;
writeInfo.pBufferInfo = &bufferInfo;
writeInfo.pTexelBufferView = nullptr;
++bindingIndex;
}
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,
......@@ -961,16 +1023,19 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
const bool isStorageBuffer = descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
const uint32_t bindingStart =
isStorageBuffer ? getStorageBuffersBindingStart() : getUniformBuffersBindingStart();
isStorageBuffer ? getStorageBlockBindingsOffset() : getUniformBlockBindingsOffset();
static_assert(
gl::IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS >=
gl::IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS,
"The descriptor arrays here would have inadequate size for uniform buffer objects");
gl::StorageBuffersArray<VkDescriptorBufferInfo> descriptorBufferInfo;
gl::StorageBuffersArray<VkWriteDescriptorSet> writeDescriptorInfo;
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.
const gl::State &glState = contextVk->getState();
......@@ -981,6 +1046,13 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
isStorageBuffer ? glState.getIndexedShaderStorageBuffer(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)
{
continue;
......@@ -1022,13 +1094,6 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
bufferInfo.offset = offset;
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];
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
......@@ -1094,8 +1159,8 @@ void ProgramVk::updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk)
}
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(glState.getCurrentTransformFeedback());
transformFeedbackVk->updateDescriptorSet(
contextVk, mState, mDescriptorSets[kUniformsAndXfbDescriptorSetIndex], kShaderTypeCount);
transformFeedbackVk->updateDescriptorSet(contextVk, mState,
mDescriptorSets[kUniformsAndXfbDescriptorSetIndex]);
}
angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk,
......@@ -1163,13 +1228,14 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk,
writeInfo.pBufferInfo = nullptr;
writeInfo.pTexelBufferView = nullptr;
writeCount++;
++writeCount;
}
}
VkDevice device = contextVk->getDevice();
ASSERT(writeCount > 0);
vkUpdateDescriptorSets(device, writeCount, writeDescriptorInfo.data(), 0, nullptr);
mTextureDescriptorsCache.emplace(texturesDesc, descriptorSet);
......@@ -1236,11 +1302,12 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
// through dynamic uniform buffers (requiring dynamic offsets). No other descriptor
// requires a dynamic offset.
const uint32_t uniformBlockOffsetCount =
descriptorSetIndex == kUniformsAndXfbDescriptorSetIndex ? kShaderTypeCount : 0;
descriptorSetIndex == kUniformsAndXfbDescriptorSetIndex ? mDynamicBufferOffsets.size()
: 0;
commandBuffer->bindGraphicsDescriptorSets(mPipelineLayout.get(), descriptorSetIndex, 1,
&descSet, uniformBlockOffsetCount,
mDynamicBufferOffsets.data() + kShaderTypeMin);
mDynamicBufferOffsets.data());
}
return angle::Result::Continue;
......
......@@ -182,11 +182,9 @@ class ProgramVk : public ProgramImpl
angle::Result linkImpl(const gl::Context *glContext, gl::InfoLog &infoLog);
void linkResources(const gl::ProgramLinkedResources &resources);
uint32_t getUniformBuffersBindingStart() const { return 0; }
uint32_t getStorageBuffersBindingStart() const
{
return static_cast<uint32_t>(mState.getUniformBlocks().size());
}
void updateBindingOffsets();
uint32_t getUniformBlockBindingsOffset() const { return 0; }
uint32_t getStorageBlockBindingsOffset() const { return mStorageBlockBindingsOffset; }
ANGLE_INLINE angle::Result initShaders(ContextVk *contextVk,
gl::PrimitiveMode mode,
......@@ -233,10 +231,7 @@ class ProgramVk : public ProgramImpl
gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks;
gl::ShaderBitSet mDefaultUniformBlocksDirty;
static constexpr uint32_t kShaderTypeMin = static_cast<uint32_t>(gl::kGLES2ShaderTypeMin);
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;
gl::ShaderVector<uint32_t> mDynamicBufferOffsets;
// 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,
......@@ -285,6 +280,10 @@ class ProgramVk : public ProgramImpl
// We keep the translated linked shader sources to use with shader draw call patching.
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
// cache management. It can also allow fewer descriptors for shaders which use fewer
// textures/buffers.
......
......@@ -47,9 +47,6 @@ namespace rx
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)
constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60;
// Wait a maximum of 10s. If that times out, we declare it a failure.
......@@ -1322,25 +1319,6 @@ const gl::Limitations &RendererVk::getNativeLimitations() const
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(
vk::Context *context,
const vk::DescriptorSetLayoutDesc &desc,
......@@ -1575,9 +1553,4 @@ angle::Result RendererVk::cleanupGarbage(vk::Context *context, bool block)
return angle::Result::Continue;
}
uint32_t GetUniformBufferDescriptorCount()
{
return kUniformBufferDescriptorsPerDescriptorSet;
}
} // namespace rx
......@@ -85,9 +85,6 @@ class RendererVk : angle::NonCopyable
const gl::TextureCapsMap &getNativeTextureCaps() const;
const gl::Extensions &getNativeExtensions() const;
const gl::Limitations &getNativeLimitations() const;
uint32_t getMaxUniformBlocks() const;
uint32_t getMaxStorageBlocks() const;
uint32_t getMaxActiveTextures() const;
uint32_t getQueueFamilyIndex() const { return mCurrentQueueFamilyIndex; }
......@@ -233,8 +230,6 @@ class RendererVk : angle::NonCopyable
DescriptorSetLayoutCache mDescriptorSetLayoutCache;
};
uint32_t GetUniformBufferDescriptorCount();
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_RENDERERVK_H_
......@@ -135,8 +135,7 @@ void TransformFeedbackVk::addFramebufferDependency(ContextVk *contextVk,
void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
const gl::ProgramState &programState,
VkDescriptorSet descSet,
uint32_t bindingOffset) const
VkDescriptorSet descSet) const
{
const std::vector<gl::OffsetBindingPointer<gl::Buffer>> &xfbBuffers =
mState.getIndexedBuffers();
......@@ -171,7 +170,7 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
VkWriteDescriptorSet writeDescriptorInfo = {};
writeDescriptorInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorInfo.dstSet = descSet;
writeDescriptorInfo.dstBinding = bindingOffset;
writeDescriptorInfo.dstBinding = kXfbBindingIndexStart;
writeDescriptorInfo.dstArrayElement = 0;
writeDescriptorInfo.descriptorCount = xfbBufferCount;
writeDescriptorInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
......
......@@ -47,8 +47,7 @@ class TransformFeedbackVk : public TransformFeedbackImpl
vk::FramebufferHelper *framebuffer) const;
void updateDescriptorSet(ContextVk *contextVk,
const gl::ProgramState &programState,
VkDescriptorSet descSet,
uint32_t bindingOffset) const;
VkDescriptorSet descSet) const;
void getBufferOffsets(ContextVk *contextVk,
const gl::ProgramState &programState,
GLint drawCallFirstVertex,
......
......@@ -1429,7 +1429,7 @@ void PipelineLayoutDesc::updatePushConstantRange(gl::ShaderType shaderType,
{
ASSERT(shaderType == gl::ShaderType::Vertex || shaderType == gl::ShaderType::Fragment ||
shaderType == gl::ShaderType::Compute);
PackedPushConstantRange &packed = mPushConstantRanges[static_cast<size_t>(shaderType)];
PackedPushConstantRange &packed = mPushConstantRanges[shaderType];
packed.offset = offset;
packed.size = size;
}
......@@ -1770,30 +1770,22 @@ angle::Result PipelineLayoutCache::getPipelineLayout(
}
}
angle::FixedVector<VkPushConstantRange, vk::kMaxPushConstantRanges> pushConstantRanges;
const vk::PushConstantRangeArray<vk::PackedPushConstantRange> &descPushConstantRanges =
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)
{
static constexpr VkShaderStageFlagBits kShaderStages[vk::kMaxPushConstantRanges] = {
VK_SHADER_STAGE_VERTEX_BIT,
VK_SHADER_STAGE_FRAGMENT_BIT,
VK_SHADER_STAGE_GEOMETRY_BIT,
VK_SHADER_STAGE_COMPUTE_BIT,
};
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);
VkPushConstantRange range;
range.stageFlags = gl_vk::kShaderStageMap[shaderType];
range.offset = pushConstantDesc.offset;
range.size = pushConstantDesc.size;
pushConstantRanges.push_back(range);
}
}
......@@ -1803,7 +1795,7 @@ angle::Result PipelineLayoutCache::getPipelineLayout(
createInfo.flags = 0;
createInfo.setLayoutCount = static_cast<uint32_t>(setLayoutHandles.size());
createInfo.pSetLayouts = setLayoutHandles.data();
createInfo.pushConstantRangeCount = static_cast<uint32_t>(pushConstantRanges.size());
createInfo.pushConstantRangeCount = pushConstantRanges.size();
createInfo.pPushConstantRanges = pushConstantRanges.data();
vk::PipelineLayout newLayout;
......
......@@ -532,10 +532,9 @@ class DescriptorSetLayoutDesc final
mPackedDescriptorSetLayout;
};
// 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.
// The following are for caching descriptor set layouts. Limited to max four descriptor set layouts.
// This can be extended in the future.
constexpr size_t kMaxDescriptorSetLayouts = 4;
constexpr size_t kMaxPushConstantRanges = angle::EnumSize<gl::ShaderType>();
struct PackedPushConstantRange
{
......@@ -548,7 +547,7 @@ using DescriptorSetLayoutArray = std::array<T, kMaxDescriptorSetLayouts>;
using DescriptorSetLayoutPointerArray =
DescriptorSetLayoutArray<BindingPointer<DescriptorSetLayout>>;
template <typename T>
using PushConstantRangeArray = std::array<T, kMaxPushConstantRanges>;
using PushConstantRangeArray = gl::ShaderMap<T>;
class PipelineLayoutDesc final
{
......@@ -575,14 +574,14 @@ class PipelineLayoutDesc final
(sizeof(DescriptorSetLayoutDesc) * kMaxDescriptorSetLayouts),
"Unexpected size");
static_assert(sizeof(decltype(mPushConstantRanges)) ==
(sizeof(PackedPushConstantRange) * kMaxPushConstantRanges),
(sizeof(PackedPushConstantRange) * angle::EnumSize<gl::ShaderType>()),
"Unexpected size");
};
// Verify the structure is properly packed.
static_assert(sizeof(PipelineLayoutDesc) ==
(sizeof(DescriptorSetLayoutArray<DescriptorSetLayoutDesc>) +
sizeof(std::array<PackedPushConstantRange, kMaxPushConstantRanges>)),
sizeof(gl::ShaderMap<PackedPushConstantRange>)),
"Unexpected Size");
// Disable warnings about struct padding.
......@@ -911,12 +910,12 @@ constexpr uint32_t kDriverUniformsDescriptorSetIndex = 3;
// Only 1 driver uniform binding is used.
constexpr uint32_t kReservedDriverUniformBindingCount = 1;
// Binding index for default uniforms in the vertex shader:
constexpr uint32_t kVertexUniformsBindingIndex = 0;
// Binding index for default uniforms in the fragment shader:
constexpr uint32_t kFragmentUniformsBindingIndex = 1;
// There is 1 default uniform binding used per stage. Currently, a maxium of two stages are
// supported.
constexpr uint32_t kReservedPerStageDefaultUniformBindingCount = 1;
constexpr uint32_t kReservedDefaultUniformBindingCount = 2;
// Binding index start for transform feedback buffers:
constexpr uint32_t kXfbBindingIndexStart = 2;
constexpr uint32_t kXfbBindingIndexStart = kReservedDefaultUniformBindingCount;
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
......@@ -176,12 +176,13 @@ void RendererVk::ensureCapsInitialized() const
// we'll defer the implementation until we tackle the next version.
// mNativeCaps.maxServerWaitTimeout
GLuint maxUniformVectors = mPhysicalDeviceProperties.limits.maxUniformBufferRange /
(sizeof(GLfloat) * kComponentsPerVector);
GLuint maxUniformBlockSize = mPhysicalDeviceProperties.limits.maxUniformBufferRange;
// Clamp the maxUniformVectors to 1024u, on AMD the maxUniformBufferRange is way too high.
maxUniformVectors = std::min(1024u, maxUniformVectors);
// Clamp the maxUniformBlockSize to 64KB (majority of devices support up to this size
// 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;
// Uniforms are implemented using a uniform buffer, so the max number of uniforms we can
......@@ -191,30 +192,49 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.maxFragmentUniformVectors = maxUniformVectors;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxUniformComponents;
// We use the same bindings on each stage, so the texture, UBO and SSBO limitations are the same
// as the per-stage limits.
// Every stage has 1 reserved uniform buffer for the default uniforms, and 1 for the driver
// uniforms.
constexpr uint32_t kTotalReservedPerStageUniformBuffers =
kReservedDriverUniformBindingCount + kReservedPerStageDefaultUniformBindingCount;
constexpr uint32_t kTotalReservedUniformBuffers =
kReservedDriverUniformBindingCount + kReservedDefaultUniformBindingCount;
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::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
// the minimum of supported samplers and sampled images.
const uint32_t maxPerStageTextures =
std::min(mPhysicalDeviceProperties.limits.maxPerStageDescriptorSamplers,
mPhysicalDeviceProperties.limits.maxPerStageDescriptorSampledImages);
mNativeCaps.maxCombinedTextureImageUnits = maxPerStageTextures;
mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] = maxPerStageTextures;
const uint32_t maxCombinedTextures =
std::min(mPhysicalDeviceProperties.limits.maxDescriptorSetSamplers,
mPhysicalDeviceProperties.limits.maxDescriptorSetSampledImages);
mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex] = maxPerStageTextures;
mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] = maxPerStageTextures;
mNativeCaps.maxCombinedTextureImageUnits = maxCombinedTextures;
const uint32_t maxPerStageStorageBuffers =
mPhysicalDeviceProperties.limits.maxPerStageDescriptorStorageBuffers;
const uint32_t maxCombinedStorageBuffers =
mPhysicalDeviceProperties.limits.maxDescriptorSetStorageBuffers;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] =
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics ? maxPerStageStorageBuffers : 0;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] =
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.
// Note that Vulkan requires maxPerStageDescriptorStorageBuffers to be at least 4 (i.e. the same
......@@ -231,22 +251,21 @@ void RendererVk::ensureCapsInitialized() const
ASSERT(maxPerStageStorageBuffers >= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] -=
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
mNativeCaps.maxCombinedShaderStorageBlocks -=
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
}
// Fill in additional limits for UBOs and SSBOs.
mNativeCaps.maxUniformBufferBindings = maxPerStageUniformBuffers;
mNativeCaps.maxUniformBlockSize = mPhysicalDeviceProperties.limits.maxUniformBufferRange;
mNativeCaps.uniformBufferOffsetAlignment =
static_cast<GLuint>(mPhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment);
mNativeCaps.maxShaderStorageBufferBindings = maxPerStageStorageBuffers;
mNativeCaps.maxShaderStorageBufferBindings = maxCombinedStorageBuffers;
mNativeCaps.maxShaderStorageBlockSize = mPhysicalDeviceProperties.limits.maxStorageBufferRange;
mNativeCaps.shaderStorageBufferOffsetAlignment =
static_cast<GLuint>(mPhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment);
// 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.
const uint32_t maxCombinedUniformComponents = maxPerStageUniformBuffers * maxUniformComponents;
// maximum number of uniform buffers, each having the maximum number of components. Note that
// this limit includes both components in and out of uniform buffers.
const uint32_t maxCombinedUniformComponents =
(maxPerStageUniformBuffers + kReservedPerStageDefaultUniformBindingCount) *
maxUniformComponents;
for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
{
mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents;
......
......@@ -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);
}
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,
float nearPlane,
float farPlane,
......
......@@ -587,11 +587,19 @@ constexpr angle::PackedEnumMap<gl::DrawElementsType, VkIndexType> kIndexTypeMap
{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 GetExtent(const gl::Extents &glExtent, VkExtent3D *vkExtent);
VkImageType GetImageType(gl::TextureType textureType);
VkImageViewType GetImageViewType(gl::TextureType textureType);
VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bool alpha);
VkShaderStageFlags GetShaderStageFlags(gl::ShaderBitSet activeShaders);
void GetViewport(const gl::Rectangle &viewport,
float nearPlane,
......
......@@ -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_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:
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.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:
// Optimal tiling not supported for format:
......
......@@ -536,23 +536,8 @@
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.min_program_texel_offset = FAIL
// Vulkan limits lower than GLES minimum:
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
// MAX_FRAGMENT_INPUT_COMPONENTS is 0
3676 VULKAN : dEQP-GLES3.functional.state_query.integers.max_fragment_input_components_get* = FAIL
// 3D texture:
3188 VULKAN : dEQP-GLES3.functional.fbo.completeness.layer.3d* = SKIP
......@@ -667,7 +652,29 @@
// Shader support:
3219 VULKAN : dEQP-GLES3.functional.negative_api.shader.link_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.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:
3193 VULKAN : dEQP-GLES3.functional.vertex_arrays.single_attribute.*.int2_10_10_10.* = SKIP
......
......@@ -39,9 +39,6 @@
// GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set.
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
3562 VULKAN : KHR-GLES31.core.constant_expressions.* = SKIP
3520 VULKAN : KHR-GLES31.core.compute_shader* = SKIP
......
......@@ -31,9 +31,6 @@
// 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.
3455 VULKAN : KHR-GLES3.copy_tex_image_conversions.forbidden.* = SKIP
3455 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.renderbuffer_* = SKIP
......@@ -50,5 +47,17 @@
// CopyTexImage conversion missing 2D Array and 3D texture support.
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.
3188 VULKAN : KHR-GLES3.packed_pixels.varied_rectangle.* = SKIP
......@@ -66,14 +66,20 @@ class VulkanUniformUpdatesTest : public ANGLETest
programVk->getDynamicDescriptorPool(rx::kUniformsAndXfbDescriptorSetIndex);
uniformPool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
rx::GetUniformBufferDescriptorCount()};
rx::kReservedDefaultUniformBindingCount};
(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 =
programVk->getDynamicDescriptorPool(rx::kTextureDescriptorSetIndex);
texturePool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
contextVk->getRenderer()->getMaxActiveTextures()};
textureCount};
(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