Skip to content

Commit

Permalink
renderer: add support for applying AV1 grain during rendering
Browse files Browse the repository at this point in the history
This change is intended to make users' lives easier, by allowing them to
simply specify AV1 grain metadata as part of the `pl_image` struct,
without having to muck about with dispatching, shaders and the likes
themselves.

Closes haasn#76.
  • Loading branch information
haasn committed Apr 2, 2020
1 parent 9307a9c commit 2af4402
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 3 deletions.
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ project('libplacebo', ['c', 'cpp'],
license: 'LGPL2.1+',
default_options: ['c_std=c99'],
meson_version: '>=0.49',
version: '1.32.0',
version: '1.33.0',
)

# Version number
Expand Down
5 changes: 5 additions & 0 deletions src/include/libplacebo/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <libplacebo/colorspace.h>
#include <libplacebo/filters.h>
#include <libplacebo/gpu.h>
#include <libplacebo/shaders/av1.h>
#include <libplacebo/shaders/colorspace.h>
#include <libplacebo/shaders/sampling.h>
#include <libplacebo/swapchain.h>
Expand Down Expand Up @@ -347,6 +348,10 @@ struct pl_image {
// implementations. So in this example, the 18x12 chroma plane would get
// treated by libplacebo as an oversized chroma plane - i.e. the plane
// would get sampled as if it was 17.5 pixels wide and 11.5 pixels large.

// Associated AV1 grain params (see <libplacebo/shaders/av1.h>). This is
// entirely optional, the default of {0} corresponds to no extra grain.
struct pl_av1_grain_data av1_grain;
};

// Represents the target of a rendering operation
Expand Down
77 changes: 75 additions & 2 deletions src/renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,16 @@ struct pl_renderer {
bool disable_overlay; // disable rendering overlays
bool disable_3dlut; // disable usage of a 3DLUT
bool disable_peak_detect; // disable peak detection shader
bool disable_grain; // disable AV1 grain code

// Shader resource objects and intermediate textures (FBOs)
struct pl_shader_obj *peak_detect_state;
struct pl_shader_obj *dither_state;
struct pl_shader_obj *lut3d_state;
struct pl_shader_obj *grain_state;
const struct pl_tex *main_scale_fbo;
const struct pl_tex *deband_fbos[PLANE_COUNT];
const struct pl_tex *grain_fbos[PLANE_COUNT];
const struct pl_tex *output_fbo;
struct sampler samplers[SCALER_COUNT];
struct sampler *osd_samplers;
Expand Down Expand Up @@ -176,12 +179,15 @@ void pl_renderer_destroy(struct pl_renderer **p_rr)
pl_tex_destroy(rr->gpu, &rr->main_scale_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]);
pl_tex_destroy(rr->gpu, &rr->output_fbo);

// Free all shader resource objects
pl_shader_obj_destroy(&rr->peak_detect_state);
pl_shader_obj_destroy(&rr->dither_state);
pl_shader_obj_destroy(&rr->lut3d_state);
pl_shader_obj_destroy(&rr->grain_state);

// Free all samplers
for (int i = 0; i < PL_ARRAY_SIZE(rr->samplers); i++)
Expand Down Expand Up @@ -713,8 +719,8 @@ static bool pass_read_image(struct pl_renderer *rr, struct pass_state *pass,
float scale = pl_color_repr_normalize(&repr);

for (int i = 0; i < image->num_planes; i++) {
struct pl_shader *psh = pl_dispatch_begin_ex(rr->dp, true);
struct pl_plane *plane = &planes[i];
float plane_scale = scale;

// Compute the source shift/scale relative to the reference size
float pw = plane->texture->params.w,
Expand All @@ -730,10 +736,76 @@ static bool pass_read_image(struct pl_renderer *rr, struct pass_state *pass,
float rrx = rx >= 1 ? roundf(rx) : 1.0 / roundf(1.0 / rx),
rry = ry >= 1 ? roundf(ry) : 1.0 / roundf(1.0 / ry);

// Perform AV1 grain first (before debanding) for several reasons:
// 1. It's closer to the intent of the spec to add grain first
// 2. Debanding implicitly crops, which screws with the AV1 grain code
// 3. Debanding may finalize the image (work-aroundable but annoying)

struct pl_av1_grain_params grain_params = {
.data = image->av1_grain,
.luma_tex = refplane->texture,
.repr = repr,
.channels = {PL_CHANNEL_NONE, PL_CHANNEL_NONE, PL_CHANNEL_NONE},
.sub_x = ilogbf(rrx),
.sub_y = ilogbf(rry),
};

for (int c = 0; c < plane->components; c++) {
int idx = plane->texture->params.format->sample_order[c];
if (idx < 0 || idx >= PL_ARRAY_SIZE(grain_params.channels))
continue;
grain_params.channels[idx] = plane->component_mapping[c];
}

const struct pl_fmt *grain_fmt = plane->texture->params.format;
if (!(grain_fmt->caps & PL_FMT_CAP_RENDERABLE))
grain_fmt = rr->fbofmt;

bool needs_grain = !rr->disable_grain && pl_needs_av1_grain(&grain_params);
if (needs_grain && !grain_fmt) {
PL_ERR(rr, "AV1 grain required but no renderable format available.. "
"disabling!");
rr->disable_grain = true;
needs_grain = false;
}

if (needs_grain) {
struct pl_shader *gsh = pl_dispatch_begin_ex(rr->dp, false);
const struct pl_tex *new_tex;
bool ok = pl_shader_sample_direct(gsh, &(struct pl_sample_src) {
.tex = plane->texture,
.scale = plane_scale,
});

if (ok)
ok = pl_shader_av1_grain(gsh, &rr->grain_state, &grain_params);

if (ok) {
struct img grain_img = {
.sh = gsh,
.w = plane->texture->params.w,
.h = plane->texture->params.h,
};

new_tex = finalize_img(rr, &grain_img, grain_fmt, &rr->grain_fbos[i]);
ok = !!new_tex;
gsh = NULL;
}

if (ok) {
plane->texture = new_tex;
plane_scale = 1.0;
} else {
PL_ERR(rr, "Failed applying AV1 grain.. disabling!");
rr->disable_grain = true;
pl_dispatch_abort(rr->dp, &gsh);
}
}

struct pl_sample_src src = {
.tex = plane->texture,
.components = plane->components,
.scale = scale,
.scale = plane_scale,
.new_w = target_w,
.new_h = target_h,
.rect = {
Expand All @@ -744,6 +816,7 @@ static bool pass_read_image(struct pl_renderer *rr, struct pass_state *pass,
},
};

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);

Expand Down
4 changes: 4 additions & 0 deletions src/tests/gpu_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,10 @@ static void pl_render_tests(const struct pl_gpu *gpu)

REQUIRE(pl_render_image(rr, &image, &target, &params));

params = pl_render_default_params;
image.av1_grain = av1_grain_data;
REQUIRE(pl_render_image(rr, &image, &target, &params));

error:
free(fbo_data);
pl_renderer_destroy(&rr);
Expand Down

0 comments on commit 2af4402

Please sign in to comment.