2019-03-18 05:52:32 +00:00
|
|
|
// Copyright 2019, Collabora, Ltd.
|
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Swapchain code for the main compositor.
|
|
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
2020-03-01 10:31:21 +00:00
|
|
|
* @ingroup comp_main
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
|
2019-03-21 20:19:52 +00:00
|
|
|
#include "util/u_misc.h"
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
#include "main/comp_compositor.h"
|
|
|
|
|
2020-05-30 15:58:34 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
swapchain_destroy(struct xrt_swapchain *xsc)
|
|
|
|
{
|
|
|
|
struct comp_swapchain *sc = comp_swapchain(xsc);
|
|
|
|
|
|
|
|
COMP_SPEW(sc->c, "DESTROY");
|
|
|
|
|
2020-04-15 16:37:34 +00:00
|
|
|
u_threading_stack_push(&sc->c->threading.destroy_swapchains, sc);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
swapchain_acquire_image(struct xrt_swapchain *xsc, uint32_t *index)
|
|
|
|
{
|
|
|
|
struct comp_swapchain *sc = comp_swapchain(xsc);
|
|
|
|
|
|
|
|
COMP_SPEW(sc->c, "ACQUIRE_IMAGE");
|
2020-05-30 15:39:35 +00:00
|
|
|
|
|
|
|
// Returns negative on empty fifo.
|
|
|
|
return u_index_fifo_pop(&sc->fifo, index) >= 0;
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
swapchain_wait_image(struct xrt_swapchain *xsc,
|
|
|
|
uint64_t timeout,
|
|
|
|
uint32_t index)
|
|
|
|
{
|
|
|
|
struct comp_swapchain *sc = comp_swapchain(xsc);
|
|
|
|
|
|
|
|
COMP_SPEW(sc->c, "WAIT_IMAGE");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index)
|
|
|
|
{
|
|
|
|
struct comp_swapchain *sc = comp_swapchain(xsc);
|
|
|
|
|
|
|
|
COMP_SPEW(sc->c, "RELEASE_IMAGE");
|
2020-05-30 15:39:35 +00:00
|
|
|
|
|
|
|
u_index_fifo_push(&sc->fifo, index);
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-03-25 15:44:01 +00:00
|
|
|
static VkResult
|
|
|
|
get_device_memory_fd(struct comp_compositor *c,
|
|
|
|
VkDeviceMemory device_memory,
|
|
|
|
int *out_fd)
|
|
|
|
{
|
|
|
|
|
|
|
|
// vkGetMemoryFdKHR parameter
|
|
|
|
VkMemoryGetFdInfoKHR fd_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
|
|
|
|
.memory = device_memory,
|
|
|
|
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
|
|
|
|
};
|
|
|
|
int fd;
|
|
|
|
VkResult ret = c->vk.vkGetMemoryFdKHR(c->vk.device, &fd_info, &fd);
|
|
|
|
if (ret != VK_SUCCESS) {
|
|
|
|
COMP_ERROR(c, "->image - vkGetMemoryFdKHR: %s",
|
|
|
|
vk_result_string(ret));
|
|
|
|
return VK_ERROR_FEATURE_NOT_PRESENT;
|
|
|
|
}
|
|
|
|
*out_fd = fd;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
static VkResult
|
|
|
|
create_image_fd(struct comp_compositor *c,
|
2019-08-16 22:06:28 +00:00
|
|
|
enum xrt_swapchain_usage_bits swapchain_usage,
|
2019-03-18 05:52:32 +00:00
|
|
|
int64_t format,
|
|
|
|
uint32_t width,
|
|
|
|
uint32_t height,
|
2019-04-30 15:22:19 +00:00
|
|
|
uint32_t array_size,
|
2019-03-18 05:52:32 +00:00
|
|
|
uint32_t mip_count,
|
|
|
|
VkImage *out_image,
|
|
|
|
VkDeviceMemory *out_mem,
|
|
|
|
struct xrt_image_fd *out_image_fd)
|
|
|
|
{
|
2019-10-07 19:40:20 +00:00
|
|
|
VkImageUsageFlags image_usage =
|
|
|
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
2019-03-25 15:44:01 +00:00
|
|
|
VkDeviceMemory device_memory = VK_NULL_HANDLE;
|
|
|
|
VkImage image = VK_NULL_HANDLE;
|
|
|
|
VkResult ret = VK_SUCCESS;
|
2020-04-29 22:47:32 +00:00
|
|
|
VkDeviceSize size;
|
2019-03-18 05:52:32 +00:00
|
|
|
int fd;
|
|
|
|
|
|
|
|
COMP_SPEW(c, "->image - vkCreateImage %dx%d", width, height);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the image.
|
|
|
|
*/
|
|
|
|
|
|
|
|
VkExternalMemoryImageCreateInfoKHR external_memory_image_create_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
|
|
|
|
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
|
|
|
|
};
|
|
|
|
|
2019-08-16 22:06:28 +00:00
|
|
|
if ((swapchain_usage & XRT_SWAPCHAIN_USAGE_COLOR) != 0) {
|
|
|
|
image_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
|
|
}
|
|
|
|
if ((swapchain_usage & XRT_SWAPCHAIN_USAGE_DEPTH_STENCIL) != 0) {
|
|
|
|
image_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
|
|
|
}
|
|
|
|
if ((swapchain_usage & XRT_SWAPCHAIN_USAGE_UNORDERED_ACCESS) != 0) {
|
|
|
|
image_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
|
|
|
}
|
|
|
|
if ((swapchain_usage & XRT_SWAPCHAIN_USAGE_TRANSFER_SRC) != 0) {
|
|
|
|
image_usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
|
|
}
|
|
|
|
if ((swapchain_usage & XRT_SWAPCHAIN_USAGE_TRANSFER_DST) != 0) {
|
|
|
|
image_usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
|
|
}
|
|
|
|
if ((swapchain_usage & XRT_SWAPCHAIN_USAGE_SAMPLED) != 0) {
|
|
|
|
image_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
VkImageCreateInfo info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
|
|
.pNext = &external_memory_image_create_info,
|
|
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
2019-03-21 20:34:57 +00:00
|
|
|
.format = (VkFormat)format,
|
2019-03-18 05:52:32 +00:00
|
|
|
.extent = {.width = width, .height = height, .depth = 1},
|
|
|
|
.mipLevels = mip_count,
|
2019-04-30 15:22:19 +00:00
|
|
|
.arrayLayers = array_size,
|
2019-03-18 05:52:32 +00:00
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
|
|
.usage = image_usage,
|
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
};
|
|
|
|
|
|
|
|
ret = c->vk.vkCreateImage(c->vk.device, &info, NULL, &image);
|
|
|
|
if (ret != VK_SUCCESS) {
|
|
|
|
COMP_ERROR(c, "->image - vkCreateImage: %s",
|
|
|
|
vk_result_string(ret));
|
2019-03-25 15:44:01 +00:00
|
|
|
// Nothing to cleanup
|
|
|
|
return ret;
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-03-25 15:44:01 +00:00
|
|
|
* Create and bind the memory.
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
2019-03-25 15:44:01 +00:00
|
|
|
// vkAllocateMemory parameters
|
2019-03-18 05:52:32 +00:00
|
|
|
VkMemoryDedicatedAllocateInfoKHR dedicated_memory_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
|
|
|
|
.image = image,
|
|
|
|
.buffer = VK_NULL_HANDLE,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkExportMemoryAllocateInfo export_alloc_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
|
|
|
|
.pNext = &dedicated_memory_info,
|
|
|
|
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
|
|
|
|
};
|
|
|
|
|
2019-03-25 15:44:01 +00:00
|
|
|
ret = vk_alloc_and_bind_image_memory(
|
|
|
|
&c->vk, image, SIZE_MAX, &export_alloc_info, &device_memory, &size);
|
2019-03-18 05:52:32 +00:00
|
|
|
if (ret != VK_SUCCESS) {
|
|
|
|
COMP_ERROR(c, "->image - vkAllocateMemory: %s",
|
|
|
|
vk_result_string(ret));
|
|
|
|
goto err_image;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the fd.
|
|
|
|
*/
|
2019-03-25 15:44:01 +00:00
|
|
|
ret = get_device_memory_fd(c, device_memory, &fd);
|
2019-03-18 05:52:32 +00:00
|
|
|
if (ret != VK_SUCCESS) {
|
|
|
|
goto err_mem;
|
|
|
|
}
|
|
|
|
|
2019-03-25 15:44:01 +00:00
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
*out_image = image;
|
|
|
|
*out_mem = device_memory;
|
|
|
|
out_image_fd->fd = fd;
|
|
|
|
out_image_fd->size = size;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
err_mem:
|
|
|
|
c->vk.vkFreeMemory(c->vk.device, device_memory, NULL);
|
|
|
|
err_image:
|
|
|
|
c->vk.vkDestroyImage(c->vk.device, image, NULL);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-04-15 16:37:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Exported functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
struct xrt_swapchain *
|
|
|
|
comp_swapchain_create(struct xrt_compositor *xc,
|
|
|
|
enum xrt_swapchain_create_flags create,
|
|
|
|
enum xrt_swapchain_usage_bits bits,
|
|
|
|
int64_t format,
|
|
|
|
uint32_t sample_count,
|
|
|
|
uint32_t width,
|
|
|
|
uint32_t height,
|
|
|
|
uint32_t face_count,
|
|
|
|
uint32_t array_size,
|
|
|
|
uint32_t mip_count)
|
|
|
|
{
|
|
|
|
struct comp_compositor *c = comp_compositor(xc);
|
|
|
|
VkCommandBuffer cmd_buffer;
|
|
|
|
uint32_t num_images = 3;
|
|
|
|
VkResult ret;
|
|
|
|
|
|
|
|
|
2020-05-27 18:56:01 +00:00
|
|
|
if ((create & XRT_SWAPCHAIN_CREATE_STATIC_IMAGE) != 0) {
|
|
|
|
num_images = 1;
|
|
|
|
}
|
|
|
|
|
2019-03-21 20:19:52 +00:00
|
|
|
struct comp_swapchain *sc = U_TYPED_CALLOC(struct comp_swapchain);
|
2019-03-18 05:52:32 +00:00
|
|
|
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.num_images = num_images;
|
2019-10-07 22:26:43 +00:00
|
|
|
sc->base.base.array_size = array_size;
|
2019-03-18 05:52:32 +00:00
|
|
|
sc->c = c;
|
|
|
|
|
|
|
|
COMP_DEBUG(c, "CREATE %p %dx%d", (void *)sc, width, height);
|
|
|
|
|
2020-05-30 15:58:34 +00:00
|
|
|
// Make sure the fds are invalid.
|
|
|
|
for (uint32_t i = 0; i < ARRAY_SIZE(sc->base.images); i++) {
|
|
|
|
sc->base.images[i].fd = -1;
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
for (uint32_t i = 0; i < num_images; i++) {
|
2019-04-30 15:22:19 +00:00
|
|
|
ret =
|
2019-08-16 22:06:28 +00:00
|
|
|
create_image_fd(c, bits, format, width, height, array_size,
|
2019-04-30 15:22:19 +00:00
|
|
|
mip_count, &sc->images[i].image,
|
|
|
|
&sc->images[i].memory, &sc->base.images[i]);
|
2019-03-18 05:52:32 +00:00
|
|
|
if (ret != VK_SUCCESS) {
|
2019-08-16 21:59:19 +00:00
|
|
|
//! @todo memory leak of image fds and swapchain
|
|
|
|
// see
|
|
|
|
// https://gitlab.freedesktop.org/monado/monado/issues/20
|
2019-03-18 05:52:32 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
vk_create_sampler(&c->vk, &sc->images[i].sampler);
|
2019-05-01 15:17:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < num_images; i++) {
|
|
|
|
sc->images[i].views =
|
|
|
|
U_TYPED_ARRAY_CALLOC(VkImageView, array_size);
|
|
|
|
|
|
|
|
for (uint32_t layer = 0; layer < array_size; ++layer) {
|
|
|
|
VkImageSubresourceRange subresource_range = {
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = 1,
|
|
|
|
.baseArrayLayer = layer,
|
|
|
|
.layerCount = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
vk_create_view(&c->vk, sc->images[i].image,
|
|
|
|
(VkFormat)format, subresource_range,
|
|
|
|
&sc->images[i].views[layer]);
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2020-05-30 15:39:35 +00:00
|
|
|
// Prime the fifo
|
|
|
|
for (uint32_t i = 0; i < num_images; i++) {
|
|
|
|
u_index_fifo_push(&sc->fifo, i);
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Transition image.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
vk_init_cmd_buffer(&c->vk, &cmd_buffer);
|
|
|
|
|
2019-05-01 15:17:17 +00:00
|
|
|
VkImageSubresourceRange subresource_range = {
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = 1,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = array_size,
|
|
|
|
};
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
for (uint32_t i = 0; i < num_images; i++) {
|
|
|
|
vk_set_image_layout(&c->vk, cmd_buffer, sc->images[i].image, 0,
|
|
|
|
VK_ACCESS_SHADER_READ_BIT,
|
|
|
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
|
|
subresource_range);
|
|
|
|
}
|
|
|
|
|
|
|
|
vk_submit_cmd_buffer(&c->vk, cmd_buffer);
|
|
|
|
|
|
|
|
return &sc->base.base;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
comp_swapchain_image_cleanup(struct vk_bundle *vk,
|
2019-05-01 15:17:17 +00:00
|
|
|
uint32_t array_size,
|
2019-03-18 05:52:32 +00:00
|
|
|
struct comp_swapchain_image *image)
|
|
|
|
{
|
2020-04-09 15:29:21 +00:00
|
|
|
vk->vkDeviceWaitIdle(vk->device);
|
|
|
|
|
2019-05-01 15:17:17 +00:00
|
|
|
if (image->views != NULL) {
|
|
|
|
for (uint32_t i = 0; i < array_size; ++i) {
|
2019-10-07 22:27:09 +00:00
|
|
|
if (image->views[i] == VK_NULL_HANDLE) {
|
|
|
|
continue;
|
2019-05-01 15:17:17 +00:00
|
|
|
}
|
2019-10-07 22:27:09 +00:00
|
|
|
|
|
|
|
vk->vkDestroyImageView(vk->device, image->views[i],
|
|
|
|
NULL);
|
|
|
|
image->views[i] = VK_NULL_HANDLE;
|
2019-05-01 15:17:17 +00:00
|
|
|
}
|
|
|
|
free(image->views);
|
|
|
|
image->views = NULL;
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2019-10-07 22:27:09 +00:00
|
|
|
if (image->sampler != VK_NULL_HANDLE) {
|
2019-03-18 05:52:32 +00:00
|
|
|
vk->vkDestroySampler(vk->device, image->sampler, NULL);
|
2019-10-07 22:27:09 +00:00
|
|
|
image->sampler = VK_NULL_HANDLE;
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2019-10-07 22:27:09 +00:00
|
|
|
if (image->image != VK_NULL_HANDLE) {
|
2019-03-18 05:52:32 +00:00
|
|
|
vk->vkDestroyImage(vk->device, image->image, NULL);
|
2019-10-07 22:27:09 +00:00
|
|
|
image->image = VK_NULL_HANDLE;
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2019-10-07 22:27:09 +00:00
|
|
|
if (image->memory != VK_NULL_HANDLE) {
|
2019-03-18 05:52:32 +00:00
|
|
|
vk->vkFreeMemory(vk->device, image->memory, NULL);
|
2019-10-07 22:27:09 +00:00
|
|
|
image->memory = VK_NULL_HANDLE;
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-15 16:37:34 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
comp_swapchain_really_destroy(struct comp_swapchain *sc)
|
|
|
|
{
|
|
|
|
struct vk_bundle *vk = &sc->c->vk;
|
|
|
|
|
|
|
|
COMP_SPEW(sc->c, "REALLY DESTROY");
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < sc->base.base.num_images; i++) {
|
|
|
|
comp_swapchain_image_cleanup(vk, sc->base.base.array_size,
|
|
|
|
&sc->images[i]);
|
|
|
|
}
|
|
|
|
|
2020-05-30 15:58:34 +00:00
|
|
|
for (uint32_t i = 0; i < sc->base.base.num_images; i++) {
|
|
|
|
if (sc->base.images[i].fd < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(sc->base.images[i].fd);
|
|
|
|
sc->base.images[i].fd = -1;
|
|
|
|
}
|
|
|
|
|
2020-04-15 16:37:34 +00:00
|
|
|
free(sc);
|
|
|
|
}
|