Home | History | Annotate | Download | only in libvulkan
      1 /*
      2  * Copyright 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "driver.h"
     18 
     19 namespace vulkan {
     20 namespace driver {
     21 
     22 DebugReportCallbackList::Node* DebugReportCallbackList::AddCallback(
     23     const VkDebugReportCallbackCreateInfoEXT& info,
     24     VkDebugReportCallbackEXT driver_handle,
     25     const VkAllocationCallbacks& allocator) {
     26     void* mem = allocator.pfnAllocation(allocator.pUserData, sizeof(Node),
     27                                         alignof(Node),
     28                                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
     29     if (!mem)
     30         return nullptr;
     31 
     32     // initialize and prepend node to the list
     33     std::lock_guard<decltype(rwmutex_)> lock(rwmutex_);
     34     head_.next = new (mem) Node{head_.next, info.flags, info.pfnCallback,
     35                                 info.pUserData, driver_handle};
     36 
     37     return head_.next;
     38 }
     39 
     40 void DebugReportCallbackList::RemoveCallback(
     41     Node* node,
     42     const VkAllocationCallbacks& allocator) {
     43     // remove node from the list
     44     {
     45         std::lock_guard<decltype(rwmutex_)> lock(rwmutex_);
     46         Node* prev = &head_;
     47         while (prev && prev->next != node)
     48             prev = prev->next;
     49         if (prev)
     50             prev->next = node->next;
     51     }
     52 
     53     allocator.pfnFree(allocator.pUserData, node);
     54 }
     55 
     56 void DebugReportCallbackList::Message(VkDebugReportFlagsEXT flags,
     57                                       VkDebugReportObjectTypeEXT object_type,
     58                                       uint64_t object,
     59                                       size_t location,
     60                                       int32_t message_code,
     61                                       const char* layer_prefix,
     62                                       const char* message) const {
     63     std::shared_lock<decltype(rwmutex_)> lock(rwmutex_);
     64     const Node* node = &head_;
     65     while ((node = node->next)) {
     66         if ((node->flags & flags) != 0) {
     67             node->callback(flags, object_type, object, location, message_code,
     68                            layer_prefix, message, node->user_data);
     69         }
     70     }
     71 }
     72 
     73 void DebugReportLogger::Message(VkDebugReportFlagsEXT flags,
     74                                 VkDebugReportObjectTypeEXT object_type,
     75                                 uint64_t object,
     76                                 size_t location,
     77                                 int32_t message_code,
     78                                 const char* layer_prefix,
     79                                 const char* message) const {
     80     const VkDebugReportCallbackCreateInfoEXT* info =
     81         reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>(
     82             instance_pnext_);
     83     while (info) {
     84         if (info->sType ==
     85                 VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT &&
     86             (info->flags & flags) != 0) {
     87             info->pfnCallback(flags, object_type, object, location,
     88                               message_code, layer_prefix, message,
     89                               info->pUserData);
     90         }
     91 
     92         info = reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>(
     93             info->pNext);
     94     }
     95 
     96     if (callbacks_) {
     97         callbacks_->Message(flags, object_type, object, location, message_code,
     98                             layer_prefix, message);
     99     }
    100 }
    101 
    102 void DebugReportLogger::PrintV(VkDebugReportFlagsEXT flags,
    103                                VkDebugReportObjectTypeEXT object_type,
    104                                uint64_t object,
    105                                const char* format,
    106                                va_list ap) const {
    107     char buf[1024];
    108     int len = vsnprintf(buf, sizeof(buf), format, ap);
    109 
    110     // message truncated
    111     if (len >= static_cast<int>(sizeof(buf)))
    112         memcpy(buf + sizeof(buf) - 4, "...", 4);
    113 
    114     Message(flags, object_type, object, 0, 0, LOG_TAG, buf);
    115 }
    116 
    117 VkResult CreateDebugReportCallbackEXT(
    118     VkInstance instance,
    119     const VkDebugReportCallbackCreateInfoEXT* create_info,
    120     const VkAllocationCallbacks* allocator,
    121     VkDebugReportCallbackEXT* callback) {
    122     const auto& driver = GetData(instance).driver;
    123     VkDebugReportCallbackEXT driver_handle = VK_NULL_HANDLE;
    124     if (driver.CreateDebugReportCallbackEXT) {
    125         VkResult result = driver.CreateDebugReportCallbackEXT(
    126             instance, create_info, allocator, &driver_handle);
    127         if (result != VK_SUCCESS)
    128             return result;
    129     }
    130 
    131     auto& callbacks = GetData(instance).debug_report_callbacks;
    132     auto node = callbacks.AddCallback(
    133         *create_info, driver_handle,
    134         (allocator) ? *allocator : GetData(instance).allocator);
    135     if (!node) {
    136         if (driver_handle != VK_NULL_HANDLE) {
    137             driver.DestroyDebugReportCallbackEXT(instance, driver_handle,
    138                                                  allocator);
    139         }
    140 
    141         return VK_ERROR_OUT_OF_HOST_MEMORY;
    142     }
    143 
    144     *callback = callbacks.GetHandle(node);
    145 
    146     return VK_SUCCESS;
    147 }
    148 
    149 void DestroyDebugReportCallbackEXT(VkInstance instance,
    150                                    VkDebugReportCallbackEXT callback,
    151                                    const VkAllocationCallbacks* allocator) {
    152     if (callback == VK_NULL_HANDLE)
    153         return;
    154 
    155     auto& callbacks = GetData(instance).debug_report_callbacks;
    156     auto node = callbacks.FromHandle(callback);
    157     auto driver_handle = callbacks.GetDriverHandle(node);
    158 
    159     callbacks.RemoveCallback(
    160         node, (allocator) ? *allocator : GetData(instance).allocator);
    161 
    162     if (driver_handle != VK_NULL_HANDLE) {
    163         GetData(instance).driver.DestroyDebugReportCallbackEXT(
    164             instance, driver_handle, allocator);
    165     }
    166 }
    167 
    168 void DebugReportMessageEXT(VkInstance instance,
    169                            VkDebugReportFlagsEXT flags,
    170                            VkDebugReportObjectTypeEXT object_type,
    171                            uint64_t object,
    172                            size_t location,
    173                            int32_t message_code,
    174                            const char* layer_prefix,
    175                            const char* message) {
    176     if (GetData(instance).driver.DebugReportMessageEXT) {
    177         GetData(instance).driver.DebugReportMessageEXT(
    178             instance, flags, object_type, object, location, message_code,
    179             layer_prefix, message);
    180     } else {
    181         GetData(instance).debug_report_callbacks.Message(
    182             flags, object_type, object, location, message_code, layer_prefix,
    183             message);
    184     }
    185 }
    186 
    187 }  // namespace driver
    188 }  // namespace vulkan
    189