From 763dc06dc4714158dd2cdbe35c41d2c2192c871e Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Fri, 8 Aug 2014 11:30:25 +0200
Subject: [PATCH 01/19] vebox: silence compilation warning.

Silence the following compilation warning:
  CC     i965_drv_video_la-gen75_vpp_vebox.lo
gen75_vpp_vebox.c: In function 'bdw_veb_dndi_iecp_command':
gen75_vpp_vebox.c:1537:5: warning: suggest parentheses around arithmetic in operand of '|' [-Wparentheses]

Also simplify the calculation of the VEB_DI_IECP::endingX variable
with existing helper macros.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 1113c90..f452e67 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -805,8 +805,8 @@ void hsw_veb_dndi_iecp_command(VADriverContextP ctx, struct intel_vebox_context
 {
     struct intel_batchbuffer *batch = proc_ctx->batch;
     unsigned char frame_ctrl_bits = 0;
-    unsigned int startingX = 0;
-    unsigned int endingX = (proc_ctx->width_input + 63 ) / 64 * 64;
+    const unsigned int startingX = 0;
+    const unsigned int endingX = ALIGN(proc_ctx->width_input, 64) - 1;
 
     /* s1:update the previous and current input */
 /*    tempFrame = proc_ctx->frame_store[FRAME_IN_PREVIOUS];
@@ -829,9 +829,7 @@ void hsw_veb_dndi_iecp_command(VADriverContextP ctx, struct intel_vebox_context
     /*s3:set reloc buffer address */
     BEGIN_VEB_BATCH(batch, 10);
     OUT_VEB_BATCH(batch, VEB_DNDI_IECP_STATE | (10 - 2));
-    OUT_VEB_BATCH(batch,
-                  startingX << 16 |
-                  (endingX-1));
+    OUT_VEB_BATCH(batch, (startingX << 16) | endingX);
     OUT_RELOC(batch,
               proc_ctx->frame_store[FRAME_IN_CURRENT].obj_surface->bo,
               I915_GEM_DOMAIN_RENDER, 0, frame_ctrl_bits);
@@ -1532,14 +1530,12 @@ void bdw_veb_dndi_iecp_command(VADriverContextP ctx, struct intel_vebox_context
 {
     struct intel_batchbuffer *batch = proc_ctx->batch;
     unsigned char frame_ctrl_bits = 0;
-    unsigned int startingX = 0;
-    unsigned int endingX = (proc_ctx->width_input + 63 ) / 64 * 64;
+    const unsigned int startingX = 0;
+    const unsigned int endingX = ALIGN(proc_ctx->width_input, 64) - 1;
 
     BEGIN_VEB_BATCH(batch, 0x14);
     OUT_VEB_BATCH(batch, VEB_DNDI_IECP_STATE | (0x14 - 2));//DWord 0
-    OUT_VEB_BATCH(batch,
-                  startingX << 16 |
-                  endingX -1);//DWord 1
+    OUT_VEB_BATCH(batch, (startingX << 16) | endingX);
 
     OUT_RELOC(batch,
               proc_ctx->frame_store[FRAME_IN_CURRENT].obj_surface->bo,

From 65e494c4b503bceeb6fcd038bdcbff3f6ec3875e Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Fri, 8 Aug 2014 15:06:10 +0200
Subject: [PATCH 02/19] vebox: drop magic numbers in filters mask.

Use the existing VPP_{DNDI,IECP}_xxx flags instead of magic numbers.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 16 ++++++++--------
 src/gen75_vpp_vebox.h |  2 ++
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index f452e67..76ecc6b 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -626,7 +626,7 @@ void hsw_veb_iecp_aoi_table(VADriverContextP ctx, struct intel_vebox_context *pr
 
 void hsw_veb_state_table_setup(VADriverContextP ctx, struct intel_vebox_context *proc_ctx)
 {
-    if(proc_ctx->filters_mask & 0x000000ff) {
+    if(proc_ctx->filters_mask & VPP_DNDI_MASK) {
         dri_bo *dndi_bo = proc_ctx->dndi_state_table.bo;
         dri_bo_map(dndi_bo, 1);
         proc_ctx->dndi_state_table.ptr = dndi_bo->virtual;
@@ -636,7 +636,7 @@ void hsw_veb_state_table_setup(VADriverContextP ctx, struct intel_vebox_context
         dri_bo_unmap(dndi_bo);
     }
 
-    if(proc_ctx->filters_mask & 0x0000ff00) {
+    if(proc_ctx->filters_mask & VPP_IECP_MASK) {
         dri_bo *iecp_bo = proc_ctx->iecp_state_table.bo;
         dri_bo_map(iecp_bo, 1);
         proc_ctx->iecp_state_table.ptr = iecp_bo->virtual;
@@ -655,9 +655,9 @@ void hsw_veb_state_table_setup(VADriverContextP ctx, struct intel_vebox_context
 void hsw_veb_state_command(VADriverContextP ctx, struct intel_vebox_context *proc_ctx)
 {
     struct intel_batchbuffer *batch = proc_ctx->batch;
-    unsigned int is_dn_enabled   = (proc_ctx->filters_mask & 0x01)? 1: 0;
-    unsigned int is_di_enabled   = (proc_ctx->filters_mask & 0x02)? 1: 0;
-    unsigned int is_iecp_enabled = (proc_ctx->filters_mask & 0xff00)?1:0;
+    unsigned int is_dn_enabled   = !!(proc_ctx->filters_mask & VPP_DNDI_DN);
+    unsigned int is_di_enabled   = !!(proc_ctx->filters_mask & VPP_DNDI_DI);
+    unsigned int is_iecp_enabled = !!(proc_ctx->filters_mask & VPP_IECP_MASK);
     unsigned int is_first_frame  = !!((proc_ctx->frame_order == -1) &&
                                       (is_di_enabled ||
                                        is_dn_enabled));
@@ -1446,9 +1446,9 @@ struct intel_vebox_context * gen75_vebox_context_init(VADriverContextP ctx)
 void bdw_veb_state_command(VADriverContextP ctx, struct intel_vebox_context *proc_ctx)
 {
     struct intel_batchbuffer *batch = proc_ctx->batch;
-    unsigned int is_dn_enabled   = (proc_ctx->filters_mask & 0x01)? 1: 0;
-    unsigned int is_di_enabled   = (proc_ctx->filters_mask & 0x02)? 1: 0;
-    unsigned int is_iecp_enabled = (proc_ctx->filters_mask & 0xff00)?1:0;
+    unsigned int is_dn_enabled   = !!(proc_ctx->filters_mask & VPP_DNDI_DN);
+    unsigned int is_di_enabled   = !!(proc_ctx->filters_mask & VPP_DNDI_DI);
+    unsigned int is_iecp_enabled = !!(proc_ctx->filters_mask & VPP_IECP_MASK);
     unsigned int is_first_frame  = !!((proc_ctx->frame_order == -1) &&
                                       (is_di_enabled ||
                                        is_dn_enabled));
diff --git a/src/gen75_vpp_vebox.h b/src/gen75_vpp_vebox.h
index a78a165..a0842b0 100644
--- a/src/gen75_vpp_vebox.h
+++ b/src/gen75_vpp_vebox.h
@@ -43,12 +43,14 @@
 
 #define VPP_DNDI_DN        0x00000001
 #define VPP_DNDI_DI        0x00000002
+#define VPP_DNDI_MASK      0x000000ff
 #define VPP_IECP_STD_STE   0x00000100
 #define VPP_IECP_ACE       0x00000200
 #define VPP_IECP_TCC       0x00000400
 #define VPP_IECP_PRO_AMP   0x00000800
 #define VPP_IECP_CSC       0x00001000
 #define VPP_IECP_AOI       0x00002000
+#define VPP_IECP_MASK      0x0000ff00
 #define MAX_FILTER_SUM     8
 
 #define PRE_FORMAT_CONVERT      0x01

From 88bbe79a7419d81b66b3fffff8d28b88c6bdba22 Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Fri, 8 Aug 2014 10:35:14 +0200
Subject: [PATCH 03/19] vebox: fix indication of field ordering in sequence.

VEBOX_DNDI_STATE::dndi_top_first indicates whether the top field is
first in sequence (TFF), or if the bottom field comes first. This is
an indication of the temporal sequence for input frames, available
in the "history" buffer. As such, the correct flag to check against,
from a VA-API perspective, is VA_DEINTERLACING_BOTTOM_FIELD_FIRST.

https://bugs.freedesktop.org/show_bug.cgi?id=72518
https://bugs.freedesktop.org/show_bug.cgi?id=72522

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 76ecc6b..e06d8fe 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -131,7 +131,7 @@ void hsw_veb_dndi_table(VADriverContextP ctx, struct intel_vebox_context *proc_c
         assert(di_param);
 
         progressive_dn = 0;
-        dndi_top_first = !(di_param->flags & VA_DEINTERLACING_BOTTOM_FIELD);
+        dndi_top_first = !(di_param->flags & VA_DEINTERLACING_BOTTOM_FIELD_FIRST);
         motion_compensated_enable = (di_param->algorithm == VAProcDeinterlacingMotionCompensated);
     }
 

From 88d5a444a29ad84b2734da1a2692170bee3a6320 Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Fri, 8 Aug 2014 10:45:53 +0200
Subject: [PATCH 04/19] vebox: fix order of submitted commands.

For each frame, the Intel HD Graphics hardware specification mandates
that the following commands should be submitted, in-order: VEBOX_STATE,
VEBOX_SURFACE_STATE(input), VEBOX_SURFACE_STATE(output), VEB_DI_IECP.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index e06d8fe..9a60c27 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -1334,11 +1334,10 @@ VAStatus gen75_vebox_process_picture(VADriverContextP ctx,
     } else {
         intel_batchbuffer_start_atomic_veb(proc_ctx->batch, 0x1000);
         intel_batchbuffer_emit_mi_flush(proc_ctx->batch);
-        hsw_veb_surface_state(ctx, proc_ctx, INPUT_SURFACE); 
-        hsw_veb_surface_state(ctx, proc_ctx, OUTPUT_SURFACE); 
         hsw_veb_state_table_setup(ctx, proc_ctx);
-
         hsw_veb_state_command(ctx, proc_ctx);		
+        hsw_veb_surface_state(ctx, proc_ctx, INPUT_SURFACE); 
+        hsw_veb_surface_state(ctx, proc_ctx, OUTPUT_SURFACE); 
         hsw_veb_dndi_iecp_command(ctx, proc_ctx);
         intel_batchbuffer_end_atomic(proc_ctx->batch);
         intel_batchbuffer_flush(proc_ctx->batch);
@@ -1632,11 +1631,10 @@ VAStatus gen8_vebox_process_picture(VADriverContextP ctx,
     } else {
         intel_batchbuffer_start_atomic_veb(proc_ctx->batch, 0x1000);
         intel_batchbuffer_emit_mi_flush(proc_ctx->batch);
-        hsw_veb_surface_state(ctx, proc_ctx, INPUT_SURFACE); 
-        hsw_veb_surface_state(ctx, proc_ctx, OUTPUT_SURFACE); 
         hsw_veb_state_table_setup(ctx, proc_ctx);
-
         bdw_veb_state_command(ctx, proc_ctx);		
+        hsw_veb_surface_state(ctx, proc_ctx, INPUT_SURFACE); 
+        hsw_veb_surface_state(ctx, proc_ctx, OUTPUT_SURFACE); 
         bdw_veb_dndi_iecp_command(ctx, proc_ctx);
         intel_batchbuffer_end_atomic(proc_ctx->batch);
         intel_batchbuffer_flush(proc_ctx->batch);

From 5734683d3e7d7690171760ed2dd5ff10ece7b7ca Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Mon, 11 Aug 2014 16:44:31 +0200
Subject: [PATCH 05/19] vebox: fix invalid conversion and scaling params order.

The arguments to vpp_surface_convert() were mixed up. i.e. both input
and output surfaces were reversed. Changed the vpp_surface_scaling()
arguments order as well to have more consistent helper functions.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 9a60c27..6971077 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -54,9 +54,9 @@ extern VAStatus
 i965_DestroyImage(VADriverContextP ctx, VAImageID image);
 
 
-VAStatus vpp_surface_convert(VADriverContextP ctx,
-                             struct object_surface *src_obj_surf,
-                             struct object_surface *dst_obj_surf)
+VAStatus
+vpp_surface_convert(VADriverContextP ctx, struct object_surface *src_obj_surf,
+    struct object_surface *dst_obj_surf)
 {
     VAStatus va_status = VA_STATUS_SUCCESS;
 
@@ -86,9 +86,9 @@ VAStatus vpp_surface_convert(VADriverContextP ctx,
     return va_status;
 }
 
-VAStatus vpp_surface_scaling(VADriverContextP ctx,
-                             struct object_surface *dst_obj_surf,
-                             struct object_surface *src_obj_surf)
+static VAStatus
+vpp_surface_scaling(VADriverContextP ctx, struct object_surface *src_obj_surf,
+    struct object_surface *dst_obj_surf)
 {
     VAStatus va_status = VA_STATUS_SUCCESS;
     int flags = I965_PP_FLAG_AVS;
@@ -1177,7 +1177,7 @@ int hsw_veb_pre_format_convert(VADriverContextP ctx,
              }
          }
        
-         vpp_surface_convert(ctx, proc_ctx->surface_input_vebox_object, proc_ctx->surface_input_object);
+         vpp_surface_convert(ctx, proc_ctx->surface_input_object, proc_ctx->surface_input_vebox_object);
       }
 
       /* create one temporary NV12 surfaces for conversion*/
@@ -1248,7 +1248,7 @@ int hsw_veb_post_format_convert(VADriverContextP ctx,
 
     if (proc_ctx->format_convert_flags & POST_COPY_CONVERT) {
         /* copy the saved frame in the second call */
-        vpp_surface_convert(ctx,proc_ctx->surface_output_object, obj_surface);
+        vpp_surface_convert(ctx, obj_surface, proc_ctx->surface_output_object);
     } else if(!(proc_ctx->format_convert_flags & POST_FORMAT_CONVERT) &&
        !(proc_ctx->format_convert_flags & POST_SCALING_CONVERT)){
         /* Output surface format is covered by vebox pipeline and 
@@ -1257,14 +1257,14 @@ int hsw_veb_post_format_convert(VADriverContextP ctx,
     } else if ((proc_ctx->format_convert_flags & POST_FORMAT_CONVERT) &&
                !(proc_ctx->format_convert_flags & POST_SCALING_CONVERT)){
        /* convert and copy NV12 to YV12/IMC3/IMC2/RGBA output*/
-        vpp_surface_convert(ctx,proc_ctx->surface_output_object, obj_surface);
+        vpp_surface_convert(ctx, obj_surface, proc_ctx->surface_output_object);
 
     } else if(proc_ctx->format_convert_flags & POST_SCALING_CONVERT) {
        /* scaling, convert and copy NV12 to YV12/IMC3/IMC2/RGBA output*/
         assert(obj_surface->fourcc == VA_FOURCC_NV12);
      
         /* first step :surface scaling */
-        vpp_surface_scaling(ctx,proc_ctx->surface_output_scaled_object, obj_surface);
+        vpp_surface_scaling(ctx, obj_surface, proc_ctx->surface_output_scaled_object);
 
         /* second step: color format convert and copy to output */
         obj_surface = proc_ctx->surface_output_object;
@@ -1276,7 +1276,7 @@ int hsw_veb_post_format_convert(VADriverContextP ctx,
            obj_surface->fourcc ==  VA_FOURCC_IMC1 ||
            obj_surface->fourcc ==  VA_FOURCC_IMC3 ||
            obj_surface->fourcc ==  VA_FOURCC_RGBA) {
-           vpp_surface_convert(ctx, proc_ctx->surface_output_object, proc_ctx->surface_output_scaled_object);
+            vpp_surface_convert(ctx, proc_ctx->surface_output_scaled_object, obj_surface);
        }else {
            assert(0); 
        }

From 9032a6c40c7f5e89f1d3ef5875363af7668b1690 Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Mon, 11 Aug 2014 11:44:12 +0200
Subject: [PATCH 06/19] vebox: clean-up frame store initialization.

Rename FRAME_STORE_SUM to FRAME_STORE_COUNT, use existing macros to
determine the number of elements in the frame store array, avoid
duplicate zero initializations.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 12 ++++--------
 src/gen75_vpp_vebox.h |  4 ++--
 2 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 6971077..05694f2 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -911,7 +911,7 @@ void hsw_veb_resource_prepare(VADriverContextP ctx,
     proc_ctx->fourcc_output = output_fourcc;
    
     /* create pipeline surfaces */
-    for(i = 0; i < FRAME_STORE_SUM; i ++) {
+    for(i = 0; i < ARRAY_ELEMS(proc_ctx->frame_store); i ++) {
         if(proc_ctx->frame_store[i].obj_surface){
             continue; //refer external surface for vebox pipeline
         }
@@ -1377,7 +1377,7 @@ void gen75_vebox_context_destroy(VADriverContextP ctx,
        proc_ctx->surface_output_scaled_object = NULL;
      }
 
-    for(i = 0; i < FRAME_STORE_SUM; i ++) {
+    for(i = 0; i < ARRAY_ELEMS(proc_ctx->frame_store); i ++) {
         if (proc_ctx->frame_store[i].is_internal_surface == 1) {
             assert(proc_ctx->frame_store[i].surface_id != VA_INVALID_ID);
 
@@ -1418,13 +1418,9 @@ struct intel_vebox_context * gen75_vebox_context_init(VADriverContextP ctx)
     int i;
 
     proc_context->batch = intel_batchbuffer_new(intel, I915_EXEC_VEBOX, 0);
-    memset(proc_context->frame_store, 0, sizeof(VEBFrameStore)*FRAME_STORE_SUM);
 
-    for (i = 0; i < FRAME_STORE_SUM; i ++) {
+    for (i = 0; i < ARRAY_ELEMS(proc_context->frame_store); i++)
         proc_context->frame_store[i].surface_id = VA_INVALID_ID;
-        proc_context->frame_store[i].is_internal_surface = 0;
-        proc_context->frame_store[i].obj_surface = NULL;
-    }
   
     proc_context->filters_mask          = 0;
     proc_context->frame_order           = -1; /* the first frame */
@@ -1469,7 +1465,7 @@ void bdw_veb_state_command(VADriverContextP ctx, struct intel_vebox_context *pro
 
         if ((di_param->algorithm == VAProcDeinterlacingMotionAdaptive ||
             di_param->algorithm == VAProcDeinterlacingMotionCompensated) &&
-            proc_ctx->frame_order != -1)
+            (1||proc_ctx->frame_order != -1))
             di_output_frames_flag = 0; /* Output both Current Frame and Previous Frame */
     }
 
diff --git a/src/gen75_vpp_vebox.h b/src/gen75_vpp_vebox.h
index a0842b0..4c763e4 100644
--- a/src/gen75_vpp_vebox.h
+++ b/src/gen75_vpp_vebox.h
@@ -67,7 +67,7 @@ enum {
     FRAME_OUT_CURRENT,
     FRAME_OUT_PREVIOUS,
     FRAME_OUT_STATISTIC,
-    FRAME_STORE_SUM,
+    FRAME_STORE_COUNT,
 };
 
 enum SURFACE_FORMAT{
@@ -121,7 +121,7 @@ struct intel_vebox_context
     int width_output;
     int height_output;
 
-    VEBFrameStore frame_store[FRAME_STORE_SUM];
+    VEBFrameStore frame_store[FRAME_STORE_COUNT];
 
     VEBBuffer dndi_state_table;
     VEBBuffer iecp_state_table;

From 946800d78798a5f92131a22539e6830d7d3da476 Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Mon, 11 Aug 2014 13:52:31 +0200
Subject: [PATCH 07/19] vebox: factor out initialization of pipeline
 parameters.

Factor out initialization and validation of pipeline parameters.
In particular, introduce a new gen75_vebox_init_pipe_params() helper
function that initializes the filters mask and ensures the supplied
filters are going to be supported.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 127 ++++++++++++++++++++++----------------------------
 1 file changed, 57 insertions(+), 70 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 05694f2..819860d 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -1285,41 +1285,60 @@ int hsw_veb_post_format_convert(VADriverContextP ctx,
     return 0;
 }
 
-VAStatus gen75_vebox_process_picture(VADriverContextP ctx,
-                         struct intel_vebox_context *proc_ctx)
+static VAStatus
+gen75_vebox_init_pipe_params(VADriverContextP ctx,
+    struct intel_vebox_context *proc_ctx)
 {
-    struct i965_driver_data *i965 = i965_driver_data(ctx);
- 
-    VAProcPipelineParameterBuffer *pipe = proc_ctx->pipeline_param;
-    VAProcFilterParameterBuffer* filter = NULL;
-    struct object_buffer *obj_buf = NULL;
+    struct i965_driver_data * const i965 = i965_driver_data(ctx);
+    const VAProcPipelineParameterBuffer * const pipe = proc_ctx->pipeline_param;
+    VAProcFilterParameterBuffer *filter;
     unsigned int i;
 
-    for (i = 0; i < pipe->num_filters; i ++) {
-         obj_buf = BUFFER(pipe->filters[i]);
-         
-         assert(obj_buf && obj_buf->buffer_store);
-
-         if (!obj_buf || !obj_buf->buffer_store)
-             goto error;
-
-         filter = (VAProcFilterParameterBuffer*)obj_buf-> buffer_store->buffer;
-            
-         if (filter->type == VAProcFilterNoiseReduction) {
-             proc_ctx->filters_mask |= VPP_DNDI_DN;
-             proc_ctx->filter_dn = filter;
-         } else if (filter->type == VAProcFilterDeinterlacing) {
-             proc_ctx->filters_mask |= VPP_DNDI_DI;
-             proc_ctx->filter_di = filter;
-         } else if (filter->type == VAProcFilterColorBalance) {
-             proc_ctx->filters_mask |= VPP_IECP_PRO_AMP;
-             proc_ctx->filter_iecp_amp = filter;
-             proc_ctx->filter_iecp_amp_num_elements = obj_buf->num_elements;
-         } else if (filter->type == VAProcFilterSkinToneEnhancement) {
-             proc_ctx->filters_mask |= VPP_IECP_STD_STE;
-             proc_ctx->filter_iecp_std = filter;
-         }
+    proc_ctx->filters_mask = 0;
+    for (i = 0; i < pipe->num_filters; i++) {
+        struct object_buffer * const obj_buffer = BUFFER(pipe->filters[i]);
+
+        assert(obj_buffer && obj_buffer->buffer_store);
+        if (!obj_buffer || !obj_buffer->buffer_store)
+            return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+        filter = (VAProcFilterParameterBuffer *)
+            obj_buffer->buffer_store->buffer;
+        switch (filter->type) {
+        case VAProcFilterNoiseReduction:
+            proc_ctx->filters_mask |= VPP_DNDI_DN;
+            proc_ctx->filter_dn = filter;
+            break;
+        case VAProcFilterDeinterlacing:
+            proc_ctx->filters_mask |= VPP_DNDI_DI;
+            proc_ctx->filter_di = filter;
+            break;
+        case VAProcFilterColorBalance:
+            proc_ctx->filters_mask |= VPP_IECP_PRO_AMP;
+            proc_ctx->filter_iecp_amp = filter;
+            proc_ctx->filter_iecp_amp_num_elements = obj_buffer->num_elements;
+            break;
+        case VAProcFilterSkinToneEnhancement:
+            proc_ctx->filters_mask |= VPP_IECP_STD_STE;
+            proc_ctx->filter_iecp_std = filter;
+            break;
+        default:
+            WARN_ONCE("unsupported filter (type: %d)\n", filter->type);
+            return VA_STATUS_ERROR_UNSUPPORTED_FILTER;
+        }
     }
+    return VA_STATUS_SUCCESS;
+}
+
+VAStatus
+gen75_vebox_process_picture(VADriverContextP ctx,
+    struct intel_vebox_context *proc_ctx)
+{
+    VAStatus status;
+
+    status = gen75_vebox_init_pipe_params(ctx, proc_ctx);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
 
     hsw_veb_pre_format_convert(ctx, proc_ctx);
     hsw_veb_surface_reference(ctx, proc_ctx);
@@ -1349,9 +1368,6 @@ VAStatus gen75_vebox_process_picture(VADriverContextP ctx,
     proc_ctx->frame_order = (proc_ctx->frame_order + 1) % 2;
      
     return VA_STATUS_SUCCESS;
-
-error:
-    return VA_STATUS_ERROR_INVALID_PARAMETER;
 }
 
 void gen75_vebox_context_destroy(VADriverContextP ctx, 
@@ -1578,41 +1594,15 @@ void bdw_veb_dndi_iecp_command(VADriverContextP ctx, struct intel_vebox_context
     ADVANCE_VEB_BATCH(batch);
 }
 
-VAStatus gen8_vebox_process_picture(VADriverContextP ctx,
-                         struct intel_vebox_context *proc_ctx)
+VAStatus
+gen8_vebox_process_picture(VADriverContextP ctx,
+    struct intel_vebox_context *proc_ctx)
 {
-    struct i965_driver_data *i965 = i965_driver_data(ctx);
- 
-    VAProcPipelineParameterBuffer *pipe = proc_ctx->pipeline_param;
-    VAProcFilterParameterBuffer* filter = NULL;
-    struct object_buffer *obj_buf = NULL;
-    unsigned int i;
+    VAStatus status;
 
-    for (i = 0; i < pipe->num_filters; i ++) {
-         obj_buf = BUFFER(pipe->filters[i]);
-         
-         assert(obj_buf && obj_buf->buffer_store);
-
-         if (!obj_buf || !obj_buf->buffer_store)
-             goto error;
-
-         filter = (VAProcFilterParameterBuffer*)obj_buf-> buffer_store->buffer;
-            
-         if (filter->type == VAProcFilterNoiseReduction) {
-             proc_ctx->filters_mask |= VPP_DNDI_DN;
-             proc_ctx->filter_dn = filter;
-         } else if (filter->type == VAProcFilterDeinterlacing) {
-             proc_ctx->filters_mask |= VPP_DNDI_DI;
-             proc_ctx->filter_di = filter;
-         } else if (filter->type == VAProcFilterColorBalance) {
-             proc_ctx->filters_mask |= VPP_IECP_PRO_AMP;
-             proc_ctx->filter_iecp_amp = filter;
-             proc_ctx->filter_iecp_amp_num_elements = obj_buf->num_elements;
-         } else if (filter->type == VAProcFilterSkinToneEnhancement) {
-             proc_ctx->filters_mask |= VPP_IECP_STD_STE;
-             proc_ctx->filter_iecp_std = filter;
-         }
-    }
+    status = gen75_vebox_init_pipe_params(ctx, proc_ctx);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
 
     hsw_veb_pre_format_convert(ctx, proc_ctx);
     hsw_veb_surface_reference(ctx, proc_ctx);
@@ -1642,8 +1632,5 @@ VAStatus gen8_vebox_process_picture(VADriverContextP ctx,
     proc_ctx->frame_order = (proc_ctx->frame_order + 1) % 2;
      
     return VA_STATUS_SUCCESS;
-
-error:
-    return VA_STATUS_ERROR_INVALID_PARAMETER;
 }
 

From 0ec9fa6158c3f52288c43ad030caeca684038657 Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Mon, 11 Aug 2014 14:37:41 +0200
Subject: [PATCH 08/19] vebox: robustify frame store surface storage
 allocations.

Clean-up frame store surface storage allocation, rename the helper
function to gen75_vebox_ensure_surfaces_storage() and make it more
robust to allocation errors. i.e. propagate them up right away.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 206 ++++++++++++++++++++++++++++----------------------
 1 file changed, 115 insertions(+), 91 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 819860d..264c4fc 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -858,123 +858,143 @@ void hsw_veb_dndi_iecp_command(VADriverContextP ctx, struct intel_vebox_context
     ADVANCE_VEB_BATCH(batch);
 }
 
-void hsw_veb_resource_prepare(VADriverContextP ctx,
-                              struct intel_vebox_context *proc_ctx)
+static VAStatus
+gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
+    struct intel_vebox_context *proc_ctx)
 {
-    VAStatus va_status;
-    dri_bo *bo;
-    struct i965_driver_data *i965 = i965_driver_data(ctx);
+    struct i965_driver_data * const i965 = i965_driver_data(ctx);
+    struct object_surface *input_obj_surface, *output_obj_surface;
     unsigned int input_fourcc, output_fourcc;
     unsigned int input_sampling, output_sampling;
     unsigned int input_tiling, output_tiling;
     unsigned int i, swizzle;
-    struct object_surface *obj_surf_out = NULL, *obj_surf_in = NULL;
-
-    if (proc_ctx->surface_input_vebox_object != NULL) {
-        obj_surf_in = proc_ctx->surface_input_vebox_object;
-    } else {
-        obj_surf_in = proc_ctx->surface_input_object;
-    } 
-
-    if (proc_ctx->surface_output_vebox_object != NULL) {
-        obj_surf_out = proc_ctx->surface_output_vebox_object;
-    } else {
-        obj_surf_out = proc_ctx->surface_output_object;
-    } 
+    drm_intel_bo *bo;
+    VAStatus status;
 
-    if(obj_surf_in->bo == NULL){
-          input_fourcc = VA_FOURCC_NV12;
-          input_sampling = SUBSAMPLE_YUV420;
-          input_tiling = 0;
-          i965_check_alloc_surface_bo(ctx, obj_surf_in, input_tiling, input_fourcc, input_sampling);
-    } else {
-        input_fourcc = obj_surf_in->fourcc;
-        input_sampling = obj_surf_in->subsampling;
-        dri_bo_get_tiling(obj_surf_in->bo, &input_tiling, &swizzle);
+    /* Determine input surface info. Use native VEBOX format whenever
+       possible. i.e. when the input surface format is not supported
+       by the VEBOX engine, then allocate a temporary surface (live
+       during the whole VPP pipeline lifetime)
+
+       XXX: derive an actual surface format compatible with the input
+       surface chroma format */
+    input_obj_surface = proc_ctx->surface_input_vebox_object ?
+        proc_ctx->surface_input_vebox_object : proc_ctx->surface_input_object;
+    if (input_obj_surface->bo) {
+        input_fourcc = input_obj_surface->fourcc;
+        input_sampling = input_obj_surface->subsampling;
+        dri_bo_get_tiling(input_obj_surface->bo, &input_tiling, &swizzle);
         input_tiling = !!input_tiling;
     }
+    else {
+        input_fourcc = VA_FOURCC_NV12;
+        input_sampling = SUBSAMPLE_YUV420;
+        input_tiling = 0;
+        status = i965_check_alloc_surface_bo(ctx, input_obj_surface,
+            input_tiling, input_fourcc, input_sampling);
+        if (status != VA_STATUS_SUCCESS)
+            return status;
+    }
 
-    if(obj_surf_out->bo == NULL){
-          output_fourcc = VA_FOURCC_NV12;
-          output_sampling = SUBSAMPLE_YUV420;
-          output_tiling = 0;
-          i965_check_alloc_surface_bo(ctx, obj_surf_out, output_tiling, output_fourcc, output_sampling);
-    }else {
-        output_fourcc   = obj_surf_out->fourcc;
-        output_sampling = obj_surf_out->subsampling;
-        dri_bo_get_tiling(obj_surf_out->bo, &output_tiling, &swizzle);
+    /* Determine output surface info.
+
+       XXX: derive an actual surface format compatible with the input
+       surface chroma format */
+    output_obj_surface = proc_ctx->surface_output_vebox_object ?
+        proc_ctx->surface_output_vebox_object : proc_ctx->surface_output_object;
+    if (output_obj_surface->bo) {
+        output_fourcc   = output_obj_surface->fourcc;
+        output_sampling = output_obj_surface->subsampling;
+        dri_bo_get_tiling(output_obj_surface->bo, &output_tiling, &swizzle);
         output_tiling = !!output_tiling;
     }
+    else {
+        output_fourcc = VA_FOURCC_NV12;
+        output_sampling = SUBSAMPLE_YUV420;
+        output_tiling = 0;
+        status = i965_check_alloc_surface_bo(ctx, output_obj_surface,
+            output_tiling, output_fourcc, output_sampling);
+        if (status != VA_STATUS_SUCCESS)
+            return status;
+    }
 
-    /* vebox pipelien input surface format info */
+    /* Update VEBOX pipeline formats */
     proc_ctx->fourcc_input = input_fourcc;
     proc_ctx->fourcc_output = output_fourcc;
    
-    /* create pipeline surfaces */
-    for(i = 0; i < ARRAY_ELEMS(proc_ctx->frame_store); i ++) {
-        if(proc_ctx->frame_store[i].obj_surface){
-            continue; //refer external surface for vebox pipeline
-        }
-    
+    /* Create pipeline surfaces */
+    for (i = 0; i < ARRAY_ELEMS(proc_ctx->frame_store); i ++) {
+        struct object_surface *obj_surface;
         VASurfaceID new_surface;
-        struct object_surface *obj_surf = NULL;
-
-        va_status =   i965_CreateSurfaces(ctx,
-                                          proc_ctx ->width_input,
-                                          proc_ctx ->height_input,
-                                          VA_RT_FORMAT_YUV420,
-                                          1,
-                                          &new_surface);
-        assert(va_status == VA_STATUS_SUCCESS);
-
-        obj_surf = SURFACE(new_surface);
-        assert(obj_surf);
-
-        if( i <= FRAME_IN_PREVIOUS || i == FRAME_OUT_CURRENT_DN) {
-            i965_check_alloc_surface_bo(ctx, obj_surf, input_tiling, input_fourcc, input_sampling);
-        } else if( i == FRAME_IN_STMM || i == FRAME_OUT_STMM){
-            i965_check_alloc_surface_bo(ctx, obj_surf, 1, input_fourcc, input_sampling);
-        } else if( i >= FRAME_OUT_CURRENT){
-            i965_check_alloc_surface_bo(ctx, obj_surf, output_tiling, output_fourcc, output_sampling);
+
+        if (proc_ctx->frame_store[i].obj_surface)
+            continue; // user allocated surface, not VEBOX internal
+
+        status = i965_CreateSurfaces(ctx, proc_ctx->width_input,
+            proc_ctx->height_input, 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 <= FRAME_IN_PREVIOUS || i == FRAME_OUT_CURRENT_DN) {
+            status = i965_check_alloc_surface_bo(ctx, obj_surface,
+                input_tiling, input_fourcc, input_sampling);
+        }
+        else if (i == FRAME_IN_STMM || i == FRAME_OUT_STMM) {
+            status = i965_check_alloc_surface_bo(ctx, obj_surface,
+                1, input_fourcc, input_sampling);
         }
+        else if (i >= FRAME_OUT_CURRENT) {
+            status = i965_check_alloc_surface_bo(ctx, obj_surface,
+                output_tiling, output_fourcc, output_sampling);
+        }
+        if (status != VA_STATUS_SUCCESS)
+            return status;
 
         proc_ctx->frame_store[i].surface_id = new_surface;
         proc_ctx->frame_store[i].is_internal_surface = 1;
-        proc_ctx->frame_store[i].obj_surface = obj_surf;
+        proc_ctx->frame_store[i].obj_surface = obj_surface;
     }
 
-    /* alloc dndi state table  */
-    dri_bo_unreference(proc_ctx->dndi_state_table.bo);
-    bo = dri_bo_alloc(i965->intel.bufmgr,
-                      "vebox: dndi state Buffer",
-                      0x1000, 0x1000);
+    /* Allocate DNDI state table  */
+    drm_intel_bo_unreference(proc_ctx->dndi_state_table.bo);
+    bo = drm_intel_bo_alloc(i965->intel.bufmgr, "vebox: dndi state Buffer",
+        0x1000, 0x1000);
     proc_ctx->dndi_state_table.bo = bo;
-    dri_bo_reference(proc_ctx->dndi_state_table.bo);
+    if (!bo)
+        return VA_STATUS_ERROR_ALLOCATION_FAILED;
+    drm_intel_bo_reference(proc_ctx->dndi_state_table.bo);
  
-    /* alloc iecp state table  */
-    dri_bo_unreference(proc_ctx->iecp_state_table.bo);
-    bo = dri_bo_alloc(i965->intel.bufmgr,
-                      "vebox: iecp state Buffer",
-                      0x1000, 0x1000);
+    /* Allocate IECP state table  */
+    drm_intel_bo_unreference(proc_ctx->iecp_state_table.bo);
+    bo = drm_intel_bo_alloc(i965->intel.bufmgr, "vebox: iecp state Buffer",
+        0x1000, 0x1000);
     proc_ctx->iecp_state_table.bo = bo;
-    dri_bo_reference(proc_ctx->iecp_state_table.bo);
-
-    /* alloc gamut state table  */
-    dri_bo_unreference(proc_ctx->gamut_state_table.bo);
-    bo = dri_bo_alloc(i965->intel.bufmgr,
-                      "vebox: gamut state Buffer",
-                      0x1000, 0x1000);
+    if (!bo)
+        return VA_STATUS_ERROR_ALLOCATION_FAILED;
+    drm_intel_bo_reference(proc_ctx->iecp_state_table.bo);
+
+    /* Allocate Gamut state table  */
+    drm_intel_bo_unreference(proc_ctx->gamut_state_table.bo);
+    bo = drm_intel_bo_alloc(i965->intel.bufmgr, "vebox: gamut state Buffer",
+        0x1000, 0x1000);
     proc_ctx->gamut_state_table.bo = bo;
-    dri_bo_reference(proc_ctx->gamut_state_table.bo);
-
-    /* alloc vertex state table  */
-    dri_bo_unreference(proc_ctx->vertex_state_table.bo);
-    bo = dri_bo_alloc(i965->intel.bufmgr,
-                      "vertex: iecp state Buffer",
-                      0x1000, 0x1000);
+    if (!bo)
+        return VA_STATUS_ERROR_ALLOCATION_FAILED;
+    drm_intel_bo_reference(proc_ctx->gamut_state_table.bo);
+
+    /* Allocate vertex state table  */
+    drm_intel_bo_unreference(proc_ctx->vertex_state_table.bo);
+    bo = drm_intel_bo_alloc(i965->intel.bufmgr, "vebox: vertex state Buffer",
+        0x1000, 0x1000);
     proc_ctx->vertex_state_table.bo = bo;
-    dri_bo_reference(proc_ctx->vertex_state_table.bo);
+    if (!bo)
+        return VA_STATUS_ERROR_ALLOCATION_FAILED;
+    drm_intel_bo_reference(proc_ctx->vertex_state_table.bo);
 
+    return VA_STATUS_SUCCESS;
 }
 
 static VAStatus
@@ -1344,7 +1364,9 @@ gen75_vebox_process_picture(VADriverContextP ctx,
     hsw_veb_surface_reference(ctx, proc_ctx);
 
     if (proc_ctx->frame_order == -1) {
-        hsw_veb_resource_prepare(ctx, proc_ctx);
+        status = gen75_vebox_ensure_surfaces_storage(ctx, proc_ctx);
+        if (status != VA_STATUS_SUCCESS)
+            return status;
     }
 
     if (proc_ctx->format_convert_flags & POST_COPY_CONVERT) {
@@ -1608,7 +1630,9 @@ gen8_vebox_process_picture(VADriverContextP ctx,
     hsw_veb_surface_reference(ctx, proc_ctx);
 
     if (proc_ctx->frame_order == -1) {
-        hsw_veb_resource_prepare(ctx, proc_ctx);
+        status = gen75_vebox_ensure_surfaces_storage(ctx, proc_ctx);
+        if (status != VA_STATUS_SUCCESS)
+            return status;
     }
 
     if (proc_ctx->format_convert_flags & POST_COPY_CONVERT) {

From 9c6262410ffa972d8871a023c63e38d307ea37f9 Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Mon, 11 Aug 2014 13:55:37 +0200
Subject: [PATCH 09/19] vebox: factor out deinterlacing code.

Completely rework the VEBOX code to factor out and improve the various
deinterlacing algorithms in particular. Introduce temporary variables
that are going to be live for the current VPP processing call.

Drop MADI/MCDI support for now.

Initial focus was to definitively fix first vs. second field detection
code, thus allowing more multiple VEBOX calls with an additional format
conversion away.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 380 ++++++++++++++++++++------------------------------
 src/gen75_vpp_vebox.h |  13 +-
 2 files changed, 165 insertions(+), 228 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 264c4fc..b060ae2 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -53,7 +53,6 @@ i965_DeriveImage(VADriverContextP ctx, VABufferID surface, VAImage *out_image);
 extern VAStatus
 i965_DestroyImage(VADriverContextP ctx, VAImageID image);
 
-
 VAStatus
 vpp_surface_convert(VADriverContextP ctx, struct object_surface *src_obj_surf,
     struct object_surface *dst_obj_surf)
@@ -121,18 +120,24 @@ void hsw_veb_dndi_table(VADriverContextP ctx, struct intel_vebox_context *proc_c
 {
     struct i965_driver_data *i965 = i965_driver_data(ctx);
     unsigned int* p_table ;
-    int progressive_dn = 1;
-    int dndi_top_first = 0;
-    int motion_compensated_enable = 0;
+    unsigned int progressive_dn = 1;
+    unsigned int dndi_top_first = 0;
+    unsigned int is_mcdi_enabled = 0;
 
-    if (proc_ctx->filters_mask & VPP_DNDI_DI) {
-        VAProcFilterParameterBufferDeinterlacing *di_param =
-            (VAProcFilterParameterBufferDeinterlacing *)proc_ctx->filter_di;
-        assert(di_param);
+    if (proc_ctx->is_di_enabled) {
+        const VAProcFilterParameterBufferDeinterlacing * const deint_params =
+            proc_ctx->filter_di;
 
         progressive_dn = 0;
-        dndi_top_first = !(di_param->flags & VA_DEINTERLACING_BOTTOM_FIELD_FIRST);
-        motion_compensated_enable = (di_param->algorithm == VAProcDeinterlacingMotionCompensated);
+
+        /* 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 & (proc_ctx->is_first_frame ?
+                VA_DEINTERLACING_BOTTOM_FIELD :
+                VA_DEINTERLACING_BOTTOM_FIELD_FIRST));
+
+        is_mcdi_enabled =
+            (deint_params->algorithm == VAProcDeinterlacingMotionCompensated);
     }
 
     /*
@@ -193,7 +198,7 @@ void hsw_veb_dndi_table(VADriverContextP ctx, struct intel_vebox_context *proc_c
                     100<< 16  |  // FMD #2 vertical difference th
                     0  << 14  |  // CAT th1
                     2  << 8   |  // FMD tear threshold
-                    motion_compensated_enable  << 7   |  // MCDI Enable, use motion compensated deinterlace algorithm
+                    is_mcdi_enabled  << 7  |  // MCDI Enable, use motion compensated deinterlace algorithm
                     progressive_dn  << 6   |  // progressive DN
                     0  << 4   |  // reserved
                     dndi_top_first  << 3   |  // DN/DI Top First
@@ -655,33 +660,6 @@ void hsw_veb_state_table_setup(VADriverContextP ctx, struct intel_vebox_context
 void hsw_veb_state_command(VADriverContextP ctx, struct intel_vebox_context *proc_ctx)
 {
     struct intel_batchbuffer *batch = proc_ctx->batch;
-    unsigned int is_dn_enabled   = !!(proc_ctx->filters_mask & VPP_DNDI_DN);
-    unsigned int is_di_enabled   = !!(proc_ctx->filters_mask & VPP_DNDI_DI);
-    unsigned int is_iecp_enabled = !!(proc_ctx->filters_mask & VPP_IECP_MASK);
-    unsigned int is_first_frame  = !!((proc_ctx->frame_order == -1) &&
-                                      (is_di_enabled ||
-                                       is_dn_enabled));
-    unsigned int di_output_frames_flag = 2; /* Output Current Frame Only */
-
-    if(proc_ctx->fourcc_input != proc_ctx->fourcc_output ||
-       (is_dn_enabled == 0 && is_di_enabled == 0)){
-       is_iecp_enabled = 1;
-    }
-
-    if (is_di_enabled) {
-        VAProcFilterParameterBufferDeinterlacing *di_param =
-            (VAProcFilterParameterBufferDeinterlacing *)proc_ctx->filter_di;
-
-        assert(di_param);
-        
-        if (di_param->algorithm == VAProcDeinterlacingBob)
-            is_first_frame = 1;
-
-        if ((di_param->algorithm == VAProcDeinterlacingMotionAdaptive ||
-            di_param->algorithm == VAProcDeinterlacingMotionCompensated) &&
-            proc_ctx->frame_order != -1)
-            di_output_frames_flag = 0; /* Output both Current Frame and Previous Frame */
-    }
 
     BEGIN_VEB_BATCH(batch, 6);
     OUT_VEB_BATCH(batch, VEB_STATE | (6 - 2));
@@ -689,13 +667,13 @@ void hsw_veb_state_command(VADriverContextP ctx, struct intel_vebox_context *pro
                   0 << 26 |       // state surface control bits
                   0 << 11 |       // reserved.
                   0 << 10 |       // pipe sync disable
-                  di_output_frames_flag << 8  |       // DI output frame
+                  proc_ctx->current_output_type << 8  | // DI output frame
                   1 << 7  |       // 444->422 downsample method
                   1 << 6  |       // 422->420 downsample method
-                  is_first_frame  << 5  |   // DN/DI first frame
-                  is_di_enabled   << 4  |             // DI enable
-                  is_dn_enabled   << 3  |             // DN enable
-                  is_iecp_enabled << 2  |             // global IECP enabled
+                  proc_ctx->is_first_frame  << 5  |   // DN/DI first frame
+                  proc_ctx->is_di_enabled   << 4  |   // DI enable
+                  proc_ctx->is_dn_enabled   << 3  |   // DN enable
+                  proc_ctx->is_iecp_enabled << 2  |   // global IECP enabled
                   0 << 1  |       // ColorGamutCompressionEnable
                   0 ) ;           // ColorGamutExpansionEnable.
 
@@ -921,6 +899,8 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
     /* Update VEBOX pipeline formats */
     proc_ctx->fourcc_input = input_fourcc;
     proc_ctx->fourcc_output = output_fourcc;
+    if (input_fourcc != output_fourcc)
+        proc_ctx->is_iecp_enabled = 1; // IECP needed for format conversion
    
     /* Create pipeline surfaces */
     for (i = 0; i < ARRAY_ELEMS(proc_ctx->frame_store); i ++) {
@@ -953,9 +933,8 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
         if (status != VA_STATUS_SUCCESS)
             return status;
 
-        proc_ctx->frame_store[i].surface_id = new_surface;
-        proc_ctx->frame_store[i].is_internal_surface = 1;
         proc_ctx->frame_store[i].obj_surface = obj_surface;
+        proc_ctx->frame_store[i].is_internal_surface = 1;
     }
 
     /* Allocate DNDI state table  */
@@ -998,139 +977,62 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
 }
 
 static VAStatus
-hsw_veb_surface_reference(VADriverContextP ctx,
-                          struct intel_vebox_context *proc_ctx)
+gen75_vebox_ensure_surfaces(VADriverContextP ctx,
+    struct intel_vebox_context *proc_ctx)
 {
-    struct object_surface * obj_surf; 
-    VEBFrameStore tmp_store;
+    struct object_surface *obj_surface;
+    VEBFrameStore *ifs, *ofs;
+    bool is_new_frame = 0;
+    int i;
 
-    if (proc_ctx->surface_input_vebox_object != NULL) {
-        obj_surf = proc_ctx->surface_input_vebox_object;
-    } else {
-        obj_surf = proc_ctx->surface_input_object;
-    } 
-
-    /* update the input surface */ 
-    proc_ctx->frame_store[FRAME_IN_CURRENT].surface_id = VA_INVALID_ID;
-    proc_ctx->frame_store[FRAME_IN_CURRENT].is_internal_surface = 0;
-    proc_ctx->frame_store[FRAME_IN_CURRENT].obj_surface = obj_surf;
-
-    /* update the previous input surface */
-    if (proc_ctx->frame_order != -1) {
-        if (proc_ctx->filters_mask == VPP_DNDI_DN) {
-            proc_ctx->frame_store[FRAME_IN_PREVIOUS] = proc_ctx->frame_store[FRAME_OUT_CURRENT_DN];
-        } else if (proc_ctx->filters_mask & VPP_DNDI_DI) {
-            VAProcFilterParameterBufferDeinterlacing *di_param =
-                (VAProcFilterParameterBufferDeinterlacing *)proc_ctx->filter_di;
-
-            if (di_param && 
-                (di_param->algorithm == VAProcDeinterlacingMotionAdaptive ||
-                di_param->algorithm == VAProcDeinterlacingMotionCompensated)) {
-                if ((proc_ctx->filters_mask & VPP_DNDI_DN) &&
-                    proc_ctx->frame_order == 0) { /* DNDI */
-                    tmp_store = proc_ctx->frame_store[FRAME_OUT_CURRENT_DN];
-                    proc_ctx->frame_store[FRAME_OUT_CURRENT_DN] = proc_ctx->frame_store[FRAME_IN_PREVIOUS];
-                    proc_ctx->frame_store[FRAME_IN_PREVIOUS] = tmp_store;
-                } else { /* DI only */
-                    VAProcPipelineParameterBuffer *pipe = proc_ctx->pipeline_param;
-                    struct object_surface *obj_surf = NULL;
-                    struct i965_driver_data * const i965 = i965_driver_data(ctx);
-
-                    if (!pipe ||
-                        !pipe->num_forward_references ||
-                        pipe->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;
-                    }
-
-                    obj_surf = SURFACE(pipe->forward_references[0]);
-                    assert(obj_surf && obj_surf->bo);
-                
-                    proc_ctx->frame_store[FRAME_IN_PREVIOUS].surface_id = pipe->forward_references[0];
-                    proc_ctx->frame_store[FRAME_IN_PREVIOUS].is_internal_surface = 0;
-                    proc_ctx->frame_store[FRAME_IN_PREVIOUS].obj_surface = obj_surf;
-                }
-            }
-        }
+    /* Update the previous input surface */
+    obj_surface = proc_ctx->surface_input_object;
+
+    is_new_frame = proc_ctx->frame_store[FRAME_IN_CURRENT].surface_id !=
+        obj_surface->base.id;
+
+    /* Update the input surface */
+    obj_surface = proc_ctx->surface_input_vebox_object ?
+        proc_ctx->surface_input_vebox_object : proc_ctx->surface_input_object;
+
+    ifs = &proc_ctx->frame_store[FRAME_IN_CURRENT];
+    ifs->obj_surface = obj_surface;
+    ifs->surface_id = proc_ctx->surface_input_object->base.id;
+    ifs->is_internal_surface = proc_ctx->surface_input_vebox_object != NULL;
+
+    /* Update the Spatial Temporal Motion Measure (STMM) surfaces */
+    if (is_new_frame) {
+        const VEBFrameStore tmpfs = proc_ctx->frame_store[FRAME_IN_STMM];
+        proc_ctx->frame_store[FRAME_IN_STMM] =
+            proc_ctx->frame_store[FRAME_OUT_STMM];
+        proc_ctx->frame_store[FRAME_OUT_STMM] = tmpfs;
     }
 
-    /* update STMM surface */
-    if (proc_ctx->frame_order != -1) {
-        tmp_store = proc_ctx->frame_store[FRAME_IN_STMM];
-        proc_ctx->frame_store[FRAME_IN_STMM] = proc_ctx->frame_store[FRAME_OUT_STMM];
-        proc_ctx->frame_store[FRAME_OUT_STMM] = tmp_store;
+    /* Reset the output surfaces to defaults. i.e. clean from user surfaces */
+    for (i = FRAME_OUT_CURRENT_DN; i <= FRAME_OUT_PREVIOUS; i++) {
+        ofs = &proc_ctx->frame_store[i];
+        if (!ofs->is_internal_surface)
+            ofs->obj_surface = NULL;
+        ofs->surface_id = proc_ctx->surface_input_object->base.id;
     }
 
-    /* update the output surface */ 
-    if (proc_ctx->surface_output_vebox_object != NULL) {
-        obj_surf = proc_ctx->surface_output_vebox_object;
-    } else {
-        obj_surf = proc_ctx->surface_output_object;
-    } 
+    /* Update the output surfaces */
+    obj_surface = proc_ctx->surface_output_vebox_object ?
+        proc_ctx->surface_output_vebox_object : proc_ctx->surface_output_object;
 
-    if (proc_ctx->filters_mask == VPP_DNDI_DN) {
-        proc_ctx->frame_store[FRAME_OUT_CURRENT_DN].surface_id = VA_INVALID_ID;
-        proc_ctx->frame_store[FRAME_OUT_CURRENT_DN].is_internal_surface = 0;
-        proc_ctx->frame_store[FRAME_OUT_CURRENT_DN].obj_surface = obj_surf;
+    proc_ctx->current_output_type = 2;
+    if (proc_ctx->filters_mask == VPP_DNDI_DN)
         proc_ctx->current_output = FRAME_OUT_CURRENT_DN;
-    } else if (proc_ctx->filters_mask & VPP_DNDI_DI) {
-        VAProcFilterParameterBufferDeinterlacing *di_param =
-            (VAProcFilterParameterBufferDeinterlacing *)proc_ctx->filter_di;
-
-        if (di_param && 
-            (di_param->algorithm == VAProcDeinterlacingMotionAdaptive ||
-            di_param->algorithm == VAProcDeinterlacingMotionCompensated)) {
-            if (proc_ctx->frame_order == -1) {
-                proc_ctx->frame_store[FRAME_OUT_CURRENT].surface_id = VA_INVALID_ID;
-                proc_ctx->frame_store[FRAME_OUT_CURRENT].is_internal_surface = 0;
-                proc_ctx->frame_store[FRAME_OUT_CURRENT].obj_surface = obj_surf;
-                proc_ctx->current_output = FRAME_OUT_CURRENT;
-            } else if (proc_ctx->frame_order == 0) {
-                proc_ctx->frame_store[FRAME_OUT_PREVIOUS].surface_id = VA_INVALID_ID;
-                proc_ctx->frame_store[FRAME_OUT_PREVIOUS].is_internal_surface = 0;
-                proc_ctx->frame_store[FRAME_OUT_PREVIOUS].obj_surface = obj_surf;
-                proc_ctx->current_output = FRAME_OUT_PREVIOUS;
-            } else {
-                proc_ctx->current_output = FRAME_OUT_CURRENT;
-                proc_ctx->format_convert_flags |= POST_COPY_CONVERT;
-            }
-        } else {
-            proc_ctx->frame_store[FRAME_OUT_CURRENT].surface_id = VA_INVALID_ID;
-            proc_ctx->frame_store[FRAME_OUT_CURRENT].is_internal_surface = 0;
-            proc_ctx->frame_store[FRAME_OUT_CURRENT].obj_surface = obj_surf;
-            proc_ctx->current_output = FRAME_OUT_CURRENT;
-        }
-    } else {
-        proc_ctx->frame_store[FRAME_OUT_CURRENT].surface_id = VA_INVALID_ID;
-        proc_ctx->frame_store[FRAME_OUT_CURRENT].is_internal_surface = 0;
-        proc_ctx->frame_store[FRAME_OUT_CURRENT].obj_surface = obj_surf;
+    else
         proc_ctx->current_output = FRAME_OUT_CURRENT;
-    }
+    ofs = &proc_ctx->frame_store[proc_ctx->current_output];
+    ofs->obj_surface = obj_surface;
+    ofs->surface_id = proc_ctx->surface_input_object->base.id;
+    ofs->is_internal_surface = proc_ctx->surface_output_vebox_object != NULL;
 
     return VA_STATUS_SUCCESS;
 }
 
-void hsw_veb_surface_unreference(VADriverContextP ctx,
-                                 struct intel_vebox_context *proc_ctx)
-{
-    /* unreference the input surface */ 
-    proc_ctx->frame_store[FRAME_IN_CURRENT].surface_id = VA_INVALID_ID;
-    proc_ctx->frame_store[FRAME_IN_CURRENT].is_internal_surface = 0;
-    proc_ctx->frame_store[FRAME_IN_CURRENT].obj_surface = NULL;
-
-    /* unreference the shared output surface */ 
-    if (proc_ctx->filters_mask == VPP_DNDI_DN) {
-        proc_ctx->frame_store[FRAME_OUT_CURRENT_DN].surface_id = VA_INVALID_ID;
-        proc_ctx->frame_store[FRAME_OUT_CURRENT_DN].is_internal_surface = 0;
-        proc_ctx->frame_store[FRAME_OUT_CURRENT_DN].obj_surface = NULL;
-    } else {
-        proc_ctx->frame_store[FRAME_OUT_CURRENT].surface_id = VA_INVALID_ID;
-        proc_ctx->frame_store[FRAME_OUT_CURRENT].is_internal_surface = 0;
-        proc_ctx->frame_store[FRAME_OUT_CURRENT].obj_surface = NULL;
-    }
-}
-
 int hsw_veb_pre_format_convert(VADriverContextP ctx,
                            struct intel_vebox_context *proc_ctx)
 {
@@ -1350,6 +1252,58 @@ gen75_vebox_init_pipe_params(VADriverContextP ctx,
     return VA_STATUS_SUCCESS;
 }
 
+static VAStatus
+gen75_vebox_init_filter_params(VADriverContextP ctx,
+    struct intel_vebox_context *proc_ctx)
+{
+    proc_ctx->format_convert_flags = 0; /* initialized in hsw_veb_pre_format_convert() */
+
+    proc_ctx->is_iecp_enabled = (proc_ctx->filters_mask & VPP_IECP_MASK) != 0;
+    proc_ctx->is_dn_enabled = (proc_ctx->filters_mask & VPP_DNDI_DN) != 0;
+    proc_ctx->is_di_enabled = (proc_ctx->filters_mask & VPP_DNDI_DI) != 0;
+    proc_ctx->is_first_frame = 0;
+    proc_ctx->is_second_field = 0;
+
+    /* Check whether we are deinterlacing the second field */
+    if (proc_ctx->is_di_enabled) {
+        const VAProcFilterParameterBufferDeinterlacing * const deint_params =
+            proc_ctx->filter_di;
+
+        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) {
+            struct object_surface * const obj_surface =
+                proc_ctx->surface_input_object;
+
+            if (proc_ctx->frame_store[FRAME_IN_CURRENT].surface_id != obj_surface->base.id) {
+                WARN_ONCE("invalid surface provided for second field\n");
+                return VA_STATUS_ERROR_INVALID_PARAMETER;
+            }
+            proc_ctx->is_second_field = 1;
+        }
+    }
+
+    /* Check whether we are deinterlacing the first frame */
+    if (proc_ctx->is_di_enabled) {
+        const VAProcFilterParameterBufferDeinterlacing * const deint_params =
+            proc_ctx->filter_di;
+
+        switch (deint_params->algorithm) {
+        case VAProcDeinterlacingBob:
+            proc_ctx->is_first_frame = 1;
+            break;
+        default:
+            WARN_ONCE("unsupported deinterlacing algorithm (%d)\n",
+                      deint_params->algorithm);
+            return VA_STATUS_ERROR_UNSUPPORTED_FILTER;
+        }
+    }
+    return VA_STATUS_SUCCESS;
+}
+
 VAStatus
 gen75_vebox_process_picture(VADriverContextP ctx,
     struct intel_vebox_context *proc_ctx)
@@ -1360,17 +1314,22 @@ gen75_vebox_process_picture(VADriverContextP ctx,
     if (status != VA_STATUS_SUCCESS)
         return status;
 
+    status = gen75_vebox_init_filter_params(ctx, proc_ctx);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
     hsw_veb_pre_format_convert(ctx, proc_ctx);
-    hsw_veb_surface_reference(ctx, proc_ctx);
 
-    if (proc_ctx->frame_order == -1) {
-        status = gen75_vebox_ensure_surfaces_storage(ctx, proc_ctx);
-        if (status != VA_STATUS_SUCCESS)
-            return status;
-    }
+    status = gen75_vebox_ensure_surfaces(ctx, proc_ctx);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    status = gen75_vebox_ensure_surfaces_storage(ctx, proc_ctx);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
 
     if (proc_ctx->format_convert_flags & POST_COPY_CONVERT) {
-        assert(proc_ctx->frame_order == 1);
+        assert(proc_ctx->is_second_field);
         /* directly copy the saved frame in the second call */
     } else {
         intel_batchbuffer_start_atomic_veb(proc_ctx->batch, 0x1000);
@@ -1385,9 +1344,6 @@ gen75_vebox_process_picture(VADriverContextP ctx,
     }
 
     hsw_veb_post_format_convert(ctx, proc_ctx);
-    // hsw_veb_surface_unreference(ctx, proc_ctx);
-
-    proc_ctx->frame_order = (proc_ctx->frame_order + 1) % 2;
      
     return VA_STATUS_SUCCESS;
 }
@@ -1415,17 +1371,17 @@ void gen75_vebox_context_destroy(VADriverContextP ctx,
        proc_ctx->surface_output_scaled_object = NULL;
      }
 
-    for(i = 0; i < ARRAY_ELEMS(proc_ctx->frame_store); i ++) {
-        if (proc_ctx->frame_store[i].is_internal_surface == 1) {
-            assert(proc_ctx->frame_store[i].surface_id != VA_INVALID_ID);
+    for (i = 0; i < ARRAY_ELEMS(proc_ctx->frame_store); i++) {
+        struct object_surface * const obj_surface =
+            proc_ctx->frame_store[i].obj_surface;
 
-            if (proc_ctx->frame_store[i].surface_id != VA_INVALID_ID)
-                i965_DestroySurfaces(ctx, &proc_ctx->frame_store[i].surface_id, 1);
+        if (proc_ctx->frame_store[i].is_internal_surface && obj_surface) {
+            VASurfaceID surface_id = obj_surface->base.id;
+            i965_DestroySurfaces(ctx, &surface_id, 1);
         }
-
+        proc_ctx->frame_store[i].obj_surface = NULL;
         proc_ctx->frame_store[i].surface_id = VA_INVALID_ID;
         proc_ctx->frame_store[i].is_internal_surface = 0;
-        proc_ctx->frame_store[i].obj_surface = NULL;
     }
 
     /* dndi state table  */
@@ -1461,7 +1417,6 @@ struct intel_vebox_context * gen75_vebox_context_init(VADriverContextP ctx)
         proc_context->frame_store[i].surface_id = VA_INVALID_ID;
   
     proc_context->filters_mask          = 0;
-    proc_context->frame_order           = -1; /* the first frame */
     proc_context->surface_output_object = NULL;
     proc_context->surface_input_object  = NULL;
     proc_context->surface_input_vebox   = VA_INVALID_ID;
@@ -1479,33 +1434,6 @@ struct intel_vebox_context * gen75_vebox_context_init(VADriverContextP ctx)
 void bdw_veb_state_command(VADriverContextP ctx, struct intel_vebox_context *proc_ctx)
 {
     struct intel_batchbuffer *batch = proc_ctx->batch;
-    unsigned int is_dn_enabled   = !!(proc_ctx->filters_mask & VPP_DNDI_DN);
-    unsigned int is_di_enabled   = !!(proc_ctx->filters_mask & VPP_DNDI_DI);
-    unsigned int is_iecp_enabled = !!(proc_ctx->filters_mask & VPP_IECP_MASK);
-    unsigned int is_first_frame  = !!((proc_ctx->frame_order == -1) &&
-                                      (is_di_enabled ||
-                                       is_dn_enabled));
-    unsigned int di_output_frames_flag = 2; /* Output Current Frame Only */
-
-    if(proc_ctx->fourcc_input != proc_ctx->fourcc_output ||
-       (is_dn_enabled == 0 && is_di_enabled == 0)){
-       is_iecp_enabled = 1;
-    }
-
-    if (is_di_enabled) {
-        VAProcFilterParameterBufferDeinterlacing *di_param =
-            (VAProcFilterParameterBufferDeinterlacing *)proc_ctx->filter_di;
-
-        assert(di_param);
-        
-        if (di_param->algorithm == VAProcDeinterlacingBob)
-            is_first_frame = 1;
-
-        if ((di_param->algorithm == VAProcDeinterlacingMotionAdaptive ||
-            di_param->algorithm == VAProcDeinterlacingMotionCompensated) &&
-            (1||proc_ctx->frame_order != -1))
-            di_output_frames_flag = 0; /* Output both Current Frame and Previous Frame */
-    }
 
     BEGIN_VEB_BATCH(batch, 0xc);
     OUT_VEB_BATCH(batch, VEB_STATE | (0xc - 2));
@@ -1519,13 +1447,13 @@ void bdw_veb_state_command(VADriverContextP ctx, struct intel_vebox_context *pro
                   0 << 12 |       // alpha plane enable
                   0 << 11 |       // vignette enable
                   0 << 10 |       // demosaic enable
-                  di_output_frames_flag << 8  |       // DI output frame
+                  proc_ctx->current_output_type << 8  | // DI output frame
                   1 << 7  |       // 444->422 downsample method
                   1 << 6  |       // 422->420 downsample method
-                  is_first_frame  << 5  |   // DN/DI first frame
-                  is_di_enabled   << 4  |             // DI enable
-                  is_dn_enabled   << 3  |             // DN enable
-                  is_iecp_enabled << 2  |             // global IECP enabled
+                  proc_ctx->is_first_frame  << 5  |   // DN/DI first frame
+                  proc_ctx->is_di_enabled   << 4  |   // DI enable
+                  proc_ctx->is_dn_enabled   << 3  |   // DN enable
+                  proc_ctx->is_iecp_enabled << 2  |   // global IECP enabled
                   0 << 1  |       // ColorGamutCompressionEnable
                   0 ) ;           // ColorGamutExpansionEnable.
 
@@ -1626,17 +1554,22 @@ gen8_vebox_process_picture(VADriverContextP ctx,
     if (status != VA_STATUS_SUCCESS)
         return status;
 
+    status = gen75_vebox_init_filter_params(ctx, proc_ctx);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
     hsw_veb_pre_format_convert(ctx, proc_ctx);
-    hsw_veb_surface_reference(ctx, proc_ctx);
 
-    if (proc_ctx->frame_order == -1) {
-        status = gen75_vebox_ensure_surfaces_storage(ctx, proc_ctx);
-        if (status != VA_STATUS_SUCCESS)
-            return status;
-    }
+    status = gen75_vebox_ensure_surfaces(ctx, proc_ctx);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    status = gen75_vebox_ensure_surfaces_storage(ctx, proc_ctx);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
 
     if (proc_ctx->format_convert_flags & POST_COPY_CONVERT) {
-        assert(proc_ctx->frame_order == 1);
+        assert(proc_ctx->is_second_field);
         /* directly copy the saved frame in the second call */
     } else {
         intel_batchbuffer_start_atomic_veb(proc_ctx->batch, 0x1000);
@@ -1651,9 +1584,6 @@ gen8_vebox_process_picture(VADriverContextP ctx,
     }
 
     hsw_veb_post_format_convert(ctx, proc_ctx);
-    // hsw_veb_surface_unreference(ctx, proc_ctx);
-
-    proc_ctx->frame_order = (proc_ctx->frame_order + 1) % 2;
      
     return VA_STATUS_SUCCESS;
 }
diff --git a/src/gen75_vpp_vebox.h b/src/gen75_vpp_vebox.h
index 4c763e4..35c657d 100644
--- a/src/gen75_vpp_vebox.h
+++ b/src/gen75_vpp_vebox.h
@@ -89,9 +89,9 @@ enum SURFACE_FORMAT{
 };
 
 typedef struct veb_frame_store {
-    VASurfaceID surface_id;
-    unsigned int is_internal_surface;
     struct object_surface *obj_surface;
+    VASurfaceID surface_id; /* always relative to the input surface */
+    unsigned int is_internal_surface;
 } VEBFrameStore;
 
 typedef struct veb_buffer {
@@ -129,8 +129,8 @@ struct intel_vebox_context
     VEBBuffer vertex_state_table;
 
     unsigned int  filters_mask;
-    int frame_order;
     int current_output;
+    int current_output_type; /* 0:Both, 1:Previous, 2:Current */
 
     VAProcPipelineParameterBuffer * pipeline_param;
     void * filter_dn;
@@ -142,6 +142,13 @@ struct intel_vebox_context
 
     unsigned int  filter_iecp_amp_num_elements;
     unsigned char format_convert_flags;
+
+    /* Temporary flags live until the current picture is processed */
+    unsigned int is_iecp_enabled        : 1;
+    unsigned int is_dn_enabled          : 1;
+    unsigned int is_di_enabled          : 1;
+    unsigned int is_first_frame         : 1;
+    unsigned int is_second_field        : 1;
 };
 
 VAStatus gen75_vebox_process_picture(VADriverContextP ctx,

From edc45152d301dbe96d6e27632f8392c2d1329ad5 Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Tue, 12 Aug 2014 15:28:40 +0200
Subject: [PATCH 10/19] vebox: add support for advanced deinterlacing.

Reintegrate Motion Adaptive Deinterlacing (MADI) and Motion Compensated
Deinterlacing (MCDI) support. This is totally reworked so that to allow
for bob-deinterlacing if no previous frame was supplied, improve global
robustness, and ensure that the right surface storage are used.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 101 +++++++++++++++++++++++++++++++++++++++++++-------
 src/gen75_vpp_vebox.h |   4 +-
 2 files changed, 91 insertions(+), 14 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index b060ae2..7e37d9c 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -836,6 +836,25 @@ void hsw_veb_dndi_iecp_command(VADriverContextP ctx, struct intel_vebox_context
     ADVANCE_VEB_BATCH(batch);
 }
 
+static void
+frame_store_reset(VEBFrameStore *fs)
+{
+    fs->obj_surface = NULL;
+    fs->surface_id = VA_INVALID_ID;
+    fs->is_internal_surface = 0;
+    fs->is_scratch_surface = 0;
+}
+
+static void
+frame_store_clear(VEBFrameStore *fs, VADriverContextP ctx)
+{
+    if (fs->obj_surface && fs->is_scratch_surface) {
+        VASurfaceID surface_id = fs->obj_surface->base.id;
+        i965_DestroySurfaces(ctx, &surface_id, 1);
+    }
+    frame_store_reset(fs);
+}
+
 static VAStatus
 gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
     struct intel_vebox_context *proc_ctx)
@@ -935,6 +954,7 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
 
         proc_ctx->frame_store[i].obj_surface = obj_surface;
         proc_ctx->frame_store[i].is_internal_surface = 1;
+        proc_ctx->frame_store[i].is_scratch_surface = 1;
     }
 
     /* Allocate DNDI state table  */
@@ -980,6 +1000,7 @@ static VAStatus
 gen75_vebox_ensure_surfaces(VADriverContextP ctx,
     struct intel_vebox_context *proc_ctx)
 {
+    struct i965_driver_data * const i965 = i965_driver_data(ctx);
     struct object_surface *obj_surface;
     VEBFrameStore *ifs, *ofs;
     bool is_new_frame = 0;
@@ -990,15 +1011,47 @@ gen75_vebox_ensure_surfaces(VADriverContextP ctx,
 
     is_new_frame = proc_ctx->frame_store[FRAME_IN_CURRENT].surface_id !=
         obj_surface->base.id;
+    if (is_new_frame) {
+        ifs = &proc_ctx->frame_store[FRAME_IN_PREVIOUS];
+        ofs = &proc_ctx->frame_store[proc_ctx->is_dn_enabled ?
+            FRAME_OUT_CURRENT_DN : FRAME_IN_CURRENT];
+        do {
+            const VAProcPipelineParameterBuffer * const pipe =
+                proc_ctx->pipeline_param;
+
+            if (pipe->num_forward_references < 1)
+                break;
+            if (pipe->forward_references[0] == VA_INVALID_ID)
+                break;
+
+            obj_surface = SURFACE(pipe->forward_references[0]);
+            if (!obj_surface || obj_surface->base.id == ifs->surface_id)
+                break;
+
+            frame_store_clear(ifs, ctx);
+            if (obj_surface->base.id == ofs->surface_id) {
+                *ifs = *ofs;
+                frame_store_reset(ofs);
+            }
+            else {
+                ifs->obj_surface = obj_surface;
+                ifs->surface_id = obj_surface->base.id;
+                ifs->is_internal_surface = 0;
+                ifs->is_scratch_surface = 0;
+            }
+        } while (0);
+    }
 
     /* Update the input surface */
     obj_surface = proc_ctx->surface_input_vebox_object ?
         proc_ctx->surface_input_vebox_object : proc_ctx->surface_input_object;
 
     ifs = &proc_ctx->frame_store[FRAME_IN_CURRENT];
+    frame_store_clear(ifs, ctx);
     ifs->obj_surface = obj_surface;
     ifs->surface_id = proc_ctx->surface_input_object->base.id;
     ifs->is_internal_surface = proc_ctx->surface_input_vebox_object != NULL;
+    ifs->is_scratch_surface = 0;
 
     /* Update the Spatial Temporal Motion Measure (STMM) surfaces */
     if (is_new_frame) {
@@ -1011,7 +1064,7 @@ gen75_vebox_ensure_surfaces(VADriverContextP ctx,
     /* Reset the output surfaces to defaults. i.e. clean from user surfaces */
     for (i = FRAME_OUT_CURRENT_DN; i <= FRAME_OUT_PREVIOUS; i++) {
         ofs = &proc_ctx->frame_store[i];
-        if (!ofs->is_internal_surface)
+        if (!ofs->is_scratch_surface)
             ofs->obj_surface = NULL;
         ofs->surface_id = proc_ctx->surface_input_object->base.id;
     }
@@ -1023,12 +1076,19 @@ gen75_vebox_ensure_surfaces(VADriverContextP ctx,
     proc_ctx->current_output_type = 2;
     if (proc_ctx->filters_mask == VPP_DNDI_DN)
         proc_ctx->current_output = FRAME_OUT_CURRENT_DN;
+    else if (proc_ctx->is_di_adv_enabled && !proc_ctx->is_first_frame) {
+        proc_ctx->current_output_type = 0;
+        proc_ctx->current_output = proc_ctx->is_second_field ?
+            FRAME_OUT_CURRENT : FRAME_OUT_PREVIOUS;
+    }
     else
         proc_ctx->current_output = FRAME_OUT_CURRENT;
     ofs = &proc_ctx->frame_store[proc_ctx->current_output];
+    frame_store_clear(ofs, ctx);
     ofs->obj_surface = obj_surface;
     ofs->surface_id = proc_ctx->surface_input_object->base.id;
     ofs->is_internal_surface = proc_ctx->surface_output_vebox_object != NULL;
+    ofs->is_scratch_surface = 0;
 
     return VA_STATUS_SUCCESS;
 }
@@ -1261,6 +1321,7 @@ gen75_vebox_init_filter_params(VADriverContextP ctx,
     proc_ctx->is_iecp_enabled = (proc_ctx->filters_mask & VPP_IECP_MASK) != 0;
     proc_ctx->is_dn_enabled = (proc_ctx->filters_mask & VPP_DNDI_DN) != 0;
     proc_ctx->is_di_enabled = (proc_ctx->filters_mask & VPP_DNDI_DI) != 0;
+    proc_ctx->is_di_adv_enabled = 0;
     proc_ctx->is_first_frame = 0;
     proc_ctx->is_second_field = 0;
 
@@ -1295,6 +1356,30 @@ gen75_vebox_init_filter_params(VADriverContextP ctx,
         case VAProcDeinterlacingBob:
             proc_ctx->is_first_frame = 1;
             break;
+        case VAProcDeinterlacingMotionAdaptive:
+        case VAProcDeinterlacingMotionCompensated:
+            if (proc_ctx->frame_store[FRAME_IN_CURRENT].surface_id == VA_INVALID_ID)
+                proc_ctx->is_first_frame = 1;
+            else if (proc_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 */
+                if (proc_ctx->frame_store[FRAME_IN_PREVIOUS].surface_id == VA_INVALID_ID)
+                    proc_ctx->is_first_frame = 1;
+            }
+            else {
+                const VAProcPipelineParameterBuffer * const pipe =
+                    proc_ctx->pipeline_param;
+
+                if (pipe->num_forward_references < 1 ||
+                    pipe->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;
+                }
+            }
+            proc_ctx->is_di_adv_enabled = 1;
+            break;
         default:
             WARN_ONCE("unsupported deinterlacing algorithm (%d)\n",
                       deint_params->algorithm);
@@ -1371,18 +1456,8 @@ void gen75_vebox_context_destroy(VADriverContextP ctx,
        proc_ctx->surface_output_scaled_object = NULL;
      }
 
-    for (i = 0; i < ARRAY_ELEMS(proc_ctx->frame_store); i++) {
-        struct object_surface * const obj_surface =
-            proc_ctx->frame_store[i].obj_surface;
-
-        if (proc_ctx->frame_store[i].is_internal_surface && obj_surface) {
-            VASurfaceID surface_id = obj_surface->base.id;
-            i965_DestroySurfaces(ctx, &surface_id, 1);
-        }
-        proc_ctx->frame_store[i].obj_surface = NULL;
-        proc_ctx->frame_store[i].surface_id = VA_INVALID_ID;
-        proc_ctx->frame_store[i].is_internal_surface = 0;
-    }
+    for (i = 0; i < ARRAY_ELEMS(proc_ctx->frame_store); i++)
+        frame_store_clear(&proc_ctx->frame_store[i], ctx);
 
     /* dndi state table  */
     dri_bo_unreference(proc_ctx->dndi_state_table.bo);
diff --git a/src/gen75_vpp_vebox.h b/src/gen75_vpp_vebox.h
index 35c657d..d857b87 100644
--- a/src/gen75_vpp_vebox.h
+++ b/src/gen75_vpp_vebox.h
@@ -91,7 +91,8 @@ enum SURFACE_FORMAT{
 typedef struct veb_frame_store {
     struct object_surface *obj_surface;
     VASurfaceID surface_id; /* always relative to the input surface */
-    unsigned int is_internal_surface;
+    unsigned int is_internal_surface : 1;
+    unsigned int is_scratch_surface : 1;
 } VEBFrameStore;
 
 typedef struct veb_buffer {
@@ -147,6 +148,7 @@ struct intel_vebox_context
     unsigned int is_iecp_enabled        : 1;
     unsigned int is_dn_enabled          : 1;
     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;
 };

From 0f77edc715f5488e2b9aa51b1daaf13b4bdf6dba Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Tue, 19 Aug 2014 17:25:17 +0200
Subject: [PATCH 11/19] vebox: use Y-tiling for internal VEBOX surfaces.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 7e37d9c..9d400d9 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -886,7 +886,7 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
     else {
         input_fourcc = VA_FOURCC_NV12;
         input_sampling = SUBSAMPLE_YUV420;
-        input_tiling = 0;
+        input_tiling = 1;
         status = i965_check_alloc_surface_bo(ctx, input_obj_surface,
             input_tiling, input_fourcc, input_sampling);
         if (status != VA_STATUS_SUCCESS)
@@ -908,7 +908,7 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
     else {
         output_fourcc = VA_FOURCC_NV12;
         output_sampling = SUBSAMPLE_YUV420;
-        output_tiling = 0;
+        output_tiling = 1;
         status = i965_check_alloc_surface_bo(ctx, output_obj_surface,
             output_tiling, output_fourcc, output_sampling);
         if (status != VA_STATUS_SUCCESS)

From b22e2fb941aaec13ef47149d85bad4b0f9125155 Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Wed, 20 Aug 2014 16:12:46 +0200
Subject: [PATCH 12/19] vebox: use Y-tiling for output VEBOX surfaces.

FIXUP 0f77edc.

Always prefer tiled surfaces for performance reasons.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_picture_process.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/gen75_picture_process.c b/src/gen75_picture_process.c
index 6978d4b..f79ef2c 100644
--- a/src/gen75_picture_process.c
+++ b/src/gen75_picture_process.c
@@ -156,7 +156,7 @@ gen75_proc_picture(VADriverContextP ctx,
     }
 
     if (!obj_dst_surf->bo) {
-        unsigned int is_tiled = 0;
+        unsigned int is_tiled = 1;
         unsigned int fourcc = VA_FOURCC_NV12;
         int sampling = SUBSAMPLE_YUV420;
         i965_check_alloc_surface_bo(ctx, obj_dst_surf, is_tiled, fourcc, sampling);

From 72610c797775a9a3c6711ec4f29bd86a64b6b134 Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Wed, 20 Aug 2014 16:33:25 +0200
Subject: [PATCH 13/19] vebox: fix denoising when IECP is enabled.

If IECP is enabled, for instance when color conversion is performed
or ProcAmp adjustments are applied, the ultimate denoised output with
additional processing operations applied is the Current Output frame,
not the plain Current Denoised Output frame.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 9d400d9..190eedb 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -1074,7 +1074,7 @@ gen75_vebox_ensure_surfaces(VADriverContextP ctx,
         proc_ctx->surface_output_vebox_object : proc_ctx->surface_output_object;
 
     proc_ctx->current_output_type = 2;
-    if (proc_ctx->filters_mask == VPP_DNDI_DN)
+    if (proc_ctx->filters_mask == VPP_DNDI_DN && !proc_ctx->is_iecp_enabled)
         proc_ctx->current_output = FRAME_OUT_CURRENT_DN;
     else if (proc_ctx->is_di_adv_enabled && !proc_ctx->is_first_frame) {
         proc_ctx->current_output_type = 0;

From 9da94b4a8570454ebc56b56b8e39ea11821f8c3e Mon Sep 17 00:00:00 2001
From: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
Date: Tue, 26 Aug 2014 17:49:05 +0200
Subject: [PATCH 14/19] vebox: fix memory leak of VEBOX state tables.

Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
---
 src/gen75_vpp_vebox.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/src/gen75_vpp_vebox.c b/src/gen75_vpp_vebox.c
index 190eedb..4668e59 100644
--- a/src/gen75_vpp_vebox.c
+++ b/src/gen75_vpp_vebox.c
@@ -964,7 +964,6 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
     proc_ctx->dndi_state_table.bo = bo;
     if (!bo)
         return VA_STATUS_ERROR_ALLOCATION_FAILED;
-    drm_intel_bo_reference(proc_ctx->dndi_state_table.bo);
  
     /* Allocate IECP state table  */
     drm_intel_bo_unreference(proc_ctx->iecp_state_table.bo);
@@ -973,7 +972,6 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
     proc_ctx->iecp_state_table.bo = bo;
     if (!bo)
         return VA_STATUS_ERROR_ALLOCATION_FAILED;
-    drm_intel_bo_reference(proc_ctx->iecp_state_table.bo);
 
     /* Allocate Gamut state table  */
     drm_intel_bo_unreference(proc_ctx->gamut_state_table.bo);
@@ -982,7 +980,6 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
     proc_ctx->gamut_state_table.bo = bo;
     if (!bo)
         return VA_STATUS_ERROR_ALLOCATION_FAILED;
-    drm_intel_bo_reference(proc_ctx->gamut_state_table.bo);
 
     /* Allocate vertex state table  */
     drm_intel_bo_unreference(proc_ctx->vertex_state_table.bo);
@@ -991,7 +988,6 @@ gen75_vebox_ensure_surfaces_storage(VADriverContextP ctx,
     proc_ctx->vertex_state_table.bo = bo;
     if (!bo)
         return VA_STATUS_ERROR_ALLOCATION_FAILED;
-    drm_intel_bo_reference(proc_ctx->vertex_state_table.bo);
 
     return VA_STATUS_SUCCESS;
 }
@@ -1460,19 +1456,19 @@ void gen75_vebox_context_destroy(VADriverContextP ctx,
         frame_store_clear(&proc_ctx->frame_store[i], ctx);
 
     /* dndi state table  */
-    dri_bo_unreference(proc_ctx->dndi_state_table.bo);
+    drm_intel_bo_unreference(proc_ctx->dndi_state_table.bo);
     proc_ctx->dndi_state_table.bo = NULL;
 
     /* iecp state table  */
-    dri_bo_unreference(proc_ctx->iecp_state_table.bo);
-    proc_ctx->dndi_state_table.bo = NULL;
+    drm_intel_bo_unreference(proc_ctx->iecp_state_table.bo);
+    proc_ctx->iecp_state_table.bo = NULL;
  
     /* gamut statu table */
-    dri_bo_unreference(proc_ctx->gamut_state_table.bo);
+    drm_intel_bo_unreference(proc_ctx->gamut_state_table.bo);
     proc_ctx->gamut_state_table.bo = NULL;
 
     /* vertex state table  */
-    dri_bo_unreference(proc_ctx->vertex_state_table.bo);
+    drm_intel_bo_unreference(proc_ctx->vertex_state_table.bo);
     proc_ctx->vertex_state_table.bo = NULL;
 
     intel_batchbuffer_free(proc_ctx->batch);

