Commit 2e43b0f5 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Implement memory barriers

Bug: angleproject:3574 Change-Id: I13d8f4fcd6f1bf9bf3496c91c2c697076e2491bd Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1699005Reviewed-by: 's avatarTobin Ehlis <tobine@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 7a5f35c4
...@@ -112,6 +112,8 @@ const char *GetResourceTypeName(CommandGraphResourceType resourceType, ...@@ -112,6 +112,8 @@ const char *GetResourceTypeName(CommandGraphResourceType resourceType,
UNREACHABLE(); UNREACHABLE();
return "FenceSync"; return "FenceSync";
} }
case CommandGraphResourceType::GraphBarrier:
return "GraphBarrier";
case CommandGraphResourceType::DebugMarker: case CommandGraphResourceType::DebugMarker:
switch (function) switch (function)
{ {
...@@ -355,6 +357,7 @@ CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function, ...@@ -355,6 +357,7 @@ CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function,
mVisitedState(VisitedState::Unvisited), mVisitedState(VisitedState::Unvisited),
mGlobalMemoryBarrierSrcAccess(0), mGlobalMemoryBarrierSrcAccess(0),
mGlobalMemoryBarrierDstAccess(0), mGlobalMemoryBarrierDstAccess(0),
mGlobalMemoryBarrierStages(0),
mRenderPassOwner(nullptr) mRenderPassOwner(nullptr)
{} {}
...@@ -529,26 +532,24 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context, ...@@ -529,26 +532,24 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
RenderPassCache *renderPassCache, RenderPassCache *renderPassCache,
PrimaryCommandBuffer *primaryCommandBuffer) PrimaryCommandBuffer *primaryCommandBuffer)
{ {
// Record the deferred pipeline barrier if necessary.
ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
if (mGlobalMemoryBarrierSrcAccess)
{
VkMemoryBarrier memoryBarrier = {};
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
primaryCommandBuffer->memoryBarrier(mGlobalMemoryBarrierStages, mGlobalMemoryBarrierStages,
&memoryBarrier);
}
switch (mFunction) switch (mFunction)
{ {
case CommandGraphNodeFunction::Generic: case CommandGraphNodeFunction::Generic:
ASSERT(mQueryPool == VK_NULL_HANDLE && mFenceSyncEvent == VK_NULL_HANDLE); ASSERT(mQueryPool == VK_NULL_HANDLE && mFenceSyncEvent == VK_NULL_HANDLE);
// Record the deferred pipeline barrier if necessary.
ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
if (mGlobalMemoryBarrierSrcAccess)
{
VkMemoryBarrier memoryBarrier = {};
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
// Use the all pipe stage to keep the state management simple.
primaryCommandBuffer->memoryBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
&memoryBarrier);
}
if (mOutsideRenderPassCommands.valid()) if (mOutsideRenderPassCommands.valid())
{ {
ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end()); ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end());
...@@ -639,6 +640,11 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context, ...@@ -639,6 +640,11 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
break; break;
case CommandGraphNodeFunction::GraphBarrier:
// Nothing to do. The memory barrier, if any, is already handled above through global
// memory barrier flags.
break;
case CommandGraphNodeFunction::InsertDebugMarker: case CommandGraphNodeFunction::InsertDebugMarker:
ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid()); ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
...@@ -707,6 +713,13 @@ void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType, ...@@ -707,6 +713,13 @@ void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
mResourceID = resourceID; mResourceID = resourceID;
} }
bool CommandGraphNode::hasDiagnosticID() const
{
// All nodes have diagnostic IDs to differentiate them except the following select few.
return mResourceType != CommandGraphResourceType::HostAvailabilityOperation &&
mResourceType != CommandGraphResourceType::GraphBarrier;
}
std::string CommandGraphNode::dumpCommandsForDiagnostics(const char *separator) const std::string CommandGraphNode::dumpCommandsForDiagnostics(const char *separator) const
{ {
std::string result; std::string result;
...@@ -989,6 +1002,13 @@ void CommandGraph::waitFenceSync(const vk::Event &event) ...@@ -989,6 +1002,13 @@ void CommandGraph::waitFenceSync(const vk::Event &event)
newNode->setFenceSync(event); newNode->setFenceSync(event);
} }
void CommandGraph::memoryBarrier(VkFlags srcAccess, VkFlags dstAccess, VkPipelineStageFlags stages)
{
CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::GraphBarrier,
CommandGraphResourceType::GraphBarrier, 0);
newNode->addGlobalMemoryBarrier(srcAccess, dstAccess, stages);
}
void CommandGraph::insertDebugMarker(GLenum source, std::string &&marker) void CommandGraph::insertDebugMarker(GLenum source, std::string &&marker)
{ {
CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::InsertDebugMarker, CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::InsertDebugMarker,
...@@ -1078,10 +1098,9 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const ...@@ -1078,10 +1098,9 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
strstr << id; strstr << id;
} }
} }
else if (node->getResourceTypeForDiagnostics() == else if (!node->hasDiagnosticID())
CommandGraphResourceType::HostAvailabilityOperation)
{ {
// Nothing to append for this special node. The name is sufficient. // Nothing to append for these special nodes. The name is sufficient.
} }
else else
{ {
......
...@@ -37,6 +37,7 @@ enum class CommandGraphResourceType ...@@ -37,6 +37,7 @@ enum class CommandGraphResourceType
// VK_EXT_transform_feedback), but still need to generate a command graph barrier node. // VK_EXT_transform_feedback), but still need to generate a command graph barrier node.
EmulatedQuery, EmulatedQuery,
FenceSync, FenceSync,
GraphBarrier,
DebugMarker, DebugMarker,
HostAvailabilityOperation, HostAvailabilityOperation,
}; };
...@@ -53,6 +54,7 @@ enum class CommandGraphNodeFunction ...@@ -53,6 +54,7 @@ enum class CommandGraphNodeFunction
EndTransformFeedbackQuery, EndTransformFeedbackQuery,
SetFenceSync, SetFenceSync,
WaitFenceSync, WaitFenceSync,
GraphBarrier,
InsertDebugMarker, InsertDebugMarker,
PushDebugMarker, PushDebugMarker,
PopDebugMarker, PopDebugMarker,
...@@ -178,6 +180,7 @@ class CommandGraphNode final : angle::NonCopyable ...@@ -178,6 +180,7 @@ class CommandGraphNode final : angle::NonCopyable
CommandGraphResourceType getResourceTypeForDiagnostics() const { return mResourceType; } CommandGraphResourceType getResourceTypeForDiagnostics() const { return mResourceType; }
uintptr_t getResourceIDForDiagnostics() const { return mResourceID; } uintptr_t getResourceIDForDiagnostics() const { return mResourceID; }
bool hasDiagnosticID() const;
std::string dumpCommandsForDiagnostics(const char *separator) const; std::string dumpCommandsForDiagnostics(const char *separator) const;
const gl::Rectangle &getRenderPassRenderArea() const { return mRenderPassRenderArea; } const gl::Rectangle &getRenderPassRenderArea() const { return mRenderPassRenderArea; }
...@@ -191,10 +194,13 @@ class CommandGraphNode final : angle::NonCopyable ...@@ -191,10 +194,13 @@ class CommandGraphNode final : angle::NonCopyable
void setDebugMarker(GLenum source, std::string &&marker); void setDebugMarker(GLenum source, std::string &&marker);
const std::string &getDebugMarker() const { return mDebugMarker; } const std::string &getDebugMarker() const { return mDebugMarker; }
ANGLE_INLINE void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess) ANGLE_INLINE void addGlobalMemoryBarrier(VkFlags srcAccess,
VkFlags dstAccess,
VkPipelineStageFlags stages)
{ {
mGlobalMemoryBarrierSrcAccess |= srcAccess; mGlobalMemoryBarrierSrcAccess |= srcAccess;
mGlobalMemoryBarrierDstAccess |= dstAccess; mGlobalMemoryBarrierDstAccess |= dstAccess;
mGlobalMemoryBarrierStages |= stages;
} }
// This can only be set for RenderPass nodes. Each RenderPass node can have at most one owner. // This can only be set for RenderPass nodes. Each RenderPass node can have at most one owner.
...@@ -257,6 +263,7 @@ class CommandGraphNode final : angle::NonCopyable ...@@ -257,6 +263,7 @@ class CommandGraphNode final : angle::NonCopyable
// For global memory barriers. // For global memory barriers.
VkFlags mGlobalMemoryBarrierSrcAccess; VkFlags mGlobalMemoryBarrierSrcAccess;
VkFlags mGlobalMemoryBarrierDstAccess; VkFlags mGlobalMemoryBarrierDstAccess;
VkPipelineStageFlags mGlobalMemoryBarrierStages;
// Render pass command buffer notifications. // Render pass command buffer notifications.
RenderPassOwner *mRenderPassOwner; RenderPassOwner *mRenderPassOwner;
...@@ -401,10 +408,10 @@ class CommandGraphResource : angle::NonCopyable ...@@ -401,10 +408,10 @@ class CommandGraphResource : angle::NonCopyable
void finishCurrentCommands(ContextVk *contextVk); void finishCurrentCommands(ContextVk *contextVk);
// Store a deferred memory barrier. Will be recorded into a primary command buffer at submit. // Store a deferred memory barrier. Will be recorded into a primary command buffer at submit.
void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess) void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess, VkPipelineStageFlags stages)
{ {
ASSERT(mCurrentWritingNode); ASSERT(mCurrentWritingNode);
mCurrentWritingNode->addGlobalMemoryBarrier(srcAccess, dstAccess); mCurrentWritingNode->addGlobalMemoryBarrier(srcAccess, dstAccess, stages);
} }
protected: protected:
...@@ -490,6 +497,8 @@ class CommandGraph final : angle::NonCopyable ...@@ -490,6 +497,8 @@ class CommandGraph final : angle::NonCopyable
// GLsync and EGLSync: // GLsync and EGLSync:
void setFenceSync(const vk::Event &event); void setFenceSync(const vk::Event &event);
void waitFenceSync(const vk::Event &event); void waitFenceSync(const vk::Event &event);
// Memory barriers:
void memoryBarrier(VkFlags srcAccess, VkFlags dstAccess, VkPipelineStageFlags stages);
// Debug markers: // Debug markers:
void insertDebugMarker(GLenum source, std::string &&marker); void insertDebugMarker(GLenum source, std::string &&marker);
void pushDebugMarker(GLenum source, std::string &&marker); void pushDebugMarker(GLenum source, std::string &&marker);
......
...@@ -2010,14 +2010,36 @@ angle::Result ContextVk::dispatchComputeIndirect(const gl::Context *context, GLi ...@@ -2010,14 +2010,36 @@ angle::Result ContextVk::dispatchComputeIndirect(const gl::Context *context, GLi
angle::Result ContextVk::memoryBarrier(const gl::Context *context, GLbitfield barriers) angle::Result ContextVk::memoryBarrier(const gl::Context *context, GLbitfield barriers)
{ {
ANGLE_VK_UNREACHABLE(this); // Note: most of the barriers specified here don't require us to issue a memory barrier, as the
return angle::Result::Stop; // relevant resources already insert the appropriate barriers. They do however require the
// resource writing nodes to finish so future buffer barriers are placed correctly, as well as
// resource dependencies not creating a graph loop. This is done by inserting a command graph
// barrier that does nothing!
VkAccessFlags srcAccess = 0;
VkAccessFlags dstAccess = 0;
if ((barriers & GL_COMMAND_BARRIER_BIT) != 0)
{
srcAccess |= VK_ACCESS_SHADER_WRITE_BIT;
dstAccess |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
}
mCommandGraph.memoryBarrier(srcAccess, dstAccess, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
return angle::Result::Continue;
} }
angle::Result ContextVk::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) angle::Result ContextVk::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
{ {
ANGLE_VK_UNREACHABLE(this); // There aren't any barrier bits here that aren't otherwise automatically handled. We only
return angle::Result::Stop; // need to make sure writer resources (framebuffers and the dispatcher) start a new node.
//
// Note: memoryBarrierByRegion is expected to affect only the fragment pipeline. Specifying
// that here is currently unnecessary, but is a reminder of this fact in case we do need to
// especially handle some future barrier bit.
mCommandGraph.memoryBarrier(0, 0, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
return angle::Result::Continue;
} }
vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType) vk::DynamicQueryPool *ContextVk::getQueryPool(gl::QueryType queryType)
......
...@@ -1322,7 +1322,7 @@ void BufferHelper::onWriteAccess(ContextVk *contextVk, ...@@ -1322,7 +1322,7 @@ void BufferHelper::onWriteAccess(ContextVk *contextVk,
VkAccessFlags barrierSrc, barrierDst; VkAccessFlags barrierSrc, barrierDst;
if (needsOnWriteBarrier(readAccessType, writeAccessType, &barrierSrc, &barrierDst)) if (needsOnWriteBarrier(readAccessType, writeAccessType, &barrierSrc, &barrierDst))
{ {
addGlobalMemoryBarrier(barrierSrc, barrierDst); addGlobalMemoryBarrier(barrierSrc, barrierDst, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
} }
bool hostVisible = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; bool hostVisible = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
......
...@@ -555,7 +555,8 @@ class BufferHelper final : public CommandGraphResource ...@@ -555,7 +555,8 @@ class BufferHelper final : public CommandGraphResource
VkAccessFlags barrierSrc, barrierDst; VkAccessFlags barrierSrc, barrierDst;
if (needsOnReadBarrier(readAccessType, &barrierSrc, &barrierDst)) if (needsOnReadBarrier(readAccessType, &barrierSrc, &barrierDst))
{ {
reader->addGlobalMemoryBarrier(barrierSrc, barrierDst); reader->addGlobalMemoryBarrier(barrierSrc, barrierDst,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
} }
} }
bool needsOnWriteBarrier(VkAccessFlags readAccessType, bool needsOnWriteBarrier(VkAccessFlags readAccessType,
......
...@@ -632,10 +632,6 @@ ...@@ -632,10 +632,6 @@
3520 VULKAN : dEQP-GLES31.functional.program_interface_query.program_*.resource_list.compute.empty = FAIL 3520 VULKAN : dEQP-GLES31.functional.program_interface_query.program_*.resource_list.compute.empty = FAIL
3520 VULKAN : dEQP-GLES31.functional.program_interface_query.shader_storage_block.buffer_data_size.* = FAIL 3520 VULKAN : dEQP-GLES31.functional.program_interface_query.shader_storage_block.buffer_data_size.* = FAIL
// glMemoryBarrier support:
3574 VULKAN : dEQP-GLES31.functional.compute.*barrier* = SKIP
3574 VULKAN : dEQP-GLES31.functional.synchronization.*memory_barrier* = SKIP
// Indirect dispatch: // Indirect dispatch:
3601 VULKAN : dEQP-GLES31.functional.compute.*indirect* = SKIP 3601 VULKAN : dEQP-GLES31.functional.compute.*indirect* = SKIP
......
...@@ -36,12 +36,11 @@ ...@@ -36,12 +36,11 @@
// General Vulkan expectations // General Vulkan expectations
// Limits: // Limits:
// GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set. Also crashes on memory barrier support missing. // GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set.
3605 VULKAN : KHR-GLES31.core.texture_gather.* = SKIP 3605 VULKAN : KHR-GLES31.core.texture_gather.* = FAIL
// Memory barriers // Dispatch indirect:
3574 VULKAN : KHR-GLES31.core.compute_shader* = SKIP 3601 VULKAN : KHR-GLES31.core.compute_shader* = SKIP
3574 VULKAN : KHR-GLES31.core.shader_atomic_counters.basic-glsl-built-in = SKIP
// Multisampled textures: // Multisampled textures:
3565 VULKAN : KHR-GLES31.core.texture_storage_multisample.* = SKIP 3565 VULKAN : KHR-GLES31.core.texture_storage_multisample.* = SKIP
......
...@@ -315,7 +315,7 @@ TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWrite) ...@@ -315,7 +315,7 @@ TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWrite)
// Tests modifying an existing shader storage buffer // Tests modifying an existing shader storage buffer
TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWriteSame) TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWriteSame)
{ {
// Vulkan doesn't support memory barriers yet. http://anglebug.com/3574 // Missing PBO support in Vulkan. http://anglebug.com/3210
ANGLE_SKIP_TEST_IF(IsVulkan()); ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kComputeShaderSource[] = constexpr char kComputeShaderSource[] =
...@@ -413,9 +413,6 @@ void main() ...@@ -413,9 +413,6 @@ void main()
// Tests reading and writing to a shader storage buffer bound at an offset. // Tests reading and writing to a shader storage buffer bound at an offset.
TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWriteOffset) TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWriteOffset)
{ {
// Vulkan doesn't support memory barriers yet. http://anglebug.com/3574
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kCS[] = R"(#version 310 es constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
......
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