Vulkan: Add dumping of the command graph to GraphViz.
Dot files are a graph format that can be visualized with GraphViz.
Giving a small visualization output can help diagnose problems with
the graph. For example extra edges or incorrect dependencies.
Bug: angleproject:2379
Change-Id: I544cba11c5e33579b06fef2fb41bad60066a64e4
Reviewed-on: https://chromium-review.googlesource.com/1254383
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Tobin Ehlis <tobine@google.com>
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.cpp b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
index 3dd7467..ca59f87 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.cpp
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
@@ -9,6 +9,8 @@
#include "libANGLE/renderer/vulkan/CommandGraph.h"
+#include <iostream>
+
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
@@ -16,13 +18,10 @@
namespace rx
{
-
namespace vk
{
-
namespace
{
-
angle::Result InitAndBeginCommandBuffer(vk::Context *context,
const CommandPool &commandPool,
const VkCommandBufferInheritanceInfo &inheritanceInfo,
@@ -50,10 +49,26 @@
return angle::Result::Continue();
}
+const char *GetResourceTypeName(CommandGraphResourceType resourceType)
+{
+ switch (resourceType)
+ {
+ case CommandGraphResourceType::Buffer:
+ return "Buffer";
+ case CommandGraphResourceType::Framebuffer:
+ return "Framebuffer";
+ case CommandGraphResourceType::Image:
+ return "Image";
+ default:
+ UNREACHABLE();
+ return "";
+ }
+}
} // anonymous namespace
// CommandGraphResource implementation.
-CommandGraphResource::CommandGraphResource() : mCurrentWritingNode(nullptr)
+CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
+ : mCurrentWritingNode(nullptr), mResourceType(resourceType)
{
}
@@ -145,6 +160,7 @@
void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
{
CommandGraphNode *newCommands = renderer->getCommandGraph()->allocateNode();
+ newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
}
@@ -390,13 +406,28 @@
return angle::Result::Continue();
}
+const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
+{
+ return mParents;
+}
+
+void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
+ uintptr_t resourceID)
+{
+ mResourceType = resourceType;
+ mResourceID = resourceID;
+}
+
const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
{
return mRenderPassRenderArea;
}
// CommandGraph implementation.
-CommandGraph::CommandGraph() = default;
+CommandGraph::CommandGraph(bool enableGraphDiagnostics)
+ : mEnableGraphDiagnostics(enableGraphDiagnostics)
+{
+}
CommandGraph::~CommandGraph()
{
@@ -431,6 +462,11 @@
return angle::Result::Continue();
}
+ if (mEnableGraphDiagnostics)
+ {
+ dumpGraphDotFile(std::cout);
+ }
+
std::vector<CommandGraphNode *> nodeStack;
VkCommandBufferBeginInfo beginInfo;
@@ -491,5 +527,80 @@
return mNodes.empty();
}
+// Dumps the command graph into a dot file that works with graphviz.
+void CommandGraph::dumpGraphDotFile(std::ostream &out) const
+{
+ // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
+ std::map<const CommandGraphNode *, int> nodeIDMap;
+ std::map<uintptr_t, int> objectIDMap;
+
+ // Map nodes to ids.
+ for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
+ {
+ const CommandGraphNode *node = mNodes[nodeIndex];
+ nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
+ }
+
+ int bufferIDCounter = 1;
+ int framebufferIDCounter = 1;
+ int imageIDCounter = 1;
+
+ out << "digraph {" << std::endl;
+
+ for (const CommandGraphNode *node : mNodes)
+ {
+ int nodeID = nodeIDMap[node];
+
+ std::stringstream strstr;
+ strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics());
+ strstr << " ";
+
+ auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
+ if (it != objectIDMap.end())
+ {
+ strstr << it->second;
+ }
+ else
+ {
+ int id = 0;
+
+ switch (node->getResourceTypeForDiagnostics())
+ {
+ case CommandGraphResourceType::Buffer:
+ id = bufferIDCounter++;
+ break;
+ case CommandGraphResourceType::Framebuffer:
+ id = framebufferIDCounter++;
+ break;
+ case CommandGraphResourceType::Image:
+ id = imageIDCounter++;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ objectIDMap[node->getResourceIDForDiagnostics()] = id;
+ strstr << id;
+ }
+
+ const std::string &label = strstr.str();
+ out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
+ << nodeID << "</FONT>>];" << std::endl;
+ }
+
+ for (const CommandGraphNode *node : mNodes)
+ {
+ int nodeID = nodeIDMap[node];
+
+ for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
+ {
+ int parentID = nodeIDMap[parent];
+ out << " " << parentID << " -> " << nodeID << ";" << std::endl;
+ }
+ }
+
+ out << "}" << std::endl;
+}
} // namespace vk
} // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.h b/src/libANGLE/renderer/vulkan/CommandGraph.h
index 447ddd1..894f6ae 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.h
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.h
@@ -24,6 +24,13 @@
Visited,
};
+enum class CommandGraphResourceType
+{
+ Buffer,
+ Framebuffer,
+ Image,
+};
+
// Only used internally in the command graph. Kept in the header for better inlining performance.
class CommandGraphNode final : angle::NonCopyable
{
@@ -72,6 +79,13 @@
RenderPassCache *renderPassCache,
CommandBuffer *primaryCommandBuffer);
+ // Only used in the command graph diagnostics.
+ const std::vector<CommandGraphNode *> &getParentsForDiagnostics() const;
+ void setDiagnosticInfo(CommandGraphResourceType resourceType, uintptr_t resourceID);
+
+ CommandGraphResourceType getResourceTypeForDiagnostics() const { return mResourceType; }
+ uintptr_t getResourceIDForDiagnostics() const { return mResourceID; }
+
const gl::Rectangle &getRenderPassRenderArea() const;
private:
@@ -99,6 +113,10 @@
// Used when traversing the dependency graph.
VisitedState mVisitedState;
+
+ // Additional diagnostic information.
+ CommandGraphResourceType mResourceType;
+ uintptr_t mResourceID;
};
// This is a helper class for back-end objects used in Vk command buffers. It records a serial
@@ -107,10 +125,9 @@
// queue serial in a special 'garbage' queue. Resources also track current read and write
// dependencies. Only one command buffer node can be writing to the Resource at a time, but many
// can be reading from it. Together the dependencies will form a command graph at submission time.
-class CommandGraphResource
+class CommandGraphResource : angle::NonCopyable
{
public:
- CommandGraphResource();
virtual ~CommandGraphResource();
// Returns true if the resource is in use by the renderer.
@@ -147,6 +164,8 @@
void finishCurrentCommands(RendererVk *renderer);
protected:
+ explicit CommandGraphResource(CommandGraphResourceType resourceType);
+
// Get the current queue serial for this resource. Only used to release resources.
Serial getStoredQueueSerial() const;
@@ -173,6 +192,9 @@
Serial mStoredQueueSerial;
std::vector<CommandGraphNode *> mCurrentReadingNodes;
CommandGraphNode *mCurrentWritingNode;
+
+ // Additional diagnostic information.
+ CommandGraphResourceType mResourceType;
};
// Translating OpenGL commands into Vulkan and submitting them immediately loses out on some
@@ -199,7 +221,7 @@
class CommandGraph final : angle::NonCopyable
{
public:
- CommandGraph();
+ explicit CommandGraph(bool enableGraphDiagnostics);
~CommandGraph();
// Allocates a new CommandGraphNode and adds it to the list of current open nodes. No ordering
@@ -215,9 +237,11 @@
bool empty() const;
private:
- std::vector<CommandGraphNode *> mNodes;
-};
+ void dumpGraphDotFile(std::ostream &out) const;
+ std::vector<CommandGraphNode *> mNodes;
+ bool mEnableGraphDiagnostics;
+};
} // namespace vk
} // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index dfb0619..91ecf3f 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -261,6 +261,9 @@
*physicalDeviceOut = physicalDevices[0];
vkGetPhysicalDeviceProperties(*physicalDeviceOut, physicalDevicePropertiesOut);
}
+
+// Initially dumping the command graphs is disabled.
+constexpr bool kEnableCommandGraphDiagnostics = false;
} // anonymous namespace
// CommandBatch implementation.
@@ -300,7 +303,8 @@
mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
mCurrentQueueSerial(mQueueSerialFactory.generate()),
mDeviceLost(false),
- mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod)
+ mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod),
+ mCommandGraph(kEnableCommandGraphDiagnostics)
{
}
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
index 254e976..d220825 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
@@ -504,7 +504,8 @@
}
// BufferHelper implementation.
-BufferHelper::BufferHelper() : mMemoryPropertyFlags{}
+BufferHelper::BufferHelper()
+ : CommandGraphResource(CommandGraphResourceType::Buffer), mMemoryPropertyFlags{}
{
}
@@ -527,12 +528,17 @@
// ImageHelper implementation.
ImageHelper::ImageHelper()
- : mFormat(nullptr), mSamples(0), mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED), mLayerCount(0)
+ : CommandGraphResource(CommandGraphResourceType::Image),
+ mFormat(nullptr),
+ mSamples(0),
+ mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED),
+ mLayerCount(0)
{
}
ImageHelper::ImageHelper(ImageHelper &&other)
- : mImage(std::move(other.mImage)),
+ : CommandGraphResource(CommandGraphResourceType::Image),
+ mImage(std::move(other.mImage)),
mDeviceMemory(std::move(other.mDeviceMemory)),
mExtents(other.mExtents),
mFormat(other.mFormat),
@@ -935,7 +941,9 @@
}
// FramebufferHelper implementation.
-FramebufferHelper::FramebufferHelper() = default;
+FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResourceType::Framebuffer)
+{
+}
FramebufferHelper::~FramebufferHelper() = default;
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
index 83b57e9..3d3c0bf 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
@@ -166,7 +166,7 @@
DynamicBuffer mDynamicIndexBuffer;
};
-class BufferHelper final : public CommandGraphResource, angle::NonCopyable
+class BufferHelper final : public CommandGraphResource
{
public:
BufferHelper();
@@ -190,7 +190,7 @@
VkMemoryPropertyFlags mMemoryPropertyFlags;
};
-class ImageHelper final : public CommandGraphResource, angle::NonCopyable
+class ImageHelper final : public CommandGraphResource
{
public:
ImageHelper();
@@ -299,7 +299,7 @@
uint32_t mLayerCount;
};
-class FramebufferHelper : public CommandGraphResource, angle::NonCopyable
+class FramebufferHelper : public CommandGraphResource
{
public:
FramebufferHelper();