|
22 | 22 | #endif |
23 | 23 |
|
24 | 24 | #ifdef PL_HAVE_OPENGL |
| 25 | +#include "mpv/render_gl.h" |
25 | 26 | #include <libplacebo/opengl.h> |
| 27 | +#include "video/out/gpu_next/libmpv_gpu_next.h" |
| 28 | +#include "video/out/gpu_next/ra.h" |
26 | 29 | #endif |
27 | 30 |
|
28 | 31 | #include "context.h" |
29 | 32 | #include "config.h" |
30 | 33 | #include "common/common.h" |
| 34 | +#include "common/msg.h" |
31 | 35 | #include "options/m_config.h" |
32 | 36 | #include "video/out/placebo/utils.h" |
33 | 37 | #include "video/out/gpu/video.h" |
|
50 | 54 | #include "video/out/vulkan/context.h" |
51 | 55 | #endif |
52 | 56 |
|
| 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 | + |
53 | 70 | #if HAVE_D3D11 |
54 | 71 | static bool d3d11_pl_init(struct vo *vo, struct gpu_ctx *ctx, |
55 | 72 | struct ra_ctx_opts *ctx_opts) |
@@ -235,3 +252,177 @@ void gpu_ctx_destroy(struct gpu_ctx **ctxp) |
235 | 252 | talloc_free(ctx); |
236 | 253 | *ctxp = NULL; |
237 | 254 | } |
| 255 | + |
| 256 | +#if HAVE_GL && defined(PL_HAVE_OPENGL) |
| 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