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