diff --git a/src/renderer.c b/src/renderer.c index 0cb1441e966b8e9c88c1b9c065ffa107eb2532ba..d61b53bdf608dc854da0d42a64232a752aebddd2 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -65,12 +65,8 @@ struct pl_renderer { struct pl_shader_obj *dither_state; struct pl_shader_obj *lut3d_state; struct pl_shader_obj *grain_state[4]; - const struct pl_tex *main_scale_fbo; - const struct pl_tex *deband_fbos[4]; - const struct pl_tex *grain_fbos[4]; - const struct pl_tex *output_fbo; - const struct pl_tex **hook_fbos; - int num_hook_fbos; + const struct pl_tex **fbos; + int num_fbos; struct sampler samplers[SCALER_COUNT]; struct sampler *osd_samplers; int num_osd_samplers; @@ -161,14 +157,8 @@ void pl_renderer_destroy(struct pl_renderer **p_rr) return; // Free all intermediate FBOs - pl_tex_destroy(rr->gpu, &rr->main_scale_fbo); - pl_tex_destroy(rr->gpu, &rr->output_fbo); - for (int i = 0; i < PL_ARRAY_SIZE(rr->deband_fbos); i++) - pl_tex_destroy(rr->gpu, &rr->deband_fbos[i]); - for (int i = 0; i < PL_ARRAY_SIZE(rr->grain_fbos); i++) - pl_tex_destroy(rr->gpu, &rr->grain_fbos[i]); - for (int i = 0; i < rr->num_hook_fbos; i++) - pl_tex_destroy(rr->gpu, &rr->hook_fbos[i]); + for (int i = 0; i < rr->num_fbos; i++) + pl_tex_destroy(rr->gpu, &rr->fbos[i]); // Free all shader resource objects pl_shader_obj_destroy(&rr->peak_detect_state); @@ -232,6 +222,29 @@ struct img { int comps; }; +struct pass_state { + // Pointer back to the renderer itself, for callbacks + struct pl_renderer *rr; + + // Represents the "current" image which we're in the process of rendering. + // This is initially set by pass_read_image, and all of the subsequent + // rendering steps will mutate this in-place. + struct img img; + + // Represents the "reference rect". Canonically, this is functionallity + // equivalent to `pl_image.src_rect`, but both guaranteed to be valid, and + // also updates as the refplane evolves (e.g. due to user hook prescalers) + struct pl_rect2df ref_rect; + + // Cached copies of the `image` / `target` for this rendering pass, + // corrected to make sure all rects etc. are properly defaulted/inferred. + struct pl_image image; + struct pl_render_target target; + + // Index into `rr->fbos` + int fbo_index; +}; + // Returns the texture parameters an `img` would have if finalized static inline struct pl_tex_params img_params(struct pl_renderer *rr, struct img *img, @@ -251,13 +264,15 @@ static inline struct pl_tex_params img_params(struct pl_renderer *rr, }; } -static const struct pl_tex *finalize_img(struct pl_renderer *rr, - struct img *img, - const struct pl_fmt *fmt, - const struct pl_tex **tex) +static const struct pl_tex *finalize_img(struct pass_state *pass, struct img *img) { - struct pl_tex_params tex_params = img_params(rr, img, fmt); - bool ok = pl_tex_recreate(rr->gpu, tex, &tex_params); + struct pl_renderer *rr = pass->rr; + if (pass->fbo_index == rr->num_fbos) + TARRAY_APPEND(rr, rr->fbos, rr->num_fbos, NULL); + + const struct pl_tex **ptex = &rr->fbos[pass->fbo_index++]; + struct pl_tex_params tex_params = img_params(rr, img, rr->fbofmt); + bool ok = pl_tex_recreate(rr->gpu, ptex, &tex_params); if (!ok) { PL_ERR(rr, "Failed creating FBO texture! Disabling advanced rendering.."); rr->fbofmt = NULL; @@ -267,7 +282,7 @@ static const struct pl_tex *finalize_img(struct pl_renderer *rr, ok = pl_dispatch_finish(rr->dp, &(struct pl_dispatch_params) { .shader = &img->sh, - .target = *tex, + .target = *ptex, }); if (!ok) { @@ -275,32 +290,9 @@ static const struct pl_tex *finalize_img(struct pl_renderer *rr, return NULL; } - return *tex; + return *ptex; } -struct pass_state { - // Pointer back to the renderer itself, for callbacks - struct pl_renderer *rr; - - // Represents the "current" image which we're in the process of rendering. - // This is initially set by pass_read_image, and all of the subsequent - // rendering steps will mutate this in-place. - struct img img; - - // Represents the "reference rect". Canonically, this is functionallity - // equivalent to `pl_image.src_rect`, but both guaranteed to be valid, and - // also updates as the refplane evolves (e.g. due to user hook prescalers) - struct pl_rect2df ref_rect; - - // Cached copies of the `image` / `target` for this rendering pass, - // corrected to make sure all rects etc. are properly defaulted/inferred. - struct pl_image image; - struct pl_render_target target; - - // Index into `rr->hook_fbos` - int hook_index; -}; - enum sampler_type { SAMPLER_DIRECT, // texture()'s built in sampling SAMPLER_BICUBIC, // fast bicubic scaling @@ -362,7 +354,7 @@ static struct sampler_info sample_src_info(struct pl_renderer *rr, return info; } -static void dispatch_sampler(struct pl_renderer *rr, struct pl_shader *sh, +static void dispatch_sampler(struct pass_state *pass, struct pl_shader *sh, struct sampler *sampler, const struct pl_render_params *params, const struct pl_sample_src *src) @@ -370,6 +362,7 @@ static void dispatch_sampler(struct pl_renderer *rr, struct pl_shader *sh, if (!sampler) goto fallback; + struct pl_renderer *rr = pass->rr; struct sampler_info info = sample_src_info(rr, src, params); struct pl_shader_obj **lut = NULL; const struct pl_tex **sep_fbo = NULL; @@ -425,7 +418,7 @@ static void dispatch_sampler(struct pl_renderer *rr, struct pl_shader *sh, }; struct pl_sample_src src2 = *src; - src2.tex = finalize_img(rr, &img, FBOFMT, sep_fbo); + src2.tex = finalize_img(pass, &img); src2.scale = 1.0; ok = src2.tex && pl_shader_sample_ortho(sh, PL_SEP_HORIZ, &src2, &fparams); } @@ -444,12 +437,13 @@ fallback: pl_shader_sample_direct(sh, src); } -static void draw_overlays(struct pl_renderer *rr, const struct pl_tex *fbo, +static void draw_overlays(struct pass_state *pass, const struct pl_tex *fbo, const struct pl_overlay *overlays, int num, struct pl_color_space color, bool use_sigmoid, struct pl_transform2x2 *scale, const struct pl_render_params *params) { + struct pl_renderer *rr = pass->rr; if (num <= 0 || rr->disable_overlay) return; @@ -497,7 +491,7 @@ static void draw_overlays(struct pl_renderer *rr, const struct pl_tex *fbo, sampler = NULL; struct pl_shader *sh = pl_dispatch_begin(rr->dp); - dispatch_sampler(rr, sh, sampler, params, &src); + dispatch_sampler(pass, sh, sampler, params, &src); GLSL("vec4 osd_color;\n"); for (int c = 0; c < src.components; c++) { @@ -561,12 +555,12 @@ static const struct pl_tex *get_hook_tex(void *priv, int width, int height) struct pass_state *pass = priv; struct pl_renderer *rr = pass->rr; - int idx = pass->hook_index; - if (idx == rr->num_hook_fbos) - TARRAY_APPEND(rr, rr->hook_fbos, rr->num_hook_fbos, NULL); + int idx = pass->fbo_index; + if (idx == rr->num_fbos) + TARRAY_APPEND(rr, rr->fbos, rr->num_fbos, NULL); pl_assert(rr->fbofmt); - bool ok = pl_tex_recreate(rr->gpu, &rr->hook_fbos[idx], &(struct pl_tex_params) { + bool ok = pl_tex_recreate(rr->gpu, &rr->fbos[idx], &(struct pl_tex_params) { .w = width, .h = height, .format = rr->fbofmt, @@ -582,18 +576,19 @@ static const struct pl_tex *get_hook_tex(void *priv, int width, int height) if (!ok) return NULL; - pass->hook_index++; - return rr->hook_fbos[idx]; + pass->fbo_index++; + return rr->fbos[idx]; } // if `ptex` is unspecified, uses `img->sh` instead // // Returns if any hook was applied (even if there were errors) -static bool pass_hook(struct pl_renderer *rr, struct pass_state *pass, - struct img *img, enum pl_hook_stage stage, +static bool pass_hook(struct pass_state *pass, struct img *img, + enum pl_hook_stage stage, const struct pl_tex **ptex, const struct pl_render_params *params) { + struct pl_renderer *rr = pass->rr; if (!rr->fbofmt || rr->disable_hooks) return false; @@ -630,11 +625,7 @@ static bool pass_hook(struct pl_renderer *rr, struct pass_state *pass, case PL_HOOK_SIG_TEX: { if (!cur_tex) { - int idx = pass->hook_index++; - if (idx == rr->num_hook_fbos) - TARRAY_APPEND(rr, rr->hook_fbos, rr->num_hook_fbos, NULL); - - cur_tex = finalize_img(rr, img, rr->fbofmt, &rr->hook_fbos[idx]); + cur_tex = finalize_img(pass, img); if (!cur_tex) { PL_ERR(rr, "Failed dispatching shader prior to hook!"); goto error; @@ -726,11 +717,7 @@ static bool pass_hook(struct pl_renderer *rr, struct pass_state *pass, if (ptex) { if (!cur_tex) { - int idx = pass->hook_index++; - if (idx == rr->num_hook_fbos) - TARRAY_APPEND(rr, rr->hook_fbos, rr->num_hook_fbos, NULL); - - cur_tex = finalize_img(rr, img, rr->fbofmt, &rr->hook_fbos[idx]); + cur_tex = finalize_img(pass, img); if (!cur_tex) { PL_ERR(rr, "Failed dispatching shader prior to hook!"); goto error; @@ -771,11 +758,12 @@ enum { DEBAND_SCALED, // debanding took care of scaling as well }; -static int deband_src(struct pl_renderer *rr, struct pl_shader *psh, - struct pl_sample_src *psrc, const struct pl_tex **fbo, +static int deband_src(struct pass_state *pass, struct pl_shader *psh, + struct pl_sample_src *psrc, const struct pl_image *image, const struct pl_render_params *params) { + struct pl_renderer *rr = pass->rr; if (rr->disable_debanding || !params->deband_params) return DEBAND_NOOP; @@ -837,7 +825,7 @@ static int deband_src(struct pl_renderer *rr, struct pl_shader *psh, .h = src->new_h, }; - const struct pl_tex *new = finalize_img(rr, &img, FBOFMT, fbo); + const struct pl_tex *new = finalize_img(pass, &img); if (!new) { PL_ERR(rr, "Failed dispatching debanding shader.. disabling debanding!"); rr->disable_debanding = true; @@ -991,12 +979,13 @@ static enum plane_type detect_plane_type(const struct plane_state *st) } // Returns true if grain was applied -static bool plane_av1_grain(struct pl_renderer *rr, int plane_idx, +static bool plane_av1_grain(struct pass_state *pass, int plane_idx, struct plane_state *st, const struct pl_tex *ref_tex, const struct pl_image *image, const struct pl_render_params *params) { + struct pl_renderer *rr = pass->rr; if (rr->disable_grain) return false; @@ -1035,8 +1024,7 @@ static bool plane_av1_grain(struct pl_renderer *rr, int plane_idx, .h = plane->texture->params.h, }; - new_tex = finalize_img(rr, &grain_img, FBOFMT, - &rr->grain_fbos[plane_idx]); + new_tex = finalize_img(pass, &grain_img); ok = !!new_tex; sh = NULL; } @@ -1054,8 +1042,7 @@ static bool plane_av1_grain(struct pl_renderer *rr, int plane_idx, } // Returns true if any user hooks were executed -static bool plane_user_hooks(struct pl_renderer *rr, struct pass_state *pass, - struct plane_state *st, const struct pl_image *image, +static bool plane_user_hooks(struct pass_state *pass, struct plane_state *st, const struct pl_render_params *params) { static const enum pl_hook_stage plane_stages[] = { @@ -1066,7 +1053,7 @@ static bool plane_user_hooks(struct pl_renderer *rr, struct pass_state *pass, [PLANE_XYZ] = PL_HOOK_XYZ_INPUT, }; - return pass_hook(rr, pass, &st->img, plane_stages[st->type], + return pass_hook(pass, &st->img, plane_stages[st->type], &st->plane.texture, params); } @@ -1184,12 +1171,12 @@ static bool pass_read_image(struct pl_renderer *rr, struct pass_state *pass, // intent of the spec (which is to apply synthesis effectively during // decoding) - if (plane_av1_grain(rr, i, st, ref_tex, image, params)) { + if (plane_av1_grain(pass, i, st, ref_tex, image, params)) { PL_TRACE(rr, "After AV1 grain:"); log_plane_info(rr, st); } - if (plane_user_hooks(rr, pass, st, image, params)) { + if (plane_user_hooks(pass, st, params)) { PL_TRACE(rr, "After user hooks:"); log_plane_info(rr, st); } @@ -1229,8 +1216,8 @@ static bool pass_read_image(struct pl_renderer *rr, struct pass_state *pass, src.rect.x1, src.rect.y1); struct pl_shader *psh = pl_dispatch_begin_ex(rr->dp, true); - if (deband_src(rr, psh, &src, &rr->deband_fbos[i], image, params) != DEBAND_SCALED) - dispatch_sampler(rr, psh, &rr->samplers[i], params, &src); + if (deband_src(pass, psh, &src, image, params) != DEBAND_SCALED) + dispatch_sampler(pass, psh, &rr->samplers[i], params, &src); ident_t sub = sh_subpass(sh, psh); if (!sub) { @@ -1279,11 +1266,11 @@ static bool pass_read_image(struct pl_renderer *rr, struct pass_state *pass, // Update the reference rect to our adjusted image coordinates pass->ref_rect = pass->img.rect; - pass_hook(rr, pass, &pass->img, PL_HOOK_NATIVE, NULL, params); + pass_hook(pass, &pass->img, PL_HOOK_NATIVE, NULL, params); // Convert the image colorspace pl_shader_decode_color(sh, &pass->img.repr, params->color_adjustment); - pass_hook(rr, pass, &pass->img, PL_HOOK_RGB, NULL, params); + pass_hook(pass, &pass->img, PL_HOOK_RGB, NULL, params); // HDR peak detection, do this as early as possible hdr_update_peak(rr, sh, pass, params); @@ -1359,17 +1346,17 @@ static bool pass_scale_main(struct pl_renderer *rr, struct pass_state *pass, if (use_linear) { pl_shader_linearize(img->sh, img->color.transfer); img->color.transfer = PL_COLOR_TRC_LINEAR; - pass_hook(rr, pass, &pass->img, PL_HOOK_LINEAR, NULL, params); + pass_hook(pass, &pass->img, PL_HOOK_LINEAR, NULL, params); } if (use_sigmoid) { pl_shader_sigmoidize(img->sh, params->sigmoid_params); - pass_hook(rr, pass, &pass->img, PL_HOOK_SIGMOID, NULL, params); + pass_hook(pass, &pass->img, PL_HOOK_SIGMOID, NULL, params); } - pass_hook(rr, pass, &pass->img, PL_HOOK_PRE_OVERLAY, NULL, params); + pass_hook(pass, &pass->img, PL_HOOK_PRE_OVERLAY, NULL, params); - src.tex = finalize_img(rr, img, FBOFMT, &rr->main_scale_fbo); + src.tex = finalize_img(pass, img); if (!src.tex) return false; @@ -1389,13 +1376,13 @@ static bool pass_scale_main(struct pl_renderer *rr, struct pass_state *pass, }; } - draw_overlays(rr, src.tex, image->overlays, image->num_overlays, + draw_overlays(pass, src.tex, image->overlays, image->num_overlays, img->color, use_sigmoid, &tf, params); - pass_hook(rr, pass, &pass->img, PL_HOOK_PRE_KERNEL, &src.tex, params); + pass_hook(pass, &pass->img, PL_HOOK_PRE_KERNEL, &src.tex, params); struct pl_shader *sh = pl_dispatch_begin_ex(rr->dp, true); - dispatch_sampler(rr, sh, &rr->samplers[SCALER_MAIN], params, &src); + dispatch_sampler(pass, sh, &rr->samplers[SCALER_MAIN], params, &src); pass->img = (struct img) { .sh = sh, .w = src.new_w, @@ -1406,12 +1393,12 @@ static bool pass_scale_main(struct pl_renderer *rr, struct pass_state *pass, .comps = img->comps, }; - pass_hook(rr, pass, &pass->img, PL_HOOK_POST_KERNEL, NULL, params); + pass_hook(pass, &pass->img, PL_HOOK_POST_KERNEL, NULL, params); if (use_sigmoid) pl_shader_unsigmoidize(sh, params->sigmoid_params); - pass_hook(rr, pass, &pass->img, PL_HOOK_SCALED, NULL, params); + pass_hook(pass, &pass->img, PL_HOOK_SCALED, NULL, params); return true; } @@ -1493,20 +1480,20 @@ fallback: bool is_comp = pl_shader_is_compute(sh); if (is_comp && !fbo->params.storable) { - bool ok = finalize_img(rr, &pass->img, FBOFMT, &rr->output_fbo); - if (!ok) { + const struct pl_tex *output_tex = finalize_img(pass, &pass->img); + if (!output_tex) { PL_ERR(rr, "Failed dispatching compute shader to intermediate FBO?"); return false; } sh = pass->img.sh = pl_dispatch_begin(rr->dp); pl_shader_sample_direct(sh, &(struct pl_sample_src) { - .tex = rr->output_fbo, + .tex = output_tex, }); } pl_shader_encode_color(sh, &target->repr); - pass_hook(rr, pass, &pass->img, PL_HOOK_OUTPUT, NULL, params); + pass_hook(pass, &pass->img, PL_HOOK_OUTPUT, NULL, params); // FIXME: What if this ends up being a compute shader?? Should we do the // is_compute unredirection *after* encode_color, or will that fuck up // the bit depth? @@ -1614,12 +1601,12 @@ bool pl_render_image(struct pl_renderer *rr, const struct pl_image *pimage, }, }; - draw_overlays(rr, target->fbo, image->overlays, image->num_overlays, + draw_overlays(&pass, target->fbo, image->overlays, image->num_overlays, target->color, false, &scale, params); } // Draw the final output overlays - draw_overlays(rr, target->fbo, target->overlays, target->num_overlays, + draw_overlays(&pass, target->fbo, target->overlays, target->num_overlays, target->color, false, NULL, params); return true;