diff options
author | Jason Ekstrand <jason.ekstrand@collabora.com> | 2022-03-18 17:31:35 -0500 |
---|---|---|
committer | Marge Bot <emma+marge@anholt.net> | 2022-04-07 16:32:21 +0000 |
commit | f06fa8f7e0df525fc38135e3717f257d0ab39f68 (patch) | |
tree | 5afdb2376b3d0ec3be48fdffb49769c5ca5c05c9 | |
parent | 0ca8b95824191d59955f5fc9654fbf804841c1d7 (diff) |
vulkan,docs: Document vk_object_base
Acked-by: Iago Toral Quiroga <itoral@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15472>
-rw-r--r-- | docs/vulkan/base-objs.rst | 83 | ||||
-rw-r--r-- | docs/vulkan/index.rst | 1 | ||||
-rw-r--r-- | src/vulkan/runtime/vk_device.h | 17 | ||||
-rw-r--r-- | src/vulkan/runtime/vk_object.h | 75 |
4 files changed, 176 insertions, 0 deletions
diff --git a/docs/vulkan/base-objs.rst b/docs/vulkan/base-objs.rst new file mode 100644 index 00000000000..fbad2b25282 --- /dev/null +++ b/docs/vulkan/base-objs.rst @@ -0,0 +1,83 @@ +Base object structs +=================== + +The Vulkan runtime code provides a set of base object structs which must be +used if you want your driver to take advantage of any of the runtime code. +There are other base structs for various things which are not covered here +but those are optional. The ones covered here are the bare minimum set +which form the core of the Vulkan runtime code: + +.. contents:: + :local: + + +vk_object_base +-------------- + +The root base struct for all Vulkan objects is +:cpp:struct:`vk_object_base`. Every object exposed to the client through +the Vulkan API *must* inherit from :cpp:struct:`vk_object_base` by having a +:cpp:struct:`vk_object_base` or some struct that inherits from +:cpp:struct:`vk_object_base` as the driver struct's first member. Even +though we have `container_of()` and use it liberally, the +:cpp:struct:`vk_object_base` should be the first member as there are a few +places, particularly in the logging framework, where we use void pointers +to avoid casting and this only works if the address of the driver struct is +the same as the address of the :cpp:struct:`vk_object_base`. + +The standard pattern for defining a Vulkan object inside a driver looks +something like this: + +.. code-block:: c + + struct drv_sampler { + struct vk_object_base base; + + /* Driver fields */ + }; + + VK_DEFINE_NONDISP_HANDLE_CASTS(drv_sampler, base, VkSampler, + VK_OBJECT_TYPE_SAMPLER); + +Then, to the object in a Vulkan entrypoint, + +.. code-block:: c + + VKAPI_ATTR void VKAPI_CALL drv_DestroySampler( + VkDevice _device, + VkSampler _sampler, + const VkAllocationCallbacks* pAllocator) + { + VK_FROM_HANDLE(drv_device, device, _device); + VK_FROM_HANDLE(drv_sampler, sampler, _sampler); + + if (!sampler) + return; + + /* Tear down the sampler */ + + vk_object_free(&device->vk, pAllocator, sampler); + } + +The :cpp:any:`VK_DEFINE_NONDISP_HANDLE_CASTS()` macro defines a set of +type-safe cast functions called ``drv_sampler_from_handle()`` and +``drv_sampler_to_handle()`` which cast a :cpp:type:`VkSampler` to and from a +``struct drv_sampler *``. Because compile-time type checking with Vulkan +handle types doesn't always work in C, the ``_from_handle()`` helper uses the +provided :cpp:type:`VkObjectType` to assert at runtime that the provided +handle is the correct type of object. Both cast helpers properly handle +``NULL`` and ``VK_NULL_HANDLE`` as inputs. The :cpp:any:`VK_FROM_HANDLE()` +macro provides a convenient way to declare a ``drv_foo`` pointer and +initialize it from a ``VkFoo`` handle in one smooth motion. + +.. doxygenstruct:: vk_object_base + :members: + +.. doxygenfunction:: vk_object_base_init +.. doxygenfunction:: vk_object_base_finish + +.. doxygendefine:: VK_DEFINE_HANDLE_CASTS + +.. doxygendefine:: VK_DEFINE_NONDISP_HANDLE_CASTS + +.. doxygendefine:: VK_FROM_HANDLE diff --git a/docs/vulkan/index.rst b/docs/vulkan/index.rst index 58e387d6f97..b0993ffce5e 100644 --- a/docs/vulkan/index.rst +++ b/docs/vulkan/index.rst @@ -9,4 +9,5 @@ hardware-agnostic bits in common code. .. toctree:: :maxdepth: 2 + base-objs renderpass diff --git a/src/vulkan/runtime/vk_device.h b/src/vulkan/runtime/vk_device.h index 166cf1e9ce0..d1dc154ac8c 100644 --- a/src/vulkan/runtime/vk_device.h +++ b/src/vulkan/runtime/vk_device.h @@ -86,13 +86,24 @@ enum vk_queue_submit_mode { VK_QUEUE_SUBMIT_MODE_THREADED_ON_DEMAND, }; +/** Base struct for VkDevice */ struct vk_device { struct vk_object_base base; + + /** Allocator used to create this device + * + * 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; + + /** Pointer to the physical device */ struct vk_physical_device *physical; + /** Table of enabled extensions */ struct vk_device_extension_table enabled_extensions; + /** Device-level dispatch table */ struct vk_device_dispatch_table dispatch_table; /** Command dispatch table @@ -228,6 +239,12 @@ struct vk_device { VK_DEVICE_TIMELINE_MODE_NATIVE, } timeline_mode; + /** Per-device submit mode + * + * This represents the device-wide submit strategy which may be different + * from the per-queue submit mode. See vk_queue.submit.mode for more + * details. + */ enum vk_queue_submit_mode submit_mode; #ifdef ANDROID diff --git a/src/vulkan/runtime/vk_object.h b/src/vulkan/runtime/vk_object.h index e8b3483976c..63d55f954f3 100644 --- a/src/vulkan/runtime/vk_object.h +++ b/src/vulkan/runtime/vk_object.h @@ -38,10 +38,23 @@ struct hash_table; struct vk_device; +/** Base struct for all Vulkan objects */ struct vk_object_base { VK_LOADER_DATA _loader_data; + + /** Type of this object + * + * This is used for runtime type checking when casting to and from Vulkan + * handle types since compile-time type checking doesn't always work. + */ VkObjectType type; + /** Pointer to the device in which this object exists, if any + * + * This is NULL for instances and physical devices but should point to a + * valid vk_device for almost everything else. (There are a few WSI + * objects that don't inherit from a device.) + */ struct vk_device *device; /* True if this object is fully constructed and visible to the client */ @@ -54,9 +67,20 @@ struct vk_object_base { char *object_name; }; +/** Initialize a vk_base_object + * + * @param[in] device The vk_device this object was created from or NULL + * @param[out] base The vk_object_base to initialize + * @param[in] obj_type The VkObjectType of the object being initialized + */ void vk_object_base_init(struct vk_device *device, struct vk_object_base *base, VkObjectType obj_type); + +/** Tear down a vk_object_base + * + * @param[out] base The vk_object_base being torn down + */ void vk_object_base_finish(struct vk_object_base *base); static inline void @@ -74,6 +98,26 @@ vk_object_base_from_u64_handle(uint64_t handle, VkObjectType obj_type) return base; } +/** Define handle cast macros for the given dispatchable handle type + * + * For a given `driver_struct`, this defines `driver_struct_to_handle()` and + * `driver_struct_from_handle()` helpers which provide type-safe (as much as + * possible with Vulkan handle types) casts to and from the `driver_struct` + * type. As an added layer of protection, these casts use the provided + * `VkObjectType` to assert that the object is of the correct type when + * running with a debug build. + * + * @param __driver_type The name of the driver struct; it is assumed this is + * the name of a struct type and `struct` will be + * prepended automatically + * + * @param __base The name of the vk_base_object member + * + * @param __VkType The Vulkan object type such as VkImage + * + * @param __VK_TYPE The VkObjectType corresponding to __VkType, such as + * VK_OBJECT_TYPE_IMAGE + */ #define VK_DEFINE_HANDLE_CASTS(__driver_type, __base, __VkType, __VK_TYPE) \ static inline struct __driver_type * \ __driver_type ## _from_handle(__VkType _handle) \ @@ -93,6 +137,26 @@ vk_object_base_from_u64_handle(uint64_t handle, VkObjectType obj_type) return (__VkType) _obj; \ } +/** Define handle cast macros for the given non-dispatchable handle type + * + * For a given `driver_struct`, this defines `driver_struct_to_handle()` and + * `driver_struct_from_handle()` helpers which provide type-safe (as much as + * possible with Vulkan handle types) casts to and from the `driver_struct` + * type. As an added layer of protection, these casts use the provided + * `VkObjectType` to assert that the object is of the correct type when + * running with a debug build. + * + * @param __driver_type The name of the driver struct; it is assumed this is + * the name of a struct type and `struct` will be + * prepended automatically + * + * @param __base The name of the vk_base_object member + * + * @param __VkType The Vulkan object type such as VkImage + * + * @param __VK_TYPE The VkObjectType corresponding to __VkType, such as + * VK_OBJECT_TYPE_IMAGE + */ #define VK_DEFINE_NONDISP_HANDLE_CASTS(__driver_type, __base, __VkType, __VK_TYPE) \ static inline struct __driver_type * \ __driver_type ## _from_handle(__VkType _handle) \ @@ -113,6 +177,17 @@ vk_object_base_from_u64_handle(uint64_t handle, VkObjectType obj_type) return (__VkType)(uintptr_t) _obj; \ } +/** Declares a __driver_type pointer which represents __handle + * + * @param __driver_type The name of the driver struct; it is assumed this is + * the name of a struct type and `struct` will be + * prepended automatically + * + * @param __name The name of the declared pointer + * + * @param __handle The Vulkan object handle with which to initialize + * `__name` + */ #define VK_FROM_HANDLE(__driver_type, __name, __handle) \ struct __driver_type *__name = __driver_type ## _from_handle(__handle) |