Commit 983e4469 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Implement debug markers

Covers both GL_KHR_debug and GL_EXT_debug_marker. Debug markers are used to specify events or hierarchically categorize a set of commands within the command buffer. When debugging, this allows for quicker navigation to the draw calls of interest, and otherwise provides context to debug output. Bug: angleproject:2853 Change-Id: Id65e11fc877d9e70b6fd0fae7f0bbbcb1164bf10 Reviewed-on: https://chromium-review.googlesource.com/c/1403956 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 55ea947c
......@@ -18,7 +18,7 @@ template <typename T>
struct Color
{
Color();
Color(T r, T g, T b, T a);
constexpr Color(T r, T g, T b, T a);
const T *data() const { return &red; }
T *ptr() { return &red; }
......
......@@ -15,7 +15,7 @@ Color<T>::Color() : Color(0, 0, 0, 0)
}
template <typename T>
Color<T>::Color(T r, T g, T b, T a) : red(r), green(g), blue(b), alpha(a)
constexpr Color<T>::Color(T r, T g, T b, T a) : red(r), green(g), blue(b), alpha(a)
{
}
......
......@@ -5005,8 +5005,8 @@ GLuint Context::getDebugMessageLog(GLuint count,
void Context::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar *message)
{
std::string msg(message, (length > 0) ? static_cast<size_t>(length) : strlen(message));
mImplementation->pushDebugGroup(source, id, msg);
mState.getDebug().pushGroup(source, id, std::move(msg));
mImplementation->pushDebugGroup(source, id, length, message);
}
void Context::popDebugGroup()
......
......@@ -137,8 +137,8 @@ class ContextImpl : public GLImplFactory
virtual void popGroupMarker() = 0;
// KHR_debug
virtual void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) = 0;
virtual void popDebugGroup() = 0;
virtual void pushDebugGroup(GLenum source, GLuint id, const std::string &message) = 0;
virtual void popDebugGroup() = 0;
// State sync with dirty bits.
virtual angle::Result syncState(const gl::Context *context,
......
......@@ -421,10 +421,10 @@ void Context11::popGroupMarker()
}
}
void Context11::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message)
void Context11::pushDebugGroup(GLenum source, GLuint id, const std::string &message)
{
// Fall through to the EXT_debug_marker functions
pushGroupMarker(length, message);
pushGroupMarker(message.size(), message.c_str());
}
void Context11::popDebugGroup()
......
......@@ -119,7 +119,7 @@ class Context11 : public ContextD3D, public MultisampleTextureInitializer
void popGroupMarker() override;
// KHR_debug
void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override;
void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override;
void popDebugGroup() override;
// State sync with dirty bits.
......
......@@ -244,10 +244,10 @@ void Context9::popGroupMarker()
}
}
void Context9::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message)
void Context9::pushDebugGroup(GLenum source, GLuint id, const std::string &message)
{
// Fall through to the EXT_debug_marker functions
pushGroupMarker(length, message);
pushGroupMarker(message.size(), message.c_str());
}
void Context9::popDebugGroup()
......
......@@ -118,7 +118,7 @@ class Context9 : public ContextD3D
void popGroupMarker() override;
// KHR_debug
void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override;
void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override;
void popDebugGroup() override;
// State sync with dirty bits.
......
......@@ -508,9 +508,9 @@ void ContextGL::popGroupMarker()
mRenderer->popGroupMarker();
}
void ContextGL::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message)
void ContextGL::pushDebugGroup(GLenum source, GLuint id, const std::string &message)
{
mRenderer->pushDebugGroup(source, id, length, message);
mRenderer->pushDebugGroup(source, id, message);
}
void ContextGL::popDebugGroup()
......
......@@ -173,7 +173,7 @@ class ContextGL : public ContextImpl
void popGroupMarker() override;
// KHR_debug
void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override;
void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override;
void popDebugGroup() override;
// State sync with dirty bits.
......
......@@ -422,7 +422,7 @@ void RendererGL::pushGroupMarker(GLsizei length, const char *marker) {}
void RendererGL::popGroupMarker() {}
void RendererGL::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) {}
void RendererGL::pushDebugGroup(GLenum source, GLuint id, const std::string &message) {}
void RendererGL::popDebugGroup() {}
......
......@@ -146,7 +146,7 @@ class RendererGL : angle::NonCopyable
void popGroupMarker();
// KHR_debug
void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message);
void pushDebugGroup(GLenum source, GLuint id, const std::string &message);
void popDebugGroup();
std::string getVendorString() const;
......
......@@ -266,7 +266,7 @@ void ContextNULL::pushGroupMarker(GLsizei length, const char *marker) {}
void ContextNULL::popGroupMarker() {}
void ContextNULL::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) {}
void ContextNULL::pushDebugGroup(GLenum source, GLuint id, const std::string &message) {}
void ContextNULL::popDebugGroup() {}
......
......@@ -140,7 +140,7 @@ class ContextNULL : public ContextImpl
void popGroupMarker() override;
// KHR_debug
void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override;
void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override;
void popDebugGroup() override;
// State sync with dirty bits.
......
......@@ -85,11 +85,45 @@ const char *GetResourceTypeName(CommandGraphResourceType resourceType,
UNREACHABLE();
return "FenceSync";
}
case CommandGraphResourceType::DebugMarker:
switch (function)
{
case CommandGraphNodeFunction::InsertDebugMarker:
return "InsertDebugMarker";
case CommandGraphNodeFunction::PushDebugMarker:
return "PushDebugMarker";
case CommandGraphNodeFunction::PopDebugMarker:
return "PopDebugMarker";
default:
UNREACHABLE();
return "DebugMarker";
}
default:
UNREACHABLE();
return "";
}
}
void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT *label)
{
static constexpr angle::ColorF kLabelColors[6] = {
angle::ColorF(1.0f, 0.5f, 0.5f, 1.0f), // DEBUG_SOURCE_API
angle::ColorF(0.5f, 1.0f, 0.5f, 1.0f), // DEBUG_SOURCE_WINDOW_SYSTEM
angle::ColorF(0.5f, 0.5f, 1.0f, 1.0f), // DEBUG_SOURCE_SHADER_COMPILER
angle::ColorF(0.7f, 0.7f, 0.7f, 1.0f), // DEBUG_SOURCE_THIRD_PARTY
angle::ColorF(0.5f, 0.8f, 0.9f, 1.0f), // DEBUG_SOURCE_APPLICATION
angle::ColorF(0.9f, 0.8f, 0.5f, 1.0f), // DEBUG_SOURCE_OTHER
};
int colorIndex = source - GL_DEBUG_SOURCE_API;
ASSERT(colorIndex >= 0 && static_cast<size_t>(colorIndex) < ArraySize(kLabelColors));
label->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
label->pNext = nullptr;
label->pLabelName = marker;
kLabelColors[colorIndex].writeData(label->color);
}
} // anonymous namespace
// CommandGraphResource implementation.
......@@ -356,6 +390,14 @@ void CommandGraphNode::setFenceSync(const vk::Event &event)
mFenceSyncEvent = event.getHandle();
}
void CommandGraphNode::setDebugMarker(GLenum source, std::string &&marker)
{
ASSERT(mFunction == CommandGraphNodeFunction::InsertDebugMarker ||
mFunction == CommandGraphNodeFunction::PushDebugMarker);
mDebugMarkerSource = source;
mDebugMarker = std::move(marker);
}
// Do not call this in anything but testing code, since it's slow.
bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
{
......@@ -499,6 +541,39 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
break;
case CommandGraphNodeFunction::InsertDebugMarker:
ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
if (vkCmdInsertDebugUtilsLabelEXT)
{
VkDebugUtilsLabelEXT label;
MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label);
vkCmdInsertDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label);
}
break;
case CommandGraphNodeFunction::PushDebugMarker:
ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
if (vkCmdBeginDebugUtilsLabelEXT)
{
VkDebugUtilsLabelEXT label;
MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label);
vkCmdBeginDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label);
}
break;
case CommandGraphNodeFunction::PopDebugMarker:
ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
if (vkCmdEndDebugUtilsLabelEXT)
{
vkCmdEndDebugUtilsLabelEXT(primaryCommandBuffer->getHandle());
}
break;
default:
UNREACHABLE();
}
......@@ -712,6 +787,26 @@ void CommandGraph::waitFenceSync(const vk::Event &event)
newNode->setFenceSync(event);
}
void CommandGraph::insertDebugMarker(GLenum source, std::string &&marker)
{
CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::DebugMarker,
CommandGraphNodeFunction::InsertDebugMarker);
newNode->setDebugMarker(source, std::move(marker));
}
void CommandGraph::pushDebugMarker(GLenum source, std::string &&marker)
{
CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::DebugMarker,
CommandGraphNodeFunction::PushDebugMarker);
newNode->setDebugMarker(source, std::move(marker));
}
void CommandGraph::popDebugMarker()
{
allocateBarrierNode(CommandGraphResourceType::DebugMarker,
CommandGraphNodeFunction::PopDebugMarker);
}
// Dumps the command graph into a dot file that works with graphviz.
void CommandGraph::dumpGraphDotFile(std::ostream &out) const
{
......@@ -739,38 +834,53 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
std::stringstream strstr;
strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
strstr << " ";
auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
if (it != objectIDMap.end())
if (node->getResourceTypeForDiagnostics() == CommandGraphResourceType::DebugMarker)
{
strstr << it->second;
// For debug markers, use the string from the debug marker itself.
if (node->getFunction() != CommandGraphNodeFunction::PopDebugMarker)
{
strstr << " " << node->getDebugMarker();
}
}
else
{
int id = 0;
strstr << " ";
switch (node->getResourceTypeForDiagnostics())
// Otherwise assign each object an ID, so all the nodes of the same object have the same
// label.
ASSERT(node->getResourceIDForDiagnostics() != 0);
auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
if (it != objectIDMap.end())
{
case CommandGraphResourceType::Buffer:
id = bufferIDCounter++;
break;
case CommandGraphResourceType::Framebuffer:
id = framebufferIDCounter++;
break;
case CommandGraphResourceType::Image:
id = imageIDCounter++;
break;
case CommandGraphResourceType::Query:
id = queryIDCounter++;
break;
default:
UNREACHABLE();
break;
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;
case CommandGraphResourceType::Query:
id = queryIDCounter++;
break;
default:
UNREACHABLE();
break;
}
objectIDMap[node->getResourceIDForDiagnostics()] = id;
strstr << id;
}
objectIDMap[node->getResourceIDForDiagnostics()] = id;
strstr << id;
}
const std::string &label = strstr.str();
......
......@@ -31,6 +31,7 @@ enum class CommandGraphResourceType
Image,
Query,
FenceSync,
DebugMarker,
};
// Certain functionality cannot be put in secondary command buffers, so they are special-cased in
......@@ -43,6 +44,9 @@ enum class CommandGraphNodeFunction
WriteTimestamp,
SetFenceSync,
WaitFenceSync,
InsertDebugMarker,
PushDebugMarker,
PopDebugMarker,
};
// Receives notifications when a command buffer is no longer able to record. Can be used with
......@@ -131,6 +135,8 @@ class CommandGraphNode final : angle::NonCopyable
void setQueryPool(const QueryPool *queryPool, uint32_t queryIndex);
void setFenceSync(const vk::Event &event);
void setDebugMarker(GLenum source, std::string &&marker);
const std::string &getDebugMarker() const { return mDebugMarker; }
ANGLE_INLINE void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess)
{
......@@ -177,6 +183,9 @@ class CommandGraphNode final : angle::NonCopyable
uint32_t mQueryIndex;
// GLsync and EGLSync:
VkEvent mFenceSyncEvent;
// Debug markers:
GLenum mDebugMarkerSource;
std::string mDebugMarker;
// Parents are commands that must be submitted before 'this' CommandNode can be submitted.
std::vector<CommandGraphNode *> mParents;
......@@ -369,6 +378,10 @@ class CommandGraph final : angle::NonCopyable
// GLsync and EGLSync:
void setFenceSync(const vk::Event &event);
void waitFenceSync(const vk::Event &event);
// Debug markers:
void insertDebugMarker(GLenum source, std::string &&marker);
void pushDebugMarker(GLenum source, std::string &&marker);
void popDebugMarker();
private:
CommandGraphNode *allocateBarrierNode(CommandGraphResourceType resourceType,
......
......@@ -565,27 +565,31 @@ std::string ContextVk::getRendererDescription() const
void ContextVk::insertEventMarker(GLsizei length, const char *marker)
{
// TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853
std::string markerStr(marker, length <= 0 ? strlen(marker) : length);
mRenderer->insertDebugMarker(GL_DEBUG_SOURCE_APPLICATION, static_cast<GLuint>(-1),
std::move(markerStr));
}
void ContextVk::pushGroupMarker(GLsizei length, const char *marker)
{
// TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853
std::string markerStr(marker, length <= 0 ? strlen(marker) : length);
mRenderer->pushDebugMarker(GL_DEBUG_SOURCE_APPLICATION, static_cast<GLuint>(-1),
std::move(markerStr));
}
void ContextVk::popGroupMarker()
{
// TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853
mRenderer->popDebugMarker();
}
void ContextVk::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message)
void ContextVk::pushDebugGroup(GLenum source, GLuint id, const std::string &message)
{
// TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853
mRenderer->pushDebugMarker(source, id, std::string(message));
}
void ContextVk::popDebugGroup()
{
// TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853
mRenderer->popDebugMarker();
}
bool ContextVk::isViewportFlipEnabledForDrawFBO() const
......
......@@ -90,7 +90,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
void popGroupMarker() override;
// KHR_debug
void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override;
void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override;
void popDebugGroup() override;
bool isViewportFlipEnabledForDrawFBO() const;
......
......@@ -225,16 +225,6 @@ DebugUtilsMessenger(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
const VkDebugUtilsMessengerCallbackDataEXT *callbackData,
void *userData)
{
constexpr VkDebugUtilsMessageSeverityFlagsEXT kSeveritiesToLog =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
// Check if we even care about this message.
if ((messageSeverity & kSeveritiesToLog) == 0)
{
return VK_FALSE;
}
// See if it's an issue we are aware of and don't want to be spammed about.
if (IsIgnoredDebugMessage(callbackData->pMessageIdName))
{
......@@ -739,12 +729,18 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
// Create the messenger callback.
VkDebugUtilsMessengerCreateInfoEXT messengerInfo = {};
constexpr VkDebugUtilsMessageSeverityFlagsEXT kSeveritiesToLog =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
constexpr VkDebugUtilsMessageTypeFlagsEXT kMessagesToLog =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
messengerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
messengerInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
messengerInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
messengerInfo.messageSeverity = kSeveritiesToLog;
messengerInfo.messageType = kMessagesToLog;
messengerInfo.pfnUserCallback = &DebugUtilsMessenger;
messengerInfo.pUserData = this;
......@@ -1744,6 +1740,21 @@ bool RendererVk::hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatu
return hasFormatFeatureBits<&VkFormatProperties::bufferFeatures>(format, featureBits);
}
void RendererVk::insertDebugMarker(GLenum source, GLuint id, std::string &&marker)
{
mCommandGraph.insertDebugMarker(source, std::move(marker));
}
void RendererVk::pushDebugMarker(GLenum source, GLuint id, std::string &&marker)
{
mCommandGraph.pushDebugMarker(source, std::move(marker));
}
void RendererVk::popDebugMarker()
{
mCommandGraph.popDebugMarker();
}
angle::Result RendererVk::synchronizeCpuGpuTime(vk::Context *context)
{
ASSERT(mGpuEventsEnabled);
......
......@@ -205,6 +205,10 @@ class RendererVk : angle::NonCopyable
bool hasTextureFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
bool hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
void insertDebugMarker(GLenum source, GLuint id, std::string &&marker);
void pushDebugMarker(GLenum source, GLuint id, std::string &&marker);
void popDebugMarker();
private:
// Number of semaphores for external entities to renderer to issue a wait, such as surface's
// image acquire.
......
......@@ -475,6 +475,9 @@ void GarbageObject::destroy(VkDevice device)
// VK_EXT_debug_utils
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr;
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr;
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT = nullptr;
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT = nullptr;
PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT = nullptr;
// VK_EXT_debug_report
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = nullptr;
......@@ -496,6 +499,9 @@ void InitDebugUtilsEXTFunctions(VkInstance instance)
{
GET_FUNC(vkCreateDebugUtilsMessengerEXT);
GET_FUNC(vkDestroyDebugUtilsMessengerEXT);
GET_FUNC(vkCmdBeginDebugUtilsLabelEXT);
GET_FUNC(vkCmdEndDebugUtilsLabelEXT);
GET_FUNC(vkCmdInsertDebugUtilsLabelEXT);
}
void InitDebugReportEXTFunctions(VkInstance instance)
......
......@@ -382,6 +382,9 @@ class BindingPointer final : angle::NonCopyable
// VK_EXT_debug_utils
extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT;
extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT;
extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT;
// VK_EXT_debug_report
extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment