diff --git a/docs/doxygen-wrapper.py b/docs/doxygen-wrapper.py index 1eab6a78426..b415f2290ab 100755 --- a/docs/doxygen-wrapper.py +++ b/docs/doxygen-wrapper.py @@ -58,6 +58,7 @@ EXPAND_ONLY_PREDEF = YES # Defines required to keep doxygen from tripping on our attribute macros PREDEFINED = PACKED= PREDEFINED += ATTRIBUTE_CONST= +PREDEFINED += MUST_CHECK= """) def run_doxygen(output_path, input_paths=[]): diff --git a/docs/vulkan/base-objs.rst b/docs/vulkan/base-objs.rst index fbad2b25282..5b66738c4c5 100644 --- a/docs/vulkan/base-objs.rst +++ b/docs/vulkan/base-objs.rst @@ -10,6 +10,13 @@ which form the core of the Vulkan runtime code: .. contents:: :local: +As one might expect, :cpp:struct:`vk_instance` is the required base struct +for implementing ``VkInstance``, :cpp:struct:`vk_physical_device` is +required for ``VkPhysicalDevice``, and :cpp:struct:`vk_device` for +``VkDevice``. Everything else must derive from +:cpp:struct:`vk_vk_objet_base` or from some struct that derives from +:cpp:struct:`vk_vk_objet_base`. + vk_object_base -------------- @@ -81,3 +88,79 @@ initialize it from a ``VkFoo`` handle in one smooth motion. .. doxygendefine:: VK_DEFINE_NONDISP_HANDLE_CASTS .. doxygendefine:: VK_FROM_HANDLE + + +vk_instance +----------- + +.. doxygenstruct:: vk_instance + :members: + +.. doxygenfunction:: vk_instance_init +.. doxygenfunction:: vk_instance_finish + +Once a driver has a :cpp:struct:`vk_instance`, implementing all the various +instance-level ``vkGet*ProcAddr()`` entrypoints is trivial: + +.. code-block:: c + + VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL + drv_GetInstanceProcAddr(VkInstance _instance, + const char *pName) + { + VK_FROM_HANDLE(vk_instance, instance, _instance); + return vk_instance_get_proc_addr(instance, + &drv_instance_entrypoints, + pName); + } + + PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL + vk_icdGetInstanceProcAddr(VkInstance instance, + const char *pName); + + PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL + vk_icdGetInstanceProcAddr(VkInstance instance, + const char *pName) + { + return drv_GetInstanceProcAddr(instance, pName); + } + + PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL + vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance, + const char* pName); + + PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL + vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance, + const char* pName) + { + VK_FROM_HANDLE(vk_instance, instance, _instance); + return vk_instance_get_physical_device_proc_addr(instance, pName); + } + +The prototypes for the ``vk_icd*`` versions are needed because those are not +actually defined in the Vulkan headers and you need the prototype somewhere +to get the C compiler to not complain. These are all implemented by +wrapping one of the provided ``vk_instance_get*_proc_addr()`` functions. + +.. doxygenfunction:: vk_instance_get_proc_addr +.. doxygenfunction:: vk_instance_get_proc_addr_unchecked +.. doxygenfunction:: vk_instance_get_physical_device_proc_addr + +We also provide an implementation of +``vkEnumerateInstanceExtensionProperties()`` which can be used similarly: + +.. code-block:: c + + VKAPI_ATTR VkResult VKAPI_CALL + drv_EnumerateInstanceExtensionProperties(const char *pLayerName, + uint32_t *pPropertyCount, + VkExtensionProperties *pProperties) + { + if (pLayerName) + return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT); + + return vk_enumerate_instance_extension_properties( + &instance_extensions, pPropertyCount, pProperties); + } + +.. doxygenfunction:: vk_enumerate_instance_extension_properties diff --git a/src/vulkan/runtime/vk_instance.h b/src/vulkan/runtime/vk_instance.h index 88af1a6b4ed..3609afc634b 100644 --- a/src/vulkan/runtime/vk_instance.h +++ b/src/vulkan/runtime/vk_instance.h @@ -35,20 +35,54 @@ extern "C" { #endif struct vk_app_info { + /** VkApplicationInfo::pApplicationName */ const char* app_name; + + /** VkApplicationInfo::applicationVersion */ uint32_t app_version; + + /** VkApplicationInfo::pEngineName */ const char* engine_name; + + /** VkApplicationInfo::engineVersion */ uint32_t engine_version; + + /** VkApplicationInfo::apiVersion or `VK_API_VERSION_1_0` + * + * If the application does not provide a `pApplicationInfo` or the + * `apiVersion` field is 0, this is set to `VK_API_VERSION_1_0`. + */ uint32_t api_version; }; +/** Base struct for all `VkInstance` implementations + * + * This contains data structures necessary for detecting enabled extensions, + * handling entrypoint dispatch, and implementing `vkGetInstanceProcAddr()`. + * It also contains data copied from the `VkInstanceCreateInfo` such as the + * application information. + */ struct vk_instance { struct vk_object_base base; + + /** Allocator used when creating this instance + * + * This is used as a fall-back for when a NULL pAllocator is passed into a + * device-level create function such as vkCreateImage(). + */ VkAllocationCallbacks alloc; + /** VkInstanceCreateInfo::pApplicationInfo */ struct vk_app_info app_info; + + /** Table of all enabled instance extensions + * + * This is generated automatically as part of `vk_instance_init()` from + * VkInstanceCreateInfo::ppEnabledExtensionNames. + */ struct vk_instance_extension_table enabled_extensions; + /** Instance-level dispatch table */ struct vk_instance_dispatch_table dispatch_table; /* VK_EXT_debug_report debug callbacks */ @@ -70,8 +104,26 @@ struct vk_instance { }; VK_DEFINE_HANDLE_CASTS(vk_instance, base, VkInstance, - VK_OBJECT_TYPE_INSTANCE) + VK_OBJECT_TYPE_INSTANCE); +/** Initialize a vk_instance + * + * Along with initializing the data structures in `vk_instance`, this function + * validates the Vulkan version number provided by the client and checks that + * every extension specified by + * `VkInstanceCreateInfo::ppEnabledExtensionNames` is actually supported by + * the implementation and returns `VK_ERROR_EXTENSION_NOT_PRESENT` if an + * unsupported extension is requested. + * + * @param[out] instance The instance to initialize + * @param[in] supported_extensions Table of all instance extensions supported + * by this instance + * @param[in] dispatch_table Instance-level dispatch table + * @param[in] pCreateInfo VkInstanceCreateInfo pointer passed to + * `vkCreateInstance()` + * @param[in] alloc Allocation callbacks used to create this + * instance; must not be `NULL` + */ VkResult MUST_CHECK vk_instance_init(struct vk_instance *instance, const struct vk_instance_extension_table *supported_extensions, @@ -79,24 +131,38 @@ vk_instance_init(struct vk_instance *instance, const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *alloc); +/** Tears down a vk_instance + * + * @param[out] instance The instance to tear down + */ void vk_instance_finish(struct vk_instance *instance); +/** Implementaiton of vkEnumerateInstanceExtensionProperties() */ VkResult vk_enumerate_instance_extension_properties( const struct vk_instance_extension_table *supported_extensions, uint32_t *pPropertyCount, VkExtensionProperties *pProperties); +/** Implementaiton of vkGetInstanceProcAddr() */ PFN_vkVoidFunction vk_instance_get_proc_addr(const struct vk_instance *instance, const struct vk_instance_entrypoint_table *entrypoints, const char *name); +/** Unchecked version of vk_instance_get_proc_addr + * + * This is identical to `vk_instance_get_proc_addr()` except that it doesn't + * check whether extensions are enabled before returning function pointers. + * This is useful in window-system code where we may use extensions without + * the client explicitly enabling them. + */ PFN_vkVoidFunction vk_instance_get_proc_addr_unchecked(const struct vk_instance *instance, const char *name); +/** Implementaiton of vk_icdGetPhysicalDeviceProcAddr() */ PFN_vkVoidFunction vk_instance_get_physical_device_proc_addr(const struct vk_instance *instance, const char *name);