Commit 1f46bc12 by Jamie Madill Committed by Commit Bot

Vulkan: Add CommandGraph class.

This also renames CommandBufferNode to CommandGraphNode. It also renames some of the intenal members to more closely represent the tree relationships (parents/children). This should clean up the command graph classes and make them a bit easier to understand. Bug: angleproject:2361 Change-Id: I024bffcc7f4157c78072ef902a3c40a07a08b18a Reviewed-on: https://chromium-review.googlesource.com/922121Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent e703c606
......@@ -198,10 +198,10 @@ vk::Error BufferVk::setDataImpl(ContextVk *contextVk,
stagingBuffer.getDeviceMemory().unmap(device);
// Enqueue a copy command on the GPU.
// 'beginWriteOperation' will stop any subsequent rendering from using the old buffer data,
// 'beginWriteResource' will stop any subsequent rendering from using the old buffer data,
// by marking any current read operations / command buffers as 'finished'.
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteOperation(renderer, &commandBuffer));
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
// Insert a barrier to ensure reads from the buffer are complete.
// TODO(jmadill): Insert minimal barriers.
......
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// CommandBufferNode:
// Deferred work constructed by GL calls, that will later be flushed to Vulkan.
//
#ifndef LIBANGLE_RENDERER_VULKAN_COMMAND_BUFFER_NODE_H_
#define LIBANGLE_RENDERER_VULKAN_COMMAND_BUFFER_NODE_H_
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
namespace rx
{
namespace vk
{
enum class VisitedState
{
Unvisited,
Ready,
Visited,
};
class CommandBufferNode final : angle::NonCopyable
{
public:
CommandBufferNode();
~CommandBufferNode();
// Immutable queries for when we're walking the commands tree.
CommandBuffer *getOutsideRenderPassCommands();
CommandBuffer *getInsideRenderPassCommands();
// For outside the render pass (copies, transitions, etc).
Error startRecording(VkDevice device,
const CommandPool &commandPool,
CommandBuffer **commandsOut);
// For rendering commands (draws).
Error startRenderPassRecording(RendererVk *renderer, CommandBuffer **commandsOut);
bool isFinishedRecording() const;
void finishRecording();
// Commands for storing info relevant to the RenderPass.
// RenderTargets must be added in order, with the depth/stencil being added last.
void storeRenderPassInfo(const Framebuffer &framebuffer,
const gl::Rectangle renderArea,
const std::vector<VkClearValue> &clearValues);
void appendColorRenderTarget(Serial serial, RenderTargetVk *colorRenderTarget);
void appendDepthStencilRenderTarget(Serial serial, RenderTargetVk *depthStencilRenderTarget);
// Commands for linking nodes in the dependency graph.
static void SetHappensBeforeDependency(CommandBufferNode *beforeNode,
CommandBufferNode *afterNode);
static void SetHappensBeforeDependencies(const std::vector<CommandBufferNode *> &beforeNodes,
CommandBufferNode *afterNode);
bool hasHappensBeforeDependencies() const;
bool hasHappensAfterDependencies() const;
// Used for testing only.
bool happensAfter(CommandBufferNode *beforeNode);
// Commands for traversing the node on a flush operation.
VisitedState visitedState() const;
void visitDependencies(std::vector<CommandBufferNode *> *stack);
Error visitAndExecute(RendererVk *renderer, CommandBuffer *primaryCommandBuffer);
private:
void initAttachmentDesc(VkAttachmentDescription *desc);
void setHasHappensAfterDependencies();
// Only used if we need a RenderPass for these commands.
RenderPassDesc mRenderPassDesc;
Framebuffer mRenderPassFramebuffer;
gl::Rectangle mRenderPassRenderArea;
gl::AttachmentArray<VkClearValue> mRenderPassClearValues;
// Keep a separate buffers for commands inside and outside a RenderPass.
// TODO(jmadill): We might not need inside and outside RenderPass commands separate.
CommandBuffer mOutsideRenderPassCommands;
CommandBuffer mInsideRenderPassCommands;
// These commands must be submitted before 'this' command can be submitted correctly.
std::vector<CommandBufferNode *> mHappensBeforeDependencies;
// If this is true, other commands exist that must be submitted after 'this' command.
bool mHasHappensAfterDependencies;
// Used when traversing the dependency graph.
VisitedState mVisitedState;
// Is recording currently enabled?
bool mIsFinishedRecording;
};
} // namespace vk
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_COMMAND_BUFFER_NODE_H_
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// CommandGraph:
// Deferred work constructed by GL calls, that will later be flushed to Vulkan.
//
#ifndef LIBANGLE_RENDERER_VULKAN_COMMAND_GRAPH_H_
#define LIBANGLE_RENDERER_VULKAN_COMMAND_GRAPH_H_
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
namespace rx
{
namespace vk
{
enum class VisitedState
{
Unvisited,
Ready,
Visited,
};
// Translating OpenGL commands into Vulkan and submitting them immediately loses out on some
// of the powerful flexiblity Vulkan offers in RenderPasses. Load/Store ops can automatically
// clear RenderPass attachments, or preserve the contents. RenderPass automatic layout transitions
// can improve certain performance cases. Also, we can remove redundant RenderPass Begin and Ends
// when processing interleaved draw operations on independent Framebuffers.
//
// ANGLE's CommandGraph (and CommandGraphNode) attempt to solve these problems using deferred
// command submission. We also sometimes call this command re-ordering. A brief summary:
//
// During GL command processing, we record Vulkan commands into secondary command buffers, which
// are stored in CommandGraphNodes, and these nodes are chained together via dependencies to
// for a directed acyclic CommandGraph. When we need to submit the CommandGraph, say during a
// SwapBuffers or ReadPixels call, we begin a primary Vulkan CommandBuffer, and walk the
// CommandGraph, starting at the most senior nodes, recording secondary CommandBuffers inside
// and outside vk::RenderPasses as necessary, filled with the right load/store operations. Once
// the primary CommandBuffer has recorded all of the secondary CommandBuffers from all the open
// CommandGraphNodes, we submit the primary CommandBuffer to the VkQueue on the device.
class CommandGraphNode final : angle::NonCopyable
{
public:
CommandGraphNode();
~CommandGraphNode();
// Immutable queries for when we're walking the commands tree.
CommandBuffer *getOutsideRenderPassCommands();
CommandBuffer *getInsideRenderPassCommands();
// For outside the render pass (copies, transitions, etc).
Error beginOutsideRenderPassRecording(VkDevice device,
const CommandPool &commandPool,
CommandBuffer **commandsOut);
// For rendering commands (draws).
Error beginInsideRenderPassRecording(RendererVk *renderer, CommandBuffer **commandsOut);
// storeRenderPassInfo and append*RenderTarget store info relevant to the RenderPass.
void storeRenderPassInfo(const Framebuffer &framebuffer,
const gl::Rectangle renderArea,
const std::vector<VkClearValue> &clearValues);
// storeRenderPassInfo and append*RenderTarget store info relevant to the RenderPass.
// Note: RenderTargets must be added in order, with the depth/stencil being added last.
void appendColorRenderTarget(Serial serial, RenderTargetVk *colorRenderTarget);
void appendDepthStencilRenderTarget(Serial serial, RenderTargetVk *depthStencilRenderTarget);
// Dependency commands order node execution in the command graph.
// Once a node has commands that must happen after it, recording is stopped and the node is
// frozen forever.
static void SetHappensBeforeDependency(CommandGraphNode *beforeNode,
CommandGraphNode *afterNode);
static void SetHappensBeforeDependencies(const std::vector<CommandGraphNode *> &beforeNodes,
CommandGraphNode *afterNode);
bool hasParents() const;
bool hasChildren() const;
// Commands for traversing the node on a flush operation.
VisitedState visitedState() const;
void visitParents(std::vector<CommandGraphNode *> *stack);
Error visitAndExecute(VkDevice device,
Serial serial,
RenderPassCache *renderPassCache,
CommandBuffer *primaryCommandBuffer);
private:
void setHasChildren();
// Used for testing only.
bool isChildOf(CommandGraphNode *parent);
// Only used if we need a RenderPass for these commands.
RenderPassDesc mRenderPassDesc;
Framebuffer mRenderPassFramebuffer;
gl::Rectangle mRenderPassRenderArea;
gl::AttachmentArray<VkClearValue> mRenderPassClearValues;
// Keep a separate buffers for commands inside and outside a RenderPass.
// TODO(jmadill): We might not need inside and outside RenderPass commands separate.
CommandBuffer mOutsideRenderPassCommands;
CommandBuffer mInsideRenderPassCommands;
// Parents are commands that must be submitted before 'this' CommandNode can be submitted.
std::vector<CommandGraphNode *> mParents;
// If this is true, other commands exist that must be submitted after 'this' command.
bool mHasChildren;
// Used when traversing the dependency graph.
VisitedState mVisitedState;
};
// The Command Graph consists of an array of open Command Graph Nodes. It supports allocating new
// nodes for the graph, which are linked via dependency relation calls in CommandGraphNode, and
// also submitting the whole command graph via submitCommands.
class CommandGraph final : angle::NonCopyable
{
public:
CommandGraph();
~CommandGraph();
// Allocates a new CommandGraphNode and adds it to the list of current open nodes. No ordering
// relations exist in the node by default. Call CommandGraphNode::SetHappensBeforeDependency
// to set up dependency relations.
CommandGraphNode *allocateNode();
Error submitCommands(VkDevice device,
Serial serial,
RenderPassCache *renderPassCache,
CommandPool *commandPool,
CommandBuffer *primaryCommandBufferOut);
bool empty() const;
private:
std::vector<CommandGraphNode *> mNodes;
};
} // namespace vk
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_COMMAND_GRAPH_H_
......@@ -14,7 +14,7 @@
#include "libANGLE/Context.h"
#include "libANGLE/Program.h"
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "libANGLE/renderer/vulkan/CommandBufferNode.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/CompilerVk.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/DeviceVk.h"
......@@ -183,15 +183,14 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
Serial queueSerial = mRenderer->getCurrentQueueSerial();
uint32_t maxAttrib = programGL->getState().getMaxActiveAttribLocation();
// TODO(jmadill): Need to link up the TextureVk to the Secondary CB.
vk::CommandBufferNode *renderNode = nullptr;
vk::CommandGraphNode *renderNode = nullptr;
ANGLE_TRY(vkFBO->getRenderNode(context, &renderNode));
if (!renderNode->getInsideRenderPassCommands()->valid())
{
mVertexArrayDirty = true;
mTexturesDirty = true;
ANGLE_TRY(renderNode->startRenderPassRecording(mRenderer, commandBuffer));
ANGLE_TRY(renderNode->beginInsideRenderPassRecording(mRenderer, commandBuffer));
}
else
{
......
......@@ -18,7 +18,7 @@
#include "libANGLE/Display.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "libANGLE/renderer/vulkan/CommandBufferNode.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
......@@ -146,7 +146,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
RendererVk *renderer = contextVk->getRenderer();
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteOperation(renderer, &commandBuffer));
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
Serial currentSerial = renderer->getCurrentQueueSerial();
......@@ -157,7 +157,7 @@ gl::Error FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
RenderTargetVk *renderTarget = nullptr;
ANGLE_TRY(colorAttachment.getRenderTarget(context, &renderTarget));
renderTarget->resource->onWriteResource(getCurrentWriteOperation(currentSerial),
renderTarget->resource->onWriteResource(getCurrentWritingNode(currentSerial),
currentSerial);
renderTarget->image->changeLayoutWithStages(
......@@ -262,7 +262,7 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
renderTarget->extents, vk::StagingUsage::Read));
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteOperation(renderer, &commandBuffer));
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
stagingImage.getImage().changeLayoutTop(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL,
commandBuffer);
......@@ -467,20 +467,20 @@ gl::Error FramebufferVk::getSamplePosition(size_t index, GLfloat *xy) const
return gl::InternalError() << "getSamplePosition is unimplemented.";
}
gl::Error FramebufferVk::getRenderNode(const gl::Context *context, vk::CommandBufferNode **nodeOut)
gl::Error FramebufferVk::getRenderNode(const gl::Context *context, vk::CommandGraphNode **nodeOut)
{
ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer();
Serial currentSerial = renderer->getCurrentQueueSerial();
if (hasCurrentWriteOperation(currentSerial) && mLastRenderNodeSerial == currentSerial)
if (hasCurrentWritingNode(currentSerial) && mLastRenderNodeSerial == currentSerial)
{
*nodeOut = getCurrentWriteOperation(currentSerial);
*nodeOut = getCurrentWritingNode(currentSerial);
ASSERT((*nodeOut)->getInsideRenderPassCommands()->valid());
return gl::NoError();
}
vk::CommandBufferNode *node = getNewWriteNode(renderer);
vk::CommandGraphNode *node = getNewWritingNode(renderer);
vk::Framebuffer *framebuffer = nullptr;
ANGLE_TRY_RESULT(getFramebuffer(context, renderer), framebuffer);
......
......@@ -85,7 +85,7 @@ class FramebufferVk : public FramebufferImpl, public ResourceVk
gl::Error getSamplePosition(size_t index, GLfloat *xy) const override;
const vk::RenderPassDesc &getRenderPassDesc(const gl::Context *context);
gl::Error getRenderNode(const gl::Context *context, vk::CommandBufferNode **nodeOut);
gl::Error getRenderNode(const gl::Context *context, vk::CommandGraphNode **nodeOut);
private:
FramebufferVk(const gl::FramebufferState &state);
......
......@@ -17,7 +17,7 @@
#include "common/debug.h"
#include "common/system_utils.h"
#include "libANGLE/renderer/driver_utils.h"
#include "libANGLE/renderer/vulkan/CommandBufferNode.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/CompilerVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/GlslangWrapper.h"
......@@ -600,7 +600,7 @@ const vk::CommandPool &RendererVk::getCommandPool() const
vk::Error RendererVk::finish(const gl::Context *context)
{
if (!mOpenCommandGraph.empty())
if (!mCommandGraph.empty())
{
vk::CommandBuffer commandBatch;
ANGLE_TRY(flushCommandGraph(context, &commandBatch));
......@@ -756,86 +756,15 @@ vk::Error RendererVk::getRenderPassWithOps(const vk::RenderPassDesc &desc,
renderPassOut);
}
vk::CommandBufferNode *RendererVk::allocateCommandNode()
vk::CommandGraphNode *RendererVk::allocateCommandNode()
{
// TODO(jmadill): Use a pool allocator for the CPU node allocations.
vk::CommandBufferNode *newCommands = new vk::CommandBufferNode();
mOpenCommandGraph.emplace_back(newCommands);
return newCommands;
return mCommandGraph.allocateNode();
}
vk::Error RendererVk::flushCommandGraph(const gl::Context *context, vk::CommandBuffer *commandBatch)
{
VkCommandBufferAllocateInfo primaryInfo;
primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
primaryInfo.pNext = nullptr;
primaryInfo.commandPool = mCommandPool.getHandle();
primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
primaryInfo.commandBufferCount = 1;
ANGLE_TRY(commandBatch->init(mDevice, primaryInfo));
if (mOpenCommandGraph.empty())
{
return vk::NoError();
}
std::vector<vk::CommandBufferNode *> nodeStack;
VkCommandBufferBeginInfo beginInfo;
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.pNext = nullptr;
beginInfo.flags = 0;
beginInfo.pInheritanceInfo = nullptr;
ANGLE_TRY(commandBatch->begin(beginInfo));
for (vk::CommandBufferNode *topLevelNode : mOpenCommandGraph)
{
// Only process commands that don't have child commands. The others will be pulled in
// automatically. Also skip commands that have already been visited.
if (topLevelNode->hasHappensAfterDependencies() ||
topLevelNode->visitedState() != vk::VisitedState::Unvisited)
continue;
nodeStack.push_back(topLevelNode);
while (!nodeStack.empty())
{
vk::CommandBufferNode *node = nodeStack.back();
switch (node->visitedState())
{
case vk::VisitedState::Unvisited:
node->visitDependencies(&nodeStack);
break;
case vk::VisitedState::Ready:
ANGLE_TRY(node->visitAndExecute(this, commandBatch));
nodeStack.pop_back();
break;
case vk::VisitedState::Visited:
nodeStack.pop_back();
break;
default:
UNREACHABLE();
break;
}
}
}
ANGLE_TRY(commandBatch->end());
resetCommandGraph();
return vk::NoError();
}
void RendererVk::resetCommandGraph()
{
// TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
for (vk::CommandBufferNode *node : mOpenCommandGraph)
{
delete node;
}
mOpenCommandGraph.clear();
return mCommandGraph.submitCommands(mDevice, mCurrentQueueSerial, &mRenderPassCache,
&mCommandPool, commandBatch);
}
vk::Error RendererVk::flush(const gl::Context *context,
......
......@@ -15,7 +15,7 @@
#include "common/angleutils.h"
#include "libANGLE/Caps.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace egl
......@@ -113,7 +113,7 @@ class RendererVk : angle::NonCopyable
// This should only be called from ResourceVk.
// TODO(jmadill): Keep in ContextVk to enable threaded rendering.
vk::CommandBufferNode *allocateCommandNode();
vk::CommandGraphNode *allocateCommandNode();
const vk::PipelineLayout &getGraphicsPipelineLayout() const;
const std::vector<vk::DescriptorSetLayout> &getGraphicsDescriptorSetLayouts() const;
......@@ -124,15 +124,10 @@ class RendererVk : angle::NonCopyable
private:
vk::Error initializeDevice(uint32_t queueFamilyIndex);
void ensureCapsInitialized() const;
void generateCaps(gl::Caps *outCaps,
gl::TextureCapsMap *outTextureCaps,
gl::Extensions *outExtensions,
gl::Limitations *outLimitations) const;
vk::Error submitFrame(const VkSubmitInfo &submitInfo, vk::CommandBuffer &&commandBatch);
vk::Error checkInFlightCommands();
void freeAllInFlightResources();
vk::Error flushCommandGraph(const gl::Context *context, vk::CommandBuffer *commandBatch);
void resetCommandGraph();
vk::Error initGraphicsPipelineLayout();
mutable bool mCapsInitialized;
......@@ -176,7 +171,9 @@ class RendererVk : angle::NonCopyable
RenderPassCache mRenderPassCache;
PipelineCache mPipelineCache;
std::vector<vk::CommandBufferNode *> mOpenCommandGraph;
// See CommandGraph.h for a desription of the Command Graph.
vk::CommandGraph mCommandGraph;
// ANGLE uses a single pipeline layout for all GL programs. It is owned here in the Renderer.
// See the design doc for an overview of the pipeline layout structure.
......
......@@ -374,7 +374,7 @@ vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
// Allocate a command buffer for clearing our images to black.
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteOperation(renderer, &commandBuffer));
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
VkClearColorValue transparentBlack;
transparentBlack.float32[0] = 0.0f;
......@@ -518,7 +518,7 @@ egl::Error WindowSurfaceVk::swap(const gl::Context *context)
RendererVk *renderer = displayVk->getRenderer();
vk::CommandBuffer *swapCommands = nullptr;
ANGLE_TRY(beginWriteOperation(renderer, &swapCommands));
ANGLE_TRY(beginWriteResource(renderer, &swapCommands));
auto &image = mSwapchainImages[mCurrentSwapchainImageIndex];
......
......@@ -253,7 +253,7 @@ gl::Error TextureVk::setSubImageImpl(ContextVk *contextVk,
stagingImage.getDeviceMemory().unmap(device);
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(beginWriteOperation(renderer, &commandBuffer));
ANGLE_TRY(beginWriteResource(renderer, &commandBuffer));
stagingImage.getImage().changeLayoutWithStages(
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
......
......@@ -13,7 +13,7 @@
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "libANGLE/renderer/vulkan/CommandBufferNode.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
......@@ -163,7 +163,7 @@ const gl::AttribArray<VkDeviceSize> &VertexArrayVk::getCurrentArrayBufferOffsets
return mCurrentArrayBufferOffsets;
}
void VertexArrayVk::updateDrawDependencies(vk::CommandBufferNode *readNode,
void VertexArrayVk::updateDrawDependencies(vk::CommandGraphNode *readNode,
const gl::AttributesMask &activeAttribsMask,
Serial serial,
DrawType drawType)
......
......@@ -36,7 +36,7 @@ class VertexArrayVk : public VertexArrayImpl
const gl::AttribArray<VkBuffer> &getCurrentArrayBufferHandles() const;
const gl::AttribArray<VkDeviceSize> &getCurrentArrayBufferOffsets() const;
void updateDrawDependencies(vk::CommandBufferNode *readNode,
void updateDrawDependencies(vk::CommandGraphNode *readNode,
const gl::AttributesMask &activeAttribsMask,
Serial serial,
DrawType drawType);
......
......@@ -10,7 +10,7 @@
#include "libANGLE/renderer/vulkan/vk_utils.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/CommandBufferNode.h"
#include "libANGLE/renderer/vulkan/CommandGraph.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
......@@ -1377,7 +1377,7 @@ VkFrontFace GetFrontFace(GLenum frontFace)
} // namespace gl_vk
ResourceVk::ResourceVk() : mCurrentWriteOperation(nullptr)
ResourceVk::ResourceVk() : mCurrentWritingNode(nullptr)
{
}
......@@ -1391,8 +1391,8 @@ void ResourceVk::updateQueueSerial(Serial queueSerial)
if (queueSerial > mStoredQueueSerial)
{
mCurrentWriteOperation = nullptr;
mCurrentReadOperations.clear();
mCurrentWritingNode = nullptr;
mCurrentReadingNodes.clear();
mStoredQueueSerial = queueSerial;
}
}
......@@ -1402,61 +1402,61 @@ Serial ResourceVk::getQueueSerial() const
return mStoredQueueSerial;
}
bool ResourceVk::hasCurrentWriteOperation(Serial currentSerial) const
bool ResourceVk::hasCurrentWritingNode(Serial currentSerial) const
{
return (mStoredQueueSerial == currentSerial && mCurrentWriteOperation != nullptr &&
!mCurrentWriteOperation->isFinishedRecording());
return (mStoredQueueSerial == currentSerial && mCurrentWritingNode != nullptr &&
!mCurrentWritingNode->hasChildren());
}
vk::CommandBufferNode *ResourceVk::getCurrentWriteOperation(Serial currentSerial)
vk::CommandGraphNode *ResourceVk::getCurrentWritingNode(Serial currentSerial)
{
ASSERT(currentSerial == mStoredQueueSerial);
return mCurrentWriteOperation;
return mCurrentWritingNode;
}
vk::CommandBufferNode *ResourceVk::getNewWriteNode(RendererVk *renderer)
vk::CommandGraphNode *ResourceVk::getNewWritingNode(RendererVk *renderer)
{
vk::CommandBufferNode *newCommands = renderer->allocateCommandNode();
vk::CommandGraphNode *newCommands = renderer->allocateCommandNode();
onWriteResource(newCommands, renderer->getCurrentQueueSerial());
return newCommands;
}
vk::Error ResourceVk::beginWriteOperation(RendererVk *renderer,
vk::CommandBuffer **commandBufferOut)
vk::Error ResourceVk::beginWriteResource(RendererVk *renderer, vk::CommandBuffer **commandBufferOut)
{
vk::CommandBufferNode *commands = getNewWriteNode(renderer);
vk::CommandGraphNode *commands = getNewWritingNode(renderer);
VkDevice device = renderer->getDevice();
ANGLE_TRY(commands->startRecording(device, renderer->getCommandPool(), commandBufferOut));
ANGLE_TRY(commands->beginOutsideRenderPassRecording(device, renderer->getCommandPool(),
commandBufferOut));
return vk::NoError();
}
void ResourceVk::onWriteResource(vk::CommandBufferNode *writeOperation, Serial serial)
void ResourceVk::onWriteResource(vk::CommandGraphNode *writingNode, Serial serial)
{
updateQueueSerial(serial);
// Make sure any open reads and writes finish before we execute 'newCommands'.
if (!mCurrentReadOperations.empty())
if (!mCurrentReadingNodes.empty())
{
vk::CommandBufferNode::SetHappensBeforeDependencies(mCurrentReadOperations, writeOperation);
mCurrentReadOperations.clear();
vk::CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes, writingNode);
mCurrentReadingNodes.clear();
}
if (mCurrentWriteOperation && mCurrentWriteOperation != writeOperation)
if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
{
vk::CommandBufferNode::SetHappensBeforeDependency(mCurrentWriteOperation, writeOperation);
vk::CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
}
mCurrentWriteOperation = writeOperation;
mCurrentWritingNode = writingNode;
}
void ResourceVk::onReadResource(vk::CommandBufferNode *readOperation, Serial serial)
void ResourceVk::onReadResource(vk::CommandGraphNode *readingNode, Serial serial)
{
if (hasCurrentWriteOperation(serial))
if (hasCurrentWritingNode(serial))
{
// Ensure 'readOperation' happens after the current write commands.
vk::CommandBufferNode::SetHappensBeforeDependency(getCurrentWriteOperation(serial),
readOperation);
vk::CommandGraphNode::SetHappensBeforeDependency(getCurrentWritingNode(serial),
readingNode);
ASSERT(mStoredQueueSerial == serial);
}
else
......@@ -1465,7 +1465,7 @@ void ResourceVk::onReadResource(vk::CommandBufferNode *readOperation, Serial ser
}
// Add the read operation to the list of nodes currently reading this resource.
mCurrentReadOperations.push_back(readOperation);
mCurrentReadingNodes.push_back(readingNode);
}
} // namespace rx
......
......@@ -83,7 +83,7 @@ enum class TextureDimension
namespace vk
{
class CommandBufferNode;
class CommandGraphNode;
struct Format;
template <typename T>
......@@ -693,28 +693,28 @@ class ResourceVk
Serial getQueueSerial() const;
// Returns true if any tracked read or write nodes match 'currentSerial'.
bool hasCurrentWriteOperation(Serial currentSerial) const;
bool hasCurrentWritingNode(Serial currentSerial) const;
// Returns the active write node, and asserts 'currentSerial' matches the stored serial.
vk::CommandBufferNode *getCurrentWriteOperation(Serial currentSerial);
vk::CommandGraphNode *getCurrentWritingNode(Serial currentSerial);
// Allocates a new write node and calls onWriteResource internally.
vk::CommandBufferNode *getNewWriteNode(RendererVk *renderer);
vk::CommandGraphNode *getNewWritingNode(RendererVk *renderer);
// Allocates a write node via getNewWriteNode and returns a started command buffer.
// The started command buffer will render outside of a RenderPass.
vk::Error beginWriteOperation(RendererVk *renderer, vk::CommandBuffer **commandBufferOut);
vk::Error beginWriteResource(RendererVk *renderer, vk::CommandBuffer **commandBufferOut);
// Called on an operation that will modify this ResourceVk.
void onWriteResource(vk::CommandBufferNode *writeOperation, Serial serial);
// Sets up dependency relations. 'writingNode' will modify 'this' ResourceVk.
void onWriteResource(vk::CommandGraphNode *writingNode, Serial serial);
// Sets up dependency relations. 'readOperation' has the commands that read from this object.
void onReadResource(vk::CommandBufferNode *readOperation, Serial serial);
// Sets up dependency relations. 'readingNode' will read from 'this' ResourceVk.
void onReadResource(vk::CommandGraphNode *readingNode, Serial serial);
private:
Serial mStoredQueueSerial;
std::vector<vk::CommandBufferNode *> mCurrentReadOperations;
vk::CommandBufferNode *mCurrentWriteOperation;
std::vector<vk::CommandGraphNode *> mCurrentReadingNodes;
vk::CommandGraphNode *mCurrentWritingNode;
};
} // namespace rx
......
......@@ -724,8 +724,8 @@
[
'libANGLE/renderer/vulkan/BufferVk.cpp',
'libANGLE/renderer/vulkan/BufferVk.h',
'libANGLE/renderer/vulkan/CommandBufferNode.cpp',
'libANGLE/renderer/vulkan/CommandBufferNode.h',
'libANGLE/renderer/vulkan/CommandGraph.cpp',
'libANGLE/renderer/vulkan/CommandGraph.h',
'libANGLE/renderer/vulkan/CompilerVk.cpp',
'libANGLE/renderer/vulkan/CompilerVk.h',
'libANGLE/renderer/vulkan/ContextVk.cpp',
......
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