mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-23 15:11:47 +00:00
a97b9a5990
Co-authored-by: Jakob Bornecrantz <jakob@collabora.com>
326 lines
9.3 KiB
C
326 lines
9.3 KiB
C
// Copyright 2018-2023, Collabora, Ltd.
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
/*!
|
|
* @file
|
|
* @brief Holds swapchain related functions.
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
|
* @ingroup oxr_main
|
|
*/
|
|
|
|
#include "util/u_debug.h"
|
|
#include "util/u_misc.h"
|
|
|
|
#include "oxr_objects.h"
|
|
#include "oxr_logger.h"
|
|
#include "oxr_handle.h"
|
|
#include "oxr_swapchain_common.h"
|
|
#include "oxr_xret.h"
|
|
|
|
|
|
/*
|
|
*
|
|
* Conversion functions.
|
|
*
|
|
*/
|
|
|
|
static enum xrt_swapchain_create_flags
|
|
convert_create_flags(XrSwapchainCreateFlags xr_flags)
|
|
{
|
|
enum xrt_swapchain_create_flags flags = 0;
|
|
|
|
if ((xr_flags & XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT) != 0) {
|
|
flags |= XRT_SWAPCHAIN_CREATE_PROTECTED_CONTENT;
|
|
}
|
|
if ((xr_flags & XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT) != 0) {
|
|
flags |= XRT_SWAPCHAIN_CREATE_STATIC_IMAGE;
|
|
}
|
|
|
|
return flags;
|
|
}
|
|
|
|
static enum xrt_swapchain_usage_bits
|
|
convert_usage_bits(XrSwapchainUsageFlags xr_usage)
|
|
{
|
|
enum xrt_swapchain_usage_bits usage = 0;
|
|
|
|
if ((xr_usage & XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT) != 0) {
|
|
usage |= XRT_SWAPCHAIN_USAGE_COLOR;
|
|
}
|
|
if ((xr_usage & XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {
|
|
usage |= XRT_SWAPCHAIN_USAGE_DEPTH_STENCIL;
|
|
}
|
|
if ((xr_usage & XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT) != 0) {
|
|
usage |= XRT_SWAPCHAIN_USAGE_UNORDERED_ACCESS;
|
|
}
|
|
if ((xr_usage & XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT) != 0) {
|
|
usage |= XRT_SWAPCHAIN_USAGE_TRANSFER_SRC;
|
|
}
|
|
if ((xr_usage & XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT) != 0) {
|
|
usage |= XRT_SWAPCHAIN_USAGE_TRANSFER_DST;
|
|
}
|
|
if ((xr_usage & XR_SWAPCHAIN_USAGE_SAMPLED_BIT) != 0) {
|
|
usage |= XRT_SWAPCHAIN_USAGE_SAMPLED;
|
|
}
|
|
if ((xr_usage & XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT) != 0) {
|
|
usage |= XRT_SWAPCHAIN_USAGE_MUTABLE_FORMAT;
|
|
}
|
|
// aliased to XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND
|
|
if ((xr_usage & XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR) != 0) {
|
|
usage |= XRT_SWAPCHAIN_USAGE_INPUT_ATTACHMENT;
|
|
}
|
|
|
|
return usage;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* Internal API functions.
|
|
*
|
|
*/
|
|
|
|
static XrResult
|
|
acquire_image(struct oxr_logger *log,
|
|
struct oxr_swapchain *sc,
|
|
const XrSwapchainImageAcquireInfo *acquireInfo,
|
|
uint32_t *out_index)
|
|
{
|
|
CHECK_OXR_RET(oxr_swapchain_common_acquire(log, sc, out_index));
|
|
|
|
return oxr_session_success_result(sc->sess);
|
|
}
|
|
|
|
static XrResult
|
|
implicit_wait_image(struct oxr_logger *log, struct oxr_swapchain *sc, const XrSwapchainImageWaitInfo *waitInfo)
|
|
{
|
|
struct xrt_swapchain *xsc = (struct xrt_swapchain *)sc->swapchain;
|
|
xrt_result_t xret;
|
|
|
|
CHECK_OXR_RET(oxr_swapchain_verify_wait_state(log, sc));
|
|
CHECK_OXR_RET(oxr_swapchain_common_wait(log, sc, waitInfo->timeout));
|
|
|
|
// Check and grab the index.
|
|
if (sc->inflight.index < 0) {
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Invalid state: sc->inflight.index < 0");
|
|
}
|
|
uint32_t index = (uint32_t)sc->inflight.index;
|
|
|
|
// Okay to transition here for all APIs except Vulkan, who has it's own implementation of this function.
|
|
xret = xrt_swapchain_barrier_image(xsc, XRT_BARRIER_TO_COMP, index);
|
|
OXR_CHECK_XRET(log, sc->sess, xret, xrt_swapchain_barrier_image);
|
|
|
|
return oxr_session_success_result(sc->sess);
|
|
}
|
|
|
|
static XrResult
|
|
implicit_release_image(struct oxr_logger *log, struct oxr_swapchain *sc, const XrSwapchainImageReleaseInfo *releaseInfo)
|
|
{
|
|
struct xrt_swapchain *xsc = (struct xrt_swapchain *)sc->swapchain;
|
|
xrt_result_t xret;
|
|
|
|
// Error checking.
|
|
if (!sc->inflight.yes) {
|
|
return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID, "No swapchain images waited on");
|
|
}
|
|
|
|
// Check and grab the index.
|
|
if (sc->inflight.index < 0) {
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Invalid state: sc->inflight.index < 0");
|
|
}
|
|
uint32_t index = (uint32_t)sc->inflight.index;
|
|
|
|
if (sc->images[index].state != OXR_IMAGE_STATE_WAITED) {
|
|
return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID, "No swapchain images waited on");
|
|
}
|
|
|
|
// Need to do a automatic transition here.
|
|
xret = xrt_swapchain_barrier_image(xsc, XRT_BARRIER_TO_COMP, index);
|
|
OXR_CHECK_XRET(log, sc->sess, xret, xrt_swapchain_barrier_image);
|
|
|
|
CHECK_OXR_RET(oxr_swapchain_common_release(log, sc));
|
|
|
|
return oxr_session_success_result(sc->sess);
|
|
}
|
|
|
|
static XrResult
|
|
destroy(struct oxr_logger *log, struct oxr_swapchain *sc)
|
|
{
|
|
// It is not safe to do transitions here for some Graphics APIs, and
|
|
// the ipc layer has to be robust enough to handle a disconnect.
|
|
|
|
// Drop our reference, does NULL checking.
|
|
xrt_swapchain_reference(&sc->swapchain, NULL);
|
|
|
|
return XR_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* Handle function.
|
|
*
|
|
*/
|
|
|
|
static XrResult
|
|
destroy_handle(struct oxr_logger *log, struct oxr_handle_base *hb)
|
|
{
|
|
struct oxr_swapchain *sc = (struct oxr_swapchain *)hb;
|
|
|
|
XrResult ret = sc->destroy(log, sc);
|
|
free(sc);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* 'Exported' functions.
|
|
*
|
|
*/
|
|
|
|
XrResult
|
|
oxr_swapchain_common_acquire(struct oxr_logger *log, struct oxr_swapchain *sc, uint32_t *out_index)
|
|
{
|
|
uint32_t index;
|
|
|
|
if (sc->acquired.num >= sc->swapchain->image_count) {
|
|
return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID, "All images have been acquired");
|
|
}
|
|
|
|
if (sc->is_static && (sc->released.yes || sc->images[0].state != OXR_IMAGE_STATE_READY)) {
|
|
return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID, "Can only acquire once on a static swapchain");
|
|
}
|
|
|
|
struct xrt_swapchain *xsc = (struct xrt_swapchain *)sc->swapchain;
|
|
|
|
xrt_result_t xret = xrt_swapchain_acquire_image(xsc, &index);
|
|
OXR_CHECK_XRET(log, sc->sess, xret, xrt_swapchain_acquire_image);
|
|
|
|
if (sc->images[index].state != OXR_IMAGE_STATE_READY) {
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
"Internal xrt_swapchain_acquire_image call returned non-ready image.");
|
|
}
|
|
|
|
sc->acquired.num++;
|
|
u_index_fifo_push(&sc->acquired.fifo, index);
|
|
sc->images[index].state = OXR_IMAGE_STATE_ACQUIRED;
|
|
|
|
// If the compositor is resuing the image,
|
|
// mark it as invalid to use in xrEndFrame.
|
|
if (sc->released.index == (int)index) {
|
|
sc->released.yes = false;
|
|
sc->released.index = -1;
|
|
}
|
|
|
|
*out_index = index;
|
|
|
|
return XR_SUCCESS;
|
|
}
|
|
|
|
XrResult
|
|
oxr_swapchain_common_wait(struct oxr_logger *log, struct oxr_swapchain *sc, XrDuration timeout)
|
|
{
|
|
uint32_t index = UINT32_MAX;
|
|
if (u_index_fifo_pop(&sc->acquired.fifo, &index) != 0) {
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "u_index_fifo_pop: failed!");
|
|
}
|
|
assert(index < INT32_MAX);
|
|
|
|
struct xrt_swapchain *xsc = (struct xrt_swapchain *)sc->swapchain;
|
|
|
|
xrt_result_t xret = xrt_swapchain_wait_image(xsc, timeout, index);
|
|
OXR_CHECK_XRET(log, sc->sess, xret, xrt_swapchain_wait_image);
|
|
|
|
// The app can only wait on one image.
|
|
sc->inflight.yes = true;
|
|
sc->inflight.index = (int)index;
|
|
sc->images[index].state = OXR_IMAGE_STATE_WAITED;
|
|
|
|
return XR_SUCCESS;
|
|
}
|
|
|
|
XrResult
|
|
oxr_swapchain_common_release(struct oxr_logger *log, struct oxr_swapchain *sc)
|
|
{
|
|
struct xrt_swapchain *xsc = (struct xrt_swapchain *)sc->swapchain;
|
|
|
|
// Check and grab the index.
|
|
if (sc->inflight.index < 0) {
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Invalid state: sc->inflight.index < 0");
|
|
}
|
|
uint32_t index = (uint32_t)sc->inflight.index;
|
|
|
|
// Clear inflight.
|
|
sc->inflight.yes = false;
|
|
sc->inflight.index = -1;
|
|
|
|
xrt_result_t xret = xrt_swapchain_release_image(xsc, index);
|
|
OXR_CHECK_XRET(log, sc->sess, xret, xrt_swapchain_release_image);
|
|
|
|
// Only decerement here.
|
|
sc->acquired.num--;
|
|
|
|
// Overwrite the old released image, with new.
|
|
sc->released.yes = true;
|
|
sc->released.index = index;
|
|
sc->images[index].state = OXR_IMAGE_STATE_READY;
|
|
|
|
return XR_SUCCESS;
|
|
}
|
|
|
|
XrResult
|
|
oxr_swapchain_common_create(struct oxr_logger *log,
|
|
struct oxr_session *sess,
|
|
const XrSwapchainCreateInfo *createInfo,
|
|
struct oxr_swapchain **out_swapchain)
|
|
{
|
|
xrt_result_t xret = XRT_SUCCESS;
|
|
|
|
struct xrt_swapchain_create_info info;
|
|
info.create = convert_create_flags(createInfo->createFlags);
|
|
info.bits = convert_usage_bits(createInfo->usageFlags);
|
|
info.format = createInfo->format;
|
|
info.sample_count = createInfo->sampleCount;
|
|
info.width = createInfo->width;
|
|
info.height = createInfo->height;
|
|
info.face_count = createInfo->faceCount;
|
|
info.array_size = createInfo->arraySize;
|
|
info.mip_count = createInfo->mipCount;
|
|
|
|
struct xrt_swapchain *xsc = NULL; // Has to be NULL.
|
|
xret = xrt_comp_create_swapchain(sess->compositor, &info, &xsc);
|
|
if (xret == XRT_ERROR_SWAPCHAIN_FLAG_VALID_BUT_UNSUPPORTED) {
|
|
return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED,
|
|
"Specified swapchain creation flag is valid, "
|
|
"but not supported");
|
|
}
|
|
if (xret == XRT_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED) {
|
|
return oxr_error(log, XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED,
|
|
"Specified swapchain format is not supported");
|
|
}
|
|
if (xret != XRT_SUCCESS) {
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to create swapchain");
|
|
}
|
|
assert(xsc != NULL);
|
|
|
|
struct oxr_swapchain *sc = NULL;
|
|
OXR_ALLOCATE_HANDLE_OR_RETURN(log, sc, OXR_XR_DEBUG_SWAPCHAIN, destroy_handle, &sess->handle);
|
|
sc->sess = sess;
|
|
sc->swapchain = xsc;
|
|
sc->width = createInfo->width;
|
|
sc->height = createInfo->height;
|
|
sc->array_layer_count = createInfo->arraySize;
|
|
sc->face_count = createInfo->faceCount;
|
|
sc->is_static = (createInfo->createFlags & XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT) != 0;
|
|
|
|
// Functions.
|
|
sc->wait_image = implicit_wait_image;
|
|
sc->release_image = implicit_release_image;
|
|
sc->acquire_image = acquire_image;
|
|
sc->destroy = destroy;
|
|
|
|
*out_swapchain = sc;
|
|
|
|
return XR_SUCCESS;
|
|
}
|