diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index ecdea1b94f..f5fd08ca0d 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -548,11 +548,10 @@ Available video output drivers are: xrgb2101010 is a packed 30 bits per pixel/10 bits per channel packed RGB format with 2 bits of padding. - Unless you have an Intel graphics card, a recent kernel and a recent - version of mesa (>=18) xrgb2101010 is unlikely to work for you. - - This currently only has an effect when used together with the ``drm`` - backend for the ``gpu`` VO. The ``drm`` VO always uses xrgb8888. + There are cases when xrgb2101010 will work with the ``drm`` VO, but not + with the ``drm`` backend for the ``gpu`` VO. This is because with the + ``gpu`` VO, in addition to requiring support in your DRM driver, + requires support for xrgb2101010 in your EGL driver ``--drm-draw-surface-size=<[WxH]>`` Sets the size of the surface used on the draw plane. The surface will diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 1947c9de0d..c68a639c4f 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -11,6 +11,7 @@ Added ~~~~~ - vo_gpu: Vulkan API implementation based on libplacebo. +- vo_drm: Add 30bpp support. Changed ~~~~~~~ diff --git a/video/out/vo_drm.c b/video/out/vo_drm.c index 281235e911..7d04b0783a 100644 --- a/video/out/vo_drm.c +++ b/video/out/vo_drm.c @@ -35,7 +35,13 @@ #include "video/sws_utils.h" #include "vo.h" -#define IMGFMT IMGFMT_BGR0 +#define IMGFMT_XRGB8888 IMGFMT_BGR0 +#if BYTE_ORDER == BIG_ENDIAN +#define IMGFMT_XRGB2101010 pixfmt2imgfmt(AV_PIX_FMT_GBRP10BE) +#else +#define IMGFMT_XRGB2101010 pixfmt2imgfmt(AV_PIX_FMT_GBRP10LE) +#endif + #define BYTES_PER_PIXEL 4 #define BITS_PER_PIXEL 32 #define USE_MASTER 0 @@ -70,6 +76,9 @@ struct priv { bool active; bool pflip_happening; + uint32_t depth; + enum mp_imgfmt imgfmt; + int32_t screen_w; int32_t screen_h; struct mp_image *last_input; @@ -99,6 +108,8 @@ static void fb_destroy(int fd, struct framebuffer *buf) static bool fb_setup_single(struct vo *vo, int fd, struct framebuffer *buf) { + struct priv *p = vo->priv; + buf->handle = 0; // create dumb buffer @@ -116,7 +127,7 @@ static bool fb_setup_single(struct vo *vo, int fd, struct framebuffer *buf) buf->handle = creq.handle; // create framebuffer object for the dumb-buffer - if (drmModeAddFB(fd, buf->width, buf->height, 24, creq.bpp, buf->stride, + if (drmModeAddFB(fd, buf->width, buf->height, p->depth, creq.bpp, buf->stride, buf->handle, &buf->fb)) { MP_ERR(vo, "Cannot create framebuffer: %s\n", mp_strerror(errno)); goto err; @@ -280,7 +291,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) mp_sws_set_from_cmdline(p->sws, vo->global); p->sws->src = *params; p->sws->dst = (struct mp_image_params) { - .imgfmt = IMGFMT, + .imgfmt = p->imgfmt, .w = w, .h = h, .p_w = 1, @@ -288,7 +299,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) }; talloc_free(p->cur_frame); - p->cur_frame = mp_image_alloc(IMGFMT, p->screen_w, p->screen_h); + p->cur_frame = mp_image_alloc(p->imgfmt, p->screen_w, p->screen_h); mp_image_params_guess_csp(&p->sws->dst); mp_image_set_params(p->cur_frame, &p->sws->dst); p->cur_frame[0].w = p->screen_w; @@ -337,10 +348,36 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) } struct framebuffer *front_buf = &p->bufs[p->front_buf]; - memcpy_pic(front_buf->map, p->cur_frame->planes[0], - p->cur_frame->w * BYTES_PER_PIXEL, p->cur_frame->h, - front_buf->stride, - p->cur_frame->stride[0]); + + if (p->depth == 30) { + // Pack GBRP10 image into XRGB2101010 for DRM + const int w = p->cur_frame->w; + const int h = p->cur_frame->h; + + const int g_padding = p->cur_frame->stride[0]/sizeof(uint16_t) - w; + const int b_padding = p->cur_frame->stride[1]/sizeof(uint16_t) - w; + const int r_padding = p->cur_frame->stride[2]/sizeof(uint16_t) - w; + const int fbuf_padding = front_buf->stride/sizeof(uint32_t) - w; + + uint16_t *g_ptr = (uint16_t*)p->cur_frame->planes[0]; + uint16_t *b_ptr = (uint16_t*)p->cur_frame->planes[1]; + uint16_t *r_ptr = (uint16_t*)p->cur_frame->planes[2]; + uint32_t *fbuf_ptr = (uint32_t*)front_buf->map; + for (unsigned y = 0; y < h; ++y) { + for (unsigned x = 0; x < w; ++x) { + *fbuf_ptr++ = (*r_ptr++ << 20) | (*g_ptr++ << 10) | (*b_ptr++); + } + g_ptr += g_padding; + b_ptr += b_padding; + r_ptr += r_padding; + fbuf_ptr += fbuf_padding; + } + } else { + memcpy_pic(front_buf->map, p->cur_frame->planes[0], + p->cur_frame->w * BYTES_PER_PIXEL, p->cur_frame->h, + front_buf->stride, + p->cur_frame->stride[0]); + } } if (mpi != p->last_input) { @@ -426,6 +463,14 @@ static int preinit(struct vo *vo) goto err; } + if (vo->opts->drm_opts->drm_format == DRM_OPTS_FORMAT_XRGB2101010) { + p->depth = 30; + p->imgfmt = IMGFMT_XRGB2101010; + } else { + p->depth = 24; + p->imgfmt = IMGFMT_XRGB8888; + } + if (!fb_setup_double_buffering(vo)) { MP_ERR(vo, "Failed to set up double buffering.\n"); goto err;