c/util: Enable swapchain to be sub-classed

This commit is contained in:
Jakob Bornecrantz 2022-08-15 14:38:08 +01:00 committed by Jakob Bornecrantz
parent d578203a8e
commit 06ee685e9a
2 changed files with 227 additions and 92 deletions

View file

@ -89,14 +89,18 @@ swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index)
}
static struct comp_swapchain *
alloc_and_set_funcs(struct vk_bundle *vk, struct comp_swapchain_gc *cscgc, uint32_t image_count)
set_common_fields(struct comp_swapchain *sc,
comp_swapchain_destroy_func_t destroy_func,
struct vk_bundle *vk,
struct comp_swapchain_gc *cscgc,
uint32_t image_count)
{
struct comp_swapchain *sc = U_TYPED_CALLOC(struct comp_swapchain);
sc->base.base.destroy = swapchain_destroy;
sc->base.base.acquire_image = swapchain_acquire_image;
sc->base.base.wait_image = swapchain_wait_image;
sc->base.base.release_image = swapchain_release_image;
sc->base.base.image_count = image_count;
sc->real_destroy = destroy_func;
sc->vk = vk;
sc->gc = cscgc;
@ -257,9 +261,143 @@ image_cleanup(struct vk_bundle *vk, struct comp_swapchain_image *image)
D(Sampler, image->repeat_sampler);
}
/*!
* Swapchain destruct is delayed until it is safe to destroy them, this function
* does the actual destruction and is called from @ref
* comp_swapchain_garbage_collect.
*
* @ingroup comp_util
*/
static void
really_destroy(struct comp_swapchain *sc)
{
// Re-use close function.
comp_swapchain_teardown(sc);
free(sc);
}
/*
*
* 'Exported' functions.
* 'Exported' parent-class functions.
*
*/
xrt_result_t
comp_swapchain_create_init(struct comp_swapchain *sc,
comp_swapchain_destroy_func_t destroy_func,
struct vk_bundle *vk,
struct comp_swapchain_gc *cscgc,
const struct xrt_swapchain_create_info *info,
const struct xrt_swapchain_create_properties *xsccp)
{
VkResult ret;
VK_DEBUG(vk, "CREATE %p %dx%d %s (%ld)", (void *)sc, //
info->width, info->height, //
vk_format_string(info->format), info->format);
if ((info->create & XRT_SWAPCHAIN_CREATE_PROTECTED_CONTENT) != 0) {
VK_WARN(vk,
"Swapchain info is valid but this compositor doesn't support creating protected content "
"swapchains!");
return XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED;
}
set_common_fields(sc, destroy_func, vk, cscgc, xsccp->image_count);
// Use the image helper to allocate the images.
ret = vk_ic_allocate(vk, info, xsccp->image_count, &sc->vkic);
if (ret == VK_ERROR_FEATURE_NOT_PRESENT) {
return XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED;
} else if (ret == VK_ERROR_FORMAT_NOT_SUPPORTED) {
return XRT_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED;
} else if (ret != VK_SUCCESS) {
return XRT_ERROR_VULKAN;
}
xrt_graphics_buffer_handle_t handles[ARRAY_SIZE(sc->vkic.images)];
vk_ic_get_handles(vk, &sc->vkic, ARRAY_SIZE(handles), handles);
for (uint32_t i = 0; i < sc->vkic.image_count; i++) {
sc->base.images[i].handle = handles[i];
sc->base.images[i].size = sc->vkic.images[i].size;
sc->base.images[i].use_dedicated_allocation = sc->vkic.images[i].use_dedicated_allocation;
}
do_post_create_vulkan_setup(vk, info, sc);
return XRT_SUCCESS;
}
xrt_result_t
comp_swapchain_import_init(struct comp_swapchain *sc,
comp_swapchain_destroy_func_t destroy_func,
struct vk_bundle *vk,
struct comp_swapchain_gc *cscgc,
const struct xrt_swapchain_create_info *info,
struct xrt_image_native *native_images,
uint32_t native_image_count)
{
VkResult ret;
VK_DEBUG(vk, "IMPORT %p %dx%d %s (%ld)", (void *)sc, //
info->width, info->height, //
vk_format_string(info->format), info->format);
set_common_fields(sc, destroy_func, vk, cscgc, native_image_count);
// Use the image helper to get the images.
ret = vk_ic_from_natives(vk, info, native_images, native_image_count, &sc->vkic);
if (ret != VK_SUCCESS) {
return XRT_ERROR_VULKAN;
}
do_post_create_vulkan_setup(vk, info, sc);
return XRT_SUCCESS;
}
void
comp_swapchain_teardown(struct comp_swapchain *sc)
{
struct vk_bundle *vk = sc->vk;
VK_TRACE(vk, "REALLY DESTROY");
for (uint32_t i = 0; i < sc->base.base.image_count; i++) {
image_cleanup(vk, &sc->images[i]);
}
for (uint32_t i = 0; i < sc->base.base.image_count; i++) {
u_graphics_buffer_unref(&sc->base.images[i].handle);
}
vk_ic_destroy(vk, &sc->vkic);
}
/*
*
* 'Exported' garbage collection functions.
*
*/
void
comp_swapchain_garbage_collect(struct comp_swapchain_gc *cscgc)
{
struct comp_swapchain *sc;
while ((sc = u_threading_stack_pop(&cscgc->destroy_swapchains))) {
sc->real_destroy(sc);
}
}
/*
*
* 'Exported' default implementation.
*
*/
@ -286,50 +424,25 @@ comp_swapchain_create(struct vk_bundle *vk,
const struct xrt_swapchain_create_properties *xsccp,
struct xrt_swapchain **out_xsc)
{
VkResult ret;
struct comp_swapchain *sc = U_TYPED_CALLOC(struct comp_swapchain);
xrt_result_t xret;
if ((info->create & XRT_SWAPCHAIN_CREATE_PROTECTED_CONTENT) != 0) {
VK_WARN(vk,
"Swapchain info is valid but this compositor doesn't support creating protected content "
"swapchains!");
return XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED;
}
struct comp_swapchain *sc = alloc_and_set_funcs(vk, cscgc, xsccp->image_count);
VK_DEBUG(vk, "CREATE %p %dx%d %s (%ld)", (void *)sc, //
info->width, info->height, //
vk_format_string(info->format), info->format);
// Use the image helper to allocate the images.
ret = vk_ic_allocate(vk, info, xsccp->image_count, &sc->vkic);
if (ret == VK_ERROR_FEATURE_NOT_PRESENT) {
xret = comp_swapchain_create_init( //
sc, //
really_destroy, //
vk, //
cscgc, //
info, //
xsccp); //
if (xret != XRT_SUCCESS) {
free(sc);
return XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED;
} else if (ret == VK_ERROR_FORMAT_NOT_SUPPORTED) {
free(sc);
return XRT_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED;
return xret;
}
if (ret != VK_SUCCESS) {
free(sc);
return XRT_ERROR_VULKAN;
}
xrt_graphics_buffer_handle_t handles[ARRAY_SIZE(sc->vkic.images)];
vk_ic_get_handles(vk, &sc->vkic, ARRAY_SIZE(handles), handles);
for (uint32_t i = 0; i < sc->vkic.image_count; i++) {
sc->base.images[i].handle = handles[i];
sc->base.images[i].size = sc->vkic.images[i].size;
sc->base.images[i].use_dedicated_allocation = sc->vkic.images[i].use_dedicated_allocation;
}
do_post_create_vulkan_setup(vk, info, sc);
// Correctly setup refcounts.
xrt_swapchain_reference(out_xsc, &sc->base.base);
return XRT_SUCCESS;
return xret;
}
xrt_result_t
@ -337,64 +450,27 @@ comp_swapchain_import(struct vk_bundle *vk,
struct comp_swapchain_gc *cscgc,
const struct xrt_swapchain_create_info *info,
struct xrt_image_native *native_images,
uint32_t images_count,
uint32_t native_image_count,
struct xrt_swapchain **out_xsc)
{
VkResult ret;
struct comp_swapchain *sc = U_TYPED_CALLOC(struct comp_swapchain);
xrt_result_t xret;
struct comp_swapchain *sc = alloc_and_set_funcs(vk, cscgc, images_count);
VK_DEBUG(vk, "IMPORT %p %dx%d %s (%ld)", (void *)sc, //
info->width, info->height, //
vk_format_string(info->format), info->format);
// Use the image helper to get the images.
ret = vk_ic_from_natives(vk, info, native_images, images_count, &sc->vkic);
if (ret != VK_SUCCESS) {
return XRT_ERROR_VULKAN;
xret = comp_swapchain_import_init( //
sc, //
really_destroy, //
vk, //
cscgc, //
info, //
native_images, //
native_image_count); //
if (xret != XRT_SUCCESS) {
free(sc);
return xret;
}
do_post_create_vulkan_setup(vk, info, sc);
// Correctly setup refcounts.
xrt_swapchain_reference(out_xsc, &sc->base.base);
return XRT_SUCCESS;
}
/*!
* Swapchain destruct is delayed until it is safe to destroy them, this function
* does the actual destruction and is called from @ref
* comp_swapchain_garbage_collect.
*
* @ingroup comp_util
*/
static void
comp_swapchain_really_destroy(struct comp_swapchain *sc)
{
struct vk_bundle *vk = sc->vk;
VK_TRACE(vk, "REALLY DESTROY");
for (uint32_t i = 0; i < sc->base.base.image_count; i++) {
image_cleanup(vk, &sc->images[i]);
}
for (uint32_t i = 0; i < sc->base.base.image_count; i++) {
u_graphics_buffer_unref(&sc->base.images[i].handle);
}
vk_ic_destroy(vk, &sc->vkic);
free(sc);
}
void
comp_swapchain_garbage_collect(struct comp_swapchain_gc *cscgc)
{
struct comp_swapchain *sc;
while ((sc = u_threading_stack_pop(&cscgc->destroy_swapchains))) {
comp_swapchain_really_destroy(sc);
}
return xret;
}

View file

@ -21,6 +21,16 @@ extern "C" {
#endif
struct comp_swapchain;
/*!
* Callback for implementing own destroy function, should call
* @ref comp_swapchain_teardown and is responsible for memory.
*
* @ingroup comp_util
*/
typedef void (*comp_swapchain_destroy_func_t)(struct comp_swapchain *sc);
/*!
* A garbage collector that collects swapchains to be safely destroyed.
*
@ -81,6 +91,9 @@ struct comp_swapchain
* image, this should probably be made even smarter.
*/
struct u_index_fifo fifo;
//! Virtual real destroy function.
comp_swapchain_destroy_func_t real_destroy;
};
@ -103,6 +116,52 @@ comp_swapchain(struct xrt_swapchain *xsc)
}
/*
*
* 'Exported' parent-class functions.
*
*/
/*!
* Helper to init a comp_swachain struct as if it was a create operation,
* useful for wrapping comp_swapchain within another struct. Ref-count is
* set to zero so the caller need to init it correctly.
*
* @ingroup comp_util
*/
xrt_result_t
comp_swapchain_create_init(struct comp_swapchain *sc,
comp_swapchain_destroy_func_t destroy_func,
struct vk_bundle *vk,
struct comp_swapchain_gc *cscgc,
const struct xrt_swapchain_create_info *info,
const struct xrt_swapchain_create_properties *xsccp);
/*!
* Helper to init a comp_swachain struct as if it was a import operation,
* useful for wrapping comp_swapchain within another struct. Ref-count is
* set to zero so the caller need to init it correctly.
*
* @ingroup comp_util
*/
xrt_result_t
comp_swapchain_import_init(struct comp_swapchain *sc,
comp_swapchain_destroy_func_t destroy_func,
struct vk_bundle *vk,
struct comp_swapchain_gc *cscgc,
const struct xrt_swapchain_create_info *info,
struct xrt_image_native *native_images,
uint32_t native_image_count);
/*!
* De-inits a comp_swapchain, usable for classes sub-classing comp_swapchain.
*
* @ingroup comp_util
*/
void
comp_swapchain_teardown(struct comp_swapchain *sc);
/*
*
* 'Exported' garbage collection functions.