Skip to content

Commit ebd470e

Browse files
author
sparks
committed
Implement libmpv with a gpu_next backend based on libplacebo
1 parent 0bbcc91 commit ebd470e

File tree

10 files changed

+1691
-6
lines changed

10 files changed

+1691
-6
lines changed

include/mpv/render.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,16 @@ typedef enum mpv_render_param_type {
422422
* See MPV_RENDER_PARAM_SW_STRIDE for alignment requirements.
423423
*/
424424
MPV_RENDER_PARAM_SW_POINTER = 20,
425+
/**
426+
* The name of the render backend to use. Valid for mpv_render_context_create().
427+
*
428+
* Type: char*
429+
*
430+
* Defined backends:
431+
* "gpu" (default)
432+
* "gpu-next"
433+
*/
434+
MPV_RENDER_PARAM_BACKEND = 21,
425435
} mpv_render_param_type;
426436

427437
/**

meson.build

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ sources = files(
237237
'video/out/gpu/utils.c',
238238
'video/out/gpu/video.c',
239239
'video/out/gpu/video_shaders.c',
240+
'video/out/gpu_next/libmpv_gpu_next.c',
241+
'video/out/gpu_next/ra.c',
242+
'video/out/gpu_next/video.c',
240243
'video/out/libmpv_sw.c',
241244
'video/out/vo.c',
242245
'video/out/vo_gpu.c',

video/out/gpu_next/context.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@
2222
#endif
2323

2424
#ifdef PL_HAVE_OPENGL
25+
#include "mpv/render_gl.h"
2526
#include <libplacebo/opengl.h>
27+
#include "video/out/gpu_next/libmpv_gpu_next.h"
28+
#include "video/out/gpu_next/ra.h"
2629
#endif
2730

2831
#include "context.h"
2932
#include "config.h"
3033
#include "common/common.h"
34+
#include "common/msg.h"
3135
#include "options/m_config.h"
3236
#include "video/out/placebo/utils.h"
3337
#include "video/out/gpu/video.h"
@@ -50,6 +54,19 @@
5054
#include "video/out/vulkan/context.h"
5155
#endif
5256

57+
#if HAVE_GL
58+
// Store Libplacebo OpenGL context information.
59+
struct priv {
60+
pl_log pl_log;
61+
pl_opengl gl;
62+
pl_gpu gpu;
63+
struct ra_next *ra;
64+
65+
// Store a persistent copy of the init params to avoid a dangling pointer.
66+
mpv_opengl_init_params gl_params;
67+
};
68+
#endif
69+
5370
#if HAVE_D3D11
5471
static bool d3d11_pl_init(struct vo *vo, struct gpu_ctx *ctx,
5572
struct ra_ctx_opts *ctx_opts)
@@ -235,3 +252,177 @@ void gpu_ctx_destroy(struct gpu_ctx **ctxp)
235252
talloc_free(ctx);
236253
*ctxp = NULL;
237254
}
255+
256+
#if HAVE_GL
257+
/**
258+
* @brief Callback to make the OpenGL context current.
259+
* @param priv Pointer to the private data (mpv_opengl_init_params).
260+
* @return True on success, false on failure.
261+
*/
262+
static bool pl_callback_makecurrent_gl(void *priv)
263+
{
264+
mpv_opengl_init_params *gl_params = priv;
265+
// The mpv render API contract specifies that the client must make the
266+
// context current inside its get_proc_address callback. We can trigger
267+
// this by calling it with a harmless, common function name.
268+
if (gl_params && gl_params->get_proc_address) {
269+
gl_params->get_proc_address(gl_params->get_proc_address_ctx, "glGetString");
270+
return true;
271+
}
272+
273+
return false;
274+
}
275+
276+
/**
277+
* @brief Callback to release the OpenGL context.
278+
* @param priv Pointer to the private data (mpv_opengl_init_params).
279+
*/
280+
static void pl_callback_releasecurrent_gl(void *priv)
281+
{
282+
}
283+
284+
/**
285+
* @brief Callback to log messages from libplacebo.
286+
* @param log_priv Pointer to the private data (mp_log).
287+
* @param level The log level.
288+
* @param msg The log message.
289+
*/
290+
static void pl_log_cb(void *log_priv, enum pl_log_level level, const char *msg)
291+
{
292+
struct mp_log *log = log_priv;
293+
mp_msg(log, MSGL_WARN, "[gpu-next:pl] %s\n", msg);
294+
}
295+
296+
/**
297+
* @brief Initializes the OpenGL context for the GPU next renderer.
298+
* @param ctx The libmpv_gpu_next_context to initialize.
299+
* @param params The render parameters.
300+
* @return 0 on success, negative error code on failure.
301+
*/
302+
static int libmpv_gpu_next_init_gl(struct libmpv_gpu_next_context *ctx, mpv_render_param *params)
303+
{
304+
ctx->priv = talloc_zero(NULL, struct priv);
305+
struct priv *p = ctx->priv;
306+
307+
mpv_opengl_init_params *gl_params =
308+
get_mpv_render_param(params, MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, NULL);
309+
if (!gl_params || !gl_params->get_proc_address)
310+
return MPV_ERROR_INVALID_PARAMETER;
311+
312+
// Make a persistent copy of the params struct's contents.
313+
p->gl_params = *gl_params;
314+
315+
// Setup libplacebo logging
316+
struct pl_log_params log_params = {
317+
.log_level = PL_LOG_DEBUG
318+
};
319+
320+
// Enable verbose logging if trace is enabled
321+
if (mp_msg_test(ctx->log, MSGL_TRACE)) {
322+
log_params.log_cb = pl_log_cb;
323+
log_params.log_priv = ctx->log;
324+
}
325+
326+
p->pl_log = pl_log_create(PL_API_VER, &log_params);
327+
p->gl = pl_opengl_create(p->pl_log, pl_opengl_params(
328+
.get_proc_addr_ex = (pl_voidfunc_t (*)(void*, const char*))gl_params->get_proc_address,
329+
.proc_ctx = gl_params->get_proc_address_ctx,
330+
.make_current = pl_callback_makecurrent_gl,
331+
.release_current = pl_callback_releasecurrent_gl,
332+
.priv = &p->gl_params // Pass the ADDRESS of our persistent copy
333+
));
334+
335+
if (!p->gl) {
336+
MP_ERR(ctx, "Failed to create libplacebo OpenGL context.\n");
337+
pl_log_destroy(&p->pl_log);
338+
return MPV_ERROR_UNSUPPORTED;
339+
}
340+
p->gpu = p->gl->gpu;
341+
342+
// Pass the libplacebo log to the RA as well.
343+
p->ra = ra_pl_create(p->gpu, ctx->log, p->pl_log);
344+
if (!p->ra) {
345+
pl_opengl_destroy(&p->gl);
346+
pl_log_destroy(&p->pl_log);
347+
return MPV_ERROR_VO_INIT_FAILED;
348+
}
349+
350+
ctx->ra = p->ra;
351+
ctx->gpu = p->gpu;
352+
return 0;
353+
}
354+
355+
/**
356+
* @brief Wraps an OpenGL framebuffer object (FBO) as a libplacebo texture.
357+
* @param ctx The libmpv_gpu_next_context.
358+
* @param params The render parameters.
359+
* @param out_tex Pointer to the output texture.
360+
* @return 0 on success, negative error code on failure.
361+
*/
362+
static int libmpv_gpu_next_wrap_fbo_gl(struct libmpv_gpu_next_context *ctx,
363+
mpv_render_param *params, pl_tex *out_tex)
364+
{
365+
struct priv *p = ctx->priv;
366+
*out_tex = NULL;
367+
368+
// Get the FBO from the render parameters
369+
mpv_opengl_fbo *fbo =
370+
get_mpv_render_param(params, MPV_RENDER_PARAM_OPENGL_FBO, NULL);
371+
if (!fbo)
372+
return MPV_ERROR_INVALID_PARAMETER;
373+
374+
// Wrap the FBO as a libplacebo texture
375+
pl_tex tex = pl_opengl_wrap(p->gpu, pl_opengl_wrap_params(
376+
.framebuffer = fbo->fbo,
377+
.width = fbo->w,
378+
.height = fbo->h,
379+
.iformat = fbo->internal_format
380+
));
381+
382+
if (!tex) {
383+
MP_ERR(ctx, "Failed to wrap provided FBO as a libplacebo texture.\n");
384+
return MPV_ERROR_GENERIC;
385+
}
386+
387+
*out_tex = tex;
388+
return 0;
389+
}
390+
391+
/**
392+
* @brief Callback to mark the end of a frame rendering.
393+
* @param ctx The libmpv_gpu_next_context.
394+
*/
395+
static void libmpv_gpu_next_done_frame_gl(struct libmpv_gpu_next_context *ctx)
396+
{
397+
// Nothing to do (yet), leaving the function empty.
398+
}
399+
400+
/**
401+
* @brief Destroys the OpenGL context for the GPU next renderer.
402+
* @param ctx The libmpv_gpu_next_context to destroy.
403+
*/
404+
static void libmpv_gpu_next_destroy_gl(struct libmpv_gpu_next_context *ctx)
405+
{
406+
struct priv *p = ctx->priv;
407+
if (!p)
408+
return;
409+
410+
if (p->ra) {
411+
ra_pl_destroy(&p->ra);
412+
}
413+
414+
pl_opengl_destroy(&p->gl);
415+
pl_log_destroy(&p->pl_log);
416+
}
417+
418+
/**
419+
* @brief Context functions for the OpenGL GPU next renderer.
420+
*/
421+
const struct libmpv_gpu_next_context_fns libmpv_gpu_next_context_gl = {
422+
.api_name = MPV_RENDER_API_TYPE_OPENGL,
423+
.init = libmpv_gpu_next_init_gl,
424+
.wrap_fbo = libmpv_gpu_next_wrap_fbo_gl,
425+
.done_frame = libmpv_gpu_next_done_frame_gl,
426+
.destroy = libmpv_gpu_next_destroy_gl,
427+
};
428+
#endif

0 commit comments

Comments
 (0)