зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
38f24ee666
Коммит
0da73fedd9
|
@ -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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче