From fc73ba0401dacaa397d9c3ee1c8ca8d7b5f99d9b Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Fri, 17 Jul 2020 17:51:45 -0500 Subject: [PATCH] comp: Split OpenGL[ES] swapchain types --- src/xrt/compositor/CMakeLists.txt | 4 + src/xrt/compositor/client/comp_egl_glue.c | 45 +++- src/xrt/compositor/client/comp_gl_client.c | 84 ++----- src/xrt/compositor/client/comp_gl_client.h | 39 ++- .../client/comp_gl_eglimage_swapchain.c | 232 ++++++++++++++++++ .../client/comp_gl_eglimage_swapchain.h | 56 +++++ .../client/comp_gl_memobj_swapchain.c | 121 +++++++++ .../client/comp_gl_memobj_swapchain.h | 55 +++++ .../compositor/client/comp_gl_xlib_client.c | 4 +- src/xrt/compositor/meson.build | 8 + 10 files changed, 562 insertions(+), 86 deletions(-) create mode 100644 src/xrt/compositor/client/comp_gl_eglimage_swapchain.c create mode 100644 src/xrt/compositor/client/comp_gl_eglimage_swapchain.h create mode 100644 src/xrt/compositor/client/comp_gl_memobj_swapchain.c create mode 100644 src/xrt/compositor/client/comp_gl_memobj_swapchain.h diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index 96bbf79e3..e3446dfe7 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -49,6 +49,8 @@ if(XRT_HAVE_OPENGL OR XRT_HAVE_OPENGLES) list(APPEND CLIENT_SOURCE_FILES client/comp_gl_client.c client/comp_gl_client.h + client/comp_gl_memobj_swapchain.c + client/comp_gl_memobj_swapchain.h ) endif() if(XRT_HAVE_OPENGL) @@ -59,6 +61,8 @@ endif() if(XRT_HAVE_OPENGLES) list(APPEND CLIENT_SOURCE_FILES client/comp_gles_glue.c + client/comp_gl_eglimage_swapchain.c + client/comp_gl_eglimage_swapchain.h ) endif() if(XRT_HAVE_OPENGL AND XRT_HAVE_XLIB) diff --git a/src/xrt/compositor/client/comp_egl_glue.c b/src/xrt/compositor/client/comp_egl_glue.c index 37e831dcb..82c01e2cb 100644 --- a/src/xrt/compositor/client/comp_egl_glue.c +++ b/src/xrt/compositor/client/comp_egl_glue.c @@ -8,18 +8,26 @@ * @ingroup comp_client */ -#define EGL_EGL_PROTOTYPES 0 -#define EGL_NO_X11 -#include -#include +#include +#include + +#include "ogl/egl_api.h" +#include "ogl/ogl_api.h" + #include #include #include "client/comp_gl_client.h" +#include "client/comp_gl_memobj_swapchain.h" +#include "client/comp_gl_eglimage_swapchain.h" #include "util/u_misc.h" #include "xrt/xrt_gfx_egl.h" +#ifndef XRT_HAVE_EGL +#error "This file shouldn't be compiled without EGL" +#endif + // Not forward declared by mesa typedef EGLBoolean EGLAPIENTRY (*PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, @@ -40,15 +48,14 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, EGLDisplay display, EGLConfig config, EGLContext context, - PFNEGLGETPROCADDRESSPROC getProcAddress) + PFNEGLGETPROCADDRESSPROC get_gl_procaddr) { - PFNEGLMAKECURRENTPROC eglMakeCurrent = - (PFNEGLMAKECURRENTPROC)getProcAddress("eglMakeCurrent"); - if (!eglMakeCurrent) { - /* TODO: sort out logging here */ - fprintf(stderr, "getProcAddress(eglMakeCurrent) failed\n"); - return NULL; - } +#if defined(XRT_HAVE_OPENGL) + gladLoadGL(get_gl_procaddr); +#elif defined(XRT_HAVE_OPENGLES) + gladLoadGLES2(get_gl_procaddr); +#endif + gladLoadEGL(display, get_gl_procaddr); if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context)) { fprintf(stderr, "Failed to make EGL context current\n"); @@ -57,7 +64,19 @@ xrt_gfx_provider_create_gl_egl(struct xrt_compositor_native *xcn, struct client_gl_compositor *c = U_TYPED_CALLOC(struct client_gl_compositor); - if (!client_gl_compositor_init(c, xcn, getProcAddress)) { + +#if defined(XRT_OS_ANDROID) + client_gl_swapchain_create_func sc_create = NULL; +#else + client_gl_swapchain_create_func sc_create = + client_gl_memobj_swapchain_create; + if (!GLAD_GL_EXT_memory_object && GLAD_EGL_EXT_image_dma_buf_import) { + sc_create = client_gl_eglimage_swapchain_create; + } +#endif + + if (!client_gl_compositor_init(c, xcn, get_gl_procaddr, sc_create)) { + free(c); fprintf(stderr, "Failed to initialize compositor\n"); return NULL; diff --git a/src/xrt/compositor/client/comp_gl_client.c b/src/xrt/compositor/client/comp_gl_client.c index 93a83ea5c..8d3d4e33b 100644 --- a/src/xrt/compositor/client/comp_gl_client.c +++ b/src/xrt/compositor/client/comp_gl_client.c @@ -42,26 +42,6 @@ client_gl_swapchain(struct xrt_swapchain *xsc) * */ -static void -client_gl_swapchain_destroy(struct xrt_swapchain *xsc) -{ - struct client_gl_swapchain *sc = client_gl_swapchain(xsc); - - uint32_t num_images = sc->base.base.num_images; - if (num_images > 0) { - glDeleteTextures(num_images, &sc->base.images[0]); - U_ZERO_ARRAY(sc->base.images); - glDeleteMemoryObjectsEXT(num_images, &sc->memory[0]); - U_ZERO_ARRAY(sc->base.images); - sc->base.base.num_images = 0; - } - - // Destroy the native swapchain as well. - xrt_swapchain_destroy((struct xrt_swapchain **)&sc->xscn); - - free(sc); -} - static xrt_result_t client_gl_swapchain_acquire_image(struct xrt_swapchain *xsc, uint32_t *out_index) @@ -285,54 +265,31 @@ client_gl_swapchain_create(struct xrt_compositor *xc, } assert(xscn != NULL); - struct xrt_swapchain *xsc = &xscn->base; - - struct client_gl_swapchain *sc = - U_TYPED_CALLOC(struct client_gl_swapchain); - sc->base.base.destroy = client_gl_swapchain_destroy; - sc->base.base.acquire_image = client_gl_swapchain_acquire_image; - sc->base.base.wait_image = client_gl_swapchain_wait_image; - sc->base.base.release_image = client_gl_swapchain_release_image; - // Fetch the number of images from the native swapchain. - sc->base.base.num_images = xsc->num_images; - sc->xscn = xscn; - + // Save texture binding GLuint prev_texture = 0; glGetIntegerv(info->array_size == 1 ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_2D_ARRAY, (GLint *)&prev_texture); - glGenTextures(xsc->num_images, sc->base.images); - for (uint32_t i = 0; i < xsc->num_images; i++) { - glBindTexture(info->array_size == 1 ? GL_TEXTURE_2D - : GL_TEXTURE_2D_ARRAY, - sc->base.images[i]); - } - glCreateMemoryObjectsEXT(xsc->num_images, &sc->memory[0]); - for (uint32_t i = 0; i < xsc->num_images; i++) { - GLint dedicated = GL_TRUE; - glMemoryObjectParameterivEXT( - sc->memory[i], GL_DEDICATED_MEMORY_OBJECT_EXT, &dedicated); - glImportMemoryFdEXT(sc->memory[i], xscn->images[i].size, - GL_HANDLE_TYPE_OPAQUE_FD_EXT, - xscn->images[i].handle); + struct xrt_swapchain *xsc = &xscn->base; - // We have consumed this handle now, make sure it's not freed - // again. - xscn->images[i].handle = XRT_GRAPHICS_BUFFER_HANDLE_INVALID; - - if (info->array_size == 1) { - glTextureStorageMem2DEXT( - sc->base.images[i], info->mip_count, - (GLuint)info->format, info->width, info->height, - sc->memory[i], 0); - } else { - glTextureStorageMem3DEXT( - sc->base.images[i], info->mip_count, - (GLuint)info->format, info->width, info->height, - info->array_size, sc->memory[i], 0); - } + struct client_gl_swapchain *sc = NULL; + if (NULL == c->create_swapchain(xc, info, xscn, &sc)) { + xrt_swapchain_destroy(&xsc); + return XRT_ERROR_OPENGL; } + if (NULL == sc->base.base.acquire_image) { + sc->base.base.acquire_image = client_gl_swapchain_acquire_image; + } + if (NULL == sc->base.base.wait_image) { + sc->base.base.wait_image = client_gl_swapchain_wait_image; + } + if (NULL == sc->base.base.release_image) { + sc->base.base.release_image = client_gl_swapchain_release_image; + } + // Fetch the number of images from the native swapchain. + sc->base.base.num_images = xsc->num_images; + sc->xscn = xscn; glBindTexture(info->array_size == 1 ? GL_TEXTURE_2D : GL_TEXTURE_2D_ARRAY, @@ -361,7 +318,8 @@ client_gl_compositor_destroy(struct xrt_compositor *xc) bool client_gl_compositor_init(struct client_gl_compositor *c, struct xrt_compositor_native *xcn, - client_gl_get_procaddr get_gl_procaddr) + client_gl_get_procaddr get_gl_procaddr, + client_gl_swapchain_create_func create_swapchain) { c->base.base.create_swapchain = client_gl_swapchain_create; c->base.base.prepare_session = client_gl_compositor_prepare_session; @@ -377,6 +335,7 @@ client_gl_compositor_init(struct client_gl_compositor *c, c->base.base.layer_commit = client_gl_compositor_layer_commit; c->base.base.destroy = client_gl_compositor_destroy; c->base.base.poll_events = client_gl_compositor_poll_events; + c->create_swapchain = create_swapchain; c->xcn = xcn; // Passthrough our formats from the native compositor to the client. @@ -395,6 +354,7 @@ client_gl_compositor_init(struct client_gl_compositor *c, gladLoadGL(get_gl_procaddr); #elif defined(XRT_HAVE_OPENGLES) gladLoadGLES2(get_gl_procaddr); + gladLoadEGL(display, get_gl_procaddr); #endif // @todo log this to a proper logger. #define CHECK_REQUIRED_EXTENSION(EXT) \ diff --git a/src/xrt/compositor/client/comp_gl_client.h b/src/xrt/compositor/client/comp_gl_client.h index 026a59527..22c97bf7a 100644 --- a/src/xrt/compositor/client/comp_gl_client.h +++ b/src/xrt/compositor/client/comp_gl_client.h @@ -15,7 +15,6 @@ extern "C" { #endif - /* * * Structs @@ -37,11 +36,30 @@ struct client_gl_swapchain struct xrt_swapchain_gl base; struct xrt_swapchain_native *xscn; - - // GLuint - unsigned int memory[XRT_MAX_SWAPCHAIN_IMAGES]; }; +/*! + * The type of a swapchain create constructor. + * + * Because our swapchain creation varies depending on available extensions and + * application choices, the swapchain constructor parameter to + * client_gl_compositor is parameterized. + * + * Note that the "common" swapchain creation function does some setup before + * invoking this, and some cleanup after. + * + * - Must populate `destroy` + * - Does not need to save/restore texture binding + */ +typedef struct xrt_swapchain *(*client_gl_swapchain_create_func)( + struct xrt_compositor *xc, + const struct xrt_swapchain_create_info *info, + struct xrt_swapchain_native *xscn, + struct client_gl_swapchain **out_sc); + +typedef void (*client_gl_void_ptr_func)(); +typedef client_gl_void_ptr_func (*client_gl_get_procaddr)(const char *name); + /*! * @class client_gl_compositor * @@ -55,6 +73,11 @@ struct client_gl_compositor struct xrt_compositor_gl base; struct xrt_compositor_native *xcn; + + /*! + * Function pointer for creating the client swapchain. + */ + client_gl_swapchain_create_func create_swapchain; }; @@ -64,7 +87,6 @@ struct client_gl_compositor * */ - /*! * Down-cast helper. * @protected @memberof client_gl_compositor @@ -75,10 +97,6 @@ client_gl_compositor(struct xrt_compositor *xc) return (struct client_gl_compositor *)xc; } -typedef void (*client_gl_void_ptr_func)(); - -typedef client_gl_void_ptr_func (*client_gl_get_procaddr)(const char *name); - /*! * Fill in a client_gl_compositor and do common OpenGL sanity checking. * @@ -93,7 +111,8 @@ typedef client_gl_void_ptr_func (*client_gl_get_procaddr)(const char *name); bool client_gl_compositor_init(struct client_gl_compositor *c, struct xrt_compositor_native *xcn, - client_gl_get_procaddr get_gl_procaddr); + client_gl_get_procaddr get_gl_procaddr, + client_gl_swapchain_create_func create_swapchain); #ifdef __cplusplus diff --git a/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c b/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c new file mode 100644 index 000000000..8ce24fa31 --- /dev/null +++ b/src/xrt/compositor/client/comp_gl_eglimage_swapchain.c @@ -0,0 +1,232 @@ +// Copyright 2019-2020, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief OpenGL client side glue to swapchain implementation - + * EGLImageKHR-backed. + * @author Ryan Pavlik + * @author Jakob Bornecrantz + * @ingroup comp_client + */ + +#include +#include +#include +#include + +#include "util/u_misc.h" + +#include +#include + +#if defined(XRT_HAVE_EGL) +#include "ogl/egl_api.h" +#endif +#if defined(XRT_HAVE_OPENGL) || defined(XRT_HAVE_OPENGLES) +#include "ogl/ogl_api.h" +#endif + +#include "client/comp_gl_client.h" +#include "client/comp_gl_eglimage_swapchain.h" + +#include + +/*! + * Down-cast helper. + * @private @memberof client_gl_eglimage_swapchain + */ +static inline struct client_gl_eglimage_swapchain * +client_gl_eglimage_swapchain(struct xrt_swapchain *xsc) +{ + return (struct client_gl_eglimage_swapchain *)xsc; +} + +/* + * + * Swapchain functions. + * + */ + +// This is shared between "destroy" and an error cleanup +static void +client_gl_eglimage_swapchain_teardown_storage( + struct client_gl_eglimage_swapchain *sc) +{ + uint32_t num_images = sc->base.base.base.num_images; + if (num_images > 0) { + glDeleteTextures(num_images, &sc->base.base.images[0]); + U_ZERO_ARRAY(sc->base.base.images); + for (uint32_t i = 0; i < num_images; ++i) { + if (sc->egl_images[i] != NULL) { + eglDestroyImageKHR(sc->display, + &(sc->egl_images[i])); + } + } + U_ZERO_ARRAY(sc->egl_images); + } +} + +static void +client_gl_eglimage_swapchain_destroy(struct xrt_swapchain *xsc) +{ + struct client_gl_eglimage_swapchain *sc = + client_gl_eglimage_swapchain(xsc); + + client_gl_eglimage_swapchain_teardown_storage(sc); + sc->base.base.base.num_images = 0; + + // Destroy the native swapchain as well. + xrt_swapchain_destroy((struct xrt_swapchain **)&sc->base.xscn); + + free(sc); +} + +#if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) + +/* + * See + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/drm/drm_fourcc.h + * for the "source of truth" for this data. + */ + +#define XRT_FOURCC(A, B, C, D) \ + ((uint32_t)(A) | ((uint32_t)(B) << 8) | ((uint32_t)(C) << 16) | \ + ((uint32_t)(D) << 24)) + +static inline uint32_t +gl_format_to_drm_fourcc(uint64_t format) +{ + switch (format) { + + case GL_RGBA8: + return XRT_FOURCC('R', 'A', '2', '4'); /*DRM_FORMAT_RGBA8888*/ + case GL_SRGB8_ALPHA8: + return XRT_FOURCC('R', 'A', '2', '4'); /*DRM_FORMAT_RGBA8888*/ + case GL_RGB10_A2: + return XRT_FOURCC('A', 'B', '3', + '0'); /*DRM_FORMAT_ABGR2101010*/ +#if 0 + /* couldn't find a matching code? */ + case GL_RGBA16F: +#endif + default: + printf("Cannot convert VK format 0x%016" PRIx64 + " to DRM FOURCC format!\n", + format); + return 0; + } +} +static inline uint32_t +gl_format_to_bpp(uint64_t format) +{ + switch (format) { + + case GL_RGBA8: return 32; /*DRM_FORMAT_RGBA8888*/ + case GL_SRGB8_ALPHA8: return 32; /*DRM_FORMAT_RGBA8888*/ + case GL_RGB10_A2: return 32; /*DRM_FORMAT_ABGR2101010*/ +#if 0 + /* couldn't find a matching code? */ + case GL_RGBA16F: +#endif + default: + printf("Cannot convert VK format 0x%016" PRIx64 + " to DRM FOURCC format!\n", + format); + return 0; + } +} +#endif // defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) + +struct xrt_swapchain * +client_gl_eglimage_swapchain_create( + struct xrt_compositor *xc, + const struct xrt_swapchain_create_info *info, + struct xrt_swapchain_native *xscn, + struct client_gl_swapchain **out_sc) +{ + if (xscn == NULL) { + return NULL; + } + +#if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) + uint32_t format = gl_format_to_drm_fourcc(info->format); + if (format == 0) { + return NULL; + } + uint32_t row_bits = gl_format_to_bpp(info->format) * info->width; + uint32_t row_pitch = row_bits / 8; + if (row_pitch * 8 < row_bits) { + // round up + row_pitch += 1; + } +#endif // defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) + + struct xrt_swapchain *native_xsc = &xscn->base; + + struct client_gl_eglimage_swapchain *sc = + U_TYPED_CALLOC(struct client_gl_eglimage_swapchain); + struct xrt_swapchain_gl *xscgl = &sc->base.base; + struct xrt_swapchain *client_xsc = &xscgl->base; + client_xsc->destroy = client_gl_eglimage_swapchain_destroy; + // Fetch the number of images from the native swapchain. + client_xsc->num_images = native_xsc->num_images; + sc->base.xscn = xscn; + + sc->display = eglGetCurrentDisplay(); + + glGenTextures(native_xsc->num_images, xscgl->images); + + + + for (uint32_t i = 0; i < native_xsc->num_images; i++) { +#ifdef XRT_OS_ANDROID + glBindTexture(GL_TEXTURE_EXTERNAL_OES, xscgl->images[i]); +#else + glBindTexture(info->array_size == 1 ? GL_TEXTURE_2D + : GL_TEXTURE_2D_ARRAY, + xscgl->images[i]); +#endif + + EGLClientBuffer native_buffer = NULL; + +#if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER) + native_buffer = + eglGetNativeClientBufferANDROID(xscn->images[i].handle); + + if (NULL == native_buffer) { + client_gl_eglimage_swapchain_teardown_storage(sc); + free(sc); + return NULL; + } + EGLint attrs[] = {EGL_NONE}; + EGLenum target = EGL_NATIVE_BUFFER_ANDROID; +#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) + EGLint attrs[] = {EGL_WIDTH, + info->width, + EGL_HEIGHT, + info->height, + EGL_LINUX_DRM_FOURCC_EXT, + format, + EGL_DMA_BUF_PLANE0_FD_EXT, + xscn->images[i].handle, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, + 0, + EGL_DMA_BUF_PLANE0_PITCH_EXT, + row_pitch, + EGL_NONE}; + EGLenum target = EGL_LINUX_DMA_BUF_EXT; +#endif + sc->egl_images[i] = eglCreateImageKHR( + sc->display, EGL_NO_CONTEXT, target, native_buffer, attrs); + if (NULL == sc->egl_images[i]) { + client_gl_eglimage_swapchain_teardown_storage(sc); + free(sc); + return NULL; + } + glEGLImageTargetTexture2DOES( + info->array_size == 1 ? GL_TEXTURE_2D : GL_TEXTURE_2D_ARRAY, + sc->egl_images[i]); + } + + return &sc->base.base.base; +} diff --git a/src/xrt/compositor/client/comp_gl_eglimage_swapchain.h b/src/xrt/compositor/client/comp_gl_eglimage_swapchain.h new file mode 100644 index 000000000..59e912c3f --- /dev/null +++ b/src/xrt/compositor/client/comp_gl_eglimage_swapchain.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief OpenGL client side glue using EGLImageKHR - header. + * @author Ryan Pavlik + * @author Jakob Bornecrantz + * @ingroup comp_client + */ + +#pragma once + +#include "comp_gl_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *EGLImage; +typedef void *EGLDisplay; + +/*! + * @class client_gl_eglimage_swapchain + * + * Wraps the real compositor swapchain providing a OpenGL based interface. + * + * Almost a one to one mapping to a OpenXR swapchain. + * + * @ingroup comp_client + * @implements xrt_swapchain_gl + */ +struct client_gl_eglimage_swapchain +{ + struct client_gl_swapchain base; + + EGLDisplay display; + // GLuint + EGLImage egl_images[XRT_MAX_SWAPCHAIN_IMAGES]; +}; + +/*! + * Create a swapchain, belonging to a client_gl_compositor, that uses + * some way of producing an EGLImageKHR from the native buffer. + * + * This is used on Android and on desktop when the EGL extension is used. + */ +struct xrt_swapchain * +client_gl_eglimage_swapchain_create( + struct xrt_compositor *xc, + const struct xrt_swapchain_create_info *info, + struct xrt_swapchain_native *xscn, + struct client_gl_swapchain **out_sc); + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/compositor/client/comp_gl_memobj_swapchain.c b/src/xrt/compositor/client/comp_gl_memobj_swapchain.c new file mode 100644 index 000000000..9c25d0845 --- /dev/null +++ b/src/xrt/compositor/client/comp_gl_memobj_swapchain.c @@ -0,0 +1,121 @@ +// Copyright 2019-2020, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief OpenGL client side glue to compositor implementation. + * @author Jakob Bornecrantz + * @ingroup comp_client + */ + +#include +#include +#include +#include + +#include +#include "util/u_misc.h" + +#include "ogl/ogl_api.h" + +#include "client/comp_gl_client.h" +#include "client/comp_gl_memobj_swapchain.h" + +#include + +/*! + * Down-cast helper. + * @private @memberof client_gl_memobj_swapchain + */ +static inline struct client_gl_memobj_swapchain * +client_gl_memobj_swapchain(struct xrt_swapchain *xsc) +{ + return (struct client_gl_memobj_swapchain *)xsc; +} + +/* + * + * Swapchain functions. + * + */ + +static void +client_gl_memobj_swapchain_destroy(struct xrt_swapchain *xsc) +{ + struct client_gl_memobj_swapchain *sc = client_gl_memobj_swapchain(xsc); + + uint32_t num_images = sc->base.base.base.num_images; + if (num_images > 0) { + glDeleteTextures(num_images, &sc->base.base.images[0]); + U_ZERO_ARRAY(sc->base.base.images); + glDeleteMemoryObjectsEXT(num_images, &sc->memory[0]); + U_ZERO_ARRAY(sc->memory); + sc->base.base.base.num_images = 0; + } + + // Destroy the native swapchain as well. + xrt_swapchain_destroy((struct xrt_swapchain **)&sc->base.xscn); + + free(sc); +} +struct xrt_swapchain * +client_gl_memobj_swapchain_create(struct xrt_compositor *xc, + const struct xrt_swapchain_create_info *info, + struct xrt_swapchain_native *xscn, + struct client_gl_swapchain **out_cglsc) +{ +#if defined(XRT_OS_ANDROID) + return NULL; +#elif defined(XRT_OS_LINUX) + struct client_gl_compositor *c = client_gl_compositor(xc); + (void)c; + + if (xscn == NULL) { + return NULL; + } + struct xrt_swapchain *native_xsc = &xscn->base; + + struct client_gl_memobj_swapchain *sc = + U_TYPED_CALLOC(struct client_gl_memobj_swapchain); + struct xrt_swapchain_gl *xscgl = &sc->base.base; + struct xrt_swapchain *client_xsc = &xscgl->base; + client_xsc->destroy = client_gl_memobj_swapchain_destroy; + // Fetch the number of images from the native swapchain. + client_xsc->num_images = native_xsc->num_images; + sc->base.xscn = xscn; + + glGenTextures(native_xsc->num_images, xscgl->images); + for (uint32_t i = 0; i < native_xsc->num_images; i++) { + glBindTexture(info->array_size == 1 ? GL_TEXTURE_2D + : GL_TEXTURE_2D_ARRAY, + xscgl->images[i]); + } + + glCreateMemoryObjectsEXT(native_xsc->num_images, &sc->memory[0]); + for (uint32_t i = 0; i < native_xsc->num_images; i++) { + GLint dedicated = GL_TRUE; + glMemoryObjectParameterivEXT( + sc->memory[i], GL_DEDICATED_MEMORY_OBJECT_EXT, &dedicated); + glImportMemoryFdEXT(sc->memory[i], xscn->images[i].size, + GL_HANDLE_TYPE_OPAQUE_FD_EXT, + xscn->images[i].handle); + + // We have consumed this now, make sure it's not freed again. + xscn->images[i].handle = XRT_GRAPHICS_BUFFER_HANDLE_INVALID; + + if (info->array_size == 1) { + glTextureStorageMem2DEXT( + xscgl->images[i], info->mip_count, + (GLuint)info->format, info->width, info->height, + sc->memory[i], 0); + } else { + glTextureStorageMem3DEXT( + xscgl->images[i], info->mip_count, + (GLuint)info->format, info->width, info->height, + info->array_size, sc->memory[i], 0); + } + } + + *out_cglsc = &sc->base; + return client_xsc; +#endif +} diff --git a/src/xrt/compositor/client/comp_gl_memobj_swapchain.h b/src/xrt/compositor/client/comp_gl_memobj_swapchain.h new file mode 100644 index 000000000..721607de8 --- /dev/null +++ b/src/xrt/compositor/client/comp_gl_memobj_swapchain.h @@ -0,0 +1,55 @@ +// Copyright 2019-2020, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief OpenGL client side glue using memory objects - header. + * @author Ryan Pavlik + * @author Jakob Bornecrantz + * @ingroup comp_client + */ + +#pragma once + +#include "comp_gl_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! + * @class client_gl_memobj_swapchain + * + * Wraps the real compositor swapchain providing a OpenGL based interface. + * + * Almost a one to one mapping to a OpenXR swapchain. + * + * @ingroup comp_client + * @implements xrt_swapchain_gl + */ +struct client_gl_memobj_swapchain +{ + struct client_gl_swapchain base; + + // GLuint + unsigned int memory[XRT_MAX_SWAPCHAIN_IMAGES]; +}; + +/*! + * Create a swapchain, belonging to a client_gl_compositor, that uses + * GL_memory_object and related extensions to access the native buffer. + * + * This is most commonly used on desktop OpenGL. + * + * @see client_gl_swapchain_create_func, client_gl_compositor_init + */ +struct xrt_swapchain * +client_gl_memobj_swapchain_create(struct xrt_compositor *xc, + const struct xrt_swapchain_create_info *info, + struct xrt_swapchain_native *xscn, + struct client_gl_swapchain **out_sc); + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/compositor/client/comp_gl_xlib_client.c b/src/xrt/compositor/client/comp_gl_xlib_client.c index 2f7209dca..35a439116 100644 --- a/src/xrt/compositor/client/comp_gl_xlib_client.c +++ b/src/xrt/compositor/client/comp_gl_xlib_client.c @@ -15,6 +15,7 @@ #include "xrt/xrt_gfx_xlib.h" #include "client/comp_gl_xlib_client.h" +#include "client/comp_gl_memobj_swapchain.h" /*! @@ -56,7 +57,8 @@ client_gl_xlib_compositor_create(struct xrt_compositor_native *xcn, struct client_gl_xlib_compositor *c = U_TYPED_CALLOC(struct client_gl_xlib_compositor); - if (!client_gl_compositor_init(&c->base, xcn, glXGetProcAddress)) { + if (!client_gl_compositor_init(&c->base, xcn, glXGetProcAddress, + client_gl_memobj_swapchain_create)) { free(c); return NULL; } diff --git a/src/xrt/compositor/meson.build b/src/xrt/compositor/meson.build index 5fb47ce47..f7e8fdf9b 100644 --- a/src/xrt/compositor/meson.build +++ b/src/xrt/compositor/meson.build @@ -48,6 +48,8 @@ if build_opengl or build_opengles compositor_srcs += [ 'client/comp_gl_client.c', 'client/comp_gl_client.h', + 'client/comp_gl_memobj_swapchain.c', + 'client/comp_gl_memobj_swapchain.h', ] endif @@ -65,6 +67,12 @@ if build_opengles compositor_deps += [opengles] compositor_includes += [glad_include] endif +if build_egl + compositor_srcs += [ + 'client/comp_gl_eglimage_swapchain.c', + 'client/comp_gl_eglimage_swapchain.h', + ] +endif if build_opengl and build_xlib compositor_srcs += [