diff options
Diffstat (limited to 'video/out/vo_rpi.c')
-rw-r--r-- | video/out/vo_rpi.c | 206 |
1 files changed, 82 insertions, 124 deletions
diff --git a/video/out/vo_rpi.c b/video/out/vo_rpi.c index 615a5a8997..95627d4073 100644 --- a/video/out/vo_rpi.c +++ b/video/out/vo_rpi.c @@ -38,35 +38,25 @@ #include "vo.h" #include "video/mp_image.h" #include "sub/osd.h" -#include "sub/img_convert.h" +#include "gl_osd.h" -// In theory, the number of RGBA subbitmaps the OSD code could give us is -// unlimited; but in practice there will be rarely many elements. -#define MAX_OSD_ELEMS MP_SUB_BB_LIST_MAX - -struct osd_elem { - DISPMANX_RESOURCE_HANDLE_T resource; - DISPMANX_ELEMENT_HANDLE_T element; -}; - -struct osd_part { - struct osd_elem elems[MAX_OSD_ELEMS]; - int num_elems; - int change_id; - bool needed; -}; +#include "gl_rpi.h" struct priv { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_ELEMENT_HANDLE_T window; + DISPMANX_ELEMENT_HANDLE_T osd_overlay; DISPMANX_UPDATE_HANDLE_T update; uint32_t w, h; double display_fps; - struct osd_part osd_parts[MAX_OSD_PARTS]; double osd_pts; struct mp_osd_res osd_res; + struct mp_egl_rpi egl; + struct gl_shader_cache *sc; + struct mpgl_osd *osd; + MMAL_COMPONENT_T *renderer; bool renderer_enabled; @@ -118,108 +108,38 @@ static size_t layout_buffer(struct mp_image *mpi, MMAL_BUFFER_HEADER_T *buffer, return size; } -static void wipe_osd_part(struct vo *vo, struct osd_part *part) -{ - struct priv *p = vo->priv; - - for (int n = 0; n < part->num_elems; n++) { - vc_dispmanx_element_remove(p->update, part->elems[n].element); - vc_dispmanx_resource_delete(part->elems[n].resource); - } - part->num_elems = 0; - part->change_id = -1; -} +#define GLSL(x) gl_sc_add(p->sc, #x "\n"); +#define GLSLF(...) gl_sc_addf(p->sc, __VA_ARGS__) -static void wipe_osd(struct vo *vo) -{ - struct priv *p = vo->priv; - - for (int x = 0; x < MAX_OSD_PARTS; x++) - wipe_osd_part(vo, &p->osd_parts[x]); -} - -static int add_element(struct vo *vo, struct osd_part *part, int index, - struct sub_bitmap *sub) -{ - struct priv *p = vo->priv; - VC_IMAGE_TYPE_T format = VC_IMAGE_ARGB8888; // assuming RPI is always LE - - struct osd_elem *elem = &part->elems[index]; - *elem = (struct osd_elem){0}; - - // I have no idea why stride must be passed in such a hacky way. It's not - // documented. Other software does it too. Other software claims aligning - // the width and "probably" the height is required too, but for me it works - // just fine without on rpi2. (See Weston's rpi renderer.) - elem->resource = vc_dispmanx_resource_create(format, - sub->w | (sub->stride << 16), - sub->h, - &(int32_t){0}); - if (!elem->resource) { - MP_ERR(vo, "Could not create %dx%d sub-bitmap\n", sub->w, sub->h); - return -1; - } - - VC_RECT_T rc = {.width = sub->w, .height = sub->h}; - vc_dispmanx_resource_write_data(elem->resource, format, - sub->stride, sub->bitmap, &rc); - VC_RECT_T src = {.width = sub->w << 16, .height = sub->h << 16}; - VC_RECT_T dst = {.x = sub->x, .y = sub->y, .width = sub->dw, .height = sub->dh}; - VC_DISPMANX_ALPHA_T alpha = { - .flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_PREMULT, - .opacity = 0xFF, - }; - elem->element = vc_dispmanx_element_add(p->update, p->display, p->osd_layer, - &dst, elem->resource, &src, - DISPMANX_PROTECTION_NONE, - &alpha, 0, 0); - if (!elem->element) { - MP_ERR(vo, "Could not create sub-bitmap element\n"); - return -1; - } - - return 0; -} - -static void osd_draw_cb(void *ctx, struct sub_bitmaps *imgs) +static void update_osd(struct vo *vo) { - struct vo *vo = ctx; struct priv *p = vo->priv; - struct osd_part *part = &p->osd_parts[imgs->render_index]; - - part->needed = true; - - if (imgs->change_id == part->change_id) - return; - - wipe_osd_part(vo, part); - part->change_id = imgs->change_id; - for (int n = 0; n < imgs->num_parts; n++) { - if (part->num_elems == MAX_OSD_ELEMS) { - MP_ERR(vo, "Too many OSD elements.\n"); + mpgl_osd_generate(p->osd, p->osd_res, p->osd_pts, 0, 0); + + for (int n = 0; n < MAX_OSD_PARTS; n++) { + enum sub_bitmap_format fmt = mpgl_osd_get_part_format(p->osd, n); + if (!fmt) + continue; + gl_sc_uniform_sampler(p->sc, "osdtex", GL_TEXTURE_2D, 0); + switch (fmt) { + case SUBBITMAP_RGBA: { + GLSLF("// OSD (RGBA)\n"); + GLSL(vec4 color = texture(osdtex, texcoord).bgra;) break; } - int index = part->num_elems++; - if (add_element(vo, part, index, &imgs->parts[n]) < 0) + case SUBBITMAP_LIBASS: { + GLSLF("// OSD (libass)\n"); + GLSL(vec4 color = + vec4(ass_color.rgb, ass_color.a * texture(osdtex, texcoord).r);) break; - } -} - -static void update_osd(struct vo *vo) -{ - struct priv *p = vo->priv; - - for (int x = 0; x < MAX_OSD_PARTS; x++) - p->osd_parts[x].needed = false; - - static const bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_RGBA] = true}; - osd_draw(vo->osd, p->osd_res, p->osd_pts, 0, formats, osd_draw_cb, vo); - - for (int x = 0; x < MAX_OSD_PARTS; x++) { - struct osd_part *part = &p->osd_parts[x]; - if (!part->needed) - wipe_osd_part(vo, part); + } + default: + abort(); + } + gl_sc_set_vao(p->sc, mpgl_osd_get_vao(p->osd)); + gl_sc_gen_shader_and_reset(p->sc); + mpgl_osd_draw_part(p->osd, p->w, -p->h, n); } } @@ -249,6 +169,25 @@ static void resize(struct vo *vo) MP_WARN(vo, "could not set video rectangle\n"); } +static void destroy_overlays(struct vo *vo) +{ + struct priv *p = vo->priv; + + if (p->window) + vc_dispmanx_element_remove(p->update, p->window); + p->window = 0; + + mpgl_osd_destroy(p->osd); + p->osd = NULL; + gl_sc_destroy(p->sc); + p->sc = NULL; + mp_egl_rpi_destroy(&p->egl); + + if (p->osd_overlay) + vc_dispmanx_element_remove(p->update, p->osd_overlay); + p->osd_overlay = 0; +} + static int update_display_size(struct vo *vo) { struct priv *p = vo->priv; @@ -267,9 +206,7 @@ static int update_display_size(struct vo *vo) MP_VERBOSE(vo, "Display size: %dx%d\n", p->w, p->h); - if (p->window) - vc_dispmanx_element_remove(p->update, p->window); - p->window = 0; + destroy_overlays(vo); // Use the whole screen. VC_RECT_T dst = {.width = p->w, .height = p->h}; @@ -286,6 +223,27 @@ static int update_display_size(struct vo *vo) return -1; } + alpha = (VC_DISPMANX_ALPHA_T){ + .flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE, + .opacity = 0xFF, + }; + p->osd_overlay = vc_dispmanx_element_add(p->update, p->display, + p->background_layer + 2, + &dst, 0, &src, + DISPMANX_PROTECTION_NONE, + &alpha, 0, 0); + if (!p->osd_overlay) { + MP_FATAL(vo, "Could not add DISPMANX element.\n"); + return -1; + } + + if (mp_egl_rpi_init(&p->egl, p->osd_overlay, p->w, p->h) < 0) { + MP_FATAL(vo, "EGL/GLES initialization for OSD renderer failed.\n"); + return -1; + } + p->sc = gl_sc_create(p->egl.gl, vo->log, vo->global), + p->osd = mpgl_osd_init(p->egl.gl, vo->log, vo->osd); + p->display_fps = 0; TV_GET_STATE_RESP_T tvstate; TV_DISPLAY_STATE_T tvstate_disp; @@ -329,10 +287,8 @@ static void flip_page(struct vo *vo) p->next_image = NULL; // For OSD - if (!p->skip_osd) { - vc_dispmanx_update_submit_sync(p->update); - p->update = vc_dispmanx_update_start(10); - } + if (!p->skip_osd && p->egl.gl) + eglSwapBuffers(p->egl.egl_display, p->egl.egl_surface); p->skip_osd = false; if (mpi) { @@ -375,8 +331,11 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) // Redraw only if the OSD has meaningfully changed, which we assume it // hasn't when a frame is merely repeated for display sync. p->skip_osd = !frame->redraw && frame->repeat; - if (!p->skip_osd) + if (!p->skip_osd && p->egl.gl) { + p->egl.gl->ClearColor(0, 0, 0, 0); + p->egl.gl->Clear(GL_COLOR_BUFFER_BIT); update_osd(vo); + } p->display_synced = frame->display_synced; @@ -610,10 +569,7 @@ static void uninit(struct vo *vo) talloc_free(p->next_image); - wipe_osd(vo); - - if (p->window) - vc_dispmanx_element_remove(p->update, p->window); + destroy_overlays(vo); if (p->update) vc_dispmanx_update_submit_sync(p->update); @@ -642,6 +598,8 @@ static int preinit(struct vo *vo) p->video_layer = p->layer + 1; p->osd_layer = p->layer + 2; + p->egl.log = vo->log; + bcm_host_init(); if (mmal_vc_init()) { |