Commit 1cde0eab by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Add storage buffer support

The storage buffers are placed in the same descriptor set as uniform buffers. Some refactoring is done to reuse code that handles UBOs to handle SSBOs as well. A good number of tests still fail as they test SSBOs in conjunction with compute shaders. Bug: angleproject:3561 Change-Id: Ia33c1f68e6f6402c746f5919ede87b2c308cf81c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1687126 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 5dfad811
......@@ -70,7 +70,7 @@ enum
IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS = 8,
// Implementation upper limits, real maximums depend on the hardware.
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINIDNGS = 64
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS = 64
};
} // namespace gl
......
......@@ -3337,11 +3337,11 @@ void Context::initCaps()
IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS);
LimitCap(&mState.mCaps.maxShaderStorageBlocks[ShaderType::Compute],
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINIDNGS);
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
LimitCap(&mState.mCaps.maxShaderStorageBufferBindings,
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINIDNGS);
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
LimitCap(&mState.mCaps.maxCombinedShaderStorageBlocks,
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINIDNGS);
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
mState.mCaps.maxSampleMaskWords =
std::min<GLuint>(mState.mCaps.maxSampleMaskWords, MAX_SAMPLE_MASK_WORDS);
......
......@@ -466,6 +466,8 @@ using ActiveTextureTypeArray = ActiveTextureArray<TextureType>;
template <typename T>
using UniformBuffersArray = std::array<T, IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS>;
template <typename T>
using StorageBuffersArray = std::array<T, IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS>;
using ImageUnitMask = angle::BitSet<IMPLEMENTATION_MAX_IMAGE_UNITS>;
......
......@@ -3640,7 +3640,7 @@ angle::Result StateManager11::syncShaderStorageBuffersForShader(const gl::Contex
{
const gl::State &glState = context->getState();
const gl::Program *program = glState.getProgram();
angle::FixedVector<Buffer11 *, gl::IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINIDNGS>
angle::FixedVector<Buffer11 *, gl::IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS>
previouslyBound;
for (size_t blockIndex = 0; blockIndex < program->getActiveShaderStorageBlockCount();
blockIndex++)
......
......@@ -205,7 +205,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mNewCommandBufferDirtyBits.set(DIRTY_BIT_TEXTURES);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_UNIFORM_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_UNIFORM_AND_STORAGE_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
......@@ -215,7 +215,8 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mDirtyBitHandlers[DIRTY_BIT_VERTEX_BUFFERS] = &ContextVk::handleDirtyVertexBuffers;
mDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyIndexBuffer;
mDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] = &ContextVk::handleDirtyDriverUniforms;
mDirtyBitHandlers[DIRTY_BIT_UNIFORM_BUFFERS] = &ContextVk::handleDirtyUniformBuffers;
mDirtyBitHandlers[DIRTY_BIT_UNIFORM_AND_STORAGE_BUFFERS] =
&ContextVk::handleDirtyUniformAndStorageBuffers;
mDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
&ContextVk::handleDirtyTransformFeedbackBuffers;
mDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets;
......@@ -649,13 +650,13 @@ angle::Result ContextVk::handleDirtyIndexBuffer(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyUniformBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
angle::Result ContextVk::handleDirtyUniformAndStorageBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
if (mProgram->hasUniformBuffers())
if (mProgram->hasUniformBuffers() || mProgram->hasStorageBuffers())
{
ANGLE_TRY(
mProgram->updateUniformBuffersDescriptorSet(this, mDrawFramebuffer->getFramebuffer()));
ANGLE_TRY(mProgram->updateUniformAndStorageBuffersDescriptorSet(
this, mDrawFramebuffer->getFramebuffer()));
}
return angle::Result::Continue;
}
......@@ -1643,7 +1644,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
{
invalidateCurrentTextures();
invalidateCurrentUniformBuffers();
invalidateCurrentUniformAndStorageBuffers();
// No additional work is needed here. We will update the pipeline desc later.
invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
bool useVertexBuffer = (mProgram->getState().getMaxActiveAttribLocation());
......@@ -1663,9 +1664,10 @@ angle::Result ContextVk::syncState(const gl::Context *context,
// Nothing to do.
break;
case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
invalidateCurrentUniformAndStorageBuffers();
break;
case gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS:
invalidateCurrentUniformBuffers();
invalidateCurrentUniformAndStorageBuffers();
break;
case gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING:
break;
......@@ -1885,12 +1887,12 @@ void ContextVk::invalidateCurrentTextures()
}
}
void ContextVk::invalidateCurrentUniformBuffers()
void ContextVk::invalidateCurrentUniformAndStorageBuffers()
{
ASSERT(mProgram);
if (mProgram->hasUniformBuffers())
if (mProgram->hasUniformBuffers() || mProgram->hasStorageBuffers())
{
mDirtyBits.set(DIRTY_BIT_UNIFORM_BUFFERS);
mDirtyBits.set(DIRTY_BIT_UNIFORM_AND_STORAGE_BUFFERS);
mDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
}
......
......@@ -328,7 +328,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
DIRTY_BIT_VERTEX_BUFFERS,
DIRTY_BIT_INDEX_BUFFER,
DIRTY_BIT_DRIVER_UNIFORMS,
DIRTY_BIT_UNIFORM_BUFFERS,
DIRTY_BIT_UNIFORM_AND_STORAGE_BUFFERS,
DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS,
DIRTY_BIT_DESCRIPTOR_SETS,
DIRTY_BIT_MAX,
......@@ -382,7 +382,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
ANGLE_INLINE void invalidateCurrentPipeline() { mDirtyBits.set(DIRTY_BIT_PIPELINE); }
void invalidateCurrentTextures();
void invalidateCurrentUniformBuffers();
void invalidateCurrentUniformAndStorageBuffers();
void invalidateDriverUniforms();
angle::Result handleDirtyDefaultAttribs(const gl::Context *context,
......@@ -395,8 +395,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyDriverUniforms(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyUniformBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyUniformAndStorageBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyTransformFeedbackBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyDescriptorSets(const gl::Context *context,
......
......@@ -43,6 +43,7 @@ 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
......@@ -484,34 +485,10 @@ void GenerateTransformFeedbackOutputs(const gl::ProgramState &programState,
vertexShader->insertTransformFeedbackDeclaration(std::move(xfbDecl));
vertexShader->insertTransformFeedbackOutput(std::move(xfbOut));
}
} // anonymous namespace
// static
void GlslangWrapper::Initialize()
{
int result = ShInitialize();
ASSERT(result != 0);
}
// static
void GlslangWrapper::Release()
void AssignAttributeLocations(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource)
{
int result = ShFinalize();
ASSERT(result != 0);
}
// static
void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
std::string *vertexSourceOut,
std::string *fragmentSourceOut)
{
gl::Shader *glVertexShader = programState.getAttachedShader(gl::ShaderType::Vertex);
gl::Shader *glFragmentShader = programState.getAttachedShader(gl::ShaderType::Fragment);
IntermediateShaderSource vertexSource(glVertexShader->getTranslatedSource());
IntermediateShaderSource fragmentSource(glFragmentShader->getTranslatedSource());
// Parse attribute locations and replace them in the vertex shader.
// See corresponding code in OutputVulkanGLSL.cpp.
for (const sh::Attribute &attribute : programState.getAttributes())
......@@ -521,23 +498,14 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
ASSERT(attribute.active);
std::string locationString = "location = " + Str(attribute.location);
vertexSource.insertLayoutSpecifier(attribute.name, locationString);
vertexSource.insertQualifierSpecifier(attribute.name, "in");
}
// 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())
{
if (attribute.active)
{
continue;
}
vertexSource.eraseLayoutAndQualifierSpecifiers(attribute.name, "");
vertexSource->insertLayoutSpecifier(attribute.name, locationString);
vertexSource->insertQualifierSpecifier(attribute.name, "in");
}
}
void AssignOutputLocations(const gl::ProgramState &programState,
IntermediateShaderSource *fragmentSource)
{
// 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
......@@ -566,10 +534,15 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
locationString = "location = 0";
}
fragmentSource.insertLayoutSpecifier(outputVar.name, locationString);
fragmentSource->insertLayoutSpecifier(outputVar.name, locationString);
}
}
}
void AssignVaryingLocations(const gl::ProgramLinkedResources &resources,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
{
// Assign varying locations.
for (const gl::PackedVaryingRegister &varyingReg : resources.varyingPacking.getRegisterList())
{
......@@ -606,8 +579,8 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
const std::string &name =
varying.isStructField() ? varying.parentStructName : varying.varying->name;
vertexSource.insertLayoutSpecifier(name, locationString);
fragmentSource.insertLayoutSpecifier(name, locationString);
vertexSource->insertLayoutSpecifier(name, locationString);
fragmentSource->insertLayoutSpecifier(name, locationString);
const char *vsQualifier = "out";
const char *fsQualifier = "in";
......@@ -626,26 +599,32 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
default:
UNREACHABLE();
}
vertexSource.insertQualifierSpecifier(name, vsQualifier);
fragmentSource.insertQualifierSpecifier(name, fsQualifier);
vertexSource->insertQualifierSpecifier(name, vsQualifier);
fragmentSource->insertQualifierSpecifier(name, fsQualifier);
}
// Remove all the markers for unused varyings.
for (const std::string &varyingName : resources.varyingPacking.getInactiveVaryingNames())
{
vertexSource.eraseLayoutAndQualifierSpecifiers(varyingName, "");
fragmentSource.eraseLayoutAndQualifierSpecifiers(varyingName, "");
}
// Substitute layout and qualifier strings for the position varying. Use the first free
// varying register after the packed varyings.
constexpr char kVaryingName[] = "ANGLEPosition";
std::stringstream layoutStream;
layoutStream << "location = " << (resources.varyingPacking.getMaxSemanticIndex() + 1);
const std::string layout = layoutStream.str();
// Assign uniform locations
vertexSource->insertLayoutSpecifier(kVaryingName, layout);
fragmentSource->insertLayoutSpecifier(kVaryingName, layout);
vertexSource->insertQualifierSpecifier(kVaryingName, "out");
fragmentSource->insertQualifierSpecifier(kVaryingName, "in");
}
void AssignUniformLocations(IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
{
// 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);
const std::string uniformBlocksDescriptorSet = "set = " + Str(kUniformBlockDescriptorSetIndex);
const std::string texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex);
std::string vertexDefaultUniformsBinding =
uniformsDescriptorSet + ", binding = " + Str(kVertexUniformsBindingIndex);
......@@ -653,32 +632,66 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
uniformsDescriptorSet + ", binding = " + Str(kFragmentUniformsBindingIndex);
constexpr char kDefaultUniformsBlockName[] = "defaultUniforms";
vertexSource.insertLayoutSpecifier(kDefaultUniformsBlockName, vertexDefaultUniformsBinding);
fragmentSource.insertLayoutSpecifier(kDefaultUniformsBlockName, fragmentDefaultUniformsBinding);
vertexSource->insertLayoutSpecifier(kDefaultUniformsBlockName, vertexDefaultUniformsBinding);
fragmentSource->insertLayoutSpecifier(kDefaultUniformsBlockName,
fragmentDefaultUniformsBinding);
// 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);
vertexSource->insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
fragmentSource->insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
}
// Assign uniform blocks to a descriptor set and binding.
const auto &uniformBlocks = programState.getUniformBlocks();
uint32_t uniformBlockBinding = 0;
for (const gl::InterfaceBlock &uniformBlock : uniformBlocks)
void AssignInterfaceBlockLocations(const std::vector<gl::InterfaceBlock> &blocks,
uint32_t bindingStart,
const char *qualifier,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
{
const std::string buffersDescriptorSet = "set = " + Str(kBufferDescriptorSetIndex);
uint32_t uniformBlockBinding = bindingStart;
for (const gl::InterfaceBlock &block : blocks)
{
const std::string setBindingString =
uniformBlocksDescriptorSet + ", binding = " + Str(uniformBlockBinding);
buffersDescriptorSet + ", binding = " + Str(uniformBlockBinding);
vertexSource.insertLayoutSpecifier(uniformBlock.name, setBindingString);
fragmentSource.insertLayoutSpecifier(uniformBlock.name, setBindingString);
vertexSource->insertLayoutSpecifier(block.name, setBindingString);
fragmentSource->insertLayoutSpecifier(block.name, setBindingString);
vertexSource.insertQualifierSpecifier(uniformBlock.name, kUniformQualifier);
fragmentSource.insertQualifierSpecifier(uniformBlock.name, kUniformQualifier);
vertexSource->insertQualifierSpecifier(block.name, qualifier);
fragmentSource->insertQualifierSpecifier(block.name, qualifier);
++uniformBlockBinding;
}
}
// 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");
}
void AssignUniformBufferLocations(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
{
AssignInterfaceBlockLocations(programState.getUniformBlocks(), 0, kUniformQualifier,
vertexSource, fragmentSource);
}
void AssignStorageBufferLocations(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
{
AssignInterfaceBlockLocations(programState.getShaderStorageBlocks(),
static_cast<uint32_t>(programState.getUniformBlocks().size()),
kSSBOQualifier, vertexSource, fragmentSource);
}
void AssignTextureLocations(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
{
const std::string texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex);
// Assign textures to a descriptor set and binding.
uint32_t textureBinding = 0;
......@@ -696,24 +709,60 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
samplerUniform.isActive(gl::ShaderType::Fragment));
if (samplerUniform.isActive(gl::ShaderType::Vertex))
{
vertexSource.insertLayoutSpecifier(samplerName, setBindingString);
vertexSource->insertLayoutSpecifier(samplerName, setBindingString);
}
vertexSource.insertQualifierSpecifier(samplerName, kUniformQualifier);
vertexSource->insertQualifierSpecifier(samplerName, kUniformQualifier);
if (samplerUniform.isActive(gl::ShaderType::Fragment))
{
fragmentSource.insertLayoutSpecifier(samplerName, setBindingString);
fragmentSource->insertLayoutSpecifier(samplerName, setBindingString);
}
fragmentSource.insertQualifierSpecifier(samplerName, kUniformQualifier);
fragmentSource->insertQualifierSpecifier(samplerName, kUniformQualifier);
textureBinding++;
}
}
void CleanupUnusedEntities(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::Shader *glVertexShader,
IntermediateShaderSource *vertexSource,
IntermediateShaderSource *fragmentSource)
{
// 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())
{
if (attribute.active)
{
continue;
}
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, "");
}
// 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");
}
// 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);
for (const gl::UnusedUniform &unusedUniform : resources.unusedUniforms)
{
......@@ -729,36 +778,56 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
std::string layoutString = layoutStringStream.str();
vertexSource.insertLayoutSpecifier(uniformName, layoutString);
fragmentSource.insertLayoutSpecifier(uniformName, layoutString);
vertexSource->insertLayoutSpecifier(uniformName, layoutString);
fragmentSource->insertLayoutSpecifier(uniformName, layoutString);
vertexSource.insertQualifierSpecifier(uniformName, kUniformQualifier);
fragmentSource.insertQualifierSpecifier(uniformName, kUniformQualifier);
vertexSource->insertQualifierSpecifier(uniformName, kUniformQualifier);
fragmentSource->insertQualifierSpecifier(uniformName, kUniformQualifier);
}
else
{
vertexSource.eraseLayoutAndQualifierSpecifiers(unusedUniform.name, "");
fragmentSource.eraseLayoutAndQualifierSpecifiers(unusedUniform.name, "");
vertexSource->eraseLayoutAndQualifierSpecifiers(unusedUniform.name, "");
fragmentSource->eraseLayoutAndQualifierSpecifiers(unusedUniform.name, "");
}
}
}
} // anonymous namespace
// 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);
// static
void GlslangWrapper::Initialize()
{
int result = ShInitialize();
ASSERT(result != 0);
}
vertexSource.insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
fragmentSource.insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
// static
void GlslangWrapper::Release()
{
int result = ShFinalize();
ASSERT(result != 0);
}
// Substitute layout and qualifier strings for the position varying. Use the first free
// varying register after the packed varyings.
constexpr char kVaryingName[] = "ANGLEPosition";
std::stringstream layoutStream;
layoutStream << "location = " << (resources.varyingPacking.getMaxSemanticIndex() + 1);
const std::string layout = layoutStream.str();
vertexSource.insertLayoutSpecifier(kVaryingName, layout);
fragmentSource.insertLayoutSpecifier(kVaryingName, layout);
// static
void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
std::string *vertexSourceOut,
std::string *fragmentSourceOut)
{
gl::Shader *glVertexShader = programState.getAttachedShader(gl::ShaderType::Vertex);
gl::Shader *glFragmentShader = programState.getAttachedShader(gl::ShaderType::Fragment);
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);
CleanupUnusedEntities(programState, resources, glVertexShader, &vertexSource, &fragmentSource);
// Write transform feedback output code.
if (programState.getLinkedTransformFeedbackVaryings().empty())
......@@ -771,9 +840,6 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
GenerateTransformFeedbackOutputs(programState, &vertexSource);
}
vertexSource.insertQualifierSpecifier(kVaryingName, "out");
fragmentSource.insertQualifierSpecifier(kVaryingName, "in");
*vertexSourceOut = vertexSource.getShaderSource();
*fragmentSourceOut = fragmentSource.getShaderSource();
}
......
......@@ -132,23 +132,23 @@ angle::Result SyncDefaultUniformBlock(ContextVk *contextVk,
return angle::Result::Continue;
}
uint32_t GetUniformBlockArraySize(const std::vector<gl::InterfaceBlock> &uniformBlocks,
uint32_t bufferIndex)
uint32_t GetInterfaceBlockArraySize(const std::vector<gl::InterfaceBlock> &blocks,
uint32_t bufferIndex)
{
const gl::InterfaceBlock &uniformBlock = uniformBlocks[bufferIndex];
const gl::InterfaceBlock &block = blocks[bufferIndex];
if (!uniformBlock.isArray)
if (!block.isArray)
{
return 1;
}
ASSERT(uniformBlock.arrayElement == 0);
ASSERT(block.arrayElement == 0);
// Search consecutively until all array indices of this block are visited.
uint32_t arraySize;
for (arraySize = 1; bufferIndex + arraySize < uniformBlocks.size(); ++arraySize)
for (arraySize = 1; bufferIndex + arraySize < blocks.size(); ++arraySize)
{
const gl::InterfaceBlock &nextBlock = uniformBlocks[bufferIndex + arraySize];
const gl::InterfaceBlock &nextBlock = blocks[bufferIndex + arraySize];
if (nextBlock.arrayElement != arraySize)
{
......@@ -157,13 +157,29 @@ uint32_t GetUniformBlockArraySize(const std::vector<gl::InterfaceBlock> &uniform
// It's unexpected for an array to start at a non-zero array size, so we can always rely on
// the sequential `arrayElement`s to belong to the same block.
ASSERT(nextBlock.name == uniformBlock.name);
ASSERT(nextBlock.name == block.name);
ASSERT(nextBlock.isArray);
}
return arraySize;
}
void AddInterfaceBlockDescriptorSetDesc(const std::vector<gl::InterfaceBlock> &blocks,
uint32_t bindingStart,
VkDescriptorType descType,
vk::DescriptorSetLayoutDesc *descOut)
{
for (uint32_t bufferIndex = 0; bufferIndex < blocks.size();)
{
const uint32_t arraySize = GetInterfaceBlockArraySize(blocks, bufferIndex);
descOut->update(bindingStart + bufferIndex, descType, arraySize,
VK_SHADER_STAGE_ALL_GRAPHICS);
bufferIndex += arraySize;
}
}
class Std140BlockLayoutEncoderFactory : public gl::CustomBlockLayoutEncoderFactory
{
public:
......@@ -355,21 +371,16 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
contextVk, uniformsAndXfbSetDesc,
&mDescriptorSetLayouts[kUniformsAndXfbDescriptorSetIndex]));
vk::DescriptorSetLayoutDesc uniformBlocksSetDesc;
vk::DescriptorSetLayoutDesc buffersSetDesc;
const std::vector<gl::InterfaceBlock> &uniformBlocks = mState.getUniformBlocks();
for (uint32_t bufferIndex = 0; bufferIndex < uniformBlocks.size();)
{
const uint32_t arraySize = GetUniformBlockArraySize(uniformBlocks, bufferIndex);
AddInterfaceBlockDescriptorSetDesc(mState.getUniformBlocks(), getUniformBuffersBindingStart(),
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &buffersSetDesc);
AddInterfaceBlockDescriptorSetDesc(mState.getShaderStorageBlocks(),
getStorageBuffersBindingStart(),
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &buffersSetDesc);
uniformBlocksSetDesc.update(bufferIndex, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, arraySize,
VK_SHADER_STAGE_ALL_GRAPHICS);
bufferIndex += arraySize;
}
ANGLE_TRY(renderer->getDescriptorSetLayout(
contextVk, uniformBlocksSetDesc, &mDescriptorSetLayouts[kUniformBlockDescriptorSetIndex]));
ANGLE_TRY(renderer->getDescriptorSetLayout(contextVk, buffersSetDesc,
&mDescriptorSetLayouts[kBufferDescriptorSetIndex]));
vk::DescriptorSetLayoutDesc texturesSetDesc;
......@@ -396,8 +407,7 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
vk::PipelineLayoutDesc pipelineLayoutDesc;
pipelineLayoutDesc.updateDescriptorSetLayout(kUniformsAndXfbDescriptorSetIndex,
uniformsAndXfbSetDesc);
pipelineLayoutDesc.updateDescriptorSetLayout(kUniformBlockDescriptorSetIndex,
uniformBlocksSetDesc);
pipelineLayoutDesc.updateDescriptorSetLayout(kBufferDescriptorSetIndex, buffersSetDesc);
pipelineLayoutDesc.updateDescriptorSetLayout(kTextureDescriptorSetIndex, texturesSetDesc);
pipelineLayoutDesc.updateDescriptorSetLayout(kDriverUniformsDescriptorSetIndex,
driverUniformsSetDesc);
......@@ -410,14 +420,15 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
std::array<VkDescriptorPoolSize, 2> uniformAndXfbSetSize = {
{{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, GetUniformBufferDescriptorCount()},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS}}};
VkDescriptorPoolSize uniformBlockSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
renderer->getMaxUniformBlocks()};
VkDescriptorPoolSize textureSetSize = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
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()};
ANGLE_TRY(mDynamicDescriptorPools[kUniformsAndXfbDescriptorSetIndex].init(
contextVk, uniformAndXfbSetSize.data(), uniformAndXfbSetSize.size()));
ANGLE_TRY(mDynamicDescriptorPools[kUniformBlockDescriptorSetIndex].init(
contextVk, &uniformBlockSetSize, 1));
ANGLE_TRY(mDynamicDescriptorPools[kBufferDescriptorSetIndex].init(
contextVk, bufferSetSize.data(), bufferSetSize.size()));
ANGLE_TRY(
mDynamicDescriptorPools[kTextureDescriptorSetIndex].init(contextVk, &textureSetSize, 1));
......@@ -939,34 +950,42 @@ void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
vkUpdateDescriptorSets(device, kShaderTypeCount, writeDescriptorInfo.data(), 0, nullptr);
}
angle::Result ProgramVk::updateUniformBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer)
void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebufferVk,
const std::vector<gl::InterfaceBlock> &blocks,
VkDescriptorType descriptorType)
{
ANGLE_TRY(allocateDescriptorSet(contextVk, kUniformBlockDescriptorSetIndex));
VkDescriptorSet descriptorSet = mDescriptorSets[kUniformBlockDescriptorSetIndex];
gl::UniformBuffersArray<VkDescriptorBufferInfo> descriptorBufferInfo;
gl::UniformBuffersArray<VkWriteDescriptorSet> writeDescriptorInfo;
VkDescriptorSet descriptorSet = mDescriptorSets[kBufferDescriptorSetIndex];
ASSERT(descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
const bool isStorageBuffer = descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
const uint32_t bindingStart =
isStorageBuffer ? getStorageBuffersBindingStart() : getUniformBuffersBindingStart();
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;
// Write uniform buffers.
const gl::State &glState = contextVk->getState();
const std::vector<gl::InterfaceBlock> &uniformBlocks = mState.getUniformBlocks();
for (uint32_t bufferIndex = 0; bufferIndex < uniformBlocks.size(); ++bufferIndex)
// Write uniform or storage buffers.
const gl::State &glState = contextVk->getState();
for (uint32_t bufferIndex = 0; bufferIndex < blocks.size(); ++bufferIndex)
{
if (glState.getIndexedUniformBuffer(uniformBlocks[bufferIndex].binding).get() == nullptr)
const gl::InterfaceBlock &block = blocks[bufferIndex];
const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
isStorageBuffer ? glState.getIndexedShaderStorageBuffer(block.binding)
: glState.getIndexedUniformBuffer(block.binding);
if (bufferBinding.get() == nullptr)
{
continue;
}
VkWriteDescriptorSet &writeInfo = writeDescriptorInfo[writeCount];
VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[writeCount];
const gl::InterfaceBlock &uniformBlock = uniformBlocks[bufferIndex];
const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
glState.getIndexedUniformBuffer(uniformBlock.binding);
gl::Buffer *buffer = bufferBinding.get();
ASSERT(buffer != nullptr);
......@@ -978,35 +997,47 @@ angle::Result ProgramVk::updateUniformBuffersDescriptorSet(ContextVk *contextVk,
BufferVk *bufferVk = vk::GetImpl(buffer);
GLintptr offset = bufferBinding.getOffset();
VkDeviceSize size = bufferBinding.getSize();
VkDeviceSize blockSize = uniformBlock.dataSize;
VkDeviceSize blockSize = block.dataSize;
vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
bufferHelper.onRead(framebuffer, VK_ACCESS_UNIFORM_READ_BIT);
if (isStorageBuffer)
{
bufferHelper.onWrite(contextVk, framebufferVk, VK_ACCESS_SHADER_READ_BIT,
VK_ACCESS_SHADER_WRITE_BIT);
}
else
{
bufferHelper.onRead(framebufferVk, VK_ACCESS_UNIFORM_READ_BIT);
}
// If size is 0, we can't always use VK_WHOLE_SIZE (or bufferHelper.getSize()), as the
// backing buffer may be larger than maxUniformBufferRange. In that case, we use the
// minimum of the backing buffer size (what's left after offset) and the uniform buffer
// size as defined by the shader.
// backing buffer may be larger than max*BufferRange. In that case, we use the minimum of
// the backing buffer size (what's left after offset) and the buffer size as defined by the
// shader.
size = std::min(size > 0 ? size : (bufferHelper.getSize() - offset), blockSize);
VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[writeCount];
bufferInfo.buffer = bufferHelper.getBuffer().getHandle();
bufferInfo.offset = offset;
bufferInfo.range = size;
if (!uniformBlock.isArray || uniformBlock.arrayElement == 0)
if (!block.isArray || block.arrayElement == 0)
{
// Array indices of the same buffer binding are placed sequentially in `uniformBlocks`.
// Thus, the uniform block binding is updated only when array index 0 is encountered.
// 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;
writeInfo.pNext = nullptr;
writeInfo.dstSet = descriptorSet;
writeInfo.dstBinding = currentBinding;
writeInfo.dstArrayElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0;
writeInfo.dstBinding = bindingStart + currentBinding;
writeInfo.dstArrayElement = block.isArray ? block.arrayElement : 0;
writeInfo.descriptorCount = 1;
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeInfo.descriptorType = descriptorType;
writeInfo.pImageInfo = nullptr;
writeInfo.pBufferInfo = &bufferInfo;
writeInfo.pTexelBufferView = nullptr;
......@@ -1018,6 +1049,18 @@ angle::Result ProgramVk::updateUniformBuffersDescriptorSet(ContextVk *contextVk,
VkDevice device = contextVk->getDevice();
vkUpdateDescriptorSets(device, writeCount, writeDescriptorInfo.data(), 0, nullptr);
}
angle::Result ProgramVk::updateUniformAndStorageBuffersDescriptorSet(
ContextVk *contextVk,
vk::FramebufferHelper *framebufferVk)
{
ANGLE_TRY(allocateDescriptorSet(contextVk, kBufferDescriptorSetIndex));
updateBuffersDescriptorSet(contextVk, framebufferVk, mState.getUniformBlocks(),
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
updateBuffersDescriptorSet(contextVk, framebufferVk, mState.getShaderStorageBlocks(),
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
return angle::Result::Continue;
}
......
......@@ -108,8 +108,8 @@ class ProgramVk : public ProgramImpl
angle::Result updateUniforms(ContextVk *contextVk);
angle::Result updateTexturesDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
angle::Result updateUniformBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
angle::Result updateUniformAndStorageBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
angle::Result updateTransformFeedbackDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
......@@ -122,6 +122,7 @@ class ProgramVk : public ProgramImpl
bool hasTextures() const { return !mState.getSamplerBindings().empty(); }
bool hasUniformBuffers() const { return !mState.getUniformBlocks().empty(); }
bool hasStorageBuffers() const { return !mState.getShaderStorageBlocks().empty(); }
bool hasTransformFeedbackOutput() const
{
return !mState.getLinkedTransformFeedbackVaryings().empty();
......@@ -168,6 +169,10 @@ class ProgramVk : public ProgramImpl
void updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
void updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk);
void updateBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebufferVk,
const std::vector<gl::InterfaceBlock> &blocks,
VkDescriptorType descriptorType);
template <class T>
void getUniformImpl(GLint location, T *v, GLenum entryPointType) const;
......@@ -177,6 +182,12 @@ 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());
}
ANGLE_INLINE angle::Result initShaders(ContextVk *contextVk,
gl::PrimitiveMode mode,
vk::ShaderProgramHelper **shaderProgramOut)
......
......@@ -953,6 +953,8 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.samplerAnisotropy = mPhysicalDeviceFeatures.samplerAnisotropy;
enabledFeatures.features.vertexPipelineStoresAndAtomics =
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics;
enabledFeatures.features.fragmentStoresAndAtomics =
mPhysicalDeviceFeatures.fragmentStoresAndAtomics;
if (!vk::CommandBuffer::ExecutesInline())
{
enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
......@@ -1324,6 +1326,12 @@ uint32_t RendererVk::getMaxUniformBlocks() const
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
......
......@@ -86,6 +86,7 @@ class RendererVk : angle::NonCopyable
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; }
......
......@@ -895,7 +895,7 @@ class PipelineLayoutCache final : angle::NonCopyable
// correspond to default uniforms in the vertex and fragment shaders respectively. Additionally,
// transform feedback buffers are bound from binding 2 and up.
// - Set 1 contains all textures.
// - Set 2 contains all uniform blocks.
// - Set 2 contains all uniform and storage blocks.
// - Set 3 contains the ANGLE driver uniforms at binding 0. Note that driver uniforms are updated
// only under rare circumstances, such as viewport or depth range change. However, there is only
// one binding in this set.
......@@ -905,7 +905,7 @@ constexpr uint32_t kUniformsAndXfbDescriptorSetIndex = 0;
// Textures set index:
constexpr uint32_t kTextureDescriptorSetIndex = 1;
// Uniform blocks set index:
constexpr uint32_t kUniformBlockDescriptorSetIndex = 2;
constexpr uint32_t kBufferDescriptorSetIndex = 2;
// ANGLE driver uniforms set index (binding is always 3):
constexpr uint32_t kDriverUniformsDescriptorSetIndex = 3;
......
......@@ -210,9 +210,11 @@ void RendererVk::ensureCapsInitialized() const
const uint32_t maxPerStageStorageBuffers =
mPhysicalDeviceProperties.limits.maxPerStageDescriptorStorageBuffers;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] = maxPerStageStorageBuffers;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] = maxPerStageStorageBuffers;
mNativeCaps.maxCombinedShaderStorageBlocks = maxPerStageStorageBuffers;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] =
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics ? maxPerStageStorageBuffers : 0;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] =
mPhysicalDeviceFeatures.fragmentStoresAndAtomics ? maxPerStageStorageBuffers : 0;
mNativeCaps.maxCombinedShaderStorageBlocks = maxPerStageStorageBuffers;
// 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
......@@ -224,9 +226,12 @@ void RendererVk::ensureCapsInitialized() const
static_assert(
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS == 4,
"Limit to ES2.0 if supported SSBO count < supporting transform feedback buffer count");
ASSERT(maxPerStageStorageBuffers >= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] -=
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
if (mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics)
{
ASSERT(maxPerStageStorageBuffers >= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] -=
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
}
// Fill in additional limits for UBOs and SSBOs.
mNativeCaps.maxUniformBufferBindings = maxPerStageUniformBuffers;
......
......@@ -630,10 +630,11 @@
// Compute shaders:
3562 VULKAN : dEQP-GLES31.functional.shaders.builtin_var.compute.* = FAIL
3562 VULKAN : dEQP-GLES31.functional.compute.* = FAIL
3566 VULKAN : dEQP-GLES31.functional.ssbo.* = FAIL
3561 VULKAN : dEQP-GLES31.functional.synchronization.*.ssbo* = FAIL
3562 VULKAN : dEQP-GLES31.functional.shaders.builtin_functions.common.*compute = FAIL
3562 VULKAN : dEQP-GLES31.functional.shaders.builtin_functions.precision*compute* = FAIL
3562 VULKAN : dEQP-GLES31.functional.state_query.*.max_compute_* = FAIL
3562 VULKAN : dEQP-GLES31.functional.state_query.program.*compute* = SKIP
3563 VULKAN : dEQP-GLES31.functional.state_query.*compute* = SKIP
3562 VULKAN : dEQP-GLES31.functional.state_query.program.compute_work_group_size_get_programiv = FAIL
3562 VULKAN : dEQP-GLES31.functional.program_interface_query.buffer_limited_query.resource_*query = FAIL
3562 VULKAN : dEQP-GLES31.functional.program_interface_query.program_*.resource_list.compute.empty = FAIL
......@@ -653,7 +654,14 @@
3569 VULKAN : dEQP-GLES31.functional.shaders.builtin_constants.core.max_* = FAIL
3569 VULKAN : dEQP-GLES31.functional.shaders.builtin_constants.core.min_program_texel_offset = FAIL
3569 VULKAN : dEQP-GLES31.functional.shaders.uniform_block.es31.valid.* = FAIL
3569 VULKAN : dEQP-GLES31.functional.program_interface_query.uniform.referenced_by_shader.*float_struct = FAIL
// Array of array and struct default uniforms:
3604 VULKAN : dEQP-GLES31.functional.program_interface_query.*float_struct = FAIL
3604 VULKAN : dEQP-GLES31.functional.program_interface_query.*random* = FAIL
3604 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.* = SKIP
// Block name matching failure:
3459 VULKAN : dEQP-GLES31.functional.shaders.linkage.es31.shader_storage_block.mismatch_with_and_without_instance_name = FAIL
// Explicit uniform locations:
3597 VULKAN : dEQP-GLES31.functional.uniform_location.* = FAIL
......@@ -664,22 +672,8 @@
// Tessellation geometry interaction:
3572 VULKAN : dEQP-GLES31.functional.tessellation_geometry_interaction.* = FAIL
// SSBO:
3561 VULKAN : dEQP-GLES31.functional.ssbo.* = SKIP
3561 VULKAN : dEQP-GLES31.functional.layout_binding.ssbo.* = SKIP
3561 VULKAN : dEQP-GLES31.functional.state_query.integer.max_*shader_storage_block* = SKIP
3561 VULKAN : dEQP-GLES31.functional.state_query.*shader_storage_buffer* = SKIP
3561 VULKAN : dEQP-GLES31.functional.synchronization.*.ssbo* = SKIP
3561 VULKAN : dEQP-GLES31.functional.shaders.opaque_type_indexing.ssbo.* = SKIP
3561 VULKAN : dEQP-GLES31.functional.shaders.linkage*shader_storage_block* = SKIP
3561 VULKAN : dEQP-GLES31.functional.program_interface_query.shader_storage_block.* = SKIP
3561 VULKAN : dEQP-GLES31.functional.program_interface_query.buffer_variable.* = SKIP
3561 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.* = SKIP
// Atomic counters:
3566 VULKAN : dEQP-GLES31.functional.atomic_counter.* = FAIL
3566 VULKAN : dEQP-GLES31.functional.state_query.*atomic_counter* = FAIL
3563 VULKAN : dEQP-GLES31.functional.synchronization.*.atomic_counter* = FAIL
3566 VULKAN : dEQP-GLES31.functional.*atomic_counter* = FAIL
// Storage image:
3563 VULKAN : dEQP-GLES31.functional.state_query.*image* = FAIL
......
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