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>
This commit is contained in:
parent
0ca8b95824
commit
f06fa8f7e0
|
@ -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
|
|
@ -9,4 +9,5 @@ hardware-agnostic bits in common code.
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
base-objs
|
||||
renderpass
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue