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,
......
......@@ -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