summaryrefslogtreecommitdiffstats
path: root/src/include/libplacebo/vulkan.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/libplacebo/vulkan.h')
-rw-r--r--src/include/libplacebo/vulkan.h638
1 files changed, 638 insertions, 0 deletions
diff --git a/src/include/libplacebo/vulkan.h b/src/include/libplacebo/vulkan.h
new file mode 100644
index 0000000..4e5db95
--- /dev/null
+++ b/src/include/libplacebo/vulkan.h
@@ -0,0 +1,638 @@
+/*
+ * This file is part of libplacebo.
+ *
+ * libplacebo is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libplacebo is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBPLACEBO_VULKAN_H_
+#define LIBPLACEBO_VULKAN_H_
+
+#include <vulkan/vulkan.h>
+#include <libplacebo/gpu.h>
+#include <libplacebo/swapchain.h>
+
+PL_API_BEGIN
+
+#define PL_VK_MIN_VERSION VK_API_VERSION_1_2
+
+// Structure representing a VkInstance. Using this is not required.
+typedef const struct pl_vk_inst_t {
+ VkInstance instance;
+
+ // The Vulkan API version supported by this VkInstance.
+ uint32_t api_version;
+
+ // The associated vkGetInstanceProcAddr pointer.
+ PFN_vkGetInstanceProcAddr get_proc_addr;
+
+ // The instance extensions that were successfully enabled, including
+ // extensions enabled by libplacebo internally. May contain duplicates.
+ const char * const *extensions;
+ int num_extensions;
+
+ // The instance layers that were successfully enabled, including
+ // layers enabled by libplacebo internally. May contain duplicates.
+ const char * const *layers;
+ int num_layers;
+} *pl_vk_inst;
+
+struct pl_vk_inst_params {
+ // If set, enable the debugging and validation layers. These should
+ // generally be lightweight and relatively harmless to enable.
+ bool debug;
+
+ // If set, also enable GPU-assisted verification and best practices
+ // layers. (Note: May cause substantial slowdown and/or result in lots of
+ // false positive spam)
+ bool debug_extra;
+
+ // If nonzero, restricts the Vulkan API version to be at most this. This
+ // is only really useful for explicitly testing backwards compatibility.
+ uint32_t max_api_version;
+
+ // Pointer to a user-provided `vkGetInstanceProcAddr`. If this is NULL,
+ // libplacebo will use the directly linked version (if available).
+ PFN_vkGetInstanceProcAddr get_proc_addr;
+
+ // Enables extra instance extensions. Instance creation will fail if these
+ // extensions are not all supported. The user may use this to enable e.g.
+ // windowing system integration.
+ const char * const *extensions;
+ int num_extensions;
+
+ // Enables extra optional instance extensions. These are opportunistically
+ // enabled if supported by the device, but otherwise skipped.
+ const char * const *opt_extensions;
+ int num_opt_extensions;
+
+ // Enables extra layers. Instance creation will fail if these layers are
+ // not all supported.
+ //
+ // NOTE: Layers needed for required/optional extensions are automatically
+ // enabled. The user does not specifically need to enable layers related
+ // to extension support.
+ const char * const *layers;
+ int num_layers;
+
+ // Enables extra optional layers. These are opportunistically enabled if
+ // supported by the platform, but otherwise skipped.
+ const char * const *opt_layers;
+ int num_opt_layers;
+};
+
+#define pl_vk_inst_params(...) (&(struct pl_vk_inst_params) { __VA_ARGS__ })
+PL_API extern const struct pl_vk_inst_params pl_vk_inst_default_params;
+
+// Helper function to simplify instance creation. The user could also bypass
+// these helpers and do it manually, but this function is provided as a
+// convenience. It also sets up a debug callback which forwards all vulkan
+// messages to the `pl_log` callback.
+PL_API pl_vk_inst pl_vk_inst_create(pl_log log, const struct pl_vk_inst_params *params);
+PL_API void pl_vk_inst_destroy(pl_vk_inst *inst);
+
+struct pl_vulkan_queue {
+ uint32_t index; // Queue family index
+ uint32_t count; // Queue family count
+};
+
+// Structure representing the actual vulkan device and associated GPU instance
+typedef const struct pl_vulkan_t *pl_vulkan;
+struct pl_vulkan_t {
+ pl_gpu gpu;
+
+ // The vulkan objects in use. The user may use this for their own purposes,
+ // but please note that the lifetime is tied to the lifetime of the
+ // pl_vulkan object, and must not be destroyed by the user. Note that the
+ // created vulkan device may have any number of queues and queue family
+ // assignments; so using it for queue submission commands is ill-advised.
+ VkInstance instance;
+ VkPhysicalDevice phys_device;
+ VkDevice device;
+
+ // The associated vkGetInstanceProcAddr pointer.
+ PFN_vkGetInstanceProcAddr get_proc_addr;
+
+ // The Vulkan API version supported by this VkPhysicalDevice.
+ uint32_t api_version;
+
+ // The device extensions that were successfully enabled, including
+ // extensions enabled by libplacebo internally. May contain duplicates.
+ const char * const *extensions;
+ int num_extensions;
+
+ // The device features that were enabled at device creation time.
+ //
+ // Note: Whenever a feature flag is ambiguious between several alternative
+ // locations, for completeness' sake, we include both.
+ const VkPhysicalDeviceFeatures2 *features;
+
+ // The explicit queue families we are using to provide a given capability.
+ struct pl_vulkan_queue queue_graphics; // provides VK_QUEUE_GRAPHICS_BIT
+ struct pl_vulkan_queue queue_compute; // provides VK_QUEUE_COMPUTE_BIT
+ struct pl_vulkan_queue queue_transfer; // provides VK_QUEUE_TRANSFER_BIT
+
+ // Functions for locking a queue. These must be used to lock VkQueues for
+ // submission or other related operations when sharing the VkDevice between
+ // multiple threads, Using this on queue families or indices not contained
+ // in `queues` is undefined behavior.
+ void (*lock_queue)(pl_vulkan vk, uint32_t qf, uint32_t qidx);
+ void (*unlock_queue)(pl_vulkan vk, uint32_t qf, uint32_t qidx);
+
+ // --- Deprecated fields
+
+ // These are the same active queue families and their queue counts in list
+ // form. This list does not contain duplicates, nor any extra queues
+ // enabled at device creation time. Deprecated in favor of querying
+ // `vkGetPhysicalDeviceQueueFamilyProperties` directly.
+ const struct pl_vulkan_queue *queues PL_DEPRECATED;
+ int num_queues PL_DEPRECATED;
+};
+
+struct pl_vulkan_params {
+ // The vulkan instance. Optional, if NULL then libplacebo will internally
+ // create a VkInstance with the settings from `instance_params`.
+ //
+ // Note: The VkInstance provided by the user *MUST* be created with a
+ // VkApplicationInfo.apiVersion of PL_VK_MIN_VERSION or higher.
+ VkInstance instance;
+
+ // Pointer to `vkGetInstanceProcAddr`. If this is NULL, libplacebo will
+ // use the directly linked version (if available).
+ //
+ // Note: This overwrites the same value from `instance_params`.
+ PFN_vkGetInstanceProcAddr get_proc_addr;
+
+ // Configures the settings used for creating an internal vulkan instance.
+ // May be NULL. Ignored if `instance` is set.
+ const struct pl_vk_inst_params *instance_params;
+
+ // When choosing the device, rule out all devices that don't support
+ // presenting to this surface. When creating a device, enable all extensions
+ // needed to ensure we can present to this surface. Optional. Only legal
+ // when specifying an existing VkInstance to use.
+ VkSurfaceKHR surface;
+
+ // --- Physical device selection options
+
+ // The vulkan physical device. May be set by the caller to indicate the
+ // physical device to use. Otherwise, libplacebo will pick the "best"
+ // available GPU, based on the advertised device type. (i.e., it will
+ // prefer discrete GPUs over integrated GPUs). Only legal when specifying
+ // an existing VkInstance to use.
+ VkPhysicalDevice device;
+
+ // When choosing the device, only choose a device with this exact name.
+ // This overrides `allow_software`. No effect if `device` is set. Note: A
+ // list of devices and their names are logged at level PL_LOG_INFO.
+ const char *device_name;
+
+ // When choosing the device, only choose a device with this exact UUID.
+ // This overrides `allow_software` and `device_name`. No effect if `device`
+ // is set.
+ uint8_t device_uuid[16];
+
+ // When choosing the device, controls whether or not to also allow software
+ // GPUs. No effect if `device` or `device_name` are set.
+ bool allow_software;
+
+ // --- Logical device creation options
+
+ // Controls whether or not to allow asynchronous transfers, using transfer
+ // queue families, if supported by the device. This can be significantly
+ // faster and more power efficient, and also allows streaming uploads in
+ // parallel with rendering commands. Enabled by default.
+ bool async_transfer;
+
+ // Controls whether or not to allow asynchronous compute, using dedicated
+ // compute queue families, if supported by the device. On some devices,
+ // these can allow the GPU to schedule compute shaders in parallel with
+ // fragment shaders. Enabled by default.
+ bool async_compute;
+
+ // Limits the number of queues to use. If left as 0, libplacebo will use as
+ // many queues as the device supports. Multiple queues can result in
+ // improved efficiency when submitting multiple commands that can entirely
+ // or partially execute in parallel. Defaults to 1, since using more queues
+ // can actually decrease performance.
+ //
+ // Note: libplacebo will always *create* logical devices with all available
+ // queues for a given QF enabled, regardless of this setting.
+ int queue_count;
+
+ // Bitmask of extra queue families to enable. If set, then *all* queue
+ // families matching *any* of these flags will be enabled at device
+ // creation time. Setting this to VK_QUEUE_FLAG_BITS_MAX_ENUM effectively
+ // enables all queue families supported by the device.
+ VkQueueFlags extra_queues;
+
+ // Enables extra device extensions. Device creation will fail if these
+ // extensions are not all supported. The user may use this to enable e.g.
+ // interop extensions.
+ const char * const *extensions;
+ int num_extensions;
+
+ // Enables extra optional device extensions. These are opportunistically
+ // enabled if supported by the device, but otherwise skipped.
+ const char * const *opt_extensions;
+ int num_opt_extensions;
+
+ // Optional extra features to enable at device creation time. These are
+ // opportunistically enabled if supported by the physical device, but
+ // otherwise kept disabled.
+ const VkPhysicalDeviceFeatures2 *features;
+
+ // --- Misc/debugging options
+
+ // Restrict specific features to e.g. work around driver bugs, or simply
+ // for testing purposes
+ int max_glsl_version; // limit the maximum GLSL version
+ uint32_t max_api_version; // limit the maximum vulkan API version
+};
+
+// Default/recommended parameters. Should generally be safe and efficient.
+#define PL_VULKAN_DEFAULTS \
+ .async_transfer = true, \
+ .async_compute = true, \
+ /* enabling multiple queues often decreases perf */ \
+ .queue_count = 1,
+
+#define pl_vulkan_params(...) (&(struct pl_vulkan_params) { PL_VULKAN_DEFAULTS __VA_ARGS__ })
+PL_API extern const struct pl_vulkan_params pl_vulkan_default_params;
+
+// Creates a new vulkan device based on the given parameters and initializes
+// a new GPU. If `params` is left as NULL, it defaults to
+// &pl_vulkan_default_params.
+//
+// Thread-safety: Safe
+PL_API pl_vulkan pl_vulkan_create(pl_log log, const struct pl_vulkan_params *params);
+
+// Destroys the vulkan device and all associated objects, except for the
+// VkInstance provided by the user.
+//
+// Note that all resources allocated from this vulkan object (e.g. via the
+// `vk->ra` or using `pl_vulkan_create_swapchain`) *must* be explicitly
+// destroyed by the user before calling this.
+//
+// Also note that this function will block until all in-flight GPU commands are
+// finished processing. You can avoid this by manually calling `pl_gpu_finish`
+// before `pl_vulkan_destroy`.
+PL_API void pl_vulkan_destroy(pl_vulkan *vk);
+
+// For a `pl_gpu` backed by `pl_vulkan`, this function can be used to retrieve
+// the underlying `pl_vulkan`. Returns NULL for any other type of `gpu`.
+PL_API pl_vulkan pl_vulkan_get(pl_gpu gpu);
+
+struct pl_vulkan_device_params {
+ // The instance to use. Required!
+ //
+ // Note: The VkInstance provided by the user *must* be created with a
+ // VkApplicationInfo.apiVersion of PL_VK_MIN_VERSION or higher.
+ VkInstance instance;
+
+ // Mirrored from `pl_vulkan_params`. All of these fields are optional.
+ PFN_vkGetInstanceProcAddr get_proc_addr;
+ VkSurfaceKHR surface;
+ const char *device_name;
+ uint8_t device_uuid[16];
+ bool allow_software;
+};
+
+#define pl_vulkan_device_params(...) (&(struct pl_vulkan_device_params) { __VA_ARGS__ })
+
+// Helper function to choose the best VkPhysicalDevice, given a VkInstance.
+// This uses the same logic as `pl_vulkan_create` uses internally. If no
+// matching device was found, this returns VK_NULL_HANDLE.
+PL_API VkPhysicalDevice pl_vulkan_choose_device(pl_log log,
+ const struct pl_vulkan_device_params *params);
+
+struct pl_vulkan_swapchain_params {
+ // The surface to use for rendering. Required, the user is in charge of
+ // creating this. Must belong to the same VkInstance as `vk->instance`.
+ VkSurfaceKHR surface;
+
+ // The preferred presentation mode. See the vulkan documentation for more
+ // information about these. If the device/surface combination does not
+ // support this mode, libplacebo will fall back to VK_PRESENT_MODE_FIFO_KHR.
+ //
+ // Warning: Leaving this zero-initialized is the same as having specified
+ // VK_PRESENT_MODE_IMMEDIATE_KHR, which is probably not what the user
+ // wants!
+ VkPresentModeKHR present_mode;
+
+ // Allow up to N in-flight frames. This essentially controls how many
+ // rendering commands may be queued up at the same time. See the
+ // documentation for `pl_swapchain_get_latency` for more information. For
+ // vulkan specifically, we are only able to wait until the GPU has finished
+ // rendering a frame - we are unable to wait until the display has actually
+ // finished displaying it. So this only provides a rough guideline.
+ // Optional, defaults to 3.
+ int swapchain_depth;
+
+ // This suppresses automatic recreation of the swapchain when any call
+ // returns VK_SUBOPTIMAL_KHR. Normally, libplacebo will recreate the
+ // swapchain internally on the next `pl_swapchain_start_frame`. If enabled,
+ // clients are assumed to take care of swapchain recreations themselves, by
+ // calling `pl_swapchain_resize` as appropriate. libplacebo will tolerate
+ // the "suboptimal" status indefinitely.
+ bool allow_suboptimal;
+
+ // Disable high-bit (10 or more) SDR formats. May help work around buggy
+ // drivers which don't dither properly when outputting high bit depth
+ // SDR backbuffers to 8-bit screens.
+ bool disable_10bit_sdr;
+};
+
+#define pl_vulkan_swapchain_params(...) (&(struct pl_vulkan_swapchain_params) { __VA_ARGS__ })
+
+// Creates a new vulkan swapchain based on an existing VkSurfaceKHR. Using this
+// function requires that the vulkan device was created with the
+// VK_KHR_swapchain extension. The easiest way of accomplishing this is to set
+// the `pl_vulkan_params.surface` explicitly at creation time.
+PL_API pl_swapchain pl_vulkan_create_swapchain(pl_vulkan vk,
+ const struct pl_vulkan_swapchain_params *params);
+
+// This will return true if the vulkan swapchain is internally detected
+// as being suboptimal (VK_SUBOPTIMAL_KHR). This might be of use to clients
+// who have `params->allow_suboptimal` enabled.
+PL_API bool pl_vulkan_swapchain_suboptimal(pl_swapchain sw);
+
+// Vulkan interop API, for sharing a single VkDevice (and associated vulkan
+// resources) directly with the API user. The use of this API is a bit sketchy
+// and requires careful communication of Vulkan API state.
+
+struct pl_vulkan_import_params {
+ // The vulkan instance. Required.
+ //
+ // Note: The VkInstance provided by the user *must* be created with a
+ // VkApplicationInfo.apiVersion of PL_VK_MIN_VERSION or higher.
+ VkInstance instance;
+
+ // Pointer to `vkGetInstanceProcAddr`. If this is NULL, libplacebo will
+ // use the directly linked version (if available).
+ PFN_vkGetInstanceProcAddr get_proc_addr;
+
+ // The physical device selected by the user. Required.
+ VkPhysicalDevice phys_device;
+
+ // The logical device created by the user. Required.
+ VkDevice device;
+
+ // --- Logical device parameters
+
+ // List of all device-level extensions that were enabled. (Instance-level
+ // extensions need not be re-specified here, since it's guaranteed that any
+ // instance-level extensions that device-level extensions depend on were
+ // enabled at the instance level)
+ const char * const *extensions;
+ int num_extensions;
+
+ // Enabled queue families. At least `queue_graphics` is required.
+ //
+ // It's okay for multiple queue families to be specified with the same
+ // index, e.g. in the event that a dedicated compute queue also happens to
+ // be the dedicated transfer queue.
+ //
+ // It's also okay to leave the queue struct as {0} in the event that no
+ // dedicated queue exists for a given operation type. libplacebo will
+ // automatically fall back to using e.g. the graphics queue instead.
+ struct pl_vulkan_queue queue_graphics; // must support VK_QUEUE_GRAPHICS_BIT
+ struct pl_vulkan_queue queue_compute; // must support VK_QUEUE_COMPUTE_BIT
+ struct pl_vulkan_queue queue_transfer; // must support VK_QUEUE_TRANSFER_BIT
+
+ // Enabled VkPhysicalDeviceFeatures. The device *must* be created with
+ // all of the features in `pl_vulkan_required_features` enabled.
+ const VkPhysicalDeviceFeatures2 *features;
+
+ // Functions for locking a queue. If set, these will be used instead of
+ // libplacebo's internal functions for `pl_vulkan.(un)lock_queue`.
+ void (*lock_queue)(void *ctx, uint32_t qf, uint32_t qidx);
+ void (*unlock_queue)(void *ctx, uint32_t qf, uint32_t qidx);
+ void *queue_ctx;
+
+ // --- Misc/debugging options
+
+ // Restrict specific features to e.g. work around driver bugs, or simply
+ // for testing purposes. See `pl_vulkan_params` for a description of these.
+ int max_glsl_version;
+ uint32_t max_api_version;
+};
+
+#define pl_vulkan_import_params(...) (&(struct pl_vulkan_import_params) { __VA_ARGS__ })
+
+// For purely informative reasons, this contains a list of extensions and
+// device features that libplacebo *can* make use of. These are all strictly
+// optional, but provide a hint to the API user as to what might be worth
+// enabling at device creation time.
+//
+// Note: This also includes physical device features provided by extensions.
+// They are all provided using extension-specific features structs, rather
+// than the more general purpose VkPhysicalDeviceVulkan11Features etc.
+PL_API extern const char * const pl_vulkan_recommended_extensions[];
+PL_API extern const int pl_vulkan_num_recommended_extensions;
+PL_API extern const VkPhysicalDeviceFeatures2 pl_vulkan_recommended_features;
+
+// A list of device features that are required by libplacebo. These
+// *must* be provided by imported Vulkan devices.
+//
+// Note: `pl_vulkan_recommended_features` does not include this list.
+PL_API extern const VkPhysicalDeviceFeatures2 pl_vulkan_required_features;
+
+// Import an existing VkDevice instead of creating a new one, and wrap it into
+// a `pl_vulkan` abstraction. It's safe to `pl_vulkan_destroy` this, which will
+// destroy application state related to libplacebo but leave the underlying
+// VkDevice intact.
+PL_API pl_vulkan pl_vulkan_import(pl_log log, const struct pl_vulkan_import_params *params);
+
+struct pl_vulkan_wrap_params {
+ // The image itself. It *must* be usable concurrently by all of the queue
+ // family indices listed in `pl_vulkan->queues`. Note that this requires
+ // the use of VK_SHARING_MODE_CONCURRENT if `pl_vulkan->num_queues` is
+ // greater than 1. If this is difficult to achieve for the user, then
+ // `async_transfer` / `async_compute` should be turned off, which
+ // guarantees the use of only one queue family.
+ VkImage image;
+
+ // Which aspect of `image` to wrap. Only useful for wrapping individual
+ // sub-planes of planar images. If left as 0, it defaults to the entire
+ // image (i.e. the union of VK_IMAGE_ASPECT_PLANE_N_BIT for planar formats,
+ // and VK_IMAGE_ASPECT_COLOR_BIT otherwise).
+ VkImageAspectFlags aspect;
+
+ // The image's dimensions (unused dimensions must be 0)
+ int width;
+ int height;
+ int depth;
+
+ // The image's format. libplacebo will try to map this to an equivalent
+ // pl_fmt. If no compatible pl_fmt is found, wrapping will fail.
+ VkFormat format;
+
+ // The usage flags the image was created with. libplacebo will set the
+ // pl_tex capabilities to include whatever it can, as determined by the set
+ // of enabled usage flags.
+ VkImageUsageFlags usage;
+
+ // See `pl_tex_params`
+ void *user_data;
+ pl_debug_tag debug_tag;
+};
+
+#define pl_vulkan_wrap_params(...) (&(struct pl_vulkan_wrap_params) { \
+ .debug_tag = PL_DEBUG_TAG, \
+ __VA_ARGS__ \
+ })
+
+// Wraps an external VkImage into a pl_tex abstraction. By default, the image
+// is considered "held" by the user and must be released before calling any
+// pl_tex_* API calls on it (see `pl_vulkan_release`).
+//
+// This wrapper can be destroyed by simply calling `pl_tex_destroy` on it,
+// which will not destroy the underlying VkImage. If a pl_tex wrapper is
+// destroyed while an image is not currently being held by the user, that
+// image is left in an undefined state.
+//
+// Wrapping the same VkImage multiple times is undefined behavior, as is trying
+// to wrap an image belonging to a different VkDevice than the one in use by
+// `gpu`.
+//
+// This function may fail, in which case it returns NULL.
+PL_API pl_tex pl_vulkan_wrap(pl_gpu gpu, const struct pl_vulkan_wrap_params *params);
+
+// Analogous to `pl_vulkan_wrap`, this function takes any `pl_tex` (including
+// ones created by `pl_tex_create`) and unwraps it to expose the underlying
+// VkImage to the user. Unlike `pl_vulkan_wrap`, this `pl_tex` is *not*
+// considered held after calling this function - the user must explicitly
+// `pl_vulkan_hold` before accessing the VkImage.
+//
+// `out_format` and `out_flags` will be updated to hold the VkImage's
+// format and usage flags. (Optional)
+PL_API VkImage pl_vulkan_unwrap(pl_gpu gpu, pl_tex tex,
+ VkFormat *out_format, VkImageUsageFlags *out_flags);
+
+// Represents a vulkan semaphore/value pair (for compatibility with timeline
+// semaphores). When using normal, binary semaphores, `value` may be ignored.
+typedef struct pl_vulkan_sem {
+ VkSemaphore sem;
+ uint64_t value;
+} pl_vulkan_sem;
+
+struct pl_vulkan_hold_params {
+ // The Vulkan image to hold. It will be marked as held. Attempting to
+ // perform any pl_tex_* operation (except pl_tex_destroy) on a held image
+ // is undefined behavior.
+ pl_tex tex;
+
+ // The layout to transition the image to when holding. Alternatively, a
+ // pointer to receive the current image layout. If `out_layout` is
+ // provided, `layout` is ignored.
+ VkImageLayout layout;
+ VkImageLayout *out_layout;
+
+ // The queue family index to transition the image to. This can be used with
+ // VK_QUEUE_FAMILY_EXTERNAL to transition the image to an external API. As
+ // a special case, if set to VK_QUEUE_FAMILY_IGNORED, libplacebo will not
+ // transition the image, even if this image was not set up for concurrent
+ // usage. Ignored for concurrent images.
+ uint32_t qf;
+
+ // The semaphore to fire when the image is available for use. (Required)
+ pl_vulkan_sem semaphore;
+};
+
+#define pl_vulkan_hold_params(...) (&(struct pl_vulkan_hold_params) { __VA_ARGS__ })
+
+// "Hold" a shared image, transferring control over the image to the user.
+// Returns whether successful.
+PL_API bool pl_vulkan_hold_ex(pl_gpu gpu, const struct pl_vulkan_hold_params *params);
+
+struct pl_vulkan_release_params {
+ // The image to be released. It must be marked as "held". Performing any
+ // operation on the VkImage underlying this `pl_tex` while it is not being
+ // held by the user is undefined behavior.
+ pl_tex tex;
+
+ // The current layout of the image at the point in time when `semaphore`
+ // fires, or if no semaphore is specified, at the time of call.
+ VkImageLayout layout;
+
+ // The queue family index to transition the image to. This can be used with
+ // VK_QUEUE_FAMILY_EXTERNAL to transition the image rom an external API. As
+ // a special case, if set to VK_QUEUE_FAMILY_IGNORED, libplacebo will not
+ // transition the image, even if this image was not set up for concurrent
+ // usage. Ignored for concurrent images.
+ uint32_t qf;
+
+ // The semaphore to wait on before libplacebo will actually use or modify
+ // the image. (Optional)
+ //
+ // Note: the lifetime of `semaphore` is indeterminate, and destroying it
+ // while the texture is still depending on that semaphore is undefined
+ // behavior.
+ //
+ // Technically, the only way to be sure that it's safe to free is to use
+ // `pl_gpu_finish()` or similar (e.g. `pl_vulkan_destroy` or
+ // `vkDeviceWaitIdle`) after another operation involving `tex` has been
+ // emitted (or the texture has been destroyed).
+ //
+ //
+ // Warning: If `tex` is a planar image (`pl_fmt.num_planes > 0`), and
+ // `semaphore` is specified, it *must* be a timeline semaphore! Failure to
+ // respect this will result in undefined behavior. This warning does not
+ // apply to individual planes (as exposed by `pl_tex.planes`).
+ pl_vulkan_sem semaphore;
+};
+
+#define pl_vulkan_release_params(...) (&(struct pl_vulkan_release_params) { __VA_ARGS__ })
+
+// "Release" a shared image, transferring control to libplacebo.
+PL_API void pl_vulkan_release_ex(pl_gpu gpu, const struct pl_vulkan_release_params *params);
+
+struct pl_vulkan_sem_params {
+ // The type of semaphore to create.
+ VkSemaphoreType type;
+
+ // For VK_SEMAPHORE_TYPE_TIMELINE, sets the initial timeline value.
+ uint64_t initial_value;
+
+ // If set, exports this VkSemaphore to the handle given in `out_handle`.
+ // The user takes over ownership, and should manually close it before
+ // destroying this VkSemaphore (via `pl_vulkan_sem_destroy`).
+ enum pl_handle_type export_handle;
+ union pl_handle *out_handle;
+
+ // Optional debug tag to identify this semaphore.
+ pl_debug_tag debug_tag;
+};
+
+#define pl_vulkan_sem_params(...) (&(struct pl_vulkan_sem_params) { \
+ .debug_tag = PL_DEBUG_TAG, \
+ __VA_ARGS__ \
+ })
+
+// Helper functions to create and destroy vulkan semaphores. Returns
+// VK_NULL_HANDLE on failure.
+PL_API VkSemaphore pl_vulkan_sem_create(pl_gpu gpu, const struct pl_vulkan_sem_params *params);
+PL_API void pl_vulkan_sem_destroy(pl_gpu gpu, VkSemaphore *semaphore);
+
+// Backwards-compatibility wrappers for older versions of the API.
+PL_DEPRECATED PL_API bool pl_vulkan_hold(pl_gpu gpu, pl_tex tex, VkImageLayout layout,
+ pl_vulkan_sem sem_out);
+PL_DEPRECATED PL_API bool pl_vulkan_hold_raw(pl_gpu gpu, pl_tex tex, VkImageLayout *out_layout,
+ pl_vulkan_sem sem_out);
+PL_DEPRECATED PL_API void pl_vulkan_release(pl_gpu gpu, pl_tex tex, VkImageLayout layout,
+ pl_vulkan_sem sem_in);
+
+PL_API_END
+
+#endif // LIBPLACEBO_VULKAN_H_