/*****************************************************************************
* opengl.c: VLC GL API
*****************************************************************************
* Copyright (C) 2011 Rémi Denis-Courmont
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <vlc_common.h>
#include <vlc_atomic.h>
#include <vlc_opengl.h>
#include <vlc_codec.h>
#include <vlc_vout_display.h>
#include "../libvlc.h"
#include <vlc_modules.h>
static const struct vlc_gl_cfg gl_cfg_default = {
.need_alpha = false
};
struct vlc_gl_priv_t
{
vlc_gl_t gl;
};
static int vlc_gl_start(void *func, bool forced, va_list ap)
{
vlc_gl_activate activate = func;
vlc_gl_t *gl = va_arg(ap, vlc_gl_t *);
unsigned width = va_arg(ap, unsigned);
unsigned height = va_arg(ap, unsigned);
const struct vlc_gl_cfg *gl_cfg = va_arg(ap, const struct vlc_gl_cfg *);
int ret = activate(gl, width, height, gl_cfg);
if (ret)
vlc_objres_clear(VLC_OBJECT(gl));
(void) forced;
return ret;
}
vlc_gl_t *vlc_gl_Create(const struct vout_display_cfg *restrict cfg,
unsigned flags, const char *name,
const struct vlc_gl_cfg * gl_cfg)
{
vlc_window_t *wnd = cfg->window;
struct vlc_gl_priv_t *glpriv;
const char *type;
if (gl_cfg == NULL)
gl_cfg = &gl_cfg_default;
enum vlc_gl_api_type api_type;
switch (flags /*& VLC_OPENGL_API_MASK*/)
{
case VLC_OPENGL:
type = "opengl";
api_type = VLC_OPENGL;
break;
case VLC_OPENGL_ES2:
type = "opengl es2";
api_type = VLC_OPENGL_ES2;
break;
default:
return NULL;
}
glpriv = vlc_custom_create(VLC_OBJECT(wnd), sizeof (*glpriv), "gl");
if (unlikely(glpriv == NULL))
return NULL;
vlc_gl_t *gl = &glpriv->gl;
gl->api_type = api_type;
gl->orientation = ORIENT_NORMAL;
gl->surface = wnd;
gl->device = NULL;
gl->module = vlc_module_load(vlc_object_logger(gl), type, name, true,
vlc_gl_start, gl,
cfg->display.width, cfg->display.height, gl_cfg);
if (gl->module == NULL)
{
vlc_object_delete(gl);
return NULL;
}
assert(gl->ops);
assert(gl->ops->make_current);
assert(gl->ops->release_current);
assert(gl->ops->swap);
assert(gl->ops->get_proc_address);
return &glpriv->gl;
}
vlc_gl_t *vlc_gl_CreateOffscreen(vlc_object_t *parent,
struct vlc_decoder_device *device,
unsigned width, unsigned height,
unsigned flags, const char *name,
const struct vlc_gl_cfg *gl_cfg)
{
struct vlc_gl_priv_t *glpriv;
const char *type;
enum vlc_gl_api_type api_type;
if (gl_cfg == NULL)
gl_cfg = &gl_cfg_default;
switch (flags /*& VLC_OPENGL_API_MASK*/)
{
case VLC_OPENGL:
type = "opengl offscreen";
api_type = VLC_OPENGL;
break;
case VLC_OPENGL_ES2:
type = "opengl es2 offscreen";
api_type = VLC_OPENGL_ES2;
break;
default:
return NULL;
}
glpriv = vlc_custom_create(parent, sizeof (*glpriv), "gl");
if (unlikely(glpriv == NULL))
return NULL;
vlc_gl_t *gl = &glpriv->gl;
gl->api_type = api_type;
gl->orientation = ORIENT_NORMAL;
gl->offscreen_chroma_out = VLC_CODEC_UNKNOWN;
gl->offscreen_vctx_out = NULL;
gl->surface = NULL;
gl->device = device ? vlc_decoder_device_Hold(device) : NULL;
gl->module = vlc_module_load(vlc_object_logger(gl), type, name, true,
vlc_gl_start, gl, width, height, gl_cfg);
if (gl->module == NULL)
{
if (gl->device)
vlc_decoder_device_Release(gl->device);
vlc_object_delete(gl);
return NULL;
}
/* The implementation must initialize the output chroma */
assert(gl->offscreen_chroma_out != VLC_CODEC_UNKNOWN);
assert(gl->ops);
assert(gl->ops->make_current);
assert(gl->ops->release_current);
assert(gl->ops->swap_offscreen);
assert(gl->ops->get_proc_address);
return &glpriv->gl;
}
void vlc_gl_Delete(vlc_gl_t *gl)
{
if (gl->ops->close != NULL)
gl->ops->close(gl);
if (gl->device)
vlc_decoder_device_Release(gl->device);
vlc_objres_clear(VLC_OBJECT(gl));
vlc_object_delete(gl);
}
#include <vlc_window.h>
typedef struct vlc_gl_surface
{
int width;
int height;
vlc_mutex_t lock;
} vlc_gl_surface_t;
static void vlc_gl_surface_ResizeNotify(vlc_window_t *surface,
unsigned width, unsigned height,
vlc_window_ack_cb cb, void *opaque)
{
vlc_gl_surface_t *sys = surface->owner.sys;
msg_Dbg(surface, "resized to %ux%u", width, height);
vlc_mutex_lock(&sys->lock);
sys->width = width;
sys->height = height;
if (cb != NULL)
cb(surface, width, height, opaque);
vlc_mutex_unlock(&sys->lock);
}
vlc_gl_t *vlc_gl_surface_Create(vlc_object_t *obj,
const vlc_window_cfg_t *cfg,
struct vlc_window **restrict wp,
const struct vlc_gl_cfg *gl_cfg)
{
vlc_gl_surface_t *sys = malloc(sizeof (*sys));
if (unlikely(sys == NULL))
return NULL;
sys->width = cfg->width;
sys->height = cfg->height;
vlc_mutex_init(&sys->lock);
static const struct vlc_window_callbacks cbs = {
.resized = vlc_gl_surface_ResizeNotify,
};
vlc_window_owner_t owner = {
.cbs = &cbs,
.sys = sys,
};
char *modlist = var_InheritString(obj, "window");
vlc_window_t *surface = vlc_window_New(obj, modlist, &owner, cfg);
free(modlist);
if (surface == NULL)
goto error;
if (vlc_window_Enable(surface)) {
vlc_window_Delete(surface);
goto error;
}
if (wp != NULL)
*wp = surface;
/* TODO: support ES? */
struct vout_display_cfg dcfg = {
.window = surface,
.display = { .width = cfg->width, cfg->height },
};
vlc_mutex_lock(&sys->lock);
if (sys->width >= 0 && sys->height >= 0) {
dcfg.display.width = sys->width;
dcfg.display.height = sys->height;
sys->width = -1;
sys->height = -1;
}
vlc_mutex_unlock(&sys->lock);
vlc_gl_t *gl = vlc_gl_Create(&dcfg, VLC_OPENGL, NULL, gl_cfg);
if (gl == NULL) {
vlc_window_Disable(surface);
vlc_window_Delete(surface);
goto error;
}
return gl;
error:
free(sys);
return NULL;
}
/**
* Checks if the dimensions of the surface used by the OpenGL context have
* changed (since the previous call), and the OpenGL viewport should be
* updated.
* \return true if at least one dimension has changed, false otherwise
* \warning This function is intrinsically race-prone.
* The dimensions can change asynchronously.
*/
bool vlc_gl_surface_CheckSize(vlc_gl_t *gl, unsigned *restrict width,
unsigned *restrict height)
{
vlc_window_t *surface = gl->surface;
vlc_gl_surface_t *sys = surface->owner.sys;
bool ret = false;
vlc_mutex_lock(&sys->lock);
if (sys->width >= 0 && sys->height >= 0)
{
*width = sys->width;
*height = sys->height;
sys->width = -1;
sys->height = -1;
vlc_gl_Resize(gl, *width, *height);
ret = true;
}
vlc_mutex_unlock(&sys->lock);
return ret;
}
void vlc_gl_surface_Destroy(vlc_gl_t *gl)
{
vlc_window_t *surface = gl->surface;
vlc_gl_surface_t *sys = surface->owner.sys;
vlc_gl_Delete(gl);
vlc_window_Disable(surface);
vlc_window_Delete(surface);
free(sys);
}
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland
|
|