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>
This commit is contained in:
Jamie Madill 2018-10-02 09:31:39 -04:00 коммит произвёл Commit Bot
Родитель 38f24ee666
Коммит 0da73fedd9
5 изменённых файлов: 165 добавлений и 18 удалений

Просмотреть файл

@ -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 @@ angle::Result InitAndBeginCommandBuffer(vk::Context *context,
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 @@ angle::Result CommandGraphResource::beginRenderPass(Context *context,
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 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
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 @@ angle::Result CommandGraph::submitCommands(Context *context,
return angle::Result::Continue();
}
if (mEnableGraphDiagnostics)
{
dumpGraphDotFile(std::cout);
}
std::vector<CommandGraphNode *> nodeStack;
VkCommandBufferBeginInfo beginInfo;
@ -491,5 +527,80 @@ bool CommandGraph::empty() const
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

Просмотреть файл

@ -24,6 +24,13 @@ enum class VisitedState
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 @@ class CommandGraphNode final : angle::NonCopyable
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 @@ class CommandGraphNode final : angle::NonCopyable
// 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 @@ class CommandGraphNode final : angle::NonCopyable
// 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 @@ class CommandGraphResource
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 @@ class CommandGraphResource
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 CommandGraphResource
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 @@ class CommandGraph final : angle::NonCopyable
bool empty() const;
private:
std::vector<CommandGraphNode *> mNodes;
};
void dumpGraphDotFile(std::ostream &out) const;
std::vector<CommandGraphNode *> mNodes;
bool mEnableGraphDiagnostics;
};
} // namespace vk
} // namespace rx

Просмотреть файл

@ -261,6 +261,9 @@ void ChoosePhysicalDevice(const std::vector<VkPhysicalDevice> &physicalDevices,
*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 @@ RendererVk::RendererVk()
mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
mCurrentQueueSerial(mQueueSerialFactory.generate()),
mDeviceLost(false),
mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod)
mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod),
mCommandGraph(kEnableCommandGraphDiagnostics)
{
}

Просмотреть файл

@ -504,7 +504,8 @@ void LineLoopHelper::Draw(uint32_t count, CommandBuffer *commandBuffer)
}
// BufferHelper implementation.
BufferHelper::BufferHelper() : mMemoryPropertyFlags{}
BufferHelper::BufferHelper()
: CommandGraphResource(CommandGraphResourceType::Buffer), mMemoryPropertyFlags{}
{
}
@ -527,12 +528,17 @@ void BufferHelper::release(RendererVk *renderer)
// 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 @@ void ImageHelper::Copy(ImageHelper *srcImage,
}
// FramebufferHelper implementation.
FramebufferHelper::FramebufferHelper() = default;
FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResourceType::Framebuffer)
{
}
FramebufferHelper::~FramebufferHelper() = default;

Просмотреть файл

@ -166,7 +166,7 @@ class LineLoopHelper final : angle::NonCopyable
DynamicBuffer mDynamicIndexBuffer;
};
class BufferHelper final : public CommandGraphResource, angle::NonCopyable
class BufferHelper final : public CommandGraphResource
{
public:
BufferHelper();
@ -190,7 +190,7 @@ class BufferHelper final : public CommandGraphResource, angle::NonCopyable
VkMemoryPropertyFlags mMemoryPropertyFlags;
};
class ImageHelper final : public CommandGraphResource, angle::NonCopyable
class ImageHelper final : public CommandGraphResource
{
public:
ImageHelper();
@ -299,7 +299,7 @@ class ImageHelper final : public CommandGraphResource, angle::NonCopyable
uint32_t mLayerCount;
};
class FramebufferHelper : public CommandGraphResource, angle::NonCopyable
class FramebufferHelper : public CommandGraphResource
{
public:
FramebufferHelper();