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         prev->next = node->next;
     50     }
     51 
     52     allocator.pfnFree(allocator.pUserData, node);
     53 }
     54 
     55 void DebugReportCallbackList::Message(VkDebugReportFlagsEXT flags,
     56                                       VkDebugReportObjectTypeEXT object_type,
     57                                       uint64_t object,
     58                                       size_t location,
     59                                       int32_t message_code,
     60                                       const char* layer_prefix,
     61                                       const char* message) const {
     62     std::shared_lock<decltype(rwmutex_)> lock(rwmutex_);
     63     const Node* node = &head_;
     64     while ((node = node->next)) {
     65         if ((node->flags & flags) != 0) {
     66             node->callback(flags, object_type, object, location, message_code,
     67                            layer_prefix, message, node->user_data);
     68         }
     69     }
     70 }
     71 
     72 void DebugReportLogger::Message(VkDebugReportFlagsEXT flags,
     73                                 VkDebugReportObjectTypeEXT object_type,
     74                                 uint64_t object,
     75                                 size_t location,
     76                                 int32_t message_code,
     77                                 const char* layer_prefix,
     78                                 const char* message) const {
     79     const VkDebugReportCallbackCreateInfoEXT* info =
     80         reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>(
     81             instance_pnext_);
     82     while (info) {
     83         if (info->sType ==
     84                 VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT &&
     85             (info->flags & flags) != 0) {
     86             info->pfnCallback(flags, object_type, object, location,
     87                               message_code, layer_prefix, message,
     88                               info->pUserData);
     89         }
     90 
     91         info = reinterpret_cast<const VkDebugReportCallbackCreateInfoEXT*>(
     92             info->pNext);
     93     }
     94 
     95     if (callbacks_) {
     96         callbacks_->Message(flags, object_type, object, location, message_code,
     97                             layer_prefix, message);
     98     }
     99 }
    100 
    101 void DebugReportLogger::PrintV(VkDebugReportFlagsEXT flags,
    102                                VkDebugReportObjectTypeEXT object_type,
    103                                uint64_t object,
    104                                const char* format,
    105                                va_list ap) const {
    106     char buf[1024];
    107     int len = vsnprintf(buf, sizeof(buf), format, ap);
    108 
    109     // message truncated
    110     if (len >= static_cast<int>(sizeof(buf)))
    111         memcpy(buf + sizeof(buf) - 4, "...", 4);
    112 
    113     Message(flags, object_type, object, 0, 0, LOG_TAG, buf);
    114 }
    115 
    116 VkResult CreateDebugReportCallbackEXT(
    117     VkInstance instance,
    118     const VkDebugReportCallbackCreateInfoEXT* create_info,
    119     const VkAllocationCallbacks* allocator,
    120     VkDebugReportCallbackEXT* callback) {
    121     const auto& driver = GetData(instance).driver;
    122     VkDebugReportCallbackEXT driver_handle = VK_NULL_HANDLE;
    123     if (driver.CreateDebugReportCallbackEXT) {
    124         VkResult result = driver.CreateDebugReportCallbackEXT(
    125             instance, create_info, allocator, &driver_handle);
    126         if (result != VK_SUCCESS)
    127             return result;
    128     }
    129 
    130     auto& callbacks = GetData(instance).debug_report_callbacks;
    131     auto node = callbacks.AddCallback(
    132         *create_info, driver_handle,
    133         (allocator) ? *allocator : GetData(instance).allocator);
    134     if (!node) {
    135         if (driver_handle != VK_NULL_HANDLE) {
    136             driver.DestroyDebugReportCallbackEXT(instance, driver_handle,
    137                                                  allocator);
    138         }
    139 
    140         return VK_ERROR_OUT_OF_HOST_MEMORY;
    141     }
    142 
    143     *callback = callbacks.GetHandle(node);
    144 
    145     return VK_SUCCESS;
    146 }
    147 
    148 void DestroyDebugReportCallbackEXT(VkInstance instance,
    149                                    VkDebugReportCallbackEXT callback,
    150                                    const VkAllocationCallbacks* allocator) {
    151     if (callback == VK_NULL_HANDLE)
    152         return;
    153 
    154     auto& callbacks = GetData(instance).debug_report_callbacks;
    155     auto node = callbacks.FromHandle(callback);
    156     auto driver_handle = callbacks.GetDriverHandle(node);
    157 
    158     callbacks.RemoveCallback(
    159         node, (allocator) ? *allocator : GetData(instance).allocator);
    160 
    161     if (driver_handle != VK_NULL_HANDLE) {
    162         GetData(instance).driver.DestroyDebugReportCallbackEXT(
    163             instance, driver_handle, allocator);
    164     }
    165 }
    166 
    167 void DebugReportMessageEXT(VkInstance instance,
    168                            VkDebugReportFlagsEXT flags,
    169                            VkDebugReportObjectTypeEXT object_type,
    170                            uint64_t object,
    171                            size_t location,
    172                            int32_t message_code,
    173                            const char* layer_prefix,
    174                            const char* message) {
    175     if (GetData(instance).driver.DebugReportMessageEXT) {
    176         GetData(instance).driver.DebugReportMessageEXT(
    177             instance, flags, object_type, object, location, message_code,
    178             layer_prefix, message);
    179     } else {
    180         GetData(instance).debug_report_callbacks.Message(
    181             flags, object_type, object, location, message_code, layer_prefix,
    182             message);
    183     }
    184 }
    185 
    186 }  // namespace driver
    187 }  // namespace vulkan
    188