Home | History | Annotate | Download | only in loader
      1 /*
      2  *
      3  * Copyright (c) 2015 The Khronos Group Inc.
      4  * Copyright (c) 2015 Valve Corporation
      5  * Copyright (c) 2015 LunarG, Inc.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and/or associated documentation files (the "Materials"), to
      9  * deal in the Materials without restriction, including without limitation the
     10  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
     11  * sell copies of the Materials, and to permit persons to whom the Materials are
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice(s) and this permission notice shall be included in
     15  * all copies or substantial portions of the Materials.
     16  *
     17  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     20  *
     21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
     24  * USE OR OTHER DEALINGS IN THE MATERIALS.
     25  *
     26  * Author: Jon Ashburn <jon (at) lunarg.com>
     27  */
     28 
     29 #include <string.h>
     30 #include "debug_report.h"
     31 #include "wsi.h"
     32 
     33 static inline void *trampolineGetProcAddr(struct loader_instance *inst,
     34                                           const char *funcName) {
     35     // Don't include or check global functions
     36     if (!strcmp(funcName, "vkGetInstanceProcAddr"))
     37         return (PFN_vkVoidFunction)vkGetInstanceProcAddr;
     38     if (!strcmp(funcName, "vkDestroyInstance"))
     39         return (PFN_vkVoidFunction)vkDestroyInstance;
     40     if (!strcmp(funcName, "vkEnumeratePhysicalDevices"))
     41         return (PFN_vkVoidFunction)vkEnumeratePhysicalDevices;
     42     if (!strcmp(funcName, "vkGetPhysicalDeviceFeatures"))
     43         return (PFN_vkVoidFunction)vkGetPhysicalDeviceFeatures;
     44     if (!strcmp(funcName, "vkGetPhysicalDeviceFormatProperties"))
     45         return (PFN_vkVoidFunction)vkGetPhysicalDeviceFormatProperties;
     46     if (!strcmp(funcName, "vkGetPhysicalDeviceImageFormatProperties"))
     47         return (PFN_vkVoidFunction)vkGetPhysicalDeviceImageFormatProperties;
     48     if (!strcmp(funcName, "vkGetPhysicalDeviceSparseImageFormatProperties"))
     49         return (
     50             PFN_vkVoidFunction)vkGetPhysicalDeviceSparseImageFormatProperties;
     51     if (!strcmp(funcName, "vkGetPhysicalDeviceProperties"))
     52         return (PFN_vkVoidFunction)vkGetPhysicalDeviceProperties;
     53     if (!strcmp(funcName, "vkGetPhysicalDeviceQueueFamilyProperties"))
     54         return (PFN_vkVoidFunction)vkGetPhysicalDeviceQueueFamilyProperties;
     55     if (!strcmp(funcName, "vkGetPhysicalDeviceMemoryProperties"))
     56         return (PFN_vkVoidFunction)vkGetPhysicalDeviceMemoryProperties;
     57     if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties"))
     58         return (PFN_vkVoidFunction)vkEnumerateDeviceLayerProperties;
     59     if (!strcmp(funcName, "vkEnumerateDeviceExtensionProperties"))
     60         return (PFN_vkVoidFunction)vkEnumerateDeviceExtensionProperties;
     61     if (!strcmp(funcName, "vkCreateDevice"))
     62         return (PFN_vkVoidFunction)vkCreateDevice;
     63     if (!strcmp(funcName, "vkGetDeviceProcAddr"))
     64         return (PFN_vkVoidFunction)vkGetDeviceProcAddr;
     65     if (!strcmp(funcName, "vkDestroyDevice"))
     66         return (PFN_vkVoidFunction)vkDestroyDevice;
     67     if (!strcmp(funcName, "vkGetDeviceQueue"))
     68         return (PFN_vkVoidFunction)vkGetDeviceQueue;
     69     if (!strcmp(funcName, "vkQueueSubmit"))
     70         return (PFN_vkVoidFunction)vkQueueSubmit;
     71     if (!strcmp(funcName, "vkQueueWaitIdle"))
     72         return (PFN_vkVoidFunction)vkQueueWaitIdle;
     73     if (!strcmp(funcName, "vkDeviceWaitIdle"))
     74         return (PFN_vkVoidFunction)vkDeviceWaitIdle;
     75     if (!strcmp(funcName, "vkAllocateMemory"))
     76         return (PFN_vkVoidFunction)vkAllocateMemory;
     77     if (!strcmp(funcName, "vkFreeMemory"))
     78         return (PFN_vkVoidFunction)vkFreeMemory;
     79     if (!strcmp(funcName, "vkMapMemory"))
     80         return (PFN_vkVoidFunction)vkMapMemory;
     81     if (!strcmp(funcName, "vkUnmapMemory"))
     82         return (PFN_vkVoidFunction)vkUnmapMemory;
     83     if (!strcmp(funcName, "vkFlushMappedMemoryRanges"))
     84         return (PFN_vkVoidFunction)vkFlushMappedMemoryRanges;
     85     if (!strcmp(funcName, "vkInvalidateMappedMemoryRanges"))
     86         return (PFN_vkVoidFunction)vkInvalidateMappedMemoryRanges;
     87     if (!strcmp(funcName, "vkGetDeviceMemoryCommitment"))
     88         return (PFN_vkVoidFunction)vkGetDeviceMemoryCommitment;
     89     if (!strcmp(funcName, "vkGetImageSparseMemoryRequirements"))
     90         return (PFN_vkVoidFunction)vkGetImageSparseMemoryRequirements;
     91     if (!strcmp(funcName, "vkGetImageMemoryRequirements"))
     92         return (PFN_vkVoidFunction)vkGetImageMemoryRequirements;
     93     if (!strcmp(funcName, "vkGetBufferMemoryRequirements"))
     94         return (PFN_vkVoidFunction)vkGetBufferMemoryRequirements;
     95     if (!strcmp(funcName, "vkBindImageMemory"))
     96         return (PFN_vkVoidFunction)vkBindImageMemory;
     97     if (!strcmp(funcName, "vkBindBufferMemory"))
     98         return (PFN_vkVoidFunction)vkBindBufferMemory;
     99     if (!strcmp(funcName, "vkQueueBindSparse"))
    100         return (PFN_vkVoidFunction)vkQueueBindSparse;
    101     if (!strcmp(funcName, "vkCreateFence"))
    102         return (PFN_vkVoidFunction)vkCreateFence;
    103     if (!strcmp(funcName, "vkDestroyFence"))
    104         return (PFN_vkVoidFunction)vkDestroyFence;
    105     if (!strcmp(funcName, "vkGetFenceStatus"))
    106         return (PFN_vkVoidFunction)vkGetFenceStatus;
    107     if (!strcmp(funcName, "vkResetFences"))
    108         return (PFN_vkVoidFunction)vkResetFences;
    109     if (!strcmp(funcName, "vkWaitForFences"))
    110         return (PFN_vkVoidFunction)vkWaitForFences;
    111     if (!strcmp(funcName, "vkCreateSemaphore"))
    112         return (PFN_vkVoidFunction)vkCreateSemaphore;
    113     if (!strcmp(funcName, "vkDestroySemaphore"))
    114         return (PFN_vkVoidFunction)vkDestroySemaphore;
    115     if (!strcmp(funcName, "vkCreateEvent"))
    116         return (PFN_vkVoidFunction)vkCreateEvent;
    117     if (!strcmp(funcName, "vkDestroyEvent"))
    118         return (PFN_vkVoidFunction)vkDestroyEvent;
    119     if (!strcmp(funcName, "vkGetEventStatus"))
    120         return (PFN_vkVoidFunction)vkGetEventStatus;
    121     if (!strcmp(funcName, "vkSetEvent"))
    122         return (PFN_vkVoidFunction)vkSetEvent;
    123     if (!strcmp(funcName, "vkResetEvent"))
    124         return (PFN_vkVoidFunction)vkResetEvent;
    125     if (!strcmp(funcName, "vkCreateQueryPool"))
    126         return (PFN_vkVoidFunction)vkCreateQueryPool;
    127     if (!strcmp(funcName, "vkDestroyQueryPool"))
    128         return (PFN_vkVoidFunction)vkDestroyQueryPool;
    129     if (!strcmp(funcName, "vkGetQueryPoolResults"))
    130         return (PFN_vkVoidFunction)vkGetQueryPoolResults;
    131     if (!strcmp(funcName, "vkCreateBuffer"))
    132         return (PFN_vkVoidFunction)vkCreateBuffer;
    133     if (!strcmp(funcName, "vkDestroyBuffer"))
    134         return (PFN_vkVoidFunction)vkDestroyBuffer;
    135     if (!strcmp(funcName, "vkCreateBufferView"))
    136         return (PFN_vkVoidFunction)vkCreateBufferView;
    137     if (!strcmp(funcName, "vkDestroyBufferView"))
    138         return (PFN_vkVoidFunction)vkDestroyBufferView;
    139     if (!strcmp(funcName, "vkCreateImage"))
    140         return (PFN_vkVoidFunction)vkCreateImage;
    141     if (!strcmp(funcName, "vkDestroyImage"))
    142         return (PFN_vkVoidFunction)vkDestroyImage;
    143     if (!strcmp(funcName, "vkGetImageSubresourceLayout"))
    144         return (PFN_vkVoidFunction)vkGetImageSubresourceLayout;
    145     if (!strcmp(funcName, "vkCreateImageView"))
    146         return (PFN_vkVoidFunction)vkCreateImageView;
    147     if (!strcmp(funcName, "vkDestroyImageView"))
    148         return (PFN_vkVoidFunction)vkDestroyImageView;
    149     if (!strcmp(funcName, "vkCreateShaderModule"))
    150         return (PFN_vkVoidFunction)vkCreateShaderModule;
    151     if (!strcmp(funcName, "vkDestroyShaderModule"))
    152         return (PFN_vkVoidFunction)vkDestroyShaderModule;
    153     if (!strcmp(funcName, "vkCreatePipelineCache"))
    154         return (PFN_vkVoidFunction)vkCreatePipelineCache;
    155     if (!strcmp(funcName, "vkDestroyPipelineCache"))
    156         return (PFN_vkVoidFunction)vkDestroyPipelineCache;
    157     if (!strcmp(funcName, "vkGetPipelineCacheData"))
    158         return (PFN_vkVoidFunction)vkGetPipelineCacheData;
    159     if (!strcmp(funcName, "vkMergePipelineCaches"))
    160         return (PFN_vkVoidFunction)vkMergePipelineCaches;
    161     if (!strcmp(funcName, "vkCreateGraphicsPipelines"))
    162         return (PFN_vkVoidFunction)vkCreateGraphicsPipelines;
    163     if (!strcmp(funcName, "vkCreateComputePipelines"))
    164         return (PFN_vkVoidFunction)vkCreateComputePipelines;
    165     if (!strcmp(funcName, "vkDestroyPipeline"))
    166         return (PFN_vkVoidFunction)vkDestroyPipeline;
    167     if (!strcmp(funcName, "vkCreatePipelineLayout"))
    168         return (PFN_vkVoidFunction)vkCreatePipelineLayout;
    169     if (!strcmp(funcName, "vkDestroyPipelineLayout"))
    170         return (PFN_vkVoidFunction)vkDestroyPipelineLayout;
    171     if (!strcmp(funcName, "vkCreateSampler"))
    172         return (PFN_vkVoidFunction)vkCreateSampler;
    173     if (!strcmp(funcName, "vkDestroySampler"))
    174         return (PFN_vkVoidFunction)vkDestroySampler;
    175     if (!strcmp(funcName, "vkCreateDescriptorSetLayout"))
    176         return (PFN_vkVoidFunction)vkCreateDescriptorSetLayout;
    177     if (!strcmp(funcName, "vkDestroyDescriptorSetLayout"))
    178         return (PFN_vkVoidFunction)vkDestroyDescriptorSetLayout;
    179     if (!strcmp(funcName, "vkCreateDescriptorPool"))
    180         return (PFN_vkVoidFunction)vkCreateDescriptorPool;
    181     if (!strcmp(funcName, "vkDestroyDescriptorPool"))
    182         return (PFN_vkVoidFunction)vkDestroyDescriptorPool;
    183     if (!strcmp(funcName, "vkResetDescriptorPool"))
    184         return (PFN_vkVoidFunction)vkResetDescriptorPool;
    185     if (!strcmp(funcName, "vkAllocateDescriptorSets"))
    186         return (PFN_vkVoidFunction)vkAllocateDescriptorSets;
    187     if (!strcmp(funcName, "vkFreeDescriptorSets"))
    188         return (PFN_vkVoidFunction)vkFreeDescriptorSets;
    189     if (!strcmp(funcName, "vkUpdateDescriptorSets"))
    190         return (PFN_vkVoidFunction)vkUpdateDescriptorSets;
    191     if (!strcmp(funcName, "vkCreateFramebuffer"))
    192         return (PFN_vkVoidFunction)vkCreateFramebuffer;
    193     if (!strcmp(funcName, "vkDestroyFramebuffer"))
    194         return (PFN_vkVoidFunction)vkDestroyFramebuffer;
    195     if (!strcmp(funcName, "vkCreateRenderPass"))
    196         return (PFN_vkVoidFunction)vkCreateRenderPass;
    197     if (!strcmp(funcName, "vkDestroyRenderPass"))
    198         return (PFN_vkVoidFunction)vkDestroyRenderPass;
    199     if (!strcmp(funcName, "vkGetRenderAreaGranularity"))
    200         return (PFN_vkVoidFunction)vkGetRenderAreaGranularity;
    201     if (!strcmp(funcName, "vkCreateCommandPool"))
    202         return (PFN_vkVoidFunction)vkCreateCommandPool;
    203     if (!strcmp(funcName, "vkDestroyCommandPool"))
    204         return (PFN_vkVoidFunction)vkDestroyCommandPool;
    205     if (!strcmp(funcName, "vkResetCommandPool"))
    206         return (PFN_vkVoidFunction)vkResetCommandPool;
    207     if (!strcmp(funcName, "vkAllocateCommandBuffers"))
    208         return (PFN_vkVoidFunction)vkAllocateCommandBuffers;
    209     if (!strcmp(funcName, "vkFreeCommandBuffers"))
    210         return (PFN_vkVoidFunction)vkFreeCommandBuffers;
    211     if (!strcmp(funcName, "vkBeginCommandBuffer"))
    212         return (PFN_vkVoidFunction)vkBeginCommandBuffer;
    213     if (!strcmp(funcName, "vkEndCommandBuffer"))
    214         return (PFN_vkVoidFunction)vkEndCommandBuffer;
    215     if (!strcmp(funcName, "vkResetCommandBuffer"))
    216         return (PFN_vkVoidFunction)vkResetCommandBuffer;
    217     if (!strcmp(funcName, "vkCmdBindPipeline"))
    218         return (PFN_vkVoidFunction)vkCmdBindPipeline;
    219     if (!strcmp(funcName, "vkCmdBindDescriptorSets"))
    220         return (PFN_vkVoidFunction)vkCmdBindDescriptorSets;
    221     if (!strcmp(funcName, "vkCmdBindVertexBuffers"))
    222         return (PFN_vkVoidFunction)vkCmdBindVertexBuffers;
    223     if (!strcmp(funcName, "vkCmdBindIndexBuffer"))
    224         return (PFN_vkVoidFunction)vkCmdBindIndexBuffer;
    225     if (!strcmp(funcName, "vkCmdSetViewport"))
    226         return (PFN_vkVoidFunction)vkCmdSetViewport;
    227     if (!strcmp(funcName, "vkCmdSetScissor"))
    228         return (PFN_vkVoidFunction)vkCmdSetScissor;
    229     if (!strcmp(funcName, "vkCmdSetLineWidth"))
    230         return (PFN_vkVoidFunction)vkCmdSetLineWidth;
    231     if (!strcmp(funcName, "vkCmdSetDepthBias"))
    232         return (PFN_vkVoidFunction)vkCmdSetDepthBias;
    233     if (!strcmp(funcName, "vkCmdSetBlendConstants"))
    234         return (PFN_vkVoidFunction)vkCmdSetBlendConstants;
    235     if (!strcmp(funcName, "vkCmdSetDepthBounds"))
    236         return (PFN_vkVoidFunction)vkCmdSetDepthBounds;
    237     if (!strcmp(funcName, "vkCmdSetStencilCompareMask"))
    238         return (PFN_vkVoidFunction)vkCmdSetStencilCompareMask;
    239     if (!strcmp(funcName, "vkCmdSetStencilWriteMask"))
    240         return (PFN_vkVoidFunction)vkCmdSetStencilWriteMask;
    241     if (!strcmp(funcName, "vkCmdSetStencilReference"))
    242         return (PFN_vkVoidFunction)vkCmdSetStencilReference;
    243     if (!strcmp(funcName, "vkCmdDraw"))
    244         return (PFN_vkVoidFunction)vkCmdDraw;
    245     if (!strcmp(funcName, "vkCmdDrawIndexed"))
    246         return (PFN_vkVoidFunction)vkCmdDrawIndexed;
    247     if (!strcmp(funcName, "vkCmdDrawIndirect"))
    248         return (PFN_vkVoidFunction)vkCmdDrawIndirect;
    249     if (!strcmp(funcName, "vkCmdDrawIndexedIndirect"))
    250         return (PFN_vkVoidFunction)vkCmdDrawIndexedIndirect;
    251     if (!strcmp(funcName, "vkCmdDispatch"))
    252         return (PFN_vkVoidFunction)vkCmdDispatch;
    253     if (!strcmp(funcName, "vkCmdDispatchIndirect"))
    254         return (PFN_vkVoidFunction)vkCmdDispatchIndirect;
    255     if (!strcmp(funcName, "vkCmdCopyBuffer"))
    256         return (PFN_vkVoidFunction)vkCmdCopyBuffer;
    257     if (!strcmp(funcName, "vkCmdCopyImage"))
    258         return (PFN_vkVoidFunction)vkCmdCopyImage;
    259     if (!strcmp(funcName, "vkCmdBlitImage"))
    260         return (PFN_vkVoidFunction)vkCmdBlitImage;
    261     if (!strcmp(funcName, "vkCmdCopyBufferToImage"))
    262         return (PFN_vkVoidFunction)vkCmdCopyBufferToImage;
    263     if (!strcmp(funcName, "vkCmdCopyImageToBuffer"))
    264         return (PFN_vkVoidFunction)vkCmdCopyImageToBuffer;
    265     if (!strcmp(funcName, "vkCmdUpdateBuffer"))
    266         return (PFN_vkVoidFunction)vkCmdUpdateBuffer;
    267     if (!strcmp(funcName, "vkCmdFillBuffer"))
    268         return (PFN_vkVoidFunction)vkCmdFillBuffer;
    269     if (!strcmp(funcName, "vkCmdClearColorImage"))
    270         return (PFN_vkVoidFunction)vkCmdClearColorImage;
    271     if (!strcmp(funcName, "vkCmdClearDepthStencilImage"))
    272         return (PFN_vkVoidFunction)vkCmdClearDepthStencilImage;
    273     if (!strcmp(funcName, "vkCmdClearAttachments"))
    274         return (PFN_vkVoidFunction)vkCmdClearAttachments;
    275     if (!strcmp(funcName, "vkCmdResolveImage"))
    276         return (PFN_vkVoidFunction)vkCmdResolveImage;
    277     if (!strcmp(funcName, "vkCmdSetEvent"))
    278         return (PFN_vkVoidFunction)vkCmdSetEvent;
    279     if (!strcmp(funcName, "vkCmdResetEvent"))
    280         return (PFN_vkVoidFunction)vkCmdResetEvent;
    281     if (!strcmp(funcName, "vkCmdWaitEvents"))
    282         return (PFN_vkVoidFunction)vkCmdWaitEvents;
    283     if (!strcmp(funcName, "vkCmdPipelineBarrier"))
    284         return (PFN_vkVoidFunction)vkCmdPipelineBarrier;
    285     if (!strcmp(funcName, "vkCmdBeginQuery"))
    286         return (PFN_vkVoidFunction)vkCmdBeginQuery;
    287     if (!strcmp(funcName, "vkCmdEndQuery"))
    288         return (PFN_vkVoidFunction)vkCmdEndQuery;
    289     if (!strcmp(funcName, "vkCmdResetQueryPool"))
    290         return (PFN_vkVoidFunction)vkCmdResetQueryPool;
    291     if (!strcmp(funcName, "vkCmdWriteTimestamp"))
    292         return (PFN_vkVoidFunction)vkCmdWriteTimestamp;
    293     if (!strcmp(funcName, "vkCmdCopyQueryPoolResults"))
    294         return (PFN_vkVoidFunction)vkCmdCopyQueryPoolResults;
    295     if (!strcmp(funcName, "vkCmdPushConstants"))
    296         return (PFN_vkVoidFunction)vkCmdPushConstants;
    297     if (!strcmp(funcName, "vkCmdBeginRenderPass"))
    298         return (PFN_vkVoidFunction)vkCmdBeginRenderPass;
    299     if (!strcmp(funcName, "vkCmdNextSubpass"))
    300         return (PFN_vkVoidFunction)vkCmdNextSubpass;
    301     if (!strcmp(funcName, "vkCmdEndRenderPass"))
    302         return (PFN_vkVoidFunction)vkCmdEndRenderPass;
    303     if (!strcmp(funcName, "vkCmdExecuteCommands"))
    304         return (PFN_vkVoidFunction)vkCmdExecuteCommands;
    305 
    306     // Instance extensions
    307     void *addr;
    308     if (debug_report_instance_gpa(inst, funcName, &addr))
    309         return addr;
    310 
    311     if (wsi_swapchain_instance_gpa(inst, funcName, &addr))
    312         return addr;
    313 
    314     addr = loader_dev_ext_gpa(inst, funcName);
    315     return addr;
    316 }
    317 
    318 static inline void *globalGetProcAddr(const char *name) {
    319     if (!name || name[0] != 'v' || name[1] != 'k')
    320         return NULL;
    321 
    322     name += 2;
    323     if (!strcmp(name, "CreateInstance"))
    324         return (void *)vkCreateInstance;
    325     if (!strcmp(name, "EnumerateInstanceExtensionProperties"))
    326         return (void *)vkEnumerateInstanceExtensionProperties;
    327     if (!strcmp(name, "EnumerateInstanceLayerProperties"))
    328         return (void *)vkEnumerateInstanceLayerProperties;
    329 
    330     return NULL;
    331 }
    332 
    333 /* These functions require special handling by the loader.
    334 *  They are not just generic trampoline code entrypoints.
    335 *  Thus GPA must return loader entrypoint for these instead of first function
    336 *  in the chain. */
    337 static inline void *loader_non_passthrough_gipa(const char *name) {
    338     if (!name || name[0] != 'v' || name[1] != 'k')
    339         return NULL;
    340 
    341     name += 2;
    342     if (!strcmp(name, "CreateInstance"))
    343         return (void *)vkCreateInstance;
    344     if (!strcmp(name, "DestroyInstance"))
    345         return (void *)vkDestroyInstance;
    346     if (!strcmp(name, "GetDeviceProcAddr"))
    347         return (void *)vkGetDeviceProcAddr;
    348     // remove once no longer locks
    349     if (!strcmp(name, "EnumeratePhysicalDevices"))
    350         return (void *)vkEnumeratePhysicalDevices;
    351     if (!strcmp(name, "EnumerateDeviceExtensionProperties"))
    352         return (void *)vkEnumerateDeviceExtensionProperties;
    353     if (!strcmp(name, "EnumerateDeviceLayerProperties"))
    354         return (void *)vkEnumerateDeviceLayerProperties;
    355     if (!strcmp(name, "GetInstanceProcAddr"))
    356         return (void *)vkGetInstanceProcAddr;
    357     if (!strcmp(name, "CreateDevice"))
    358         return (void *)vkCreateDevice;
    359 
    360     return NULL;
    361 }
    362 
    363 static inline void *loader_non_passthrough_gdpa(const char *name) {
    364     if (!name || name[0] != 'v' || name[1] != 'k')
    365         return NULL;
    366 
    367     name += 2;
    368 
    369     if (!strcmp(name, "GetDeviceProcAddr"))
    370         return (void *)vkGetDeviceProcAddr;
    371     if (!strcmp(name, "DestroyDevice"))
    372         return (void *)vkDestroyDevice;
    373     if (!strcmp(name, "GetDeviceQueue"))
    374         return (void *)vkGetDeviceQueue;
    375     if (!strcmp(name, "AllocateCommandBuffers"))
    376         return (void *)vkAllocateCommandBuffers;
    377 
    378     return NULL;
    379 }
    380