t/gui: Add OpenGL sink code

This commit is contained in:
Jakob Bornecrantz 2019-08-31 14:57:19 +01:00 committed by Jakob Bornecrantz
parent 968952aa9e
commit c474112782
3 changed files with 216 additions and 1 deletions

View file

@ -16,6 +16,7 @@ include_directories(
set(SOURCE_FILES
gui_common.h
gui_main.c
gui_ogl.c
gui_prober.c
gui_sdl2.c
../../../external/glad/gl.h

View file

@ -9,7 +9,7 @@
#pragma once
#include "xrt/xrt_defines.h"
#include "xrt/xrt_frame.h"
#include <SDL2/SDL.h>
/*!
@ -55,6 +55,23 @@ struct program
struct time_state *timekeeping;
struct xrt_device *xdevs[NUM_XDEVS];
struct xrt_prober *xp;
struct gui_ogl_texture *texs[256];
};
/*!
* A OpenGL texture.
*
* @ingroup gui
*/
struct gui_ogl_texture
{
uint64_t seq;
uint64_t dropped;
const char *name;
uint32_t w, h;
uint32_t id;
bool half;
};
/*!
@ -118,6 +135,27 @@ gui_prober_update(struct program *p);
void
gui_prober_teardown(struct program *p);
/*!
* Create a sink that will turn frames into OpenGL textures, since the frame
* can come from another thread @ref gui_ogl_sink_update needs to be called.
*
* Destruction is handled by the frame context.
*
* @ingroup gui
*/
struct gui_ogl_texture *
gui_ogl_sink_create(const char *name,
struct xrt_frame_context *xfctx,
struct xrt_frame_sink **out_sink);
/*!
* Update the texture to the latest received frame.
*
* @ingroup gui
*/
void
gui_ogl_sink_update(struct gui_ogl_texture *);
#ifdef __cplusplus
}

View file

@ -0,0 +1,176 @@
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief OpenGL functions to drive the gui.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup gui
*/
#include "xrt/xrt_frame.h"
#include "util/u_misc.h"
#include "gui_common.h"
#include "glad/gl.h"
#include <pthread.h>
struct gui_ogl_sink
{
struct gui_ogl_texture tex;
struct xrt_frame_sink sink;
struct xrt_frame_node node;
struct xrt_frame *frame;
pthread_mutex_t mutex;
bool running;
};
static void
push_frame(struct xrt_frame_sink *xs, struct xrt_frame *xf)
{
struct gui_ogl_sink *s = container_of(xs, struct gui_ogl_sink, sink);
// The fields are protected.
pthread_mutex_lock(&s->mutex);
// If we are in the process of shutting down, don't take the reference.
if (s->running) {
xrt_frame_reference(&s->frame, xf);
}
// Done
pthread_mutex_unlock(&s->mutex);
}
static void
break_apart(struct xrt_frame_node *node)
{
struct gui_ogl_sink *s = container_of(node, struct gui_ogl_sink, node);
// Stop receiving any more reference.
pthread_mutex_lock(&s->mutex);
s->running = false;
pthread_mutex_unlock(&s->mutex);
}
static void
destroy(struct xrt_frame_node *node)
{
struct gui_ogl_sink *s = container_of(node, struct gui_ogl_sink, node);
glDeleteTextures(1, &s->tex.id);
pthread_mutex_destroy(&s->mutex);
free(s);
}
static void
update_r8g8b8(struct gui_ogl_sink *s, GLint w, GLint h, uint8_t *data)
{
glBindTexture(GL_TEXTURE_2D, s->tex.id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB,
GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, 0);
}
static void
update_l8(struct gui_ogl_sink *s, GLint w, GLint h, uint8_t *data)
{
glBindTexture(GL_TEXTURE_2D, s->tex.id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED,
GL_UNSIGNED_BYTE, data);
GLint swizzleMask[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
glBindTexture(GL_TEXTURE_2D, 0);
}
void
gui_ogl_sink_update(struct gui_ogl_texture *tex)
{
struct gui_ogl_sink *s = container_of(tex, struct gui_ogl_sink, tex);
(void)s;
// Take the frame no need to adjust reference.
pthread_mutex_lock(&s->mutex);
struct xrt_frame *frame = s->frame;
s->frame = NULL;
pthread_mutex_unlock(&s->mutex);
if (frame == NULL) {
return;
}
GLint w, h;
uint8_t *data;
w = frame->width;
h = frame->height;
if (tex->w != (uint32_t)w || tex->h != (uint32_t)h) {
tex->w = w;
tex->h = h;
// Automatically set the half scaling.
if (tex->w >= 1024 || tex->h >= 1024) {
tex->half = true;
}
}
tex->seq = frame->source_sequence;
data = frame->data;
switch (frame->format) {
case XRT_FORMAT_R8G8B8: update_r8g8b8(s, w, h, data); break;
case XRT_FORMAT_L8: update_l8(s, w, h, data); break;
default: break;
}
xrt_frame_reference(&frame, NULL);
}
struct gui_ogl_texture *
gui_ogl_sink_create(const char *name,
struct xrt_frame_context *xfctx,
struct xrt_frame_sink **out_sink)
{
struct gui_ogl_sink *s = U_TYPED_CALLOC(struct gui_ogl_sink);
int ret = 0;
s->sink.push_frame = push_frame;
s->node.break_apart = break_apart;
s->node.destroy = destroy;
s->tex.name = name;
s->tex.w = 256;
s->tex.h = 256;
s->running = true;
ret = pthread_mutex_init(&s->mutex, NULL);
if (ret != 0) {
free(s);
return NULL;
}
// Temporary texture
glGenTextures(1, &s->tex.id);
glBindTexture(GL_TEXTURE_2D, s->tex.id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLint w = 1;
GLint h = 1;
struct xrt_colour_rgb_u8 pink = {255, 0, 255};
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB,
GL_UNSIGNED_BYTE, &pink.r);
glBindTexture(GL_TEXTURE_2D, 0);
*out_sink = &s->sink;
return &s->tex;
}