2016-02-23 13:45:51 +01:00
|
|
|
/*
|
|
|
|
|
* Vulkan examples debug wrapper
|
2016-06-08 22:41:29 +02:00
|
|
|
*
|
|
|
|
|
* Appendix for VK_EXT_Debug_Report can be found at https://github.com/KhronosGroup/Vulkan-Docs/blob/1.0-VK_EXT_debug_report/doc/specs/vulkan/appendices/debug_report.txt
|
2016-02-23 13:45:51 +01:00
|
|
|
*
|
|
|
|
|
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
|
|
|
|
|
*
|
|
|
|
|
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
|
|
|
|
*/
|
|
|
|
|
|
2017-02-12 11:33:04 +01:00
|
|
|
#include "VulkanDebug.h"
|
2016-02-16 15:07:25 +01:00
|
|
|
#include <iostream>
|
|
|
|
|
|
2017-02-12 11:33:04 +01:00
|
|
|
namespace vks
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-02-12 11:33:04 +01:00
|
|
|
namespace debug
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-03-13 19:24:07 +01:00
|
|
|
#if !defined(__ANDROID__)
|
|
|
|
|
// On desktop the LunarG loaders exposes a meta layer that contains all layers
|
|
|
|
|
int32_t validationLayerCount = 1;
|
|
|
|
|
const char *validationLayerNames[] = {
|
2017-02-12 11:33:04 +01:00
|
|
|
"VK_LAYER_LUNARG_standard_validation"
|
2016-06-08 22:41:29 +02:00
|
|
|
};
|
2017-03-13 19:24:07 +01:00
|
|
|
#else
|
|
|
|
|
// On Android we need to explicitly select all layers
|
2017-03-13 19:32:23 +01:00
|
|
|
int32_t validationLayerCount = 6;
|
2017-03-13 19:24:07 +01:00
|
|
|
const char *validationLayerNames[] = {
|
|
|
|
|
"VK_LAYER_GOOGLE_threading",
|
|
|
|
|
"VK_LAYER_LUNARG_parameter_validation",
|
|
|
|
|
"VK_LAYER_LUNARG_object_tracker",
|
|
|
|
|
"VK_LAYER_LUNARG_core_validation",
|
|
|
|
|
"VK_LAYER_LUNARG_swapchain",
|
|
|
|
|
"VK_LAYER_GOOGLE_unique_objects"
|
|
|
|
|
};
|
|
|
|
|
#endif
|
2017-02-12 11:33:04 +01:00
|
|
|
|
|
|
|
|
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback = VK_NULL_HANDLE;
|
|
|
|
|
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback = VK_NULL_HANDLE;
|
|
|
|
|
PFN_vkDebugReportMessageEXT dbgBreakCallback = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
|
|
VkDebugReportCallbackEXT msgCallback;
|
|
|
|
|
|
|
|
|
|
VkBool32 messageCallback(
|
|
|
|
|
VkDebugReportFlagsEXT flags,
|
|
|
|
|
VkDebugReportObjectTypeEXT objType,
|
|
|
|
|
uint64_t srcObject,
|
|
|
|
|
size_t location,
|
|
|
|
|
int32_t msgCode,
|
|
|
|
|
const char* pLayerPrefix,
|
|
|
|
|
const char* pMsg,
|
|
|
|
|
void* pUserData)
|
2016-06-08 22:41:29 +02:00
|
|
|
{
|
2017-02-12 11:33:04 +01:00
|
|
|
// Select prefix depending on flags passed to the callback
|
|
|
|
|
// Note that multiple flags may be set for a single validation message
|
|
|
|
|
std::string prefix("");
|
2016-06-08 22:41:29 +02:00
|
|
|
|
2017-02-12 11:33:04 +01:00
|
|
|
// Error that may result in undefined behaviour
|
|
|
|
|
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
|
|
|
|
|
{
|
|
|
|
|
prefix += "ERROR:";
|
|
|
|
|
};
|
|
|
|
|
// Warnings may hint at unexpected / non-spec API usage
|
|
|
|
|
if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
|
|
|
|
|
{
|
|
|
|
|
prefix += "WARNING:";
|
|
|
|
|
};
|
|
|
|
|
// May indicate sub-optimal usage of the API
|
|
|
|
|
if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
|
|
|
|
|
{
|
|
|
|
|
prefix += "PERFORMANCE:";
|
|
|
|
|
};
|
|
|
|
|
// Informal messages that may become handy during debugging
|
|
|
|
|
if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)
|
|
|
|
|
{
|
|
|
|
|
prefix += "INFO:";
|
|
|
|
|
}
|
|
|
|
|
// Diagnostic info from the Vulkan loader and layers
|
|
|
|
|
// Usually not helpful in terms of API usage, but may help to debug layer and loader problems
|
|
|
|
|
if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT)
|
|
|
|
|
{
|
|
|
|
|
prefix += "DEBUG:";
|
|
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2017-03-12 17:46:50 +01:00
|
|
|
// Display message to default output (console/logcat)
|
|
|
|
|
std::stringstream debugMessage;
|
|
|
|
|
debugMessage << prefix << " [" << pLayerPrefix << "] Code " << msgCode << " : " << pMsg;
|
|
|
|
|
|
2017-03-13 19:24:07 +01:00
|
|
|
#if defined(__ANDROID__)
|
2017-03-12 17:46:50 +01:00
|
|
|
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
|
|
|
|
|
LOGE("%s", debugMessage.str().c_str());
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
LOGD("%s", debugMessage.str().c_str());
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
|
|
|
|
|
std::cerr << debugMessage.str() << "\n";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
std::cout << debugMessage.str() << "\n";
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2017-02-12 11:33:04 +01:00
|
|
|
fflush(stdout);
|
2016-02-16 15:07:25 +01:00
|
|
|
|
2017-02-12 11:33:04 +01:00
|
|
|
// The return value of this callback controls wether the Vulkan call that caused
|
|
|
|
|
// the validation message will be aborted or not
|
|
|
|
|
// We return VK_FALSE as we DON'T want Vulkan calls that cause a validation message
|
|
|
|
|
// (and return a VkResult) to abort
|
|
|
|
|
// If you instead want to have calls abort, pass in VK_TRUE and the function will
|
|
|
|
|
// return VK_ERROR_VALIDATION_FAILED_EXT
|
|
|
|
|
return VK_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setupDebugging(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportCallbackEXT callBack)
|
2016-02-16 15:07:25 +01:00
|
|
|
{
|
2017-02-12 11:33:04 +01:00
|
|
|
CreateDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
|
|
|
|
|
DestroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
|
|
|
|
|
dbgBreakCallback = reinterpret_cast<PFN_vkDebugReportMessageEXT>(vkGetInstanceProcAddr(instance, "vkDebugReportMessageEXT"));
|
|
|
|
|
|
|
|
|
|
VkDebugReportCallbackCreateInfoEXT dbgCreateInfo = {};
|
|
|
|
|
dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
|
|
|
|
|
dbgCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)messageCallback;
|
|
|
|
|
dbgCreateInfo.flags = flags;
|
|
|
|
|
|
|
|
|
|
VkResult err = CreateDebugReportCallback(
|
|
|
|
|
instance,
|
|
|
|
|
&dbgCreateInfo,
|
|
|
|
|
nullptr,
|
|
|
|
|
(callBack != VK_NULL_HANDLE) ? &callBack : &msgCallback);
|
|
|
|
|
assert(!err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void freeDebugCallback(VkInstance instance)
|
|
|
|
|
{
|
|
|
|
|
if (msgCallback != VK_NULL_HANDLE)
|
|
|
|
|
{
|
|
|
|
|
DestroyDebugReportCallback(instance, msgCallback, nullptr);
|
|
|
|
|
}
|
2016-02-16 15:07:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-07 14:05:56 +02:00
|
|
|
|
2017-02-12 11:33:04 +01:00
|
|
|
namespace debugmarker
|
2016-05-07 14:05:56 +02:00
|
|
|
{
|
2016-05-28 12:00:43 +02:00
|
|
|
bool active = false;
|
2016-05-07 14:05:56 +02:00
|
|
|
|
2016-05-28 12:00:43 +02:00
|
|
|
PFN_vkDebugMarkerSetObjectTagEXT pfnDebugMarkerSetObjectTag = VK_NULL_HANDLE;
|
|
|
|
|
PFN_vkDebugMarkerSetObjectNameEXT pfnDebugMarkerSetObjectName = VK_NULL_HANDLE;
|
|
|
|
|
PFN_vkCmdDebugMarkerBeginEXT pfnCmdDebugMarkerBegin = VK_NULL_HANDLE;
|
|
|
|
|
PFN_vkCmdDebugMarkerEndEXT pfnCmdDebugMarkerEnd = VK_NULL_HANDLE;
|
|
|
|
|
PFN_vkCmdDebugMarkerInsertEXT pfnCmdDebugMarkerInsert = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
|
|
void setup(VkDevice device)
|
2016-05-07 14:05:56 +02:00
|
|
|
{
|
2016-08-02 20:41:16 +02:00
|
|
|
pfnDebugMarkerSetObjectTag = reinterpret_cast<PFN_vkDebugMarkerSetObjectTagEXT>(vkGetDeviceProcAddr(device, "vkDebugMarkerSetObjectTagEXT"));
|
|
|
|
|
pfnDebugMarkerSetObjectName = reinterpret_cast<PFN_vkDebugMarkerSetObjectNameEXT>(vkGetDeviceProcAddr(device, "vkDebugMarkerSetObjectNameEXT"));
|
|
|
|
|
pfnCmdDebugMarkerBegin = reinterpret_cast<PFN_vkCmdDebugMarkerBeginEXT>(vkGetDeviceProcAddr(device, "vkCmdDebugMarkerBeginEXT"));
|
|
|
|
|
pfnCmdDebugMarkerEnd = reinterpret_cast<PFN_vkCmdDebugMarkerEndEXT>(vkGetDeviceProcAddr(device, "vkCmdDebugMarkerEndEXT"));
|
|
|
|
|
pfnCmdDebugMarkerInsert = reinterpret_cast<PFN_vkCmdDebugMarkerInsertEXT>(vkGetDeviceProcAddr(device, "vkCmdDebugMarkerInsertEXT"));
|
2016-05-28 12:00:43 +02:00
|
|
|
|
|
|
|
|
// Set flag if at least one function pointer is present
|
|
|
|
|
active = (pfnDebugMarkerSetObjectName != VK_NULL_HANDLE);
|
2016-05-07 14:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-22 20:29:03 +02:00
|
|
|
void setObjectName(VkDevice device, uint64_t object, VkDebugReportObjectTypeEXT objectType, const char *name)
|
2016-05-07 14:05:56 +02:00
|
|
|
{
|
2016-05-28 12:00:43 +02:00
|
|
|
// Check for valid function pointer (may not be present if not running in a debugging application)
|
|
|
|
|
if (pfnDebugMarkerSetObjectName)
|
2016-05-22 20:29:03 +02:00
|
|
|
{
|
|
|
|
|
VkDebugMarkerObjectNameInfoEXT nameInfo = {};
|
|
|
|
|
nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT;
|
|
|
|
|
nameInfo.objectType = objectType;
|
|
|
|
|
nameInfo.object = object;
|
|
|
|
|
nameInfo.pObjectName = name;
|
2016-05-28 12:00:43 +02:00
|
|
|
pfnDebugMarkerSetObjectName(device, &nameInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setObjectTag(VkDevice device, uint64_t object, VkDebugReportObjectTypeEXT objectType, uint64_t name, size_t tagSize, const void* tag)
|
|
|
|
|
{
|
|
|
|
|
// Check for valid function pointer (may not be present if not running in a debugging application)
|
|
|
|
|
if (pfnDebugMarkerSetObjectTag)
|
|
|
|
|
{
|
|
|
|
|
VkDebugMarkerObjectTagInfoEXT tagInfo = {};
|
|
|
|
|
tagInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT;
|
|
|
|
|
tagInfo.objectType = objectType;
|
|
|
|
|
tagInfo.object = object;
|
|
|
|
|
tagInfo.tagName = name;
|
|
|
|
|
tagInfo.tagSize = tagSize;
|
|
|
|
|
tagInfo.pTag = tag;
|
|
|
|
|
pfnDebugMarkerSetObjectTag(device, &tagInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void beginRegion(VkCommandBuffer cmdbuffer, const char* pMarkerName, glm::vec4 color)
|
|
|
|
|
{
|
|
|
|
|
// Check for valid function pointer (may not be present if not running in a debugging application)
|
|
|
|
|
if (pfnCmdDebugMarkerBegin)
|
|
|
|
|
{
|
|
|
|
|
VkDebugMarkerMarkerInfoEXT markerInfo = {};
|
|
|
|
|
markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
|
|
|
|
|
memcpy(markerInfo.color, &color[0], sizeof(float) * 4);
|
|
|
|
|
markerInfo.pMarkerName = pMarkerName;
|
|
|
|
|
pfnCmdDebugMarkerBegin(cmdbuffer, &markerInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void insert(VkCommandBuffer cmdbuffer, std::string markerName, glm::vec4 color)
|
|
|
|
|
{
|
|
|
|
|
// Check for valid function pointer (may not be present if not running in a debugging application)
|
|
|
|
|
if (pfnCmdDebugMarkerInsert)
|
|
|
|
|
{
|
|
|
|
|
VkDebugMarkerMarkerInfoEXT markerInfo = {};
|
|
|
|
|
markerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
|
|
|
|
|
memcpy(markerInfo.color, &color[0], sizeof(float) * 4);
|
|
|
|
|
markerInfo.pMarkerName = markerName.c_str();
|
|
|
|
|
pfnCmdDebugMarkerInsert(cmdbuffer, &markerInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void endRegion(VkCommandBuffer cmdBuffer)
|
|
|
|
|
{
|
|
|
|
|
// Check for valid function (may not be present if not runnin in a debugging application)
|
|
|
|
|
if (pfnCmdDebugMarkerEnd)
|
|
|
|
|
{
|
|
|
|
|
pfnCmdDebugMarkerEnd(cmdBuffer);
|
2016-05-22 20:29:03 +02:00
|
|
|
}
|
2016-05-07 14:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-22 20:29:03 +02:00
|
|
|
void setCommandBufferName(VkDevice device, VkCommandBuffer cmdBuffer, const char * name)
|
2016-05-07 14:05:56 +02:00
|
|
|
{
|
2016-05-22 20:29:03 +02:00
|
|
|
setObjectName(device, (uint64_t)cmdBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, name);
|
2016-05-07 14:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-22 20:29:03 +02:00
|
|
|
void setQueueName(VkDevice device, VkQueue queue, const char * name)
|
2016-05-07 14:05:56 +02:00
|
|
|
{
|
2016-05-22 20:29:03 +02:00
|
|
|
setObjectName(device, (uint64_t)queue, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, name);
|
2016-05-07 14:05:56 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-22 20:29:03 +02:00
|
|
|
void setImageName(VkDevice device, VkImage image, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, name);
|
|
|
|
|
}
|
2016-05-07 14:05:56 +02:00
|
|
|
|
2016-05-22 20:29:03 +02:00
|
|
|
void setSamplerName(VkDevice device, VkSampler sampler, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)sampler, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setBufferName(VkDevice device, VkBuffer buffer, const char * name)
|
2016-05-07 14:05:56 +02:00
|
|
|
{
|
2016-05-22 20:29:03 +02:00
|
|
|
setObjectName(device, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setDeviceMemoryName(VkDevice device, VkDeviceMemory memory, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)memory, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setShaderModuleName(VkDevice device, VkShaderModule shaderModule, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)shaderModule, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setPipelineName(VkDevice device, VkPipeline pipeline, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)pipeline, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setPipelineLayoutName(VkDevice device, VkPipelineLayout pipelineLayout, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)pipelineLayout, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setRenderPassName(VkDevice device, VkRenderPass renderPass, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)renderPass, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setFramebufferName(VkDevice device, VkFramebuffer framebuffer, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)framebuffer, VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setDescriptorSetLayoutName(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)descriptorSetLayout, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setDescriptorSetName(VkDevice device, VkDescriptorSet descriptorSet, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)descriptorSet, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setSemaphoreName(VkDevice device, VkSemaphore semaphore, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)semaphore, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setFenceName(VkDevice device, VkFence fence, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)fence, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setEventName(VkDevice device, VkEvent _event, const char * name)
|
|
|
|
|
{
|
|
|
|
|
setObjectName(device, (uint64_t)_event, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT, name);
|
|
|
|
|
}
|
2016-05-28 12:00:43 +02:00
|
|
|
};
|
2016-05-22 20:29:03 +02:00
|
|
|
}
|
|
|
|
|
|