This fixes support for Motion Adaptive deinterlacing mode on both
Sandybridge and Ivybridge platforms. In particular, correct field
ordering is now supported, and STMM ping-pong buffering is added.

v2: changed STMM surface format to Y800 for a single plane.

Signed-off-by: Gwenole Beauchesne <gwenole.beauche...@intel.com>
---
 src/gen8_post_processing.c |   6 -
 src/i965_post_processing.c | 779 +++++++++++++++++++++++++--------------------
 src/i965_post_processing.h |  27 +-
 3 files changed, 452 insertions(+), 360 deletions(-)

diff --git a/src/gen8_post_processing.c b/src/gen8_post_processing.c
index 8a42ad7..a99faf1 100644
--- a/src/gen8_post_processing.c
+++ b/src/gen8_post_processing.c
@@ -1392,9 +1392,6 @@ gen8_post_processing_context_finalize(VADriverContextP 
ctx,
     dri_bo_unreference(pp_context->surface_state_binding_table.bo);
     pp_context->surface_state_binding_table.bo = NULL;
 
-    dri_bo_unreference(pp_context->pp_dndi_context.stmm_bo);
-    pp_context->pp_dndi_context.stmm_bo = NULL;
-
     dri_bo_unreference(pp_context->pp_dn_context.stmm_bo);
     pp_context->pp_dn_context.stmm_bo = NULL;
 
@@ -1498,9 +1495,6 @@ gen8_post_processing_context_init(VADriverContextP ctx,
     pp_context->pp_static_parameter = calloc(sizeof(struct 
gen7_pp_static_parameter), 1);
     pp_context->pp_inline_parameter = calloc(sizeof(struct 
gen7_pp_inline_parameter), 1);
 
-    pp_context->pp_dndi_context.current_out_surface = VA_INVALID_SURFACE;
-    pp_context->pp_dndi_context.current_out_obj_surface = NULL;
-    pp_context->pp_dndi_context.frame_order = -1;
     pp_context->batch = batch;
 
     pp_context->idrt_size = 5 * sizeof(struct gen8_interface_descriptor_data);
diff --git a/src/i965_post_processing.c b/src/i965_post_processing.c
index d819561..fbcafa0 100755
--- a/src/i965_post_processing.c
+++ b/src/i965_post_processing.c
@@ -1137,6 +1137,271 @@ static struct pp_module pp_modules_gen75[] = {
             
 };
 
+static void
+pp_dndi_frame_store_reset(DNDIFrameStore *fs)
+{
+    fs->obj_surface = NULL;
+    fs->surface_id = VA_INVALID_ID;
+    fs->is_scratch_surface = 0;
+}
+
+static inline void
+pp_dndi_frame_store_swap(DNDIFrameStore *fs1, DNDIFrameStore *fs2)
+{
+    const DNDIFrameStore tmpfs = *fs1;
+    *fs1 = *fs2;
+    *fs2 = tmpfs;
+}
+
+static inline void
+pp_dndi_frame_store_clear(DNDIFrameStore *fs, VADriverContextP ctx)
+{
+    if (fs->obj_surface && fs->is_scratch_surface) {
+        VASurfaceID va_surface = fs->obj_surface->base.id;
+        i965_DestroySurfaces(ctx, &va_surface, 1);
+    }
+    pp_dndi_frame_store_reset(fs);
+}
+
+static void
+pp_dndi_context_init(struct pp_dndi_context *dndi_ctx)
+{
+    int i;
+
+    memset(dndi_ctx, 0, sizeof(*dndi_ctx));
+    for (i = 0; i < ARRAY_ELEMS(dndi_ctx->frame_store); i++)
+        pp_dndi_frame_store_reset(&dndi_ctx->frame_store[i]);
+}
+
+static VAStatus
+pp_dndi_context_init_surface_params(struct pp_dndi_context *dndi_ctx,
+    struct object_surface *obj_surface,
+    const VAProcPipelineParameterBuffer *pipe_params,
+    const VAProcFilterParameterBufferDeinterlacing *deint_params)
+{
+    DNDIFrameStore *fs;
+
+    dndi_ctx->is_di_enabled = 1;
+    dndi_ctx->is_di_adv_enabled = 0;
+    dndi_ctx->is_first_frame = 0;
+    dndi_ctx->is_second_field = 0;
+
+    /* Check whether we are deinterlacing the second field */
+    if (dndi_ctx->is_di_enabled) {
+        const unsigned int tff =
+            !(deint_params->flags & VA_DEINTERLACING_BOTTOM_FIELD_FIRST);
+        const unsigned int is_top_field =
+            !(deint_params->flags & VA_DEINTERLACING_BOTTOM_FIELD);
+
+        if ((tff ^ is_top_field) != 0) {
+            fs = &dndi_ctx->frame_store[DNDI_FRAME_IN_CURRENT];
+            if (fs->surface_id != obj_surface->base.id) {
+                WARN_ONCE("invalid surface provided for second field\n");
+                return VA_STATUS_ERROR_INVALID_PARAMETER;
+            }
+            dndi_ctx->is_second_field = 1;
+        }
+    }
+
+    /* Check whether we are deinterlacing the first frame */
+    if (dndi_ctx->is_di_enabled) {
+        switch (deint_params->algorithm) {
+        case VAProcDeinterlacingBob:
+            dndi_ctx->is_first_frame = 1;
+            break;
+        case VAProcDeinterlacingMotionAdaptive:
+            fs = &dndi_ctx->frame_store[DNDI_FRAME_IN_CURRENT];
+            if (fs->surface_id == VA_INVALID_ID)
+                dndi_ctx->is_first_frame = 1;
+            else if (dndi_ctx->is_second_field) {
+                /* At this stage, we have already deinterlaced the
+                   first field successfully. So, the first frame flag
+                   is trigerred if the previous field was deinterlaced
+                   without reference frame */
+                fs = &dndi_ctx->frame_store[DNDI_FRAME_IN_PREVIOUS];
+                if (fs->surface_id == VA_INVALID_ID)
+                    dndi_ctx->is_first_frame = 1;
+            }
+            else {
+                if (pipe_params->num_forward_references < 1 ||
+                    pipe_params->forward_references[0] == VA_INVALID_ID) {
+                    WARN_ONCE("A forward temporal reference is needed for 
Motion adaptive/compensated deinterlacing !!!\n");
+                    return VA_STATUS_ERROR_INVALID_PARAMETER;
+                }
+            }
+            dndi_ctx->is_di_adv_enabled = 1;
+            break;
+        default:
+            WARN_ONCE("unsupported deinterlacing algorithm (%d)\n",
+                      deint_params->algorithm);
+            return VA_STATUS_ERROR_UNSUPPORTED_FILTER;
+        }
+    }
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+pp_dndi_context_ensure_surfaces_storage(VADriverContextP ctx,
+    struct i965_post_processing_context *pp_context,
+    struct object_surface *src_surface, struct object_surface *dst_surface)
+{
+    struct i965_driver_data * const i965 = i965_driver_data(ctx);
+    struct pp_dndi_context * const dndi_ctx = &pp_context->pp_dndi_context;
+    unsigned int src_fourcc, dst_fourcc;
+    unsigned int src_sampling, dst_sampling;
+    unsigned int src_tiling, dst_tiling;
+    unsigned int i, swizzle;
+    VAStatus status;
+
+    /* Determine input surface info. Always use NV12 Y-tiled */
+    if (src_surface->bo) {
+        src_fourcc = src_surface->fourcc;
+        src_sampling = src_surface->subsampling;
+        dri_bo_get_tiling(src_surface->bo, &src_tiling, &swizzle);
+        src_tiling = !!src_tiling;
+    }
+    else {
+        src_fourcc = VA_FOURCC_NV12;
+        src_sampling = SUBSAMPLE_YUV420;
+        src_tiling = 1;
+        status = i965_check_alloc_surface_bo(ctx, src_surface,
+            src_tiling, src_fourcc, src_sampling);
+        if (status != VA_STATUS_SUCCESS)
+            return status;
+    }
+
+    /* Determine output surface info. Always use NV12 Y-tiled */
+    if (dst_surface->bo) {
+        dst_fourcc   = dst_surface->fourcc;
+        dst_sampling = dst_surface->subsampling;
+        dri_bo_get_tiling(dst_surface->bo, &dst_tiling, &swizzle);
+        dst_tiling = !!dst_tiling;
+    }
+    else {
+        dst_fourcc = VA_FOURCC_NV12;
+        dst_sampling = SUBSAMPLE_YUV420;
+        dst_tiling = 1;
+        status = i965_check_alloc_surface_bo(ctx, dst_surface,
+            dst_tiling, dst_fourcc, dst_sampling);
+        if (status != VA_STATUS_SUCCESS)
+            return status;
+    }
+
+    /* Create pipeline surfaces */
+    for (i = 0; i < ARRAY_ELEMS(dndi_ctx->frame_store); i ++) {
+        struct object_surface *obj_surface;
+        VASurfaceID new_surface;
+        unsigned int width, height;
+
+        if (dndi_ctx->frame_store[i].obj_surface)
+            continue; // user allocated surface, not VPP internal
+
+        if (i <= DNDI_FRAME_IN_STMM) {
+            width = src_surface->orig_width;
+            height = src_surface->orig_height;
+        }
+        else {
+            width = dst_surface->orig_width;
+            height = dst_surface->orig_height;
+        }
+
+        status = i965_CreateSurfaces(ctx, width, height, VA_RT_FORMAT_YUV420,
+            1, &new_surface);
+        if (status != VA_STATUS_SUCCESS)
+            return status;
+
+        obj_surface = SURFACE(new_surface);
+        assert(obj_surface != NULL);
+
+        if (i <= DNDI_FRAME_IN_PREVIOUS) {
+            status = i965_check_alloc_surface_bo(ctx, obj_surface,
+                src_tiling, src_fourcc, src_sampling);
+        }
+        else if (i == DNDI_FRAME_IN_STMM || i == DNDI_FRAME_OUT_STMM) {
+            status = i965_check_alloc_surface_bo(ctx, obj_surface,
+                1, VA_FOURCC_Y800, SUBSAMPLE_YUV400);
+        }
+        else if (i >= DNDI_FRAME_OUT_CURRENT) {
+            status = i965_check_alloc_surface_bo(ctx, obj_surface,
+                dst_tiling, dst_fourcc, dst_sampling);
+        }
+        if (status != VA_STATUS_SUCCESS)
+            return status;
+
+        dndi_ctx->frame_store[i].obj_surface = obj_surface;
+        dndi_ctx->frame_store[i].is_scratch_surface = 1;
+    }
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+pp_dndi_context_ensure_surfaces(VADriverContextP ctx,
+    struct i965_post_processing_context *pp_context,
+    struct object_surface *src_surface, struct object_surface *dst_surface)
+{
+    struct i965_driver_data * const i965 = i965_driver_data(ctx);
+    struct pp_dndi_context * const dndi_ctx = &pp_context->pp_dndi_context;
+    DNDIFrameStore *ifs, *ofs;
+    bool is_new_frame = false;
+
+    /* Update the previous input surface */
+    is_new_frame = dndi_ctx->frame_store[DNDI_FRAME_IN_CURRENT].surface_id !=
+        src_surface->base.id;
+    if (is_new_frame) {
+        ifs = &dndi_ctx->frame_store[DNDI_FRAME_IN_PREVIOUS];
+        ofs = &dndi_ctx->frame_store[DNDI_FRAME_IN_CURRENT];
+        do {
+            const VAProcPipelineParameterBuffer * const pipe_params =
+                pp_context->pipeline_param;
+            struct object_surface *obj_surface;
+
+            if (pipe_params->num_forward_references < 1)
+                break;
+            if (pipe_params->forward_references[0] == VA_INVALID_ID)
+                break;
+
+            obj_surface = SURFACE(pipe_params->forward_references[0]);
+            if (!obj_surface || obj_surface->base.id == ifs->surface_id)
+                break;
+
+            pp_dndi_frame_store_clear(ifs, ctx);
+            if (obj_surface->base.id == ofs->surface_id) {
+                *ifs = *ofs;
+                pp_dndi_frame_store_reset(ofs);
+            }
+            else {
+                ifs->obj_surface = obj_surface;
+                ifs->surface_id = obj_surface->base.id;
+            }
+        } while (0);
+    }
+
+    /* Update the input surface */
+    ifs = &dndi_ctx->frame_store[DNDI_FRAME_IN_CURRENT];
+    pp_dndi_frame_store_clear(ifs, ctx);
+    ifs->obj_surface = src_surface;
+    ifs->surface_id = src_surface->base.id;
+
+    /* Update the Spatial Temporal Motion Measure (STMM) surfaces */
+    if (is_new_frame)
+        pp_dndi_frame_store_swap(&dndi_ctx->frame_store[DNDI_FRAME_IN_STMM],
+            &dndi_ctx->frame_store[DNDI_FRAME_OUT_STMM]);
+
+    /* Update the output surfaces */
+    ofs = &dndi_ctx->frame_store[DNDI_FRAME_OUT_CURRENT];
+    if (dndi_ctx->is_di_adv_enabled && !dndi_ctx->is_first_frame) {
+        pp_dndi_frame_store_swap(ofs,
+            &dndi_ctx->frame_store[DNDI_FRAME_OUT_PREVIOUS]);
+        if (!dndi_ctx->is_second_field)
+            ofs = &dndi_ctx->frame_store[DNDI_FRAME_OUT_PREVIOUS];
+    }
+    pp_dndi_frame_store_clear(ofs, ctx);
+    ofs->obj_surface = dst_surface;
+    ofs->surface_id = dst_surface->base.id;
+
+    return VA_STATUS_SUCCESS;
+}
+
 static int
 pp_get_surface_fourcc(VADriverContextP ctx, const struct i965_surface *surface)
 {
@@ -3087,177 +3352,91 @@ pp_nv12_dndi_initialize(VADriverContextP ctx, struct 
i965_post_processing_contex
                         const VARectangle *dst_rect,
                         void *filter_param)
 {
-    struct i965_driver_data *i965 = i965_driver_data(ctx);
-    struct pp_dndi_context *pp_dndi_context = (struct pp_dndi_context 
*)&pp_context->pp_dndi_context;
+    struct pp_dndi_context * const dndi_ctx = &pp_context->pp_dndi_context;
     struct pp_inline_parameter *pp_inline_parameter = 
pp_context->pp_inline_parameter;
     struct pp_static_parameter *pp_static_parameter = 
pp_context->pp_static_parameter;
-    struct object_surface *previous_in_obj_surface, *current_in_obj_surface, 
*previous_out_obj_surface, *current_out_obj_surface;
+    const VAProcPipelineParameterBuffer * const pipe_params =
+        pp_context->pipeline_param;
+    const VAProcFilterParameterBufferDeinterlacing * const deint_params =
+        filter_param;
+    struct object_surface * const src_obj_surface = (struct object_surface *)
+        src_surface->base;
+    struct object_surface * const dst_obj_surface = (struct object_surface *)
+        dst_surface->base;
+    struct object_surface *obj_surface;
     struct i965_sampler_dndi *sampler_dndi;
-    int index;
-    int w, h;
-    int orig_w, orig_h;
-    int dndi_top_first = 1;
-    VAProcFilterParameterBufferDeinterlacing *di_filter_param = 
(VAProcFilterParameterBufferDeinterlacing *)filter_param;
-    int is_first_frame = (pp_dndi_context->frame_order == -1);
-
-    if (di_filter_param->flags & VA_DEINTERLACING_BOTTOM_FIELD)
-        dndi_top_first = 0;
-    else
-        dndi_top_first = 1;
-
-    /* surface */
-    current_in_obj_surface = (struct object_surface *)src_surface->base;
-
-    if (di_filter_param->algorithm == VAProcDeinterlacingBob) {
-        previous_in_obj_surface = current_in_obj_surface;
-        is_first_frame = 1;
-    } else if (di_filter_param->algorithm == 
VAProcDeinterlacingMotionAdaptive) {
-        if (pp_dndi_context->frame_order == 0) {
-            VAProcPipelineParameterBuffer *pipeline_param = 
pp_context->pipeline_param;
-            if (!pipeline_param ||
-                !pipeline_param->num_forward_references ||
-                pipeline_param->forward_references[0] == VA_INVALID_ID) {
-                WARN_ONCE("A forward temporal reference is needed for Motion 
adaptive deinterlacing !!!\n");
-
-                return VA_STATUS_ERROR_INVALID_PARAMETER;
-            } else {
-                previous_in_obj_surface = 
SURFACE(pipeline_param->forward_references[0]);
-                assert(previous_in_obj_surface && previous_in_obj_surface->bo);
-
-                is_first_frame = 0;
-            }
-        } else if (pp_dndi_context->frame_order == 1) {
-            vpp_surface_convert(ctx,
-                                pp_dndi_context->current_out_obj_surface,
-                                (struct object_surface *)dst_surface->base);
-            pp_dndi_context->frame_order = (pp_dndi_context->frame_order + 1) 
% 2;
-            is_first_frame = 0;
-
-            return VA_STATUS_SUCCESS_1;
-        } else {
-            previous_in_obj_surface = current_in_obj_surface;
-            is_first_frame = 1;
-        }
-    } else {
-        return VA_STATUS_ERROR_UNIMPLEMENTED;
-    }
-
-    /* source (temporal reference) YUV surface index 5 */
-    orig_w = previous_in_obj_surface->orig_width;
-    orig_h = previous_in_obj_surface->orig_height;
-    w = previous_in_obj_surface->width;
-    h = previous_in_obj_surface->height;
-    i965_pp_set_surface2_state(ctx, pp_context,
-                               previous_in_obj_surface->bo, 0,
-                               orig_w, orig_h, w,
-                               0, h,
-                               SURFACE_FORMAT_PLANAR_420_8, 1,
-                               5);
-
-    /* source surface */
-    orig_w = current_in_obj_surface->orig_width;
-    orig_h = current_in_obj_surface->orig_height;
-    w = current_in_obj_surface->width;
-    h = current_in_obj_surface->height;
-
-    /* source UV surface index 2 */
-    i965_pp_set_surface_state(ctx, pp_context,
-                              current_in_obj_surface->bo, w * h,
-                              orig_w / 4, orig_h / 2, w, 
I965_SURFACEFORMAT_R8G8_UNORM,
-                              2, 0);
-
-    /* source YUV surface index 4 */
-    i965_pp_set_surface2_state(ctx, pp_context,
-                               current_in_obj_surface->bo, 0,
-                               orig_w, orig_h, w,
-                               0, h,
-                               SURFACE_FORMAT_PLANAR_420_8, 1,
-                               4);
-
-    /* source STMM surface index 6 */
-    if (pp_dndi_context->stmm_bo == NULL) {
-        pp_dndi_context->stmm_bo = dri_bo_alloc(i965->intel.bufmgr,
-                                                "STMM surface",
-                                                w * h,
-                                                4096);
-        assert(pp_dndi_context->stmm_bo);
-    }
-
-    i965_pp_set_surface_state(ctx, pp_context,
-                              pp_dndi_context->stmm_bo, 0,
-                              orig_w, orig_h, w, I965_SURFACEFORMAT_R8_UNORM,
-                              6, 0);
-
-    /* destination (Previous frame) */
-    previous_out_obj_surface = (struct object_surface *)dst_surface->base;
-    orig_w = previous_out_obj_surface->orig_width;
-    orig_h = previous_out_obj_surface->orig_height;
-    w = previous_out_obj_surface->width;
-    h = previous_out_obj_surface->height;
-
-    if (is_first_frame) {
-        current_out_obj_surface = previous_out_obj_surface;
-    } else {
-        VAStatus va_status;
-
-        if (pp_dndi_context->current_out_surface == VA_INVALID_SURFACE) {
-            unsigned int tiling = 0, swizzle = 0;
-            dri_bo_get_tiling(previous_out_obj_surface->bo, &tiling, &swizzle);
-
-            va_status = i965_CreateSurfaces(ctx,
-                                            orig_w,
-                                            orig_h,
-                                            VA_RT_FORMAT_YUV420,
-                                            1,
-                                            
&pp_dndi_context->current_out_surface);
-            assert(va_status == VA_STATUS_SUCCESS);
-            pp_dndi_context->current_out_obj_surface = 
SURFACE(pp_dndi_context->current_out_surface);
-            assert(pp_dndi_context->current_out_obj_surface);
-            i965_check_alloc_surface_bo(ctx,
-                                        
pp_dndi_context->current_out_obj_surface,
-                                        tiling != I915_TILING_NONE,
-                                        VA_FOURCC_NV12,
-                                        SUBSAMPLE_YUV420);
-        }
+    int index, dndi_top_first;
+    int w, h, orig_w, orig_h;
+    VAStatus status;
 
-        current_out_obj_surface = pp_dndi_context->current_out_obj_surface;
-    }
+    status = pp_dndi_context_init_surface_params(dndi_ctx, src_obj_surface,
+        pipe_params, deint_params);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    status = pp_dndi_context_ensure_surfaces(ctx, pp_context,
+        src_obj_surface, dst_obj_surface);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    status = pp_dndi_context_ensure_surfaces_storage(ctx, pp_context,
+        src_obj_surface, dst_obj_surface);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    /* Current input surface (index = 4) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_IN_CURRENT].obj_surface;
+    i965_pp_set_surface2_state(ctx, pp_context, obj_surface->bo, 0,
+        obj_surface->orig_width, obj_surface->orig_height, obj_surface->width,
+        0, obj_surface->y_cb_offset, SURFACE_FORMAT_PLANAR_420_8, 1, 4);
+
+    /* Previous input surface (index = 5) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_IN_PREVIOUS].obj_surface;
+    i965_pp_set_surface2_state(ctx, pp_context, obj_surface->bo, 0,
+        obj_surface->orig_width, obj_surface->orig_height, obj_surface->width,
+        0, obj_surface->y_cb_offset, SURFACE_FORMAT_PLANAR_420_8, 1, 5);
+
+    /* STMM input surface (index = 6) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_IN_STMM].obj_surface;
+    i965_pp_set_surface_state(ctx, pp_context, obj_surface->bo, 0,
+        obj_surface->orig_width, obj_surface->orig_height, obj_surface->width,
+        I965_SURFACEFORMAT_R8_UNORM, 6, 1);
+
+    /* Previous output surfaces (index = { 7, 8 }) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_OUT_PREVIOUS].obj_surface;
+    w = obj_surface->width;
+    h = obj_surface->height;
+    orig_w = obj_surface->orig_width;
+    orig_h = obj_surface->orig_height;
 
-    /* destination (Previous frame) Y surface index 7 */
-    i965_pp_set_surface_state(ctx, pp_context,
-                              previous_out_obj_surface->bo, 0,
-                              orig_w / 4, orig_h, w, 
I965_SURFACEFORMAT_R8_UNORM,
-                              7, 1);
+    i965_pp_set_surface_state(ctx, pp_context, obj_surface->bo, 0,
+        orig_w / 4, orig_h, w, I965_SURFACEFORMAT_R8_UNORM, 7, 1);
+    i965_pp_set_surface_state(ctx, pp_context, obj_surface->bo, w * h,
+        orig_w / 4, orig_h / 2, w, I965_SURFACEFORMAT_R8G8_UNORM, 8, 1);
 
-    /* destination (Previous frame) UV surface index 8 */
-    i965_pp_set_surface_state(ctx, pp_context,
-                              previous_out_obj_surface->bo, w * h,
-                              orig_w / 4, orig_h / 2, w, 
I965_SURFACEFORMAT_R8G8_UNORM,
-                              8, 1);
+    /* Current output surfaces (index = { 10, 11 }) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_OUT_CURRENT].obj_surface;
+    w = obj_surface->width;
+    h = obj_surface->height;
+    orig_w = obj_surface->orig_width;
+    orig_h = obj_surface->orig_height;
 
-    /* destination(Current frame) */
-    orig_w = current_out_obj_surface->orig_width;
-    orig_h = current_out_obj_surface->orig_height;
-    w = current_out_obj_surface->width;
-    h = current_out_obj_surface->height;
+    i965_pp_set_surface_state(ctx, pp_context, obj_surface->bo, 0,
+        orig_w / 4, orig_h, w, I965_SURFACEFORMAT_R8_UNORM, 10, 1);
+    i965_pp_set_surface_state(ctx, pp_context, obj_surface->bo, w * h,
+        orig_w / 4, orig_h / 2, w, I965_SURFACEFORMAT_R8G8_UNORM, 11, 1);
 
-    /* destination (Current frame) Y surface index xxx */
-    i965_pp_set_surface_state(ctx, pp_context,
-                              current_out_obj_surface->bo, 0,
-                              orig_w / 4, orig_h, w, 
I965_SURFACEFORMAT_R8_UNORM,
-                              10, 1);
+    /* STMM output surface (index = 20) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_OUT_STMM].obj_surface;
+    i965_pp_set_surface_state(ctx, pp_context, obj_surface->bo, 0,
+        obj_surface->orig_width, obj_surface->orig_height, obj_surface->width,
+        I965_SURFACEFORMAT_R8_UNORM, 20, 1);
 
-    /* destination (Current frame) UV surface index xxx */
-    i965_pp_set_surface_state(ctx, pp_context,
-                              current_out_obj_surface->bo, w * h,
-                              orig_w / 4, orig_h / 2, w, 
I965_SURFACEFORMAT_R8G8_UNORM,
-                              11, 1);
-
-    /* STMM output surface, index 20 */
-    i965_pp_set_surface_state(ctx, pp_context,
-                              pp_dndi_context->stmm_bo, 0,
-                              orig_w, orig_h, w, I965_SURFACEFORMAT_R8_UNORM,
-                              20, 1);
+    /* If we are in "First Frame" mode, i.e. past frames are not
+       available for motion measure, then don't use the TFF flag */
+    dndi_top_first = !(deint_params->flags & (dndi_ctx->is_first_frame ?
+            VA_DEINTERLACING_BOTTOM_FIELD :
+            VA_DEINTERLACING_BOTTOM_FIELD_FIRST));
 
     /* sampler dndi */
     dri_bo_map(pp_context->sampler_state_table.bo, True);
@@ -3306,7 +3485,7 @@ pp_nv12_dndi_initialize(VADriverContextP ctx, struct 
i965_post_processing_contex
     sampler_dndi[index].dw6.di_partial = 0;
     sampler_dndi[index].dw6.dndi_top_first = dndi_top_first;
     sampler_dndi[index].dw6.dndi_stream_id = 0;
-    sampler_dndi[index].dw6.dndi_first_frame = is_first_frame;
+    sampler_dndi[index].dw6.dndi_first_frame = dndi_ctx->is_first_frame;
     sampler_dndi[index].dw6.progressive_dn = 0;
     sampler_dndi[index].dw6.fmd_tear_threshold = 2;
     sampler_dndi[index].dw6.fmd2_vertical_difference_threshold = 100;
@@ -3322,7 +3501,7 @@ pp_nv12_dndi_initialize(VADriverContextP ctx, struct 
i965_post_processing_contex
     /* private function & data */
     pp_context->pp_x_steps = pp_dndi_x_steps;
     pp_context->pp_y_steps = pp_dndi_y_steps;
-    pp_context->private_context = &pp_context->pp_dndi_context;
+    pp_context->private_context = dndi_ctx;
     pp_context->pp_set_block_parameter = pp_dndi_set_block_parameter;
 
     pp_static_parameter->grf1.statistics_surface_picth = w / 2;
@@ -3335,13 +3514,10 @@ pp_nv12_dndi_initialize(VADriverContextP ctx, struct 
i965_post_processing_contex
     pp_inline_parameter->grf5.block_vertical_mask = 0xff;
     pp_inline_parameter->grf5.block_horizontal_mask = 0xffff;
 
-    pp_dndi_context->dest_w = w;
-    pp_dndi_context->dest_h = h;
+    dndi_ctx->dest_w = w;
+    dndi_ctx->dest_h = h;
 
     dst_surface->flags = I965_SURFACE_FLAG_FRAME;
-
-    pp_dndi_context->frame_order = (pp_dndi_context->frame_order + 1) % 2;
-
     return VA_STATUS_SUCCESS;
 }
 
@@ -3587,176 +3763,90 @@ gen7_pp_nv12_dndi_initialize(VADriverContextP ctx, 
struct i965_post_processing_c
                              const VARectangle *dst_rect,
                              void *filter_param)
 {
-    struct i965_driver_data *i965 = i965_driver_data(ctx);
-    struct pp_dndi_context *pp_dndi_context = (struct pp_dndi_context 
*)&pp_context->pp_dndi_context;
+    struct pp_dndi_context * const dndi_ctx = &pp_context->pp_dndi_context;
     struct gen7_pp_static_parameter *pp_static_parameter = 
pp_context->pp_static_parameter;
-    struct object_surface *previous_in_obj_surface, *current_in_obj_surface, 
*previous_out_obj_surface, *current_out_obj_surface;
+    const VAProcPipelineParameterBuffer * const pipe_params =
+        pp_context->pipeline_param;
+    const VAProcFilterParameterBufferDeinterlacing * const deint_params =
+        filter_param;
+    struct object_surface * const src_obj_surface = (struct object_surface *)
+        src_surface->base;
+    struct object_surface * const dst_obj_surface = (struct object_surface *)
+        dst_surface->base;
+    struct object_surface *obj_surface;
     struct gen7_sampler_dndi *sampler_dndi;
-    int index;
-    int w, h;
-    int orig_w, orig_h;
-    int dndi_top_first = 1;
-    VAProcFilterParameterBufferDeinterlacing *di_filter_param = 
(VAProcFilterParameterBufferDeinterlacing *)filter_param;
-    int is_first_frame = (pp_dndi_context->frame_order == -1);
-
-    if (di_filter_param->flags & VA_DEINTERLACING_BOTTOM_FIELD)
-        dndi_top_first = 0;
-    else
-        dndi_top_first = 1;
-
-    /* surface */
-    current_in_obj_surface = (struct object_surface *)src_surface->base;
-
-    if (di_filter_param->algorithm == VAProcDeinterlacingBob) {
-        previous_in_obj_surface = current_in_obj_surface;
-        is_first_frame = 1;
-    } else if (di_filter_param->algorithm == 
VAProcDeinterlacingMotionAdaptive) {
-        if (pp_dndi_context->frame_order == 0) {
-            VAProcPipelineParameterBuffer *pipeline_param = 
pp_context->pipeline_param;
-            if (!pipeline_param ||
-                !pipeline_param->num_forward_references ||
-                pipeline_param->forward_references[0] == VA_INVALID_ID) {
-                WARN_ONCE("A forward temporal reference is needed for Motion 
adaptive deinterlacing !!!\n");
-
-                return VA_STATUS_ERROR_INVALID_PARAMETER;
-            } else {
-                previous_in_obj_surface = 
SURFACE(pipeline_param->forward_references[0]);
-                assert(previous_in_obj_surface && previous_in_obj_surface->bo);
-
-                is_first_frame = 0;
-            }
-        } else if (pp_dndi_context->frame_order == 1) {
-            vpp_surface_convert(ctx,
-                                pp_dndi_context->current_out_obj_surface,
-                                (struct object_surface *)dst_surface->base);
-            pp_dndi_context->frame_order = (pp_dndi_context->frame_order + 1) 
% 2;
-            is_first_frame = 0;
-
-            return VA_STATUS_SUCCESS_1;
-        } else {
-            previous_in_obj_surface = current_in_obj_surface;
-            is_first_frame = 1;
-        }
-    } else {
-        return VA_STATUS_ERROR_UNIMPLEMENTED;
-    }
-
-    /* source (temporal reference) YUV surface index 4 */
-    orig_w = previous_in_obj_surface->orig_width;
-    orig_h = previous_in_obj_surface->orig_height;
-    w = previous_in_obj_surface->width;
-    h = previous_in_obj_surface->height;
-    gen7_pp_set_surface2_state(ctx, pp_context,
-                               previous_in_obj_surface->bo, 0,
-                               orig_w, orig_h, w,
-                               0, h,
-                               SURFACE_FORMAT_PLANAR_420_8, 1,
-                               4);
-
-    /* source surface */
-    orig_w = current_in_obj_surface->orig_width;
-    orig_h = current_in_obj_surface->orig_height;
-    w = current_in_obj_surface->width;
-    h = current_in_obj_surface->height;
-
-    /* source UV surface index 1 */
-    gen7_pp_set_surface_state(ctx, pp_context,
-                              current_in_obj_surface->bo, w * h,
-                              orig_w / 4, orig_h / 2, w, 
I965_SURFACEFORMAT_R8G8_UNORM,
-                              1, 0);
-
-    /* source YUV surface index 3 */
-    gen7_pp_set_surface2_state(ctx, pp_context,
-                               current_in_obj_surface->bo, 0,
-                               orig_w, orig_h, w,
-                               0, h,
-                               SURFACE_FORMAT_PLANAR_420_8, 1,
-                               3);
-
-    /* STMM / History Statistics input surface, index 5 */
-    if (pp_dndi_context->stmm_bo == NULL) {
-        pp_dndi_context->stmm_bo = dri_bo_alloc(i965->intel.bufmgr,
-                                                "STMM surface",
-                                                w * h,
-                                                4096);
-        assert(pp_dndi_context->stmm_bo);
-    }
-
-    gen7_pp_set_surface_state(ctx, pp_context,
-                              pp_dndi_context->stmm_bo, 0,
-                              orig_w, orig_h, w, I965_SURFACEFORMAT_R8_UNORM,
-                              5, 1);
-
-    /* destination surface */
-    previous_out_obj_surface = (struct object_surface *)dst_surface->base;
-    orig_w = previous_out_obj_surface->orig_width;
-    orig_h = previous_out_obj_surface->orig_height;
-    w = previous_out_obj_surface->width;
-    h = previous_out_obj_surface->height;
-
-    if (is_first_frame) {
-        current_out_obj_surface = previous_out_obj_surface;
-    } else {
-        VAStatus va_status;
-
-        if (pp_dndi_context->current_out_surface == VA_INVALID_SURFACE) {
-            unsigned int tiling = 0, swizzle = 0;
-            dri_bo_get_tiling(previous_out_obj_surface->bo, &tiling, &swizzle);
-
-            va_status = i965_CreateSurfaces(ctx,
-                                            orig_w,
-                                            orig_h,
-                                            VA_RT_FORMAT_YUV420,
-                                            1,
-                                            
&pp_dndi_context->current_out_surface);
-            assert(va_status == VA_STATUS_SUCCESS);
-            pp_dndi_context->current_out_obj_surface = 
SURFACE(pp_dndi_context->current_out_surface);
-            assert(pp_dndi_context->current_out_obj_surface);
-            i965_check_alloc_surface_bo(ctx,
-                                        
pp_dndi_context->current_out_obj_surface,
-                                        tiling != I915_TILING_NONE,
-                                        VA_FOURCC_NV12,
-                                        SUBSAMPLE_YUV420);
-        }
-
-        current_out_obj_surface = pp_dndi_context->current_out_obj_surface;
-    }
-
-    /* destination(Previous frame) Y surface index 27 */
-    gen7_pp_set_surface_state(ctx, pp_context,
-                              previous_out_obj_surface->bo, 0,
-                              orig_w / 4, orig_h, w, 
I965_SURFACEFORMAT_R8_UNORM,
-                              27, 1);
+    int index, dndi_top_first;
+    int w, h, orig_w, orig_h;
+    VAStatus status;
 
-    /* destination(Previous frame) UV surface index 28 */
-    gen7_pp_set_surface_state(ctx, pp_context,
-                              previous_out_obj_surface->bo, w * h,
-                              orig_w / 4, orig_h / 2, w, 
I965_SURFACEFORMAT_R8G8_UNORM,
-                              28, 1);
+    status = pp_dndi_context_init_surface_params(dndi_ctx, src_obj_surface,
+        pipe_params, deint_params);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    status = pp_dndi_context_ensure_surfaces(ctx, pp_context,
+        src_obj_surface, dst_obj_surface);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    status = pp_dndi_context_ensure_surfaces_storage(ctx, pp_context,
+        src_obj_surface, dst_obj_surface);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    /* Current input surface (index = 3) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_IN_CURRENT].obj_surface;
+    gen7_pp_set_surface2_state(ctx, pp_context, obj_surface->bo, 0,
+        obj_surface->orig_width, obj_surface->orig_height, obj_surface->width,
+        0, obj_surface->y_cb_offset, SURFACE_FORMAT_PLANAR_420_8, 1, 3);
+
+    /* Previous input surface (index = 4) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_IN_PREVIOUS].obj_surface;
+    gen7_pp_set_surface2_state(ctx, pp_context, obj_surface->bo, 0,
+        obj_surface->orig_width, obj_surface->orig_height, obj_surface->width,
+        0, obj_surface->y_cb_offset, SURFACE_FORMAT_PLANAR_420_8, 1, 4);
+
+    /* STMM input surface (index = 5) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_IN_STMM].obj_surface;
+    gen7_pp_set_surface_state(ctx, pp_context, obj_surface->bo, 0,
+        obj_surface->orig_width, obj_surface->orig_height, obj_surface->width,
+        I965_SURFACEFORMAT_R8_UNORM, 5, 1);
+
+    /* Previous output surfaces (index = { 27, 28 }) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_OUT_PREVIOUS].obj_surface;
+    w = obj_surface->width;
+    h = obj_surface->height;
+    orig_w = obj_surface->orig_width;
+    orig_h = obj_surface->orig_height;
 
-    /* destination(Current frame) Y surface index 30 */
-    gen7_pp_set_surface_state(ctx, pp_context,
-                              current_out_obj_surface->bo, 0,
-                              orig_w / 4, orig_h, w, 
I965_SURFACEFORMAT_R8_UNORM,
-                              30, 1);
+    gen7_pp_set_surface_state(ctx, pp_context, obj_surface->bo, 0,
+        orig_w / 4, orig_h, w, I965_SURFACEFORMAT_R8_UNORM, 27, 1);
+    gen7_pp_set_surface_state(ctx, pp_context, obj_surface->bo, w * h,
+        orig_w / 4, orig_h / 2, w, I965_SURFACEFORMAT_R8G8_UNORM, 28, 1);
 
-    /* destination(Current frame) UV surface index 31 */
-    orig_w = current_out_obj_surface->orig_width;
-    orig_h = current_out_obj_surface->orig_height;
-    w = current_out_obj_surface->width;
-    h = current_out_obj_surface->height;
+    /* Current output surfaces (index = { 30, 31 }) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_OUT_CURRENT].obj_surface;
+    w = obj_surface->width;
+    h = obj_surface->height;
+    orig_w = obj_surface->orig_width;
+    orig_h = obj_surface->orig_height;
 
-    gen7_pp_set_surface_state(ctx, pp_context,
-                              current_out_obj_surface->bo, w * h,
-                              orig_w / 4, orig_h / 2, w, 
I965_SURFACEFORMAT_R8G8_UNORM,
-                              31, 1);
+    gen7_pp_set_surface_state(ctx, pp_context, obj_surface->bo, 0,
+        orig_w / 4, orig_h, w, I965_SURFACEFORMAT_R8_UNORM, 30, 1);
+    gen7_pp_set_surface_state(ctx, pp_context, obj_surface->bo, w * h,
+        orig_w / 4, orig_h / 2, w, I965_SURFACEFORMAT_R8G8_UNORM, 31, 1);
 
-    /* STMM output surface, index 33 */
-    gen7_pp_set_surface_state(ctx, pp_context,
-                              pp_dndi_context->stmm_bo, 0,
-                              orig_w, orig_h, w, I965_SURFACEFORMAT_R8_UNORM,
-                              33, 1);
+    /* STMM output surface (index = 33) */
+    obj_surface = dndi_ctx->frame_store[DNDI_FRAME_OUT_STMM].obj_surface;
+    gen7_pp_set_surface_state(ctx, pp_context, obj_surface->bo, 0,
+        obj_surface->orig_width, obj_surface->orig_height, obj_surface->width,
+        I965_SURFACEFORMAT_R8_UNORM, 33, 1);
 
+    /* If we are in "First Frame" mode, i.e. past frames are not
+       available for motion measure, then don't use the TFF flag */
+    dndi_top_first = !(deint_params->flags & (dndi_ctx->is_first_frame ?
+            VA_DEINTERLACING_BOTTOM_FIELD :
+            VA_DEINTERLACING_BOTTOM_FIELD_FIRST));
 
     /* sampler dndi */
     dri_bo_map(pp_context->sampler_state_table.bo, True);
@@ -3808,7 +3898,7 @@ gen7_pp_nv12_dndi_initialize(VADriverContextP ctx, struct 
i965_post_processing_c
     sampler_dndi[index].dw6.di_partial = 0;
     sampler_dndi[index].dw6.dndi_top_first = dndi_top_first;
     sampler_dndi[index].dw6.dndi_stream_id = 1;
-    sampler_dndi[index].dw6.dndi_first_frame = is_first_frame;
+    sampler_dndi[index].dw6.dndi_first_frame = dndi_ctx->is_first_frame;
     sampler_dndi[index].dw6.progressive_dn = 0;
     sampler_dndi[index].dw6.mcdi_enable = 0;
     sampler_dndi[index].dw6.fmd_tear_threshold = 2;
@@ -3830,7 +3920,7 @@ gen7_pp_nv12_dndi_initialize(VADriverContextP ctx, struct 
i965_post_processing_c
     /* private function & data */
     pp_context->pp_x_steps = gen7_pp_dndi_x_steps;
     pp_context->pp_y_steps = gen7_pp_dndi_y_steps;
-    pp_context->private_context = &pp_context->pp_dndi_context;
+    pp_context->private_context = dndi_ctx;
     pp_context->pp_set_block_parameter = gen7_pp_dndi_set_block_parameter;
 
     pp_static_parameter->grf1.di_statistics_surface_pitch_div2 = w / 2;
@@ -3845,13 +3935,10 @@ gen7_pp_nv12_dndi_initialize(VADriverContextP ctx, 
struct i965_post_processing_c
     pp_static_parameter->grf4.di_hoffset_svf_from_dvf = 0;
     pp_static_parameter->grf4.di_voffset_svf_from_dvf = 0;
 
-    pp_dndi_context->dest_w = w;
-    pp_dndi_context->dest_h = h;
+    dndi_ctx->dest_w = w;
+    dndi_ctx->dest_h = h;
 
     dst_surface->flags = I965_SURFACE_FLAG_FRAME;
-
-    pp_dndi_context->frame_order = (pp_dndi_context->frame_order + 1) % 2;
-
     return VA_STATUS_SUCCESS;
 }
 
@@ -5305,15 +5392,9 @@ i965_post_processing_context_finalize(VADriverContextP 
ctx,
     dri_bo_unreference(pp_context->vfe_state.bo);
     pp_context->vfe_state.bo = NULL;
 
-    dri_bo_unreference(pp_context->pp_dndi_context.stmm_bo);
-    pp_context->pp_dndi_context.stmm_bo = NULL;
-
-    if (pp_context->pp_dndi_context.current_out_surface != VA_INVALID_ID) {
-        i965_DestroySurfaces(ctx,
-            &pp_context->pp_dndi_context.current_out_surface, 1);
-        pp_context->pp_dndi_context.current_out_surface = VA_INVALID_ID;
-        pp_context->pp_dndi_context.current_out_obj_surface = NULL;
-    }
+    for (i = 0; i < ARRAY_ELEMS(pp_context->pp_dndi_context.frame_store); i++)
+        pp_dndi_frame_store_clear(&pp_context->pp_dndi_context.frame_store[i],
+            ctx);
 
     dri_bo_unreference(pp_context->pp_dn_context.stmm_bo);
     pp_context->pp_dn_context.stmm_bo = NULL;
@@ -5418,10 +5499,8 @@ i965_post_processing_context_init(VADriverContextP ctx,
         pp_context->pp_inline_parameter = calloc(sizeof(struct 
pp_inline_parameter), 1);
     }
 
-    pp_context->pp_dndi_context.current_out_surface = VA_INVALID_SURFACE;
-    pp_context->pp_dndi_context.current_out_obj_surface = NULL;
-    pp_context->pp_dndi_context.frame_order = -1;
     pp_context->batch = batch;
+    pp_dndi_context_init(&pp_context->pp_dndi_context);
 
     avs_config = IS_IRONLAKE(i965->intel.device_info) ? &gen5_avs_config :
         &gen6_avs_config;
diff --git a/src/i965_post_processing.h b/src/i965_post_processing.h
index 2d4cc10..0e32d99 100755
--- a/src/i965_post_processing.h
+++ b/src/i965_post_processing.h
@@ -88,14 +88,33 @@ struct pp_avs_context
     float horiz_range;
 };
 
+enum {
+    DNDI_FRAME_IN_CURRENT = 0,
+    DNDI_FRAME_IN_PREVIOUS,
+    DNDI_FRAME_IN_STMM,
+    DNDI_FRAME_OUT_STMM,
+    DNDI_FRAME_OUT_CURRENT,
+    DNDI_FRAME_OUT_PREVIOUS,
+    DNDI_FRAME_STORE_COUNT
+};
+
+typedef struct dndi_frame_store {
+    struct object_surface *obj_surface;
+    VASurfaceID surface_id; /* always relative to the input surface */
+    unsigned int is_scratch_surface : 1;
+} DNDIFrameStore;
+
 struct pp_dndi_context
 {
     int dest_w;
     int dest_h;
-    dri_bo *stmm_bo;
-    int frame_order; /* -1 for the first frame */
-    VASurfaceID current_out_surface;
-    struct object_surface *current_out_obj_surface;
+    DNDIFrameStore frame_store[DNDI_FRAME_STORE_COUNT];
+
+    /* Temporary flags live until the current picture is processed */
+    unsigned int is_di_enabled          : 1;
+    unsigned int is_di_adv_enabled      : 1;
+    unsigned int is_first_frame         : 1;
+    unsigned int is_second_field        : 1;
 };
 
 struct pp_dn_context
-- 
1.9.1

_______________________________________________
Libva mailing list
Libva@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libva

Reply via email to