[Mesa-dev] [RFC PATCH 4/7] gallium/vl: Provide an g3dvl implementation of the utility_video_compositor abstraction
Thomas Hellstrom
thellstrom at vmware.com
Thu Mar 2 20:00:08 UTC 2017
Provide a 3D implementation that can be partly overridden by
the video drivers. The implementation is based on the vl compositor- and the
vdpau mixer code. A driver that wants to utilize a dedicated hardware
postprocessor can typically replace the render method and then use the
bounce buffer cache and render helper to do part of the rendering using
the 3D pipeline.
The main functional difference between the previous vdpau mixer implementation
and this implementation is that filtering will always be performed as a
unique step and not together with scaling. This will make the results
consistent (for example the sharpness filter will not enhance borders
between the video image and the background color).
but will in some cases introduce an additional rendering step.
This, in turn, will improve performance in some situations (videos that
are upscaled significantly) and somwehat reduce performance in other
situations (videos that are not scaled or downscaled).
Operation order (including buffer layer)
*deinterlacing.
*color conversion and luma keying.
*noise reduction.
*sharpening / blurring.
*scaling (possibly using hq).
Signed-off-by: Thomas Hellstrom <thellstrom at vmware.com>
Reviewed-by: Brian Paul <brianp at vmware.com>
---
src/gallium/auxiliary/Makefile.sources | 2 +
src/gallium/auxiliary/vl/vl_postproc.c | 970 +++++++++++++++++++++++++++++++++
src/gallium/auxiliary/vl/vl_postproc.h | 172 ++++++
3 files changed, 1144 insertions(+)
create mode 100644 src/gallium/auxiliary/vl/vl_postproc.c
create mode 100644 src/gallium/auxiliary/vl/vl_postproc.h
diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources
index 32f0128..8a35298 100644
--- a/src/gallium/auxiliary/Makefile.sources
+++ b/src/gallium/auxiliary/Makefile.sources
@@ -344,6 +344,8 @@ VL_SOURCES := \
vl/vl_mpeg12_bitstream.h \
vl/vl_mpeg12_decoder.c \
vl/vl_mpeg12_decoder.h \
+ vl/vl_postproc.c \
+ vl/vl_postproc.h \
vl/vl_rbsp.h \
vl/vl_types.h \
vl/vl_vertex_buffers.c \
diff --git a/src/gallium/auxiliary/vl/vl_postproc.c b/src/gallium/auxiliary/vl/vl_postproc.c
new file mode 100644
index 0000000..bf0043f
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_postproc.c
@@ -0,0 +1,970 @@
+/**************************************************************************
+ *
+ * Copyright 2010 Thomas Balling Sørensen.
+ * Copyright 2016 VMware Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *************************************************************************/
+
+#include "util/u_video_compositor.h"
+#include "util/u_memory.h"
+#include "util/u_bounce.h"
+#include "vl/vl_compositor.h"
+#include "vl/vl_postproc.h"
+#include "vl/vl_matrix_filter.h"
+#include "vl/vl_median_filter.h"
+
+/**
+ * \brief The postprocessor structure.
+ */
+struct vl_pproc {
+ /** \brief The struct util_video_compositor we derive from. */
+ struct util_video_compositor base;
+ /** \brief A struct vl_compositor, used for 3D pipeline functionality. */
+ struct vl_compositor compositor;
+};
+
+/**
+ * \brief A postprocessor context.
+ */
+struct vl_pproc_ctx {
+ /** \brief The struct util_video_compositor_context we derive from. */
+ struct util_video_compositor_context base;
+ /** \brief The state of the struct vl_compositor. */
+ struct vl_compositor_state state;
+ /** \brief Helper state for color conversion only. */
+ struct vl_compositor_state tmp_state;
+ /**
+ * \brief Saved state for the buffer layer if any. This is exposed and can
+ * be used by a wrapping driver implementing the buffer layer operations
+ * only and that relies on the 3D pipeline (this implementation) for the
+ * final compositing and optionally filtering, blending and rotation.
+ */
+ struct vl_pproc_buffer_layer bl;
+};
+
+/**
+ * Get the derived type container.
+ */
+static struct vl_pproc *
+to_vl_pproc(struct util_video_compositor *comp)
+{
+ return (struct vl_pproc *) comp;
+}
+
+/**
+ * Get the derived type container.
+ */
+static struct vl_pproc_ctx *
+to_vl_pproc_ctx(struct util_video_compositor_context *ctx)
+{
+ return (struct vl_pproc_ctx *) ctx;
+}
+
+/**
+ * \brief Set the postprocessor context csc matrix.
+ */
+static bool
+vl_pproc_set_csc_matrix(struct util_video_compositor_context *ctx,
+ const util_video_compositor_csc_matrix *matrix)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc_buffer_layer *bl = &to_vl_pproc_ctx(ctx)->bl;
+ bool ret;
+
+ memcpy(bl->matrix, matrix, sizeof(util_video_compositor_csc_matrix));
+ ret = vl_compositor_set_csc_matrix(&proc_ctx->state,
+ (vl_csc_matrix const *)bl->matrix,
+ bl->luma_key.luma_min,
+ bl->luma_key.luma_max);
+ if (!ret)
+ return FALSE;
+
+ return vl_compositor_set_csc_matrix(&proc_ctx->tmp_state,
+ (vl_csc_matrix const *)bl->matrix,
+ bl->luma_key.luma_min,
+ bl->luma_key.luma_max);
+}
+
+/**
+ * \brief Set the postprocessor context clear color.
+ */
+static void
+vl_pproc_set_clear_color(struct util_video_compositor_context *ctx,
+ const union pipe_color_union *color)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+
+ proc_ctx->bl.clear_color = *color;
+ vl_compositor_set_clear_color(&proc_ctx->state,
+ (union pipe_color_union *) color);
+}
+
+/**
+ * \brief Get the postprocessor context clear color.
+ */
+static void
+vl_pproc_get_clear_color(struct util_video_compositor_context *ctx,
+ union pipe_color_union *color)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+
+ vl_compositor_get_clear_color(&proc_ctx->state, color);
+}
+
+/**
+ * \brief Set the postprocessor context destination clip rect.
+ */
+static void
+vl_pproc_set_dst_clip(struct util_video_compositor_context *ctx,
+ const struct u_rect * dst_clip)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+
+ proc_ctx->bl.has_dst_clip = !!dst_clip;
+
+ if (dst_clip)
+ proc_ctx->bl.dst_clip = *dst_clip;
+
+ vl_compositor_set_dst_clip(&proc_ctx->state, (struct u_rect *) dst_clip);
+}
+
+/**
+ * \brief Clear all postprocessor context layers, effectively resetting the
+ * postprocessor context.
+ */
+static void
+vl_pproc_clear_layers(struct util_video_compositor_context *ctx)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+
+ proc_ctx->bl.has_buffer_layer = false;
+ proc_ctx->bl.buffer_layer_error = PIPE_OK;
+ proc_ctx->bl.has_bsrc = false;
+ proc_ctx->bl.has_bdst = false;
+ proc_ctx->bl.has_bblend = false;
+ proc_ctx->bl.has_brotate = false;
+ proc_ctx->bl.has_viewport = false;
+
+ vl_compositor_clear_layers(&proc_ctx->state);
+}
+
+/**
+ * \brief Set a blend state for a postprocessor context layer.
+ */
+static void
+vl_pproc_set_layer_blend(struct util_video_compositor_context *ctx,
+ unsigned layer,
+ const void *blend,
+ bool is_clearing)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+
+ if (layer == bl->buffer_layer && bl->has_buffer_layer) {
+ bl->has_bblend = (blend != NULL);
+ bl->bblend = blend;
+ bl->blend_is_clearing = is_clearing;
+ } else {
+ vl_compositor_set_layer_blend(&proc_ctx->state, layer, (void *)blend,
+ is_clearing);
+ }
+}
+
+/**
+ * \brief Set a viewport for a postprocessor context layer.
+ */
+static void
+vl_pproc_set_layer_dst_area(struct util_video_compositor_context *ctx,
+ unsigned layer,
+ const struct u_rect *dst_area)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+
+ if (layer == bl->buffer_layer && bl->has_buffer_layer) {
+ bl->has_viewport = !!dst_area;
+ if (dst_area)
+ bl->viewport = *dst_area;
+ }
+
+ vl_compositor_set_layer_dst_area(&proc_ctx->state, layer,
+ (struct u_rect *)dst_area);
+}
+
+/**
+ * \brief Initialize a video buffer layer for a postprocessor context.
+ */
+static void
+vl_pproc_set_buffer_layer(struct util_video_compositor_context *ctx,
+ unsigned layer,
+ struct pipe_video_buffer *buffer,
+ const struct u_rect *src_rect,
+ const struct u_rect *dst_rect,
+ enum util_video_compositor_deinterlace
+ deinterlace)
+{
+ struct vl_pproc_buffer_layer *bl = &to_vl_pproc_ctx(ctx)->bl;
+
+ if (layer != bl->buffer_layer && bl->has_buffer_layer) {
+ debug_printf("Illegal buffer layer: %d\n", layer);
+ bl->buffer_layer_error = PIPE_ERROR_BAD_INPUT;
+ return;
+ }
+
+ /*
+ * The vl_compositor buffer layer slot will be populated in render,
+ * if needed.
+ */
+ bl->has_bsrc = !!src_rect;
+ if (src_rect)
+ bl->bsrc = *src_rect;
+ bl->has_bdst = !!dst_rect;
+ if (dst_rect)
+ bl->bdst = *dst_rect;
+ bl->buffer = buffer;
+ bl->deinterlace = deinterlace;
+ bl->buffer_layer = layer;
+ bl->has_buffer_layer = true;
+}
+
+/**
+ * \brief Initialize a palette layer for a postprocessor context.
+ */
+static void
+vl_pproc_set_palette_layer(struct util_video_compositor_context *ctx,
+ unsigned layer,
+ struct pipe_sampler_view *indices,
+ struct pipe_sampler_view *palette,
+ const struct u_rect *src_rect,
+ const struct u_rect *dst_rect,
+ bool include_color_conversion)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc *proc = to_vl_pproc(ctx->compositor);
+
+ vl_compositor_set_palette_layer(&proc_ctx->state, &proc->compositor,
+ layer, indices, palette,
+ (struct u_rect *)src_rect,
+ (struct u_rect *)dst_rect,
+ include_color_conversion);
+}
+
+/**
+ * \brief Initialize a rgba layer for a postprocessor context.
+ */
+static void
+vl_pproc_set_rgba_layer(struct util_video_compositor_context *ctx,
+ unsigned layer,
+ struct pipe_sampler_view *rgba,
+ const struct u_rect *src_rect,
+ const struct u_rect *dst_rect,
+ const struct util_video_vertex4f *colors)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc *proc = to_vl_pproc(ctx->compositor);
+
+ vl_compositor_set_rgba_layer(&proc_ctx->state, &proc->compositor,
+ layer, rgba,
+ (struct u_rect *)src_rect,
+ (struct u_rect *)dst_rect,
+ (struct vertex4f *)colors);
+}
+
+/**
+ * \brief Apply a rotation for a postprocessor context layer.
+ */
+static void
+vl_pproc_set_layer_rotation(struct util_video_compositor_context *ctx,
+ unsigned layer,
+ enum util_video_compositor_rotation rotate)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+
+ if (layer == bl->buffer_layer && bl->has_buffer_layer) {
+ bl->has_brotate = (rotate != UTIL_VIDEO_COMPOSITOR_ROTATE_0);
+ bl->rotate = rotate;
+ } else {
+ vl_compositor_set_layer_rotation(&proc_ctx->state, layer,
+ (enum vl_compositor_rotation) rotate);
+ }
+}
+
+/**
+ * \brief Update the 3D pipeline sharpness filter state.
+ *
+ * Calculates the pixel coefficients and resets the filter width and height
+ * to signal that the filter should be recreated on next use.
+ *
+ * \param proc_ctx[in,out] The postprocessor context.
+ */
+static void
+vl_pproc_update_sharpness_filter(struct vl_pproc_ctx *proc_ctx)
+{
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+ float value = bl->sharpness.value;
+
+ if (fabsf(value) < 2.*FLT_EPSILON)
+ bl->sharpness.filter.enabled = false;
+
+ /* and create a new filter as needed. */
+ if (bl->sharpness.filter.enabled) {
+ float matrix[9];
+ unsigned i;
+
+ if (value > 0.0f) {
+ matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f;
+ matrix[3] = -1.0f; matrix[4] = 8.0f; matrix[5] = -1.0f;
+ matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f;
+
+ for (i = 0; i < 9; ++i)
+ matrix[i] *= value;
+
+ matrix[4] += 1.0f;
+ } else {
+ matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f;
+ matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f;
+ matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f;
+
+ for (i = 0; i < 9; ++i)
+ matrix[i] *= fabsf(value) / 16.0f;
+
+ matrix[4] += 1.0f - fabsf(value);
+ }
+ memcpy(bl->sharpness_3d.matrix, matrix, sizeof(matrix));
+ bl->sharpness_3d.width = 0;
+ bl->sharpness_3d.height = 0;
+ }
+}
+
+/**
+ * Set a buffer filter.
+ */
+static bool
+vl_pproc_set_buffer_filter(struct util_video_compositor_context *ctx,
+ const struct util_video_filter *filter)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+ bool ret = true;
+
+ switch(filter->ftype) {
+ case UTIL_VIDEO_FILTER_LUMA_KEY:
+ bl->luma_key =
+ *to_video_filter_container(filter, struct util_video_filter_luma_key);
+ if (!filter->enabled) {
+ bl->luma_key.luma_max = 0.f;
+ bl->luma_key.luma_min = 1.f;
+ }
+ ret = vl_compositor_set_csc_matrix(&proc_ctx->state,
+ (vl_csc_matrix const *)bl->matrix,
+ bl->luma_key.luma_min,
+ bl->luma_key.luma_max);
+ if (!ret)
+ return false;
+
+ ret = vl_compositor_set_csc_matrix(&proc_ctx->tmp_state,
+ (vl_csc_matrix const *)bl->matrix,
+ bl->luma_key.luma_min,
+ bl->luma_key.luma_max);
+ break;
+ case UTIL_VIDEO_FILTER_DEINT_TEMPORAL:
+ bl->deint =
+ *to_video_filter_container(filter, struct util_video_filter_deint);
+ break;
+ case UTIL_VIDEO_FILTER_SHARPNESS:
+ bl->sharpness =
+ *to_video_filter_container(filter, struct util_video_filter_sharpness);
+ vl_pproc_update_sharpness_filter(proc_ctx);
+ break;
+ case UTIL_VIDEO_FILTER_NOISE_REDUCTION:
+ bl->noise_red =
+ *to_video_filter_container(filter, struct util_video_filter_noise_red);
+ if (fabsf(bl->noise_red.level < 2.f*FLT_EPSILON))
+ bl->noise_red.filter.enabled = false;
+ break;
+ case UTIL_VIDEO_FILTER_HQ_SCALING:
+ bl->hq =
+ *to_video_filter_container(filter, struct util_video_filter_hq_scaling);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * \brief Optionally perform a 3D pipeline sharpening operation.
+ *
+ * \param proc_ctx[in,out] The postprocessor context
+ * \param intermediate[in,out] Intermediate RGBA surface holding the buffer
+ * layer content before sharpening. If no sharpening is performed, this surface
+ * will be returned by the function. Otherwise it will be released to the
+ * bounce surface cache.
+ * \param features_3d 3D pipeline operations remaining.
+ * \return An intermediate RGBA surface holding the buffer layer content after
+ * the sharpening operation.
+ */
+static struct util_bounce *
+vl_pproc_sharpen_intermediate(struct vl_pproc_ctx *proc_ctx,
+ struct util_bounce *intermediate,
+ uint32_t features_3d)
+{
+ struct pipe_context *pipe = proc_ctx->base.compositor->pipe;
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+ struct util_bounce *dst;
+ unsigned width = 0, height = 0;
+ struct pipe_resource *src;
+
+ if (intermediate) {
+ src = util_bounce_texture(intermediate);
+ width = src->width0;
+ height = src->height0;
+ }
+
+ /* If filter is disabled or we need to rebuild the filter. */
+ if ((!(features_3d & VL_FEATURE_3D_SHARPNESS) ||
+ bl->sharpness_3d.width != width ||
+ bl->sharpness_3d.height != height) &&
+ bl->sharpness_3d.filter) {
+ vl_matrix_filter_cleanup(bl->sharpness_3d.filter);
+ FREE(bl->sharpness_3d.filter);
+ bl->sharpness_3d.filter = NULL;
+ }
+
+ if (!intermediate || !(features_3d & VL_FEATURE_3D_SHARPNESS))
+ return intermediate;
+
+ if (!bl->sharpness_3d.filter) {
+ bl->sharpness_3d.filter = MALLOC(sizeof(struct vl_matrix_filter));
+
+ /* If we fail creating a filter, just skip filtering. */
+ if (!bl->sharpness_3d.filter)
+ return intermediate;
+ vl_matrix_filter_init(bl->sharpness_3d.filter, pipe,
+ width, height, 3, 3, bl->sharpness_3d.matrix);
+ bl->sharpness_3d.width = width;
+ bl->sharpness_3d.height = height;
+ }
+
+ dst = util_bounce_clone(bl->cache, intermediate, TRUE, TRUE);
+ if (!dst)
+ return intermediate;
+
+ vl_matrix_filter_render(bl->sharpness_3d.filter,
+ util_bounce_sampler_view(intermediate),
+ util_bounce_surface(dst));
+
+ /* The source intermediate texture can now be reused. */
+ util_bounce_put(intermediate);
+
+ return dst;
+}
+
+/**
+ * \brief Optionally perform a 3D pipeline noise reduction operation.
+ *
+ * \param proc_ctx[in,out] The postprocessor context
+ * \param intermediate[in,out] Intermediate RGBA surface holding the buffer
+ * layer content before noise reduction. If no sharpening is performed,
+ * this surface will be returned by the function. Otherwise it will be
+ * released to the bounce surface cache.
+ * \param features_3d 3D pipeline operations remaining.
+ * \return An intermediate RGBA surface holding the buffer layer content after
+ * the sharpening operation.
+ */
+static struct util_bounce *
+vl_pproc_noise_reduce_intermediate(struct vl_pproc_ctx *proc_ctx,
+ struct util_bounce *intermediate,
+ uint32_t features_3d)
+{
+ struct pipe_context *pipe = proc_ctx->base.compositor->pipe;
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+ struct pipe_resource *src;
+ struct util_bounce *dst;
+ unsigned width = 0, height = 0;
+
+ if (intermediate) {
+ src = util_bounce_texture(intermediate);
+ width = src->width0;
+ height = src->height0;
+ }
+
+ /* If filter is disabled or we need to rebuild the filter. */
+ if ((!(features_3d & VL_FEATURE_3D_NOISE_RED) ||
+ bl->noise_red_3d.width != width ||
+ bl->noise_red_3d.height != height) &&
+ bl->noise_red_3d.filter) {
+ vl_median_filter_cleanup(bl->noise_red_3d.filter);
+ FREE(bl->noise_red_3d.filter);
+ bl->noise_red_3d.filter = NULL;
+ }
+
+ if (!intermediate || !(features_3d & VL_FEATURE_3D_NOISE_RED))
+ return intermediate;
+
+ if (!bl->noise_red_3d.filter) {
+ bl->noise_red_3d.filter = MALLOC(sizeof(struct vl_median_filter));
+ if (!bl->noise_red_3d.filter)
+ return intermediate;
+
+ vl_median_filter_init(bl->noise_red_3d.filter,
+ pipe,
+ width, height,
+ proc_ctx->bl.noise_red.level + 1,
+ VL_MEDIAN_FILTER_CROSS);
+ bl->noise_red_3d.width = width;
+ bl->noise_red_3d.height = height;
+ }
+
+ dst = util_bounce_clone(bl->cache, intermediate, TRUE, TRUE);
+ if (!dst)
+ return intermediate;
+
+ vl_median_filter_render(bl->noise_red_3d.filter,
+ util_bounce_sampler_view(intermediate),
+ util_bounce_surface(dst));
+ util_bounce_put(intermediate);
+
+ return dst;
+}
+
+/**
+ * \brief Optionally perform a temporal deinterlacing operation on the
+ * YUV pipe_video_buffer.
+ *
+ * An adaptive deinterlacing step will be performed on the video buffer
+ * if the buffer contents is indicated to be interlaced and there are enough
+ * future - and past fields for the algorithm. If deinterlacing is performed,
+ * the pipe_video_buffer's content on return will be progressive, both fields
+ * populated. Otherwise it will remain untouched.
+ *
+ * \param proc_ctx[in,out] The postprocessor context.
+ * \param deinterlace[in,out] The picture structure on input and output.
+ * \param video_buffer[in] The video buffer to be deinterlaced.
+ * \param past[in] Past reference video buffers.
+ * \param future[in] Future reference video buffers.
+ * \param num_past Number of past video buffers.
+ * \param num_future Number of future video buffers.
+ * \return The (potentially deinterlaced) video buffer.
+ */
+static struct pipe_video_buffer *
+vl_pproc_deinterlace_buffer_layer(struct vl_pproc_ctx *proc_ctx,
+ enum util_video_compositor_deinterlace
+ *deinterlace,
+ struct pipe_video_buffer *video_buffer,
+ struct pipe_video_buffer *past[],
+ struct pipe_video_buffer *future[],
+ unsigned num_past,
+ unsigned num_future)
+{
+ struct pipe_context *pipe = proc_ctx->base.compositor->pipe;
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+ struct util_video_filter_deint *deint = &bl->deint;
+
+ *deinterlace = bl->deinterlace;
+ if (*deinterlace != UTIL_VIDEO_COMPOSITOR_WEAVE &&
+ deint->filter.enabled && num_past > 1 && num_future > 0 &&
+ past[0] && past[1] && future[0] &&
+ vl_deint_filter_check_buffers(&bl->deint_3d.filter,
+ past[1], past[0], video_buffer,
+ future[0])) {
+ /* (Re)Create a new deinterlace filter if necessary. */
+ unsigned width = video_buffer->width;
+ unsigned height = video_buffer->height;
+
+ if (!bl->deint_3d.initialized || bl->deint_3d.width != width ||
+ bl->deint_3d.height != height ||
+ bl->deint_3d.skip_chroma != deint->skip_chroma) {
+
+ if (bl->deint_3d.initialized)
+ vl_deint_filter_cleanup(&bl->deint_3d.filter);
+
+ bl->deint_3d.initialized =
+ vl_deint_filter_init(&bl->deint_3d.filter, pipe,
+ width, height, deint->skip_chroma, false);
+ if (!bl->deint_3d.initialized)
+ return video_buffer;
+
+ bl->deint_3d.width = width;
+ bl->deint_3d.height = height;
+ bl->deint_3d.skip_chroma = deint->skip_chroma;
+ }
+
+ vl_deint_filter_render(&bl->deint_3d.filter, past[1], past[0],
+ video_buffer, future[0],
+ *deinterlace == UTIL_VIDEO_COMPOSITOR_BOB_BOTTOM);
+ *deinterlace = UTIL_VIDEO_COMPOSITOR_WEAVE;
+ return bl->deint_3d.filter.video_buffer;
+ }
+
+ return video_buffer;
+}
+
+/**
+ * \brief Perform remaining 3D pipeline operations on the buffer layer and
+ * final composition.
+ */
+static void
+vl_pproc_render_helper(struct util_video_compositor_context *ctx,
+ uint32_t features_3d,
+ struct util_bounce *bounce,
+ struct pipe_surface *dst_surface,
+ struct u_rect *dirty_area,
+ bool clear_dirty)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc *proc = to_vl_pproc(ctx->compositor);
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+
+ if (bl->has_buffer_layer) {
+ bounce = vl_pproc_noise_reduce_intermediate(proc_ctx, bounce,
+ features_3d);
+ bounce = vl_pproc_sharpen_intermediate(proc_ctx, bounce,
+ features_3d);
+ if (bounce) {
+ struct pipe_sampler_view *rgba = util_bounce_sampler_view(bounce);
+
+ if (features_3d & VL_FEATURE_3D_HQ) {
+ vl_compositor_set_bicubic_rgba_layer(&proc_ctx->state,
+ &proc->compositor,
+ bl->buffer_layer,
+ rgba,
+ bl->has_bsrc ?
+ &bl->bsrc : NULL,
+ bl->has_bdst ?
+ &bl->bdst : NULL);
+ } else {
+ vl_compositor_set_rgba_layer(&proc_ctx->state, &proc->compositor,
+ bl->buffer_layer,
+ rgba,
+ bl->has_bsrc ?
+ &bl->bsrc : NULL,
+ bl->has_bdst ?
+ &bl->bdst : NULL,
+ NULL);
+ }
+ if (features_3d & VL_FEATURE_3D_BLEND) {
+ vl_compositor_set_layer_blend(&proc_ctx->state,
+ bl->buffer_layer,
+ (void *) bl->bblend,
+ bl->blend_is_clearing);
+ }
+ vl_compositor_set_layer_rotation(&proc_ctx->state,
+ bl->buffer_layer,
+ (features_3d & VL_FEATURE_3D_ROTATE) ?
+ (enum vl_compositor_rotation)
+ bl->rotate :
+ VL_COMPOSITOR_ROTATE_0);
+ }
+ }
+
+ vl_compositor_render(&proc_ctx->state, &proc->compositor,
+ dst_surface, dirty_area, clear_dirty);
+ if (bounce)
+ util_bounce_put(bounce);
+}
+
+/**
+ * \brief Color convert the buffer layer from YUV to RGB.
+ *
+ * Creates an intermediate surface and color converts the buffer layer.
+ *
+ * \param proc_ctx[in,out] The postprocessor context.
+ * \param format[in] Format to be used for the intermediate surface.
+ * \param video_buffer[in] The video buffer to be color-converted.
+ * \param deinterlace What fields to convert.
+ * \return An intermediate surface containing the color-converted buffer layer,
+ * or NULL if color conversion failed.
+ */
+static struct util_bounce *
+vl_pproc_color_convert_buffer_layer(struct vl_pproc_ctx *proc_ctx,
+ enum pipe_format format,
+ struct pipe_video_buffer *video_buffer,
+ enum util_video_compositor_deinterlace
+ deinterlace)
+{
+ struct vl_pproc *proc = to_vl_pproc(proc_ctx->base.compositor);
+ unsigned width = video_buffer->width;
+ unsigned height = video_buffer->height;
+ struct util_bounce *bounce;
+
+ bounce = util_bounce_get(proc_ctx->bl.cache, width, height, format,
+ TRUE, TRUE);
+ if (!bounce)
+ return NULL;
+
+ vl_compositor_clear_layers(&proc_ctx->tmp_state);
+ vl_compositor_set_dst_clip(&proc_ctx->tmp_state, NULL);
+ vl_compositor_set_buffer_layer(&proc_ctx->tmp_state,
+ &proc->compositor,
+ 0, video_buffer, NULL, NULL,
+ deinterlace);
+ vl_compositor_render(&proc_ctx->tmp_state, &proc->compositor,
+ util_bounce_surface(bounce), NULL, false);
+ return bounce;
+}
+
+/**
+ * \brief Perform postprocessor rendering.
+ */
+static void
+vl_pproc_render(struct util_video_compositor_context *ctx,
+ struct pipe_surface *dst_surface,
+ struct u_rect *dirty_area,
+ bool clear_dirty,
+ struct pipe_video_buffer *past[],
+ struct pipe_video_buffer *future[],
+ unsigned num_past,
+ unsigned num_future)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc *proc = to_vl_pproc(ctx->compositor);
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+ uint32_t feature_3d = 0;
+ struct util_bounce *bounce = NULL;
+
+ if (bl->has_buffer_layer) {
+ enum util_video_compositor_deinterlace deinterlace;
+ struct pipe_video_buffer *video_buffer = bl->buffer;
+
+ video_buffer = vl_pproc_deinterlace_buffer_layer(proc_ctx, &deinterlace,
+ video_buffer,
+ past, future,
+ num_past, num_future);
+ /* Check if we need an intermediate surface. */
+ feature_3d |= (bl->sharpness.filter.enabled) ?
+ VL_FEATURE_3D_SHARPNESS : 0;
+ feature_3d |= (bl->noise_red.filter.enabled) ?
+ VL_FEATURE_3D_NOISE_RED : 0;
+ feature_3d |= (bl->hq.filter.enabled) ?
+ VL_FEATURE_3D_HQ : 0;
+
+ if (feature_3d) {
+ bounce = vl_pproc_color_convert_buffer_layer(proc_ctx,
+ dst_surface->format,
+ video_buffer,
+ deinterlace);
+ feature_3d |= (bl->has_bblend) ? VL_FEATURE_3D_BLEND : 0;
+ feature_3d |= (bl->has_brotate) ? VL_FEATURE_3D_ROTATE : 0;
+ }
+
+ if (!bounce) {
+ vl_compositor_set_buffer_layer(&proc_ctx->state, &proc->compositor,
+ bl->buffer_layer, video_buffer,
+ bl->has_bsrc ? &bl->bsrc : NULL,
+ bl->has_bdst ? &bl->bdst : NULL,
+ deinterlace);
+ if (bl->has_bblend) {
+ vl_compositor_set_layer_blend(&proc_ctx->state, bl->buffer_layer,
+ (void *) bl->bblend,
+ bl->blend_is_clearing);
+ }
+ if (bl->has_brotate) {
+ vl_compositor_set_layer_rotation(&proc_ctx->state, bl->buffer_layer,
+ (enum vl_compositor_rotation)
+ bl->rotate);
+ }
+ feature_3d = 0;
+ }
+ }
+
+ vl_pproc_render_helper(ctx, feature_3d, bounce, dst_surface,
+ dirty_area, clear_dirty);
+}
+
+/**
+ * \brief Destroy a postprocessor context.
+ */
+static void
+vl_pproc_ctx_destroy(struct util_video_compositor_context *ctx)
+{
+ struct vl_pproc_ctx *proc_ctx = to_vl_pproc_ctx(ctx);
+ struct vl_pproc_buffer_layer *bl = &proc_ctx->bl;
+
+ if (bl->sharpness_3d.filter) {
+ vl_matrix_filter_cleanup(bl->sharpness_3d.filter);
+ FREE(bl->sharpness_3d.filter);
+ }
+ if (bl->noise_red_3d.filter) {
+ vl_median_filter_cleanup(bl->noise_red_3d.filter);
+ FREE(bl->noise_red_3d.filter);
+ }
+ if (bl->deint_3d.initialized)
+ vl_deint_filter_cleanup(&bl->deint_3d.filter);
+
+ vl_compositor_cleanup_state(&proc_ctx->tmp_state);
+ vl_compositor_cleanup_state(&proc_ctx->state);
+ util_bounce_cache_destroy(proc_ctx->bl.cache);
+ FREE(proc_ctx);
+}
+
+/**
+ * \brief Query the postprocessor for the maximum number of layers.
+ */
+static unsigned
+vl_pproc_query_max_layers(struct util_video_compositor *comp)
+{
+ return VL_COMPOSITOR_MAX_LAYERS;
+}
+
+/**
+ * \brief Destroy a postprocessor.
+ */
+static void
+vl_pproc_destroy(struct util_video_compositor *comp)
+{
+ struct vl_pproc *proc = to_vl_pproc(comp);
+
+ vl_compositor_cleanup(&proc->compositor);
+
+ FREE(proc);
+}
+
+/**
+ * \brief Create a postprocessor context.
+ */
+static struct util_video_compositor_context *
+vl_pproc_ctx_create(struct util_video_compositor *comp)
+{
+ struct vl_pproc_ctx *proc_ctx = CALLOC_STRUCT(vl_pproc_ctx);
+
+ if (!proc_ctx)
+ return NULL;
+
+ if (!vl_compositor_init_state(&proc_ctx->state, comp->pipe))
+ goto out_no_state;
+
+ if (!vl_compositor_init_state(&proc_ctx->tmp_state, comp->pipe))
+ goto out_no_tmp_state;
+
+ proc_ctx->bl.cache = util_bounce_cache_create(comp->pipe,
+ PIPE_TEXTURE_2D, 5);
+ if (!proc_ctx->bl.cache)
+ goto out_no_cache;
+
+ proc_ctx->base.compositor = comp;
+ proc_ctx->base.set_csc_matrix = vl_pproc_set_csc_matrix;
+ proc_ctx->base.set_clear_color = vl_pproc_set_clear_color;
+ proc_ctx->base.get_clear_color = vl_pproc_get_clear_color;
+ proc_ctx->base.set_dst_clip = vl_pproc_set_dst_clip;
+ proc_ctx->base.clear_layers = vl_pproc_clear_layers;
+ proc_ctx->base.set_layer_blend = vl_pproc_set_layer_blend;
+ proc_ctx->base.set_layer_dst_area = vl_pproc_set_layer_dst_area;
+ proc_ctx->base.set_buffer_layer = vl_pproc_set_buffer_layer;
+ proc_ctx->base.set_palette_layer = vl_pproc_set_palette_layer;
+ proc_ctx->base.set_rgba_layer = vl_pproc_set_rgba_layer;
+ proc_ctx->base.set_layer_rotation = vl_pproc_set_layer_rotation;
+ proc_ctx->base.set_buffer_filter = vl_pproc_set_buffer_filter;
+ proc_ctx->base.render = vl_pproc_render;
+ proc_ctx->base.destroy = vl_pproc_ctx_destroy;
+ proc_ctx->bl.comp = comp;
+ /* Initial value to communicate helpers to wrappers. */
+
+ return &proc_ctx->base;
+
+out_no_cache:
+ vl_compositor_cleanup_state(&proc_ctx->tmp_state);
+out_no_tmp_state:
+ vl_compositor_cleanup_state(&proc_ctx->state);
+out_no_state:
+ FREE(proc_ctx);
+ return NULL;
+}
+
+/**
+ * \brief Supported filters query.
+ */
+static int
+vl_pproc_buffer_filter_supported(struct util_video_compositor *comp,
+ enum util_video_filter_type ftype)
+{
+ switch (ftype) {
+ case UTIL_VIDEO_FILTER_HQ_SCALING:
+ return 1;
+ case UTIL_VIDEO_FILTER_LUMA_KEY:
+ case UTIL_VIDEO_FILTER_DEINT_TEMPORAL:
+ case UTIL_VIDEO_FILTER_SHARPNESS:
+ case UTIL_VIDEO_FILTER_NOISE_REDUCTION:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * \brief Return the postprocessor context's buffer layer.
+ */
+static struct vl_pproc_buffer_layer *
+vl_pproc_buffer_layer(struct util_video_compositor_context *ctx)
+{
+ return &to_vl_pproc_ctx(ctx)->bl;
+}
+
+/**
+ * \brief Wrapping driver helpers.
+ */
+static struct vl_pproc_helpers vl_pproc_helpers = {
+ .buffer_layer = vl_pproc_buffer_layer,
+ .render_helper = vl_pproc_render_helper
+};
+
+/**
+ * \brief Create a customized video postprocessor.
+ *
+ * Creates a customized 3D pipeline video postprocessor.
+ *
+ * \param pipe[in] The pipe context to use for 3D pipeline operations.
+ * \return A struct util_video_compositor, or NULL if the function fails.
+ */
+struct util_video_compositor *
+vl_pproc_create(struct pipe_context *pipe,
+ struct vl_pproc_helpers *helpers)
+{
+ struct vl_pproc *proc = CALLOC_STRUCT(vl_pproc);
+
+ if (!proc)
+ return NULL;
+
+ if (!vl_compositor_init(&proc->compositor, pipe))
+ goto out_no_comp;
+
+ proc->base.pipe = pipe;
+ proc->base.query_max_layers = vl_pproc_query_max_layers;
+ proc->base.context_create = vl_pproc_ctx_create;
+ proc->base.buffer_filter_supported = vl_pproc_buffer_filter_supported;
+ proc->base.destroy = vl_pproc_destroy;
+
+ if (helpers)
+ *helpers = vl_pproc_helpers;
+
+ return &proc->base;
+
+ out_no_comp:
+ FREE(proc);
+ return NULL;
+}
diff --git a/src/gallium/auxiliary/vl/vl_postproc.h b/src/gallium/auxiliary/vl/vl_postproc.h
new file mode 100644
index 0000000..6ee1edc
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_postproc.h
@@ -0,0 +1,172 @@
+/**************************************************************************
+ *
+ * Copyright 2016 VMware Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *************************************************************************/
+
+#ifndef _VL_POSTPROC_H_
+#define _VL_POSTPROC_H_
+#include "util/u_video_compositor.h"
+#include "vl/vl_csc.h"
+#include "vl/vl_deint_filter.h"
+
+#define VL_FEATURE_3D_BLEND (1 << 0)
+#define VL_FEATURE_3D_ROTATE (1 << 1)
+#define VL_FEATURE_3D_HQ (1 << 2)
+#define VL_FEATURE_3D_SHARPNESS (1 << 3)
+#define VL_FEATURE_3D_NOISE_RED (1 << 4)
+
+struct vl_matrix_filter;
+struct vl_median_filter;
+struct util_bounce;
+
+struct vl_pproc_buffer_layer {
+ struct util_video_compositor *comp;
+ /** \brief Whether a buffer layer has been defined. */
+ bool has_buffer_layer;
+ /** \brief The layer number of the buffer layer if defined. */
+ unsigned buffer_layer;
+ /** \brief The current procamp to use for the buffer layer. */
+ util_video_compositor_csc_matrix matrix;
+ struct vl_procamp procamp;
+ /** \brief The current color conversion matrix to use. */
+ enum VL_CSC_COLOR_STANDARD cs;
+ /** \brief Buffer layer error occured during state processing. */
+ enum pipe_error buffer_layer_error;
+ /** \brief The buffer layer source rect. */
+ struct u_rect bsrc;
+ /** \brief The buffer layer destination rect. */
+ struct u_rect bdst;
+ /** \brief The buffer layer clip rect. */
+ struct u_rect dst_clip;
+ /** \brief The buffer layer viewport. */
+ struct u_rect viewport;
+ /** \brief Buffer layer field to present. */
+ enum util_video_compositor_deinterlace deinterlace;
+ /** \brief Whether we have a buffer layer source rect. */
+ bool has_bsrc;
+ /** \brief Whether we have a buffer layer destination rect. */
+ bool has_bdst;
+ /** \brief Whether we have a buffer layer blend state. */
+ bool has_bblend;
+ const void *bblend;
+ bool blend_is_clearing;
+ /** \brief Whether we have a buffer layer rotation. */
+ bool has_brotate;
+ enum util_video_compositor_rotation rotate;
+ /** \brief Whether we have a buffer layer destination clip. */
+ bool has_dst_clip;
+ /** \brief Whether we have a buffer layer viewport. */
+ bool has_viewport;
+ /** \brief The buffer layer pipe_video_buffer. */
+ struct pipe_video_buffer *buffer;
+ /** \brief The buffer layer clear color used outside of the destination
+ * rect, but not outside of the clip rect.
+ */
+ union pipe_color_union clear_color;
+ /** \brief Intermediate surface cache. */
+ struct util_bounce_cache *cache;
+ /** \brief Luma key filter settings. */
+ struct util_video_filter_luma_key luma_key;
+ /** \brief Deinterlacing filter settings. */
+ struct util_video_filter_deint deint;
+ /** \brief Sharpness filter settings. */
+ struct util_video_filter_sharpness sharpness;
+ /** \brief Noise reduction filter settings. */
+ struct util_video_filter_noise_red noise_red;
+ /** \brief High quality scaling filter settings. */
+ struct util_video_filter_hq_scaling hq;
+ /** \brief 3D pipeline sharpness filter state. */
+ struct {
+ struct vl_matrix_filter *filter; /**< \brief Standalone filter state. */
+ float matrix[9]; /**< \brief Pixel coefficients. */
+ unsigned width; /**< \brief Filter width. */
+ unsigned height; /**< \brief Filter height. */
+ } sharpness_3d;
+ /** \brief 3D pipeline noise reduction filter state. */
+ struct {
+ struct vl_median_filter *filter; /**< \brief Standalone filter state. */
+ unsigned width; /**< \brief Filter width. */
+ unsigned height; /**< \brief Filter weight. */
+ } noise_red_3d;
+ /** \brief 3D pipeline deinterlacing filter state. */
+ struct {
+ struct vl_deint_filter filter; /**< \brief Standalone filter state. */
+ bool initialized; /**< \brief Filter initialized?. */
+ unsigned width; /**< \brief Filter width. */
+ unsigned height; /**< \brief Filter height. */
+ bool skip_chroma; /**< \brief Skip chroma deinterlacing? */
+ } deint_3d;
+};
+
+/** Wrapping filter helpers */
+struct vl_pproc_helpers {
+ /**
+ * \brief Get the current buffer layer state.
+ *
+ * For a wrapping driver that potentially implements its own buffer layer
+ * color conversion, scaling and filtering, get the
+ * util_video_compositor_context's buffer layer state.
+ *
+ * \param ctx[in] The postprocessor context.
+ * \return The buffer layer state.
+ */
+ struct vl_pproc_buffer_layer *
+ (*buffer_layer)(struct util_video_compositor_context *ctx);
+
+ /**
+ * \brief Finalize the rendering.
+ *
+ * For a wrapping driver that potentially implements its own buffer layer
+ * color conversion, scaling and filtering, Finalize any 3D pipeline
+ * filtering and scaling remaining and perform the final composition
+ *
+ * \param ctx[in,out] The postprocessor context.
+ * \param features_3d[in] Remaining buffer layer rendering that is to be
+ * performed by the 3D pipeline. VL_FEATURE_3D flags.
+ * \param bounce[in] Bounce buffer holding the current buffer layer RGBA
+ * data. This function will release that bounce buffer to the bounce
+ * buffer cache.
+ * \param dirty_area[in,out] Dirty area to be cleared before rendering.
+ * The dirty_area gets updated by this function to the area actually
+ * rendered by this function. This is an optimization to avoid clearing
+ * the whole render target on each render.
+ * \param clear_dirty[in] Whether to clear the dirty area.
+ */
+ void
+ (*render_helper)(struct util_video_compositor_context *ctx,
+ uint32_t features_3d,
+ struct util_bounce *bounce,
+ struct pipe_surface *dst_surface,
+ struct u_rect *dirty_area,
+ bool clear_dirty);
+};
+
+struct util_video_compositor *
+vl_pproc_create(struct pipe_context *pipe,
+ struct vl_pproc_helpers *helpers);
+
+#endif
--
2.4.11
More information about the mesa-dev
mailing list