From 61b654567826d3d9ecf358edcb51e7d0985c4f66 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Tue, 26 Jan 2021 18:04:21 +0100 Subject: dav1dplay: Update/modernize placebo-based renderer Upstream libplacebo added support for dav1d integration directly, allowing us to vastly simplify all of this code. In order to take advantage of new optimizations, I had to allow update_frame to unref the Dav1dPicture. (This is fine, since double unref is a no-op) In addition, some of the functions we use were deprecated in recent libplacebo versions, so since we're taking a new dependency we might as well fix the deprecation warnings. --- examples/dav1dplay.c | 2 +- examples/dp_renderer.h | 2 +- examples/dp_renderer_placebo.c | 358 ++++------------------------------------- examples/meson.build | 2 +- 4 files changed, 33 insertions(+), 331 deletions(-) (limited to 'examples') diff --git a/examples/dav1dplay.c b/examples/dav1dplay.c index b3ab40e..e5379f4 100644 --- a/examples/dav1dplay.c +++ b/examples/dav1dplay.c @@ -317,8 +317,8 @@ static void dp_rd_ctx_post_event(Dav1dPlayRenderContext *rd_ctx, uint32_t type) static void dp_rd_ctx_update_with_dav1d_picture(Dav1dPlayRenderContext *rd_ctx, Dav1dPicture *dav1d_pic) { - renderer_info->update_frame(rd_ctx->rd_priv, dav1d_pic, &rd_ctx->settings); rd_ctx->current_ts = dav1d_pic->m.timestamp; + renderer_info->update_frame(rd_ctx->rd_priv, dav1d_pic, &rd_ctx->settings); } /** diff --git a/examples/dp_renderer.h b/examples/dp_renderer.h index 19dcf07..75276da 100644 --- a/examples/dp_renderer.h +++ b/examples/dp_renderer.h @@ -87,7 +87,7 @@ typedef struct rdr_info void (*destroy_renderer)(void *cookie); // Callback to the render function that renders a prevously sent frame void (*render)(void *cookie, const Dav1dPlaySettings *settings); - // Callback to the send frame function + // Callback to the send frame function, _may_ also unref dav1d_pic! int (*update_frame)(void *cookie, Dav1dPicture *dav1d_pic, const Dav1dPlaySettings *settings); // Callback for alloc/release pictures (optional) diff --git a/examples/dp_renderer_placebo.c b/examples/dp_renderer_placebo.c index cca532f..320df4e 100644 --- a/examples/dp_renderer_placebo.c +++ b/examples/dp_renderer_placebo.c @@ -30,7 +30,7 @@ #include #include -#include +#include #ifdef HAVE_PLACEBO_VULKAN # include @@ -72,7 +72,7 @@ typedef struct renderer_priv_ctx // Lock protecting access to the texture SDL_mutex *lock; // Image to render, and planes backing them - struct pl_image image; + struct pl_frame image; const struct pl_tex *plane_tex[3]; } Dav1dPlayRendererPrivateContext; @@ -319,22 +319,15 @@ static void placebo_render(void *cookie, const Dav1dPlaySettings *settings) if (settings->highquality) render_params = pl_render_default_params; - struct pl_render_target target; - pl_render_target_from_swapchain(&target, &frame); - target.profile = (struct pl_icc_profile) { - .data = NULL, - .len = 0, - }; - -#if PL_API_VER >= 66 - pl_rect2df_aspect_copy(&target.dst_rect, &rd_priv_ctx->image.src_rect, 0.0); - if (pl_render_target_partial(&target)) - pl_tex_clear(rd_priv_ctx->gpu, target.fbo, (float[4]){ 0.0 }); -#endif + struct pl_frame target; + pl_frame_from_swapchain(&target, &frame); + pl_rect2df_aspect_copy(&target.crop, &rd_priv_ctx->image.crop, 0.0); + if (pl_frame_is_cropped(&target)) + pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 0.0 }); if (!pl_render_image(rd_priv_ctx->renderer, &rd_priv_ctx->image, &target, &render_params)) { fprintf(stderr, "Failed rendering frame!\n"); - pl_tex_clear(rd_priv_ctx->gpu, target.fbo, (float[4]){ 1.0 }); + pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 1.0 }); } ok = pl_swapchain_submit_frame(rd_priv_ctx->swapchain); @@ -351,320 +344,37 @@ static void placebo_render(void *cookie, const Dav1dPlaySettings *settings) static int placebo_upload_image(void *cookie, Dav1dPicture *dav1d_pic, const Dav1dPlaySettings *settings) { - Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie; - assert(rd_priv_ctx != NULL); - - SDL_LockMutex(rd_priv_ctx->lock); - - if (dav1d_pic == NULL) { - SDL_UnlockMutex(rd_priv_ctx->lock); - return 0; - } - - int width = dav1d_pic->p.w; - int height = dav1d_pic->p.h; - int sub_x = 0, sub_y = 0; - int bytes = (dav1d_pic->p.bpc + 7) / 8; // rounded up - enum pl_chroma_location chroma_loc = PL_CHROMA_UNKNOWN; - - struct pl_image *image = &rd_priv_ctx->image; - *image = (struct pl_image) { - .num_planes = 3, - .width = width, - .height = height, - .src_rect = {0, 0, width, height}, - - .repr = { - .bits = { - .sample_depth = bytes * 8, - .color_depth = dav1d_pic->p.bpc, - }, - }, - }; - - // Figure out the correct plane dimensions/count - switch (dav1d_pic->p.layout) { - case DAV1D_PIXEL_LAYOUT_I400: - image->num_planes = 1; - break; - case DAV1D_PIXEL_LAYOUT_I420: - sub_x = sub_y = 1; - break; - case DAV1D_PIXEL_LAYOUT_I422: - sub_x = 1; - break; - case DAV1D_PIXEL_LAYOUT_I444: - break; - } - - // Set the right colorspace metadata etc. - switch (dav1d_pic->seq_hdr->pri) { - case DAV1D_COLOR_PRI_UNKNOWN: image->color.primaries = PL_COLOR_PRIM_UNKNOWN; break; - case DAV1D_COLOR_PRI_BT709: image->color.primaries = PL_COLOR_PRIM_BT_709; break; - case DAV1D_COLOR_PRI_BT470M: image->color.primaries = PL_COLOR_PRIM_BT_470M; break; - case DAV1D_COLOR_PRI_BT470BG: image->color.primaries = PL_COLOR_PRIM_BT_601_625; break; - case DAV1D_COLOR_PRI_BT601: image->color.primaries = PL_COLOR_PRIM_BT_601_625; break; - case DAV1D_COLOR_PRI_BT2020: image->color.primaries = PL_COLOR_PRIM_BT_2020; break; - - case DAV1D_COLOR_PRI_XYZ: - // Handled below - assert(dav1d_pic->seq_hdr->mtrx == DAV1D_MC_IDENTITY); - break; - - default: - printf("warning: unknown dav1d color primaries %d.. ignoring, picture " - "may be very incorrect\n", dav1d_pic->seq_hdr->pri); - break; - } - - switch (dav1d_pic->seq_hdr->trc) { - case DAV1D_TRC_BT709: - case DAV1D_TRC_BT470M: - case DAV1D_TRC_BT470BG: - case DAV1D_TRC_BT601: - case DAV1D_TRC_SMPTE240: - case DAV1D_TRC_BT2020_10BIT: - case DAV1D_TRC_BT2020_12BIT: - // These all map to the effective "SDR" CRT-based EOTF, BT.1886 - image->color.transfer = PL_COLOR_TRC_BT_1886; - break; - - case DAV1D_TRC_UNKNOWN: image->color.transfer = PL_COLOR_TRC_UNKNOWN; break; - case DAV1D_TRC_LINEAR: image->color.transfer = PL_COLOR_TRC_LINEAR; break; - case DAV1D_TRC_SRGB: image->color.transfer = PL_COLOR_TRC_SRGB; break; - case DAV1D_TRC_SMPTE2084: image->color.transfer = PL_COLOR_TRC_PQ; break; - case DAV1D_TRC_HLG: image->color.transfer = PL_COLOR_TRC_HLG; break; - - default: - printf("warning: unknown dav1d color transfer %d.. ignoring, picture " - "may be very incorrect\n", dav1d_pic->seq_hdr->trc); - break; - } - - switch (dav1d_pic->seq_hdr->mtrx) { - case DAV1D_MC_IDENTITY: - // This is going to be either RGB or XYZ - if (dav1d_pic->seq_hdr->pri == DAV1D_COLOR_PRI_XYZ) { - image->repr.sys = PL_COLOR_SYSTEM_XYZ; - } else { - image->repr.sys = PL_COLOR_SYSTEM_RGB; - } - break; - - case DAV1D_MC_UNKNOWN: - // PL_COLOR_SYSTEM_UNKNOWN maps to RGB, so hard-code this one - image->repr.sys = pl_color_system_guess_ycbcr(width, height); - break; - - case DAV1D_MC_BT709: image->repr.sys = PL_COLOR_SYSTEM_BT_709; break; - case DAV1D_MC_BT601: image->repr.sys = PL_COLOR_SYSTEM_BT_601; break; - case DAV1D_MC_SMPTE240: image->repr.sys = PL_COLOR_SYSTEM_SMPTE_240M; break; - case DAV1D_MC_SMPTE_YCGCO: image->repr.sys = PL_COLOR_SYSTEM_YCGCO; break; - case DAV1D_MC_BT2020_NCL: image->repr.sys = PL_COLOR_SYSTEM_BT_2020_NC; break; - case DAV1D_MC_BT2020_CL: image->repr.sys = PL_COLOR_SYSTEM_BT_2020_C; break; - - case DAV1D_MC_ICTCP: - // This one is split up based on the actual HDR curve in use - if (dav1d_pic->seq_hdr->trc == DAV1D_TRC_HLG) { - image->repr.sys = PL_COLOR_SYSTEM_BT_2100_HLG; - } else { - image->repr.sys = PL_COLOR_SYSTEM_BT_2100_PQ; - } - break; - - default: - printf("warning: unknown dav1d color matrix %d.. ignoring, picture " - "may be very incorrect\n", dav1d_pic->seq_hdr->mtrx); - break; - } - - if (dav1d_pic->seq_hdr->color_range) { - image->repr.levels = PL_COLOR_LEVELS_PC; - } else { - image->repr.levels = PL_COLOR_LEVELS_TV; - } - - switch (dav1d_pic->seq_hdr->chr) { - case DAV1D_CHR_UNKNOWN: chroma_loc = PL_CHROMA_UNKNOWN; break; - case DAV1D_CHR_VERTICAL: chroma_loc = PL_CHROMA_LEFT; break; - case DAV1D_CHR_COLOCATED: chroma_loc = PL_CHROMA_TOP_LEFT; break; - } - -#if PL_API_VER >= 63 - if (settings->gpugrain && dav1d_pic->frame_hdr->film_grain.present) { - Dav1dFilmGrainData *src = &dav1d_pic->frame_hdr->film_grain.data; - struct pl_av1_grain_data *dst = &image->av1_grain; - *dst = (struct pl_av1_grain_data) { - .grain_seed = src->seed, - .num_points_y = src->num_y_points, - .chroma_scaling_from_luma = src->chroma_scaling_from_luma, - .num_points_uv = { src->num_uv_points[0], src->num_uv_points[1] }, - .scaling_shift = src->scaling_shift, - .ar_coeff_lag = src->ar_coeff_lag, - .ar_coeff_shift = (int)src->ar_coeff_shift, - .grain_scale_shift = src->grain_scale_shift, - .uv_mult = { src->uv_mult[0], src->uv_mult[1] }, - .uv_mult_luma = { src->uv_luma_mult[0], src->uv_luma_mult[1] }, - .uv_offset = { src->uv_offset[0], src->uv_offset[1] }, - .overlap = src->overlap_flag, - }; - - assert(sizeof(dst->points_y) == sizeof(src->y_points)); - assert(sizeof(dst->points_uv) == sizeof(src->uv_points)); - assert(sizeof(dst->ar_coeffs_y) == sizeof(src->ar_coeffs_y)); - memcpy(dst->points_y, src->y_points, sizeof(src->y_points)); - memcpy(dst->points_uv, src->uv_points, sizeof(src->uv_points)); - memcpy(dst->ar_coeffs_y, src->ar_coeffs_y, sizeof(src->ar_coeffs_y)); - - // this one has different row sizes for alignment - for (int c = 0; c < 2; c++) { - for (int i = 0; i < 25; i++) - dst->ar_coeffs_uv[c][i] = src->ar_coeffs_uv[c][i]; - } - } -#endif - - // Upload the actual planes - struct pl_plane_data data[3] = { - { - // Y plane - .type = PL_FMT_UNORM, - .width = width, - .height = height, - .pixel_stride = bytes, - .row_stride = dav1d_pic->stride[0], - .component_size = {bytes * 8}, - .component_map = {0}, - }, { - // U plane - .type = PL_FMT_UNORM, - .width = width >> sub_x, - .height = height >> sub_y, - .pixel_stride = bytes, - .row_stride = dav1d_pic->stride[1], - .component_size = {bytes * 8}, - .component_map = {1}, - }, { - // V plane - .type = PL_FMT_UNORM, - .width = width >> sub_x, - .height = height >> sub_y, - .pixel_stride = bytes, - .row_stride = dav1d_pic->stride[1], - .component_size = {bytes * 8}, - .component_map = {2}, - }, + Dav1dPlayRendererPrivateContext *p = cookie; + assert(p != NULL); + int ret = 0; + + if (!dav1d_pic) + return ret; + + struct pl_dav1d_upload_params params = { + .picture = dav1d_pic, + .film_grain = settings->gpugrain, + .gpu_allocated = settings->zerocopy, + .asynchronous = true, }; - bool ok = true; - - for (int i = 0; i < image->num_planes; i++) { - if (settings->zerocopy) { - const struct pl_buf *buf = dav1d_pic->allocator_data; - assert(buf); - data[i].buf = buf; - data[i].buf_offset = (uintptr_t) dav1d_pic->data[i] - (uintptr_t) buf->data; - } else { - data[i].pixels = dav1d_pic->data[i]; - } - - ok &= pl_upload_plane(rd_priv_ctx->gpu, &image->planes[i], &rd_priv_ctx->plane_tex[i], &data[i]); - } - - // Apply the correct chroma plane shift. This has to be done after pl_upload_plane -#if PL_API_VER >= 67 - pl_image_set_chroma_location(image, chroma_loc); -#else - pl_chroma_location_offset(chroma_loc, &image->planes[1].shift_x, &image->planes[1].shift_y); - pl_chroma_location_offset(chroma_loc, &image->planes[2].shift_x, &image->planes[2].shift_y); -#endif - - if (!ok) { + SDL_LockMutex(p->lock); + if (!pl_upload_dav1dpicture(p->gpu, &p->image, p->plane_tex, ¶ms)) { fprintf(stderr, "Failed uploading planes!\n"); - *image = (struct pl_image) {0}; + p->image = (struct pl_frame) {0}; + ret = -1; } - - SDL_UnlockMutex(rd_priv_ctx->lock); - return !ok; + SDL_UnlockMutex(p->lock); + return ret; } -// Align to power of 2 -#define ALIGN2(x, align) (((x) + (align) - 1) & ~((align) - 1)) - -static int placebo_alloc_pic(Dav1dPicture *const p, void *cookie) +static int placebo_alloc_pic(Dav1dPicture *const pic, void *cookie) { Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie; assert(rd_priv_ctx != NULL); - SDL_LockMutex(rd_priv_ctx->lock); - const struct pl_gpu *gpu = rd_priv_ctx->gpu; - int ret = DAV1D_ERR(ENOMEM); - - // Copied from dav1d_default_picture_alloc - const int hbd = p->p.bpc > 8; - const int aligned_w = ALIGN2(p->p.w, 128); - const int aligned_h = ALIGN2(p->p.h, 128); - const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400; - const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420; - const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444; - p->stride[0] = aligned_w << hbd; - p->stride[1] = has_chroma ? (aligned_w >> ss_hor) << hbd : 0; - - // Align strides up to multiples of the GPU performance hints - p->stride[0] = ALIGN2(p->stride[0], gpu->limits.align_tex_xfer_stride); - p->stride[1] = ALIGN2(p->stride[1], gpu->limits.align_tex_xfer_stride); - - // Aligning offsets to 4 also implicity aligns to the texel size (1 or 2) - size_t off_align = ALIGN2(gpu->limits.align_tex_xfer_offset, 4); - const size_t y_sz = ALIGN2(p->stride[0] * aligned_h, off_align); - const size_t uv_sz = ALIGN2(p->stride[1] * (aligned_h >> ss_ver), off_align); - - // The extra DAV1D_PICTURE_ALIGNMENTs are to brute force plane alignment, - // even in the case that the driver gives us insane alignments - const size_t pic_size = y_sz + 2 * uv_sz; - const size_t total_size = pic_size + DAV1D_PICTURE_ALIGNMENT * 4; - - // Validate size limitations - if (total_size > gpu->limits.max_xfer_size) { - printf("alloc of %zu bytes exceeds limits\n", total_size); - goto err; - } - - const struct pl_buf *buf = pl_buf_create(gpu, &(struct pl_buf_params) { - .type = PL_BUF_TEX_TRANSFER, - .host_mapped = true, - .size = total_size, - .memory_type = PL_BUF_MEM_HOST, - .user_data = p, - }); - - if (!buf) { - printf("alloc of GPU mapped buffer failed\n"); - goto err; - } - - assert(buf->data); - uintptr_t base = (uintptr_t) buf->data, data[3]; - data[0] = ALIGN2(base, DAV1D_PICTURE_ALIGNMENT); - data[1] = ALIGN2(data[0] + y_sz, DAV1D_PICTURE_ALIGNMENT); - data[2] = ALIGN2(data[1] + uv_sz, DAV1D_PICTURE_ALIGNMENT); - - // Sanity check offset alignment for the sake of debugging - if (data[0] - base != ALIGN2(data[0] - base, off_align) || - data[1] - base != ALIGN2(data[1] - base, off_align) || - data[2] - base != ALIGN2(data[2] - base, off_align)) - { - printf("GPU buffer horribly misaligned, expect slowdown!\n"); - } - - p->allocator_data = (void *) buf; - p->data[0] = (void *) data[0]; - p->data[1] = (void *) data[1]; - p->data[2] = (void *) data[2]; - ret = 0; - - // fall through -err: + SDL_LockMutex(rd_priv_ctx->lock); + int ret = pl_allocate_dav1dpicture(pic, rd_priv_ctx->gpu); SDL_UnlockMutex(rd_priv_ctx->lock); return ret; } @@ -673,11 +383,9 @@ static void placebo_release_pic(Dav1dPicture *pic, void *cookie) { Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie; assert(rd_priv_ctx != NULL); - assert(pic->allocator_data); SDL_LockMutex(rd_priv_ctx->lock); - const struct pl_gpu *gpu = rd_priv_ctx->gpu; - pl_buf_destroy(gpu, (const struct pl_buf **) &pic->allocator_data); + pl_release_dav1dpicture(pic, rd_priv_ctx->gpu); SDL_UnlockMutex(rd_priv_ctx->lock); } @@ -690,10 +398,7 @@ const Dav1dPlayRenderInfo rdr_placebo_vk = { .update_frame = placebo_upload_image, .alloc_pic = placebo_alloc_pic, .release_pic = placebo_release_pic, - -# if PL_API_VER >= 63 .supports_gpu_grain = 1, -# endif }; #else const Dav1dPlayRenderInfo rdr_placebo_vk = { NULL }; @@ -706,10 +411,7 @@ const Dav1dPlayRenderInfo rdr_placebo_gl = { .destroy_renderer = placebo_renderer_destroy, .render = placebo_render, .update_frame = placebo_upload_image, - -# if PL_API_VER >= 63 .supports_gpu_grain = 1, -# endif }; #else const Dav1dPlayRenderInfo rdr_placebo_gl = { NULL }; diff --git a/examples/meson.build b/examples/meson.build index 50e097a..9bca088 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -46,7 +46,7 @@ if sdl2_dependency.found() dav1dplay_deps = [sdl2_dependency] dav1dplay_cflags = [] - placebo_dependency = dependency('libplacebo', version: '>= 1.18.0', required: false) + placebo_dependency = dependency('libplacebo', version: '>= 3.110.0', required: false) if placebo_dependency.found() dav1dplay_deps += placebo_dependency -- cgit v1.2.3