diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.cpp b/src/libANGLE/renderer/vulkan/CommandGraph.cpp index 3dd74678b..ca59f87af 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 + #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(this)); onWriteImpl(newCommands, renderer->getCurrentQueueSerial()); } @@ -390,13 +406,28 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context, return angle::Result::Continue(); } +const std::vector &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 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 nodeIDMap; + std::map objectIDMap; + + // Map nodes to ids. + for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex) + { + const CommandGraphNode *node = mNodes[nodeIndex]; + nodeIDMap[node] = static_cast(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 << "
Node ID " + << nodeID << ">];" << 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 447ddd15f..894f6ae89 100644 --- a/src/libANGLE/renderer/vulkan/CommandGraph.h +++ b/src/libANGLE/renderer/vulkan/CommandGraph.h @@ -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 &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 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 mNodes; -}; + void dumpGraphDotFile(std::ostream &out) const; + std::vector mNodes; + bool mEnableGraphDiagnostics; +}; } // namespace vk } // namespace rx diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp index dfb0619e6..91ecf3f34 100644 --- a/src/libANGLE/renderer/vulkan/RendererVk.cpp +++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp @@ -261,6 +261,9 @@ void ChoosePhysicalDevice(const std::vector &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) { } diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp index 254e97675..d22082531 100644 --- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp +++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp @@ -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; diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h index 83b57e951..3d3c0bffb 100644 --- a/src/libANGLE/renderer/vulkan/vk_helpers.h +++ b/src/libANGLE/renderer/vulkan/vk_helpers.h @@ -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();