st/gui: Add gui_widget_native_images

This commit is contained in:
Jakob Bornecrantz 2023-09-21 14:53:25 +01:00
parent 92f5b0c1a6
commit f586a5ae6a
3 changed files with 341 additions and 1 deletions

View file

@ -1,4 +1,4 @@
# Copyright 2019-2021, Collabora, Ltd.
# Copyright 2019-2024, Collabora, Ltd.
# SPDX-License-Identifier: BSL-1.0
# c-imgui doesn't do well with IPO - lots of warnings.
@ -23,6 +23,8 @@ add_library(
gui_scene_video.c
gui_scene_tracking_overrides.c
gui_stb.c
gui_widget_native_images.c
gui_widget_native_images.h
gui_window_record.c
gui_window_record.h
)

View file

@ -0,0 +1,185 @@
// Copyright 2019-2024, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Swapchain rendering helper code.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup gui
*/
#include "ogl/ogl_api.h"
#include "ogl/ogl_helpers.h"
#include "util/u_misc.h"
#include "util/u_logging.h"
#include "util/u_native_images_debug.h"
#include "gui_ogl.h"
#include "gui_widget_native_images.h"
#include <assert.h>
#include <inttypes.h>
/*
*
* Helpers.
*
*/
static void
destroy_resources(struct gui_widget_native_images *gwni)
{
uint32_t texture_count = gwni->texture_count;
if (texture_count == 0) {
return;
}
glDeleteTextures(texture_count, gwni->textures);
glDeleteMemoryObjectsEXT(texture_count, gwni->memories);
U_ZERO_ARRAY(gwni->textures);
U_ZERO_ARRAY(gwni->memories);
gwni->texture_count = 0;
}
static void
recreate_locked(struct gui_widget_native_images *gwni, struct u_native_images_debug *unid)
{
// Clear old resources.
destroy_resources(gwni);
if (unid->native_images == NULL) {
return;
}
struct ogl_import_results results;
bool bret = ogl_import_from_native( //
unid->native_images, //
unid->native_image_count, //
unid->xscci, //
&results); //
if (!bret) {
return;
}
for (uint32_t i = 0; i < results.image_count; i++) {
gwni->textures[i] = results.textures[i];
}
gwni->texture_count = results.image_count;
gwni->width = unid->xscci->width;
gwni->height = unid->xscci->height;
gwni->flip_y = unid->flip_y;
}
/*
*
* 'Exported' widget functions.
*
*/
void
gui_widget_native_images_init(struct gui_widget_native_images *gwni)
{
U_ZERO(gwni);
gwni->active_index = GUI_WIDGET_SWAPCHAIN_INVALID_INDEX;
}
void
gui_widget_native_images_update(struct gui_widget_native_images *gwni, struct u_native_images_debug *unid)
{
u_native_images_debug_lock(unid);
xrt_limited_unique_id_t id = unid->limited_unique_id;
if (gwni->cache_id.data != id.data) {
U_LOG_D("Updating imported textures (%" PRIu64 " != %" PRIu64 ")", gwni->cache_id.data, id.data);
recreate_locked(gwni, unid);
gwni->cache_id = id;
}
if (id.data == 0 || gwni->texture_count == 0) {
gwni->active_index = GUI_WIDGET_SWAPCHAIN_INVALID_INDEX;
gwni->flip_y = false;
} else {
gwni->active_index = unid->active_index;
gwni->flip_y = unid->flip_y;
}
u_native_images_debug_unlock(unid);
}
void
gui_widget_native_images_render(struct gui_widget_native_images *gwni, struct gui_program *p)
{
if (gwni->active_index == GUI_WIDGET_SWAPCHAIN_INVALID_INDEX) {
return;
}
uint32_t tex_id = gwni->textures[gwni->active_index];
gui_ogl_draw_image( //
gwni->width, // width
gwni->height, // height
tex_id, // tex_id
0.5f, // scale
false, // rotate_180
gwni->flip_y); // flip_y
}
void
gui_widget_native_images_to_background(struct gui_widget_native_images *gwni, struct gui_program *p)
{
if (gwni->active_index == GUI_WIDGET_SWAPCHAIN_INVALID_INDEX) {
return;
}
uint32_t tex_id = gwni->textures[gwni->active_index];
gui_ogl_draw_background( //
gwni->width, // width
gwni->height, // height
tex_id, // tex_id
false, // rotate_180
gwni->flip_y); // flip_y
}
void
gui_widget_native_images_close(struct gui_widget_native_images *gwni)
{
destroy_resources(gwni);
U_ZERO(gwni);
}
/*
*
* 'Exported' storage functions.
*
*/
struct gui_widget_native_images *
gui_widget_native_images_storage_ensure(struct gui_widget_native_images_storage *gwnis,
struct u_native_images_debug *unid)
{
assert(unid != NULL);
for (uint32_t i = 0; i < ARRAY_SIZE(gwnis->records); i++) {
if (gwnis->records[i].ptr == unid) {
return &gwnis->records[i].gwni;
}
}
for (uint32_t i = 0; i < ARRAY_SIZE(gwnis->records); i++) {
if (gwnis->records[i].ptr != NULL) {
continue;
}
gui_widget_native_images_init(&gwnis->records[i].gwni);
gwnis->records[i].ptr = unid;
return &gwnis->records[i].gwni;
}
return NULL;
}

View file

@ -0,0 +1,153 @@
// Copyright 2019-2024, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Swapchain rendering helper code.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup gui
*/
#pragma once
#include "xrt/xrt_compositor.h"
#include "xrt/xrt_defines.h"
#include "xrt/xrt_limits.h"
#ifdef __cplusplus
extern "C" {
#endif
struct gui_program;
struct u_native_images_debug;
#define GUI_WIDGET_SWAPCHAIN_INVALID_INDEX 0xffffffff
/*!
* A small widget that interfaces a @ref u_native_images_debug struct, caching the
* imports from the listed @ref xrt_image_native list.
*
* @ingroup gui
*/
struct gui_widget_native_images
{
//! To check if swapchain has been changed.
xrt_limited_unique_id_t cache_id;
uint32_t memories[XRT_MAX_SWAPCHAIN_IMAGES];
uint32_t textures[XRT_MAX_SWAPCHAIN_IMAGES];
//! The current number of images that has been imported.
uint32_t texture_count;
//! Dimensions.
uint32_t width, height;
//! Set to GUI_WIDGET_SWAPCHAIN_INVALID_INDEX on invalid.
uint32_t active_index;
//! Should the image be flipped in y direction.
bool flip_y;
};
/*!
* A single record in a native image widget storage.
*
* @ingroup gui
*/
struct gui_widget_native_images_record
{
void *ptr;
struct gui_widget_native_images gwni;
};
/*!
* Helper struct to cache @ref gui_widget_native_images.
*
* @ingroup gui
*/
struct gui_widget_native_images_storage
{
struct gui_widget_native_images_record records[32];
};
/*
*
* Swapchain functions.
*
*/
/*!
* Initialise a embeddable record window.
*
* @ingroup gui
*/
void
gui_widget_native_images_init(struct gui_widget_native_images *gwni);
/*!
* Update the swapchain widget.
*
* @ingroup gui
*/
void
gui_widget_native_images_update(struct gui_widget_native_images *gwni, struct u_native_images_debug *unid);
/*!
* Renders all controls of a record window.
*
* @ingroup gui
*/
void
gui_widget_native_images_render(struct gui_widget_native_images *gwni, struct gui_program *p);
/*!
* Draw the sink image as the background to the background of the render view.
* Basically the main window in which all ImGui windows lives in, not to a
* ImGui window.
*
* @ingroup gui
*/
void
gui_widget_native_images_to_background(struct gui_widget_native_images *gwni, struct gui_program *p);
/*!
* Frees all resources associated with a record window. Make sure to only call
* this function on the main gui thread, and that nothing is pushing into the
* record windows sink.
*
* @ingroup gui
*/
void
gui_widget_native_images_close(struct gui_widget_native_images *gwni);
/*
*
* Storage functions.
*
*/
/*!
* Search the storage for the matching record for the debug swapchain and
* return it, if not found and there is room create it.
*
* @ingroup gui
*/
struct gui_widget_native_images *
gui_widget_native_images_storage_ensure(struct gui_widget_native_images_storage *gwnis,
struct u_native_images_debug *unid);
/*!
* Close the storage.
*
* @ingroup gui
*/
struct gui_widget_native_images *
gui_widget_native_images_storage_close(struct gui_widget_native_images_storage *gwnis,
struct u_native_images_debug *unid);
#ifdef __cplusplus
}
#endif