1Base object structs 2=================== 3 4The Vulkan runtime code provides a set of base object structs which must be 5used if you want your driver to take advantage of any of the runtime code. 6There are other base structs for various things which are not covered here 7but those are optional. The ones covered here are the bare minimum set 8which form the core of the Vulkan runtime code: 9 10.. contents:: 11 :local: 12 13As one might expect, :cpp:struct:`vk_instance` is the required base struct 14for implementing ``VkInstance``, :cpp:struct:`vk_physical_device` is 15required for ``VkPhysicalDevice``, and :cpp:struct:`vk_device` for 16``VkDevice``. Everything else must derive from 17:cpp:struct:`vk_vk_objet_base` or from some struct that derives from 18:cpp:struct:`vk_vk_objet_base`. 19 20 21vk_object_base 22-------------- 23 24The root base struct for all Vulkan objects is 25:cpp:struct:`vk_object_base`. Every object exposed to the client through 26the Vulkan API *must* inherit from :cpp:struct:`vk_object_base` by having a 27:cpp:struct:`vk_object_base` or some struct that inherits from 28:cpp:struct:`vk_object_base` as the driver struct's first member. Even 29though we have `container_of()` and use it liberally, the 30:cpp:struct:`vk_object_base` should be the first member as there are a few 31places, particularly in the logging framework, where we use void pointers 32to avoid casting and this only works if the address of the driver struct is 33the same as the address of the :cpp:struct:`vk_object_base`. 34 35The standard pattern for defining a Vulkan object inside a driver looks 36something like this: 37 38.. code-block:: c 39 40 struct drv_sampler { 41 struct vk_object_base base; 42 43 /* Driver fields */ 44 }; 45 46 VK_DEFINE_NONDISP_HANDLE_CASTS(drv_sampler, base, VkSampler, 47 VK_OBJECT_TYPE_SAMPLER); 48 49Then, to the object in a Vulkan entrypoint, 50 51.. code-block:: c 52 53 VKAPI_ATTR void VKAPI_CALL drv_DestroySampler( 54 VkDevice _device, 55 VkSampler _sampler, 56 const VkAllocationCallbacks* pAllocator) 57 { 58 VK_FROM_HANDLE(drv_device, device, _device); 59 VK_FROM_HANDLE(drv_sampler, sampler, _sampler); 60 61 if (!sampler) 62 return; 63 64 /* Tear down the sampler */ 65 66 vk_object_free(&device->vk, pAllocator, sampler); 67 } 68 69The :cpp:any:`VK_DEFINE_NONDISP_HANDLE_CASTS()` macro defines a set of 70type-safe cast functions called ``drv_sampler_from_handle()`` and 71``drv_sampler_to_handle()`` which cast a :cpp:type:`VkSampler` to and from a 72``struct drv_sampler *``. Because compile-time type checking with Vulkan 73handle types doesn't always work in C, the ``_from_handle()`` helper uses the 74provided :cpp:type:`VkObjectType` to assert at runtime that the provided 75handle is the correct type of object. Both cast helpers properly handle 76``NULL`` and ``VK_NULL_HANDLE`` as inputs. The :cpp:any:`VK_FROM_HANDLE()` 77macro provides a convenient way to declare a ``drv_foo`` pointer and 78initialize it from a ``VkFoo`` handle in one smooth motion. 79 80.. doxygenstruct:: vk_object_base 81 :members: 82 83.. doxygenfunction:: vk_object_base_init 84.. doxygenfunction:: vk_object_base_finish 85 86.. doxygendefine:: VK_DEFINE_HANDLE_CASTS 87 88.. doxygendefine:: VK_DEFINE_NONDISP_HANDLE_CASTS 89 90.. doxygendefine:: VK_FROM_HANDLE 91 92 93vk_instance 94----------- 95 96.. doxygenstruct:: vk_instance 97 :members: 98 99.. doxygenfunction:: vk_instance_init 100.. doxygenfunction:: vk_instance_finish 101 102Once a driver has a :cpp:struct:`vk_instance`, implementing all the various 103instance-level ``vkGet*ProcAddr()`` entrypoints is trivial: 104 105.. code-block:: c 106 107 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL 108 drv_GetInstanceProcAddr(VkInstance _instance, 109 const char *pName) 110 { 111 VK_FROM_HANDLE(vk_instance, instance, _instance); 112 return vk_instance_get_proc_addr(instance, 113 &drv_instance_entrypoints, 114 pName); 115 } 116 117 PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL 118 vk_icdGetInstanceProcAddr(VkInstance instance, 119 const char *pName); 120 121 PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL 122 vk_icdGetInstanceProcAddr(VkInstance instance, 123 const char *pName) 124 { 125 return drv_GetInstanceProcAddr(instance, pName); 126 } 127 128 PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL 129 vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance, 130 const char* pName); 131 132 PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL 133 vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance, 134 const char* pName) 135 { 136 VK_FROM_HANDLE(vk_instance, instance, _instance); 137 return vk_instance_get_physical_device_proc_addr(instance, pName); 138 } 139 140The prototypes for the ``vk_icd*`` versions are needed because those are not 141actually defined in the Vulkan headers and you need the prototype somewhere 142to get the C compiler to not complain. These are all implemented by 143wrapping one of the provided ``vk_instance_get*_proc_addr()`` functions. 144 145.. doxygenfunction:: vk_instance_get_proc_addr 146.. doxygenfunction:: vk_instance_get_proc_addr_unchecked 147.. doxygenfunction:: vk_instance_get_physical_device_proc_addr 148 149We also provide an implementation of 150``vkEnumerateInstanceExtensionProperties()`` which can be used similarly: 151 152.. code-block:: c 153 154 VKAPI_ATTR VkResult VKAPI_CALL 155 drv_EnumerateInstanceExtensionProperties(const char *pLayerName, 156 uint32_t *pPropertyCount, 157 VkExtensionProperties *pProperties) 158 { 159 if (pLayerName) 160 return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT); 161 162 return vk_enumerate_instance_extension_properties( 163 &instance_extensions, pPropertyCount, pProperties); 164 } 165 166.. doxygenfunction:: vk_enumerate_instance_extension_properties 167 168vk_physical_device 169------------------ 170 171.. doxygenstruct:: vk_physical_device 172 :members: 173 174.. doxygenfunction:: vk_physical_device_init 175.. doxygenfunction:: vk_physical_device_finish 176 177vk_device 178------------------ 179 180.. doxygenstruct:: vk_device 181 :members: 182 183.. doxygenfunction:: vk_device_init 184.. doxygenfunction:: vk_device_finish 185