[vlc-commits] xcb/render: implement SPU blending (fixes #12348)
Rémi Denis-Courmont
git at videolan.org
Thu Dec 20 20:33:22 CET 2018
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Thu Dec 20 20:29:45 2018 +0200| [0f4426eef1974acb287215f2039fd0c98c6da61c] | committer: Rémi Denis-Courmont
xcb/render: implement SPU blending (fixes #12348)
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=0f4426eef1974acb287215f2039fd0c98c6da61c
---
modules/video_output/Makefile.am | 2 +-
modules/video_output/xcb/render.c | 103 +++++++++++++++++++++++++++++++++++++-
2 files changed, 102 insertions(+), 3 deletions(-)
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index c55c187444..8051b5e554 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -197,7 +197,7 @@ libxcb_render_plugin_la_SOURCES = \
libxcb_render_plugin_la_CFLAGS = $(AM_CFLAGS) \
$(XCB_CFLAGS) $(XCB_SHM_CFLAGS) $(XCB_RENDER_CFLAGS)
libxcb_render_plugin_la_LIBADD = libvlc_xcb_events.la \
- $(XCB_LIBS) $(XCB_SHM_LIBS) $(XCB_RENDER_LIBS)
+ $(XCB_LIBS) $(XCB_SHM_LIBS) $(XCB_RENDER_LIBS) $(LIBM)
libxcb_xv_plugin_la_SOURCES = \
video_output/xcb/pictures.c video_output/xcb/pictures.h \
diff --git a/modules/video_output/xcb/render.c b/modules/video_output/xcb/render.c
index a1e969acc5..b3d223985f 100644
--- a/modules/video_output/xcb/render.c
+++ b/modules/video_output/xcb/render.c
@@ -24,6 +24,7 @@
# include <config.h>
#endif
+#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
@@ -49,16 +50,21 @@ struct vout_display_sys_t {
xcb_pixmap_t source;
xcb_pixmap_t crop;
xcb_pixmap_t scale;
+ xcb_pixmap_t subpic;
+ xcb_pixmap_t alpha;
xcb_window_t dest;
} drawable;
struct {
xcb_render_picture_t source;
xcb_render_picture_t crop;
xcb_render_picture_t scale;
+ xcb_render_picture_t subpic;
+ xcb_render_picture_t alpha;
xcb_render_picture_t dest;
} picture;
struct {
xcb_render_pictformat_t argb;
+ xcb_render_pictformat_t alpha;
} format;
xcb_gcontext_t gc;
@@ -69,6 +75,7 @@ struct vout_display_sys_t {
vout_display_place_t place;
int32_t src_x;
int32_t src_y;
+ vlc_fourcc_t spu_chromas[2];
};
static size_t PictureAttach(vout_display_t *vd, picture_t *pic)
@@ -103,6 +110,76 @@ static void PictureDetach(vout_display_t *vd)
xcb_shm_detach(sys->conn, sys->segment);
}
+static void RenderRegion(vout_display_t *vd, const subpicture_t *subpic,
+ const subpicture_region_t *reg)
+{
+ vout_display_sys_t *sys = vd->sys;
+ xcb_connection_t *conn = sys->conn;
+ const vout_display_place_t *place = &sys->place;
+ picture_t *pic = reg->p_picture;
+ unsigned sw = reg->fmt.i_width;
+ unsigned sh = reg->fmt.i_height;
+ xcb_rectangle_t rects[] = { { 0, 0, sw, sh }, };
+
+ xcb_create_pixmap(conn, 32, sys->drawable.subpic, sys->root, sw, sh);
+ xcb_create_pixmap(conn, 8, sys->drawable.alpha, sys->root, sw, sh);
+ xcb_render_create_picture(conn, sys->picture.subpic, sys->drawable.subpic,
+ sys->format.argb, 0, NULL);
+ xcb_render_create_picture(conn, sys->picture.alpha, sys->drawable.alpha,
+ sys->format.alpha, 0, NULL);
+
+ /* Upload region (TODO: use FD passing for SPU?) */
+ xcb_put_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, sys->drawable.subpic,
+ sys->gc, pic->p->i_pitch / pic->p->i_pixel_pitch,
+ pic->p->i_lines, 0, 0, 0, 32,
+ pic->p->i_pitch * pic->p->i_lines, pic->p->p_pixels);
+
+ /* Copy alpha channel */
+ xcb_render_composite(conn, XCB_RENDER_PICT_OP_SRC,
+ sys->picture.subpic, XCB_RENDER_PICTURE_NONE,
+ sys->picture.alpha, 0, 0, 0, 0, 0, 0, sw, sh);
+
+ /* Force alpha channel to maximum (add 100% and clip).
+ * This is to compensate RENDER expecting pre-multiplied RGB
+ * while VLC uses straight RGB.
+ */
+ static const xcb_render_color_t alpha_one_color = { 0, 0, 0, 0xffff };
+
+ xcb_render_fill_rectangles(conn, XCB_RENDER_PICT_OP_ADD,
+ sys->picture.subpic, alpha_one_color,
+ ARRAY_SIZE(rects), rects);
+
+ /* Multiply by region and subpicture alpha factors */
+ static const float alpha_fixed = 0xffffp0f / (0xffp0f * 0xffp0f);
+ xcb_render_color_t alpha_color = {
+ 0, 0, 0, lroundf(reg->i_alpha * subpic->i_alpha * alpha_fixed) };
+
+ xcb_render_fill_rectangles(conn, XCB_RENDER_PICT_OP_IN_REVERSE,
+ sys->picture.subpic, alpha_color,
+ ARRAY_SIZE(rects), rects);
+
+ /* Mask in the original alpha channel then renver over the scaled pixmap.
+ * Mask (pre)multiplies RGB channels and restores the alpha channel.
+ */
+ int_fast16_t dx = reg->i_x * place->width
+ / subpic->i_original_picture_width;
+ int_fast16_t dy = reg->i_y * place->height
+ / subpic->i_original_picture_height;
+ uint_fast16_t dw = (reg->i_x + reg->fmt.i_visible_width) * place->width
+ / subpic->i_original_picture_width;
+ uint_fast16_t dh = (reg->i_y + reg->fmt.i_visible_height) * place->height
+ / subpic->i_original_picture_height;
+
+ xcb_render_composite(conn, XCB_RENDER_PICT_OP_OVER,
+ sys->picture.subpic, sys->picture.alpha,
+ sys->picture.scale, 0, 0, 0, 0, dx, dy, dw, dh);
+
+ xcb_render_free_picture(conn, sys->picture.alpha);
+ xcb_render_free_picture(conn, sys->picture.subpic);
+ xcb_free_pixmap(conn, sys->drawable.alpha);
+ xcb_free_pixmap(conn, sys->drawable.subpic);
+}
+
static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic,
vlc_tick_t date)
{
@@ -150,8 +227,15 @@ static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic,
sys->place.width, sys->place.height);
if (offset != (size_t)-1)
PictureDetach(vd);
+
+ /* Blend subpictures */
+ if (subpic != NULL)
+ for (subpicture_region_t *r = subpic->p_region; r != NULL;
+ r = r->p_next)
+ RenderRegion(vd, subpic, r);
+
xcb_flush(conn);
- (void) subpic; (void) date;
+ (void) date;
}
static void Display(vout_display_t *vd, picture_t *pic)
@@ -486,6 +570,7 @@ static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
sys->conn = conn;
sys->root = screen->root;
sys->format.argb = 0;
+ sys->format.alpha = 0;
if (!CheckRender(vd, conn))
goto error;
@@ -506,6 +591,12 @@ static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
const xcb_render_pictforminfo_t *const pic_fmt = pic_fmts + i;
const xcb_render_directformat_t *const d = &pic_fmt->direct;
+ if (pic_fmt->depth == 8 && pic_fmt->direct.alpha_mask == 0xff) {
+ /* Alpha mask format */
+ sys->format.alpha = pic_fmt->id;
+ continue;
+ }
+
xcb_visualid_t vid = FindVisual(setup, screen, pic_fmt_r, pic_fmt->id);
if (vid == 0)
continue;
@@ -528,7 +619,7 @@ static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
free(pic_fmt_r);
- if (unlikely(sys->format.argb == 0))
+ if (unlikely(sys->format.argb == 0 || sys->format.alpha == 0))
goto error; /* Buggy server */
msg_Dbg(obj, "using RENDER picture format %u", sys->format.argb);
@@ -545,10 +636,14 @@ static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
sys->drawable.source = xcb_generate_id(conn);
sys->drawable.crop = xcb_generate_id(conn);
sys->drawable.scale = xcb_generate_id(conn);
+ sys->drawable.subpic = xcb_generate_id(conn);
+ sys->drawable.alpha = xcb_generate_id(conn);
sys->drawable.dest = xcb_generate_id(conn);
sys->picture.source = xcb_generate_id(conn);
sys->picture.crop = xcb_generate_id(conn);
sys->picture.scale = xcb_generate_id(conn);
+ sys->picture.subpic = xcb_generate_id(conn);
+ sys->picture.alpha = xcb_generate_id(conn);
sys->picture.dest = xcb_generate_id(conn);
sys->gc = xcb_generate_id(conn);
@@ -589,6 +684,10 @@ static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
CreateBuffers(vd, cfg);
xcb_map_window(conn, sys->drawable.dest);
+ sys->spu_chromas[0] = fmtp->i_chroma;
+ sys->spu_chromas[1] = 0;
+
+ vd->info.subpicture_chromas = sys->spu_chromas;
vd->prepare = Prepare;
vd->display = Display;
vd->control = Control;
More information about the vlc-commits
mailing list