2020-05-30 15:56:33 +00:00
|
|
|
// Copyright 2019-2020, Collabora, Ltd.
|
2019-03-18 05:52:32 +00:00
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief OpenGL client side glue to compositor implementation.
|
|
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
|
|
|
* @ingroup comp_client
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2019-10-30 11:02:37 +00:00
|
|
|
#include <assert.h>
|
2019-03-18 05:52:32 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2019-03-21 20:19:52 +00:00
|
|
|
#include "util/u_misc.h"
|
|
|
|
|
2019-10-09 15:39:38 +00:00
|
|
|
#include "ogl/ogl_api.h"
|
2019-03-18 05:52:32 +00:00
|
|
|
#include "client/comp_gl_client.h"
|
|
|
|
|
2020-04-29 22:47:32 +00:00
|
|
|
#include <inttypes.h>
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Swapchain functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
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]);
|
2019-06-18 19:04:19 +00:00
|
|
|
U_ZERO_ARRAY(sc->base.images);
|
2019-03-18 05:52:32 +00:00
|
|
|
glDeleteMemoryObjectsEXT(num_images, &sc->base.memory[0]);
|
2019-06-18 19:04:19 +00:00
|
|
|
U_ZERO_ARRAY(sc->base.images);
|
2019-03-18 05:52:32 +00:00
|
|
|
sc->base.base.num_images = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy the fd swapchain as well.
|
|
|
|
sc->xscfd->base.destroy(&sc->xscfd->base);
|
|
|
|
|
|
|
|
free(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
client_gl_swapchain_acquire_image(struct xrt_swapchain *xsc, uint32_t *index)
|
|
|
|
{
|
|
|
|
struct client_gl_swapchain *sc = client_gl_swapchain(xsc);
|
|
|
|
|
|
|
|
// Pipe down call into fd swapchain.
|
|
|
|
return sc->xscfd->base.acquire_image(&sc->xscfd->base, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
client_gl_swapchain_wait_image(struct xrt_swapchain *xsc,
|
|
|
|
uint64_t timeout,
|
|
|
|
uint32_t index)
|
|
|
|
{
|
|
|
|
struct client_gl_swapchain *sc = client_gl_swapchain(xsc);
|
|
|
|
|
|
|
|
// Pipe down call into fd swapchain.
|
|
|
|
return sc->xscfd->base.wait_image(&sc->xscfd->base, timeout, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
client_gl_swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index)
|
|
|
|
{
|
|
|
|
struct client_gl_swapchain *sc = client_gl_swapchain(xsc);
|
|
|
|
|
|
|
|
// Pipe down call into fd swapchain.
|
|
|
|
return sc->xscfd->base.release_image(&sc->xscfd->base, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Compositor functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
client_gl_compositor_begin_session(struct xrt_compositor *xc,
|
|
|
|
enum xrt_view_type type)
|
|
|
|
{
|
|
|
|
struct client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
// Pipe down call into fd compositor.
|
|
|
|
c->xcfd->base.begin_session(&c->xcfd->base, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
client_gl_compositor_end_session(struct xrt_compositor *xc)
|
|
|
|
{
|
|
|
|
struct client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
// Pipe down call into fd compositor.
|
|
|
|
c->xcfd->base.end_session(&c->xcfd->base);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
client_gl_compositor_wait_frame(struct xrt_compositor *xc,
|
2020-03-02 19:34:43 +00:00
|
|
|
uint64_t *predicted_display_time,
|
|
|
|
uint64_t *predicted_display_period)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
|
|
|
struct client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
// Pipe down call into fd compositor.
|
|
|
|
c->xcfd->base.wait_frame(&c->xcfd->base, predicted_display_time,
|
|
|
|
predicted_display_period);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
client_gl_compositor_begin_frame(struct xrt_compositor *xc)
|
|
|
|
{
|
|
|
|
struct client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
// Pipe down call into fd compositor.
|
|
|
|
c->xcfd->base.begin_frame(&c->xcfd->base);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
client_gl_compositor_discard_frame(struct xrt_compositor *xc)
|
|
|
|
{
|
|
|
|
struct client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
// Pipe down call into fd compositor.
|
|
|
|
c->xcfd->base.discard_frame(&c->xcfd->base);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-04-22 12:59:40 +00:00
|
|
|
client_gl_compositor_layer_begin(struct xrt_compositor *xc,
|
|
|
|
enum xrt_blend_mode env_blend_mode)
|
2019-03-18 05:52:32 +00:00
|
|
|
{
|
|
|
|
struct client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
|
2020-04-22 12:59:40 +00:00
|
|
|
xrt_comp_layer_begin(&c->xcfd->base, env_blend_mode);
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-04-22 12:59:40 +00:00
|
|
|
static void
|
|
|
|
client_gl_compositor_layer_stereo_projection(
|
|
|
|
struct xrt_compositor *xc,
|
|
|
|
uint64_t timestamp,
|
|
|
|
struct xrt_device *xdev,
|
|
|
|
enum xrt_input_name name,
|
|
|
|
enum xrt_layer_composition_flags layer_flags,
|
|
|
|
struct xrt_swapchain *l_sc,
|
|
|
|
uint32_t l_image_index,
|
|
|
|
struct xrt_rect *l_rect,
|
|
|
|
uint32_t l_array_index,
|
|
|
|
struct xrt_fov *l_fov,
|
|
|
|
struct xrt_pose *l_pose,
|
|
|
|
struct xrt_swapchain *r_sc,
|
|
|
|
uint32_t r_image_index,
|
|
|
|
struct xrt_rect *r_rect,
|
|
|
|
uint32_t r_array_index,
|
|
|
|
struct xrt_fov *r_fov,
|
2020-05-22 14:01:41 +00:00
|
|
|
struct xrt_pose *r_pose,
|
|
|
|
bool flip_y)
|
2020-04-22 12:59:40 +00:00
|
|
|
{
|
|
|
|
struct client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
struct xrt_swapchain *l_xscfd, *r_xscfd;
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-04-22 12:59:40 +00:00
|
|
|
l_xscfd = &client_gl_swapchain(l_sc)->xscfd->base;
|
|
|
|
r_xscfd = &client_gl_swapchain(r_sc)->xscfd->base;
|
|
|
|
|
|
|
|
xrt_comp_layer_stereo_projection(
|
|
|
|
&c->xcfd->base, timestamp, xdev, name, layer_flags, l_xscfd,
|
|
|
|
l_image_index, l_rect, l_array_index, l_fov, l_pose, r_xscfd,
|
2020-05-22 14:01:41 +00:00
|
|
|
r_image_index, r_rect, r_array_index, r_fov, r_pose, true);
|
2020-04-22 12:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
client_gl_compositor_layer_quad(struct xrt_compositor *xc,
|
|
|
|
uint64_t timestamp,
|
|
|
|
struct xrt_device *xdev,
|
|
|
|
enum xrt_input_name name,
|
|
|
|
enum xrt_layer_composition_flags layer_flags,
|
|
|
|
enum xrt_layer_eye_visibility visibility,
|
|
|
|
struct xrt_swapchain *sc,
|
|
|
|
uint32_t image_index,
|
|
|
|
struct xrt_rect *rect,
|
|
|
|
uint32_t array_index,
|
|
|
|
struct xrt_pose *pose,
|
2020-05-22 14:01:41 +00:00
|
|
|
struct xrt_vec2 *size,
|
|
|
|
bool flip_y)
|
2020-04-22 12:59:40 +00:00
|
|
|
{
|
|
|
|
struct client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
struct xrt_swapchain *xscfb;
|
|
|
|
|
|
|
|
xscfb = &client_gl_swapchain(sc)->xscfd->base;
|
|
|
|
|
|
|
|
xrt_comp_layer_quad(&c->xcfd->base, timestamp, xdev, name, layer_flags,
|
|
|
|
visibility, xscfb, image_index, rect, array_index,
|
2020-05-22 14:01:41 +00:00
|
|
|
pose, size, true);
|
2020-04-22 12:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
client_gl_compositor_layer_commit(struct xrt_compositor *xc)
|
|
|
|
{
|
|
|
|
struct client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
|
|
|
|
xrt_comp_layer_commit(&c->xcfd->base);
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t
|
|
|
|
gl_format_to_vk(int64_t format)
|
|
|
|
{
|
|
|
|
switch (format) {
|
|
|
|
case GL_RGBA8: return 37 /*VK_FORMAT_R8G8B8A8_UNORM*/;
|
2019-05-04 20:25:24 +00:00
|
|
|
case GL_SRGB8_ALPHA8: return 43 /*VK_FORMAT_R8G8B8A8_SRGB*/;
|
2019-03-18 05:52:32 +00:00
|
|
|
default: return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-17 10:21:35 +00:00
|
|
|
static int64_t
|
|
|
|
vk_format_to_gl(int64_t format)
|
|
|
|
{
|
|
|
|
switch (format) {
|
|
|
|
case 37 /*VK_FORMAT_R8G8B8A8_UNORM*/: return GL_RGBA8;
|
|
|
|
case 43 /*VK_FORMAT_R8G8B8A8_SRGB*/: return GL_SRGB8_ALPHA8;
|
|
|
|
case 44 /*VK_FORMAT_B8G8R8A8_UNORM*/: return 0;
|
|
|
|
case 50 /*VK_FORMAT_B8G8R8A8_SRGB*/: return 0;
|
|
|
|
default:
|
2020-04-29 22:47:32 +00:00
|
|
|
printf("Cannot convert VK format 0x%016" PRIx64
|
|
|
|
" to GL format!\n",
|
|
|
|
format);
|
2020-04-17 10:21:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
static struct xrt_swapchain *
|
|
|
|
client_gl_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 client_gl_compositor *c = client_gl_compositor(xc);
|
|
|
|
|
2019-11-15 16:30:57 +00:00
|
|
|
if (array_size > 1) {
|
|
|
|
const char *version_str = (const char *)glGetString(GL_VERSION);
|
|
|
|
if (strstr(version_str, "OpenGL ES 2.") == version_str) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s - only one array layer is supported with "
|
|
|
|
"OpenGL ES 2\n",
|
|
|
|
__func__);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
int64_t vk_format = gl_format_to_vk(format);
|
|
|
|
if (vk_format == 0) {
|
|
|
|
fprintf(stderr, "%s - Invalid format!\n", __func__);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct xrt_swapchain *xsc = c->xcfd->base.create_swapchain(
|
|
|
|
&c->xcfd->base, create, bits, vk_format, sample_count, width,
|
|
|
|
height, face_count, array_size, mip_count);
|
|
|
|
|
|
|
|
if (xsc == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-04-08 14:13:28 +00:00
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
struct client_gl_swapchain *sc =
|
2019-03-21 20:19:52 +00:00
|
|
|
U_TYPED_CALLOC(struct client_gl_swapchain);
|
2019-03-18 05:52:32 +00:00
|
|
|
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;
|
2020-04-08 14:13:28 +00:00
|
|
|
// Fetch the number of images from the fd swapchain.
|
|
|
|
sc->base.base.num_images = xsc->num_images;
|
2019-03-18 05:52:32 +00:00
|
|
|
sc->xscfd = xrt_swapchain_fd(xsc);
|
|
|
|
|
2019-10-30 14:30:50 +00:00
|
|
|
GLuint prev_texture = 0;
|
|
|
|
glGetIntegerv(array_size == 1 ? GL_TEXTURE_BINDING_2D
|
|
|
|
: GL_TEXTURE_BINDING_2D_ARRAY,
|
|
|
|
(GLint *)&prev_texture);
|
|
|
|
|
2020-04-08 14:13:28 +00:00
|
|
|
glGenTextures(xsc->num_images, sc->base.images);
|
|
|
|
for (uint32_t i = 0; i < xsc->num_images; i++) {
|
2019-10-30 14:30:50 +00:00
|
|
|
glBindTexture(array_size == 1 ? GL_TEXTURE_2D
|
|
|
|
: GL_TEXTURE_2D_ARRAY,
|
|
|
|
sc->base.images[i]);
|
|
|
|
}
|
2020-04-08 14:13:28 +00:00
|
|
|
glCreateMemoryObjectsEXT(xsc->num_images, &sc->base.memory[0]);
|
|
|
|
for (uint32_t i = 0; i < xsc->num_images; i++) {
|
2019-03-18 05:52:32 +00:00
|
|
|
GLint dedicated = GL_TRUE;
|
|
|
|
glMemoryObjectParameterivEXT(sc->base.memory[i],
|
|
|
|
GL_DEDICATED_MEMORY_OBJECT_EXT,
|
|
|
|
&dedicated);
|
|
|
|
glImportMemoryFdEXT(
|
|
|
|
sc->base.memory[i], sc->xscfd->images[i].size,
|
|
|
|
GL_HANDLE_TYPE_OPAQUE_FD_EXT, sc->xscfd->images[i].fd);
|
2020-05-30 15:56:33 +00:00
|
|
|
|
|
|
|
// We have consumed this fd now, make sure it's not freed again.
|
|
|
|
sc->xscfd->images[i].fd = -1;
|
|
|
|
|
2019-04-30 15:22:19 +00:00
|
|
|
if (array_size == 1) {
|
|
|
|
glTextureStorageMem2DEXT(sc->base.images[i], mip_count,
|
|
|
|
(GLuint)format, width, height,
|
|
|
|
sc->base.memory[i], 0);
|
|
|
|
} else {
|
|
|
|
glTextureStorageMem3DEXT(
|
|
|
|
sc->base.images[i], mip_count, (GLuint)format,
|
|
|
|
width, height, array_size, sc->base.memory[i], 0);
|
|
|
|
}
|
2019-03-18 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2019-10-30 14:30:50 +00:00
|
|
|
glBindTexture(array_size == 1 ? GL_TEXTURE_2D : GL_TEXTURE_2D_ARRAY,
|
|
|
|
prev_texture);
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
return &sc->base.base;
|
|
|
|
}
|
|
|
|
|
2019-10-30 11:02:37 +00:00
|
|
|
static void
|
|
|
|
client_gl_compositor_destroy(struct xrt_compositor *xc)
|
|
|
|
{
|
|
|
|
assert(!"Destroy should be implemented by the winsys code that uses the GL code.");
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
bool
|
|
|
|
client_gl_compositor_init(struct client_gl_compositor *c,
|
|
|
|
struct xrt_compositor_fd *xcfd,
|
|
|
|
client_gl_get_procaddr get_gl_procaddr)
|
|
|
|
{
|
|
|
|
c->base.base.create_swapchain = client_gl_swapchain_create;
|
|
|
|
c->base.base.begin_session = client_gl_compositor_begin_session;
|
|
|
|
c->base.base.end_session = client_gl_compositor_end_session;
|
|
|
|
c->base.base.wait_frame = client_gl_compositor_wait_frame;
|
|
|
|
c->base.base.begin_frame = client_gl_compositor_begin_frame;
|
|
|
|
c->base.base.discard_frame = client_gl_compositor_discard_frame;
|
2020-04-22 12:59:40 +00:00
|
|
|
c->base.base.layer_begin = client_gl_compositor_layer_begin;
|
|
|
|
c->base.base.layer_stereo_projection =
|
|
|
|
client_gl_compositor_layer_stereo_projection;
|
|
|
|
c->base.base.layer_quad = client_gl_compositor_layer_quad;
|
|
|
|
c->base.base.layer_commit = client_gl_compositor_layer_commit;
|
2019-10-30 11:02:37 +00:00
|
|
|
c->base.base.destroy = client_gl_compositor_destroy;
|
2019-03-18 05:52:32 +00:00
|
|
|
c->xcfd = xcfd;
|
|
|
|
|
2020-04-17 10:21:35 +00:00
|
|
|
// Passthrough our formats from the fd compositor to the client.
|
|
|
|
size_t count = 0;
|
|
|
|
for (uint32_t i = 0; i < xcfd->base.num_formats; i++) {
|
|
|
|
int64_t f = vk_format_to_gl(xcfd->base.formats[i]);
|
|
|
|
if (f == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
c->base.base.formats[count++] = f;
|
|
|
|
}
|
|
|
|
c->base.base.num_formats = count;
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
gladLoadGL(get_gl_procaddr);
|
|
|
|
|
|
|
|
if (!GLAD_GL_EXT_memory_object_fd) {
|
|
|
|
// @todo log this to a proper logger.
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s - Needed extension"
|
|
|
|
" GL_EXT_memory_object_fd not supported\n",
|
|
|
|
__func__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|