summaryrefslogtreecommitdiffstats
path: root/video/out/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/opengl')
-rw-r--r--video/out/opengl/common.c2
-rw-r--r--video/out/opengl/context_drm_egl.c4
-rw-r--r--video/out/opengl/context_glx.c2
-rw-r--r--video/out/opengl/context_rpi.c327
-rw-r--r--video/out/opengl/context_wayland.c4
-rw-r--r--video/out/opengl/context_win.c22
-rw-r--r--video/out/opengl/egl_helpers.c10
-rw-r--r--video/out/opengl/formats.c2
-rw-r--r--video/out/opengl/hwdec_rpi.c384
9 files changed, 31 insertions, 726 deletions
diff --git a/video/out/opengl/common.c b/video/out/opengl/common.c
index ee26508..e3fc1ba 100644
--- a/video/out/opengl/common.c
+++ b/video/out/opengl/common.c
@@ -398,7 +398,7 @@ static const struct gl_functions gl_functions[] = {
.provides = MPGL_CAP_NESTED_ARRAY,
},
// Swap control, always an OS specific extension
- // The OSX code loads this manually.
+ // The macOS code loads this manually.
{
.extension = "GLX_SGI_swap_control",
.functions = (const struct gl_function[]) {
diff --git a/video/out/opengl/context_drm_egl.c b/video/out/opengl/context_drm_egl.c
index 2db428f..ff4de18 100644
--- a/video/out/opengl/context_drm_egl.c
+++ b/video/out/opengl/context_drm_egl.c
@@ -616,6 +616,10 @@ static bool drm_egl_init(struct ra_ctx *ctx)
xrgb_format = GBM_FORMAT_XBGR8888;
break;
default:
+ if (drm->opts->drm_format != DRM_OPTS_FORMAT_XRGB8888) {
+ MP_VERBOSE(ctx->vo, "Requested format not supported by context, "
+ "falling back to xrgb8888\n");
+ }
argb_format = GBM_FORMAT_ARGB8888;
xrgb_format = GBM_FORMAT_XRGB8888;
break;
diff --git a/video/out/opengl/context_glx.c b/video/out/opengl/context_glx.c
index 4062224..a2a63e1 100644
--- a/video/out/opengl/context_glx.c
+++ b/video/out/opengl/context_glx.c
@@ -25,7 +25,7 @@
#define GLX_CONTEXT_FLAGS_ARB 0x2094
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#ifndef __APPLE__
-// These are respectively 0x00000001 and 0x00000002 on OSX
+// These are respectively 0x00000001 and 0x00000002 on macOS
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
#endif
diff --git a/video/out/opengl/context_rpi.c b/video/out/opengl/context_rpi.c
deleted file mode 100644
index 0b6babb..0000000
--- a/video/out/opengl/context_rpi.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * This file is part of mpv.
- *
- * mpv 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.
- *
- * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <assert.h>
-#include <stdatomic.h>
-#include <stddef.h>
-
-#include <bcm_host.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#include "common/common.h"
-#include "video/out/win_state.h"
-#include "context.h"
-#include "egl_helpers.h"
-
-struct priv {
- struct GL gl;
- DISPMANX_DISPLAY_HANDLE_T display;
- DISPMANX_ELEMENT_HANDLE_T window;
- DISPMANX_UPDATE_HANDLE_T update;
- EGLDisplay egl_display;
- EGLConfig egl_config;
- EGLContext egl_context;
- EGLSurface egl_surface;
- // yep, the API keeps a pointer to it
- EGL_DISPMANX_WINDOW_T egl_window;
- int x, y, w, h;
- double display_fps;
- atomic_int reload_display;
- int win_params[4];
-};
-
-static void tv_callback(void *callback_data, uint32_t reason, uint32_t param1,
- uint32_t param2)
-{
- struct ra_ctx *ctx = callback_data;
- struct priv *p = ctx->priv;
- atomic_store(&p->reload_display, true);
- vo_wakeup(ctx->vo);
-}
-
-static void destroy_dispmanx(struct ra_ctx *ctx)
-{
- struct priv *p = ctx->priv;
-
- if (p->egl_surface) {
- eglMakeCurrent(p->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
- EGL_NO_CONTEXT);
- eglDestroySurface(p->egl_display, p->egl_surface);
- p->egl_surface = EGL_NO_SURFACE;
- }
-
- if (p->window)
- vc_dispmanx_element_remove(p->update, p->window);
- p->window = 0;
- if (p->display)
- vc_dispmanx_display_close(p->display);
- p->display = 0;
- if (p->update)
- vc_dispmanx_update_submit_sync(p->update);
- p->update = 0;
-}
-
-static void rpi_uninit(struct ra_ctx *ctx)
-{
- struct priv *p = ctx->priv;
- ra_gl_ctx_uninit(ctx);
-
- vc_tv_unregister_callback_full(tv_callback, ctx);
-
- destroy_dispmanx(ctx);
-
- if (p->egl_context)
- eglDestroyContext(p->egl_display, p->egl_context);
- p->egl_context = EGL_NO_CONTEXT;
- eglReleaseThread();
- p->egl_display = EGL_NO_DISPLAY;
-}
-
-static bool recreate_dispmanx(struct ra_ctx *ctx)
-{
- struct priv *p = ctx->priv;
- int display_nr = 0;
- int layer = 0;
-
- MP_VERBOSE(ctx, "Recreating DISPMANX state...\n");
-
- destroy_dispmanx(ctx);
-
- p->display = vc_dispmanx_display_open(display_nr);
- p->update = vc_dispmanx_update_start(0);
- if (!p->display || !p->update) {
- MP_FATAL(ctx, "Could not get DISPMANX objects.\n");
- goto fail;
- }
-
- uint32_t dispw, disph;
- if (graphics_get_display_size(0, &dispw, &disph) < 0) {
- MP_FATAL(ctx, "Could not get display size.\n");
- goto fail;
- }
- p->w = dispw;
- p->h = disph;
-
- if (ctx->vo->opts->fullscreen) {
- p->x = p->y = 0;
- } else {
- struct vo_win_geometry geo;
- struct mp_rect screenrc = {0, 0, p->w, p->h};
-
- vo_calc_window_geometry(ctx->vo, &screenrc, &geo);
-
- mp_rect_intersection(&geo.win, &screenrc);
-
- p->x = geo.win.x0;
- p->y = geo.win.y0;
- p->w = geo.win.x1 - geo.win.x0;
- p->h = geo.win.y1 - geo.win.y0;
- }
-
- // dispmanx is like a neanderthal version of Wayland - you can add an
- // overlay any place on the screen.
- VC_RECT_T dst = {.x = p->x, .y = p->y, .width = p->w, .height = p->h};
- VC_RECT_T src = {.width = p->w << 16, .height = p->h << 16};
- VC_DISPMANX_ALPHA_T alpha = {
- .flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS,
- .opacity = 0xFF,
- };
- p->window = vc_dispmanx_element_add(p->update, p->display, layer, &dst, 0,
- &src, DISPMANX_PROTECTION_NONE, &alpha,
- 0, 0);
- if (!p->window) {
- MP_FATAL(ctx, "Could not add DISPMANX element.\n");
- goto fail;
- }
-
- vc_dispmanx_update_submit_sync(p->update);
- p->update = vc_dispmanx_update_start(0);
-
- p->egl_window = (EGL_DISPMANX_WINDOW_T){
- .element = p->window,
- .width = p->w,
- .height = p->h,
- };
- p->egl_surface = eglCreateWindowSurface(p->egl_display, p->egl_config,
- &p->egl_window, NULL);
-
- if (p->egl_surface == EGL_NO_SURFACE) {
- MP_FATAL(ctx, "Could not create EGL surface!\n");
- goto fail;
- }
-
- if (!eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface,
- p->egl_context))
- {
- MP_FATAL(ctx, "Failed to set context!\n");
- goto fail;
- }
-
- p->display_fps = 0;
- TV_GET_STATE_RESP_T tvstate;
- TV_DISPLAY_STATE_T tvstate_disp;
- if (!vc_tv_get_state(&tvstate) && !vc_tv_get_display_state(&tvstate_disp)) {
- if (tvstate_disp.state & (VC_HDMI_HDMI | VC_HDMI_DVI)) {
- p->display_fps = tvstate_disp.display.hdmi.frame_rate;
-
- HDMI_PROPERTY_PARAM_T param = {
- .property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE,
- };
- if (!vc_tv_hdmi_get_property(&param) &&
- param.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC)
- p->display_fps = p->display_fps / 1.001;
- } else {
- p->display_fps = tvstate_disp.display.sdtv.frame_rate;
- }
- }
-
- p->win_params[0] = display_nr;
- p->win_params[1] = layer;
- p->win_params[2] = p->x;
- p->win_params[3] = p->y;
-
- ctx->vo->dwidth = p->w;
- ctx->vo->dheight = p->h;
- if (ctx->swapchain)
- ra_gl_ctx_resize(ctx->swapchain, p->w, p->h, 0);
-
- ctx->vo->want_redraw = true;
-
- vo_event(ctx->vo, VO_EVENT_WIN_STATE);
- return true;
-
-fail:
- destroy_dispmanx(ctx);
- return false;
-}
-
-static void rpi_swap_buffers(struct ra_ctx *ctx)
-{
- struct priv *p = ctx->priv;
- eglSwapBuffers(p->egl_display, p->egl_surface);
-}
-
-static bool rpi_init(struct ra_ctx *ctx)
-{
- struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
-
- bcm_host_init();
-
- vc_tv_register_callback(tv_callback, ctx);
-
- p->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (!eglInitialize(p->egl_display, NULL, NULL)) {
- MP_FATAL(ctx, "EGL failed to initialize.\n");
- goto fail;
- }
-
- if (!mpegl_create_context(ctx, p->egl_display, &p->egl_context, &p->egl_config))
- goto fail;
-
- if (!recreate_dispmanx(ctx))
- goto fail;
-
- mpegl_load_functions(&p->gl, ctx->log);
-
- struct ra_gl_ctx_params params = {
- .swap_buffers = rpi_swap_buffers,
- };
-
- if (!ra_gl_ctx_init(ctx, &p->gl, params))
- goto fail;
-
- ra_add_native_resource(ctx->ra, "MPV_RPI_WINDOW", p->win_params);
-
- ra_gl_ctx_resize(ctx->swapchain, ctx->vo->dwidth, ctx->vo->dheight, 0);
- return true;
-
-fail:
- rpi_uninit(ctx);
- return false;
-}
-
-static bool rpi_reconfig(struct ra_ctx *ctx)
-{
- return recreate_dispmanx(ctx);
-}
-
-static struct mp_image *take_screenshot(struct ra_ctx *ctx)
-{
- struct priv *p = ctx->priv;
-
- if (!p->display)
- return NULL;
-
- struct mp_image *img = mp_image_alloc(IMGFMT_BGR0, p->w, p->h);
- if (!img)
- return NULL;
-
- DISPMANX_RESOURCE_HANDLE_T resource =
- vc_dispmanx_resource_create(VC_IMAGE_ARGB8888,
- img->w | ((img->w * 4) << 16), img->h,
- &(int32_t){0});
- if (!resource)
- goto fail;
-
- if (vc_dispmanx_snapshot(p->display, resource, 0))
- goto fail;
-
- VC_RECT_T rc = {.width = img->w, .height = img->h};
- if (vc_dispmanx_resource_read_data(resource, &rc, img->planes[0], img->stride[0]))
- goto fail;
-
- vc_dispmanx_resource_delete(resource);
- return img;
-
-fail:
- vc_dispmanx_resource_delete(resource);
- talloc_free(img);
- return NULL;
-}
-
-static int rpi_control(struct ra_ctx *ctx, int *events, int request, void *arg)
-{
- struct priv *p = ctx->priv;
-
- switch (request) {
- case VOCTRL_SCREENSHOT_WIN:
- *(struct mp_image **)arg = take_screenshot(ctx);
- return VO_TRUE;
- case VOCTRL_CHECK_EVENTS:
- if (atomic_fetch_and(&p->reload_display, 0)) {
- MP_WARN(ctx, "Recovering from display mode switch...\n");
- recreate_dispmanx(ctx);
- }
- return VO_TRUE;
- case VOCTRL_GET_DISPLAY_FPS:
- *(double *)arg = p->display_fps;
- return VO_TRUE;
- }
-
- return VO_NOTIMPL;
-}
-
-const struct ra_ctx_fns ra_ctx_rpi = {
- .type = "opengl",
- .name = "rpi",
- .reconfig = rpi_reconfig,
- .control = rpi_control,
- .init = rpi_init,
- .uninit = rpi_uninit,
-};
diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c
index 26c5268..2c5611b 100644
--- a/video/out/opengl/context_wayland.c
+++ b/video/out/opengl/context_wayland.c
@@ -47,14 +47,14 @@ static void resize(struct ra_ctx *ctx)
const int32_t width = mp_rect_w(wl->geometry);
const int32_t height = mp_rect_h(wl->geometry);
+ vo_wayland_handle_scale(wl);
+
vo_wayland_set_opaque_region(wl, ctx->opts.want_alpha);
if (p->egl_window)
wl_egl_window_resize(p->egl_window, width, height, 0, 0);
wl->vo->dwidth = width;
wl->vo->dheight = height;
-
- vo_wayland_handle_fractional_scale(wl);
}
static bool wayland_egl_check_visible(struct ra_ctx *ctx)
diff --git a/video/out/opengl/context_win.c b/video/out/opengl/context_win.c
index 968b176..a582e28 100644
--- a/video/out/opengl/context_win.c
+++ b/video/out/opengl/context_win.c
@@ -96,6 +96,7 @@ static bool create_dc(struct ra_ctx *ctx)
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
+ pfd.cAlphaBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
int pf = ChoosePixelFormat(hdc, &pfd);
@@ -293,6 +294,9 @@ static bool wgl_init(struct ra_ctx *ctx)
if (!vo_w32_init(ctx->vo))
goto fail;
+ if (ctx->opts.want_alpha)
+ vo_w32_set_transparency(ctx->vo, ctx->opts.want_alpha);
+
vo_w32_run_on_thread(ctx->vo, create_ctx, ctx);
if (!p->context)
goto fail;
@@ -368,11 +372,17 @@ static int wgl_control(struct ra_ctx *ctx, int *events, int request, void *arg)
return ret;
}
+static void wgl_update_render_opts(struct ra_ctx *ctx)
+{
+ vo_w32_set_transparency(ctx->vo, ctx->opts.want_alpha);
+}
+
const struct ra_ctx_fns ra_ctx_wgl = {
- .type = "opengl",
- .name = "win",
- .init = wgl_init,
- .reconfig = wgl_reconfig,
- .control = wgl_control,
- .uninit = wgl_uninit,
+ .type = "opengl",
+ .name = "win",
+ .init = wgl_init,
+ .reconfig = wgl_reconfig,
+ .control = wgl_control,
+ .update_render_opts = wgl_update_render_opts,
+ .uninit = wgl_uninit,
};
diff --git a/video/out/opengl/egl_helpers.c b/video/out/opengl/egl_helpers.c
index 3bf6239..18d9027 100644
--- a/video/out/opengl/egl_helpers.c
+++ b/video/out/opengl/egl_helpers.c
@@ -192,18 +192,20 @@ static bool create_context(struct ra_ctx *ctx, EGLDisplay display,
}
if (!egl_ctx) {
// Fallback for EGL 1.4 without EGL_KHR_create_context or GLES
- // Add the context flags only for GLES - GL has been attempted above
EGLint attrs[] = {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- es ? EGL_CONTEXT_FLAGS_KHR : EGL_NONE, ctx_flags,
+ EGL_CONTEXT_FLAGS_KHR, ctx_flags,
+ es ? EGL_CONTEXT_CLIENT_VERSION : EGL_NONE, 2,
EGL_NONE
};
egl_ctx = eglCreateContext(display, config, EGL_NO_CONTEXT, attrs);
+ if (!egl_ctx)
+ egl_ctx = eglCreateContext(display, config, EGL_NO_CONTEXT, &attrs[2]);
}
if (!egl_ctx) {
- MP_MSG(ctx, msgl, "Could not create EGL context for %s!\n", name);
+ MP_MSG(ctx, msgl, "Could not create EGL context for %s (error=%d)!\n",
+ name, eglGetError());
return false;
}
diff --git a/video/out/opengl/formats.c b/video/out/opengl/formats.c
index a0b79e2..dd0e89d 100644
--- a/video/out/opengl/formats.c
+++ b/video/out/opengl/formats.c
@@ -94,7 +94,7 @@ const struct gl_format gl_formats[] = {
// Special formats.
{"rgb565", GL_RGB8, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, F_TF | F_GL2 | F_GL3},
- // Worthless, but needed by OSX videotoolbox interop on old Apple hardware.
+ // Worthless, but needed by macOS videotoolbox interop on old Apple hardware.
{"appleyp", GL_RGB, GL_RGB_422_APPLE,
GL_UNSIGNED_SHORT_8_8_APPLE, F_TF | F_APPL},
diff --git a/video/out/opengl/hwdec_rpi.c b/video/out/opengl/hwdec_rpi.c
deleted file mode 100644
index 5362832..0000000
--- a/video/out/opengl/hwdec_rpi.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * This file is part of mpv.
- *
- * mpv 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.
- *
- * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <stdbool.h>
-#include <assert.h>
-
-#include <bcm_host.h>
-#include <interface/mmal/mmal.h>
-#include <interface/mmal/util/mmal_util.h>
-#include <interface/mmal/util/mmal_default_components.h>
-#include <interface/mmal/vc/mmal_vc_api.h>
-
-#include <libavutil/rational.h>
-
-#include "common/common.h"
-#include "common/msg.h"
-#include "video/mp_image.h"
-#include "video/out/gpu/hwdec.h"
-
-#include "common.h"
-
-struct priv {
- struct mp_log *log;
-
- struct mp_image_params params;
-
- MMAL_COMPONENT_T *renderer;
- bool renderer_enabled;
-
- // for RAM input
- MMAL_POOL_T *swpool;
-
- struct mp_image *current_frame;
-
- struct mp_rect src, dst;
- int cur_window[4]; // raw user params
-};
-
-// Magic alignments (in pixels) expected by the MMAL internals.
-#define ALIGN_W 32
-#define ALIGN_H 16
-
-// Make mpi point to buffer, assuming MMAL_ENCODING_I420.
-// buffer can be NULL.
-// Return the required buffer space.
-static size_t layout_buffer(struct mp_image *mpi, MMAL_BUFFER_HEADER_T *buffer,
- struct mp_image_params *params)
-{
- assert(params->imgfmt == IMGFMT_420P);
- mp_image_set_params(mpi, params);
- int w = MP_ALIGN_UP(params->w, ALIGN_W);
- int h = MP_ALIGN_UP(params->h, ALIGN_H);
- uint8_t *cur = buffer ? buffer->data : NULL;
- size_t size = 0;
- for (int i = 0; i < 3; i++) {
- int div = i ? 2 : 1;
- mpi->planes[i] = cur;
- mpi->stride[i] = w / div;
- size_t plane_size = h / div * mpi->stride[i];
- if (cur)
- cur += plane_size;
- size += plane_size;
- }
- return size;
-}
-
-static MMAL_FOURCC_T map_csp(enum mp_csp csp)
-{
- switch (csp) {
- case MP_CSP_BT_601: return MMAL_COLOR_SPACE_ITUR_BT601;
- case MP_CSP_BT_709: return MMAL_COLOR_SPACE_ITUR_BT709;
- case MP_CSP_SMPTE_240M: return MMAL_COLOR_SPACE_SMPTE240M;
- default: return MMAL_COLOR_SPACE_UNKNOWN;
- }
-}
-
-static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
-{
- mmal_buffer_header_release(buffer);
-}
-
-static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
-{
- struct mp_image *mpi = buffer->user_data;
- talloc_free(mpi);
-}
-
-static void disable_renderer(struct ra_hwdec *hw)
-{
- struct priv *p = hw->priv;
-
- if (p->renderer_enabled) {
- mmal_port_disable(p->renderer->control);
- mmal_port_disable(p->renderer->input[0]);
-
- mmal_port_flush(p->renderer->control);
- mmal_port_flush(p->renderer->input[0]);
-
- mmal_component_disable(p->renderer);
- }
- mmal_pool_destroy(p->swpool);
- p->swpool = NULL;
- p->renderer_enabled = false;
-}
-
-// check_window_only: assume params and dst/src rc are unchanged
-static void update_overlay(struct ra_hwdec *hw, bool check_window_only)
-{
- struct priv *p = hw->priv;
- MMAL_PORT_T *input = p->renderer->input[0];
- struct mp_rect src = p->src;
- struct mp_rect dst = p->dst;
-
- int defs[4] = {0, 0, 0, 0};
- int *z = ra_get_native_resource(hw->ra_ctx->ra, "MPV_RPI_WINDOW");
- if (!z)
- z = defs;
-
- // As documented in the libmpv openglcb headers.
- int display = z[0];
- int layer = z[1];
- int x = z[2];
- int y = z[3];
-
- if (check_window_only && memcmp(z, p->cur_window, sizeof(p->cur_window)) == 0)
- return;
-
- memcpy(p->cur_window, z, sizeof(p->cur_window));
-
- int rotate[] = {MMAL_DISPLAY_ROT0,
- MMAL_DISPLAY_ROT90,
- MMAL_DISPLAY_ROT180,
- MMAL_DISPLAY_ROT270};
-
- int src_w = src.x1 - src.x0, src_h = src.y1 - src.y0,
- dst_w = dst.x1 - dst.x0, dst_h = dst.y1 - dst.y0;
- int p_x, p_y;
- av_reduce(&p_x, &p_y, dst_w * src_h, src_w * dst_h, 16000);
- MMAL_DISPLAYREGION_T dr = {
- .hdr = { .id = MMAL_PARAMETER_DISPLAYREGION,
- .size = sizeof(MMAL_DISPLAYREGION_T), },
- .src_rect = { .x = src.x0, .y = src.y0,
- .width = src_w, .height = src_h },
- .dest_rect = { .x = dst.x0 + x, .y = dst.y0 + y,
- .width = dst_w, .height = dst_h },
- .layer = layer - 1, // under the GL layer
- .display_num = display,
- .pixel_x = p_x,
- .pixel_y = p_y,
- .transform = rotate[p->params.rotate / 90],
- .fullscreen = 0,
- .set = MMAL_DISPLAY_SET_SRC_RECT | MMAL_DISPLAY_SET_DEST_RECT |
- MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_NUM |
- MMAL_DISPLAY_SET_PIXEL | MMAL_DISPLAY_SET_TRANSFORM |
- MMAL_DISPLAY_SET_FULLSCREEN,
- };
-
- if (p->params.rotate % 180 == 90) {
- MPSWAP(int, dr.src_rect.x, dr.src_rect.y);
- MPSWAP(int, dr.src_rect.width, dr.src_rect.height);
- }
-
- if (mmal_port_parameter_set(input, &dr.hdr))
- MP_WARN(p, "could not set video rectangle\n");
-}
-
-static int enable_renderer(struct ra_hwdec *hw)
-{
- struct priv *p = hw->priv;
- MMAL_PORT_T *input = p->renderer->input[0];
- struct mp_image_params *params = &p->params;
-
- if (p->renderer_enabled)
- return 0;
-
- if (!params->imgfmt)
- return -1;
-
- bool opaque = params->imgfmt == IMGFMT_MMAL;
-
- input->format->encoding = opaque ? MMAL_ENCODING_OPAQUE : MMAL_ENCODING_I420;
- input->format->es->video.width = MP_ALIGN_UP(params->w, ALIGN_W);
- input->format->es->video.height = MP_ALIGN_UP(params->h, ALIGN_H);
- input->format->es->video.crop = (MMAL_RECT_T){0, 0, params->w, params->h};
- input->format->es->video.par = (MMAL_RATIONAL_T){params->p_w, params->p_h};
- input->format->es->video.color_space = map_csp(params->color.space);
-
- if (mmal_port_format_commit(input))
- return -1;
-
- input->buffer_num = MPMAX(input->buffer_num_min,
- input->buffer_num_recommended) + 3;
- input->buffer_size = MPMAX(input->buffer_size_min,
- input->buffer_size_recommended);
-
- if (!opaque) {
- size_t size = layout_buffer(&(struct mp_image){0}, NULL, params);
- if (input->buffer_size != size) {
- MP_FATAL(hw, "We disagree with MMAL about buffer sizes.\n");
- return -1;
- }
-
- p->swpool = mmal_pool_create(input->buffer_num, input->buffer_size);
- if (!p->swpool) {
- MP_FATAL(hw, "Could not allocate buffer pool.\n");
- return -1;
- }
- }
-
- update_overlay(hw, false);
-
- p->renderer_enabled = true;
-
- if (mmal_port_enable(p->renderer->control, control_port_cb))
- return -1;
-
- if (mmal_port_enable(input, input_port_cb))
- return -1;
-
- if (mmal_component_enable(p->renderer)) {
- MP_FATAL(hw, "Failed to enable video renderer.\n");
- return -1;
- }
-
- return 0;
-}
-
-static void free_mmal_buffer(void *arg)
-{
- MMAL_BUFFER_HEADER_T *buffer = arg;
- mmal_buffer_header_release(buffer);
-}
-
-static struct mp_image *upload(struct ra_hwdec *hw, struct mp_image *hw_image)
-{
- struct priv *p = hw->priv;
-
- MMAL_BUFFER_HEADER_T *buffer = mmal_queue_wait(p->swpool->queue);
- if (!buffer) {
- MP_ERR(hw, "Can't allocate buffer.\n");
- return NULL;
- }
- mmal_buffer_header_reset(buffer);
-
- struct mp_image *new_ref = mp_image_new_custom_ref(NULL, buffer,
- free_mmal_buffer);
- if (!new_ref) {
- mmal_buffer_header_release(buffer);
- MP_ERR(hw, "Out of memory.\n");
- return NULL;
- }
-
- mp_image_setfmt(new_ref, IMGFMT_MMAL);
- new_ref->planes[3] = (void *)buffer;
-
- struct mp_image dmpi = {0};
- buffer->length = layout_buffer(&dmpi, buffer, &p->params);
- mp_image_copy(&dmpi, hw_image);
-
- return new_ref;
-}
-
-static int overlay_frame(struct ra_hwdec *hw, struct mp_image *hw_image,
- struct mp_rect *src, struct mp_rect *dst, bool newframe)
-{
- struct priv *p = hw->priv;
-
- if (hw_image && !mp_image_params_equal(&p->params, &hw_image->params)) {
- p->params = hw_image->params;
-
- disable_renderer(hw);
- mp_image_unrefp(&p->current_frame);
-
- if (enable_renderer(hw) < 0)
- return -1;
- }
-
- if (hw_image && p->current_frame && !newframe) {
- if (!mp_rect_equals(&p->src, src) ||mp_rect_equals(&p->dst, dst)) {
- p->src = *src;
- p->dst = *dst;
- update_overlay(hw, false);
- }
- return 0; // don't reupload
- }
-
- mp_image_unrefp(&p->current_frame);
-
- if (!hw_image) {
- disable_renderer(hw);
- return 0;
- }
-
- if (enable_renderer(hw) < 0)
- return -1;
-
- update_overlay(hw, true);
-
- struct mp_image *mpi = NULL;
- if (hw_image->imgfmt == IMGFMT_MMAL) {
- mpi = mp_image_new_ref(hw_image);
- } else {
- mpi = upload(hw, hw_image);
- }
-
- if (!mpi) {
- disable_renderer(hw);
- return -1;
- }
-
- MMAL_BUFFER_HEADER_T *ref = (void *)mpi->planes[3];
-
- // Assume this field is free for use by us.
- ref->user_data = mpi;
-
- if (mmal_port_send_buffer(p->renderer->input[0], ref)) {
- MP_ERR(hw, "could not queue picture!\n");
- talloc_free(mpi);
- return -1;
- }
-
- return 0;
-}
-
-static void destroy(struct ra_hwdec *hw)
-{
- struct priv *p = hw->priv;
-
- disable_renderer(hw);
-
- if (p->renderer)
- mmal_component_release(p->renderer);
-
- mmal_vc_deinit();
-}
-
-static int create(struct ra_hwdec *hw)
-{
- struct priv *p = hw->priv;
- p->log = hw->log;
-
- bcm_host_init();
-
- if (mmal_vc_init()) {
- MP_FATAL(hw, "Could not initialize MMAL.\n");
- return -1;
- }
-
- if (mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &p->renderer))
- {
- MP_FATAL(hw, "Could not create MMAL renderer.\n");
- mmal_vc_deinit();
- return -1;
- }
-
- return 0;
-}
-
-const struct ra_hwdec_driver ra_hwdec_rpi_overlay = {
- .name = "rpi-overlay",
- .priv_size = sizeof(struct priv),
- .imgfmts = {IMGFMT_MMAL, IMGFMT_420P, 0},
- .init = create,
- .overlay_frame = overlay_frame,
- .uninit = destroy,
-};