Vulkan 1.0 - EXT_debug_report

The Khronos Vulkan Working Group

Based off version 1.0.18 of the Vulkan Spec, Tue Jul 19 16:32:53
from git branch: 1.0-VK_EXT_debug_report commit: a9611a4809a2f859b31620c4109b9e37181870de



Copyright © 2014-2016 The Khronos Group Inc. All Rights Reserved.

This specification is protected by copyright laws and contains material proprietary to the Khronos Group, Inc. It or any components may not be reproduced, republished, distributed, transmitted, displayed, broadcast or otherwise exploited in any manner without the express prior written permission of Khronos Group. You may use this specification for implementing the functionality therein, without altering or removing any trademark, copyright or other notice from the specification, but the receipt or possession of this specification does not convey any rights to reproduce, disclose, or distribute its contents, or to manufacture, use, or sell anything that it may describe, in whole or in part.

Khronos Group grants express permission to any current Promoter, Contributor or Adopter member of Khronos to copy and redistribute UNMODIFIED versions of this specification in any fashion, provided that NO CHARGE is made for the specification and the latest available update of the specification for any version of the API is used whenever possible. Such distributed specification may be reformatted AS LONG AS the contents of the specification are not changed in any way. The specification may be incorporated into a product that is sold as long as such product includes significant independent work developed by the seller. A link to the current version of this specification on the Khronos Group web-site should be included whenever possible with specification distributions.

This specification has been created under the Khronos Intellectual Property Rights Policy, which is Attachment A of the Khronos Group Membership Agreement available at www.khronos.org/files/member_agreement.pdf. This specification contains substantially unmodified functionality from, and is a successor to, Khronos specifications including OpenGL, OpenGL ES and OpenCL.

Some parts of this Specification are purely informative and do not define requirements necessary for compliance and so are outside the Scope of this Specification. These parts of the Specification are marked by the “Note” icon or designated “Informative”.

Where this Specification uses terms, defined in the Glossary or otherwise, that refer to enabling technologies that are not expressly set forth as being required for compliance, those enabling technologies are outside the Scope of this Specification.

Where this Specification uses the terms “may”, or “optional”, such features or behaviors do not define requirements necessary for compliance and so are outside the Scope of this Specification.

Where this Specification uses the terms “not required”, such features or behaviors may be omitted from certain implementations, but when they are included, they define requirements necessary for compliance and so are INCLUDED in the Scope of this Specification.

Where this Specification includes normative references to external documents, the specifically identified sections and functionality of those external documents are in Scope. Requirements defined by external documents not created by Khronos may contain contributions from non-members of Khronos not covered by the Khronos Intellectual Property Rights Policy.

Khronos Group makes no, and expressly disclaims any, representations or warranties, express or implied, regarding this specification, including, without limitation, any implied warranties of merchantability or fitness for a particular purpose or non-infringement of any intellectual property. Khronos Group makes no, and expressly disclaims any, warranties, express or implied, regarding the correctness, accuracy, completeness, timeliness, and reliability of the specification. Under no circumstances will the Khronos Group, or any of its Promoters, Contributors or Members or their respective partners, officers, directors, employees, agents or representatives be liable for any damages, whether direct, indirect, special or consequential damages for lost revenues, lost profits, or otherwise, arising from or in connection with these materials.

Khronos and Vulkan are trademarks of The Khronos Group Inc. OpenCL is a trademark of Apple Inc. and OpenGL is a registered trademark of Silicon Graphics International, both used under license by Khronos.

Debug Report Extension

Due to the nature of the Vulkan interface, there is very little error information available to the developer/application. By enabling optional validation layers and using the Debug Report extension a developer has much more detailed feedback on the application’s use of Vulkan.

This extension adds two entrypoints (vkCreateDebugReportCallbackEXT, vkDestroyDebugReportCallbackEXT) and an extension structure that together define a way for layers and the implementation to call back to the application for events of interest to the application. An application enables this extension by including “VK_EXT_debug_report” in the list of ppEnabledExtensionNames at vkCreateInstance. Layers indicating support will return VK_EXT_debug_report in the extension list queried via vkEnumerateInstanceExtensionProperties.

To register a callback, an application uses vkCreateDebugReportCallbackEXT.

 

VkResult vkCreateDebugReportCallbackEXT(
    VkInstance                                  instance,
    const VkDebugReportCallbackCreateInfoEXT*   pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
    VkDebugReportCallbackEXT*                   pCallback);

  • instance the instance the callback will be logged on.
  • pCreateInfo points to a VkDebugReportCallbackCreateInfoEXT structure which defines the conditions under which this callback will be called.
  • pCallback is a pointer to record the VkDebugReportCallbackEXT object created.

The definition of VkDebugReportCallbackCreateInfoEXT is:

 

typedef struct VkDebugReportCallbackCreateInfoEXT {
    VkStructureType                 sType;
    const void*                     pNext;
    VkDebugReportFlagsEXT           flags;
    PFN_vkDebugReportCallbackEXT    pfnCallback;
    void*                           pUserData;
} VkDebugReportCallbackCreateInfoEXT;

  • sType is the type of this structure.
  • pNext is NULL or a pointer to an extension-specific structure.
  • flags indicate which event(s) will cause this callback to be called. Flags are interpreted as bit fields and multiple may be set.

The definition of VkDebugReportFlagBitsEXT is:

 

typedef enum VkDebugReportFlagBitsEXT {
    VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,
    VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002,
    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004,
    VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,
    VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
} VkDebugReportFlagBitsEXT;

  • VK_DEBUG_REPORT_ERROR_BIT_EXT indicates an error that may cause undefined results, including an application crash.
  • VK_DEBUG_REPORT_WARNING_BIT_EXT indicates an unexpected use. E.g. Not destroying objects prior to destroying the containing object or potential inconsistencies between descriptor set layout and the layout in the corresponding shader, etc.
  • VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT indicates a potentially non-optimal use of Vulkan. E.g. using vkCmdClearImage when a RenderPass load_op would have worked.
  • VK_DEBUG_REPORT_INFORMATION_BIT_EXT indicates an informational message such as resource details that may be handy when debugging an application.
  • VK_DEBUG_REPORT_DEBUG_BIT_EXT indicates diagnostic information from the loader and layers.
  • pfnCallback the application callback function to call.
  • pUserData User data to be passed to the callback.

For each VkDebugReportCallbackEXT that is created the flags determine when that function is called. A callback will be made for issues that match any bit set in its flags. The callback will come directly from the component that detected the event, unless some other layer intercepts the calls for its own purposes (filter them in different way, log to system error log, etc.) An application may receive multiple callbacks if multiple VkDebugReportCallbackEXT objects were created. A callback will always be executed in the same thread as the originating Vulkan call. A callback may be called from multiple threads simultaneously (if the application is making Vulkan calls from multiple threads).

The prototype for the callback function implemented by the app is:

 

typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)(
    VkDebugReportFlagsEXT                       flags,
    VkDebugReportObjectTypeEXT                  objectType,
    uint64_t                                    object,
    size_t                                      location,
    int32_t                                     messageCode,
    const char*                                 pLayerPrefix,
    const char*                                 pMessage,
    void*                                       pUserData);

  • flags indicates the VkDebugReportFlagBitsEXT that triggered this callback.
  • objType the type of object being used / created at the time the event was triggered. Object types are defined by VkDebugReportObjectTypeEXT.
  • object gives the object where the issue was detected. object may be VK_NULL_OBJECT if there is no object associated with the event.
  • location is a component (layer, driver, loader) defined value that indicates the "location" of the trigger. This is an optional value.
  • messageCode a layer defined value indicating what test triggered this callback.
  • pLayerPrefix abbreviation of the component making the callback.
  • pMessage a null terminated string detailing the trigger conditions.
  • pUserData the user data given when the DebugReportCallback was created.

The callback returns a VkBool32 that indicates to the calling layer if the Vulkan call should be aborted or not. Applications should always return VK_FALSE so that they see the same behavior with and without validation layers enabled.

If the application returns VK_TRUE from it’s callback and the Vulkan call being aborted returns a VkResult, the layer will return VK_ERROR_VALIDATION_FAILED_EXT.

[Note]Note

The primary expected use of VK_ERROR_VALIDATION_FAILED_EXT is for validation layer testing. It’s not expected that an application would see this this error code during normal use of the validation layers.

To inject it’s own messages into the debug stream an application uses vkDebugReportMessageEXT.

 

void vkDebugReportMessageEXT(
    VkInstance                                  instance,
    VkDebugReportFlagsEXT                       flags,
    VkDebugReportObjectTypeEXT                  objectType,
    uint64_t                                    object,
    size_t                                      location,
    int32_t                                     messageCode,
    const char*                                 pLayerPrefix,
    const char*                                 pMessage);

  • instance the instance the callback will be logged on.
  • flags indicates the VkDebugReportFlagBitsEXT that triggered this callback.
  • objType the type of object being used / created at the time the event was triggered. Object types are defined by VkDebugReportObjectTypeEXT.
  • object gives the object where the issue was detected. object may be VK_NULL_OBJECT if there is no object associated with the event.
  • location is a component (layer, driver, loader) defined value that indicates the "location" of the trigger. This is an optional value.
  • messageCode a layer defined value indicating what test triggered this callback.
  • pLayerPrefix abbreviation of the component making the callback.
  • pMessage a null terminated string detailing the trigger conditions.

The call will propagate through the layers and cause a callback to the application. The parameters are passed on to the callback in addition to the pUserData value that was defined at the time the callback was registered.

To destroy a VkDebugReportCallbackEXT object an application calls vkDestroyDebugReportCallbackEXT.

 

void vkDestroyDebugReportCallbackEXT(
    VkInstance                                  instance,
    VkDebugReportCallbackEXT                    callback,
    const VkAllocationCallbacks*                pAllocator);

  • instance the instance where the callback was created.
  • callback the VkDebugReportCallbackEXT object to destroy.

Using the VK_EXT_debug_report allows an application to register multiple callbacks with the validation layers. Some callbacks may log the information to a file, others may cause a debug break point or other application defined behavior. An application can register callbacks even when no validation layers are enabled, but they will only be called for loader and, if implemented, driver events.

To capture issues found while creating or destroying an instance an application can link a VkDebugReportCallbackCreateInfoEXT structure to the pNext element of the VkInstanceCreateInfo structure given to vkCreateInstance. This callback is only valid for the duration of the vkCreateInstance and the vkDestroyInstance call. Use vkCreateDebugReportCallbackEXT to create persistent callback objects.

Example uses: Create three callback objects. One will log errors and warnings to the debug console using Windows OutputDebugString. The second will cause the debugger to break at that callback when an error happens and the third will log warnings to stdout.

    VkResult res;
    VkDebugReportCallbackEXT cb1, cb2, cb3;

    VkDebugReportCallbackCreateInfoEXT callback1 = {
            VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,    // sType
            NULL,                                                       // pNext
            VK_DEBUG_REPORT_ERROR_BIT_EXT |                             // flags
            VK_DEBUG_REPORT_WARNING_BIT_EXT,
            myOutputDebugString,                                        // pfnCallback
            NULL                                                        // pUserData
    };
    res = vkCreateDebugReportCallbackEXT(instance, &callback1, &cb1);
    if (res != VK_SUCCESS)
       /* Do error handling for VK_ERROR_OUT_OF_MEMORY */

    callback.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT;
    callback.pfnCallback = myDebugBreak;
    callback.pUserData = NULL;
    res = vkCreateDebugReportCallbackEXT(instance, &callback, &cb2);
    if (res != VK_SUCCESS)
       /* Do error handling for VK_ERROR_OUT_OF_MEMORY */

    VkDebugReportCallbackCreateInfoEXT callback3 = {
            VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,    // sType
            NULL,                                                       // pNext
            VK_DEBUG_REPORT_WARNING_BIT_EXT,                            // flags
            mystdOutLogger,                                             // pfnCallback
            NULL                                                        // pUserData
    };
    res = vkCreateDebugReportCallbackEXT(instance, &callback3, &cb3);
    if (res != VK_SUCCESS)
       /* Do error handling for VK_ERROR_OUT_OF_MEMORY */

    ...

    /* remove callbacks when cleaning up */
    vkDestroyDebugReportCallbackEXT(instance, cb1);
    vkDestroyDebugReportCallbackEXT(instance, cb2);
    vkDestroyDebugReportCallbackEXT(instance, cb3);