Commit a4e06ca0 by Ben Clayton

Vulkan: Add debugging of the command buffer.

Add a debugger context and server to vk::Device, along with a getter for acquiring the debugger context. Generate a synthetic file containing all the Vulkan commands in the command buffer, and allow the debugger to single line step over these. All of this is no-op unless ENABLE_VK_DEBUGGER is defined at compile time, and the VK_DEBUGGER_PORT env var is set at run time. Bug: b/145351270 Change-Id: I8bea398a6c08d4cb23d76172dbca2a08ae109a6d Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38913 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent 45a4d0f3
......@@ -15,14 +15,14 @@
#ifndef VK_DEBUG_VALUE_HPP_
#define VK_DEBUG_VALUE_HPP_
#include "Type.hpp"
#include <memory>
#include <string>
namespace vk {
namespace dbg {
class Type;
// FormatFlags holds settings used to serialize a Value to a string.
struct FormatFlags
{
......
......@@ -25,6 +25,12 @@
#include "VkRenderPass.hpp"
#include "Device/Renderer.hpp"
#include "./Debug/Context.hpp"
#include "./Debug/File.hpp"
#include "./Debug/Thread.hpp"
#include "marl/defer.h"
#include <cstring>
class vk::CommandBuffer::Command
......@@ -1281,8 +1287,9 @@ private:
namespace vk {
CommandBuffer::CommandBuffer(VkCommandBufferLevel pLevel)
: level(pLevel)
CommandBuffer::CommandBuffer(Device *device, VkCommandBufferLevel pLevel)
: device(device)
, level(pLevel)
{
// FIXME (b/119409619): replace this vector by an allocator so we can control all memory allocations
commands = new std::vector<std::unique_ptr<Command>>();
......@@ -1329,6 +1336,19 @@ VkResult CommandBuffer::end()
state = EXECUTABLE;
#ifdef ENABLE_VK_DEBUGGER
auto debuggerContext = device->getDebuggerContext();
if(debuggerContext)
{
std::string source;
for(auto &command : *commands)
{
source += command->description() + "\n";
}
debuggerFile = debuggerContext->lock().createVirtualFile("VkCommandBuffer", source.c_str());
}
#endif // ENABLE_VK_DEBUGGER
return VK_SUCCESS;
}
......@@ -1745,8 +1765,30 @@ void CommandBuffer::submit(CommandBuffer::ExecutionState &executionState)
// Perform recorded work
state = PENDING;
#ifdef ENABLE_VK_DEBUGGER
std::shared_ptr<vk::dbg::Thread> debuggerThread;
auto debuggerContext = device->getDebuggerContext();
if(debuggerContext)
{
auto lock = debuggerContext->lock();
debuggerThread = lock.currentThread();
debuggerThread->setName("vkQueue processor");
debuggerThread->enter(lock, debuggerFile, "vkCommandBuffer::submit");
lock.unlock();
}
defer(if(debuggerThread) { debuggerThread->exit(); });
int line = 1;
#endif // ENABLE_VK_DEBUGGER
for(auto &command : *commands)
{
#ifdef ENABLE_VK_DEBUGGER
if(debuggerThread)
{
debuggerThread->update({ line++, debuggerFile });
}
#endif // ENABLE_VK_DEBUGGER
command->play(executionState);
}
......
......@@ -20,6 +20,7 @@
#include "VkObject.hpp"
#include "Device/Color.hpp"
#include "Device/Context.hpp"
#include <memory>
#include <vector>
......@@ -33,6 +34,11 @@ class TaskEvents;
namespace vk {
namespace dbg {
class File;
} // namespace dbg
class Device;
class Buffer;
class Event;
class Framebuffer;
......@@ -47,7 +53,7 @@ class CommandBuffer
public:
static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; }
CommandBuffer(VkCommandBufferLevel pLevel);
CommandBuffer(Device *device, VkCommandBufferLevel pLevel);
static inline CommandBuffer *Cast(VkCommandBuffer object)
{
......@@ -201,11 +207,17 @@ private:
PENDING,
INVALID
};
Device *const device;
State state = INITIAL;
VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
// FIXME (b/119409619): replace this vector by an allocator so we can control all memory allocations
std::vector<std::unique_ptr<Command>> *commands;
#ifdef ENABLE_VK_DEBUGGER
std::shared_ptr<vk::dbg::File> debuggerFile;
#endif // ENABLE_VK_DEBUGGER
};
using DispatchableCommandBuffer = DispatchableObject<CommandBuffer, VkCommandBuffer>;
......
......@@ -46,7 +46,7 @@ size_t CommandPool::ComputeRequiredAllocationSize(const VkCommandPoolCreateInfo
return 0;
}
VkResult CommandPool::allocateCommandBuffers(VkCommandBufferLevel level, uint32_t commandBufferCount, VkCommandBuffer *pCommandBuffers)
VkResult CommandPool::allocateCommandBuffers(Device *device, VkCommandBufferLevel level, uint32_t commandBufferCount, VkCommandBuffer *pCommandBuffers)
{
for(uint32_t i = 0; i < commandBufferCount; i++)
{
......@@ -54,7 +54,7 @@ VkResult CommandPool::allocateCommandBuffers(VkCommandBufferLevel level, uint32_
void *deviceMemory = vk::allocate(sizeof(DispatchableCommandBuffer), REQUIRED_MEMORY_ALIGNMENT,
DEVICE_MEMORY, DispatchableCommandBuffer::GetAllocationScope());
ASSERT(deviceMemory);
DispatchableCommandBuffer *commandBuffer = new(deviceMemory) DispatchableCommandBuffer(level);
DispatchableCommandBuffer *commandBuffer = new(deviceMemory) DispatchableCommandBuffer(device, level);
if(commandBuffer)
{
pCommandBuffers[i] = *commandBuffer;
......
......@@ -16,10 +16,13 @@
#define VK_COMMAND_POOL_HPP_
#include "VkObject.hpp"
#include <set>
namespace vk {
class Device;
class CommandPool : public Object<CommandPool, VkCommandPool>
{
public:
......@@ -28,7 +31,7 @@ public:
static size_t ComputeRequiredAllocationSize(const VkCommandPoolCreateInfo *pCreateInfo);
VkResult allocateCommandBuffers(VkCommandBufferLevel level, uint32_t commandBufferCount, VkCommandBuffer *pCommandBuffers);
VkResult allocateCommandBuffers(Device *device, VkCommandBufferLevel level, uint32_t commandBufferCount, VkCommandBuffer *pCommandBuffers);
void freeCommandBuffers(uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers);
VkResult reset(VkCommandPoolResetFlags flags);
void trim(VkCommandPoolTrimFlags flags);
......
......@@ -19,6 +19,8 @@
#include "VkDescriptorSetLayout.hpp"
#include "VkFence.hpp"
#include "VkQueue.hpp"
#include "Debug/Context.hpp"
#include "Debug/Server.hpp"
#include "Device/Blitter.hpp"
#include <chrono>
......@@ -97,6 +99,18 @@ Device::Device(const VkDeviceCreateInfo *pCreateInfo, void *mem, PhysicalDevice
// FIXME (b/119409619): use an allocator here so we can control all memory allocations
blitter.reset(new sw::Blitter());
samplingRoutineCache.reset(new SamplingRoutineCache());
#ifdef ENABLE_VK_DEBUGGER
static auto port = getenv("VK_DEBUGGER_PORT");
if(port)
{
// Construct the debugger context and server - this may block for a
// debugger connection, allowing breakpoints to be set before they're
// executed.
debugger.context = vk::dbg::Context::create();
debugger.server = vk::dbg::Server::create(debugger.context, atoi(port));
}
#endif // ENABLE_VK_DEBUGGER
}
void Device::destroy(const VkAllocationCallbacks *pAllocator)
......
......@@ -33,6 +33,11 @@ namespace vk {
class PhysicalDevice;
class Queue;
namespace dbg {
class Context;
class Server;
} // namespace dbg
class Device
{
public:
......@@ -93,6 +98,13 @@ public:
rr::Routine *findInConstCache(const SamplingRoutineCache::Key &key) const;
void updateSamplingRoutineConstCache();
#ifdef ENABLE_VK_DEBUGGER
std::shared_ptr<vk::dbg::Context> getDebuggerContext() const
{
return debugger.context;
}
#endif // ENABLE_VK_DEBUGGER
private:
PhysicalDevice *const physicalDevice = nullptr;
Queue *const queues = nullptr;
......@@ -105,6 +117,14 @@ private:
ExtensionName *extensions = nullptr;
const VkPhysicalDeviceFeatures enabledFeatures = {};
std::shared_ptr<marl::Scheduler> scheduler;
#ifdef ENABLE_VK_DEBUGGER
struct
{
std::shared_ptr<vk::dbg::Context> context;
std::shared_ptr<vk::dbg::Server> server;
} debugger;
#endif // ENABLE_VK_DEBUGGER
};
using DispatchableDevice = DispatchableObject<Device, VkDevice>;
......
......@@ -1964,7 +1964,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers(VkDevice device, const V
nextInfo = nextInfo->pNext;
}
return vk::Cast(pAllocateInfo->commandPool)->allocateCommandBuffers(pAllocateInfo->level, pAllocateInfo->commandBufferCount, pCommandBuffers);
return vk::Cast(pAllocateInfo->commandPool)->allocateCommandBuffers(vk::Cast(device), pAllocateInfo->level, pAllocateInfo->commandBufferCount, pCommandBuffers);
}
VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers)
......
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