<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Aug 24, 2017 at 9:52 PM, Tapani Pälli <span dir="ltr"><<a href="mailto:tapani.palli@intel.com" target="_blank">tapani.palli@intel.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi;<br>
<br>
On 08/24/2017 08:36 PM, Jason Ekstrand wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
On Wed, Aug 23, 2017 at 11:23 PM, Tapani Pälli <<a href="mailto:tapani.palli@intel.com" target="_blank">tapani.palli@intel.com</a> <mailto:<a href="mailto:tapani.palli@intel.com" target="_blank">tapani.palli@intel.com</a><wbr>>> wrote:<br>
<br>
    Patch adds required functionality for extension to manage a list of<br>
    application provided callbacks and handle debug reporting from driver<br>
    and application side.<br>
<br>
    Signed-off-by: Tapani Pälli <<a href="mailto:tapani.palli@intel.com" target="_blank">tapani.palli@intel.com</a><br></span>
    <mailto:<a href="mailto:tapani.palli@intel.com" target="_blank">tapani.palli@intel.com</a><wbr>>><div><div class="h5"><br>
    ---<br>
      src/intel/Makefile.sources          |   1 +<br>
      src/intel/vulkan/anv_debug_rep<wbr>ort.c | 133<br>
    ++++++++++++++++++++++++++++++<wbr>++++++<br>
      src/intel/vulkan/anv_device.c       |  40 +++++++++++<br>
      src/intel/vulkan/anv_extension<wbr>s.py  |   1 +<br>
      src/intel/vulkan/anv_private.<wbr>h      |  32 +++++++++<br>
      5 files changed, 207 insertions(+)<br>
      create mode 100644 src/intel/vulkan/anv_debug_rep<wbr>ort.c<br>
<br>
    diff --git a/src/intel/Makefile.sources b/src/intel/Makefile.sources<br>
    index 4074ba9ee5..200713b06e 100644<br>
    --- a/src/intel/Makefile.sources<br>
    +++ b/src/intel/Makefile.sources<br>
    @@ -205,6 +205,7 @@ VULKAN_FILES := \<br>
             vulkan/anv_batch_chain.c \<br>
             vulkan/anv_blorp.c \<br>
             vulkan/anv_cmd_buffer.c \<br>
    +       vulkan/anv_debug_report.c \<br>
             vulkan/anv_descriptor_set.c \<br>
             vulkan/anv_device.c \<br>
             vulkan/anv_dump.c \<br>
    diff --git a/src/intel/vulkan/anv_debug_r<wbr>eport.c<br>
    b/src/intel/vulkan/anv_debug_r<wbr>eport.c<br>
    new file mode 100644<br>
    index 0000000000..1a4868cd52<br>
    --- /dev/null<br>
    +++ b/src/intel/vulkan/anv_debug_r<wbr>eport.c<br>
    @@ -0,0 +1,133 @@<br>
    +/*<br>
    + * Copyright © 2017 Intel Corporation<br>
    + *<br>
    + * Permission is hereby granted, free of charge, to any person<br>
    obtaining a<br>
    + * copy of this software and associated documentation files (the<br>
    "Software"),<br>
    + * to deal in the Software without restriction, including without<br>
    limitation<br>
    + * the rights to use, copy, modify, merge, publish, distribute,<br>
    sublicense,<br>
    + * and/or sell copies of the Software, and to permit persons to<br>
    whom the<br>
    + * Software is furnished to do so, subject to the following conditions:<br>
    + *<br>
    + * The above copyright notice and this permission notice (including<br>
    the next<br>
    + * paragraph) shall be included in all copies or substantial<br>
    portions of the<br>
    + * Software.<br>
    + *<br>
    + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,<br>
    EXPRESS OR<br>
    + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF<br>
    MERCHANTABILITY,<br>
    + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO<br>
    EVENT SHALL<br>
    + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,<br>
    DAMAGES OR OTHER<br>
    + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>
    ARISING<br>
    + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR<br>
    OTHER DEALINGS<br>
    + * IN THE SOFTWARE.<br>
    + */<br>
    +<br>
    +#include "anv_private.h"<br>
    +#include "vk_util.h"<br>
    +<br>
    +/* This file contains implementation for VK_EXT_debug_report. */<br>
    +<br>
    +VkResult<br>
    +anv_CreateDebugReportCallback<wbr>EXT(VkInstance _instance,<br>
    +                                 const<br>
    VkDebugReportCallbackCreateInf<wbr>oEXT* pCreateInfo,<br>
    +                                 const VkAllocationCallbacks*<br>
    pAllocator,<br>
    +                                 VkDebugReportCallbackEXT* pCallback)<br>
    +{<br>
    +   ANV_FROM_HANDLE(anv_instance, instance, _instance);<br>
    +   const VkAllocationCallbacks *alloc =<br>
    +      pAllocator ? pAllocator : &instance->alloc;<br>
<br>
<br>
This is what vk_alloc2 is for.<br>
</div></div></blockquote>
<br>
Thanks, I had a feeling that there might be a helper for this but did not figure it out.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    +<br>
    +   vk_foreach_struct(info, pCreateInfo) {<br>
<br>
<br>
Usually, we handle the primary structure directly and then call vk_foreach_struct on pCreateInfo->pNext.  This is because the things in the pNext chain are going to be modifiers to the original thing so they probably need to happen between allocating the callback and list_addtail().<br>
</blockquote>
<br></span>
Right, this would be for extending the functionality. I wrote it like this because it seems for me that the typical pattern would be to chain few report callbacks and send them all at once rather than calling the function n times. I'll change so that I handle first item out of the loop.<span class=""><br></span></blockquote><div><br></div><div>Is that allowed??? That would be weird but it honestly wouldn't surprise me that much for this extension.  Normally, you don't chain multiple of the same struct together.  You chain extension structs on to modify the original struct.  If inserting multiple callbacks at one go this way is allowed, then we should probably do it the way you did it.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    +      switch (info->sType) {<br>
    +      case VK_STRUCTURE_TYPE_DEBUG_REPORT<wbr>_CALLBACK_CREATE_INFO_EXT: {<br>
    +         struct anv_debug_callback *cb =<br>
    +            vk_alloc(alloc, sizeof(struct anv_debug_callback), 8,<br>
    +                     VK_SYSTEM_ALLOCATION_SCOPE_IN<wbr>STANCE);<br>
    +         if (!cb)<br>
    +            return vk_error(VK_ERROR_OUT_OF_HOST_<wbr>MEMORY);<br>
    +<br>
    +         cb->flags = pCreateInfo->flags;<br>
    +         cb->callback = pCreateInfo->pfnCallback;<br>
    +         cb->data = pCreateInfo->pUserData;<br>
    +<br>
    +         list_addtail(&cb->link, &instance->callbacks);<br>
<br>
<br>
What kind of threading guarantees does debug_report provide?  I'm guessing none in which case we need to lock around this list.<br>
</blockquote>
<br></span>
True, this is something I completely forgot. Will add locking.<div><div class="h5"><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    +         break;<br>
    +      }<br>
    +      default:<br>
    +         anv_debug_ignored_stype(info-<wbr>>sType);<br>
    +         break;<br>
    +      }<br>
    +   }<br>
    +<br>
    +   return VK_SUCCESS;<br>
    +}<br>
    +<br>
    +void<br>
    +anv_DestroyDebugReportCallbac<wbr>kEXT(VkInstance _instance,<br>
    +                                  VkDebugReportCallbackEXT callback,<br>
    +                                  const VkAllocationCallbacks*<br>
    pAllocator)<br>
    +{<br>
    +   ANV_FROM_HANDLE(anv_instance, instance, _instance);<br>
    +   const VkAllocationCallbacks *alloc =<br>
    +      pAllocator ? pAllocator : &instance->alloc;<br>
    +<br>
    +   list_for_each_entry_safe(stru<wbr>ct anv_debug_callback, debug_cb,<br>
    +                            &instance->callbacks, link) {<br>
    +      /* Found a match, remove from list and destroy given callback. */<br>
    +      if ((VkDebugReportCallbackEXT)deb<wbr>ug_cb->callback == callback) {<br>
    +         list_del(&debug_cb->link);<br>
<br>
<br>
lock<br>
<br>
    +         vk_free(alloc, debug_cb);<br>
    +      }<br>
    +   }<br>
    +}<br>
    +<br>
    +void<br>
    +anv_DebugReportMessageEXT(VkI<wbr>nstance _instance,<br>
    +                          VkDebugReportFlagsEXT flags,<br>
    +                          VkDebugReportObjectTypeEXT objectType,<br>
    +                          uint64_t object,<br>
    +                          size_t location,<br>
    +                          int32_t messageCode,<br>
    +                          const char* pLayerPrefix,<br>
    +                          const char* pMessage)<br>
<br>
<br>
Woah... This is a bit unexpected.  I wonder why this entrypoint even exists.  One would think that the loader could just do the aggrigation without it.<br>
</blockquote>
<br></div></div>
Yep, I was wondering about this one as well.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    +{<br>
    +   ANV_FROM_HANDLE(anv_instance, instance, _instance);<br>
    +   anv_debug_report(instance, flags, objectType, object,<br>
    +                    location, messageCode, pLayerPrefix, pMessage);<br>
    +<br>
    +}<br>
    +<br>
    +void<br>
    +anv_debug_report_call(struct anv_debug_callback *cb,<br>
    +                      VkDebugReportFlagsEXT flags,<br>
    +                      VkDebugReportObjectTypeEXT object_type,<br>
    +                      uint64_t handle,<br>
    +                      size_t location,<br>
    +                      int32_t messageCode,<br>
    +                      const char* pLayerPrefix,<br>
    +                      const char *pMessage)<br>
<br>
<br>
Why is this broken out into a helper?  There's nothing strictly wrong with doing so but it seems kind-of pointless to me.<br>
</blockquote>
<br></span>
Yes, does not make sense. I went this way because I wanted instance ctor/dtor to call same functionality as anv_debug_report in case there will be something more that the call itself ... but now that it's just 2 lines .. I'll remove it.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
    +{<br>
    +   cb->callback(flags, object_type, handle, location, messageCode,<br>
    +                pLayerPrefix, pMessage, cb->data);<br>
    +}<br>
    +<br>
    +void<br>
    +anv_debug_report(struct anv_instance *instance,<br>
    +                 VkDebugReportFlagsEXT flags,<br>
    +                 VkDebugReportObjectTypeEXT object_type,<br>
    +                 uint64_t handle,<br>
    +                 size_t location,<br>
    +                 int32_t messageCode,<br>
    +                 const char* pLayerPrefix,<br>
    +                 const char *pMessage)<br>
    +{<br>
    +   /* Allow passing NULL for now. */<br>
    +   if (!instance)<br>
    +      return;<br>
    +<br>
    +   list_for_each_entry_safe(stru<wbr>ct anv_debug_callback, cb,<br>
    +                            &instance->callbacks, link) {<br>
<br>
<br>
Why is are you using for_each_entry_safe?  You're not deleting anything.  I suppose it is possible that one of the callbacks could respond by deleting itself but that seems weird.  If that's legal then we have a bunch of other weird things to consider.<br>
</blockquote>
<br></span>
Because I copy-pasted the line from anv_DestroyDebugReportCallback<wbr>EXT at some point :) Will change to be unsafe version. Spec prohibits calling destroy from callback, section for vkDestroyDebugReportCallbackEX<wbr>T says:<br>
<br>
"callback is an externally synchronized object and must not be used on more than one thread at a time. This means that vkDestroyDebugReportCallbackEX<wbr>T must not be called when a callback is active."<br>
</blockquote><div><br></div><div>Please put that spec quote as a comment above the list walk.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Also, I think we need to lock around walking this list.  Just to keep things efficient, we probably want to do an "if (list_empty(&instance->callbac<wbr>ks)) return" before taking the lock.  It's safe to check list_empty outside the lock because it's just one pointer compare.  The worst that happens is list_empty returns false and then we go, lock, and walk the list.<br>
<br>
    +      if (cb->flags & flags)<br>
    +         anv_debug_report_call(cb, flags, object_type, handle,<br>
    +                               location, messageCode, pLayerPrefix,<br>
    pMessage);<br>
    +   }<br>
    +}<br>
    diff --git a/src/intel/vulkan/anv_device.<wbr>c<br>
    b/src/intel/vulkan/anv_device.<wbr>c<br>
    index a6d5215ab8..01e1869720 100644<br>
    --- a/src/intel/vulkan/anv_device.<wbr>c<br>
    +++ b/src/intel/vulkan/anv_device.<wbr>c<br>
    @@ -441,9 +441,32 @@ VkResult anv_CreateInstance(<br>
          VkInstance*                                 pInstance)<br>
      {<br>
         struct anv_instance *instance;<br>
    +   struct anv_debug_callback ctor_cb = { 0 };<br>
<br>
         assert(pCreateInfo->sType ==<br>
    VK_STRUCTURE_TYPE_INSTANCE_CRE<wbr>ATE_INFO);<br>
<br>
    +   /* Check if user passed a debug report callback to be used during<br>
    +    * Create/Destroy of instance.<br>
    +    */<br>
    +   vk_foreach_struct(ext, pCreateInfo->pNext) {<br>
    +      switch (ext->sType) {<br>
    +      case VK_STRUCTURE_TYPE_DEBUG_REPORT<wbr>_CALLBACK_CREATE_INFO_EXT: {<br>
    +         <wbr>VkDebugReportCallbackCreateInf<wbr>oEXT *cb =<br>
    +            (VkDebugReportCallbackCreateIn<wbr>foEXT *) ext;<br>
    +         ctor_cb.flags = cb->flags;<br>
    +         ctor_cb.callback = cb->pfnCallback;<br>
    +         ctor_cb.data = cb->pUserData;<br>
<br>
<br>
Would it be worth adding this to the list and them removing it later?  I don't know if that would actually simplify things or not.<br>
</blockquote>
<br></div></div>
I thought about it but it seems more complex as then one would need to special case this one callback when calling and know that we are inside instance ctor/dtor.<span class=""><br></span></blockquote><div><br></div><div>Fair enough.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Also, have you written any tests for debug_report?  Really, the only thing we can test it for is "did it crash?" but it's probably worth adding some debug_report stuff to crucible for that purpose.<br>
</blockquote>
<br></span>
I have own test application that creates/destroys callbacks and then I've modified Mesa to report extra errors and perf warnings here and there to see that functionality works. Writing a crucible test makes sense, I'll do that.<span class="HOEnZb"><font color="#888888"><br></font></span></blockquote><div><br></div><div>I think it makes sense to just tie it in at a fairly high level in crucible like we do for pAllocator.  Crucible provides a pAllocator at the instance level that memsets everything to 139 to help test for undefined values.  We can do something similar where crucible plugs in a debug report callback and ties it into crucible's logging infastructure.  Shouldn't be too hard.</div><div><br></div><div>--Jason<br></div></div><br></div></div>