Commit bc4ec4c1 by Ian Elliott Committed by Commit Bot

Vulkan: Plumb OpenGL ES commands to AGI/debuggers

Use vkCmd*DebugUtilsLabelEXT() calls to delimit all GLES commands, and group them under GLES draw/dispatch calls. Plumb calls from the EVENT macro (for every GL entrypoint) to vkCmd*DebugUtilsLabelEXT() via a newly-implemented DebugAnnotatorVk class. Use a new dirty bit so that cached entrypoints are associated with a triggering draw/dispatch command. The DebugAnnotatorVk::beginEvent() method saves a string in a vector of all GL commands in ContextVk. The dirty bit converts the strings into begin-end vkCmd*DebugUtilsLabelEXT() pairs. The DebugAnnotatorVk::endEvent() method makes the final vkCmdEndDebugUtilsLabelEXT() call for a draw/dispatch command. Enable the OGL->VK mapping feature by setting "angle_enable_trace = true" in GN args. Bug: b/162068318 Bug: b/169243237 Change-Id: I61b6a8d113168c0ce578d6efd002d8a393659aba Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2451517Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Ian Elliott <ianelliott@google.com>
parent 0faa4a3d
...@@ -81,7 +81,7 @@ std::ostream *gSwallowStream; ...@@ -81,7 +81,7 @@ std::ostream *gSwallowStream;
bool DebugAnnotationsActive() bool DebugAnnotationsActive()
{ {
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) || defined(ANGLE_ENABLE_DEBUG_TRACE)
return g_debugAnnotator != nullptr && g_debugAnnotator->getStatus(); return g_debugAnnotator != nullptr && g_debugAnnotator->getStatus();
#else #else
return false; return false;
......
...@@ -27,6 +27,8 @@ _vulkan_backend_sources = [ ...@@ -27,6 +27,8 @@ _vulkan_backend_sources = [
"CompilerVk.h", "CompilerVk.h",
"ContextVk.cpp", "ContextVk.cpp",
"ContextVk.h", "ContextVk.h",
"DebugAnnotatorVk.cpp",
"DebugAnnotatorVk.h",
"DeviceVk.cpp", "DeviceVk.cpp",
"DeviceVk.h", "DeviceVk.h",
"DisplayVk.cpp", "DisplayVk.cpp",
......
...@@ -714,6 +714,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -714,6 +714,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS); mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING); mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS_BINDING);
mGraphicsDirtyBitHandlers[DIRTY_BIT_EVENT_LOG] = &ContextVk::handleDirtyGraphicsEventLog;
mGraphicsDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] = mGraphicsDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] =
&ContextVk::handleDirtyGraphicsDefaultAttribs; &ContextVk::handleDirtyGraphicsDefaultAttribs;
mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyGraphicsPipeline; mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyGraphicsPipeline;
...@@ -744,8 +745,9 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -744,8 +745,9 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets; mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets;
mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyComputePipeline; mComputeDirtyBitHandlers[DIRTY_BIT_EVENT_LOG] = &ContextVk::handleDirtyGraphicsEventLog;
mComputeDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyComputeTextures; mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyComputePipeline;
mComputeDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyComputeTextures;
mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] = mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] =
&ContextVk::handleDirtyComputeDriverUniforms; &ContextVk::handleDirtyComputeDriverUniforms;
mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS_BINDING] = mComputeDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS_BINDING] =
...@@ -1328,6 +1330,57 @@ angle::Result ContextVk::setupDispatch(const gl::Context *context, ...@@ -1328,6 +1330,57 @@ angle::Result ContextVk::setupDispatch(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result ContextVk::handleDirtyGraphicsEventLog(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
if (mEventLog.empty())
{
return angle::Result::Continue;
}
// Insert OpenGL ES commands into debug label. We create a 3-level cascade here for
// OpenGL-ES-first debugging in AGI. Here's the general outline of commands:
// -glDrawCommand
// --vkCmdBeginDebugUtilsLabelEXT() #1 for "glDrawCommand"
// --OpenGL ES Commands
// ---vkCmdBeginDebugUtilsLabelEXT() #2 for "OpenGL ES Commands"
// ---Individual OpenGL ES Commands leading up to glDrawCommand
// ----vkCmdBeginDebugUtilsLabelEXT() #3 for each individual OpenGL ES Command
// ----vkCmdEndDebugUtilsLabelEXT() #3 for each individual OpenGL ES Command
// ----...More Individual OGL Commands...
// ----Final Individual OGL command will be the same glDrawCommand shown in #1 above
// ---vkCmdEndDebugUtilsLabelEXT() #2 for "OpenGL ES Commands"
// --VK SetupDraw & Draw-related commands will be embedded here under glDraw #1
// --vkCmdEndDebugUtilsLabelEXT() #1 is called after each vkDraw* or vkDispatch* call
VkDebugUtilsLabelEXT label = {VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
nullptr,
mEventLog.back().c_str(),
{0.0f, 0.0f, 0.0f, 0.0f}};
// This is #1 from comment above
commandBuffer->beginDebugUtilsLabelEXT(label);
std::string oglCmds = "OpenGL ES Commands";
label.pLabelName = oglCmds.c_str();
// This is #2 from comment above
commandBuffer->beginDebugUtilsLabelEXT(label);
for (uint32_t i = 0; i < mEventLog.size(); ++i)
{
label.pLabelName = mEventLog[i].c_str();
// NOTE: We have to use a begin/end pair here because AGI does not promote the
// pLabelName from an insertDebugUtilsLabelEXT() call to the Commands panel.
// Internal bug b/169243237 is tracking this and once the insert* call shows the
// pLabelName similar to begin* call, we can switch these to insert* calls instead.
// This is #3 from comment above.
commandBuffer->beginDebugUtilsLabelEXT(label);
commandBuffer->endDebugUtilsLabelEXT();
}
commandBuffer->endDebugUtilsLabelEXT();
// The final end* call for #1 above is made in the ContextVk::draw* or
// ContextVk::dispatch* function calls.
mEventLog.clear();
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyGraphicsDefaultAttribs(const gl::Context *context, angle::Result ContextVk::handleDirtyGraphicsDefaultAttribs(const gl::Context *context,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
{ {
...@@ -2633,6 +2686,22 @@ angle::Result ContextVk::popDebugGroup(const gl::Context *context) ...@@ -2633,6 +2686,22 @@ angle::Result ContextVk::popDebugGroup(const gl::Context *context)
return angle::Result::Continue; return angle::Result::Continue;
} }
void ContextVk::logEvent(const char *eventString)
{
// Save this event (about an OpenGL ES command being called).
mEventLog.push_back(eventString);
// Set a dirty bit in order to stay off the "hot path" for when not logging.
mGraphicsDirtyBits.set(DIRTY_BIT_EVENT_LOG);
mComputeDirtyBits.set(DIRTY_BIT_EVENT_LOG);
}
void ContextVk::endEventLog(gl::EntryPoint entryPoint)
{
ASSERT(mRenderPassCommands);
mRenderPassCommands->getCommandBuffer().endDebugUtilsLabelEXT();
}
bool ContextVk::isViewportFlipEnabledForDrawFBO() const bool ContextVk::isViewportFlipEnabledForDrawFBO() const
{ {
return mFlipViewportForDrawFramebuffer && mFlipYForCurrentSurface; return mFlipViewportForDrawFramebuffer && mFlipYForCurrentSurface;
......
...@@ -261,6 +261,10 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -261,6 +261,10 @@ class ContextVk : public ContextImpl, public vk::Context
const std::string &message) override; const std::string &message) override;
angle::Result popDebugGroup(const gl::Context *context) override; angle::Result popDebugGroup(const gl::Context *context) override;
// Record GL API calls for debuggers
void logEvent(const char *eventString);
void endEventLog(gl::EntryPoint entryPoint);
bool isViewportFlipEnabledForDrawFBO() const; bool isViewportFlipEnabledForDrawFBO() const;
bool isViewportFlipEnabledForReadFBO() const; bool isViewportFlipEnabledForReadFBO() const;
// When the device/surface is rotated such that the surface's aspect ratio is different than // When the device/surface is rotated such that the surface's aspect ratio is different than
...@@ -675,6 +679,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -675,6 +679,7 @@ class ContextVk : public ContextImpl, public vk::Context
// Dirty bits. // Dirty bits.
enum DirtyBitType : size_t enum DirtyBitType : size_t
{ {
DIRTY_BIT_EVENT_LOG,
DIRTY_BIT_DEFAULT_ATTRIBS, DIRTY_BIT_DEFAULT_ATTRIBS,
DIRTY_BIT_PIPELINE, DIRTY_BIT_PIPELINE,
DIRTY_BIT_TEXTURES, DIRTY_BIT_TEXTURES,
...@@ -846,6 +851,8 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -846,6 +851,8 @@ class ContextVk : public ContextImpl, public vk::Context
void invalidateDriverUniforms(); void invalidateDriverUniforms();
// Handlers for graphics pipeline dirty bits. // Handlers for graphics pipeline dirty bits.
angle::Result handleDirtyGraphicsEventLog(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsDefaultAttribs(const gl::Context *context, angle::Result handleDirtyGraphicsDefaultAttribs(const gl::Context *context,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsPipeline(const gl::Context *context, angle::Result handleDirtyGraphicsPipeline(const gl::Context *context,
...@@ -1165,6 +1172,9 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -1165,6 +1172,9 @@ class ContextVk : public ContextImpl, public vk::Context
vk::DynamicBuffer mStagingBuffer; vk::DynamicBuffer mStagingBuffer;
std::vector<std::string> mCommandBufferDiagnostics; std::vector<std::string> mCommandBufferDiagnostics;
// Record GL API calls for debuggers
std::vector<std::string> mEventLog;
}; };
ANGLE_INLINE angle::Result ContextVk::endRenderPassIfTransformFeedbackBuffer( ANGLE_INLINE angle::Result ContextVk::endRenderPassIfTransformFeedbackBuffer(
......
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DebugAnnotatorVk.cpp: Vulkan helpers for adding trace annotations.
//
#include "libANGLE/renderer/vulkan/DebugAnnotatorVk.h"
#include "libANGLE/Context.h"
#include "libANGLE/entry_points_enum_autogen.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
namespace rx
{
DebugAnnotatorVk::DebugAnnotatorVk() {}
DebugAnnotatorVk::~DebugAnnotatorVk() {}
void DebugAnnotatorVk::beginEvent(gl::Context *context,
gl::EntryPoint entryPoint,
const char *eventName,
const char *eventMessage)
{
angle::LoggingAnnotator::beginEvent(context, entryPoint, eventName, eventMessage);
if (context)
{
ContextVk *contextVk = vk::GetImpl(static_cast<gl::Context *>(context));
contextVk->logEvent(eventMessage);
}
}
void DebugAnnotatorVk::endEvent(gl::Context *context,
const char *eventName,
gl::EntryPoint entryPoint)
{
angle::LoggingAnnotator::endEvent(context, eventName, entryPoint);
if (context && isDrawOrDispatchEntryPoint(entryPoint))
{
ContextVk *contextVk = vk::GetImpl(static_cast<gl::Context *>(context));
contextVk->endEventLog(entryPoint);
}
}
bool DebugAnnotatorVk::getStatus()
{
return true;
}
bool DebugAnnotatorVk::isDrawOrDispatchEntryPoint(gl::EntryPoint entryPoint) const
{
switch (entryPoint)
{
case gl::EntryPoint::DispatchCompute:
case gl::EntryPoint::DispatchComputeIndirect:
case gl::EntryPoint::DrawArrays:
case gl::EntryPoint::DrawArraysIndirect:
case gl::EntryPoint::DrawArraysInstanced:
case gl::EntryPoint::DrawArraysInstancedANGLE:
case gl::EntryPoint::DrawArraysInstancedBaseInstance:
case gl::EntryPoint::DrawArraysInstancedBaseInstanceANGLE:
case gl::EntryPoint::DrawArraysInstancedEXT:
case gl::EntryPoint::DrawBuffer:
case gl::EntryPoint::DrawBuffers:
case gl::EntryPoint::DrawBuffersEXT:
case gl::EntryPoint::DrawElements:
case gl::EntryPoint::DrawElementsBaseVertex:
case gl::EntryPoint::DrawElementsBaseVertexEXT:
case gl::EntryPoint::DrawElementsBaseVertexOES:
case gl::EntryPoint::DrawElementsIndirect:
case gl::EntryPoint::DrawElementsInstanced:
case gl::EntryPoint::DrawElementsInstancedANGLE:
case gl::EntryPoint::DrawElementsInstancedBaseInstance:
case gl::EntryPoint::DrawElementsInstancedBaseVertex:
case gl::EntryPoint::DrawElementsInstancedBaseVertexBaseInstance:
case gl::EntryPoint::DrawElementsInstancedBaseVertexBaseInstanceANGLE:
case gl::EntryPoint::DrawElementsInstancedBaseVertexEXT:
case gl::EntryPoint::DrawElementsInstancedBaseVertexOES:
case gl::EntryPoint::DrawElementsInstancedEXT:
case gl::EntryPoint::DrawPixels:
case gl::EntryPoint::DrawRangeElements:
case gl::EntryPoint::DrawRangeElementsBaseVertex:
case gl::EntryPoint::DrawRangeElementsBaseVertexEXT:
case gl::EntryPoint::DrawRangeElementsBaseVertexOES:
case gl::EntryPoint::DrawTexfOES:
case gl::EntryPoint::DrawTexfvOES:
case gl::EntryPoint::DrawTexiOES:
case gl::EntryPoint::DrawTexivOES:
case gl::EntryPoint::DrawTexsOES:
case gl::EntryPoint::DrawTexsvOES:
case gl::EntryPoint::DrawTexxOES:
case gl::EntryPoint::DrawTexxvOES:
case gl::EntryPoint::DrawTransformFeedback:
case gl::EntryPoint::DrawTransformFeedbackInstanced:
case gl::EntryPoint::DrawTransformFeedbackStream:
case gl::EntryPoint::DrawTransformFeedbackStreamInstanced:
return true;
default:
return false;
}
}
} // namespace rx
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DebugAnnotatorVk.h: Vulkan helpers for adding trace annotations.
//
#ifndef LIBANGLE_RENDERER_VULKAN_DEBUGANNOTATORVK_H_
#define LIBANGLE_RENDERER_VULKAN_DEBUGANNOTATORVK_H_
#include "libANGLE/LoggingAnnotator.h"
namespace rx
{
class DebugAnnotatorVk : public angle::LoggingAnnotator
{
public:
DebugAnnotatorVk();
~DebugAnnotatorVk() override;
void beginEvent(gl::Context *context,
gl::EntryPoint entryPoint,
const char *eventName,
const char *eventMessage) override;
void endEvent(gl::Context *context, const char *eventName, gl::EntryPoint entryPoint) override;
bool getStatus() override;
private:
bool isDrawOrDispatchEntryPoint(gl::EntryPoint entryPoint) const;
// Note: To avoid any race conditions between threads, this class has no private data; all
// events are stored in ContextVk.
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_DEBUGANNOTATORVK_H_
...@@ -909,6 +909,7 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, ...@@ -909,6 +909,7 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
mCommandProcessorThread = mCommandProcessorThread =
std::thread(&CommandProcessor::processCommandProcessorTasks, &mCommandProcessor); std::thread(&CommandProcessor::processCommandProcessorTasks, &mCommandProcessor);
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -2378,9 +2379,12 @@ void RendererVk::onCompletedSerial(Serial serial) ...@@ -2378,9 +2379,12 @@ void RendererVk::onCompletedSerial(Serial serial)
void RendererVk::setGlobalDebugAnnotator() void RendererVk::setGlobalDebugAnnotator()
{ {
// TODO(ianelliott): Implement this method. // If the vkCmd*DebugUtilsLabelEXT functions exist, initialize DebugAnnotatorVk to log the
// // OpenGL ES commands that are used, for debuggers (e.g. AGI).
// https://issuetracker.google.com/issues/162068318 if (vkCmdBeginDebugUtilsLabelEXT)
{
gl::InitializeDebugAnnotations(&mAnnotator);
}
} }
void RendererVk::reloadVolkIfNeeded() const void RendererVk::reloadVolkIfNeeded() const
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "libANGLE/BlobCache.h" #include "libANGLE/BlobCache.h"
#include "libANGLE/Caps.h" #include "libANGLE/Caps.h"
#include "libANGLE/renderer/vulkan/CommandProcessor.h" #include "libANGLE/renderer/vulkan/CommandProcessor.h"
#include "libANGLE/renderer/vulkan/DebugAnnotatorVk.h"
#include "libANGLE/renderer/vulkan/QueryVk.h" #include "libANGLE/renderer/vulkan/QueryVk.h"
#include "libANGLE/renderer/vulkan/ResourceVk.h" #include "libANGLE/renderer/vulkan/ResourceVk.h"
#include "libANGLE/renderer/vulkan/UtilsVk.h" #include "libANGLE/renderer/vulkan/UtilsVk.h"
...@@ -371,6 +372,8 @@ class RendererVk : angle::NonCopyable ...@@ -371,6 +372,8 @@ class RendererVk : angle::NonCopyable
std::string mLastValidationMessage; std::string mLastValidationMessage;
uint32_t mValidationMessageCount; uint32_t mValidationMessageCount;
DebugAnnotatorVk mAnnotator;
// How close to VkPhysicalDeviceLimits::maxMemoryAllocationCount we allow ourselves to get // How close to VkPhysicalDeviceLimits::maxMemoryAllocationCount we allow ourselves to get
static constexpr double kPercentMaxMemoryAllocationCount = 0.3; static constexpr double kPercentMaxMemoryAllocationCount = 0.3;
// How many objects to garbage collect before issuing a flush() // How many objects to garbage collect before issuing a flush()
......
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