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