summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Ekstrand <jason.ekstrand@collabora.com>2022-03-18 17:31:35 -0500
committerMarge Bot <emma+marge@anholt.net>2022-04-07 16:32:21 +0000
commitf06fa8f7e0df525fc38135e3717f257d0ab39f68 (patch)
tree5afdb2376b3d0ec3be48fdffb49769c5ca5c05c9
parent0ca8b95824191d59955f5fc9654fbf804841c1d7 (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.rst83
-rw-r--r--docs/vulkan/index.rst1
-rw-r--r--src/vulkan/runtime/vk_device.h17
-rw-r--r--src/vulkan/runtime/vk_object.h75
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)