Commit 9cceac42 by Jamie Madill Committed by Commit Bot

Vulkan: Update resource dependency semantics.

This removes passing the Serial around to several methods, so that dependency management is a bit more automatic. This makes life a bit easier when dealing with state updates when resources are in use by Vulkan. The FramebuffeVk no longer stores an extra serial of the last draw, instead it will trigger creation of a new writing node on a state change update. Bug: angleproject:2318 Change-Id: Ie58ec66e6e8644ba4d402c509255c3795d363dd3 Reviewed-on: https://chromium-review.googlesource.com/985201 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org>
parent 6c7ab7fe
...@@ -190,7 +190,7 @@ vk::Error BufferVk::setDataImpl(ContextVk *contextVk, ...@@ -190,7 +190,7 @@ vk::Error BufferVk::setDataImpl(ContextVk *contextVk,
VkDevice device = contextVk->getDevice(); VkDevice device = contextVk->getDevice();
// Use map when available. // Use map when available.
if (renderer->isSerialInUse(getQueueSerial())) if (checkResourceInUseAndRefreshDeps(renderer))
{ {
vk::StagingBuffer stagingBuffer; vk::StagingBuffer stagingBuffer;
ANGLE_TRY(stagingBuffer.init(contextVk, static_cast<VkDeviceSize>(size), ANGLE_TRY(stagingBuffer.init(contextVk, static_cast<VkDeviceSize>(size),
......
...@@ -77,15 +77,13 @@ Serial CommandGraphResource::getQueueSerial() const ...@@ -77,15 +77,13 @@ Serial CommandGraphResource::getQueueSerial() const
return mStoredQueueSerial; return mStoredQueueSerial;
} }
bool CommandGraphResource::hasCurrentWritingNode(Serial currentSerial) const bool CommandGraphResource::hasChildlessWritingNode() const
{ {
return (mStoredQueueSerial == currentSerial && mCurrentWritingNode != nullptr && return (mCurrentWritingNode != nullptr && !mCurrentWritingNode->hasChildren());
!mCurrentWritingNode->hasChildren());
} }
CommandGraphNode *CommandGraphResource::getCurrentWritingNode(Serial currentSerial) CommandGraphNode *CommandGraphResource::getCurrentWritingNode()
{ {
ASSERT(currentSerial == mStoredQueueSerial);
return mCurrentWritingNode; return mCurrentWritingNode;
} }
...@@ -111,7 +109,7 @@ void CommandGraphResource::onWriteResource(CommandGraphNode *writingNode, Serial ...@@ -111,7 +109,7 @@ void CommandGraphResource::onWriteResource(CommandGraphNode *writingNode, Serial
{ {
updateQueueSerial(serial); updateQueueSerial(serial);
// Make sure any open reads and writes finish before we execute 'newCommands'. // Make sure any open reads and writes finish before we execute 'writingNode'.
if (!mCurrentReadingNodes.empty()) if (!mCurrentReadingNodes.empty())
{ {
CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes, writingNode); CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes, writingNode);
...@@ -128,19 +126,32 @@ void CommandGraphResource::onWriteResource(CommandGraphNode *writingNode, Serial ...@@ -128,19 +126,32 @@ void CommandGraphResource::onWriteResource(CommandGraphNode *writingNode, Serial
void CommandGraphResource::onReadResource(CommandGraphNode *readingNode, Serial serial) void CommandGraphResource::onReadResource(CommandGraphNode *readingNode, Serial serial)
{ {
if (hasCurrentWritingNode(serial)) updateQueueSerial(serial);
if (hasChildlessWritingNode())
{ {
// Ensure 'readOperation' happens after the current write commands.
CommandGraphNode::SetHappensBeforeDependency(getCurrentWritingNode(serial), readingNode);
ASSERT(mStoredQueueSerial == serial); ASSERT(mStoredQueueSerial == serial);
// Ensure 'readingNode' happens after the current writing node.
CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
}
// Add the read node to the list of nodes currently reading this resource.
mCurrentReadingNodes.push_back(readingNode);
}
bool CommandGraphResource::checkResourceInUseAndRefreshDeps(RendererVk *renderer)
{
if (!renderer->isResourceInUse(*this))
{
mCurrentReadingNodes.clear();
mCurrentWritingNode = nullptr;
return false;
} }
else else
{ {
updateQueueSerial(serial); return true;
} }
// Add the read operation to the list of nodes currently reading this resource.
mCurrentReadingNodes.push_back(readingNode);
} }
// CommandGraphNode implementation. // CommandGraphNode implementation.
...@@ -247,9 +258,9 @@ void CommandGraphNode::appendDepthStencilRenderTarget(Serial serial, ...@@ -247,9 +258,9 @@ void CommandGraphNode::appendDepthStencilRenderTarget(Serial serial,
void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode, void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
CommandGraphNode *afterNode) CommandGraphNode *afterNode)
{ {
ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
afterNode->mParents.emplace_back(beforeNode); afterNode->mParents.emplace_back(beforeNode);
beforeNode->setHasChildren(); beforeNode->setHasChildren();
ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
} }
// static // static
......
...@@ -33,11 +33,11 @@ class CommandGraphResource ...@@ -33,11 +33,11 @@ class CommandGraphResource
void updateQueueSerial(Serial queueSerial); void updateQueueSerial(Serial queueSerial);
Serial getQueueSerial() const; Serial getQueueSerial() const;
// Returns true if any tracked read or write nodes match 'currentSerial'. // Returns true if this node has a current writing node with no children.
bool hasCurrentWritingNode(Serial currentSerial) const; bool hasChildlessWritingNode() const;
// Returns the active write node, and asserts 'currentSerial' matches the stored serial. // Returns the active write node.
CommandGraphNode *getCurrentWritingNode(Serial currentSerial); CommandGraphNode *getCurrentWritingNode();
// Allocates a new write node and calls onWriteResource internally. // Allocates a new write node and calls onWriteResource internally.
CommandGraphNode *getNewWritingNode(RendererVk *renderer); CommandGraphNode *getNewWritingNode(RendererVk *renderer);
...@@ -52,6 +52,9 @@ class CommandGraphResource ...@@ -52,6 +52,9 @@ class CommandGraphResource
// Sets up dependency relations. 'readingNode' will read from 'this' ResourceVk. // Sets up dependency relations. 'readingNode' will read from 'this' ResourceVk.
void onReadResource(CommandGraphNode *readingNode, Serial serial); void onReadResource(CommandGraphNode *readingNode, Serial serial);
// Returns false if the resource is not in use, and clears any current read/write nodes.
bool checkResourceInUseAndRefreshDeps(RendererVk *renderer);
private: private:
Serial mStoredQueueSerial; Serial mStoredQueueSerial;
std::vector<CommandGraphNode *> mCurrentReadingNodes; std::vector<CommandGraphNode *> mCurrentReadingNodes;
......
...@@ -54,20 +54,12 @@ FramebufferVk *FramebufferVk::CreateDefaultFBO(const gl::FramebufferState &state ...@@ -54,20 +54,12 @@ FramebufferVk *FramebufferVk::CreateDefaultFBO(const gl::FramebufferState &state
} }
FramebufferVk::FramebufferVk(const gl::FramebufferState &state) FramebufferVk::FramebufferVk(const gl::FramebufferState &state)
: FramebufferImpl(state), : FramebufferImpl(state), mBackbuffer(nullptr), mRenderPassDesc(), mFramebuffer()
mBackbuffer(nullptr),
mRenderPassDesc(),
mFramebuffer(),
mLastRenderNodeSerial()
{ {
} }
FramebufferVk::FramebufferVk(const gl::FramebufferState &state, WindowSurfaceVk *backbuffer) FramebufferVk::FramebufferVk(const gl::FramebufferState &state, WindowSurfaceVk *backbuffer)
: FramebufferImpl(state), : FramebufferImpl(state), mBackbuffer(backbuffer), mRenderPassDesc(), mFramebuffer()
mBackbuffer(backbuffer),
mRenderPassDesc(),
mFramebuffer(),
mLastRenderNodeSerial()
{ {
} }
...@@ -154,7 +146,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -154,7 +146,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
if (clearDepth || clearStencil) if (clearDepth || clearStencil)
{ {
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer)); ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
writingNode = getCurrentWritingNode(currentSerial); writingNode = getCurrentWritingNode();
const VkClearDepthStencilValue &clearDepthStencilValue = const VkClearDepthStencilValue &clearDepthStencilValue =
contextVk->getClearDepthStencilValue().depthStencil; contextVk->getClearDepthStencilValue().depthStencil;
...@@ -183,7 +175,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ...@@ -183,7 +175,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
if (!commandBuffer) if (!commandBuffer)
{ {
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer)); ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
writingNode = getCurrentWritingNode(currentSerial); writingNode = getCurrentWritingNode();
} }
// TODO(jmadill): Support gaps in RenderTargets. http://anglebug.com/2394 // TODO(jmadill): Support gaps in RenderTargets. http://anglebug.com/2394
...@@ -340,8 +332,8 @@ gl::Error FramebufferVk::syncState(const gl::Context *context, ...@@ -340,8 +332,8 @@ gl::Error FramebufferVk::syncState(const gl::Context *context,
mRenderPassDesc.reset(); mRenderPassDesc.reset();
renderer->releaseResource(*this, &mFramebuffer); renderer->releaseResource(*this, &mFramebuffer);
// Trigger a new set of secondary commands next time we render to this FBO,. // Trigger a new set of secondary commands next time we render to this FBO.
mLastRenderNodeSerial = Serial(); getNewWritingNode(renderer);
contextVk->invalidateCurrentPipeline(); contextVk->invalidateCurrentPipeline();
...@@ -538,14 +530,22 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context, ...@@ -538,14 +530,22 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context,
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
Serial currentSerial = renderer->getCurrentQueueSerial(); Serial currentSerial = renderer->getCurrentQueueSerial();
if (hasCurrentWritingNode(currentSerial) && mLastRenderNodeSerial == currentSerial) // This will reset the current writing node if it has been completed.
updateQueueSerial(currentSerial);
if (hasChildlessWritingNode())
{ {
*nodeOut = getCurrentWritingNode(currentSerial); *nodeOut = getCurrentWritingNode();
ASSERT((*nodeOut)->getInsideRenderPassCommands()->valid()); }
return gl::NoError(); else
{
*nodeOut = getNewWritingNode(renderer);
} }
vk::CommandGraphNode *node = getNewWritingNode(renderer); if ((*nodeOut)->getInsideRenderPassCommands()->valid())
{
return gl::NoError();
}
vk::Framebuffer *framebuffer = nullptr; vk::Framebuffer *framebuffer = nullptr;
ANGLE_TRY_RESULT(getFramebuffer(context, renderer), framebuffer); ANGLE_TRY_RESULT(getFramebuffer(context, renderer), framebuffer);
...@@ -553,8 +553,15 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context, ...@@ -553,8 +553,15 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context,
std::vector<VkClearValue> attachmentClearValues; std::vector<VkClearValue> attachmentClearValues;
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(node->beginOutsideRenderPassRecording(renderer->getDevice(), if (!(*nodeOut)->getOutsideRenderPassCommands()->valid())
renderer->getCommandPool(), &commandBuffer)); {
ANGLE_TRY((*nodeOut)->beginOutsideRenderPassRecording(
renderer->getDevice(), renderer->getCommandPool(), &commandBuffer));
}
else
{
commandBuffer = (*nodeOut)->getOutsideRenderPassCommands();
}
// Initialize RenderPass info. // Initialize RenderPass info.
// TODO(jmadill): Support gaps in RenderTargets. http://anglebug.com/2394 // TODO(jmadill): Support gaps in RenderTargets. http://anglebug.com/2394
...@@ -569,7 +576,7 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context, ...@@ -569,7 +576,7 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context,
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
commandBuffer); commandBuffer);
node->appendColorRenderTarget(currentSerial, colorRenderTarget); (*nodeOut)->appendColorRenderTarget(currentSerial, colorRenderTarget);
attachmentClearValues.emplace_back(contextVk->getClearColorValue()); attachmentClearValues.emplace_back(contextVk->getClearColorValue());
} }
...@@ -585,17 +592,15 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context, ...@@ -585,17 +592,15 @@ gl::Error FramebufferVk::getCommandGraphNodeForDraw(const gl::Context *context,
aspectFlags, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, aspectFlags, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
commandBuffer); commandBuffer);
node->appendDepthStencilRenderTarget(currentSerial, depthStencilRenderTarget); (*nodeOut)->appendDepthStencilRenderTarget(currentSerial, depthStencilRenderTarget);
attachmentClearValues.emplace_back(contextVk->getClearDepthStencilValue()); attachmentClearValues.emplace_back(contextVk->getClearDepthStencilValue());
} }
// Hard-code RenderPass to clear the first render target to the current clear value. // Hard-code RenderPass to clear the first render target to the current clear value.
// TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
const gl::State &glState = context->getGLState(); const gl::State &glState = context->getGLState();
node->storeRenderPassInfo(*framebuffer, glState.getViewport(), attachmentClearValues); (*nodeOut)->storeRenderPassInfo(*framebuffer, glState.getViewport(), attachmentClearValues);
mLastRenderNodeSerial = currentSerial;
*nodeOut = node;
return gl::NoError(); return gl::NoError();
} }
......
...@@ -106,7 +106,6 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource ...@@ -106,7 +106,6 @@ class FramebufferVk : public FramebufferImpl, public vk::CommandGraphResource
Optional<vk::RenderPassDesc> mRenderPassDesc; Optional<vk::RenderPassDesc> mRenderPassDesc;
vk::Framebuffer mFramebuffer; vk::Framebuffer mFramebuffer;
Serial mLastRenderNodeSerial;
RenderTargetCache<RenderTargetVk> mRenderTargetCache; RenderTargetCache<RenderTargetVk> mRenderTargetCache;
}; };
......
...@@ -255,7 +255,7 @@ const gl::AttribArray<VkDeviceSize> &VertexArrayVk::getCurrentArrayBufferOffsets ...@@ -255,7 +255,7 @@ const gl::AttribArray<VkDeviceSize> &VertexArrayVk::getCurrentArrayBufferOffsets
return mCurrentArrayBufferOffsets; return mCurrentArrayBufferOffsets;
} }
void VertexArrayVk::updateArrayBufferReadDependencies(vk::CommandGraphNode *drawNode, void VertexArrayVk::updateArrayBufferReadDependencies(vk::CommandGraphNode *readingNode,
const gl::AttributesMask &activeAttribsMask, const gl::AttributesMask &activeAttribsMask,
Serial serial) Serial serial)
{ {
...@@ -263,17 +263,17 @@ void VertexArrayVk::updateArrayBufferReadDependencies(vk::CommandGraphNode *draw ...@@ -263,17 +263,17 @@ void VertexArrayVk::updateArrayBufferReadDependencies(vk::CommandGraphNode *draw
for (size_t attribIndex : activeAttribsMask) for (size_t attribIndex : activeAttribsMask)
{ {
if (mCurrentArrayBufferResources[attribIndex]) if (mCurrentArrayBufferResources[attribIndex])
mCurrentArrayBufferResources[attribIndex]->onReadResource(drawNode, serial); mCurrentArrayBufferResources[attribIndex]->onReadResource(readingNode, serial);
} }
} }
void VertexArrayVk::updateElementArrayBufferReadDependency(vk::CommandGraphNode *drawNode, void VertexArrayVk::updateElementArrayBufferReadDependency(vk::CommandGraphNode *readingNode,
Serial serial) Serial serial)
{ {
// Handle the bound element array buffer. // Handle the bound element array buffer.
if (mCurrentElementArrayBufferResource) if (mCurrentElementArrayBufferResource)
{ {
mCurrentElementArrayBufferResource->onReadResource(drawNode, serial); mCurrentElementArrayBufferResource->onReadResource(readingNode, serial);
} }
} }
......
...@@ -45,7 +45,7 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -45,7 +45,7 @@ class VertexArrayVk : public VertexArrayImpl
const gl::AttribArray<VkBuffer> &getCurrentArrayBufferHandles() const; const gl::AttribArray<VkBuffer> &getCurrentArrayBufferHandles() const;
const gl::AttribArray<VkDeviceSize> &getCurrentArrayBufferOffsets() const; const gl::AttribArray<VkDeviceSize> &getCurrentArrayBufferOffsets() const;
void updateDrawDependencies(vk::CommandGraphNode *readNode, void updateDrawDependencies(vk::CommandGraphNode *readingNode,
const gl::AttributesMask &activeAttribsMask, const gl::AttributesMask &activeAttribsMask,
vk::CommandGraphResource *elementArrayBufferOverride, vk::CommandGraphResource *elementArrayBufferOverride,
Serial serial, Serial serial,
......
...@@ -365,7 +365,7 @@ gl::Error LineLoopHandler::createIndexBufferFromElementArrayBuffer(RendererVk *r ...@@ -365,7 +365,7 @@ gl::Error LineLoopHandler::createIndexBufferFromElementArrayBuffer(RendererVk *r
beginWriteResource(renderer, &commandBuffer); beginWriteResource(renderer, &commandBuffer);
Serial currentSerial = renderer->getCurrentQueueSerial(); Serial currentSerial = renderer->getCurrentQueueSerial();
elementArrayBufferVk->onReadResource(getCurrentWritingNode(currentSerial), currentSerial); elementArrayBufferVk->onReadResource(getCurrentWritingNode(), currentSerial);
commandBuffer->copyBuffer(elementArrayBufferVk->getVkBuffer().getHandle(), *bufferHandleOut, 2, commandBuffer->copyBuffer(elementArrayBufferVk->getVkBuffer().getHandle(), *bufferHandleOut, 2,
copies.data()); copies.data());
......
...@@ -523,7 +523,9 @@ TEST_P(SimpleOperationTest, DrawIndexedQuadAndSwap) ...@@ -523,7 +523,9 @@ TEST_P(SimpleOperationTest, DrawIndexedQuadAndSwap)
{ {
ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader); ANGLE_GL_PROGRAM(program, kBasicVertexShader, kGreenFragmentShader);
for (int i = 0; i < 8; ++i) // 32 iterations is an arbitrary number. The more iterations, the more flaky syncronization
// issues will reproduce consistently.
for (int i = 0; i < 32; ++i)
{ {
drawIndexedQuad(program.get(), "position", 0.5f, 1.0f, true); drawIndexedQuad(program.get(), "position", 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
......
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