/*
 * Copyright (C) 2017 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *    Xiang, Haihao <haihao.xiang@intel.com>
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <assert.h>

#include "intel_batchbuffer.h"
#include "intel_driver.h"

#include "i965_defines.h"
#include "i965_drv_video.h"
#include "i965_encoder.h"
#include "i965_gpe_utils.h"
#include "i965_encoder_vp8.h"
#include "vp8_probs.h"
#include "vpx_quant.h"

#define SCALE_FACTOR_4X                 4
#define SCALE_FACTOR_16X                16

#define MAX_VP8_ENCODER_SURFACES        128

#define MAX_URB_SIZE                    2048 /* In register */
#define NUM_KERNELS_PER_GPE_CONTEXT     1

#define VP8_BRC_KBPS                    1000

#define BRC_KERNEL_CBR                  0x0010
#define BRC_KERNEL_VBR                  0x0020

struct i965_kernel vp8_kernels_brc_init_reset[NUM_VP8_BRC_RESET] = {
	{
		"VP8 BRC Init",
		VP8_BRC_INIT,
		NULL,
		0,
		NULL
	},

	{
		"VP8 BRC Reset",
		VP8_BRC_RESET,
		NULL,
		0,
		NULL
	},
};

struct i965_kernel vp8_kernels_scaling[NUM_VP8_SCALING] = {
	{
		"VP8 SCALE 4X",
		VP8_SCALING_4X,
		NULL,
		0,
		NULL
	},

	{
		"VP8 SCALE 16",
		VP8_SCALING_16X,
		NULL,
		0,
		NULL
	},
};

struct i965_kernel vp8_kernels_me[NUM_VP8_ME] = {
	{
		"VP8 ME 4X",
		VP8_ME_4X,
		NULL,
		0,
		NULL
	},

	{
		"VP8 ME 16",
		VP8_ME_16X,
		NULL,
		0,
		NULL
	},
};

struct i965_kernel vp8_kernels_mbenc[NUM_VP8_MBENC] = {
	{
		"VP8 MBEnc I Frame Dist",
		VP8_MBENC_I_FRAME_DIST,
		NULL,
		0,
		NULL
	},

	{
		"VP8 MBEnc I Frame Luma",
		VP8_MBENC_I_FRAME_LUMA,
		NULL,
		0,
		NULL
	},

	{
		"VP8 MBEnc I Frame Chroma",
		VP8_MBENC_I_FRAME_CHROMA,
		NULL,
		0,
		NULL
	},

	{
		"VP8 MBEnc P Frame",
		VP8_MBENC_P_FRAME,
		NULL,
		0,
		NULL
	},
};

struct i965_kernel vp8_kernels_mpu[NUM_VP8_MPU] = {
	{
		"VP8 MPU",
		VP8_MPU,
		NULL,
		0,
		NULL
	},
};

struct i965_kernel vp8_kernels_tpu[NUM_VP8_TPU] = {
	{
		"VP8 TPU",
		VP8_TPU,
		NULL,
		0,
		NULL
	},
};

struct i965_kernel vp8_kernels_brc_update[NUM_VP8_BRC_UPDATE] = {
	{
		"VP8 BRC Update",
		VP8_BRC_UPDATE,
		NULL,
		0,
		NULL
	},
};

static const unsigned char
vp8_num_refs[8] = {
	0, 1, 1, 2, 1, 2, 2, 3
};

static const unsigned int
vp8_search_path[8][16] = {
	// MEMethod: 0
	{
		0x120FF10F, 0x1E22E20D, 0x20E2FF10, 0x2EDD06FC, 0x11D33FF1, 0xEB1FF33D, 0x4EF1F1F1, 0xF1F21211,
		0x0DFFFFE0, 0x11201F1F, 0x1105F1CF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
	},
	// MEMethod: 1
	{
		0x120FF10F, 0x1E22E20D, 0x20E2FF10, 0x2EDD06FC, 0x11D33FF1, 0xEB1FF33D, 0x4EF1F1F1, 0xF1F21211,
		0x0DFFFFE0, 0x11201F1F, 0x1105F1CF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
	},
	// MEMethod: 2
	{
		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
		0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
	},
	// MEMethod: 3
	{
		0x01010101, 0x11010101, 0x01010101, 0x11010101, 0x01010101, 0x11010101, 0x01010101, 0x11010101,
		0x01010101, 0x11010101, 0x01010101, 0x00010101, 0x00000000, 0x00000000, 0x00000000, 0x00000000
	},
	// MEMethod: 4
	{
		0x0101F00F, 0x0F0F1010, 0xF0F0F00F, 0x01010101, 0x10101010, 0x0F0F0F0F, 0xF0F0F00F, 0x0101F0F0,
		0x01010101, 0x10101010, 0x0F0F1010, 0x0F0F0F0F, 0xF0F0F00F, 0xF0F0F0F0, 0x00000000, 0x00000000
	},
	// MEMethod: 5
	{
		0x0101F00F, 0x0F0F1010, 0xF0F0F00F, 0x01010101, 0x10101010, 0x0F0F0F0F, 0xF0F0F00F, 0x0101F0F0,
		0x01010101, 0x10101010, 0x0F0F1010, 0x0F0F0F0F, 0xF0F0F00F, 0xF0F0F0F0, 0x00000000, 0x00000000
	},
	// MEMethod: 6
	{
		0x120FF10F, 0x1E22E20D, 0x20E2FF10, 0x2EDD06FC, 0x11D33FF1, 0xEB1FF33D, 0x4EF1F1F1, 0xF1F21211,
		0x0DFFFFE0, 0x11201F1F, 0x1105F1CF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
	},
	// MEMethod: 7
	{
		0x1F11F10F, 0x2E22E2FE, 0x20E220DF, 0x2EDD06FC, 0x11D33FF1, 0xEB1FF33D, 0x02F1F1F1, 0x1F201111,
		0xF1EFFF0C, 0xF01104F1, 0x10FF0A50, 0x000FF1C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000
	}
};

static const unsigned char
i_frame_vme_costs_vp8[NUM_QP_VP8][4] = {
	{0x05, 0x1f, 0x02, 0x09},
	{0x05, 0x1f, 0x02, 0x09},
	{0x08, 0x2b, 0x03, 0x0e},
	{0x08, 0x2b, 0x03, 0x0e},
	{0x0a, 0x2f, 0x04, 0x12},
	{0x0a, 0x2f, 0x04, 0x12},
	{0x0d, 0x39, 0x05, 0x17},
	{0x0d, 0x39, 0x05, 0x17},
	{0x0d, 0x39, 0x05, 0x17},
	{0x0f, 0x3b, 0x06, 0x1b},
	{0x0f, 0x3b, 0x06, 0x1b},
	{0x19, 0x3d, 0x07, 0x20},
	{0x19, 0x3d, 0x07, 0x20},
	{0x1a, 0x3f, 0x08, 0x24},
	{0x1a, 0x3f, 0x08, 0x24},
	{0x1a, 0x3f, 0x08, 0x24},
	{0x1b, 0x48, 0x09, 0x29},
	{0x1b, 0x48, 0x09, 0x29},
	{0x1d, 0x49, 0x09, 0x2d},
	{0x1d, 0x49, 0x09, 0x2d},
	{0x1d, 0x49, 0x09, 0x2d},
	{0x1d, 0x49, 0x09, 0x2d},
	{0x1e, 0x4a, 0x0a, 0x32},
	{0x1e, 0x4a, 0x0a, 0x32},
	{0x1e, 0x4a, 0x0a, 0x32},
	{0x1e, 0x4a, 0x0a, 0x32},
	{0x1f, 0x4b, 0x0b, 0x36},
	{0x1f, 0x4b, 0x0b, 0x36},
	{0x1f, 0x4b, 0x0b, 0x36},
	{0x28, 0x4c, 0x0c, 0x3b},
	{0x28, 0x4c, 0x0c, 0x3b},
	{0x29, 0x4d, 0x0d, 0x3f},
	{0x29, 0x4d, 0x0d, 0x3f},
	{0x29, 0x4e, 0x0e, 0x44},
	{0x29, 0x4e, 0x0e, 0x44},
	{0x2a, 0x4f, 0x0f, 0x48},
	{0x2a, 0x4f, 0x0f, 0x48},
	{0x2b, 0x58, 0x10, 0x4d},
	{0x2b, 0x58, 0x10, 0x4d},
	{0x2b, 0x58, 0x11, 0x51},
	{0x2b, 0x58, 0x11, 0x51},
	{0x2b, 0x58, 0x11, 0x51},
	{0x2c, 0x58, 0x12, 0x56},
	{0x2c, 0x58, 0x12, 0x56},
	{0x2c, 0x59, 0x13, 0x5a},
	{0x2c, 0x59, 0x13, 0x5a},
	{0x2d, 0x59, 0x14, 0x5f},
	{0x2d, 0x59, 0x14, 0x5f},
	{0x2e, 0x5a, 0x15, 0x63},
	{0x2e, 0x5a, 0x15, 0x63},
	{0x2e, 0x5a, 0x16, 0x68},
	{0x2e, 0x5a, 0x16, 0x68},
	{0x2e, 0x5a, 0x16, 0x68},
	{0x2f, 0x5b, 0x17, 0x6c},
	{0x2f, 0x5b, 0x17, 0x6c},
	{0x38, 0x5b, 0x18, 0x71},
	{0x38, 0x5b, 0x18, 0x71},
	{0x38, 0x5c, 0x19, 0x76},
	{0x38, 0x5c, 0x19, 0x76},
	{0x38, 0x5c, 0x1a, 0x7a},
	{0x38, 0x5c, 0x1a, 0x7a},
	{0x39, 0x5d, 0x1a, 0x7f},
	{0x39, 0x5d, 0x1a, 0x7f},
	{0x39, 0x5d, 0x1b, 0x83},
	{0x39, 0x5d, 0x1b, 0x83},
	{0x39, 0x5e, 0x1c, 0x88},
	{0x39, 0x5e, 0x1c, 0x88},
	{0x3a, 0x5e, 0x1d, 0x8c},
	{0x3a, 0x5e, 0x1d, 0x8c},
	{0x3a, 0x5f, 0x1e, 0x91},
	{0x3a, 0x5f, 0x1e, 0x91},
	{0x3a, 0x5f, 0x1f, 0x95},
	{0x3a, 0x5f, 0x1f, 0x95},
	{0x3a, 0x68, 0x20, 0x9a},
	{0x3a, 0x68, 0x20, 0x9a},
	{0x3b, 0x68, 0x21, 0x9e},
	{0x3b, 0x68, 0x21, 0x9e},
	{0x3b, 0x68, 0x22, 0xa3},
	{0x3b, 0x68, 0x22, 0xa3},
	{0x3b, 0x68, 0x23, 0xa7},
	{0x3b, 0x68, 0x23, 0xa7},
	{0x3c, 0x68, 0x24, 0xac},
	{0x3c, 0x68, 0x24, 0xac},
	{0x3c, 0x68, 0x24, 0xac},
	{0x3c, 0x69, 0x25, 0xb0},
	{0x3c, 0x69, 0x25, 0xb0},
	{0x3c, 0x69, 0x26, 0xb5},
	{0x3c, 0x69, 0x26, 0xb5},
	{0x3d, 0x69, 0x27, 0xb9},
	{0x3d, 0x69, 0x27, 0xb9},
	{0x3d, 0x69, 0x28, 0xbe},
	{0x3d, 0x69, 0x28, 0xbe},
	{0x3d, 0x6a, 0x29, 0xc2},
	{0x3d, 0x6a, 0x29, 0xc2},
	{0x3e, 0x6a, 0x2a, 0xc7},
	{0x3e, 0x6a, 0x2a, 0xc7},
	{0x3e, 0x6a, 0x2b, 0xcb},
	{0x3e, 0x6a, 0x2b, 0xd0},
	{0x3f, 0x6b, 0x2c, 0xd4},
	{0x3f, 0x6b, 0x2d, 0xd9},
	{0x3f, 0x6b, 0x2e, 0xdd},
	{0x48, 0x6b, 0x2f, 0xe2},
	{0x48, 0x6b, 0x2f, 0xe2},
	{0x48, 0x6c, 0x30, 0xe6},
	{0x48, 0x6c, 0x31, 0xeb},
	{0x48, 0x6c, 0x32, 0xf0},
	{0x48, 0x6c, 0x33, 0xf4},
	{0x48, 0x6c, 0x34, 0xf9},
	{0x49, 0x6d, 0x35, 0xfd},
	{0x49, 0x6d, 0x36, 0xff},
	{0x49, 0x6d, 0x37, 0xff},
	{0x49, 0x6d, 0x38, 0xff},
	{0x49, 0x6e, 0x3a, 0xff},
	{0x49, 0x6e, 0x3b, 0xff},
	{0x4a, 0x6e, 0x3c, 0xff},
	{0x4a, 0x6f, 0x3d, 0xff},
	{0x4a, 0x6f, 0x3d, 0xff},
	{0x4a, 0x6f, 0x3e, 0xff},
	{0x4a, 0x6f, 0x3f, 0xff},
	{0x4a, 0x6f, 0x40, 0xff},
	{0x4b, 0x78, 0x41, 0xff},
	{0x4b, 0x78, 0x42, 0xff},
	{0x4b, 0x78, 0x43, 0xff},
	{0x4b, 0x78, 0x44, 0xff},
	{0x4b, 0x78, 0x46, 0xff},
	{0x4c, 0x78, 0x47, 0xff},
	{0x4c, 0x79, 0x49, 0xff},
	{0x4c, 0x79, 0x4a, 0xff}
};

static const unsigned char
mainref_table_vp8[8] = {
	0, 1, 2, 9, 3, 13, 14, 57
};

static const unsigned int
cost_table_vp8[NUM_QP_VP8][7] = {
	{0x398f0500, 0x6f6f6f6f, 0x0000006f, 0x06040402, 0x1a0c0907, 0x08, 0x0e},
	{0x3b8f0600, 0x6f6f6f6f, 0x0000006f, 0x06040402, 0x1a0c0907, 0x0a, 0x11},
	{0x3e8f0700, 0x6f6f6f6f, 0x0000006f, 0x06040402, 0x1a0c0907, 0x0c, 0x14},
	{0x488f0800, 0x6f6f6f6f, 0x0000006f, 0x06040402, 0x1a0c0907, 0x0f, 0x18},
	{0x498f0a00, 0x6f6f6f6f, 0x0000006f, 0x0d080805, 0x291b190e, 0x11, 0x1b},
	{0x4a8f0b00, 0x6f6f6f6f, 0x0000006f, 0x0d080805, 0x291b190e, 0x13, 0x1e},
	{0x4b8f0c00, 0x6f6f6f6f, 0x0000006f, 0x0d080805, 0x291b190e, 0x15, 0x22},
	{0x4b8f0c00, 0x6f6f6f6f, 0x0000006f, 0x0d080805, 0x291b190e, 0x15, 0x22},
	{0x4d8f0d00, 0x6f6f6f6f, 0x0000006f, 0x0d080805, 0x291b190e, 0x17, 0x25},
	{0x4e8f0e00, 0x6f6f6f6f, 0x0000006f, 0x190b0c07, 0x2e281e1a, 0x19, 0x29},
	{0x4f8f0f00, 0x6f6f6f6f, 0x0000006f, 0x190b0c07, 0x2e281e1a, 0x1b, 0x2c},
	{0x588f1800, 0x6f6f6f6f, 0x0000006f, 0x190b0c07, 0x2e281e1a, 0x1d, 0x2f},
	{0x588f1900, 0x6f6f6f6f, 0x0000006f, 0x190b0c07, 0x2e281e1a, 0x1f, 0x33},
	{0x598f1900, 0x6f6f6f6f, 0x0000006f, 0x1c0f0f0a, 0x392b291e, 0x21, 0x36},
	{0x5a8f1a00, 0x6f6f6f6f, 0x0000006f, 0x1c0f0f0a, 0x392b291e, 0x23, 0x3a},
	{0x5a8f1a00, 0x6f6f6f6f, 0x0000006f, 0x1c0f0f0a, 0x392b291e, 0x23, 0x3a},
	{0x5a8f1a00, 0x6f6f6f6f, 0x0000006f, 0x1c0f0f0a, 0x392b291e, 0x25, 0x3d},
	{0x5b8f1b00, 0x6f6f6f6f, 0x0000006f, 0x1c0f0f0a, 0x392b291e, 0x27, 0x40},
	{0x5b8f1c00, 0x6f6f6f6f, 0x0000006f, 0x2819190c, 0x3c2e2b29, 0x2a, 0x44},
	{0x5b8f1c00, 0x6f6f6f6f, 0x0000006f, 0x2819190c, 0x3c2e2b29, 0x2a, 0x44},
	{0x5c8f1c00, 0x6f6f6f6f, 0x0000006f, 0x2819190c, 0x3c2e2b29, 0x2c, 0x47},
	{0x5c8f1c00, 0x6f6f6f6f, 0x0000006f, 0x2819190c, 0x3c2e2b29, 0x2c, 0x47},
	{0x5d8f1d00, 0x6f6f6f6f, 0x0000006f, 0x2819190c, 0x3c2e2b29, 0x2e, 0x4a},
	{0x5d8f1d00, 0x6f6f6f6f, 0x0000006f, 0x2819190c, 0x3c2e2b29, 0x2e, 0x4a},
	{0x5d8f1d00, 0x6f6f6f6f, 0x0000006f, 0x2819190c, 0x3c2e2b29, 0x30, 0x4e},
	{0x5d8f1d00, 0x6f6f6f6f, 0x0000006f, 0x2819190c, 0x3c2e2b29, 0x30, 0x4e},
	{0x5e8f1e00, 0x6f6f6f6f, 0x0000006f, 0x291b1b0f, 0x3e382e2a, 0x32, 0x51},
	{0x5e8f1f00, 0x6f6f6f6f, 0x0000006f, 0x291b1b0f, 0x3e382e2a, 0x34, 0x55},
	{0x5e8f1f00, 0x6f6f6f6f, 0x0000006f, 0x291b1b0f, 0x3e382e2a, 0x34, 0x55},
	{0x5f8f1f00, 0x6f6f6f6f, 0x0000006f, 0x291b1b0f, 0x3e382e2a, 0x36, 0x58},
	{0x688f2800, 0x6f6f6f6f, 0x0000006f, 0x291b1b0f, 0x3e382e2a, 0x38, 0x5b},
	{0x688f2800, 0x6f6f6f6f, 0x0000006f, 0x2b1d1d18, 0x483a382c, 0x3a, 0x5f},
	{0x688f2800, 0x6f6f6f6f, 0x0000006f, 0x2b1d1d18, 0x483a382c, 0x3c, 0x62},
	{0x688f2900, 0x6f6f6f6f, 0x0000006f, 0x2b1d1d18, 0x483a382c, 0x3e, 0x65},
	{0x698f2900, 0x6f6f6f6f, 0x0000006f, 0x2b1d1d18, 0x483a382c, 0x40, 0x69},
	{0x698f2900, 0x6f6f6f6f, 0x0000006f, 0x2c1f1f19, 0x493b392e, 0x43, 0x6c},
	{0x698f2900, 0x6f6f6f6f, 0x0000006f, 0x2c1f1f19, 0x493b392e, 0x45, 0x70},
	{0x6a8f2a00, 0x6f6f6f6f, 0x0000006f, 0x2c1f1f19, 0x493b392e, 0x47, 0x73},
	{0x6a8f2a00, 0x6f6f6f6f, 0x0000006f, 0x2c1f1f19, 0x493b392e, 0x49, 0x76},
	{0x6a8f2a00, 0x6f6f6f6f, 0x0000006f, 0x2e28281b, 0x4b3d3a38, 0x4b, 0x7a},
	{0x6b8f2b00, 0x6f6f6f6f, 0x0000006f, 0x2e28281b, 0x4b3d3a38, 0x4d, 0x7d},
	{0x6b8f2b00, 0x6f6f6f6f, 0x0000006f, 0x2e28281b, 0x4b3d3a38, 0x4d, 0x7d},
	{0x6b8f2b00, 0x6f6f6f6f, 0x0000006f, 0x2e28281b, 0x4b3d3a38, 0x4f, 0x81},
	{0x6b8f2b00, 0x6f6f6f6f, 0x0000006f, 0x2e28281b, 0x4b3d3a38, 0x51, 0x84},
	{0x6b8f2c00, 0x6f6f6f6f, 0x0000006f, 0x2f29291c, 0x4c3e3b38, 0x53, 0x87},
	{0x6c8f2c00, 0x6f6f6f6f, 0x0000006f, 0x2f29291c, 0x4c3e3b38, 0x55, 0x8b},
	{0x6c8f2c00, 0x6f6f6f6f, 0x0000006f, 0x2f29291c, 0x4c3e3b38, 0x57, 0x8e},
	{0x6c8f2c00, 0x6f6f6f6f, 0x0000006f, 0x2f29291c, 0x4c3e3b38, 0x59, 0x91},
	{0x6d8f2d00, 0x6f6f6f6f, 0x0000006f, 0x382a2a1d, 0x4d483c39, 0x5b, 0x95},
	{0x6d8f2d00, 0x6f6f6f6f, 0x0000006f, 0x382a2a1d, 0x4d483c39, 0x5e, 0x98},
	{0x6d8f2d00, 0x6f6f6f6f, 0x0000006f, 0x382a2a1d, 0x4d483c39, 0x60, 0x9c},
	{0x6d8f2d00, 0x6f6f6f6f, 0x0000006f, 0x382a2a1d, 0x4d483c39, 0x60, 0x9c},
	{0x6d8f2e00, 0x6f6f6f6f, 0x0000006f, 0x382a2a1d, 0x4d483c39, 0x62, 0x9f},
	{0x6e8f2e00, 0x6f6f6f6f, 0x0000006f, 0x392b2b1e, 0x4e483e3a, 0x64, 0xa2},
	{0x6e8f2e00, 0x6f6f6f6f, 0x0000006f, 0x392b2b1e, 0x4e483e3a, 0x66, 0xa6},
	{0x6e8f2e00, 0x6f6f6f6f, 0x0000006f, 0x392b2b1e, 0x4e483e3a, 0x68, 0xa9},
	{0x6f8f2f00, 0x6f6f6f6f, 0x0000006f, 0x392b2b1e, 0x4e483e3a, 0x6a, 0xad},
	{0x6f8f2f00, 0x6f6f6f6f, 0x0000006f, 0x3a2c2c1f, 0x4f493f3b, 0x6c, 0xb0},
	{0x6f8f2f00, 0x6f6f6f6f, 0x0000006f, 0x3a2c2c1f, 0x4f493f3b, 0x6e, 0xb3},
	{0x788f3800, 0x6f6f6f6f, 0x0000006f, 0x3a2c2c1f, 0x4f493f3b, 0x70, 0xb7},
	{0x788f3800, 0x6f6f6f6f, 0x0000006f, 0x3a2c2c1f, 0x4f493f3b, 0x72, 0xba},
	{0x788f3800, 0x6f6f6f6f, 0x0000006f, 0x3b2d2d28, 0x584a483c, 0x74, 0xbd},
	{0x788f3800, 0x6f6f6f6f, 0x0000006f, 0x3b2d2d28, 0x584a483c, 0x76, 0xc1},
	{0x788f3800, 0x6f6f6f6f, 0x0000006f, 0x3b2d2d28, 0x584a483c, 0x79, 0xc4},
	{0x788f3800, 0x6f6f6f6f, 0x0000006f, 0x3b2d2d28, 0x584a483c, 0x7b, 0xc8},
	{0x788f3800, 0x6f6f6f6f, 0x0000006f, 0x3b2e2e29, 0x594b483d, 0x7d, 0xcb},
	{0x798f3900, 0x6f6f6f6f, 0x0000006f, 0x3b2e2e29, 0x594b483d, 0x7f, 0xce},
	{0x798f3900, 0x6f6f6f6f, 0x0000006f, 0x3b2e2e29, 0x594b483d, 0x81, 0xd2},
	{0x798f3900, 0x6f6f6f6f, 0x0000006f, 0x3b2e2e29, 0x594b483d, 0x83, 0xd5},
	{0x798f3900, 0x6f6f6f6f, 0x0000006f, 0x3c2f2f29, 0x594b493e, 0x85, 0xd9},
	{0x798f3900, 0x6f6f6f6f, 0x0000006f, 0x3c2f2f29, 0x594b493e, 0x87, 0xdc},
	{0x798f3900, 0x6f6f6f6f, 0x0000006f, 0x3c2f2f29, 0x594b493e, 0x89, 0xdf},
	{0x798f3a00, 0x6f6f6f6f, 0x0000006f, 0x3c2f2f29, 0x594b493e, 0x8b, 0xe3},
	{0x7a8f3a00, 0x6f6f6f6f, 0x0000006f, 0x3d38382a, 0x5a4c493f, 0x8d, 0xe6},
	{0x7a8f3a00, 0x6f6f6f6f, 0x0000006f, 0x3d38382a, 0x5a4c493f, 0x8f, 0xe9},
	{0x7a8f3a00, 0x6f6f6f6f, 0x0000006f, 0x3d38382a, 0x5a4c493f, 0x91, 0xed},
	{0x7a8f3a00, 0x6f6f6f6f, 0x0000006f, 0x3d38382a, 0x5a4c493f, 0x94, 0xf0},
	{0x7a8f3a00, 0x6f6f6f6f, 0x0000006f, 0x3e38382b, 0x5b4d4a48, 0x96, 0xf4},
	{0x7a8f3a00, 0x6f6f6f6f, 0x0000006f, 0x3e38382b, 0x5b4d4a48, 0x98, 0xf7},
	{0x7b8f3b00, 0x6f6f6f6f, 0x0000006f, 0x3e38382b, 0x5b4d4a48, 0x9a, 0xfa},
	{0x7b8f3b00, 0x6f6f6f6f, 0x0000006f, 0x3e38382b, 0x5b4d4a48, 0x9c, 0xfe},
	{0x7b8f3b00, 0x6f6f6f6f, 0x0000006f, 0x3f38392b, 0x5b4d4b48, 0x9e, 0xff},
	{0x7b8f3b00, 0x6f6f6f6f, 0x0000006f, 0x3f38392b, 0x5b4d4b48, 0x9e, 0xff},
	{0x7b8f3b00, 0x6f6f6f6f, 0x0000006f, 0x3f38392b, 0x5b4d4b48, 0xa0, 0xff},
	{0x7b8f3b00, 0x6f6f6f6f, 0x0000006f, 0x3f38392b, 0x5b4d4b48, 0xa2, 0xff},
	{0x7b8f3b00, 0x6f6f6f6f, 0x0000006f, 0x3f38392b, 0x5b4d4b48, 0xa4, 0xff},
	{0x7b8f3b00, 0x6f6f6f6f, 0x0000006f, 0x3f39392c, 0x5c4e4b48, 0xa6, 0xff},
	{0x7c8f3c00, 0x6f6f6f6f, 0x0000006f, 0x3f39392c, 0x5c4e4b48, 0xa8, 0xff},
	{0x7c8f3c00, 0x6f6f6f6f, 0x0000006f, 0x3f39392c, 0x5c4e4b48, 0xaa, 0xff},
	{0x7c8f3c00, 0x6f6f6f6f, 0x0000006f, 0x3f39392c, 0x5c4e4b48, 0xac, 0xff},
	{0x7c8f3c00, 0x6f6f6f6f, 0x0000006f, 0x48393a2c, 0x5c4f4c49, 0xaf, 0xff},
	{0x7c8f3c00, 0x6f6f6f6f, 0x0000006f, 0x48393a2c, 0x5c4f4c49, 0xb1, 0xff},
	{0x7c8f3c00, 0x6f6f6f6f, 0x0000006f, 0x48393a2c, 0x5c4f4c49, 0xb3, 0xff},
	{0x7c8f3c00, 0x6f6f6f6f, 0x0000006f, 0x48393a2c, 0x5c4f4c49, 0xb5, 0xff},
	{0x7d8f3d00, 0x6f6f6f6f, 0x0000006f, 0x483a3a2d, 0x5d584c49, 0xb7, 0xff},
	{0x7d8f3d00, 0x6f6f6f6f, 0x0000006f, 0x483a3a2d, 0x5d584c49, 0xb9, 0xff},
	{0x7d8f3d00, 0x6f6f6f6f, 0x0000006f, 0x483a3a2d, 0x5d584c49, 0xbd, 0xff},
	{0x7d8f3d00, 0x6f6f6f6f, 0x0000006f, 0x493a3b2e, 0x5e584d4a, 0xc1, 0xff},
	{0x7e8f3e00, 0x6f6f6f6f, 0x0000006f, 0x493a3b2e, 0x5e584d4a, 0xc5, 0xff},
	{0x7e8f3e00, 0x6f6f6f6f, 0x0000006f, 0x493b3b2e, 0x5e584e4a, 0xc8, 0xff},
	{0x7e8f3e00, 0x6f6f6f6f, 0x0000006f, 0x493b3b2e, 0x5e584e4a, 0xcc, 0xff},
	{0x7e8f3e00, 0x6f6f6f6f, 0x0000006f, 0x493b3c2f, 0x5f594e4b, 0xd0, 0xff},
	{0x7f8f3f00, 0x6f6f6f6f, 0x0000006f, 0x493b3c2f, 0x5f594e4b, 0xd2, 0xff},
	{0x7f8f3f00, 0x6f6f6f6f, 0x0000006f, 0x493b3c2f, 0x5f594e4b, 0xd4, 0xff},
	{0x7f8f3f00, 0x6f6f6f6f, 0x0000006f, 0x4a3c3c2f, 0x5f594f4b, 0xd8, 0xff},
	{0x7f8f3f00, 0x6f6f6f6f, 0x0000006f, 0x4a3c3c2f, 0x5f594f4b, 0xdc, 0xff},
	{0x888f4800, 0x6f6f6f6f, 0x0000006f, 0x4a3c3d38, 0x68594f4c, 0xe0, 0xff},
	{0x888f4800, 0x6f6f6f6f, 0x0000006f, 0x4a3c3d38, 0x68594f4c, 0xe5, 0xff},
	{0x888f4800, 0x6f6f6f6f, 0x0000006f, 0x4b3d3d38, 0x685a584c, 0xe9, 0xff},
	{0x888f4800, 0x6f6f6f6f, 0x0000006f, 0x4b3d3d38, 0x685a584c, 0xed, 0xff},
	{0x888f4800, 0x6f6f6f6f, 0x0000006f, 0x4b3d3e38, 0x685a584c, 0xf1, 0xff},
	{0x888f4800, 0x6f6f6f6f, 0x0000006f, 0x4b3d3e38, 0x685a584c, 0xf5, 0xff},
	{0x898f4900, 0x6f6f6f6f, 0x0000006f, 0x4b3e3e39, 0x695b584d, 0xfe, 0xff},
	{0x898f4900, 0x6f6f6f6f, 0x0000006f, 0x4c3e3e39, 0x695b594d, 0xff, 0xff},
	{0x898f4900, 0x6f6f6f6f, 0x0000006f, 0x4c3e3e39, 0x695b594d, 0xff, 0xff},
	{0x898f4900, 0x6f6f6f6f, 0x0000006f, 0x4c3f3f39, 0x695b594e, 0xff, 0xff},
	{0x898f4900, 0x6f6f6f6f, 0x0000006f, 0x4c3f3f39, 0x695b594e, 0xff, 0xff},
	{0x898f4900, 0x6f6f6f6f, 0x0000006f, 0x4d3f3f3a, 0x6a5c594e, 0xff, 0xff},
	{0x898f4900, 0x6f6f6f6f, 0x0000006f, 0x4d3f3f3a, 0x6a5c594e, 0xff, 0xff},
	{0x8a8f4a00, 0x6f6f6f6f, 0x0000006f, 0x4d48483a, 0x6a5c594f, 0xff, 0xff},
	{0x8a8f4a00, 0x6f6f6f6f, 0x0000006f, 0x4d48483a, 0x6a5c594f, 0xff, 0xff},
	{0x8a8f4a00, 0x6f6f6f6f, 0x0000006f, 0x4d48483a, 0x6a5c5a4f, 0xff, 0xff},
	{0x8a8f4a00, 0x6f6f6f6f, 0x0000006f, 0x4d48483a, 0x6a5c5a4f, 0xff, 0xff},
	{0x8a8f4a00, 0x6f6f6f6f, 0x0000006f, 0x4e48483a, 0x6a5d5a58, 0xff, 0xff},
	{0x8b8f4b00, 0x6f6f6f6f, 0x0000006f, 0x4e48483b, 0x6b5d5a58, 0xff, 0xff},
	{0x8b8f4b00, 0x6f6f6f6f, 0x0000006f, 0x4e48483b, 0x6b5d5a58, 0xff, 0xff},
	{0x8b8f4b00, 0x6f6f6f6f, 0x0000006f, 0x4f48493b, 0x6b5d5b58, 0xff, 0xff},
	{0x8b8f4b00, 0x6f6f6f6f, 0x0000006f, 0x4f49493b, 0x6b5e5b58, 0xff, 0xff}
};

static const unsigned int single_su_vp8[56] = {
	0x00000000, 0x00000000, 0x00000000, 0x00000000,
	0x00000000, 0x00000000, 0x00000000, 0x00000000,
	0x00000000, 0x00000000, 0x00000000, 0x00000000,
	0x00000000, 0x00000000
};

static const unsigned char full_spiral_48x40_vp8[56] = {
	// L -> U -> R -> D
	0x0F,
	0xF0,
	0x01, 0x01,
	0x10, 0x10,
	0x0F, 0x0F, 0x0F,
	0xF0, 0xF0, 0xF0,
	0x01, 0x01, 0x01, 0x01,
	0x10, 0x10, 0x10, 0x10,
	0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
	0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
	0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
	0x10, 0x10, 0x10, 0x10, 0x10, 0x10,       // The last 0x10 steps outside the search window.
	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // These are outside the search window.
	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0
};

static const unsigned char raster_scan_48x40_vp8[56] = {
	0x11, 0x01, 0x01, 0x01,
	0x11, 0x01, 0x01, 0x01,
	0x11, 0x01, 0x01, 0x01,
	0x11, 0x01, 0x01, 0x01,
	0x11, 0x01, 0x01, 0x01,
	0x01, 0x01, 0x01, 0x01,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00
};

static const unsigned char diamond_vp8[56] = {
	0x0F, 0xF1, 0x0F, 0x12,//5
	0x0D, 0xE2, 0x22, 0x1E,//9
	0x10, 0xFF, 0xE2, 0x20,//13
	0xFC, 0x06, 0xDD,//16
	0x2E, 0xF1, 0x3F, 0xD3, 0x11, 0x3D, 0xF3, 0x1F,//24
	0xEB, 0xF1, 0xF1, 0xF1,//28
	0x4E, 0x11, 0x12, 0xF2, 0xF1,//33
	0xE0, 0xFF, 0xFF, 0x0D, 0x1F, 0x1F,//39
	0x20, 0x11, 0xCF, 0xF1, 0x05, 0x11,//45
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//51
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

static const unsigned short
mv_ref_cost_context_vp8[6][4][2] = {
	{   {1328, 10},
		{2047, 1},
		{2047, 1},
		{214, 304},
	},
	{   {1072, 21},
		{979, 27},
		{1072, 21},
		{321, 201},
	},
	{   {235, 278},
		{511, 107},
		{553, 93},
		{488, 115},
	},
	{   {534, 99},
		{560, 92},
		{255, 257},
		{505, 109},
	},
	{   {174, 361},
		{238, 275},
		{255, 257},
		{744, 53},
	},
	{   {32, 922},
		{113, 494},
		{255, 257},
		{816, 43},
	},
};

static const unsigned int
new_mv_skip_threshold_vp8[NUM_QP_VP8] = {
	111, 120, 129, 137, 146, 155, 163, 172, 180, 189, 198, 206, 215, 224, 232, 241,
	249, 258, 267, 275, 284, 293, 301, 310, 318, 327, 336, 344, 353, 362, 370, 379,
	387, 396, 405, 413, 422, 431, 439, 448, 456, 465, 474, 482, 491, 500, 508, 517,
	525, 534, 543, 551, 560, 569, 577, 586, 594, 603, 612, 620, 629, 638, 646, 655,
	663, 672, 681, 689, 698, 707, 715, 724, 733, 741, 750, 758, 767, 776, 784, 793,
	802, 810, 819, 827, 836, 845, 853, 862, 871, 879, 888, 896, 905, 914, 922, 931,
	940, 948, 957, 965, 974, 983, 991, 1000, 1009, 1017, 1026, 1034, 1043, 1052, 1060, 1069,
	1078, 1086, 1095, 1103, 1112, 1121, 1129, 1138, 1147, 1155, 1164, 1172, 1181, 1190, 1198, 1208
};

static const unsigned short
mb_mode_cost_luma_vp8[10] = {
	657,    869,    915,    917,    208,    0,      0,      0,      0,      0
};


static const unsigned short
block_mode_cost_vp8[10][10][10] = {
	{
		{37,  1725,  1868,  1151,  1622,  2096,  2011,  1770,  2218,  2128  },
		{139,  759,  1683,  911,  1455,  1846,  1570,  1295,  1792,  1648   },
		{560,  1383,  408,  639,  1612,  1174,  1562,  1736,  847,  991     },
		{191,  1293,  1299,  466,  1774,  1840,  1784,  1691,  1698,  1505  },
		{211,  1624,  1294,  779,  714,  1622,  2222,  1554,  1706,  903    },
		{297,  1259,  1098,  1062,  1583,  618,  1053,  1889,  851,  1127   },
		{275,  703,  1356,  1111,  1597,  1075,  656,  1529,  1531,  1275   },
		{150,  1046,  1760,  1039,  1353,  1981,  2174,  728,  1730,  1379  },
		{516,  1414,  741,  1045,  1495,  738,  1288,  1619,  442,  1200    },
		{424,  1365,  706,  825,  1197,  1453,  1191,  1462,  1186,  519    },
	},
	{
		{393,  515,  1491,  549,  1598,  1524,  964,  1126,  1651,  2172    },
		{693,  237,  1954,  641,  1525,  2073,  1183,  971,  1973,  2235    },
		{560,  739,  855,  836,  1224,  1115,  966,  839,  1076,  767       },
		{657,  368,  1406,  425,  1672,  1853,  1210,  1125,  1969,  1542   },
		{321,  1056,  1776,  774,  803,  3311,  1265,  1177,  1366,  636    },
		{693,  510,  949,  877,  1049,  658,  882,  1178,  1515,  1111      },
		{744,  377,  1278,  958,  1576,  1168,  477,  1146,  1838,  1501    },
		{488,  477,  1767,  973,  1107,  1511,  1773,  486,  1527,  1449    },
		{744,  1004,  695,  1012,  1326,  834,  1215,  774,  724,  704      },
		{522,  567,  1036,  1082,  1039,  1333,  873,  1135,  1189,  677    },
	},
	{
		{103,  1441,  1000,  864,  1513,  1928,  1832,  1916,  1663,  1567  },
		{304,  872,  1100,  515,  1416,  1417,  3463,  1051,  1305,  1227   },
		{684,  2176,  242,  729,  1867,  1496,  2056,  1544,  1038,  930    },
		{534,  1198,  669,  300,  1805,  1377,  2165,  1894,  1249,  1153   },
		{346,  1602,  1178,  612,  997,  3381,  1335,  1328,  997,  646     },
		{393,  1027,  649,  813,  1276,  945,  1545,  1278,  875,  1031     },
		{528,  996,  930,  617,  1086,  1190,  621,  2760,  787,  1347      },
		{216,  873,  1595,  738,  1339,  3896,  3898,  743,  1343,  1605    },
		{675,  1580,  543,  749,  1859,  1245,  1589,  2377,  384,  1075    },
		{594,  1163,  415,  684,  1474,  1080,  1491,  1478,  1077,  801    },
	},
	{
		{238,  1131,  1483,  398,  1510,  1651,  1495,  1545,  1970,  2090  },
		{499,  456,  1499,  449,  1558,  1691,  1272,  969,  2114,  2116    },
		{675,  1386,  318,  645,  1449,  1588,  1666,  1925,  979,  859     },
		{467,  957,  1223,  238,  1825,  1704,  1608,  1560,  1665,  1376   },
		{331,  1460,  1238,  627,  787,  1882,  3928,  1544,  1897,  579    },
		{457,  1038,  903,  784,  1158,  725,  955,  1517,  842,  1016      },
		{505,  497,  1131,  812,  1508,  1206,  703,  1072,  1254,  1256    },
		{397,  741,  1336,  642,  1506,  1852,  1340,  599,  1854,  1000    },
		{625,  1212,  597,  750,  1291,  1057,  1401,  1401,  527,  954     },
		{499,  1041,  654,  752,  1299,  1217,  1605,  1424,  1377,  505    },
	},
	{
		{263,  1094,  1218,  602,  938,  1487,  1231,  1016,  1724,  1448   },
		{452,  535,  1728,  562,  1008,  1471,  1473,  873,  3182,  1136    },
		{553,  1570,  935,  1093,  826,  1339,  879,  1007,  1006,  476     },
		{365,  900,  1050,  582,  866,  1398,  1236,  1123,  1608,  1039    },
		{294,  2044,  1790,  1143,  430,  1642,  3688,  1549,  2080,  704   },
		{703,  1210,  958,  815,  1211,  960,  623,  2455,  815,  559       },
		{675,  574,  862,  1261,  866,  864,  761,  1267,  1014,  936       },
		{342,  1254,  1857,  989,  612,  1856,  1858,  553,  1840,  1037    },
		{553,  1316,  811,  1072,  1068,  728,  1328,  1317,  1064,  475    },
		{288,  1303,  1167,  1167,  823,  1634,  1636,  2497,  1294,  491   },
	},
	{
		{227,  1059,  1369,  1066,  1505,  740,  970,  1511,  972,  1775    },
		{516,  587,  1033,  646,  1188,  748,  978,  1445,  1294,  1450     },
		{684,  1048,  663,  747,  1126,  826,  1386,  1128,  635,  924      },
		{494,  814,  933,  510,  1606,  951,  878,  1344,  1031,  1347      },
		{553,  1071,  1327,  726,  809,  3376,  1330,  1324,  1062,  407    },
		{625,  1120,  988,  1121,  1197,  347,  1064,  1308,  862,  1206    },
		{633,  853,  1657,  1073,  1662,  634,  460,  1405,  811,  1155     },
		{505,  621,  1394,  876,  1394,  876,  878,  795,  878,  1399       },
		{684,  1302,  968,  1704,  1280,  561,  972,  1713,  387,  1104     },
		{397,  1447,  1060,  867,  957,  1058,  749,  1475,  1210,  660     },
	},
	{
		{331,  933,  1647,  761,  1647,  998,  513,  1402,  1461,  2219     },
		{573,  485,  1968,  641,  1570,  1198,  588,  1086,  1382,  1982    },
		{790,  942,  570,  790,  1607,  1005,  938,  1193,  714,  751       },
		{511,  745,  1152,  492,  1878,  1206,  596,  1867,  1617,  1157    },
		{452,  1308,  896,  896,  451,  1308,  3354,  1301,  1306,  794     },
		{693,  670,  1072,  1020,  1687,  566,  488,  1432,  1096,  3142    },
		{778,  566,  1993,  1283,  3139,  1251,  227,  1378,  1784,  1447   },
		{393,  937,  1091,  934,  939,  1348,  1092,  579,  1351,  1095     },
		{560,  1013,  1007,  1014,  1011,  644,  1165,  1155,  605,  1016   },
		{567,  627,  997,  793,  2562,  998,  849,  1260,  922,  748        },
	},
	{
		{338,  762,  1868,  717,  1247,  1757,  1263,  535,  1751,  2162    },
		{488,  442,  3235,  756,  1658,  1814,  1264,  528,  1857,  2119    },
		{522,  1087,  840,  1103,  843,  1354,  1098,  888,  946,  588      },
		{483,  688,  1502,  651,  1213,  1446,  1397,  491,  1908,  1253    },
		{452,  1386,  1910,  1175,  298,  1507,  3553,  930,  1904,  905    },
		{713,  839,  716,  715,  932,  719,  931,  848,  3088,  1042        },
		{516,  495,  1331,  1340,  1331,  1069,  665,  702,  1593,  1337    },
		{401,  977,  2167,  1537,  1069,  1764,  3810,  259,  3624,  1578   },
		{560,  1104,  601,  1371,  965,  658,  2704,  779,  967,  969       },
		{547,  1057,  801,  1141,  1133,  1397,  937,  605,  1252,  631     },
	},
	{
		{163,  1240,  925,  983,  1653,  1321,  1353,  1566,  946,  1601    },
		{401,  726,  758,  836,  1241,  926,  1656,  795,  1394,  1396      },
		{905,  1073,  366,  876,  1436,  1576,  1732,  2432,  459,  1019    },
		{594,  922,  835,  417,  1387,  1124,  1098,  2042,  843,  1023     },
		{415,  1262,  860,  1274,  758,  1272,  3318,  1010,  1276,  503    },
		{641,  1018,  1020,  1095,  1619,  667,  1371,  2348,  397,  849    },
		{560,  817,  903,  1014,  1420,  695,  756,  904,  821,  1421       },
		{406,  596,  1001,  993,  1257,  1258,  1260,  746,  1002,  1264    },
		{979,  1371,  780,  1188,  1693,  1024,  1286,  1699,  183,  1405   },
		{733,  1292,  458,  884,  1554,  889,  1151,  1286,  738,  740      },
	},
	{
		{109,  1377,  1177,  933,  1140,  1928,  1639,  1705,  1861,  1292  },
		{342,  570,  1081,  638,  1154,  1231,  1339,  1342,  1750,  1494   },
		{560,  1203,  345,  767,  1325,  1681,  1425,  1905,  1205,  786    },
		{406,  1027,  1011,  410,  1306,  1901,  1389,  1636,  1493,  776   },
		{206,  1329,  1337,  1037,  802,  1600,  3646,  1451,  1603,  693   },
		{472,  1167,  758,  911,  1424,  703,  2749,  1428,  703,  764      },
		{342,  780,  1139,  889,  1290,  1139,  781,  1544,  957,  1042     },
		{227,  888,  1039,  929,  988,  3753,  1707,  818,  1710,  1306     },
		{767,  1055,  627,  725,  1312,  980,  1065,  1324,  599,  811      },
		{304,  1372,  888,  1173,  979,  1578,  1580,  1974,  1318,  482    },
	}
};

static const unsigned char
brc_qpadjustment_distthreshold_maxframethreshold_distqpadjustment_ipb_vp8[576] = {
	0x01, 0x03, 0x05, 0x07, 0x09, 0x01, 0x02, 0x03, 0x05, 0x07, 0x00, 0x00, 0x01, 0x02, 0x04, 0x00,
	0x00, 0x00, 0x01, 0x02, 0xff, 0x00, 0x00, 0x00, 0x01, 0xfd, 0xfe, 0xff, 0x00, 0x00, 0xfb, 0xfc,
	0xfe, 0xff, 0x00, 0xf9, 0xfa, 0xfc, 0xfe, 0xff, 0xf7, 0xf9, 0xfb, 0xfe, 0xff, 0x00, 0x04, 0x1e,
	0x3c, 0x50, 0x78, 0x8c, 0xc8, 0xff, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x01, 0x02, 0x05, 0x08, 0x0a, 0x01, 0x02, 0x04, 0x06, 0x08, 0x00, 0x01, 0x02, 0x04, 0x06, 0x00,
	0x00, 0x00, 0x01, 0x02, 0xff, 0x00, 0x00, 0x00, 0x01, 0xfe, 0xff, 0xff, 0x00, 0x00, 0xfd, 0xfe,
	0xff, 0xff, 0x00, 0xfb, 0xfd, 0xfe, 0xff, 0x00, 0xf9, 0xfa, 0xfc, 0xfe, 0xff, 0x00, 0x04, 0x1e,
	0x3c, 0x50, 0x78, 0x8c, 0xc8, 0xff, 0x04, 0x05, 0x06, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x01, 0x02, 0x05, 0x08, 0x0a, 0x01, 0x02, 0x04, 0x06, 0x08, 0x00, 0x01, 0x02, 0x04, 0x06, 0x00,
	0x00, 0x00, 0x01, 0x02, 0xff, 0x00, 0x00, 0x00, 0x01, 0xfe, 0xff, 0xff, 0x00, 0x00, 0xfd, 0xfe,
	0xff, 0xff, 0x00, 0xfb, 0xfd, 0xfe, 0xff, 0x00, 0xf9, 0xfa, 0xfc, 0xfe, 0xff, 0x00, 0x02, 0x14,
	0x28, 0x46, 0x82, 0xa0, 0xc8, 0xff, 0x04, 0x05, 0x06, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x06, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05,
	0x07, 0x09, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x06, 0x07, 0xfe, 0xff, 0x00, 0x00, 0x00,
	0x01, 0x02, 0x03, 0x05, 0xfd, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x01, 0x03, 0x05, 0xfc, 0xfe, 0xff,
	0x00, 0x00, 0x00, 0x01, 0x03, 0x05, 0xfb, 0xfd, 0xfe, 0xff, 0x00, 0x00, 0x01, 0x03, 0x05, 0xfa,
	0xfc, 0xfe, 0xff, 0x00, 0x00, 0x01, 0x03, 0x05, 0xfa, 0xfc, 0xfe, 0xff, 0x00, 0x00, 0x01, 0x03,
	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x07, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05,
	0x06, 0x08, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x07, 0x08, 0xfe, 0xff, 0x00, 0x00, 0x00,
	0x02, 0x04, 0x05, 0x06, 0xfd, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0xfc, 0xfe, 0xff,
	0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0xfc, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x05, 0xfc,
	0xfd, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x01, 0x05, 0xfb, 0xfc, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x01,
	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x07, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05,
	0x06, 0x08, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x07, 0x08, 0xfe, 0xff, 0x00, 0x00, 0x00,
	0x02, 0x04, 0x05, 0x06, 0xfd, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0xfc, 0xfe, 0xff,
	0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0xfc, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x05, 0xfc,
	0xfd, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x01, 0x05, 0xfb, 0xfc, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x01,
	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

static const unsigned char
brc_iframe_cost_vp8[128][4] = {
	{ 0x5, 0x5, 0x8, 0x8 },
	{ 0xa, 0xa, 0xd, 0xd },
	{ 0xd, 0xf, 0xf, 0x19 },
	{ 0x19, 0x1a, 0x1a, 0x1a },
	{ 0x1b, 0x1b, 0x1d, 0x1d },
	{ 0x1d, 0x1d, 0x1e, 0x1e },
	{ 0x1e, 0x1e, 0x1f, 0x1f },
	{ 0x1f, 0x28, 0x28, 0x29 },
	{ 0x29, 0x29, 0x29, 0x2a },
	{ 0x2a, 0x2b, 0x2b, 0x2b },
	{ 0x2b, 0x2b, 0x2c, 0x2c },
	{ 0x2c, 0x2c, 0x2d, 0x2d },
	{ 0x2e, 0x2e, 0x2e, 0x2e },
	{ 0x2e, 0x2f, 0x2f, 0x38 },
	{ 0x38, 0x38, 0x38, 0x38 },
	{ 0x38, 0x39, 0x39, 0x39 },
	{ 0x39, 0x39, 0x39, 0x3a },
	{ 0x3a, 0x3a, 0x3a, 0x3a },
	{ 0x3a, 0x3a, 0x3a, 0x3b },
	{ 0x3b, 0x3b, 0x3b, 0x3b },
	{ 0x3b, 0x3c, 0x3c, 0x3c },
	{ 0x3c, 0x3c, 0x3c, 0x3c },
	{ 0x3d, 0x3d, 0x3d, 0x3d },
	{ 0x3d, 0x3d, 0x3e, 0x3e },
	{ 0x3e, 0x3e, 0x3f, 0x3f },
	{ 0x3f, 0x48, 0x48, 0x48 },
	{ 0x48, 0x48, 0x48, 0x48 },
	{ 0x49, 0x49, 0x49, 0x49 },
	{ 0x49, 0x49, 0x4a, 0x4a },
	{ 0x4a, 0x4a, 0x4a, 0x4a },
	{ 0x4b, 0x4b, 0x4b, 0x4b },
	{ 0x4b, 0x4c, 0x4c, 0x4c },
	{ 0x1f, 0x1f, 0x2b, 0x2b },
	{ 0x2f, 0x2f, 0x39, 0x39 },
	{ 0x39, 0x3b, 0x3b, 0x3d },
	{ 0x3d, 0x3f, 0x3f, 0x3f },
	{ 0x48, 0x48, 0x49, 0x49 },
	{ 0x49, 0x49, 0x4a, 0x4a },
	{ 0x4a, 0x4a, 0x4b, 0x4b },
	{ 0x4b, 0x4c, 0x4c, 0x4d },
	{ 0x4d, 0x4e, 0x4e, 0x4f },
	{ 0x4f, 0x58, 0x58, 0x58 },
	{ 0x58, 0x58, 0x58, 0x58 },
	{ 0x59, 0x59, 0x59, 0x59 },
	{ 0x5a, 0x5a, 0x5a, 0x5a },
	{ 0x5a, 0x5b, 0x5b, 0x5b },
	{ 0x5b, 0x5c, 0x5c, 0x5c },
	{ 0x5c, 0x5d, 0x5d, 0x5d },
	{ 0x5d, 0x5e, 0x5e, 0x5e },
	{ 0x5e, 0x5f, 0x5f, 0x5f },
	{ 0x5f, 0x68, 0x68, 0x68 },
	{ 0x68, 0x68, 0x68, 0x68 },
	{ 0x68, 0x68, 0x68, 0x68 },
	{ 0x69, 0x69, 0x69, 0x69 },
	{ 0x69, 0x69, 0x69, 0x69 },
	{ 0x6a, 0x6a, 0x6a, 0x6a },
	{ 0x6a, 0x6a, 0x6b, 0x6b },
	{ 0x6b, 0x6b, 0x6b, 0x6c },
	{ 0x6c, 0x6c, 0x6c, 0x6c },
	{ 0x6d, 0x6d, 0x6d, 0x6d },
	{ 0x6e, 0x6e, 0x6e, 0x6f },
	{ 0x6f, 0x6f, 0x6f, 0x6f },
	{ 0x78, 0x78, 0x78, 0x78 },
	{ 0x78, 0x78, 0x79, 0x79 },
	{ 0x2, 0x2, 0x3, 0x3 },
	{ 0x4, 0x4, 0x5, 0x5 },
	{ 0x5, 0x6, 0x6, 0x7 },
	{ 0x7, 0x8, 0x8, 0x8 },
	{ 0x9, 0x9, 0x9, 0x9 },
	{ 0x9, 0x9, 0xa, 0xa },
	{ 0xa, 0xa, 0xb, 0xb },
	{ 0xb, 0xc, 0xc, 0xd },
	{ 0xd, 0xe, 0xe, 0xf },
	{ 0xf, 0x10, 0x10, 0x11 },
	{ 0x11, 0x11, 0x12, 0x12 },
	{ 0x13, 0x13, 0x14, 0x14 },
	{ 0x15, 0x15, 0x16, 0x16 },
	{ 0x16, 0x17, 0x17, 0x18 },
	{ 0x18, 0x19, 0x19, 0x1a },
	{ 0x1a, 0x1a, 0x1a, 0x1b },
	{ 0x1b, 0x1c, 0x1c, 0x1d },
	{ 0x1d, 0x1e, 0x1e, 0x1f },
	{ 0x1f, 0x20, 0x20, 0x21 },
	{ 0x21, 0x22, 0x22, 0x23 },
	{ 0x23, 0x24, 0x24, 0x24 },
	{ 0x25, 0x25, 0x26, 0x26 },
	{ 0x27, 0x27, 0x28, 0x28 },
	{ 0x29, 0x29, 0x2a, 0x2a },
	{ 0x2b, 0x2b, 0x2c, 0x2d },
	{ 0x2e, 0x2f, 0x2f, 0x30 },
	{ 0x31, 0x32, 0x33, 0x34 },
	{ 0x35, 0x36, 0x37, 0x38 },
	{ 0x3a, 0x3b, 0x3c, 0x3d },
	{ 0x3d, 0x3e, 0x3f, 0x40 },
	{ 0x41, 0x42, 0x43, 0x44 },
	{ 0x46, 0x47, 0x49, 0x4a },
	{ 0x9, 0x9, 0xe, 0xe },
	{ 0x12, 0x12, 0x17, 0x17 },
	{ 0x17, 0x1b, 0x1b, 0x20 },
	{ 0x20, 0x24, 0x24, 0x24 },
	{ 0x29, 0x29, 0x2d, 0x2d },
	{ 0x2d, 0x2d, 0x32, 0x32 },
	{ 0x32, 0x32, 0x36, 0x36 },
	{ 0x36, 0x3b, 0x3b, 0x3f },
	{ 0x3f, 0x44, 0x44, 0x48 },
	{ 0x48, 0x4d, 0x4d, 0x51 },
	{ 0x51, 0x51, 0x56, 0x56 },
	{ 0x5a, 0x5a, 0x5f, 0x5f },
	{ 0x63, 0x63, 0x68, 0x68 },
	{ 0x68, 0x6c, 0x6c, 0x71 },
	{ 0x71, 0x76, 0x76, 0x7a },
	{ 0x7a, 0x7f, 0x7f, 0x83 },
	{ 0x83, 0x88, 0x88, 0x8c },
	{ 0x8c, 0x91, 0x91, 0x95 },
	{ 0x95, 0x9a, 0x9a, 0x9e },
	{ 0x9e, 0xa3, 0xa3, 0xa7 },
	{ 0xa7, 0xac, 0xac, 0xac },
	{ 0xb0, 0xb0, 0xb5, 0xb5 },
	{ 0xb9, 0xb9, 0xbe, 0xbe },
	{ 0xc2, 0xc2, 0xc7, 0xc7 },
	{ 0xcb, 0xd0, 0xd4, 0xd9 },
	{ 0xdd, 0xe2, 0xe2, 0xe6 },
	{ 0xeb, 0xf0, 0xf4, 0xf9 },
	{ 0xfd, 0xff, 0xff, 0xff },
	{ 0xff, 0xff, 0xff, 0xff },
	{ 0xff, 0xff, 0xff, 0xff },
	{ 0xff, 0xff, 0xff, 0xff },
	{ 0xff, 0xff, 0xff, 0xff },
};

static const unsigned int
brc_pframe_cost_vp8[256] = {
	0x06040402,
	0x06040402,
	0x06040402,
	0x06040402,
	0x0d080805,
	0x0d080805,
	0x0d080805,
	0x0d080805,
	0x0d080805,
	0x190b0c07,
	0x190b0c07,
	0x190b0c07,
	0x190b0c07,
	0x1c0f0f0a,
	0x1c0f0f0a,
	0x1c0f0f0a,
	0x1c0f0f0a,
	0x1c0f0f0a,
	0x2819190c,
	0x2819190c,
	0x2819190c,
	0x2819190c,
	0x2819190c,
	0x2819190c,
	0x2819190c,
	0x2819190c,
	0x291b1b0f,
	0x291b1b0f,
	0x291b1b0f,
	0x291b1b0f,
	0x291b1b0f,
	0x2b1d1d18,
	0x2b1d1d18,
	0x2b1d1d18,
	0x2b1d1d18,
	0x2c1f1f19,
	0x2c1f1f19,
	0x2c1f1f19,
	0x2c1f1f19,
	0x2e28281b,
	0x2e28281b,
	0x2e28281b,
	0x2e28281b,
	0x2e28281b,
	0x2f29291c,
	0x2f29291c,
	0x2f29291c,
	0x2f29291c,
	0x382a2a1d,
	0x382a2a1d,
	0x382a2a1d,
	0x382a2a1d,
	0x382a2a1d,
	0x392b2b1e,
	0x392b2b1e,
	0x392b2b1e,
	0x392b2b1e,
	0x3a2c2c1f,
	0x3a2c2c1f,
	0x3a2c2c1f,
	0x3a2c2c1f,
	0x3b2d2d28,
	0x3b2d2d28,
	0x3b2d2d28,
	0x3b2d2d28,
	0x3b2e2e29,
	0x3b2e2e29,
	0x3b2e2e29,
	0x3b2e2e29,
	0x3c2f2f29,
	0x3c2f2f29,
	0x3c2f2f29,
	0x3c2f2f29,
	0x3d38382a,
	0x3d38382a,
	0x3d38382a,
	0x3d38382a,
	0x3e38382b,
	0x3e38382b,
	0x3e38382b,
	0x3e38382b,
	0x3f38392b,
	0x3f38392b,
	0x3f38392b,
	0x3f38392b,
	0x3f38392b,
	0x3f39392c,
	0x3f39392c,
	0x3f39392c,
	0x3f39392c,
	0x48393a2c,
	0x48393a2c,
	0x48393a2c,
	0x48393a2c,
	0x483a3a2d,
	0x483a3a2d,
	0x483a3a2d,
	0x493a3b2e,
	0x493a3b2e,
	0x493b3b2e,
	0x493b3b2e,
	0x493b3c2f,
	0x493b3c2f,
	0x493b3c2f,
	0x4a3c3c2f,
	0x4a3c3c2f,
	0x4a3c3d38,
	0x4a3c3d38,
	0x4b3d3d38,
	0x4b3d3d38,
	0x4b3d3e38,
	0x4b3d3e38,
	0x4b3e3e39,
	0x4c3e3e39,
	0x4c3e3e39,
	0x4c3f3f39,
	0x4c3f3f39,
	0x4d3f3f3a,
	0x4d3f3f3a,
	0x4d48483a,
	0x4d48483a,
	0x4d48483a,
	0x4d48483a,
	0x4e48483a,
	0x4e48483b,
	0x4e48483b,
	0x4f48493b,
	0x4f49493b,
	0x1a0c0907,
	0x1a0c0907,
	0x1a0c0907,
	0x1a0c0907,
	0x291b190e,
	0x291b190e,
	0x291b190e,
	0x291b190e,
	0x291b190e,
	0x2e281e1a,
	0x2e281e1a,
	0x2e281e1a,
	0x2e281e1a,
	0x392b291e,
	0x392b291e,
	0x392b291e,
	0x392b291e,
	0x392b291e,
	0x3c2e2b29,
	0x3c2e2b29,
	0x3c2e2b29,
	0x3c2e2b29,
	0x3c2e2b29,
	0x3c2e2b29,
	0x3c2e2b29,
	0x3c2e2b29,
	0x3e382e2a,
	0x3e382e2a,
	0x3e382e2a,
	0x3e382e2a,
	0x3e382e2a,
	0x483a382c,
	0x483a382c,
	0x483a382c,
	0x483a382c,
	0x493b392e,
	0x493b392e,
	0x493b392e,
	0x493b392e,
	0x4b3d3a38,
	0x4b3d3a38,
	0x4b3d3a38,
	0x4b3d3a38,
	0x4b3d3a38,
	0x4c3e3b38,
	0x4c3e3b38,
	0x4c3e3b38,
	0x4c3e3b38,
	0x4d483c39,
	0x4d483c39,
	0x4d483c39,
	0x4d483c39,
	0x4d483c39,
	0x4e483e3a,
	0x4e483e3a,
	0x4e483e3a,
	0x4e483e3a,
	0x4f493f3b,
	0x4f493f3b,
	0x4f493f3b,
	0x4f493f3b,
	0x584a483c,
	0x584a483c,
	0x584a483c,
	0x584a483c,
	0x594b483d,
	0x594b483d,
	0x594b483d,
	0x594b483d,
	0x594b493e,
	0x594b493e,
	0x594b493e,
	0x594b493e,
	0x5a4c493f,
	0x5a4c493f,
	0x5a4c493f,
	0x5a4c493f,
	0x5b4d4a48,
	0x5b4d4a48,
	0x5b4d4a48,
	0x5b4d4a48,
	0x5b4d4b48,
	0x5b4d4b48,
	0x5b4d4b48,
	0x5b4d4b48,
	0x5b4d4b48,
	0x5c4e4b48,
	0x5c4e4b48,
	0x5c4e4b48,
	0x5c4e4b48,
	0x5c4f4c49,
	0x5c4f4c49,
	0x5c4f4c49,
	0x5c4f4c49,
	0x5d584c49,
	0x5d584c49,
	0x5d584c49,
	0x5e584d4a,
	0x5e584d4a,
	0x5e584e4a,
	0x5e584e4a,
	0x5f594e4b,
	0x5f594e4b,
	0x5f594e4b,
	0x5f594f4b,
	0x5f594f4b,
	0x68594f4c,
	0x68594f4c,
	0x685a584c,
	0x685a584c,
	0x685a584c,
	0x685a584c,
	0x695b584d,
	0x695b594d,
	0x695b594d,
	0x695b594e,
	0x695b594e,
	0x6a5c594e,
	0x6a5c594e,
	0x6a5c594f,
	0x6a5c594f,
	0x6a5c5a4f,
	0x6a5c5a4f,
	0x6a5d5a58,
	0x6b5d5a58,
	0x6b5d5a58,
	0x6b5d5b58,
	0x6b5e5b58,
};

static const unsigned short
brc_skip_mv_threshold_vp8[256] = {
	111,  120,  129,  137,  146,  155,  163,  172,  180,  189,  198,  206,  215,  224,  232,  241,
	249,  258,  267,  275,  284,  293,  301,  310,  318,  327,  336,  344,  353,  362,  370,  379,
	387,  396,  405,  413,  422,  431,  439,  448,  456,  465,  474,  482,  491,  500,  508,  517,
	525,  534,  543,  551,  560,  569,  577,  586,  594,  603,  612,  620,  629,  638,  646,  655,
	663,  672,  681,  689,  698,  707,  715,  724,  733,  741,  750,  758,  767,  776,  784,  793,
	802,  810,  819,  827,  836,  845,  853,  862,  871,  879,  888,  896,  905,  914,  922,  931,
	940,  948,  957,  965,  974,  983,  991, 1000, 1009, 1017, 1026, 1034, 1043, 1052, 1060, 1069,
	1078, 1086, 1095, 1103, 1112, 1121, 1129, 1138, 1147, 1155, 1164, 1172, 1181, 1190, 1198, 1208
};

void
i965_encoder_vp8_check_motion_estimation(VADriverContextP ctx, struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;

	if (vp8_context->down_scaled_width_4x < vp8_context->min_scaled_dimension  ||
		vp8_context->down_scaled_width_in_mb4x < vp8_context->min_scaled_dimension_in_mbs ||
		vp8_context->down_scaled_height_4x < vp8_context->min_scaled_dimension ||
		vp8_context->down_scaled_height_in_mb4x < vp8_context->min_scaled_dimension_in_mbs) {

		vp8_context->hme_16x_supported = 0;

		if (vp8_context->down_scaled_width_4x < vp8_context->min_scaled_dimension  ||
			vp8_context->down_scaled_width_in_mb4x < vp8_context->min_scaled_dimension_in_mbs) {

			vp8_context->down_scaled_width_4x = vp8_context->min_scaled_dimension;
			vp8_context->down_scaled_width_in_mb4x = vp8_context->min_scaled_dimension_in_mbs;
		}

		if (vp8_context->down_scaled_height_4x < vp8_context->min_scaled_dimension ||
			vp8_context->down_scaled_height_in_mb4x < vp8_context->min_scaled_dimension_in_mbs) {

			vp8_context->down_scaled_height_4x = vp8_context->min_scaled_dimension;
			vp8_context->down_scaled_height_in_mb4x = vp8_context->min_scaled_dimension_in_mbs;
		}
	} else if (vp8_context->down_scaled_width_16x < vp8_context->min_scaled_dimension ||
			   vp8_context->down_scaled_width_in_mb16x < vp8_context->min_scaled_dimension_in_mbs ||
			   vp8_context->down_scaled_height_16x < vp8_context->min_scaled_dimension ||
			   vp8_context->down_scaled_height_in_mb16x < vp8_context->min_scaled_dimension_in_mbs) {

		if (vp8_context->down_scaled_width_16x < vp8_context->min_scaled_dimension ||
			vp8_context->down_scaled_width_in_mb16x < vp8_context->min_scaled_dimension_in_mbs) {

			vp8_context->down_scaled_width_16x = vp8_context->min_scaled_dimension;
			vp8_context->down_scaled_width_in_mb16x = vp8_context->min_scaled_dimension_in_mbs;
		}

		if (vp8_context->down_scaled_height_16x < vp8_context->min_scaled_dimension ||
			vp8_context->down_scaled_height_in_mb16x < vp8_context->min_scaled_dimension_in_mbs) {

			vp8_context->down_scaled_height_16x = vp8_context->min_scaled_dimension;
			vp8_context->down_scaled_height_in_mb16x = vp8_context->min_scaled_dimension_in_mbs;
		}
	}
}

static void
i965_encoder_vp8_free_surfaces(void **data)
{
	struct i965_encoder_vp8_surface *vp8_surface;

	if (!data || !(*data))
		return;

	vp8_surface = *data;

	if (vp8_surface->scaled_4x_surface_obj) {
		i965_DestroySurfaces(vp8_surface->ctx, &vp8_surface->scaled_4x_surface_id, 1);
		vp8_surface->scaled_4x_surface_id = VA_INVALID_SURFACE;
		vp8_surface->scaled_4x_surface_obj = NULL;
	}

	if (vp8_surface->scaled_16x_surface_obj) {
		i965_DestroySurfaces(vp8_surface->ctx, &vp8_surface->scaled_16x_surface_id, 1);
		vp8_surface->scaled_16x_surface_id = VA_INVALID_SURFACE;
		vp8_surface->scaled_16x_surface_obj = NULL;
	}

	free(vp8_surface);
}

static void
i965_encoder_vp8_allocate_surfaces(VADriverContextP ctx,
								   struct intel_encoder_context *encoder_context,
								   struct object_surface *obj_surface,
								   int forced_free)
{
	struct i965_driver_data *i965 = i965_driver_data(ctx);
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_surface *vp8_surface;
	int down_scaled_width_4x, down_scaled_height_4x;
	int down_scaled_width_16x, down_scaled_height_16x;

	if (!obj_surface)
		return;

	if (obj_surface->private_data && obj_surface->free_private_data) {
		if (forced_free && obj_surface->free_private_data != i965_encoder_vp8_free_surfaces)
			obj_surface->free_private_data(obj_surface->private_data);
		else
			return;
	}

	vp8_surface = calloc(1, sizeof(struct i965_encoder_vp8_surface));

	if (!vp8_surface) {
		obj_surface->private_data = NULL;
		obj_surface->free_private_data = NULL;

		return;
	}

	vp8_surface->ctx = ctx;

	down_scaled_width_4x = vp8_context->down_scaled_width_4x;
	down_scaled_height_4x = vp8_context->down_scaled_height_4x;
	i965_CreateSurfaces(ctx,
						down_scaled_width_4x,
						down_scaled_height_4x,
						VA_RT_FORMAT_YUV420,
						1,
						&vp8_surface->scaled_4x_surface_id);
	vp8_surface->scaled_4x_surface_obj = SURFACE(vp8_surface->scaled_4x_surface_id);

	if (vp8_surface->scaled_4x_surface_obj)
		i965_check_alloc_surface_bo(ctx, vp8_surface->scaled_4x_surface_obj, 1,
									VA_FOURCC('N', 'V', '1', '2'), SUBSAMPLE_YUV420);

	down_scaled_width_16x = vp8_context->down_scaled_width_16x;
	down_scaled_height_16x = vp8_context->down_scaled_height_16x;
	i965_CreateSurfaces(ctx,
						down_scaled_width_16x,
						down_scaled_height_16x,
						VA_RT_FORMAT_YUV420,
						1,
						&vp8_surface->scaled_16x_surface_id);
	vp8_surface->scaled_16x_surface_obj = SURFACE(vp8_surface->scaled_16x_surface_id);

	if (vp8_surface->scaled_16x_surface_obj)
		i965_check_alloc_surface_bo(ctx, vp8_surface->scaled_16x_surface_obj, 1,
									VA_FOURCC('N', 'V', '1', '2'), SUBSAMPLE_YUV420);

	obj_surface->private_data = vp8_surface;
	obj_surface->free_private_data = i965_encoder_vp8_free_surfaces;
}

static void
i965_encoder_vp8_read_encode_status(VADriverContextP ctx, struct intel_encoder_context *encoder_context)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct i965_encoder_vp8_encode_status_buffer *encode_status_buffer = &vp8_context->encode_status_buffer;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct gpe_mi_store_register_mem_parameter mi_store_register_mem_param;
	struct gpe_mi_flush_dw_parameter mi_flush_dw_param;
	unsigned int base_offset;

	base_offset = encode_status_buffer->base_offset;

	memset(&mi_flush_dw_param, 0, sizeof(mi_flush_dw_param));
	gpe->mi_flush_dw(ctx, batch, &mi_flush_dw_param);

	memset(&mi_store_register_mem_param, 0, sizeof(mi_store_register_mem_param));
	mi_store_register_mem_param.bo = encode_status_buffer->bo;
	mi_store_register_mem_param.offset = base_offset + encode_status_buffer->bitstream_byte_count_offset;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFC_BITSTREAM_BYTECOUNT_FRAME_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	mi_store_register_mem_param.offset = base_offset + encode_status_buffer->image_status_mask_offset;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFC_IMAGE_STATUS_MASK_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	mi_store_register_mem_param.offset = base_offset + encode_status_buffer->image_status_ctrl_offset;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFC_IMAGE_STATUS_CTRL_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	memset(&mi_flush_dw_param, 0, sizeof(mi_flush_dw_param));
	gpe->mi_flush_dw(ctx, batch, &mi_flush_dw_param);
}

static void
i965_encoder_vp8_read_pak_statistics(VADriverContextP ctx,
									 struct intel_encoder_context *encoder_context,
									 int ipass)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct gpe_mi_store_data_imm_parameter mi_store_data_imm_param;
	struct gpe_mi_store_register_mem_parameter mi_store_register_mem_param;
	struct gpe_mi_flush_dw_parameter mi_flush_dw_param;

	memset(&mi_flush_dw_param, 0, sizeof(mi_flush_dw_param));
	gpe->mi_flush_dw(ctx, batch, &mi_flush_dw_param);

	if (ipass < vp8_context->num_brc_pak_passes) {
		memset(&mi_store_data_imm_param, 0, sizeof(mi_store_data_imm_param));
		mi_store_data_imm_param.bo = vp8_context->brc_pak_statistics_buffer.bo;
		mi_store_data_imm_param.offset = sizeof(unsigned int) * 2;
		mi_store_data_imm_param.dw0 = (ipass + 1) << 8;
		gpe->mi_store_data_imm(ctx, batch, &mi_store_data_imm_param);
	}

	memset(&mi_store_register_mem_param, 0, sizeof(mi_store_register_mem_param));
	mi_store_register_mem_param.bo = vp8_context->brc_pak_statistics_buffer.bo;
	mi_store_register_mem_param.offset = 0;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFC_BITSTREAM_BYTECOUNT_FRAME_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	mi_store_register_mem_param.offset = sizeof(unsigned int) * 5;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_DQ_INDEX_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	mi_store_register_mem_param.offset = sizeof(unsigned int) * 6;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_D_LOOP_FILTER_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	if (ipass == 0) {
		mi_store_register_mem_param.offset = sizeof(unsigned int) * 4;
		mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CUMULATIVE_DQ_INDEX01_REG_OFFSET;
		gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);
	}

	mi_store_register_mem_param.offset = sizeof(unsigned int) * 9;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CUMULATIVE_DQ_INDEX01_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	mi_store_register_mem_param.offset = sizeof(unsigned int) * 10;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CUMULATIVE_DQ_INDEX23_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	mi_store_register_mem_param.offset = sizeof(unsigned int) * 11;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CUMULATIVE_D_LOOP_FILTER01_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	mi_store_register_mem_param.offset = sizeof(unsigned int) * 12;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CUMULATIVE_D_LOOP_FILTER23_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

	mi_store_register_mem_param.offset = sizeof(unsigned int) * 13;
	mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CONVERGENCE_STATUS_REG_OFFSET;
	gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);
}

static void
i965_encoder_vp8_gpe_context_init_once(VADriverContextP ctx,
									   struct i965_gpe_context *gpe_context,
									   struct vp8_encoder_kernel_parameters *kernel_params,
									   unsigned int idrt_entry_size)
{
	struct i965_driver_data *i965 = i965_driver_data(ctx);

	gpe_context->curbe.length = kernel_params->curbe_size; // in bytes

	gpe_context->sampler.entry_size = 0;
	gpe_context->sampler.max_entries = 0;

	gpe_context->idrt.entry_size = idrt_entry_size;
	gpe_context->idrt.max_entries = NUM_KERNELS_PER_GPE_CONTEXT;

	gpe_context->surface_state_binding_table.max_entries = MAX_VP8_ENCODER_SURFACES;
	gpe_context->surface_state_binding_table.binding_table_offset = 0;
	gpe_context->surface_state_binding_table.surface_state_offset = gpe_context->surface_state_binding_table.binding_table_offset +
																	ALIGN(MAX_VP8_ENCODER_SURFACES * 4, 64);
	gpe_context->surface_state_binding_table.length = ALIGN(MAX_VP8_ENCODER_SURFACES * 4, 64) + ALIGN(MAX_VP8_ENCODER_SURFACES * SURFACE_STATE_PADDED_SIZE_GEN8, 64);

	if (i965->intel.eu_total > 0)
		gpe_context->vfe_state.max_num_threads = 6 * i965->intel.eu_total;
	else
		gpe_context->vfe_state.max_num_threads = 112;

	gpe_context->vfe_state.curbe_allocation_size = ALIGN(gpe_context->curbe.length, 32) >> 5; // in registers
	gpe_context->vfe_state.urb_entry_size = MAX(1, (ALIGN(kernel_params->inline_data_size, 32) +
													ALIGN(kernel_params->external_data_size, 32)) >> 5); // in registers
	gpe_context->vfe_state.num_urb_entries = (MAX_URB_SIZE -
											  gpe_context->vfe_state.curbe_allocation_size -
											  ((gpe_context->idrt.entry_size >> 5) *
											   gpe_context->idrt.max_entries)) / gpe_context->vfe_state.urb_entry_size;
	gpe_context->vfe_state.num_urb_entries = CLAMP(gpe_context->vfe_state.num_urb_entries, 1, 64);
	gpe_context->vfe_state.gpgpu_mode = 0;
}

static void
i965_encoder_vp8_gpe_context_vfe_scoreboard_init(struct i965_gpe_context *gpe_context, struct vp8_encoder_scoreboard_parameters *scoreboard_params)
{
	gpe_context->vfe_desc5.scoreboard0.mask = scoreboard_params->mask;
	gpe_context->vfe_desc5.scoreboard0.type = scoreboard_params->type;
	gpe_context->vfe_desc5.scoreboard0.enable = scoreboard_params->enable;

	// Scoreboard 0
	gpe_context->vfe_desc6.scoreboard1.delta_x0 = -1;
	gpe_context->vfe_desc6.scoreboard1.delta_y0 = 0;

	// Scoreboard 1
	gpe_context->vfe_desc6.scoreboard1.delta_x1 = 0;
	gpe_context->vfe_desc6.scoreboard1.delta_y1 = -1;

	// Scoreboard 2
	gpe_context->vfe_desc6.scoreboard1.delta_x2 = 1;
	gpe_context->vfe_desc6.scoreboard1.delta_y2 = -1;

	// Scoreboard 3
	gpe_context->vfe_desc6.scoreboard1.delta_x3 = -1;
	gpe_context->vfe_desc6.scoreboard1.delta_y3 = -1;

	// Scoreboard 4
	gpe_context->vfe_desc7.scoreboard2.delta_x4 = -1;
	gpe_context->vfe_desc7.scoreboard2.delta_y4 = 1;

	// Scoreboard 5
	gpe_context->vfe_desc7.scoreboard2.delta_x5 = 0;
	gpe_context->vfe_desc7.scoreboard2.delta_y5 = -2;
	// Scoreboard 6
	gpe_context->vfe_desc7.scoreboard2.delta_x6 = 1;
	gpe_context->vfe_desc7.scoreboard2.delta_y6 = -2;
	// Scoreboard 7
	gpe_context->vfe_desc7.scoreboard2.delta_x6 = -1;
	gpe_context->vfe_desc7.scoreboard2.delta_y6 = -2;
}

static void
i965_add_dri_buffer_gpe_surface(VADriverContextP ctx,
								struct intel_encoder_context *encoder_context,
								struct i965_gpe_context *gpe_context,
								dri_bo *bo,
								int is_raw_buffer,
								unsigned int size,
								unsigned int offset,
								int index)
{
	struct i965_gpe_resource gpe_resource;

	i965_dri_object_to_buffer_gpe_resource(&gpe_resource, bo);
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&gpe_resource,
								is_raw_buffer,
								size,
								offset,
								index);

	i965_free_gpe_resource(&gpe_resource);
}

static void
i965_add_dri_buffer_2d_gpe_surface(VADriverContextP ctx,
								   struct intel_encoder_context *encoder_context,
								   struct i965_gpe_context *gpe_context,
								   dri_bo *bo,
								   unsigned int width,
								   unsigned int height,
								   unsigned int pitch,
								   int is_media_block_rw,
								   unsigned int format,
								   int index)
{
	struct i965_gpe_resource gpe_resource;

	i965_dri_object_to_2d_gpe_resource(&gpe_resource, bo, width, height, pitch);
	i965_add_buffer_2d_gpe_surface(ctx,
								   gpe_context,
								   &gpe_resource,
								   is_media_block_rw,
								   format,
								   index);

	i965_free_gpe_resource(&gpe_resource);
}

static void
i965_run_kernel_media_object(VADriverContextP ctx,
							 struct intel_encoder_context *encoder_context,
							 struct i965_gpe_context *gpe_context,
							 int media_function,
							 struct gpe_media_object_parameter *param)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct intel_batchbuffer *batch = encoder_context->base.batch;

	intel_batchbuffer_start_atomic(batch, 0x1000);

	intel_batchbuffer_emit_mi_flush(batch);
	gpe->pipeline_setup(ctx, gpe_context, batch);
	gpe->media_object(ctx, gpe_context, batch, param);
	gpe->media_state_flush(ctx, gpe_context, batch);
	gpe->pipeline_end(ctx, gpe_context, batch);

	intel_batchbuffer_end_atomic(batch);

	intel_batchbuffer_flush(batch);
}

static void
i965_init_media_object_walker_parameters(struct intel_encoder_context *encoder_context,
										 struct vp8_encoder_kernel_walker_parameter *kernel_walker_param,
										 struct gpe_media_object_walker_parameter *walker_param)
{
	memset(walker_param, 0, sizeof(*walker_param));

	walker_param->use_scoreboard = kernel_walker_param->use_scoreboard;

	walker_param->block_resolution.x = kernel_walker_param->resolution_x;
	walker_param->block_resolution.y = kernel_walker_param->resolution_y;

	walker_param->global_resolution.x = kernel_walker_param->resolution_x;
	walker_param->global_resolution.y = kernel_walker_param->resolution_y;

	walker_param->global_outer_loop_stride.x = kernel_walker_param->resolution_x;
	walker_param->global_outer_loop_stride.y = 0;

	walker_param->global_inner_loop_unit.x = 0;
	walker_param->global_inner_loop_unit.y = kernel_walker_param->resolution_y;

	walker_param->local_loop_exec_count = 0xFFFF;  //MAX VALUE
	walker_param->global_loop_exec_count = 0xFFFF;  //MAX VALUE

	if (kernel_walker_param->no_dependency) {
		walker_param->scoreboard_mask = 0;

		// Raster scan walking pattern
		walker_param->local_outer_loop_stride.x = 0;
		walker_param->local_outer_loop_stride.y = 1;
		walker_param->local_inner_loop_unit.x = 1;
		walker_param->local_inner_loop_unit.y = 0;
		walker_param->local_end.x = kernel_walker_param->resolution_x - 1;
		walker_param->local_end.y = 0;
	} else {
		walker_param->local_end.x = 0;
		walker_param->local_end.y = 0;

		if (kernel_walker_param->walker_degree == VP8_ENCODER_46_DEGREE) {
			// 46 degree
			walker_param->scoreboard_mask = kernel_walker_param->scoreboard_mask;
			walker_param->local_outer_loop_stride.x = 1;
			walker_param->local_outer_loop_stride.y = 0;
			walker_param->local_inner_loop_unit.x = -1;
			walker_param->local_inner_loop_unit.y = 1;
		} else if (kernel_walker_param->walker_degree == VP8_ENCODER_45Z_DEGREE) {
			// 45z degree
			walker_param->scoreboard_mask = 0x0F;

			walker_param->global_loop_exec_count = 0x3FF;
			walker_param->local_loop_exec_count = 0x3FF;

			walker_param->global_resolution.x = (unsigned int)(kernel_walker_param->resolution_x / 2.f) + 1;
			walker_param->global_resolution.y = 2 * kernel_walker_param->resolution_y;

			walker_param->global_start.x = 0;
			walker_param->global_start.y = 0;

			walker_param->global_outer_loop_stride.x = walker_param->global_resolution.x;
			walker_param->global_outer_loop_stride.y = 0;

			walker_param->global_inner_loop_unit.x = 0;
			walker_param->global_inner_loop_unit.y = walker_param->global_resolution.y;

			walker_param->block_resolution.x = walker_param->global_resolution.x;
			walker_param->block_resolution.y = walker_param->global_resolution.y;

			walker_param->local_start.x = 0;
			walker_param->local_start.y = 0;

			walker_param->local_outer_loop_stride.x = 1;
			walker_param->local_outer_loop_stride.y = 0;

			walker_param->local_inner_loop_unit.x = -1;
			walker_param->local_inner_loop_unit.y = 4;

			walker_param->middle_loop_extra_steps = 3;
			walker_param->mid_loop_unit_x = 0;
			walker_param->mid_loop_unit_y = 1;
		} else if (kernel_walker_param->walker_degree == VP8_ENCODER_45_DEGREE) {
			// 45 degree
			walker_param->scoreboard_mask = 0x03;
			walker_param->local_outer_loop_stride.x = 1;
			walker_param->local_outer_loop_stride.y = 0;
			walker_param->local_inner_loop_unit.x = -1;
			walker_param->local_inner_loop_unit.y = 1;
		} else {
			// 26 degree
			walker_param->scoreboard_mask = 0x0F;
			walker_param->local_outer_loop_stride.x = 1;
			walker_param->local_outer_loop_stride.y = 0;
			walker_param->local_inner_loop_unit.x = -2;
			walker_param->local_inner_loop_unit.y = 1;
		}
	}
}

static void
i965_run_kernel_media_object_walker(VADriverContextP ctx,
									struct intel_encoder_context *encoder_context,
									struct i965_gpe_context *gpe_context,
									int media_function,
									struct gpe_media_object_walker_parameter *param)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct intel_batchbuffer *batch = encoder_context->base.batch;

	intel_batchbuffer_start_atomic(batch, 0x1000);

	intel_batchbuffer_emit_mi_flush(batch);
	gpe->pipeline_setup(ctx, gpe_context, batch);
	gpe->media_object_walker(ctx, gpe_context, batch, param);
	gpe->media_state_flush(ctx, gpe_context, batch);
	gpe->pipeline_end(ctx, gpe_context, batch);

	intel_batchbuffer_end_atomic(batch);

	intel_batchbuffer_flush(batch);
}

static void
i965_encoder_vp8_vme_init_mpu_tpu_buffer(VADriverContextP ctx,
										 struct intel_encoder_context *encoder_context,
										 struct i965_encoder_vp8_context *vp8_context)
{
	char *pbuffer = NULL;

	i965_zero_gpe_resource(&vp8_context->pak_mpu_tpu_mode_probs_buffer);
	i965_zero_gpe_resource(&vp8_context->pak_mpu_tpu_ref_mode_probs_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_ref_coeff_probs_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, vp8_default_coef_probs, sizeof(vp8_default_coef_probs));
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_ref_coeff_probs_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_entropy_cost_table_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, vp8_prob_cost, sizeof(vp8_prob_cost));
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_entropy_cost_table_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_pak_token_update_flags_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, vp8_probs_update_flag, sizeof(vp8_probs_update_flag));
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_pak_token_update_flags_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_default_token_probability_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, vp8_coef_update_probs, sizeof(vp8_coef_update_probs));
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_default_token_probability_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_key_frame_token_probability_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, vp8_default_coef_probs, sizeof(vp8_default_coef_probs));
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_key_frame_token_probability_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_updated_token_probability_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, vp8_default_coef_probs, sizeof(vp8_default_coef_probs));
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_updated_token_probability_buffer);
}

#define ALLOC_VP8_RESOURCE_BUFFER(buffer, bufsize, des)         \
	do {                                                        \
		vp8_context->buffer.type = I965_GPE_RESOURCE_BUFFER;    \
		vp8_context->buffer.width = (bufsize);                  \
		vp8_context->buffer.height = 1;                         \
		vp8_context->buffer.pitch = vp8_context->buffer.width;  \
		vp8_context->buffer.size = vp8_context->buffer.pitch *  \
			vp8_context->buffer.height;                         \
		vp8_context->buffer.tiling = I915_TILING_NONE;          \
		i965_allocate_gpe_resource(i965->intel.bufmgr,          \
								   &vp8_context->buffer,        \
								   vp8_context->buffer.size,    \
								   (des));                      \
	} while (0)

static void
i965_encoder_vp8_vme_allocate_resources(VADriverContextP ctx,
										struct intel_encoder_context *encoder_context,
										struct i965_encoder_vp8_context *vp8_context)
{
	struct i965_driver_data *i965 = i965_driver_data(ctx);
	unsigned int frame_size_in_mbs = vp8_context->frame_width_in_mbs *
									 vp8_context->frame_height_in_mbs;

	vp8_context->mv_offset = ALIGN((frame_size_in_mbs * 16 * 4), 4096);
	vp8_context->mb_coded_buffer_size = vp8_context->mv_offset + (frame_size_in_mbs * 16 * sizeof(unsigned int));

	ALLOC_VP8_RESOURCE_BUFFER(reference_frame_mb_count_buffer, 32, "Reference frame mb count buffer");

	vp8_context->mb_mode_cost_luma_buffer.type = I965_GPE_RESOURCE_2D;
	vp8_context->mb_mode_cost_luma_buffer.width = ALIGN((sizeof(short) * 10), 64);
	vp8_context->mb_mode_cost_luma_buffer.height = 1;
	vp8_context->mb_mode_cost_luma_buffer.pitch = vp8_context->mb_mode_cost_luma_buffer.width;
	vp8_context->mb_mode_cost_luma_buffer.size = vp8_context->mb_mode_cost_luma_buffer.pitch *
												 vp8_context->mb_mode_cost_luma_buffer.height;
	vp8_context->mb_mode_cost_luma_buffer.tiling = I915_TILING_NONE;
	i965_allocate_gpe_resource(i965->intel.bufmgr,
							   &vp8_context->mb_mode_cost_luma_buffer,
							   vp8_context->mb_mode_cost_luma_buffer.size,
							   "MB mode cost luma buffer");

	vp8_context->block_mode_cost_buffer.type = I965_GPE_RESOURCE_2D;
	vp8_context->block_mode_cost_buffer.width = ALIGN((sizeof(short) * 10 * 10 * 10), 64);
	vp8_context->block_mode_cost_buffer.height = 1;
	vp8_context->block_mode_cost_buffer.pitch = vp8_context->block_mode_cost_buffer.width;
	vp8_context->block_mode_cost_buffer.size = vp8_context->block_mode_cost_buffer.pitch *
											   vp8_context->block_mode_cost_buffer.height;
	vp8_context->block_mode_cost_buffer.tiling = I915_TILING_NONE;
	i965_allocate_gpe_resource(i965->intel.bufmgr,
							   &vp8_context->block_mode_cost_buffer,
							   vp8_context->block_mode_cost_buffer.size,
							   "Block mode cost luma buffer");

	ALLOC_VP8_RESOURCE_BUFFER(chroma_recon_buffer, frame_size_in_mbs * 64, "Chroma recon buffer");

	vp8_context->per_mb_quant_data_buffer.type = I965_GPE_RESOURCE_2D;
	vp8_context->per_mb_quant_data_buffer.width = ALIGN((vp8_context->frame_width_in_mbs * 4), 64);
	vp8_context->per_mb_quant_data_buffer.height = vp8_context->frame_height_in_mbs;
	vp8_context->per_mb_quant_data_buffer.pitch = vp8_context->per_mb_quant_data_buffer.width;
	vp8_context->per_mb_quant_data_buffer.size = vp8_context->per_mb_quant_data_buffer.pitch *
												 vp8_context->per_mb_quant_data_buffer.height;
	vp8_context->per_mb_quant_data_buffer.tiling = I915_TILING_NONE;
	i965_allocate_gpe_resource(i965->intel.bufmgr,
							   &vp8_context->per_mb_quant_data_buffer,
							   vp8_context->per_mb_quant_data_buffer.size,
							   "Per MB quant data buffer");

	ALLOC_VP8_RESOURCE_BUFFER(pred_mv_data_buffer, frame_size_in_mbs * 4 * sizeof(unsigned int), "Pred mv data buffer");
	ALLOC_VP8_RESOURCE_BUFFER(mode_cost_update_buffer, 16 * sizeof(unsigned int), "Mode cost update buffer");

	/*
	 * BRC buffers
	 */
	ALLOC_VP8_RESOURCE_BUFFER(brc_history_buffer, VP8_BRC_HISTORY_BUFFER_SIZE, "BRC history buffer");
	i965_zero_gpe_resource(&vp8_context->brc_history_buffer);

	vp8_context->brc_segment_map_buffer.type = I965_GPE_RESOURCE_2D;
	vp8_context->brc_segment_map_buffer.width = vp8_context->frame_width_in_mbs;
	vp8_context->brc_segment_map_buffer.height = vp8_context->frame_height_in_mbs;
	vp8_context->brc_segment_map_buffer.pitch = vp8_context->brc_segment_map_buffer.width;
	vp8_context->brc_segment_map_buffer.size = vp8_context->brc_segment_map_buffer.pitch *
											   vp8_context->brc_segment_map_buffer.height;
	vp8_context->brc_segment_map_buffer.tiling = I915_TILING_NONE;
	i965_allocate_gpe_resource(i965->intel.bufmgr,
							   &vp8_context->brc_segment_map_buffer,
							   vp8_context->brc_segment_map_buffer.size,
							   "BRC segment map buffer");

	vp8_context->brc_distortion_buffer.type = I965_GPE_RESOURCE_2D;
	vp8_context->brc_distortion_buffer.width = ALIGN((vp8_context->down_scaled_width_in_mb4x * 8), 64);
	vp8_context->brc_distortion_buffer.height = 2 * ALIGN((vp8_context->down_scaled_height_in_mb4x * 4), 8);
	vp8_context->brc_distortion_buffer.pitch = vp8_context->brc_distortion_buffer.width;
	vp8_context->brc_distortion_buffer.size = vp8_context->brc_distortion_buffer.pitch *
											  vp8_context->brc_distortion_buffer.height;
	vp8_context->brc_distortion_buffer.tiling = I915_TILING_NONE;
	i965_allocate_gpe_resource(i965->intel.bufmgr,
							   &vp8_context->brc_distortion_buffer,
							   vp8_context->brc_distortion_buffer.size,
							   "BRC distortion buffer");
	i965_zero_gpe_resource(&vp8_context->brc_distortion_buffer);

	ALLOC_VP8_RESOURCE_BUFFER(brc_pak_statistics_buffer, sizeof(struct vp8_brc_pak_statistics), "BRC pak statistics buffer");
	i965_zero_gpe_resource(&vp8_context->brc_pak_statistics_buffer);

	ALLOC_VP8_RESOURCE_BUFFER(brc_vp8_cfg_command_read_buffer, VP8_BRC_IMG_STATE_SIZE_PER_PASS * VP8_BRC_MAXIMUM_NUM_PASSES, "BRC VP8 configuration command read buffer");
	i965_zero_gpe_resource(&vp8_context->brc_vp8_cfg_command_read_buffer);

	ALLOC_VP8_RESOURCE_BUFFER(brc_vp8_cfg_command_write_buffer, VP8_BRC_IMG_STATE_SIZE_PER_PASS * VP8_BRC_MAXIMUM_NUM_PASSES, "BRC VP8 configuration command write buffer");
	i965_zero_gpe_resource(&vp8_context->brc_vp8_cfg_command_write_buffer);

	ALLOC_VP8_RESOURCE_BUFFER(brc_vp8_constant_data_buffer, VP8_BRC_CONSTANT_DATA_SIZE, "BRC VP8 constant data buffer");
	i965_zero_gpe_resource(&vp8_context->brc_vp8_constant_data_buffer);

	ALLOC_VP8_RESOURCE_BUFFER(brc_pak_statistics_dump_buffer, vp8_context->num_brc_pak_passes * sizeof(unsigned int) * 12, "BRC pak statistics buffer");
	i965_zero_gpe_resource(&vp8_context->brc_pak_statistics_dump_buffer);

	vp8_context->me_4x_mv_data_buffer.type = I965_GPE_RESOURCE_2D;
	vp8_context->me_4x_mv_data_buffer.width = vp8_context->down_scaled_width_in_mb4x * 32;
	vp8_context->me_4x_mv_data_buffer.height = vp8_context->down_scaled_height_in_mb4x * 4 * 4;
	vp8_context->me_4x_mv_data_buffer.pitch = ALIGN(vp8_context->me_4x_mv_data_buffer.width, 64);
	vp8_context->me_4x_mv_data_buffer.size = vp8_context->me_4x_mv_data_buffer.pitch *
											 vp8_context->me_4x_mv_data_buffer.height;
	vp8_context->me_4x_mv_data_buffer.tiling = I915_TILING_NONE;
	i965_allocate_gpe_resource(i965->intel.bufmgr,
							   &vp8_context->me_4x_mv_data_buffer,
							   vp8_context->me_4x_mv_data_buffer.size,
							   "ME 4x MV Data buffer");

	vp8_context->me_4x_distortion_buffer.type = I965_GPE_RESOURCE_2D;
	vp8_context->me_4x_distortion_buffer.width = vp8_context->down_scaled_width_in_mb4x * 8;
	vp8_context->me_4x_distortion_buffer.height = vp8_context->down_scaled_height_in_mb4x * 4 * 4;
	vp8_context->me_4x_distortion_buffer.pitch = ALIGN(vp8_context->me_4x_distortion_buffer.width, 64);
	vp8_context->me_4x_distortion_buffer.size = vp8_context->me_4x_distortion_buffer.pitch *
												vp8_context->me_4x_distortion_buffer.height;
	vp8_context->me_4x_distortion_buffer.tiling = I915_TILING_NONE;
	i965_allocate_gpe_resource(i965->intel.bufmgr,
							   &vp8_context->me_4x_distortion_buffer,
							   vp8_context->me_4x_distortion_buffer.size,
							   "ME 4x Distortion buffer");

	vp8_context->me_16x_mv_data_buffer.type = I965_GPE_RESOURCE_2D;
	vp8_context->me_16x_mv_data_buffer.width = ALIGN((vp8_context->down_scaled_width_in_mb16x * 32), 64);
	vp8_context->me_16x_mv_data_buffer.height = vp8_context->down_scaled_height_in_mb16x * 4 * VP8_ME_MV_DATA_SIZE_MULTIPLIER;
	vp8_context->me_16x_mv_data_buffer.pitch = vp8_context->me_16x_mv_data_buffer.width;
	vp8_context->me_16x_mv_data_buffer.size = vp8_context->me_16x_mv_data_buffer.pitch *
											  vp8_context->me_16x_mv_data_buffer.height;
	vp8_context->me_16x_mv_data_buffer.tiling = I915_TILING_NONE;
	i965_allocate_gpe_resource(i965->intel.bufmgr,
							   &vp8_context->me_16x_mv_data_buffer,
							   vp8_context->me_16x_mv_data_buffer.size,
							   "ME 16x MV Data buffer");

	ALLOC_VP8_RESOURCE_BUFFER(histogram_buffer, VP8_HISTOGRAM_SIZE, "Histogram buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_intra_row_store_scratch_buffer, vp8_context->frame_width_in_mbs * 64, "Intra row store scratch buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_deblocking_filter_row_store_scratch_buffer, vp8_context->frame_width_in_mbs * 4 * 64, "Deblocking filter row store scratch buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpc_row_store_scratch_buffer, vp8_context->frame_width_in_mbs * 2 * 64, "MPC row store scratch buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_stream_out_buffer, frame_size_in_mbs * 16, "stream out buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_frame_header_buffer, VP8_FRAME_HEADER_SIZE, "Frame header buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_intermediate_buffer, frame_size_in_mbs * 256 * 2 + frame_size_in_mbs * 64 + VP8_INTERMEDIATE_PARTITION0_SIZE, "Intermediate buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_mode_probs_buffer, VP8_MODE_PROPABILITIES_SIZE, "Mode probs buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_ref_mode_probs_buffer, VP8_MODE_PROPABILITIES_SIZE, "Ref mode probs buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_coeff_probs_buffer, VP8_COEFFS_PROPABILITIES_SIZE, "Coeff probs buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_ref_coeff_probs_buffer, VP8_COEFFS_PROPABILITIES_SIZE, "Ref coeff probs buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_token_bits_data_buffer, VP8_TOKEN_BITS_DATA_SIZE, "Token bits data buffer");
	i965_zero_gpe_resource(&vp8_context->pak_mpu_tpu_token_bits_data_buffer);
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_picture_state_buffer, VP8_PICTURE_STATE_SIZE, "Picture state buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_mpu_bitstream_buffer, VP8_MPU_BITSTREAM_SIZE, "Mpu bitstream buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_tpu_bitstream_buffer, VP8_TPU_BITSTREAM_SIZE, "Tpu bitstream buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_entropy_cost_table_buffer, VP8_ENTROPY_COST_TABLE_SIZE, "Entropy cost buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_pak_token_statistics_buffer, VP8_TOKEN_STATISTICS_SIZE, "Pak token statistics buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_pak_token_update_flags_buffer, VP8_COEFFS_PROPABILITIES_SIZE, "Pak token update flags buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_default_token_probability_buffer, VP8_COEFFS_PROPABILITIES_SIZE, "Default token probability buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_key_frame_token_probability_buffer, VP8_COEFFS_PROPABILITIES_SIZE, "Key frame token probability buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_updated_token_probability_buffer, VP8_COEFFS_PROPABILITIES_SIZE, "Updated token probability buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_hw_token_probability_pak_pass_2_buffer, VP8_COEFFS_PROPABILITIES_SIZE, "Hw token probability pak pass 2 buffer");
	ALLOC_VP8_RESOURCE_BUFFER(pak_mpu_tpu_repak_decision_buffer, VP8_REPAK_DECISION_BUF_SIZE, "Tpu repak decision buffer");

	i965_encoder_vp8_vme_init_mpu_tpu_buffer(ctx, encoder_context, vp8_context);

	ALLOC_VP8_RESOURCE_BUFFER(mb_coded_buffer, vp8_context->mb_coded_buffer_size, "MB coded buffer");
}

#undef ALLOC_VP8_RESOURCE_BUFFER

static void
i965_encoder_vp8_vme_free_resources(struct i965_encoder_vp8_context *vp8_context)
{
	i965_free_gpe_resource(&vp8_context->reference_frame_mb_count_buffer);
	i965_free_gpe_resource(&vp8_context->mb_mode_cost_luma_buffer);
	i965_free_gpe_resource(&vp8_context->block_mode_cost_buffer);
	i965_free_gpe_resource(&vp8_context->chroma_recon_buffer);
	i965_free_gpe_resource(&vp8_context->per_mb_quant_data_buffer);
	i965_free_gpe_resource(&vp8_context->pred_mv_data_buffer);
	i965_free_gpe_resource(&vp8_context->mode_cost_update_buffer);

	i965_free_gpe_resource(&vp8_context->brc_history_buffer);
	i965_free_gpe_resource(&vp8_context->brc_segment_map_buffer);
	i965_free_gpe_resource(&vp8_context->brc_distortion_buffer);
	i965_free_gpe_resource(&vp8_context->brc_pak_statistics_buffer);
	i965_free_gpe_resource(&vp8_context->brc_vp8_cfg_command_read_buffer);
	i965_free_gpe_resource(&vp8_context->brc_vp8_cfg_command_write_buffer);
	i965_free_gpe_resource(&vp8_context->brc_vp8_constant_data_buffer);
	i965_free_gpe_resource(&vp8_context->brc_pak_statistics_dump_buffer);

	i965_free_gpe_resource(&vp8_context->me_4x_mv_data_buffer);
	i965_free_gpe_resource(&vp8_context->me_4x_distortion_buffer);
	i965_free_gpe_resource(&vp8_context->me_16x_mv_data_buffer);

	i965_free_gpe_resource(&vp8_context->histogram_buffer);

	i965_free_gpe_resource(&vp8_context->pak_intra_row_store_scratch_buffer);
	i965_free_gpe_resource(&vp8_context->pak_deblocking_filter_row_store_scratch_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpc_row_store_scratch_buffer);
	i965_free_gpe_resource(&vp8_context->pak_stream_out_buffer);
	i965_free_gpe_resource(&vp8_context->pak_frame_header_buffer);
	i965_free_gpe_resource(&vp8_context->pak_intermediate_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_mode_probs_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_ref_mode_probs_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_coeff_probs_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_ref_coeff_probs_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_token_bits_data_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_picture_state_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_mpu_bitstream_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_tpu_bitstream_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_entropy_cost_table_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_pak_token_statistics_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_pak_token_update_flags_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_default_token_probability_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_key_frame_token_probability_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_updated_token_probability_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_hw_token_probability_pak_pass_2_buffer);
	i965_free_gpe_resource(&vp8_context->pak_mpu_tpu_repak_decision_buffer);

	i965_free_gpe_resource(&vp8_context->mb_coded_buffer);
}

static void
i965_encoder_vp8_update_internal_rc_mode(VADriverContextP ctx,
										 struct encode_state *encode_state,
										 struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;

	if (encoder_context->rate_control_mode & VA_RC_CBR)
		vp8_context->internal_rate_mode = I965_BRC_CBR;
	else if (encoder_context->rate_control_mode & VA_RC_VBR)
		vp8_context->internal_rate_mode = I965_BRC_VBR;
	else
		vp8_context->internal_rate_mode = I965_BRC_CQP;
}

static void
i965_encoder_vp8_get_sequence_parameter(VADriverContextP ctx,
										struct encode_state *encode_state,
										struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;

	/*
	 * It is required to update frame width and height for each frame
	 */
	if (encoder_context->frame_width_in_pixel != vp8_context->picture_width ||
		encoder_context->frame_height_in_pixel != vp8_context->picture_height) {
		vp8_context->picture_width = encoder_context->frame_width_in_pixel;
		vp8_context->picture_height = encoder_context->frame_height_in_pixel;

		vp8_context->frame_width_in_mbs = WIDTH_IN_MACROBLOCKS(vp8_context->picture_width);
		vp8_context->frame_height_in_mbs = HEIGHT_IN_MACROBLOCKS(vp8_context->picture_height);

		vp8_context->frame_width = vp8_context->frame_width_in_mbs * 16;
		vp8_context->frame_height = vp8_context->frame_height_in_mbs * 16;

		vp8_context->down_scaled_width_in_mb4x = WIDTH_IN_MACROBLOCKS(vp8_context->frame_width / SCALE_FACTOR_4X);
		vp8_context->down_scaled_height_in_mb4x = HEIGHT_IN_MACROBLOCKS(vp8_context->frame_height / SCALE_FACTOR_4X);
		vp8_context->down_scaled_width_4x = vp8_context->down_scaled_width_in_mb4x * 16;
		vp8_context->down_scaled_height_4x = vp8_context->down_scaled_height_in_mb4x * 16;

		vp8_context->down_scaled_width_in_mb16x = WIDTH_IN_MACROBLOCKS(vp8_context->frame_width / SCALE_FACTOR_16X);
		vp8_context->down_scaled_height_in_mb16x = HEIGHT_IN_MACROBLOCKS(vp8_context->frame_height / SCALE_FACTOR_16X);
		vp8_context->down_scaled_width_16x = vp8_context->down_scaled_width_in_mb16x * 16;
		vp8_context->down_scaled_height_16x = vp8_context->down_scaled_height_in_mb16x * 16;

		i965_encoder_vp8_check_motion_estimation(ctx, encoder_context);

		i965_encoder_vp8_vme_free_resources(vp8_context);
		i965_encoder_vp8_vme_allocate_resources(ctx, encoder_context, vp8_context);
	}

	vp8_context->num_passes = 0;
	vp8_context->repak_pass_iter_val = 0;
	vp8_context->ref_ctrl_optimization_done = 0;
}

static void
i965_encoder_vp8_get_picture_parameter(VADriverContextP ctx,
									   struct encode_state *encode_state,
									   struct intel_encoder_context *encoder_context)
{
	struct i965_driver_data *i965 = i965_driver_data(ctx);
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct object_surface *obj_surface;
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	VAQMatrixBufferVP8 *quant_params = (VAQMatrixBufferVP8 *)encode_state->q_matrix->buffer;
	int is_intra, i;
	unsigned int average_qp = 0;
	unsigned char brc_enabled = (vp8_context->internal_rate_mode == I965_BRC_CBR ||
								 vp8_context->internal_rate_mode == I965_BRC_VBR);

	vp8_context->frame_type = pic_param->pic_flags.bits.frame_type ? MPEG_P_PICTURE : MPEG_I_PICTURE;
	is_intra = (vp8_context->frame_type == MPEG_I_PICTURE);

	if (is_intra) {
		vp8_context->ref_frame_ctrl = 0;
	} else {
		vp8_context->ref_frame_ctrl =
			((!pic_param->ref_flags.bits.no_ref_last) |
			 (!pic_param->ref_flags.bits.no_ref_gf << 1) |
			 (!pic_param->ref_flags.bits.no_ref_arf << 2));
	}

	vp8_context->hme_enabled = (vp8_context->hme_supported && !is_intra && vp8_context->ref_frame_ctrl != 0);
	vp8_context->hme_16x_enabled = (vp8_context->hme_16x_supported && !is_intra);

	if (pic_param->ref_last_frame != VA_INVALID_SURFACE) {
		obj_surface = SURFACE(pic_param->ref_last_frame);

		if (obj_surface && obj_surface->bo)
			vp8_context->ref_last_frame = obj_surface;
		else
			vp8_context->ref_last_frame = NULL;
	} else {
		vp8_context->ref_last_frame = NULL;
	}

	if (pic_param->ref_gf_frame != VA_INVALID_SURFACE) {
		obj_surface = SURFACE(pic_param->ref_gf_frame);

		if (obj_surface && obj_surface->bo)
			vp8_context->ref_gf_frame = obj_surface;
		else
			vp8_context->ref_gf_frame = NULL;
	} else {
		vp8_context->ref_gf_frame = NULL;
	}

	if (pic_param->ref_arf_frame != VA_INVALID_SURFACE) {
		obj_surface = SURFACE(pic_param->ref_arf_frame);

		if (obj_surface && obj_surface->bo)
			vp8_context->ref_arf_frame = obj_surface;
		else
			vp8_context->ref_arf_frame = NULL;
	} else {
		vp8_context->ref_arf_frame = NULL;
	}

	vp8_context->brc_distortion_buffer_need_reset = 0;

	if (brc_enabled) {
		if (is_intra) {
			vp8_context->brc_distortion_buffer_need_reset = 1;
		} else {
			if (vp8_context->frame_num % vp8_context->gop_size == 1) {
				vp8_context->brc_distortion_buffer_need_reset = 1;
			}
		}
	}

	if (pic_param->pic_flags.bits.segmentation_enabled) {
		for (i = 0; i < VP8_MAX_SEGMENTS; i++) {
			average_qp += quant_params->quantization_index[i] + quant_params->quantization_index_delta[i];
		}

		average_qp = average_qp / VP8_MAX_SEGMENTS;
	} else {
		average_qp += quant_params->quantization_index[0] + quant_params->quantization_index_delta[0];
	}

	if (is_intra) {
		vp8_context->average_i_frame_qp = average_qp;
	} else {
		vp8_context->average_p_frame_qp = average_qp;
	}

	if (brc_enabled && vp8_context->multiple_pass_brc_supported)
		vp8_context->num_brc_pak_passes = VP8_BRC_MINIMUM_NUM_PASSES;
	else
		vp8_context->num_brc_pak_passes = VP8_BRC_SINGLE_PASS;

	vp8_context->num_passes = 0;
	vp8_context->min_pak_passes = 1;
	vp8_context->repak_pass_iter_val = 0;

	if (encoder_context->quality_level == ENCODER_DEFAULT_QUALITY) {
		vp8_context->num_passes = 1;
		vp8_context->min_pak_passes = 2;
	} else if (encoder_context->quality_level == ENCODER_LOW_QUALITY) {
		vp8_context->num_passes = 0;
		vp8_context->min_pak_passes = 1;
	} else {
		vp8_context->num_passes = 0;
		vp8_context->min_pak_passes = 1;
	}

	if (!vp8_context->repak_supported) {
		vp8_context->num_passes = 0;
		vp8_context->min_pak_passes = 1;
	}

	if (brc_enabled)
		vp8_context->num_passes += (vp8_context->num_brc_pak_passes - 1);

	if (vp8_context->repak_supported && vp8_context->min_pak_passes > 1)
		vp8_context->repak_pass_iter_val = vp8_context->num_passes;
}

static void
i965_encoder_vp8_get_misc_parameters(VADriverContextP ctx,
									 struct encode_state *encode_state,
									 struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;

	if (vp8_context->internal_rate_mode == I965_BRC_CQP) {
		vp8_context->init_vbv_buffer_fullness_in_bit = 0;
		vp8_context->vbv_buffer_size_in_bit = 0;
		vp8_context->target_bit_rate = 0;
		vp8_context->max_bit_rate = 0;
		vp8_context->min_bit_rate = 0;
		vp8_context->brc_need_reset = 0;
	} else {
		vp8_context->gop_size = encoder_context->brc.gop_size;

		if (encoder_context->brc.need_reset) {
			vp8_context->framerate = encoder_context->brc.framerate[0];
			vp8_context->vbv_buffer_size_in_bit = encoder_context->brc.hrd_buffer_size;
			vp8_context->init_vbv_buffer_fullness_in_bit = encoder_context->brc.hrd_initial_buffer_fullness;
			vp8_context->max_bit_rate = encoder_context->brc.bits_per_second[0]; // currently only one layer is supported
			vp8_context->brc_need_reset = (vp8_context->brc_initted && encoder_context->brc.need_reset);

			if (vp8_context->internal_rate_mode == I965_BRC_CBR) {
				vp8_context->min_bit_rate = vp8_context->max_bit_rate;
				vp8_context->target_bit_rate = vp8_context->max_bit_rate;
			} else {
				assert(vp8_context->internal_rate_mode == I965_BRC_VBR);

				if (encoder_context->brc.target_percentage[0] <= 50)
					vp8_context->min_bit_rate = 0;
				else
					vp8_context->min_bit_rate = vp8_context->max_bit_rate * (2 * encoder_context->brc.target_percentage[0] - 100) / 100;

				vp8_context->target_bit_rate = vp8_context->max_bit_rate * encoder_context->brc.target_percentage[0] / 100;
			}
		}
	}

	if (encoder_context->quality_level == ENCODER_LOW_QUALITY)
		vp8_context->hme_16x_supported = 0;
}

static VAStatus
i965_encoder_vp8_get_paramters(VADriverContextP ctx,
							   struct encode_state *encode_state,
							   struct intel_encoder_context *encoder_context)
{
	VAQMatrixBufferVP8 *quant_params = (VAQMatrixBufferVP8 *)encode_state->q_matrix->buffer;
	struct i965_encoder_vp8_surface *vp8_surface;

	i965_encoder_vp8_update_internal_rc_mode(ctx, encode_state, encoder_context);
	i965_encoder_vp8_get_sequence_parameter(ctx, encode_state, encoder_context);
	i965_encoder_vp8_get_misc_parameters(ctx, encode_state, encoder_context);
	i965_encoder_vp8_get_picture_parameter(ctx, encode_state, encoder_context);

	i965_encoder_vp8_allocate_surfaces(ctx, encoder_context, encode_state->reconstructed_object, 1);
	vp8_surface = encode_state->reconstructed_object->private_data;
	vp8_surface->qp_index = quant_params->quantization_index[0];

	return VA_STATUS_SUCCESS;
}

static VAStatus
i965_encoder_vp8_vme_gpe_kernel_init(VADriverContextP ctx,
									 struct encode_state *encode_state,
									 struct intel_encoder_context *encoder_context)
{
	struct i965_driver_data *i965 = i965_driver_data(ctx);
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_encoder_vp8_mbenc_context *mbenc_context = &vp8_context->mbenc_context;
	struct i965_encoder_vp8_mpu_context *mpu_context = &vp8_context->mpu_context;
	struct i965_encoder_vp8_tpu_context *tpu_context = &vp8_context->tpu_context;
	struct gpe_dynamic_state_parameter ds_param;
	int i;

	/*
	 * BRC will update MBEnc curbe data buffer, so initialize GPE context for
	 * MBEnc first
	 */
	for (i = 0; i < NUM_VP8_MBENC; i++) {
		gpe->context_init(ctx, &mbenc_context->gpe_contexts[i]);
	}

	/*
	 * VP8_MBENC_I_FRAME_LUMA and VP8_MBENC_I_FRAME_CHROMA will use the same
	 * the dynamic state buffer,
	 */
	ds_param.bo_size = ALIGN(MAX(sizeof(struct vp8_mbenc_i_frame_curbe_data), sizeof(struct vp8_mbenc_p_frame_curbe_data)), 64) +
					   vp8_context->idrt_entry_size * 2;
	mbenc_context->luma_chroma_dynamic_buffer = dri_bo_alloc(i965->intel.bufmgr,
															 "IFrame Luma & CHROMA curbe buffer",
															 ds_param.bo_size,
															 0x1000);

	/*
	 * VP8_MBENC_I_FRAME_LUMA and VP8_MBENC_I_FRAME_CHROMA will share the same
	 * the curbe data buffer
	 */
	ds_param.bo = mbenc_context->luma_chroma_dynamic_buffer;
	ds_param.curbe_offset = 0;
	ds_param.idrt_offset = ALIGN(MAX(sizeof(struct vp8_mbenc_i_frame_curbe_data), sizeof(struct vp8_mbenc_p_frame_curbe_data)), 64);
	ds_param.sampler_offset = ds_param.bo_size;
	gpe->set_dynamic_buffer(ctx, &mbenc_context->gpe_contexts[VP8_MBENC_I_FRAME_LUMA], &ds_param);

	ds_param.idrt_offset = ds_param.idrt_offset + vp8_context->idrt_entry_size;
	gpe->set_dynamic_buffer(ctx, &mbenc_context->gpe_contexts[VP8_MBENC_I_FRAME_CHROMA], &ds_param);

	/*
	 * BRC will update MPU curbe data buffer, so initialize GPE context for
	 * MPU first
	 */
	gpe->context_init(ctx, &mpu_context->gpe_contexts[0]);
	ds_param.bo_size = ALIGN(sizeof(struct vp8_mpu_curbe_data), 64) + vp8_context->idrt_entry_size;
	mpu_context->dynamic_buffer = dri_bo_alloc(i965->intel.bufmgr,
											   "MPU dynamic buffer",
											   ds_param.bo_size,
											   0x1000);

	ds_param.bo = mpu_context->dynamic_buffer;
	ds_param.curbe_offset = 0;
	ds_param.idrt_offset = ALIGN(sizeof(struct vp8_mpu_curbe_data), 64);
	ds_param.sampler_offset = ds_param.bo_size;
	gpe->set_dynamic_buffer(ctx, &mpu_context->gpe_contexts[0], &ds_param);

	/*
	 * BRC will update TPU curbe data buffer, so initialize GPE context for
	 * TPU first
	 */
	gpe->context_init(ctx, &tpu_context->gpe_contexts[0]);
	ds_param.bo_size = ALIGN(sizeof(struct vp8_tpu_curbe_data), 64) + vp8_context->idrt_entry_size;
	tpu_context->dynamic_buffer = dri_bo_alloc(i965->intel.bufmgr,
											   "MPU dynamic buffer",
											   ds_param.bo_size,
											   0x1000);

	ds_param.bo = tpu_context->dynamic_buffer;
	ds_param.curbe_offset = 0;
	ds_param.idrt_offset = ALIGN(sizeof(struct vp8_tpu_curbe_data), 64);
	ds_param.sampler_offset = ds_param.bo_size;
	gpe->set_dynamic_buffer(ctx, &tpu_context->gpe_contexts[0], &ds_param);

	return VA_STATUS_SUCCESS;
}

static void
i965_encoder_vp8_vme_brc_init_reset_set_curbe(VADriverContextP ctx,
											  struct encode_state *encode_state,
											  struct intel_encoder_context *encoder_context,
											  struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	struct vp8_brc_init_reset_curbe_data *pcmd = i965_gpe_context_map_curbe(gpe_context);
	double input_bits_per_frame, bps_ratio;

	if (!pcmd)
		return;

	memset(pcmd, 0, sizeof(*pcmd));

	pcmd->dw0.profile_level_max_frame = vp8_context->frame_width * vp8_context->frame_height;
	pcmd->dw1.init_buf_full_in_bits = vp8_context->init_vbv_buffer_fullness_in_bit;
	pcmd->dw2.buf_size_in_bits = vp8_context->vbv_buffer_size_in_bit;
	pcmd->dw3.average_bitrate = (vp8_context->target_bit_rate + VP8_BRC_KBPS - 1) / VP8_BRC_KBPS * VP8_BRC_KBPS;
	pcmd->dw4.max_bitrate = (vp8_context->max_bit_rate + VP8_BRC_KBPS - 1) / VP8_BRC_KBPS * VP8_BRC_KBPS;
	pcmd->dw6.frame_rate_m = vp8_context->framerate.num;
	pcmd->dw7.frame_rate_d = vp8_context->framerate.den;
	pcmd->dw8.brc_flag = 0;
	pcmd->dw8.gop_minus1 = vp8_context->gop_size - 1;

	if (vp8_context->internal_rate_mode == I965_BRC_CBR) {
		pcmd->dw4.max_bitrate = pcmd->dw3.average_bitrate;

		pcmd->dw8.brc_flag = pcmd->dw8.brc_flag | BRC_KERNEL_CBR;
	} else if (vp8_context->internal_rate_mode == I965_BRC_VBR) {
		if (pcmd->dw4.max_bitrate < pcmd->dw3.average_bitrate) {
			pcmd->dw4.max_bitrate = 2 * pcmd->dw3.average_bitrate;
		}

		pcmd->dw8.brc_flag = pcmd->dw8.brc_flag | BRC_KERNEL_VBR;
	}

	input_bits_per_frame =
		((double)(pcmd->dw4.max_bitrate) * (double)(pcmd->dw7.frame_rate_d) /
		 (double)(pcmd->dw6.frame_rate_m));

	if (pcmd->dw2.buf_size_in_bits < (unsigned int)input_bits_per_frame * 4) {
		pcmd->dw2.buf_size_in_bits = (unsigned int)input_bits_per_frame * 4;
	}

	if (pcmd->dw1.init_buf_full_in_bits == 0) {
		pcmd->dw1.init_buf_full_in_bits = 7 * pcmd->dw2.buf_size_in_bits / 8;
	}

	if (pcmd->dw1.init_buf_full_in_bits < (unsigned int)(input_bits_per_frame * 2)) {
		pcmd->dw1.init_buf_full_in_bits = (unsigned int)(input_bits_per_frame * 2);
	}

	if (pcmd->dw1.init_buf_full_in_bits > pcmd->dw2.buf_size_in_bits) {
		pcmd->dw1.init_buf_full_in_bits = pcmd->dw2.buf_size_in_bits;
	}

	bps_ratio = input_bits_per_frame / ((double)(pcmd->dw2.buf_size_in_bits) / 30);
	bps_ratio = (bps_ratio < 0.1) ? 0.1 : (bps_ratio > 3.5) ? 3.5 : bps_ratio;

	pcmd->dw9.frame_width_in_bytes = vp8_context->picture_width;
	pcmd->dw10.frame_height_in_bytes = vp8_context->picture_height;
	pcmd->dw10.avbr_accuracy = 30;
	pcmd->dw11.avbr_convergence = 150;
	pcmd->dw11.min_qp = pic_param->clamp_qindex_low;
	pcmd->dw12.max_qp = pic_param->clamp_qindex_high;
	pcmd->dw12.level_qp = 60;

	// DW13 default 100
	pcmd->dw13.max_section_pct = 100;
	pcmd->dw13.under_shoot_cbr_pct = 115;

	// DW14 default 100
	pcmd->dw14.min_section_pct = 100;
	pcmd->dw14.vbr_bias_pct = 100;
	pcmd->dw15.instant_rate_threshold_0_for_p = 30;
	pcmd->dw15.instant_rate_threshold_1_for_p = 50;
	pcmd->dw15.instant_rate_threshold_2_for_p = 70;
	pcmd->dw15.instant_rate_threshold_3_for_p = 120;

	pcmd->dw17.instant_rate_threshold_0_for_i = 30;
	pcmd->dw17.instant_rate_threshold_1_for_i = 50;
	pcmd->dw17.instant_rate_threshold_2_for_i = 90;
	pcmd->dw17.instant_rate_threshold_3_for_i = 115;
	pcmd->dw18.deviation_threshold_0_for_p = (unsigned int)(-50 * pow(0.9, bps_ratio));
	pcmd->dw18.deviation_threshold_1_for_p = (unsigned int)(-50 * pow(0.66, bps_ratio));
	pcmd->dw18.deviation_threshold_2_for_p = (unsigned int)(-50 * pow(0.46, bps_ratio));
	pcmd->dw18.deviation_threshold_3_for_p = (unsigned int)(-50 * pow(0.3, bps_ratio));
	pcmd->dw19.deviation_threshold_4_for_p = (unsigned int)(50 * pow(0.3, bps_ratio));
	pcmd->dw19.deviation_threshold_5_for_p = (unsigned int)(50 * pow(0.46, bps_ratio));
	pcmd->dw19.deviation_threshold_6_for_p = (unsigned int)(50 * pow(0.7, bps_ratio));
	pcmd->dw19.deviation_threshold_7_for_p = (unsigned int)(50 * pow(0.9, bps_ratio));
	pcmd->dw20.deviation_threshold_0_for_vbr = (unsigned int)(-50 * pow(0.9, bps_ratio));
	pcmd->dw20.deviation_threshold_1_for_vbr = (unsigned int)(-50 * pow(0.7, bps_ratio));
	pcmd->dw20.deviation_threshold_2_for_vbr = (unsigned int)(-50 * pow(0.5, bps_ratio));
	pcmd->dw20.deviation_threshold_3_for_vbr = (unsigned int)(-50 * pow(0.3, bps_ratio));
	pcmd->dw21.deviation_threshold_4_for_vbr = (unsigned int)(100 * pow(0.4, bps_ratio));
	pcmd->dw21.deviation_threshold_5_for_vbr = (unsigned int)(100 * pow(0.5, bps_ratio));
	pcmd->dw21.deviation_threshold_6_for_vbr = (unsigned int)(100 * pow(0.75, bps_ratio));
	pcmd->dw21.deviation_threshold_7_for_vbr = (unsigned int)(100 * pow(0.9, bps_ratio));
	pcmd->dw22.deviation_threshold_0_for_i = (unsigned int)(-50 * pow(0.8, bps_ratio));
	pcmd->dw22.deviation_threshold_1_for_i = (unsigned int)(-50 * pow(0.6, bps_ratio));
	pcmd->dw22.deviation_threshold_2_for_i = (unsigned int)(-50 * pow(0.34, bps_ratio));
	pcmd->dw22.deviation_threshold_3_for_i = (unsigned int)(-50 * pow(0.2, bps_ratio));
	pcmd->dw23.deviation_threshold_4_for_i = (unsigned int)(50 * pow(0.2, bps_ratio));
	pcmd->dw23.deviation_threshold_5_for_i = (unsigned int)(50 * pow(0.4, bps_ratio));
	pcmd->dw23.deviation_threshold_6_for_i = (unsigned int)(50 * pow(0.66, bps_ratio));
	pcmd->dw23.deviation_threshold_7_for_i = (unsigned int)(50 * pow(0.9, bps_ratio));

	// Default: 1
	pcmd->dw24.num_t_levels = 1;

	if (!vp8_context->brc_initted) {
		vp8_context->brc_init_current_target_buf_full_in_bits = pcmd->dw1.init_buf_full_in_bits;
	}

	vp8_context->brc_init_reset_buf_size_in_bits = pcmd->dw2.buf_size_in_bits;
	vp8_context->brc_init_reset_input_bits_per_frame = input_bits_per_frame;

	pcmd->dw26.history_buffer_bti = VP8_BTI_BRC_INIT_RESET_HISTORY;
	pcmd->dw27.distortion_buffer_bti = VP8_BTI_BRC_INIT_RESET_DISTORTION;

	i965_gpe_context_unmap_curbe(gpe_context);
}

static void
i965_encoder_vp8_vme_brc_init_reset_add_surfaces(VADriverContextP ctx,
												 struct encode_state *encode_state,
												 struct intel_encoder_context *encoder_context,
												 struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;

	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->brc_history_buffer,
								0,
								vp8_context->brc_history_buffer.size,
								0,
								VP8_BTI_BRC_INIT_RESET_HISTORY);

	i965_add_buffer_2d_gpe_surface(ctx,
								   gpe_context,
								   &vp8_context->brc_distortion_buffer,
								   1,
								   I965_SURFACEFORMAT_R8_UNORM,
								   VP8_BTI_BRC_INIT_RESET_DISTORTION);
}

static VAStatus
i965_encoder_vp8_vme_brc_init_reset(VADriverContextP ctx,
									struct encode_state *encode_state,
									struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_brc_init_reset_context *init_reset_context = &vp8_context->brc_init_reset_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct gpe_media_object_parameter media_object_param;
	struct i965_gpe_context *gpe_context;
	int gpe_index = VP8_BRC_INIT;
	int media_function = VP8_MEDIA_STATE_BRC_INIT_RESET;

	if (vp8_context->brc_initted)
		gpe_index = VP8_BRC_RESET;

	gpe_context = &init_reset_context->gpe_contexts[gpe_index];

	gpe->context_init(ctx, gpe_context);
	gpe->reset_binding_table(ctx, gpe_context);
	i965_encoder_vp8_vme_brc_init_reset_set_curbe(ctx, encode_state, encoder_context, gpe_context);
	i965_encoder_vp8_vme_brc_init_reset_add_surfaces(ctx, encode_state, encoder_context, gpe_context);
	gpe->setup_interface_data(ctx, gpe_context);

	memset(&media_object_param, 0, sizeof(media_object_param));
	i965_run_kernel_media_object(ctx, encoder_context, gpe_context, media_function, &media_object_param);

	return VA_STATUS_SUCCESS;
}

static void
i965_encoder_vp8_vme_scaling_set_curbe(VADriverContextP ctx,
									   struct encode_state *encode_state,
									   struct intel_encoder_context *encoder_context,
									   struct i965_gpe_context *gpe_context,
									   struct scaling_curbe_parameters *params)
{
	struct vp8_scaling_curbe_data *pcmd = i965_gpe_context_map_curbe(gpe_context);

	if (!pcmd)
		return;

	memset(pcmd, 0, sizeof(*pcmd));

	pcmd->dw0.input_picture_width = params->input_picture_width;
	pcmd->dw0.input_picture_height = params->input_picture_height;

	if (!params->is_field_picture) {
		pcmd->dw1.input_y_bti_frame = VP8_BTI_SCALING_FRAME_SRC_Y;
		pcmd->dw2.output_y_bti_frame = VP8_BTI_SCALING_FRAME_DST_Y;
	} else {
		pcmd->dw1.input_y_bti_top_field = VP8_BTI_SCALING_FIELD_TOP_SRC_Y;
		pcmd->dw2.output_y_bti_top_field = VP8_BTI_SCALING_FIELD_TOP_DST_Y;
		pcmd->dw3.input_y_bti_bottom_field = VP8_BTI_SCALING_FIELD_BOT_SRC_Y;
		pcmd->dw4.output_y_bti_bottom_field = VP8_BTI_SCALING_FIELD_BOT_DST_Y;
	}

	if (params->flatness_check_enabled) {
		pcmd->dw5.flatness_threshold = 128;
		pcmd->dw6.enable_mb_flatness_check = 1;

		if (!params->is_field_picture) {
			pcmd->dw8.flatness_output_bti_frame = VP8_BTI_SCALING_FRAME_FLATNESS_DST;
		} else {
			pcmd->dw8.flatness_output_bti_top_field = VP8_BTI_SCALING_FIELD_TOP_FLATNESS_DST;
			pcmd->dw9.flatness_output_bti_bottom_field = VP8_BTI_SCALING_FIELD_BOT_FLATNESS_DST;
		}
	} else {
		pcmd->dw6.enable_mb_flatness_check = 0;
	}

	pcmd->dw6.enable_mb_variance_output = params->mb_variance_output_enabled;
	pcmd->dw6.enable_mb_pixel_average_output = params->mb_pixel_average_output_enabled;

	if (params->mb_variance_output_enabled || params->mb_pixel_average_output_enabled) {
		if (!params->is_field_picture) {
			pcmd->dw10.mbv_proc_stats_bti_frame = VP8_BTI_SCALING_FRAME_MBVPROCSTATS_DST;
		} else {
			pcmd->dw10.mbv_proc_stats_bti_top_field = VP8_BTI_SCALING_FIELD_TOP_MBVPROCSTATS_DST;
			pcmd->dw11.mbv_proc_stats_bti_bottom_field = VP8_BTI_SCALING_FIELD_BOT_MBVPROCSTATS_DST;
		}
	}

	i965_gpe_context_unmap_curbe(gpe_context);
}

static void
i965_encoder_vp8_vme_scaling_add_surfaces(VADriverContextP ctx,
										  struct encode_state *encode_state,
										  struct intel_encoder_context *encoder_context,
										  struct i965_gpe_context *gpe_context,
										  struct scaling_surface_parameters *params)
{
	i965_add_2d_gpe_surface(ctx,
							gpe_context,
							params->input_obj_surface,
							0,
							1,
							I965_SURFACEFORMAT_R32_UNORM,
							VP8_BTI_SCALING_FRAME_SRC_Y);
	i965_add_2d_gpe_surface(ctx,
							gpe_context,
							params->output_obj_surface,
							0,
							1,
							I965_SURFACEFORMAT_R32_UNORM,
							VP8_BTI_SCALING_FRAME_DST_Y);
}

static VAStatus
i965_encoder_vp8_vme_scaling(VADriverContextP ctx,
							 struct encode_state *encode_state,
							 struct intel_encoder_context *encoder_context,
							 int scaling_16x_enabled)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_scaling_context *scaling_context = &vp8_context->scaling_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct gpe_media_object_walker_parameter media_object_walker_param;
	struct i965_gpe_context *gpe_context;
	struct scaling_curbe_parameters scaling_curbe_params;
	struct scaling_surface_parameters scaling_surface_params;
	struct vp8_encoder_kernel_walker_parameter kernel_walker_param;
	struct object_surface *input_obj_surface, *output_obj_surface;
	struct i965_encoder_vp8_surface *vp8_surface;
	unsigned int input_frame_width, input_frame_height, output_frame_width, output_frame_height;
	unsigned int down_scaled_width_in_mbs, down_scaled_height_in_mbs;
	int gpe_index, media_function;

	vp8_surface = encode_state->reconstructed_object->private_data;

	if (scaling_16x_enabled) {
		gpe_index = VP8_SCALING_16X;
		media_function = VP8_MEDIA_STATE_16X_SCALING;

		down_scaled_width_in_mbs = vp8_context->down_scaled_width_in_mb16x;
		down_scaled_height_in_mbs = vp8_context->down_scaled_height_in_mb16x;

		input_obj_surface = vp8_surface->scaled_4x_surface_obj;
		input_frame_width = vp8_context->down_scaled_width_4x;
		input_frame_height = vp8_context->down_scaled_height_4x;

		output_obj_surface = vp8_surface->scaled_16x_surface_obj;
		output_frame_width = vp8_context->down_scaled_width_16x;
		output_frame_height = vp8_context->down_scaled_height_16x;
	} else {
		gpe_index = VP8_SCALING_4X;
		media_function = VP8_MEDIA_STATE_4X_SCALING;

		down_scaled_width_in_mbs = vp8_context->down_scaled_width_in_mb4x;
		down_scaled_height_in_mbs = vp8_context->down_scaled_height_in_mb4x;

		input_obj_surface = encode_state->input_yuv_object;
		input_frame_width = vp8_context->picture_width;         /* the orignal width */
		input_frame_height = vp8_context->picture_height;       /* the orignal height */

		output_obj_surface = vp8_surface->scaled_4x_surface_obj;
		output_frame_width = vp8_context->down_scaled_width_4x;
		output_frame_height = vp8_context->down_scaled_height_4x;
	}

	gpe_context = &scaling_context->gpe_contexts[gpe_index];

	gpe->context_init(ctx, gpe_context);
	gpe->reset_binding_table(ctx, gpe_context);

	memset(&scaling_curbe_params, 0, sizeof(scaling_curbe_params));
	scaling_curbe_params.input_picture_width = input_frame_width;
	scaling_curbe_params.input_picture_height = input_frame_height;
	scaling_curbe_params.is_field_picture = 0;
	scaling_curbe_params.flatness_check_enabled = 0;
	scaling_curbe_params.mb_variance_output_enabled = 0;
	scaling_curbe_params.mb_pixel_average_output_enabled = 0;
	i965_encoder_vp8_vme_scaling_set_curbe(ctx, encode_state, encoder_context, gpe_context, &scaling_curbe_params);

	scaling_surface_params.input_obj_surface = input_obj_surface;
	scaling_surface_params.input_width = input_frame_width;
	scaling_surface_params.input_height = input_frame_height;
	scaling_surface_params.output_obj_surface = output_obj_surface;
	scaling_surface_params.output_width = output_frame_width;
	scaling_surface_params.output_height = output_frame_height;
	i965_encoder_vp8_vme_scaling_add_surfaces(ctx, encode_state, encoder_context, gpe_context, &scaling_surface_params);

	gpe->setup_interface_data(ctx, gpe_context);

	memset(&kernel_walker_param, 0, sizeof(kernel_walker_param));
	kernel_walker_param.resolution_x = down_scaled_width_in_mbs * 2; /* 8x8 level */
	kernel_walker_param.resolution_y = down_scaled_height_in_mbs * 2;
	kernel_walker_param.no_dependency = 1;
	i965_init_media_object_walker_parameters(encoder_context, &kernel_walker_param, &media_object_walker_param);

	i965_run_kernel_media_object_walker(ctx, encoder_context, gpe_context, media_function, &media_object_walker_param);

	return VA_STATUS_SUCCESS;
}

static void
i965_encoder_vp8_vme_me_set_curbe(VADriverContextP ctx,
								  struct encode_state *encode_state,
								  struct intel_encoder_context *encoder_context,
								  struct i965_gpe_context *gpe_context,
								  struct me_curbe_parameters *params)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct vp8_me_curbe_data *pcmd = i965_gpe_context_map_curbe(gpe_context);
	int me_mode, me_method;

	if (!pcmd)
		return;

	if (vp8_context->hme_16x_enabled) {
		if (params->use_16x_me)
			me_mode = VP8_ME_MODE_ME16X_BEFORE_ME4X;
		else
			me_mode = VP8_ME_MODE_ME4X_AFTER_ME16X;
	} else {
		me_mode = VP8_ME_MODE_ME4X_ONLY;
	}

	memset(pcmd, 0, sizeof(*pcmd));

	pcmd->dw1.max_num_mvs = 0x10;
	pcmd->dw1.bi_weight = 0;

	pcmd->dw2.max_num_su = 57;
	pcmd->dw2.max_len_sp = 57;

	pcmd->dw3.sub_mb_part_mask = 0x77;
	pcmd->dw3.inter_sad = 0;
	pcmd->dw3.intra_sad = 0;
	pcmd->dw3.bme_disable_fbr = 1;
	pcmd->dw3.sub_pel_mode = 3;

	pcmd->dw4.picture_height_minus1 = params->down_scaled_height_in_mbs - 1;
	pcmd->dw4.picture_width = params->down_scaled_width_in_mbs;

	if (pcmd->dw4.picture_height_minus1 < 2)
		pcmd->dw4.picture_height_minus1 = 2;

	if (pcmd->dw4.picture_width < 3)
		pcmd->dw4.picture_width = 3;

	pcmd->dw5.ref_height = 40;
	pcmd->dw5.ref_width = 48;

	pcmd->dw6.me_mode = me_mode;

	if (encoder_context->quality_level == ENCODER_DEFAULT_QUALITY)
		pcmd->dw6.super_combine_dist = 5;
	else if (encoder_context->quality_level == ENCODER_LOW_QUALITY)
		pcmd->dw6.super_combine_dist = 0;
	else
		pcmd->dw6.super_combine_dist = 1;

	pcmd->dw6.max_vmv_range = 0x7fc;

	pcmd->dw13.num_ref_idx_l0_minus1 = vp8_num_refs[vp8_context->ref_frame_ctrl] - 1;
	pcmd->dw13.num_ref_idx_l1_minus1 = 0;

	me_method = (encoder_context->quality_level == ENCODER_DEFAULT_QUALITY) ? 6 : 4;
	memcpy(&pcmd->dw16, vp8_search_path[me_method], 14 * sizeof(pcmd->dw16));

	pcmd->dw32.vp8_me_mv_output_data_bti = VP8_BTI_ME_MV_DATA;
	pcmd->dw33.vp8_me_mv_input_data_bti = VP8_BTI_16X_ME_MV_DATA;
	pcmd->dw34.vp8_me_distorion_bti = VP8_BTI_ME_DISTORTION;
	pcmd->dw35.vp8_me_min_dist_brc_bti = VP8_BTI_ME_MIN_DIST_BRC_DATA;
	pcmd->dw36.vp8_me_forward_ref_bti = VP8_BTI_VME_INTER_PRED;

	i965_gpe_context_unmap_curbe(gpe_context);
}

static void
i965_encoder_vp8_vme_me_add_surfaces(VADriverContextP ctx,
									 struct encode_state *encode_state,
									 struct intel_encoder_context *encoder_context,
									 struct i965_gpe_context *gpe_context,
									 struct me_surface_parameters *params)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_surface *vp8_surface;
	struct i965_gpe_resource *me_gpe_buffer, *me_brc_distortion_buffer;
	struct object_surface *obj_surface;
	unsigned char brc_enabled = (vp8_context->internal_rate_mode == I965_BRC_CBR ||
								 vp8_context->internal_rate_mode == I965_BRC_VBR);

	if (brc_enabled)
		me_brc_distortion_buffer = &vp8_context->brc_distortion_buffer;
	else
		me_brc_distortion_buffer = &vp8_context->me_4x_distortion_buffer;

	if (params->use_16x_me) {
		me_gpe_buffer = &vp8_context->me_16x_mv_data_buffer;
	} else {
		me_gpe_buffer = &vp8_context->me_4x_mv_data_buffer;
	}

	i965_add_buffer_2d_gpe_surface(ctx,
								   gpe_context,
								   me_gpe_buffer,
								   1,
								   I965_SURFACEFORMAT_R8_UNORM,
								   VP8_BTI_ME_MV_DATA);

	if (vp8_context->hme_16x_enabled) {
		me_gpe_buffer = &vp8_context->me_16x_mv_data_buffer;
		i965_add_buffer_2d_gpe_surface(ctx,
									   gpe_context,
									   me_gpe_buffer,
									   1,
									   I965_SURFACEFORMAT_R8_UNORM,
									   VP8_BTI_16X_ME_MV_DATA);
	}

	if (!params->use_16x_me) {
		me_gpe_buffer = &vp8_context->me_4x_distortion_buffer;
		i965_add_buffer_2d_gpe_surface(ctx,
									   gpe_context,
									   me_gpe_buffer,
									   1,
									   I965_SURFACEFORMAT_R8_UNORM,
									   VP8_BTI_ME_DISTORTION);

		me_gpe_buffer = me_brc_distortion_buffer;
		i965_add_buffer_2d_gpe_surface(ctx,
									   gpe_context,
									   me_gpe_buffer,
									   1,
									   I965_SURFACEFORMAT_R8_UNORM,
									   VP8_BTI_ME_MIN_DIST_BRC_DATA);
	}

	vp8_surface = encode_state->reconstructed_object->private_data;
	assert(vp8_surface);

	if (params->use_16x_me) {
		obj_surface = vp8_surface->scaled_16x_surface_obj;
	} else {
		obj_surface = vp8_surface->scaled_4x_surface_obj;
	}

	i965_add_adv_gpe_surface(ctx,
							 gpe_context,
							 obj_surface,
							 VP8_BTI_VME_INTER_PRED);

	if (vp8_context->ref_last_frame != NULL &&
		vp8_context->ref_last_frame->bo != NULL) {
		vp8_surface = vp8_context->ref_last_frame->private_data;
		obj_surface = NULL;

		if (vp8_surface) {
			if (params->use_16x_me) {
				obj_surface = vp8_surface->scaled_16x_surface_obj;
			} else {
				obj_surface = vp8_surface->scaled_4x_surface_obj;
			}
		}

		if (obj_surface) {
			i965_add_adv_gpe_surface(ctx,
									 gpe_context,
									 obj_surface,
									 VP8_BTI_ME_REF1_PIC);
		}
	}

	if (vp8_context->ref_gf_frame != NULL &&
		vp8_context->ref_gf_frame->bo != NULL) {
		vp8_surface = vp8_context->ref_gf_frame->private_data;
		obj_surface = NULL;

		if (vp8_surface) {
			if (params->use_16x_me) {
				obj_surface = vp8_surface->scaled_16x_surface_obj;
			} else {
				obj_surface = vp8_surface->scaled_4x_surface_obj;
			}
		}

		if (obj_surface) {
			switch (vp8_context->ref_frame_ctrl) {
			case 2:
			case 6:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_ME_REF1_PIC);
				break;

			case 3:
			case 7:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_ME_REF2_PIC);
				break;
			}
		}
	}

	if (vp8_context->ref_arf_frame != NULL &&
		vp8_context->ref_arf_frame->bo != NULL) {
		vp8_surface = vp8_context->ref_arf_frame->private_data;
		obj_surface = NULL;

		if (vp8_surface) {
			if (params->use_16x_me) {
				obj_surface = vp8_surface->scaled_16x_surface_obj;
			} else {
				obj_surface = vp8_surface->scaled_4x_surface_obj;
			}
		}

		if (obj_surface) {
			switch (vp8_context->ref_frame_ctrl) {
			case 4:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_ME_REF1_PIC);
				break;

			case 5:
			case 6:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_ME_REF2_PIC);
				break;

			case 7:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_ME_REF3_PIC);
				break;
			}
		}
	}
}

static void
i965_encoder_vp8_vme_init_brc_distorion_buffer(VADriverContextP ctx, struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;

	i965_zero_gpe_resource(&vp8_context->brc_distortion_buffer);
}

static VAStatus
i965_encoder_vp8_vme_me(VADriverContextP ctx,
						struct encode_state *encode_state,
						struct intel_encoder_context *encoder_context,
						int use_16x_me)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_me_context *me_context = &vp8_context->me_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct gpe_media_object_walker_parameter media_object_walker_param;
	struct vp8_encoder_kernel_walker_parameter kernel_walker_params;
	struct me_curbe_parameters me_curbe_params;
	struct i965_gpe_context *gpe_context;
	struct me_surface_parameters me_surface_params;
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	unsigned int down_scaled_width_in_mbs, down_scaled_height_in_mbs;
	unsigned int ref_frame_flag_final, ref_frame_flag;
	int gpe_index, media_function;

	if (vp8_context->frame_type == MPEG_P_PICTURE) {
		ref_frame_flag = VP8_REF_FLAG_ALL;

		if (pic_param->ref_last_frame == pic_param->ref_gf_frame) {
			ref_frame_flag &= ~VP8_REF_FLAG_GOLDEN;
		}

		if (pic_param->ref_last_frame == pic_param->ref_arf_frame) {
			ref_frame_flag &= ~VP8_REF_FLAG_ALT;
		}

		if (pic_param->ref_gf_frame == pic_param->ref_arf_frame) {
			ref_frame_flag &= ~VP8_REF_FLAG_ALT;
		}
	} else {
		ref_frame_flag = VP8_REF_FLAG_LAST;
	}

	switch (vp8_context->ref_frame_ctrl) {
	case 0:
		ref_frame_flag_final = VP8_REF_FLAG_NONE;
		break;

	case 1:
		ref_frame_flag_final = VP8_REF_FLAG_LAST;       // Last Ref only
		break;

	case 2:
		ref_frame_flag_final = VP8_REF_FLAG_GOLDEN;     // Gold Ref only
		break;

	case 4:
		ref_frame_flag_final = VP8_REF_FLAG_ALT;        // Alt Ref only
		break;

	default:
		ref_frame_flag_final = ref_frame_flag;
	}

	vp8_context->ref_frame_ctrl = ref_frame_flag_final;
	vp8_context->ref_ctrl_optimization_done = 1;

	if (use_16x_me) {
		gpe_index = VP8_ME_16X;
		media_function = VP8_MEDIA_STATE_16X_ME;
		down_scaled_width_in_mbs = vp8_context->down_scaled_width_in_mb16x;
		down_scaled_height_in_mbs = vp8_context->down_scaled_height_in_mb16x;
	} else {
		gpe_index = VP8_ME_4X;
		media_function = VP8_MEDIA_STATE_4X_ME;
		down_scaled_width_in_mbs = vp8_context->down_scaled_width_in_mb4x;
		down_scaled_height_in_mbs = vp8_context->down_scaled_height_in_mb4x;
	}

	gpe_context = &me_context->gpe_contexts[gpe_index];

	gpe->context_init(ctx, gpe_context);
	gpe->reset_binding_table(ctx, gpe_context);

	memset(&me_curbe_params, 0, sizeof(me_curbe_params));
	me_curbe_params.down_scaled_width_in_mbs = down_scaled_width_in_mbs;
	me_curbe_params.down_scaled_height_in_mbs = down_scaled_height_in_mbs;
	me_curbe_params.use_16x_me = use_16x_me;
	i965_encoder_vp8_vme_me_set_curbe(ctx, encode_state, encoder_context, gpe_context, &me_curbe_params);

	if (vp8_context->brc_distortion_buffer_need_reset && !use_16x_me) {
		i965_encoder_vp8_vme_init_brc_distorion_buffer(ctx, encoder_context);
	}

	memset(&me_surface_params, 0, sizeof(me_surface_params));
	me_surface_params.use_16x_me = use_16x_me;
	i965_encoder_vp8_vme_me_add_surfaces(ctx, encode_state, encoder_context, gpe_context, &me_surface_params);

	gpe->setup_interface_data(ctx, gpe_context);

	memset(&kernel_walker_params, 0, sizeof(kernel_walker_params));
	kernel_walker_params.resolution_x = down_scaled_width_in_mbs;
	kernel_walker_params.resolution_y = down_scaled_height_in_mbs;
	kernel_walker_params.no_dependency = 1;
	i965_init_media_object_walker_parameters(encoder_context, &kernel_walker_params, &media_object_walker_param);

	i965_run_kernel_media_object_walker(ctx, encoder_context, gpe_context, media_function, &media_object_walker_param);

	return VA_STATUS_SUCCESS;
}

#define QUANT_INDEX(index, q_index, q_index_delta)                      \
	do {                                                                \
		index = quant_param->quantization_index[q_index] + quant_param->quantization_index_delta[q_index_delta]; \
		index = MIN(MAX_QP_VP8, index);                            \
	} while (0)

static void
i965_encoder_vp8_vme_mbenc_set_i_frame_curbe(VADriverContextP ctx,
											 struct encode_state *encode_state,
											 struct intel_encoder_context *encoder_context,
											 struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct vp8_mbenc_i_frame_curbe_data *pcmd = i965_gpe_context_map_curbe(gpe_context);
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	VAQMatrixBufferVP8 *quant_param = (VAQMatrixBufferVP8 *)encode_state->q_matrix->buffer;
	unsigned int segmentation_enabled = pic_param->pic_flags.bits.segmentation_enabled;
	unsigned short y_quanta_dc_idx, uv_quanta_dc_idx, uv_quanta_ac_idx;

	if (!pcmd)
		return;

	memset(pcmd, 0, sizeof(*pcmd));

	pcmd->dw0.frame_width = vp8_context->frame_width;
	pcmd->dw0.frame_height = vp8_context->frame_height;

	pcmd->dw1.frame_type = 0; /* key frame */
	pcmd->dw1.enable_segmentation = segmentation_enabled;
	pcmd->dw1.enable_hw_intra_prediction = (encoder_context->quality_level == ENCODER_LOW_QUALITY) ? 1 : 0;
	pcmd->dw1.enable_chroma_ip_enhancement = 1; /* Cannot be disabled */
	pcmd->dw1.enable_debug_dumps = 0;
	pcmd->dw1.enable_mpu_histogram_update = 1;
	pcmd->dw1.vme_distortion_measure = 2; /* HAAR transform */
	pcmd->dw1.vme_enable_tm_check = 0;

	QUANT_INDEX(y_quanta_dc_idx, 0, 0);
	pcmd->dw2.lambda_seg_0 = (unsigned short)((quant_dc_vp8[y_quanta_dc_idx] * quant_dc_vp8[y_quanta_dc_idx]) / 4);

	if (segmentation_enabled) {
		QUANT_INDEX(y_quanta_dc_idx, 1, 0);
		pcmd->dw2.lambda_seg_1 = (unsigned short)((quant_dc_vp8[y_quanta_dc_idx] * quant_dc_vp8[y_quanta_dc_idx]) / 4);

		QUANT_INDEX(y_quanta_dc_idx, 2, 0);
		pcmd->dw3.lambda_seg_2 = (unsigned short)((quant_dc_vp8[y_quanta_dc_idx] * quant_dc_vp8[y_quanta_dc_idx]) / 4);

		QUANT_INDEX(y_quanta_dc_idx, 3, 0);
		pcmd->dw3.lambda_seg_3 = (unsigned short)((quant_dc_vp8[y_quanta_dc_idx] * quant_dc_vp8[y_quanta_dc_idx]) / 4);
	}

	pcmd->dw4.all_dc_bias_segment_0 = DC_BIAS_SEGMENT_DEFAULT_VAL_VP8;

	if (segmentation_enabled) {
		pcmd->dw4.all_dc_bias_segment_1 = DC_BIAS_SEGMENT_DEFAULT_VAL_VP8;
		pcmd->dw5.all_dc_bias_segment_2 = DC_BIAS_SEGMENT_DEFAULT_VAL_VP8;
		pcmd->dw5.all_dc_bias_segment_3 = DC_BIAS_SEGMENT_DEFAULT_VAL_VP8;
	}

	QUANT_INDEX(uv_quanta_dc_idx, 0, 1);
	pcmd->dw6.chroma_dc_de_quant_segment_0 = quant_dc_vp8[uv_quanta_dc_idx];

	if (segmentation_enabled) {
		QUANT_INDEX(uv_quanta_dc_idx, 1, 1);
		pcmd->dw6.chroma_dc_de_quant_segment_1 = quant_dc_vp8[uv_quanta_dc_idx];

		QUANT_INDEX(uv_quanta_dc_idx, 2, 1);
		pcmd->dw7.chroma_dc_de_quant_segment_2 = quant_dc_vp8[uv_quanta_dc_idx];

		QUANT_INDEX(uv_quanta_dc_idx, 3, 1);
		pcmd->dw7.chroma_dc_de_quant_segment_3 = quant_dc_vp8[uv_quanta_dc_idx];
	}

	QUANT_INDEX(uv_quanta_ac_idx, 0, 2);
	pcmd->dw8.chroma_ac_de_quant_segment0 = quant_ac_vp8[uv_quanta_ac_idx];
	pcmd->dw10.chroma_ac0_threshold0_segment0 = (unsigned short)((((((1) << 16) -
																	1) * 1.0 / ((1 << 16) / quant_ac_vp8[uv_quanta_ac_idx]) -
																   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7)) *
																  (1 << 13) + 3400) / 2217.0);
	pcmd->dw10.chroma_ac0_threshold1_segment0 = (unsigned short)((((((2) << 16) -
																	1) * 1.0 / ((1 << 16) / quant_ac_vp8[uv_quanta_ac_idx]) -
																   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7)) *
																  (1 << 13) + 3400) / 2217.0);

	if (segmentation_enabled) {
		QUANT_INDEX(uv_quanta_ac_idx, 1, 2);
		pcmd->dw8.chroma_ac_de_quant_segment1 = quant_ac_vp8[uv_quanta_ac_idx];
		pcmd->dw10.chroma_ac0_threshold0_segment0 = (unsigned short)((((((1) << 16) -
																		1) * 1.0 / ((1 << 16) /
																					quant_ac_vp8[uv_quanta_ac_idx]) -
																	   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7)) *
																	  (1 << 13) + 3400) / 2217.0);
		pcmd->dw10.chroma_ac0_threshold1_segment0 = (unsigned short)((((((2) << 16) -
																		1) * 1.0 / ((1 << 16) /
																					quant_ac_vp8[uv_quanta_ac_idx]) -
																	   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7)) *
																	  (1 << 13) + 3400) / 2217.0);

		QUANT_INDEX(uv_quanta_ac_idx, 2, 2);
		pcmd->dw9.chroma_ac_de_quant_segment2 = quant_ac_vp8[uv_quanta_ac_idx];
		pcmd->dw12.chroma_ac0_threshold0_segment2 = (unsigned short)((((((1) << 16) -
																		1) * 1.0 / ((1 << 16) /
																					quant_ac_vp8[uv_quanta_ac_idx]) -
																	   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7)) *
																	  (1 << 13) + 3400) / 2217.0);
		pcmd->dw12.chroma_ac0_threshold1_segment2 = (unsigned short)((((((2) << 16) -
																		1) * 1.0 / ((1 << 16) /
																					quant_ac_vp8[uv_quanta_ac_idx]) -
																	   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7)) *
																	  (1 << 13) + 3400) / 2217.0);

		QUANT_INDEX(uv_quanta_ac_idx, 3, 2);
		pcmd->dw9.chroma_ac_de_quant_segment3 = quant_ac_vp8[uv_quanta_ac_idx];
		pcmd->dw13.chroma_ac0_threshold0_segment3 = (unsigned short)((((((1) << 16) -
																		1) * 1.0 / ((1 << 16) /
																					quant_ac_vp8[uv_quanta_ac_idx]) -
																	   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7)) *
																	  (1 << 13) + 3400) / 2217.0);
		pcmd->dw13.chroma_ac0_threshold1_segment3 = (unsigned short)((((((2) << 16) -
																		1) * 1.0 / ((1 << 16) /
																					quant_ac_vp8[uv_quanta_ac_idx]) -
																	   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7)) *
																	  (1 << 13) + 3400) / 2217.0);
	}

	QUANT_INDEX(uv_quanta_dc_idx, 0, 1);
	pcmd->dw14.chroma_dc_threshold0_segment0 = (((1) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
											   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
	pcmd->dw14.chroma_dc_threshold1_segment0 = (((2) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
											   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
	pcmd->dw15.chroma_dc_threshold2_segment0 = (((3) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
											   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
	pcmd->dw15.chroma_dc_threshold3_segment0 = (((4) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
											   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);

	if (segmentation_enabled) {
		QUANT_INDEX(uv_quanta_dc_idx, 1, 1);
		pcmd->dw16.chroma_dc_threshold0_segment1 = (((1) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
		pcmd->dw16.chroma_dc_threshold1_segment1 = (((2) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
		pcmd->dw17.chroma_dc_threshold2_segment1 = (((3) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
		pcmd->dw17.chroma_dc_threshold3_segment1 = (((4) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);

		QUANT_INDEX(uv_quanta_dc_idx, 2, 1);
		pcmd->dw18.chroma_dc_threshold0_segment2 = (((1) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
		pcmd->dw18.chroma_dc_threshold1_segment2 = (((2) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
		pcmd->dw19.chroma_dc_threshold2_segment2 = (((3) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
		pcmd->dw19.chroma_dc_threshold3_segment2 = (((4) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);

		QUANT_INDEX(uv_quanta_dc_idx, 3, 1);
		pcmd->dw20.chroma_dc_threshold0_segment3 = (((1) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
		pcmd->dw20.chroma_dc_threshold1_segment3 = (((2) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
		pcmd->dw21.chroma_dc_threshold2_segment3 = (((3) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
		pcmd->dw21.chroma_dc_threshold3_segment3 = (((4) << 16) - 1) / ((1 << 16) / quant_dc_vp8[uv_quanta_dc_idx]) -
												   ((48 * quant_dc_vp8[uv_quanta_dc_idx]) >> 7);
	}

	QUANT_INDEX(uv_quanta_ac_idx, 0, 2);
	pcmd->dw22.chroma_ac1_threshold_segment0 = ((1 << (16)) - 1) / ((1 << 16) / quant_ac_vp8[uv_quanta_ac_idx]) -
											   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7);

	if (segmentation_enabled) {
		QUANT_INDEX(uv_quanta_ac_idx, 1, 2);
		pcmd->dw22.chroma_ac1_threshold_segment1 = ((1 << (16)) - 1) / ((1 << 16) / quant_ac_vp8[uv_quanta_ac_idx]) -
												   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7);

		QUANT_INDEX(uv_quanta_ac_idx, 2, 2);
		pcmd->dw23.chroma_ac1_threshold_segment2 = ((1 << (16)) - 1) / ((1 << 16) / quant_ac_vp8[uv_quanta_ac_idx]) -
												   ((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7);

		QUANT_INDEX(uv_quanta_ac_idx, 3, 2);
		pcmd->dw23.chroma_ac1_threshold_segment3 =
			((1 << (16)) - 1) / ((1 << 16) / quant_ac_vp8[uv_quanta_ac_idx]) -
			((48 * quant_ac_vp8[uv_quanta_ac_idx]) >> 7);
	}

	QUANT_INDEX(uv_quanta_dc_idx, 0, 0);
	pcmd->dw24.vme_16x16_cost_segment0 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][0];
	pcmd->dw25.vme_4x4_cost_segment0 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][1];
	pcmd->dw26.vme_16x16_non_dc_penalty_segment0 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][2];
	pcmd->dw27.vme_4x4_non_dc_penalty_segment0 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][3];

	if (segmentation_enabled) {
		QUANT_INDEX(uv_quanta_dc_idx, 1, 0);
		pcmd->dw24.vme_16x16_cost_segment1 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][0];
		pcmd->dw25.vme_4x4_cost_segment1 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][1];
		pcmd->dw26.vme_16x16_non_dc_penalty_segment1 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][2];
		pcmd->dw27.vme_4x4_non_dc_penalty_segment1 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][3];

		QUANT_INDEX(uv_quanta_dc_idx, 2, 0);
		pcmd->dw24.vme_16x16_cost_segment2 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][0];
		pcmd->dw25.vme_4x4_cost_segment2 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][1];
		pcmd->dw26.vme_16x16_non_dc_penalty_segment2 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][2];
		pcmd->dw27.vme_4x4_non_dc_penalty_segment2 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][3];

		QUANT_INDEX(uv_quanta_dc_idx, 3, 0);
		pcmd->dw24.vme_16x16_cost_segment3 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][0];
		pcmd->dw25.vme_4x4_cost_segment3 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][1];
		pcmd->dw26.vme_16x16_non_dc_penalty_segment3 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][2];
		pcmd->dw27.vme_4x4_non_dc_penalty_segment3 = i_frame_vme_costs_vp8[uv_quanta_dc_idx & 0x7F][3];
	}

	pcmd->dw32.mb_enc_per_mb_out_data_surf_bti = VP8_BTI_MBENC_PER_MB_OUT;
	pcmd->dw33.mb_enc_curr_y_bti = VP8_BTI_MBENC_CURR_Y;
	pcmd->dw34.mb_enc_curr_uv_bti = VP8_BTI_MBENC_CURR_Y;
	pcmd->dw35.mb_mode_cost_luma_bti = VP8_BTI_MBENC_MB_MODE_COST_LUMA;
	pcmd->dw36.mb_enc_block_mode_cost_bti = VP8_BTI_MBENC_BLOCK_MODE_COST;
	pcmd->dw37.chroma_recon_surf_bti = VP8_BTI_MBENC_CHROMA_RECON;
	pcmd->dw38.segmentation_map_bti = VP8_BTI_MBENC_SEGMENTATION_MAP;
	pcmd->dw39.histogram_bti = VP8_BTI_MBENC_HISTOGRAM;
	pcmd->dw40.mb_enc_vme_debug_stream_out_bti = VP8_BTI_MBENC_I_VME_DEBUG_STREAMOUT;
	pcmd->dw41.vme_bti = VP8_BTI_MBENC_VME;
	pcmd->dw42.idist_surface_bti = VP8_BTI_MBENC_IDIST;
	pcmd->dw43.curr_y_down_scaled_bti = VP8_BTI_MBENC_CURR_Y_DOWNSCALED;
	pcmd->dw44.vme_coarse_intra_bti = VP8_BTI_MBENC_VME_COARSE_INTRA;

	i965_gpe_context_unmap_curbe(gpe_context);
}

static void
i965_encoder_vp8_vme_mbenc_set_p_frame_curbe(VADriverContextP ctx,
											 struct encode_state *encode_state,
											 struct intel_encoder_context *encoder_context,
											 struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct vp8_mbenc_p_frame_curbe_data *pcmd = i965_gpe_context_map_curbe(gpe_context);
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	VAQMatrixBufferVP8 *quant_param = (VAQMatrixBufferVP8 *)encode_state->q_matrix->buffer;
	unsigned int segmentation_enabled = pic_param->pic_flags.bits.segmentation_enabled;
	unsigned short qp_seg0, qp_seg1, qp_seg2, qp_seg3;
	unsigned char me_method = (encoder_context->quality_level == ENCODER_DEFAULT_QUALITY) ? 6 : 4;

	if (!pcmd)
		return;

	memset(pcmd, 0, sizeof(*pcmd));

	QUANT_INDEX(qp_seg0, 0, 0);
	QUANT_INDEX(qp_seg1, 0, 0);
	QUANT_INDEX(qp_seg2, 0, 0);
	QUANT_INDEX(qp_seg3, 3, 0);

	pcmd->dw0.frame_width = vp8_context->frame_width;
	pcmd->dw0.frame_height = vp8_context->frame_height;

	pcmd->dw1.frame_type = 1;   // P-frame
	pcmd->dw1.multiple_pred = (encoder_context->quality_level == ENCODER_DEFAULT_QUALITY) ? 1 :
							  ((encoder_context->quality_level == ENCODER_LOW_QUALITY) ? 0 : 2);
	pcmd->dw1.hme_enable = vp8_context->hme_enabled;
	pcmd->dw1.hme_combine_overlap = 1;
	pcmd->dw1.enable_temporal_scalability = 0;
	pcmd->dw1.ref_frame_flags = vp8_context->ref_frame_ctrl;
	pcmd->dw1.enable_segmentation = segmentation_enabled;
	pcmd->dw1.enable_segmentation_info_update = 1;
	pcmd->dw1.multi_reference_qp_check = 0;
	pcmd->dw1.mode_cost_enable_flag = 1;
	pcmd->dw1.main_ref = mainref_table_vp8[vp8_context->ref_frame_ctrl];

	pcmd->dw2.lambda_intra_segment0 = quant_dc_vp8[qp_seg0];
	pcmd->dw2.lambda_inter_segment0 = (quant_dc_vp8[qp_seg0] >> 2);

	pcmd->dw3.lambda_intra_segment1 = quant_dc_vp8[qp_seg1];
	pcmd->dw3.lambda_inter_segment1 = (quant_dc_vp8[qp_seg1] >> 2);

	pcmd->dw4.lambda_intra_segment2 = quant_dc_vp8[qp_seg2];
	pcmd->dw4.lambda_inter_segment2 = (quant_dc_vp8[qp_seg2] >> 2);

	pcmd->dw5.lambda_intra_segment3 = quant_dc_vp8[qp_seg3];
	pcmd->dw5.lambda_inter_segment3 = (quant_dc_vp8[qp_seg3] >> 2);

	pcmd->dw6.reference_frame_sign_bias_3 = pic_param->pic_flags.bits.sign_bias_golden;
	pcmd->dw6.reference_frame_sign_bias_2 = pic_param->pic_flags.bits.sign_bias_alternate;
	pcmd->dw6.reference_frame_sign_bias_1 = pic_param->pic_flags.bits.sign_bias_golden ^ pic_param->pic_flags.bits.sign_bias_alternate;
	pcmd->dw6.reference_frame_sign_bias_0 = 0;

	pcmd->dw7.raw_dist_threshold = (encoder_context->quality_level == ENCODER_DEFAULT_QUALITY) ? 50 :
								   ((encoder_context->quality_level == ENCODER_LOW_QUALITY) ? 0 : 100);
	pcmd->dw7.temporal_layer_id = 0;

	pcmd->dw8.early_ime_successful_stop_threshold = 0;
	pcmd->dw8.adaptive_search_enable = (encoder_context->quality_level != ENCODER_LOW_QUALITY) ? 1 : 0;
	pcmd->dw8.skip_mode_enable = 1;
	pcmd->dw8.bidirectional_mix_disbale = 0;
	pcmd->dw8.transform8x8_flag_for_inter_enable = 0;
	pcmd->dw8.early_ime_success_enable = 0;

	pcmd->dw9.ref_pixel_bias_enable = 0;
	pcmd->dw9.unidirection_mix_enable = 0;
	pcmd->dw9.bidirectional_weight = 0;
	pcmd->dw9.ref_id_polarity_bits = 0;
	pcmd->dw9.max_num_of_motion_vectors = 0;

	pcmd->dw10.max_fixed_search_path_length = (encoder_context->quality_level == ENCODER_DEFAULT_QUALITY) ? 25 :
											  ((encoder_context->quality_level == ENCODER_LOW_QUALITY) ? 9 : 57);
	pcmd->dw10.maximum_search_path_length = 57;

	pcmd->dw11.submacro_block_subPartition_mask = 0;
	pcmd->dw11.intra_sad_measure_adjustment = 2;
	pcmd->dw11.inter_sad_measure_adjustment = 2;
	pcmd->dw11.block_based_skip_enable = 0;
	pcmd->dw11.bme_disable_for_fbr_message = 0;
	pcmd->dw11.forward_trans_form_skip_check_enable = 0;
	pcmd->dw11.process_inter_chroma_pixels_mode = 0;
	pcmd->dw11.disable_field_cache_allocation = 0;
	pcmd->dw11.skip_mode_type = 0;
	pcmd->dw11.sub_pel_mode = 3;
	pcmd->dw11.dual_search_path_option = 0;
	pcmd->dw11.search_control = 0;
	pcmd->dw11.reference_access = 0;
	pcmd->dw11.source_access = 0;
	pcmd->dw11.inter_mb_type_road_map = 0;
	pcmd->dw11.source_block_size = 0;

	pcmd->dw12.reference_search_windows_height = (encoder_context->quality_level != ENCODER_LOW_QUALITY) ? 40 : 28;
	pcmd->dw12.reference_search_windows_width = (encoder_context->quality_level != ENCODER_LOW_QUALITY) ? 48 : 28;

	pcmd->dw13.mode_0_3_cost_seg0 = cost_table_vp8[qp_seg0][0];
	pcmd->dw14.mode_4_7_cost_seg0 = cost_table_vp8[qp_seg0][1];
	pcmd->dw15.mode_8_9_ref_id_chroma_cost_seg0 = cost_table_vp8[qp_seg0][2];

	switch (me_method) {
	case 2:
		memcpy(&(pcmd->dw16), single_su_vp8, sizeof(single_su_vp8));
		break;

	case 3:
		memcpy(&(pcmd->dw16), raster_scan_48x40_vp8, sizeof(raster_scan_48x40_vp8));
		break;

	case 4:
	case 5:
		memcpy(&(pcmd->dw16), full_spiral_48x40_vp8, sizeof(full_spiral_48x40_vp8));
		break;

	case 6:
	default:
		memcpy(&(pcmd->dw16), diamond_vp8, sizeof(diamond_vp8));
		break;
	}

	pcmd->dw30.mv_0_3_cost_seg0 = cost_table_vp8[qp_seg0][3];
	pcmd->dw31.mv_4_7_cost_seg0 = cost_table_vp8[qp_seg0][4];

	pcmd->dw32.bilinear_enable = 0;
	pcmd->dw32.intra_16x16_no_dc_penalty_segment0 = cost_table_vp8[qp_seg0][5];
	pcmd->dw32.intra_16x16_no_dc_penalty_segment1 = cost_table_vp8[qp_seg1][5];

	pcmd->dw33.intra_16x16_no_dc_penalty_segment2 = cost_table_vp8[qp_seg2][5];
	pcmd->dw33.intra_16x16_no_dc_penalty_segment3 = cost_table_vp8[qp_seg3][5];
	pcmd->dw33.hme_combine_len = 8;

	/* dw34 to dw 57 */
	memcpy(&(pcmd->dw34), mv_ref_cost_context_vp8, 24 * sizeof(unsigned int));

	pcmd->dw58.enc_cost_16x16 = 0;
	pcmd->dw58.enc_cost_16x8 = 0x73c;

	pcmd->dw59.enc_cost_8x8 = 0x365;
	pcmd->dw59.enc_cost_4x4 = 0xdc9;

	pcmd->dw60.frame_count_probability_ref_frame_cost_0 = 0x0204;
	pcmd->dw60.frame_count_probability_ref_frame_cost_1 = 0x006a;

	pcmd->dw61.frame_count_probability_ref_frame_cost_2 = 0x0967;
	pcmd->dw61.frame_count_probability_ref_frame_cost_3 = 0x0969;

	switch (vp8_context->frame_num % vp8_context->gop_size) {
	case 1:
		pcmd->dw62.average_qp_of_last_ref_frame = quant_dc_vp8[vp8_context->average_i_frame_qp];
		pcmd->dw62.average_qp_of_gold_ref_frame = pcmd->dw62.average_qp_of_last_ref_frame;
		pcmd->dw62.average_qp_of_alt_ref_frame  = pcmd->dw62.average_qp_of_last_ref_frame;
		break;

	case 2:
		pcmd->dw62.average_qp_of_last_ref_frame = quant_dc_vp8[vp8_context->average_p_frame_qp];
		pcmd->dw62.average_qp_of_gold_ref_frame = quant_dc_vp8[vp8_context->average_i_frame_qp];
		pcmd->dw62.average_qp_of_alt_ref_frame  = pcmd->dw62.average_qp_of_gold_ref_frame;
		break;

	case 3:
		pcmd->dw62.average_qp_of_last_ref_frame = quant_dc_vp8[vp8_context->average_p_frame_qp];
		pcmd->dw62.average_qp_of_gold_ref_frame = quant_dc_vp8[vp8_context->average_p_frame_qp];
		pcmd->dw62.average_qp_of_alt_ref_frame  = quant_dc_vp8[vp8_context->average_i_frame_qp];
		break;

	default:
		pcmd->dw62.average_qp_of_last_ref_frame = quant_dc_vp8[vp8_context->average_p_frame_qp];
		pcmd->dw62.average_qp_of_gold_ref_frame = pcmd->dw62.average_qp_of_last_ref_frame;
		pcmd->dw62.average_qp_of_alt_ref_frame  = pcmd->dw62.average_qp_of_last_ref_frame;
		break;
	}

	pcmd->dw63.intra_4x4_no_dc_penalty_segment0 = cost_table_vp8[qp_seg0][6];
	pcmd->dw63.intra_4x4_no_dc_penalty_segment1 = cost_table_vp8[qp_seg1][6];
	pcmd->dw63.intra_4x4_no_dc_penalty_segment2 = cost_table_vp8[qp_seg2][6];
	pcmd->dw63.intra_4x4_no_dc_penalty_segment3 = cost_table_vp8[qp_seg3][6];

	pcmd->dw64.mode_0_3_cost_seg1 = cost_table_vp8[qp_seg1][0];
	pcmd->dw65.mode_4_7_cost_seg1 = cost_table_vp8[qp_seg1][1];
	pcmd->dw66.mode_8_9_ref_id_chroma_cost_seg1 = cost_table_vp8[qp_seg1][2];

	pcmd->dw67.mv_0_3_cost_seg1 = cost_table_vp8[qp_seg1][3];
	pcmd->dw68.mv_4_7_cost_seg1 = cost_table_vp8[qp_seg1][4];

	pcmd->dw69.mode_0_3_cost_seg2 = cost_table_vp8[qp_seg2][0];
	pcmd->dw70.mode_4_7_cost_seg2 = cost_table_vp8[qp_seg2][1];
	pcmd->dw71.mode_8_9_ref_id_chroma_cost_seg2 = cost_table_vp8[qp_seg2][2];

	pcmd->dw72.mv_0_3_cost_seg2 = cost_table_vp8[qp_seg2][3];
	pcmd->dw73.mv_4_7_cost_seg2 = cost_table_vp8[qp_seg2][4];

	pcmd->dw74.mode_0_3_cost_seg3 = cost_table_vp8[qp_seg3][0];
	pcmd->dw75.mode_4_7_cost_seg3 = cost_table_vp8[qp_seg3][1];
	pcmd->dw76.mode_8_9_ref_id_chroma_cost_seg3 = cost_table_vp8[qp_seg3][2];

	pcmd->dw77.mv_0_3_cost_seg3 = cost_table_vp8[qp_seg3][3];
	pcmd->dw78.mv_4_7_cost_seg3 = cost_table_vp8[qp_seg3][4];

	pcmd->dw79.new_mv_skip_threshold_segment0 = new_mv_skip_threshold_vp8[qp_seg0];
	pcmd->dw79.new_mv_skip_threshold_segment1 = new_mv_skip_threshold_vp8[qp_seg1];
	pcmd->dw80.new_mv_skip_threshold_segment2 = new_mv_skip_threshold_vp8[qp_seg2];
	pcmd->dw80.new_mv_skip_threshold_segment3 = new_mv_skip_threshold_vp8[qp_seg3];

	pcmd->dw81.per_mb_output_data_surface_bti = VP8_BTI_MBENC_PER_MB_OUT;
	pcmd->dw82.current_picture_y_surface_bti = VP8_BTI_MBENC_CURR_Y;
	pcmd->dw83.current_picture_interleaved_uv_surface_bti = VP8_BTI_MBENC_CURR_Y;
	pcmd->dw84.hme_mv_data_surface_bti = VP8_BTI_MBENC_MV_DATA_FROM_ME;
	pcmd->dw85.mv_data_surface_bti = VP8_BTI_MBENC_IND_MV_DATA;
	pcmd->dw86.mb_count_per_reference_frame_bti = VP8_BTI_MBENC_REF_MB_COUNT;
	pcmd->dw87.vme_inter_prediction_bti = VP8_BTI_MBENC_INTER_PRED;
	pcmd->dw88.active_ref1_bti = VP8_BTI_MBENC_REF1_PIC;
	pcmd->dw89.active_ref2_bti = VP8_BTI_MBENC_REF2_PIC;
	pcmd->dw90.active_ref3_bti = VP8_BTI_MBENC_REF3_PIC;
	pcmd->dw91.per_mb_quant_data_bti = VP8_BTI_MBENC_P_PER_MB_QUANT;
	pcmd->dw92.segment_map_bti = VP8_BTI_MBENC_SEGMENTATION_MAP;
	pcmd->dw93.inter_prediction_distortion_bti = VP8_BTI_MBENC_INTER_PRED_DISTORTION;
	pcmd->dw94.histogram_bti = VP8_BTI_MBENC_HISTOGRAM;
	pcmd->dw95.pred_mv_data_bti = VP8_BTI_MBENC_PRED_MV_DATA;
	pcmd->dw96.mode_cost_update_bti = VP8_BTI_MBENC_MODE_COST_UPDATE;
	pcmd->dw97.kernel_debug_dump_bti = VP8_BTI_MBENC_P_VME_DEBUG_STREAMOUT;

	i965_gpe_context_unmap_curbe(gpe_context);
}

#undef QUANT_INDEX

static void
i965_encoder_vp8_vme_mbenc_set_curbe(VADriverContextP ctx,
									 struct encode_state *encode_state,
									 struct intel_encoder_context *encoder_context,
									 struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;

	if (vp8_context->frame_type == MPEG_I_PICTURE)
		i965_encoder_vp8_vme_mbenc_set_i_frame_curbe(ctx, encode_state, encoder_context, gpe_context);
	else
		i965_encoder_vp8_vme_mbenc_set_p_frame_curbe(ctx, encode_state, encoder_context, gpe_context);
}

static void
i965_encoder_vp8_vme_mbenc_add_surfaces(VADriverContextP ctx,
										struct encode_state *encode_state,
										struct intel_encoder_context *encoder_context,
										struct i965_gpe_context *gpe_context,
										struct mbenc_surface_parameters *params)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_surface *vp8_surface;
	struct object_surface *obj_surface;
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	unsigned int size = vp8_context->frame_width_in_mbs * vp8_context->frame_height_in_mbs * 16;
	unsigned int segmentation_enabled = pic_param->pic_flags.bits.segmentation_enabled;

	/* Per MB output data buffer */
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->mb_coded_buffer,
								0,
								size,
								0,
								VP8_BTI_MBENC_PER_MB_OUT);

	/* Current input surface Y & UV */
	i965_add_2d_gpe_surface(ctx,
							gpe_context,
							encode_state->input_yuv_object,
							0,
							1,
							I965_SURFACEFORMAT_R8_UNORM,
							VP8_BTI_MBENC_CURR_Y);

	i965_add_2d_gpe_surface(ctx,
							gpe_context,
							encode_state->input_yuv_object,
							1,
							1,
							I965_SURFACEFORMAT_R8_UNORM,
							VP8_BTI_MBENC_CURR_UV);

	/* Current surface for VME */
	i965_add_adv_gpe_surface(ctx,
							 gpe_context,
							 encode_state->input_yuv_object,
							 VP8_BTI_MBENC_VME);

	if (segmentation_enabled) {
		/* TODO check the internal segmetation buffer */
		dri_bo *bo = NULL;

		if (encode_state->encmb_map)
			bo = encode_state->encmb_map->bo;

		if (bo) {
			i965_add_dri_buffer_2d_gpe_surface(ctx,
											   encoder_context,
											   gpe_context,
											   bo,
											   vp8_context->frame_width_in_mbs,
											   vp8_context->frame_height_in_mbs,
											   vp8_context->frame_width_in_mbs,
											   0,
											   I965_SURFACEFORMAT_R8_UNORM,
											   VP8_BTI_MBENC_SEGMENTATION_MAP);
		}
	}

	/* Histogram buffer */
	size = VP8_HISTOGRAM_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->histogram_buffer,
								1,
								size,
								0,
								VP8_BTI_MBENC_HISTOGRAM);

	if (vp8_context->frame_type == MPEG_I_PICTURE) {
		i965_add_buffer_2d_gpe_surface(ctx,
									   gpe_context,
									   &vp8_context->mb_mode_cost_luma_buffer,
									   0,
									   I965_SURFACEFORMAT_R8_UNORM,
									   VP8_BTI_MBENC_MB_MODE_COST_LUMA);

		i965_add_buffer_2d_gpe_surface(ctx,
									   gpe_context,
									   &vp8_context->block_mode_cost_buffer,
									   0,
									   I965_SURFACEFORMAT_R8_UNORM,
									   VP8_BTI_MBENC_BLOCK_MODE_COST);

		/* Chroma recon buffer */
		size = vp8_context->frame_width_in_mbs * vp8_context->frame_height_in_mbs * 64;
		i965_add_buffer_gpe_surface(ctx,
									gpe_context,
									&vp8_context->chroma_recon_buffer,
									0,
									size,
									0,
									VP8_BTI_MBENC_CHROMA_RECON);

		if (params->i_frame_dist_in_use) {
			i965_add_buffer_2d_gpe_surface(ctx,
										   gpe_context,
										   params->me_brc_distortion_buffer,
										   1,
										   I965_SURFACEFORMAT_R8_UNORM,
										   VP8_BTI_MBENC_IDIST);


			vp8_surface = encode_state->reconstructed_object->private_data;
			assert(vp8_surface);

			if (vp8_surface && vp8_surface->scaled_4x_surface_obj) {
				obj_surface = vp8_surface->scaled_4x_surface_obj;
			} else
				obj_surface = NULL;

			if (obj_surface) {
				i965_add_2d_gpe_surface(ctx,
										gpe_context,
										obj_surface,
										0,
										0,
										I965_SURFACEFORMAT_R8_UNORM,
										VP8_BTI_MBENC_CURR_Y_DOWNSCALED);

				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_MBENC_VME_COARSE_INTRA);
			}
		}
	} else {
		size = vp8_context->frame_width_in_mbs * vp8_context->frame_height_in_mbs * 64;

		i965_add_buffer_gpe_surface(ctx,
									gpe_context,
									&vp8_context->mb_coded_buffer,
									1,
									size,
									vp8_context->mv_offset,
									VP8_BTI_MBENC_IND_MV_DATA);

		if (vp8_context->hme_enabled) {
			i965_add_buffer_2d_gpe_surface(ctx,
										   gpe_context,
										   &vp8_context->me_4x_mv_data_buffer,
										   1,
										   I965_SURFACEFORMAT_R8_UNORM,
										   VP8_BTI_MBENC_MV_DATA_FROM_ME);
		}

		i965_add_buffer_gpe_surface(ctx,
									gpe_context,
									&vp8_context->reference_frame_mb_count_buffer,
									0,
									32, /* sizeof(unsigned int) * 8 */
									0,
									VP8_BTI_MBENC_REF_MB_COUNT);

		i965_add_adv_gpe_surface(ctx,
								 gpe_context,
								 encode_state->input_yuv_object,
								 VP8_BTI_MBENC_INTER_PRED);

		if (vp8_context->ref_last_frame &&
			vp8_context->ref_last_frame->bo) {
			obj_surface = vp8_context->ref_last_frame;

			switch (vp8_context->ref_frame_ctrl) {
			case 1:
			case 3:
			case 5:
			case 7:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_MBENC_REF1_PIC);
				break;
			}
		}

		if (vp8_context->ref_gf_frame &&
			vp8_context->ref_gf_frame->bo) {
			obj_surface = vp8_context->ref_gf_frame;

			switch (vp8_context->ref_frame_ctrl) {
			case 2:
			case 6:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_MBENC_REF1_PIC);
				break;

			case 3:
			case 7:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_MBENC_REF2_PIC);
				break;
			}
		}

		if (vp8_context->ref_arf_frame &&
			vp8_context->ref_arf_frame->bo) {
			obj_surface = vp8_context->ref_arf_frame;

			switch (vp8_context->ref_frame_ctrl) {
			case 4:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_MBENC_REF1_PIC);
				break;

			case 5:
			case 6:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_MBENC_REF2_PIC);
				break;

			case 7:
				i965_add_adv_gpe_surface(ctx,
										 gpe_context,
										 obj_surface,
										 VP8_BTI_MBENC_REF3_PIC);
				break;
			}
		}

		i965_add_buffer_2d_gpe_surface(ctx,
									   gpe_context,
									   &vp8_context->per_mb_quant_data_buffer,
									   1,
									   I965_SURFACEFORMAT_R8_UNORM,
									   VP8_BTI_MBENC_P_PER_MB_QUANT);

		i965_add_buffer_2d_gpe_surface(ctx,
									   gpe_context,
									   &vp8_context->me_4x_distortion_buffer,
									   0,
									   I965_SURFACEFORMAT_R8_UNORM,
									   VP8_BTI_MBENC_INTER_PRED_DISTORTION);

		size = vp8_context->frame_width_in_mbs * vp8_context->frame_height_in_mbs * 16;
		i965_add_buffer_gpe_surface(ctx,
									gpe_context,
									&vp8_context->pred_mv_data_buffer,
									0,
									size,
									0,
									VP8_BTI_MBENC_PRED_MV_DATA);

		size = 16 * sizeof(unsigned int);
		i965_add_buffer_gpe_surface(ctx,
									gpe_context,
									&vp8_context->mode_cost_update_buffer,
									1,
									size,
									0,
									VP8_BTI_MBENC_MODE_COST_UPDATE);
	}
}

static void
i965_encoder_vp8_vme_mbenc_init_constant_buffer(VADriverContextP ctx,
												struct encode_state *encode_state,
												struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	char *pbuffer = NULL;

	i965_zero_gpe_resource(&vp8_context->mb_mode_cost_luma_buffer);
	i965_zero_gpe_resource(&vp8_context->block_mode_cost_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->mb_mode_cost_luma_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, mb_mode_cost_luma_vp8, sizeof(mb_mode_cost_luma_vp8));
	i965_unmap_gpe_resource(&vp8_context->mb_mode_cost_luma_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->block_mode_cost_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, block_mode_cost_vp8, sizeof(block_mode_cost_vp8));
	i965_unmap_gpe_resource(&vp8_context->block_mode_cost_buffer);
}

static VAStatus
i965_encoder_vp8_vme_mbenc(VADriverContextP ctx,
						   struct encode_state *encode_state,
						   struct intel_encoder_context *encoder_context,
						   int is_phase2,
						   int is_iframe_dist)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_mbenc_context *mbenc_context = &vp8_context->mbenc_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *gpe_context;
	struct mbenc_surface_parameters mbenc_surface_params;
	struct gpe_media_object_walker_parameter media_object_walker_param;
	struct vp8_encoder_kernel_walker_parameter kernel_walker_param;
	int is_intra = (vp8_context->frame_type == MPEG_I_PICTURE);
	int gpe_index, media_function;

	if (is_iframe_dist) {
		gpe_index = VP8_MBENC_I_FRAME_DIST;
		media_function = VP8_MEDIA_STATE_ENC_I_FRAME_DIST;
	} else if (!is_phase2) {
		if (is_intra) {
			gpe_index = VP8_MBENC_I_FRAME_LUMA;
			media_function = VP8_MEDIA_STATE_ENC_I_FRAME_LUMA;
		} else {
			gpe_index = VP8_MBENC_P_FRAME;
			media_function = VP8_MEDIA_STATE_ENC_P_FRAME;
		}
	} else {
		gpe_index = VP8_MBENC_I_FRAME_CHROMA;
		media_function = VP8_MEDIA_STATE_ENC_I_FRAME_CHROMA;
	}

	gpe_context = &mbenc_context->gpe_contexts[gpe_index];

	if (!is_phase2 || (is_phase2 && vp8_context->brc_mbenc_phase1_ignored)) {
		if (!vp8_context->mbenc_curbe_updated_in_brc_update || is_iframe_dist) {
			VAEncPictureParameterBufferVP8 *pic_param =
				(VAEncPictureParameterBufferVP8 *) encode_state->pic_param_ext->buffer;
			unsigned int ref_frame_flag_final, ref_frame_flag;

			if (!vp8_context->ref_ctrl_optimization_done) {
				if (!is_intra) {
					ref_frame_flag = VP8_REF_FLAG_ALL;

					if (pic_param->ref_last_frame == pic_param->ref_gf_frame) {
						ref_frame_flag &= ~VP8_REF_FLAG_GOLDEN;
					}

					if (pic_param->ref_last_frame == pic_param->ref_arf_frame) {
						ref_frame_flag &= ~VP8_REF_FLAG_ALT;
					}

					if (pic_param->ref_gf_frame == pic_param->ref_arf_frame) {
						ref_frame_flag &= ~VP8_REF_FLAG_ALT;
					}
				} else {
					ref_frame_flag = VP8_REF_FLAG_LAST;
				}

				switch (vp8_context->ref_frame_ctrl) {
				case 0:
					ref_frame_flag_final = VP8_REF_FLAG_NONE;
					break;

				case 1:
					ref_frame_flag_final = VP8_REF_FLAG_LAST;
					break;

				case 2:
					ref_frame_flag_final = VP8_REF_FLAG_GOLDEN;
					break;

				case 4:
					ref_frame_flag_final = VP8_REF_FLAG_ALT;
					break;

				default:
					ref_frame_flag_final = ref_frame_flag;
				}

				vp8_context->ref_frame_ctrl = ref_frame_flag_final;
			}

			i965_encoder_vp8_vme_mbenc_set_curbe(ctx, encode_state, encoder_context, gpe_context);
		}

		if (is_intra) {
			i965_encoder_vp8_vme_mbenc_init_constant_buffer(ctx, encode_state, encoder_context);
		}

		if (vp8_context->brc_distortion_buffer_need_reset && is_iframe_dist) {
			i965_encoder_vp8_vme_init_brc_distorion_buffer(ctx, encoder_context);
		}
	}

	if (!is_phase2 || (is_phase2 && vp8_context->brc_mbenc_phase1_ignored)) {
		i965_zero_gpe_resource(&vp8_context->histogram_buffer);
	}

	gpe->reset_binding_table(ctx, gpe_context);

	memset(&mbenc_surface_params, 0, sizeof(mbenc_surface_params));
	mbenc_surface_params.i_frame_dist_in_use = is_iframe_dist;

	if (is_iframe_dist)
		mbenc_surface_params.me_brc_distortion_buffer = &vp8_context->brc_distortion_buffer;
	else
		mbenc_surface_params.me_brc_distortion_buffer = &vp8_context->me_4x_distortion_buffer;

	i965_encoder_vp8_vme_mbenc_add_surfaces(ctx, encode_state, encoder_context, gpe_context, &mbenc_surface_params);

	gpe->setup_interface_data(ctx, gpe_context);

	memset(&kernel_walker_param, 0, sizeof(kernel_walker_param));

	kernel_walker_param.use_scoreboard = vp8_context->use_hw_scoreboard;

	if (is_iframe_dist) {
		kernel_walker_param.resolution_x = vp8_context->down_scaled_width_in_mb4x;
		kernel_walker_param.resolution_y = vp8_context->down_scaled_height_in_mb4x;
	} else {
		kernel_walker_param.resolution_x = vp8_context->frame_width_in_mbs;
		kernel_walker_param.resolution_y = vp8_context->frame_height_in_mbs;
	}

	if (is_intra && !is_phase2)
		kernel_walker_param.no_dependency = 1;
	else
		kernel_walker_param.walker_degree = VP8_ENCODER_45_DEGREE;

	i965_init_media_object_walker_parameters(encoder_context, &kernel_walker_param, &media_object_walker_param);

	i965_run_kernel_media_object_walker(ctx, encoder_context, gpe_context, media_function, &media_object_walker_param);

	return VA_STATUS_SUCCESS;
}

static void
i965_encoder_vp8_vme_brc_update_set_curbe(VADriverContextP ctx,
										  struct encode_state *encode_state,
										  struct intel_encoder_context *encoder_context,
										  struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct vp8_brc_update_curbe_data *pcmd = i965_gpe_context_map_curbe(gpe_context);
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	VAQMatrixBufferVP8 *quant_param = (VAQMatrixBufferVP8 *)encode_state->q_matrix->buffer;
	int is_intra = (vp8_context->frame_type == MPEG_I_PICTURE);

	if (!pcmd)
		return;

	memset(pcmd, 0, sizeof(*pcmd));

	pcmd->dw2.picture_header_size = 0;

	pcmd->dw3.start_global_adjust_frame0 = 10;
	pcmd->dw3.start_global_adjust_frame1 = 50;

	pcmd->dw4.start_global_adjust_frame2 = 100;
	pcmd->dw4.start_global_adjust_frame3 = 150;

	pcmd->dw5.target_size_flag = 0;

	if (vp8_context->brc_init_current_target_buf_full_in_bits > (double)vp8_context->brc_init_reset_buf_size_in_bits) {
		vp8_context->brc_init_current_target_buf_full_in_bits -= (double)vp8_context->brc_init_reset_buf_size_in_bits;
		pcmd->dw5.target_size_flag = 1;
	}

	pcmd->dw0.target_size = (unsigned int)vp8_context->brc_init_current_target_buf_full_in_bits;

	pcmd->dw5.curr_frame_type = is_intra ? 2 : 0;
	pcmd->dw5.brc_flag = 16 * vp8_context->internal_rate_mode;
	pcmd->dw5.max_num_paks = vp8_context->num_brc_pak_passes;

	pcmd->dw6.tid = 0;
	pcmd->dw6.num_t_levels = 1;

	pcmd->dw8.start_global_adjust_mult0 = 1;
	pcmd->dw8.start_global_adjust_mult1 = 1;
	pcmd->dw8.start_global_adjust_mult2 = 3;
	pcmd->dw8.start_global_adjust_mult3 = 2;

	pcmd->dw9.start_global_adjust_div0 = 40;
	pcmd->dw9.start_global_adjust_div1 = 5;
	pcmd->dw9.start_global_adjust_div2 = 5;
	pcmd->dw9.start_global_adjust_mult4 = 1;

	pcmd->dw10.start_global_adjust_div3 = 3;
	pcmd->dw10.start_global_adjust_div4 = 1;
	pcmd->dw10.qp_threshold0 = 20;
	pcmd->dw10.qp_threshold1 = 40;

	pcmd->dw11.qp_threshold2 = 60;
	pcmd->dw11.qp_threshold3 = 90;
	pcmd->dw11.g_rate_ratio_threshold0 = 40;
	pcmd->dw11.g_rate_ratio_threshold1 = 75;

	pcmd->dw12.g_rate_ratio_threshold2 = 97;
	pcmd->dw12.g_rate_ratio_threshold3 = 103;
	pcmd->dw12.g_rate_ratio_threshold4 = 125;
	pcmd->dw12.g_rate_ratio_threshold5 = 160;

	pcmd->dw13.g_rate_ratio_threshold_qp0 = -3;
	pcmd->dw13.g_rate_ratio_threshold_qp1 = -2;
	pcmd->dw13.g_rate_ratio_threshold_qp2 = -1;
	pcmd->dw13.g_rate_ratio_threshold_qp3 = 0;

	pcmd->dw14.g_rate_ratio_threshold_qp4 = 1;
	pcmd->dw14.g_rate_ratio_threshold_qp5 = 2;
	pcmd->dw14.g_rate_ratio_threshold_qp6 = 3;
	pcmd->dw14.index_of_previous_qp = 0;

	pcmd->dw15.frame_width_in_mb = vp8_context->frame_width_in_mbs;
	pcmd->dw15.frame_height_in_mb = vp8_context->frame_height_in_mbs;

	pcmd->dw16.p_frame_qp_seg0 = quant_param->quantization_index[0];
	pcmd->dw16.p_frame_qp_seg1 = quant_param->quantization_index[1];
	pcmd->dw16.p_frame_qp_seg2 = quant_param->quantization_index[2];
	pcmd->dw16.p_frame_qp_seg3 = quant_param->quantization_index[3];

	pcmd->dw17.key_frame_qp_seg0 = quant_param->quantization_index[0];
	pcmd->dw17.key_frame_qp_seg1 = quant_param->quantization_index[1];
	pcmd->dw17.key_frame_qp_seg2 = quant_param->quantization_index[2];
	pcmd->dw17.key_frame_qp_seg3 = quant_param->quantization_index[3];

	pcmd->dw18.qdelta_plane0 = 0;
	pcmd->dw18.qdelta_plane1 = 0;
	pcmd->dw18.qdelta_plane2 = 0;
	pcmd->dw18.qdelta_plane3 = 0;

	pcmd->dw19.qdelta_plane4 = 0;
	pcmd->dw19.main_ref = is_intra ? 0 : mainref_table_vp8[vp8_context->ref_frame_ctrl];
	pcmd->dw19.ref_frame_flags = is_intra ? 0 : vp8_context->ref_frame_ctrl;

	pcmd->dw20.seg_on = pic_param->pic_flags.bits.segmentation_enabled;
	pcmd->dw20.brc_method = vp8_context->internal_rate_mode;
	pcmd->dw20.mb_rc = 0;

	pcmd->dw20.vme_intra_prediction = (encoder_context->quality_level == ENCODER_LOW_QUALITY) ? 1 : 0;

	pcmd->dw22.historyt_buffer_bti = VP8_BTI_BRC_UPDATE_HISTORY;
	pcmd->dw23.pak_statistics_bti = VP8_BTI_BRC_UPDATE_PAK_STATISTICS_OUTPUT;
	pcmd->dw24.mfx_vp8_encoder_cfg_read_bti = VP8_BTI_BRC_UPDATE_MFX_ENCODER_CFG_READ;
	pcmd->dw25.mfx_vp8_encoder_cfg_write_bti = VP8_BTI_BRC_UPDATE_MFX_ENCODER_CFG_WRITE;
	pcmd->dw26.mbenc_curbe_read_bti = VP8_BTI_BRC_UPDATE_MBENC_CURBE_READ;
	pcmd->dw27.mbenc_curbe_write_bti = VP8_BTI_BRC_UPDATE_MBENC_CURBE_WRITE;
	pcmd->dw28.distortion_bti = VP8_BTI_BRC_UPDATE_DISTORTION_SURFACE;
	pcmd->dw29.constant_data_bti = VP8_BTI_BRC_UPDATE_CONSTANT_DATA;
	pcmd->dw30.segment_map_bti = VP8_BTI_BRC_UPDATE_SEGMENT_MAP;
	pcmd->dw31.mpu_curbe_read_bti = VP8_BTI_BRC_UPDATE_MPU_CURBE_READ;
	pcmd->dw32.mpu_curbe_write_bti = VP8_BTI_BRC_UPDATE_MPU_CURBE_WRITE;
	pcmd->dw33.tpu_curbe_read_bti = VP8_BTI_BRC_UPDATE_TPU_CURBE_READ;
	pcmd->dw34.tpu_curbe_write_bti = VP8_BTI_BRC_UPDATE_TPU_CURBE_WRITE;

	vp8_context->brc_init_current_target_buf_full_in_bits += vp8_context->brc_init_reset_input_bits_per_frame;

	i965_gpe_context_unmap_curbe(gpe_context);
}

static void
i965_encoder_vp8_vme_mpu_set_curbe(VADriverContextP ctx,
								   struct encode_state *encode_state,
								   struct intel_encoder_context *encoder_context,
								   struct i965_gpe_context *gpe_context);
static void
i965_encoder_vp8_pak_tpu_set_curbe(VADriverContextP ctx,
								   struct encode_state *encode_state,
								   struct intel_encoder_context *encoder_context,
								   struct i965_gpe_context *gpe_context);

static void
i965_encoder_vp8_vme_brc_update_add_surfaces(VADriverContextP ctx,
											 struct encode_state *encode_state,
											 struct intel_encoder_context *encoder_context,
											 struct i965_gpe_context *gpe_context,
											 struct brc_update_surface_parameters *params)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	unsigned int size;
	int is_intra = (vp8_context->frame_type == MPEG_I_PICTURE);

	/* BRC history buffer */
	size = VP8_BRC_HISTORY_BUFFER_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->brc_history_buffer,
								0,
								size,
								0,
								VP8_BTI_BRC_UPDATE_HISTORY);

	/* PAK Statistics buffer */
	size = sizeof(struct vp8_brc_pak_statistics);
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->brc_pak_statistics_buffer,
								0,
								size,
								0,
								VP8_BTI_BRC_UPDATE_PAK_STATISTICS_OUTPUT);

	/* Encoder CFG command surface - read only */
	size = VP8_BRC_IMG_STATE_SIZE_PER_PASS * VP8_BRC_MAXIMUM_NUM_PASSES;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->brc_vp8_cfg_command_write_buffer,
								0,
								size,
								0,
								VP8_BTI_BRC_UPDATE_MFX_ENCODER_CFG_READ);

	/* Encoder CFG command surface - write only */
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->brc_vp8_cfg_command_write_buffer,
								0,
								size,
								0,
								VP8_BTI_BRC_UPDATE_MFX_ENCODER_CFG_WRITE);

	/* MBEnc CURBE Buffer - read only */
	size = ALIGN(params->mbenc_gpe_context->curbe.length, 64);
	i965_add_dri_buffer_gpe_surface(ctx,
									encoder_context,
									gpe_context,
									params->mbenc_gpe_context->curbe.bo,
									0,
									size,
									params->mbenc_gpe_context->curbe.offset,
									VP8_BTI_BRC_UPDATE_MBENC_CURBE_READ);

	/* MBEnc CURBE Buffer - write only */
	i965_add_dri_buffer_gpe_surface(ctx,
									encoder_context,
									gpe_context,
									params->mbenc_gpe_context->curbe.bo,
									0,
									size,
									params->mbenc_gpe_context->curbe.offset,
									VP8_BTI_BRC_UPDATE_MBENC_CURBE_WRITE);

	/* BRC Distortion data buffer - input/output */
	i965_add_buffer_2d_gpe_surface(ctx,
								   gpe_context,
								   is_intra ? &vp8_context->brc_distortion_buffer : &vp8_context->me_4x_distortion_buffer,
								   1,
								   I965_SURFACEFORMAT_R8_UNORM,
								   VP8_BTI_BRC_UPDATE_DISTORTION_SURFACE);

	/* Constant Data Surface */
	size = VP8_BRC_CONSTANT_DATA_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->brc_vp8_constant_data_buffer,
								0,
								size,
								0,
								VP8_BTI_BRC_UPDATE_CONSTANT_DATA);

	/* Segmap surface */
	i965_add_buffer_2d_gpe_surface(ctx,
								   gpe_context,
								   &vp8_context->brc_segment_map_buffer,
								   0,
								   I965_SURFACEFORMAT_R8_UNORM,
								   VP8_BTI_BRC_UPDATE_SEGMENT_MAP);

	/* MPU CURBE Buffer - read only */
	size = ALIGN(params->mpu_gpe_context->curbe.length, 64);
	i965_add_dri_buffer_gpe_surface(ctx,
									encoder_context,
									gpe_context,
									params->mpu_gpe_context->curbe.bo,
									0,
									size,
									params->mpu_gpe_context->curbe.offset,
									VP8_BTI_BRC_UPDATE_MPU_CURBE_READ);

	/* MPU CURBE Buffer - write only */
	size = ALIGN(params->mpu_gpe_context->curbe.length, 64);
	i965_add_dri_buffer_gpe_surface(ctx,
									encoder_context,
									gpe_context,
									params->mpu_gpe_context->curbe.bo,
									0,
									size,
									params->mpu_gpe_context->curbe.offset,
									VP8_BTI_BRC_UPDATE_MPU_CURBE_WRITE);

	/* TPU CURBE Buffer - read only */
	size = ALIGN(params->tpu_gpe_context->curbe.length, 64);
	i965_add_dri_buffer_gpe_surface(ctx,
									encoder_context,
									gpe_context,
									params->tpu_gpe_context->curbe.bo,
									0,
									size,
									params->tpu_gpe_context->curbe.offset,
									VP8_BTI_BRC_UPDATE_TPU_CURBE_READ);

	/* TPU CURBE Buffer - write only */
	size = ALIGN(params->tpu_gpe_context->curbe.length, 64);
	i965_add_dri_buffer_gpe_surface(ctx,
									encoder_context,
									gpe_context,
									params->tpu_gpe_context->curbe.bo,
									0,
									size,
									params->tpu_gpe_context->curbe.offset,
									VP8_BTI_BRC_UPDATE_TPU_CURBE_WRITE);
}

static void
i965_encoder_vp8_vme_init_brc_update_constant_data(VADriverContextP ctx,
												   struct encode_state *encode_state,
												   struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	char *pbuffer;

	pbuffer = i965_map_gpe_resource(&vp8_context->brc_vp8_constant_data_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer,
		   brc_qpadjustment_distthreshold_maxframethreshold_distqpadjustment_ipb_vp8,
		   sizeof(brc_qpadjustment_distthreshold_maxframethreshold_distqpadjustment_ipb_vp8));
	pbuffer += sizeof(brc_qpadjustment_distthreshold_maxframethreshold_distqpadjustment_ipb_vp8);

	memcpy(pbuffer, brc_iframe_cost_vp8, sizeof(brc_iframe_cost_vp8));
	pbuffer += sizeof(brc_iframe_cost_vp8);

	memcpy(pbuffer, brc_pframe_cost_vp8, sizeof(brc_pframe_cost_vp8));
	pbuffer += sizeof(brc_pframe_cost_vp8);

	memcpy(pbuffer, quant_dc_vp8, sizeof(quant_dc_vp8));
	pbuffer += sizeof(quant_dc_vp8);

	memcpy(pbuffer, quant_ac_vp8, sizeof(quant_ac_vp8));
	pbuffer += sizeof(quant_ac_vp8);

	memcpy(pbuffer, brc_skip_mv_threshold_vp8, sizeof(brc_skip_mv_threshold_vp8));

	i965_unmap_gpe_resource(&vp8_context->brc_vp8_constant_data_buffer);
}

static void
i965_encoder_vp8_vme_init_mfx_config_command(VADriverContextP ctx,
											 struct encode_state *encode_state,
											 struct intel_encoder_context *encoder_context,
											 struct vp8_mpu_encoder_config_parameters *params);

static VAStatus
i965_encoder_vp8_vme_brc_update(VADriverContextP ctx,
								struct encode_state *encode_state,
								struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_brc_update_context *brc_update_context = &vp8_context->brc_update_context;
	struct i965_encoder_vp8_mbenc_context *mbenc_context = &vp8_context->mbenc_context;
	struct i965_encoder_vp8_mpu_context *mpu_context = &vp8_context->mpu_context;
	struct i965_encoder_vp8_tpu_context *tpu_context = &vp8_context->tpu_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *gpe_context, *mbenc_gpe_context, *mpu_gpe_context, *tpu_gpe_context;
	struct brc_update_surface_parameters brc_update_surface_params;
	struct gpe_media_object_parameter media_object_param;
	struct vp8_mpu_encoder_config_parameters config_params;
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	unsigned int ref_frame_flag_final, ref_frame_flag;
	int is_intra = (vp8_context->frame_type == MPEG_I_PICTURE);
	int media_function = VP8_MEDIA_STATE_BRC_UPDATE;
	int i;

	gpe_context = &brc_update_context->gpe_contexts[0];

	if (is_intra)
		mbenc_gpe_context = &mbenc_context->gpe_contexts[VP8_MBENC_I_FRAME_LUMA];
	else
		mbenc_gpe_context = &mbenc_context->gpe_contexts[VP8_MBENC_P_FRAME];

	mpu_gpe_context = &mpu_context->gpe_contexts[0];
	tpu_gpe_context = &tpu_context->gpe_contexts[0];

	if (!is_intra) {
		ref_frame_flag = VP8_REF_FLAG_ALL;

		if (pic_param->ref_last_frame == pic_param->ref_gf_frame) {
			ref_frame_flag &= ~VP8_REF_FLAG_GOLDEN;
		}

		if (pic_param->ref_last_frame == pic_param->ref_arf_frame) {
			ref_frame_flag &= ~VP8_REF_FLAG_ALT;
		}

		if (pic_param->ref_gf_frame == pic_param->ref_arf_frame) {
			ref_frame_flag &= ~VP8_REF_FLAG_ALT;
		}
	} else {
		ref_frame_flag = VP8_REF_FLAG_LAST;
	}

	switch (vp8_context->ref_frame_ctrl) {
	case 0:
		ref_frame_flag_final = VP8_REF_FLAG_NONE;
		break;

	case 1:
		ref_frame_flag_final = VP8_REF_FLAG_LAST;       // Last Ref only
		break;

	case 2:
		ref_frame_flag_final = VP8_REF_FLAG_GOLDEN;     // Gold Ref only
		break;

	case 4:
		ref_frame_flag_final = VP8_REF_FLAG_ALT;        // Alt Ref only
		break;

	default:
		ref_frame_flag_final = ref_frame_flag;
	}

	vp8_context->ref_frame_ctrl = ref_frame_flag_final;
	i965_encoder_vp8_vme_mbenc_set_curbe(ctx, encode_state, encoder_context, mbenc_gpe_context);
	vp8_context->mbenc_curbe_updated_in_brc_update = 1;

	/* Set MPU & TPU curbe here */
	i965_encoder_vp8_vme_mpu_set_curbe(ctx, encode_state, encoder_context, mpu_gpe_context);
	vp8_context->mpu_curbe_updated_in_brc_update = 1;

	i965_encoder_vp8_pak_tpu_set_curbe(ctx, encode_state, encoder_context, tpu_gpe_context);
	vp8_context->tpu_curbe_updated_in_brc_update = 1;

	gpe->context_init(ctx, gpe_context);
	gpe->reset_binding_table(ctx, gpe_context);

	i965_encoder_vp8_vme_brc_update_set_curbe(ctx, encode_state, encoder_context, gpe_context);

	if (vp8_context->brc_constant_buffer_supported) {
		i965_encoder_vp8_vme_init_brc_update_constant_data(ctx, encode_state, encoder_context);
	}

	memset(&config_params, 0, sizeof(config_params));
	config_params.buffer_size = VP8_HEADER_METADATA_SIZE;
	config_params.config_buffer = &vp8_context->brc_vp8_cfg_command_write_buffer;

	for (i = 0; i < VP8_BRC_MAXIMUM_NUM_PASSES; i++) {
		config_params.is_first_pass = !i;
		config_params.command_offset = i * VP8_HEADER_METADATA_SIZE;
		i965_encoder_vp8_vme_init_mfx_config_command(ctx, encode_state, encoder_context, &config_params);
	}

	vp8_context->mfx_encoder_config_command_initialized = 1;

	memset(&brc_update_surface_params, 0, sizeof(brc_update_surface_params));
	brc_update_surface_params.mbenc_gpe_context = mbenc_gpe_context;
	brc_update_surface_params.mpu_gpe_context = mpu_gpe_context;
	brc_update_surface_params.tpu_gpe_context = tpu_gpe_context;
	i965_encoder_vp8_vme_brc_update_add_surfaces(ctx, encode_state, encoder_context, gpe_context, &brc_update_surface_params);

	gpe->setup_interface_data(ctx, gpe_context);

	memset(&media_object_param, 0, sizeof(media_object_param));
	i965_run_kernel_media_object(ctx, encoder_context, gpe_context, media_function, &media_object_param);

	return VA_STATUS_SUCCESS;
}

static void
i965_encoder_vp8_vme_mpu_set_curbe(VADriverContextP ctx,
								   struct encode_state *encode_state,
								   struct intel_encoder_context *encoder_context,
								   struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct vp8_mpu_curbe_data *pcmd = i965_gpe_context_map_curbe(gpe_context);
	VAEncSequenceParameterBufferVP8 *seq_param = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer;
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	VAQMatrixBufferVP8 *quant_param = (VAQMatrixBufferVP8 *)encode_state->q_matrix->buffer;

	if (!pcmd)
		return;

	memset(pcmd, 0, sizeof(*pcmd));

	pcmd->dw0.frame_width = vp8_context->frame_width;
	pcmd->dw0.frame_height = vp8_context->frame_height;

	pcmd->dw1.frame_type = pic_param->pic_flags.bits.frame_type;
	pcmd->dw1.version = pic_param->pic_flags.bits.version;
	pcmd->dw1.show_frame = pic_param->pic_flags.bits.show_frame;
	pcmd->dw1.horizontal_scale_code = seq_param->frame_width_scale;
	pcmd->dw1.vertical_scale_code = seq_param->frame_height_scale;
	pcmd->dw1.color_space_type = pic_param->pic_flags.bits.color_space;
	pcmd->dw1.clamp_type = pic_param->pic_flags.bits.clamping_type;
	pcmd->dw1.partition_num_l2 = pic_param->pic_flags.bits.num_token_partitions;
	pcmd->dw1.enable_segmentation = pic_param->pic_flags.bits.segmentation_enabled;
	pcmd->dw1.seg_map_update = pic_param->pic_flags.bits.segmentation_enabled ? pic_param->pic_flags.bits.update_mb_segmentation_map : 0;
	pcmd->dw1.segmentation_feature_update = pic_param->pic_flags.bits.update_segment_feature_data;
	pcmd->dw1.segmentation_feature_mode = 1;
	pcmd->dw1.loop_filter_type = pic_param->pic_flags.bits.loop_filter_type;
	pcmd->dw1.sharpness_level = pic_param->sharpness_level;
	pcmd->dw1.loop_filter_adjustment_on = pic_param->pic_flags.bits.loop_filter_adj_enable;
	pcmd->dw1.mb_no_coeffiscient_skip = pic_param->pic_flags.bits.mb_no_coeff_skip;
	pcmd->dw1.golden_reference_copy_flag = ((pic_param->pic_flags.bits.refresh_golden_frame == 1) ? 3 : pic_param->pic_flags.bits.copy_buffer_to_golden);
	pcmd->dw1.alternate_reference_copy_flag = ((pic_param->pic_flags.bits.refresh_alternate_frame == 1) ? 3 : pic_param->pic_flags.bits.copy_buffer_to_alternate);
	pcmd->dw1.last_frame_update = pic_param->pic_flags.bits.refresh_last;
	pcmd->dw1.sign_bias_golden = pic_param->pic_flags.bits.sign_bias_golden;
	pcmd->dw1.sign_bias_alt_ref = pic_param->pic_flags.bits.sign_bias_alternate;
	pcmd->dw1.refresh_entropy_p = pic_param->pic_flags.bits.refresh_entropy_probs;
	pcmd->dw1.forced_lf_update_for_key_frame = pic_param->pic_flags.bits.forced_lf_adjustment;

	pcmd->dw2.loop_filter_level = pic_param->loop_filter_level[0];
	pcmd->dw2.qindex = quant_param->quantization_index[0];
	pcmd->dw2.y1_dc_qindex = quant_param->quantization_index_delta[0];
	pcmd->dw2.y2_dc_qindex = quant_param->quantization_index_delta[3];

	pcmd->dw3.y2_ac_qindex = quant_param->quantization_index_delta[4];
	pcmd->dw3.uv_dc_qindex = quant_param->quantization_index_delta[1];
	pcmd->dw3.uv_ac_qindex = quant_param->quantization_index_delta[2];
	pcmd->dw3.feature_data0_segment0 = quant_param->quantization_index[0];

	pcmd->dw4.feature_data0_segment1 = quant_param->quantization_index[1];
	pcmd->dw4.feature_data0_segment2 = quant_param->quantization_index[2];
	pcmd->dw4.feature_data0_segment3 = quant_param->quantization_index[3];
	pcmd->dw4.feature_data1_segment0 = pic_param->loop_filter_level[0];

	pcmd->dw5.feature_data1_segment1 = pic_param->loop_filter_level[1];
	pcmd->dw5.feature_data1_segment2 = pic_param->loop_filter_level[2];
	pcmd->dw5.feature_data1_segment3 = pic_param->loop_filter_level[3];
	pcmd->dw5.ref_lf_delta0 = pic_param->ref_lf_delta[0];

	pcmd->dw6.ref_lf_delta1 = pic_param->ref_lf_delta[1];
	pcmd->dw6.ref_lf_delta2 = pic_param->ref_lf_delta[2];
	pcmd->dw6.ref_lf_delta3 = pic_param->ref_lf_delta[3];
	pcmd->dw6.mode_lf_delta0 = pic_param->mode_lf_delta[0];

	pcmd->dw7.mode_lf_delta1 = pic_param->mode_lf_delta[1];
	pcmd->dw7.mode_lf_delta2 = pic_param->mode_lf_delta[2];
	pcmd->dw7.mode_lf_delta3 = pic_param->mode_lf_delta[3];
	pcmd->dw7.mc_filter_select = pic_param->pic_flags.bits.version > 0 ? 1 : 0;
	pcmd->dw7.chroma_full_pixel_mc_filter_mode = pic_param->pic_flags.bits.version < 3 ? 0 : 1;
	pcmd->dw7.max_num_pak_passes = vp8_context->num_brc_pak_passes;
	pcmd->dw7.forced_token_surface_read = 1;
	pcmd->dw7.mode_cost_enable_flag = 1;

	pcmd->dw8.num_t_levels = 1;
	pcmd->dw8.temporal_layer_id = 0;

	pcmd->dw12.histogram_bti = VP8_BTI_MPU_HISTOGRAM;
	pcmd->dw13.reference_mode_probability_bti = VP8_BTI_MPU_REF_MODE_PROBABILITY;
	pcmd->dw14.mode_probability_bti = VP8_BTI_MPU_CURR_MODE_PROBABILITY;
	pcmd->dw15.reference_token_probability_bti = VP8_BTI_MPU_REF_TOKEN_PROBABILITY;
	pcmd->dw16.token_probability_bti = VP8_BTI_MPU_CURR_TOKEN_PROBABILITY;
	pcmd->dw17.frame_header_bitstream_bti = VP8_BTI_MPU_HEADER_BITSTREAM;
	pcmd->dw18.header_meta_data_bti = VP8_BTI_MPU_HEADER_METADATA;
	pcmd->dw19.picture_state_bti = VP8_BTI_MPU_PICTURE_STATE;
	pcmd->dw20.mpu_bitstream_bti = VP8_BTI_MPU_MPU_BITSTREAM;
	pcmd->dw21.token_bits_data_bti = VP8_BTI_MPU_TOKEN_BITS_DATA_TABLE;
	pcmd->dw22.kernel_debug_dump_bti = VP8_BTI_MPU_VME_DEBUG_STREAMOUT;
	pcmd->dw23.entropy_cost_bti = VP8_BTI_MPU_ENTROPY_COST_TABLE;
	pcmd->dw24.mode_cost_update_bti = VP8_BTI_MPU_MODE_COST_UPDATE;

	i965_gpe_context_unmap_curbe(gpe_context);
}

static void
i965_encoder_vp8_vme_mpu_add_surfaces(VADriverContextP ctx,
									  struct encode_state *encode_state,
									  struct intel_encoder_context *encoder_context,
									  struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	unsigned int size;
	unsigned char brc_enabled = (vp8_context->internal_rate_mode == I965_BRC_CBR ||
								 vp8_context->internal_rate_mode == I965_BRC_VBR);

	/* Histogram buffer */
	size = VP8_HISTOGRAM_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->histogram_buffer,
								1,
								size,
								0,
								VP8_BTI_MPU_HISTOGRAM);

	// Reference mode probability
	size = VP8_MODE_PROPABILITIES_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_ref_mode_probs_buffer,
								1,
								size,
								0,
								VP8_BTI_MPU_REF_MODE_PROBABILITY);

	// Mode probability
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_mode_probs_buffer,
								1,
								size,
								0,
								VP8_BTI_MPU_CURR_MODE_PROBABILITY);

	// Reference Token probability
	size = VP8_COEFFS_PROPABILITIES_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_ref_coeff_probs_buffer,
								1,
								size,
								0,
								VP8_BTI_MPU_REF_TOKEN_PROBABILITY);

	// Token probability
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_coeff_probs_buffer,
								1,
								size,
								0,
								VP8_BTI_MPU_CURR_TOKEN_PROBABILITY);

	// Frame header
	size = VP8_FRAME_HEADER_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_frame_header_buffer,
								0,
								size,
								0,
								VP8_BTI_MPU_HEADER_BITSTREAM);

	// Header Metadata
	size = VP8_HEADER_METADATA_SIZE;

	if (brc_enabled) {
		i965_add_buffer_gpe_surface(ctx,
									gpe_context,
									&vp8_context->brc_vp8_cfg_command_write_buffer,
									0,
									size,
									0,
									VP8_BTI_MPU_HEADER_METADATA);
	} else {
		i965_add_buffer_gpe_surface(ctx,
									gpe_context,
									&vp8_context->pak_mpu_tpu_picture_state_buffer,
									0,
									size,
									VP8_HEADER_METADATA_OFFSET,
									VP8_BTI_MPU_HEADER_METADATA);
	}

	// Picture state MFX_VP8_PIC_STATE
	size = 38 * sizeof(unsigned int);
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_picture_state_buffer,
								0,
								size,
								0,
								VP8_BTI_MPU_PICTURE_STATE);

	// Mpu Bitstream
	size = VP8_MPU_BITSTREAM_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_mpu_bitstream_buffer,
								0,
								size,
								0,
								VP8_BTI_MPU_MPU_BITSTREAM);

	// Token bits Data Surface
	size = VP8_TOKEN_BITS_DATA_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_token_bits_data_buffer,
								1,
								size,
								0,
								VP8_BTI_MPU_TOKEN_BITS_DATA_TABLE);

	// Entropy cost table
	size = VP8_ENTROPY_COST_TABLE_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_entropy_cost_table_buffer,
								1,
								size,
								0,
								VP8_BTI_MPU_ENTROPY_COST_TABLE);

	//Mode Cost Update Surface
	size = 16 * sizeof(unsigned int);
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->mode_cost_update_buffer,
								0,
								size,
								0,
								VP8_BTI_MPU_MODE_COST_UPDATE);
}

static void
i965_encoder_vp8_vme_update_key_frame_mpu_tpu_buffer(VADriverContextP ctx,
													 struct encode_state *encode_state,
													 struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	char *key_buffer, *pbuffer;

	key_buffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_key_frame_token_probability_buffer);

	if (!key_buffer)
		return;

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_coeff_probs_buffer);

	if (!pbuffer) {
		i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_key_frame_token_probability_buffer);

		return;
	}

	memcpy(pbuffer, key_buffer, VP8_COEFFS_PROPABILITIES_SIZE);
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_coeff_probs_buffer);
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_key_frame_token_probability_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_ref_coeff_probs_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, vp8_default_coef_probs, sizeof(vp8_default_coef_probs));
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_ref_coeff_probs_buffer);

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_hw_token_probability_pak_pass_2_buffer);

	if (!pbuffer)
		return;

	memcpy(pbuffer, vp8_default_coef_probs, sizeof(vp8_default_coef_probs));
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_hw_token_probability_pak_pass_2_buffer);
}

static void
i965_encoder_vp8_vme_init_mfx_config_command(VADriverContextP ctx,
											 struct encode_state *encode_state,
											 struct intel_encoder_context *encoder_context,
											 struct vp8_mpu_encoder_config_parameters *params)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct vp8_mfx_encoder_cfg_cmd *pcmd;
	VAEncSequenceParameterBufferVP8 *seq_param = (VAEncSequenceParameterBufferVP8 *)encode_state->seq_param_ext->buffer;
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	VAQMatrixBufferVP8 *quant_param = (VAQMatrixBufferVP8 *)encode_state->q_matrix->buffer;
	unsigned int segmentation_enabled = pic_param->pic_flags.bits.segmentation_enabled;
	int i;
	char *pbuffer;
	unsigned char brc_enabled = (vp8_context->internal_rate_mode == I965_BRC_CBR ||
								 vp8_context->internal_rate_mode == I965_BRC_VBR);

	pbuffer = i965_map_gpe_resource(params->config_buffer);

	if (!pbuffer)
		return;

	pbuffer += params->command_offset;
	memset(pbuffer, 0, params->buffer_size);

	pcmd = (struct vp8_mfx_encoder_cfg_cmd *)pbuffer;

	pcmd->dw0.value = (MFX_VP8_ENCODER_CFG | (sizeof(*pcmd) / 4 - 2));

	pcmd->dw1.rate_control_initial_pass = params->is_first_pass ? 1 : 0;
	pcmd->dw1.per_segment_delta_qindex_loop_filter_disable  = (params->is_first_pass || !brc_enabled);
	pcmd->dw1.token_statistics_output_enable = 1;

	if (segmentation_enabled) {
		for (i = 1; i < 4; i++) {
			if ((quant_param->quantization_index[i] != quant_param->quantization_index[0]) ||
				(pic_param->loop_filter_level[i] != pic_param->loop_filter_level[0])) {
				pcmd->dw1.update_segment_feature_data_flag = 1;
				break;
			}
		}
	}

	if (brc_enabled) {
		pcmd->dw2.max_frame_bit_count_rate_control_enable_mask = 1;
		pcmd->dw2.min_frame_bit_count_rate_control_enable_mask = 1;
	}

	pcmd->dw22.show_frame = pic_param->pic_flags.bits.show_frame;
	pcmd->dw22.bitstream_format_version = pic_param->pic_flags.bits.version;

	pcmd->dw23.horizontal_size_code = ((seq_param->frame_width_scale << 14) | seq_param->frame_width);
	pcmd->dw23.vertical_size_code = ((seq_param->frame_height_scale << 14) | seq_param->frame_height);

	//Add batch buffer end command
	pbuffer += sizeof(*pcmd);
	*((unsigned int *)pbuffer) = MI_BATCH_BUFFER_END;

	i965_unmap_gpe_resource(params->config_buffer);
}

static VAStatus
i965_encoder_vp8_vme_mpu(VADriverContextP ctx,
						 struct encode_state *encode_state,
						 struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_mpu_context *mpu_context = &vp8_context->mpu_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct gpe_media_object_parameter media_object_param;
	struct i965_gpe_context *gpe_context;
	struct vp8_mpu_encoder_config_parameters config_params;
	int media_function = VP8_MEDIA_STATE_MPU;

	gpe_context = &mpu_context->gpe_contexts[0];
	/* gpe->context_init(ctx, gpe_context); */
	gpe->reset_binding_table(ctx, gpe_context);

	if (vp8_context->frame_type == MPEG_I_PICTURE)
		i965_encoder_vp8_vme_update_key_frame_mpu_tpu_buffer(ctx, encode_state, encoder_context);

	if (!vp8_context->mfx_encoder_config_command_initialized) {
		memset(&config_params, 0, sizeof(config_params));
		config_params.is_first_pass = !vp8_context->curr_pass;
		config_params.command_offset = VP8_HEADER_METADATA_OFFSET;
		config_params.buffer_size = VP8_PICTURE_STATE_SIZE;
		config_params.config_buffer = &vp8_context->pak_mpu_tpu_picture_state_buffer;
		i965_encoder_vp8_vme_init_mfx_config_command(ctx, encode_state, encoder_context, &config_params);
	}

	if (!vp8_context->mpu_curbe_updated_in_brc_update)
		i965_encoder_vp8_vme_mpu_set_curbe(ctx, encode_state, encoder_context, gpe_context);

	i965_encoder_vp8_vme_mpu_add_surfaces(ctx, encode_state, encoder_context, gpe_context);
	gpe->setup_interface_data(ctx, gpe_context);

	memset(&media_object_param, 0, sizeof(media_object_param));
	i965_run_kernel_media_object(ctx, encoder_context, gpe_context, media_function, &media_object_param);

	return VA_STATUS_SUCCESS;
}

static VAStatus
i965_encoder_vp8_vme_gpe_kernel_function(VADriverContextP ctx,
										 struct encode_state *encode_state,
										 struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	int is_intra = (vp8_context->frame_type == MPEG_I_PICTURE);
	unsigned char brc_enabled = (vp8_context->internal_rate_mode == I965_BRC_CBR ||
								 vp8_context->internal_rate_mode == I965_BRC_VBR);
	unsigned char scaling_enabled = vp8_context->hme_supported;
	unsigned char scaling_16x_enabled = vp8_context->hme_16x_supported;
	unsigned char hme_enabled = vp8_context->hme_enabled;
	unsigned char hme_16x_enabled = vp8_context->hme_16x_enabled;

	if (brc_enabled) {
		if (!vp8_context->brc_initted || vp8_context->brc_need_reset) {
			i965_encoder_vp8_vme_brc_init_reset(ctx, encode_state, encoder_context);
		}
	}

	if (scaling_enabled) {
		i965_encoder_vp8_vme_scaling(ctx, encode_state, encoder_context, 0);

		if (scaling_16x_enabled)
			i965_encoder_vp8_vme_scaling(ctx, encode_state, encoder_context, 1);
	}

	if (hme_enabled) {
		if (hme_16x_enabled)
			i965_encoder_vp8_vme_me(ctx, encode_state, encoder_context, 1);

		i965_encoder_vp8_vme_me(ctx, encode_state, encoder_context, 0);
	}

	if (brc_enabled) {
		if (is_intra) {
			i965_encoder_vp8_vme_mbenc(ctx, encode_state, encoder_context, 0, 1);
		}

		i965_encoder_vp8_vme_brc_update(ctx, encode_state, encoder_context);
	}

	vp8_context->brc_initted = 1;
	vp8_context->brc_mbenc_phase1_ignored = 0;

	if (is_intra && encoder_context->quality_level == ENCODER_LOW_QUALITY) {
		vp8_context->brc_mbenc_phase1_ignored = 1;
	} else {
		i965_encoder_vp8_vme_mbenc(ctx, encode_state, encoder_context, 0, 0);
	}

	if (is_intra) {
		i965_encoder_vp8_vme_mbenc(ctx, encode_state, encoder_context, 1, 0);
	}

	i965_encoder_vp8_vme_mpu(ctx, encode_state, encoder_context);

	return VA_STATUS_SUCCESS;
}

static VAStatus
i965_encoder_vp8_vme_gpe_kernel_final(VADriverContextP ctx,
									  struct encode_state *encode_state,
									  struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_mbenc_context *mbenc_context = &vp8_context->mbenc_context;
	struct i965_encoder_vp8_mpu_context *mpu_context = &vp8_context->mpu_context;

	dri_bo_unreference(mbenc_context->luma_chroma_dynamic_buffer);
	mbenc_context->luma_chroma_dynamic_buffer = NULL;

	dri_bo_unreference(mpu_context->dynamic_buffer);
	mpu_context->dynamic_buffer = NULL;

	return VA_STATUS_SUCCESS;
}

static void
i965_encoder_vp8_vme_set_status_buffer(VADriverContextP ctx,
									   struct encode_state *encode_state,
									   struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;
	struct i965_encoder_vp8_encode_status_buffer *encode_status_buffer = &vp8_context->encode_status_buffer;
	struct vp8_encode_status *encode_status;
	char *pbuffer;

	dri_bo_unreference(encode_status_buffer->bo);
	encode_status_buffer->bo = encode_state->coded_buf_object->buffer_store->bo;
	dri_bo_reference(encode_status_buffer->bo);

	encode_status_buffer->base_offset = offsetof(struct i965_coded_buffer_segment, codec_private_data);
	encode_status_buffer->size = ALIGN(sizeof(struct vp8_encode_status), sizeof(unsigned int) * 2);

	encode_status_buffer->bitstream_byte_count_offset = offsetof(struct vp8_encode_status, bitstream_byte_count_per_frame);
	encode_status_buffer->image_status_mask_offset = offsetof(struct vp8_encode_status, image_status_mask);
	encode_status_buffer->image_status_ctrl_offset = offsetof(struct vp8_encode_status, image_status_ctrl);

	dri_bo_map(encode_status_buffer->bo, 1);

	if (!encode_status_buffer->bo->virtual)
		return;

	pbuffer = encode_status_buffer->bo->virtual;
	pbuffer += encode_status_buffer->base_offset;
	encode_status = (struct vp8_encode_status *)pbuffer;
	memset(encode_status, 0, sizeof(*encode_status));

	dri_bo_unmap(encode_status_buffer->bo);
}

static VAStatus
i965_encoder_vp8_vme_pipeline(VADriverContextP ctx,
							  VAProfile profile,
							  struct encode_state *encode_state,
							  struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;

	vp8_context->is_render_context = 1;

	i965_encoder_vp8_vme_set_status_buffer(ctx, encode_state, encoder_context);

	i965_encoder_vp8_get_paramters(ctx, encode_state, encoder_context);

	i965_encoder_vp8_vme_gpe_kernel_init(ctx, encode_state, encoder_context);
	i965_encoder_vp8_vme_gpe_kernel_function(ctx, encode_state, encoder_context);
	i965_encoder_vp8_vme_gpe_kernel_final(ctx, encode_state, encoder_context);

	vp8_context->frame_num++;
	vp8_context->brc_need_reset = 0;

	vp8_context->mbenc_curbe_updated_in_brc_update = 0;
	vp8_context->mpu_curbe_updated_in_brc_update = 0;
	vp8_context->mfx_encoder_config_command_initialized = 0;

	return VA_STATUS_SUCCESS;
}

static void
i965_encoder_vp8_vme_kernel_context_destroy(struct i965_encoder_vp8_context *vp8_context)
{
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	int i;

	for (i = 0; i < NUM_VP8_BRC_RESET; i++)
		gpe->context_destroy(&vp8_context->brc_init_reset_context.gpe_contexts[i]);

	for (i = 0; i < NUM_VP8_SCALING; i++)
		gpe->context_destroy(&vp8_context->scaling_context.gpe_contexts[i]);

	for (i = 0; i < NUM_VP8_ME; i++)
		gpe->context_destroy(&vp8_context->me_context.gpe_contexts[i]);

	for (i = 0; i < NUM_VP8_MBENC; i++)
		gpe->context_destroy(&vp8_context->mbenc_context.gpe_contexts[i]);

	for (i = 0; i < NUM_VP8_BRC_UPDATE; i++)
		gpe->context_destroy(&vp8_context->brc_update_context.gpe_contexts[i]);

	for (i = 0; i < NUM_VP8_MPU; i++)
		gpe->context_destroy(&vp8_context->mpu_context.gpe_contexts[i]);

	i965_encoder_vp8_vme_free_resources(vp8_context);
}

static void
i965_encoder_vp8_vme_context_destroy(void *context)
{
	struct i965_encoder_vp8_context *vp8_context = context;
	struct i965_encoder_vp8_encode_status_buffer *encode_status_buffer = &vp8_context->encode_status_buffer;

	i965_encoder_vp8_vme_kernel_context_destroy(vp8_context);

	dri_bo_unreference(encode_status_buffer->bo);
	encode_status_buffer->bo = NULL;

	free(vp8_context);
}

static void
i965_encoder_vp8_vme_brc_init_reset_context_init(VADriverContextP ctx,
												 struct i965_encoder_vp8_context *vp8_context,
												 struct i965_encoder_vp8_brc_init_reset_context *brc_init_reset_context)
{
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *gpe_context = NULL;
	struct vp8_encoder_kernel_parameters kernel_params;
	struct vp8_encoder_scoreboard_parameters scoreboard_params;
	int i;

	kernel_params.curbe_size = sizeof(struct vp8_brc_init_reset_curbe_data);
	kernel_params.inline_data_size = 0;
	kernel_params.external_data_size = 0;

	memset(&scoreboard_params, 0, sizeof(scoreboard_params));
	scoreboard_params.mask = 0xFF;
	scoreboard_params.enable = vp8_context->use_hw_scoreboard;
	scoreboard_params.type = vp8_context->use_hw_non_stalling_scoreborad;

	for (i = 0; i < NUM_VP8_BRC_RESET; i++) {
		gpe_context = &brc_init_reset_context->gpe_contexts[i];
		i965_encoder_vp8_gpe_context_init_once(ctx, gpe_context, &kernel_params, vp8_context->idrt_entry_size);
		i965_encoder_vp8_gpe_context_vfe_scoreboard_init(gpe_context, &scoreboard_params);
		gpe->load_kernels(ctx,
						  gpe_context,
						  &vp8_kernels_brc_init_reset[i],
						  1);
	}
}

static void
i965_encoder_vp8_vme_scaling_context_init(VADriverContextP ctx,
										  struct i965_encoder_vp8_context *vp8_context,
										  struct i965_encoder_vp8_scaling_context *scaling_context)
{
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *gpe_context = NULL;
	struct vp8_encoder_kernel_parameters kernel_params;
	struct vp8_encoder_scoreboard_parameters scoreboard_params;
	int i;

	kernel_params.curbe_size = sizeof(struct vp8_scaling_curbe_data);
	kernel_params.inline_data_size = 0;
	kernel_params.external_data_size = 0;

	memset(&scoreboard_params, 0, sizeof(scoreboard_params));
	scoreboard_params.mask = 0xFF;
	scoreboard_params.enable = vp8_context->use_hw_scoreboard;
	scoreboard_params.type = vp8_context->use_hw_non_stalling_scoreborad;

	for (i = 0; i < NUM_VP8_SCALING; i++) {
		gpe_context = &scaling_context->gpe_contexts[i];
		i965_encoder_vp8_gpe_context_init_once(ctx, gpe_context, &kernel_params, vp8_context->idrt_entry_size);
		i965_encoder_vp8_gpe_context_vfe_scoreboard_init(gpe_context, &scoreboard_params);
		gpe->load_kernels(ctx,
						  gpe_context,
						  &vp8_kernels_scaling[i],
						  1);
	}
}

static void
i965_encoder_vp8_vme_me_context_init(VADriverContextP ctx,
									 struct i965_encoder_vp8_context *vp8_context,
									 struct i965_encoder_vp8_me_context *me_context)
{
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *gpe_context = NULL;
	struct vp8_encoder_kernel_parameters kernel_params;
	struct vp8_encoder_scoreboard_parameters scoreboard_params;
	int i;

	kernel_params.curbe_size = sizeof(struct vp8_me_curbe_data);
	kernel_params.inline_data_size = 0;
	kernel_params.external_data_size = 0;

	memset(&scoreboard_params, 0, sizeof(scoreboard_params));
	scoreboard_params.mask = 0xFF;
	scoreboard_params.enable = vp8_context->use_hw_scoreboard;
	scoreboard_params.type = vp8_context->use_hw_non_stalling_scoreborad;

	for (i = 0; i < NUM_VP8_ME; i++) {
		gpe_context = &me_context->gpe_contexts[i];
		i965_encoder_vp8_gpe_context_init_once(ctx, gpe_context, &kernel_params, vp8_context->idrt_entry_size);
		i965_encoder_vp8_gpe_context_vfe_scoreboard_init(gpe_context, &scoreboard_params);
		gpe->load_kernels(ctx,
						  gpe_context,
						  &vp8_kernels_me[i],
						  1);
	}
}

static void
i965_encoder_vp8_vme_mbenc_context_init(VADriverContextP ctx,
										struct i965_encoder_vp8_context *vp8_context,
										struct i965_encoder_vp8_mbenc_context *mbenc_context)
{
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *gpe_context = NULL;
	struct vp8_encoder_kernel_parameters kernel_params;
	struct vp8_encoder_scoreboard_parameters scoreboard_params;
	int i;

	kernel_params.curbe_size = MAX(sizeof(struct vp8_mbenc_i_frame_curbe_data), sizeof(struct vp8_mbenc_p_frame_curbe_data));
	kernel_params.inline_data_size = 0;
	kernel_params.external_data_size = 0;

	memset(&scoreboard_params, 0, sizeof(scoreboard_params));
	scoreboard_params.mask = 0xFF;
	scoreboard_params.enable = vp8_context->use_hw_scoreboard;
	scoreboard_params.type = vp8_context->use_hw_non_stalling_scoreborad;

	for (i = 0; i < NUM_VP8_MBENC; i++) {
		gpe_context = &mbenc_context->gpe_contexts[i];
		i965_encoder_vp8_gpe_context_init_once(ctx, gpe_context, &kernel_params, vp8_context->idrt_entry_size);
		i965_encoder_vp8_gpe_context_vfe_scoreboard_init(gpe_context, &scoreboard_params);
		gpe->load_kernels(ctx,
						  gpe_context,
						  &vp8_kernels_mbenc[i],
						  1);
	}
}

static void
i965_encoder_vp8_vme_brc_update_context_init(VADriverContextP ctx,
											 struct i965_encoder_vp8_context *vp8_context,
											 struct i965_encoder_vp8_brc_update_context *brc_update_context)
{
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *gpe_context = NULL;
	struct vp8_encoder_kernel_parameters kernel_params;
	struct vp8_encoder_scoreboard_parameters scoreboard_params;
	int i;

	kernel_params.curbe_size = sizeof(struct vp8_brc_update_curbe_data);
	kernel_params.inline_data_size = 0;
	kernel_params.external_data_size = 0;

	memset(&scoreboard_params, 0, sizeof(scoreboard_params));
	scoreboard_params.mask = 0xFF;
	scoreboard_params.enable = vp8_context->use_hw_scoreboard;
	scoreboard_params.type = vp8_context->use_hw_non_stalling_scoreborad;

	for (i = 0; i < NUM_VP8_BRC_UPDATE; i++) {
		gpe_context = &brc_update_context->gpe_contexts[i];
		i965_encoder_vp8_gpe_context_init_once(ctx, gpe_context, &kernel_params, vp8_context->idrt_entry_size);
		i965_encoder_vp8_gpe_context_vfe_scoreboard_init(gpe_context, &scoreboard_params);
		gpe->load_kernels(ctx,
						  gpe_context,
						  &vp8_kernels_brc_update[i],
						  1);
	}
}

static void
i965_encoder_vp8_vme_mpu_context_init(VADriverContextP ctx,
									  struct i965_encoder_vp8_context *vp8_context,
									  struct i965_encoder_vp8_mpu_context *mpu_context)
{
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *gpe_context = NULL;
	struct vp8_encoder_kernel_parameters kernel_params;
	struct vp8_encoder_scoreboard_parameters scoreboard_params;
	int i;

	kernel_params.curbe_size = sizeof(struct vp8_mpu_curbe_data);
	kernel_params.inline_data_size = 0;
	kernel_params.external_data_size = 0;

	memset(&scoreboard_params, 0, sizeof(scoreboard_params));
	scoreboard_params.mask = 0xFF;
	scoreboard_params.enable = vp8_context->use_hw_scoreboard;
	scoreboard_params.type = vp8_context->use_hw_non_stalling_scoreborad;

	for (i = 0; i < NUM_VP8_MPU; i++) {
		gpe_context = &mpu_context->gpe_contexts[i];
		i965_encoder_vp8_gpe_context_init_once(ctx, gpe_context, &kernel_params, vp8_context->idrt_entry_size);
		i965_encoder_vp8_gpe_context_vfe_scoreboard_init(gpe_context, &scoreboard_params);
		gpe->load_kernels(ctx,
						  gpe_context,
						  &vp8_kernels_mpu[i],
						  1);
	}
}

static Bool
i965_encoder_vp8_vme_var_init(VADriverContextP ctx,
							  struct intel_encoder_context *encoder_context,
							  struct i965_encoder_vp8_context *vp8_context)
{
	struct i965_driver_data *i965 = i965_driver_data(ctx);

	vp8_context->mocs = i965->intel.mocs_state;

	vp8_context->gpe_table = &i965->gpe_table;

	vp8_context->min_scaled_dimension = 48;
	vp8_context->min_scaled_dimension_in_mbs = WIDTH_IN_MACROBLOCKS(vp8_context->min_scaled_dimension);

	vp8_context->vdbox_idc = BSD_RING0;
	vp8_context->vdbox_mmio_base = VDBOX0_MMIO_BASE;

	/* TODO: This is a WA for VDBOX loading balance only, */
	if (i965->intel.has_bsd2) {
		srandom(time(NULL));
		vp8_context->vdbox_idc = (random() % 2 ? BSD_RING1 : BSD_RING0);
	}

	if (vp8_context->vdbox_idc == BSD_RING1)
		vp8_context->vdbox_mmio_base = VDBOX1_MMIO_BASE;

	vp8_context->frame_type = MPEG_I_PICTURE;

	vp8_context->use_hw_scoreboard = 1;
	vp8_context->use_hw_non_stalling_scoreborad = 1; /* default: non-stalling */
	vp8_context->brc_distortion_buffer_supported = 1;
	vp8_context->brc_constant_buffer_supported = 1;
	vp8_context->repak_supported = 1;
	vp8_context->multiple_pass_brc_supported = 1;
	vp8_context->is_first_frame = 1;
	vp8_context->is_first_two_frame = 1;
	vp8_context->gop_size = 30;
	vp8_context->hme_supported = 1;
	vp8_context->hme_16x_supported = 1;
	vp8_context->hme_enabled = 0;
	vp8_context->hme_16x_enabled = 0;
	vp8_context->brc_initted = 0;
	vp8_context->frame_num = 0;
	vp8_context->framerate = (struct intel_fraction) {
		30, 1
	};

	return True;
}

static Bool
i965_encoder_vp8_vme_kernels_context_init(VADriverContextP ctx,
										  struct intel_encoder_context *encoder_context,
										  struct i965_encoder_vp8_context *vp8_context)
{
	i965_encoder_vp8_vme_brc_init_reset_context_init(ctx, vp8_context, &vp8_context->brc_init_reset_context);
	i965_encoder_vp8_vme_scaling_context_init(ctx, vp8_context, &vp8_context->scaling_context);
	i965_encoder_vp8_vme_me_context_init(ctx, vp8_context, &vp8_context->me_context);
	i965_encoder_vp8_vme_mbenc_context_init(ctx, vp8_context, &vp8_context->mbenc_context);
	i965_encoder_vp8_vme_brc_update_context_init(ctx, vp8_context, &vp8_context->brc_update_context);
	i965_encoder_vp8_vme_mpu_context_init(ctx, vp8_context, &vp8_context->mpu_context);

	return True;
}

extern Bool
gen8_encoder_vp8_context_init(VADriverContextP, struct intel_encoder_context *, struct i965_encoder_vp8_context *);

extern Bool
gen9_encoder_vp8_context_init(VADriverContextP, struct intel_encoder_context *, struct i965_encoder_vp8_context *);

extern Bool
gen10_encoder_vp8_context_init(VADriverContextP, struct intel_encoder_context *, struct i965_encoder_vp8_context *);

Bool
i965_encoder_vp8_vme_context_init(VADriverContextP ctx, struct intel_encoder_context *encoder_context)
{
	struct i965_driver_data *i965 = i965_driver_data(ctx);
	struct i965_encoder_vp8_context *vp8_context = NULL;

	vp8_context = calloc(1, sizeof(struct i965_encoder_vp8_context));

	if (!vp8_context)
		return False;

	i965_encoder_vp8_vme_var_init(ctx, encoder_context, vp8_context);

	if (IS_CHERRYVIEW(i965->intel.device_info))
		gen8_encoder_vp8_context_init(ctx, encoder_context, vp8_context);
	else if (IS_GEN9(i965->intel.device_info)) {
		gen9_encoder_vp8_context_init(ctx, encoder_context, vp8_context);
	} else if (IS_GEN10(i965->intel.device_info)) {
		gen10_encoder_vp8_context_init(ctx, encoder_context, vp8_context);
	} else {
		free(vp8_context);

		return False;
	}

	i965_encoder_vp8_vme_kernels_context_init(ctx, encoder_context, vp8_context);

	encoder_context->vme_context = vp8_context;
	encoder_context->vme_pipeline = i965_encoder_vp8_vme_pipeline;
	encoder_context->vme_context_destroy = i965_encoder_vp8_vme_context_destroy;

	return True;
}

/*
 * PAK part
 */
static void
i965_encoder_vp8_pak_pre_pipeline(struct encode_state *encode_state,
								  struct intel_encoder_context *encoder_context)
{
	/* No thing to do */
}

static void
i965_encoder_vp8_pak_kernels_context_destroy(struct i965_encoder_vp8_context *vp8_context)
{
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	int i;

	for (i = 0; i < NUM_VP8_TPU; i++)
		gpe->context_destroy(&vp8_context->tpu_context.gpe_contexts[i]);
}


static void
i965_encoder_vp8_pak_context_destroy(void *context)
{
	struct i965_encoder_vp8_context *vp8_context = context;
	int i;

	dri_bo_unreference(vp8_context->post_deblocking_output.bo);
	vp8_context->post_deblocking_output.bo = NULL;

	dri_bo_unreference(vp8_context->pre_deblocking_output.bo);
	vp8_context->pre_deblocking_output.bo = NULL;

	dri_bo_unreference(vp8_context->uncompressed_picture_source.bo);
	vp8_context->uncompressed_picture_source.bo = NULL;

	dri_bo_unreference(vp8_context->indirect_pak_bse_object.bo);
	vp8_context->indirect_pak_bse_object.bo = NULL;

	for (i = 0; i < MAX_MFX_REFERENCE_SURFACES; i++) {
		dri_bo_unreference(vp8_context->reference_surfaces[i].bo);
		vp8_context->reference_surfaces[i].bo = NULL;
	}

	i965_encoder_vp8_pak_kernels_context_destroy(vp8_context);

	/* vme & pak same the same structure, so don't free the context here */
}

static void
i965_encoder_vp8_pak_pipe_mode_select(VADriverContextP ctx, struct intel_encoder_context *encoder_context)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;

	BEGIN_BCS_BATCH(batch, 5);

	OUT_BCS_BATCH(batch, MFX_PIPE_MODE_SELECT | (5 - 2));
	OUT_BCS_BATCH(batch,
				  (MFX_LONG_MODE << 17) | /* Must be long format for encoder */
				  (MFD_MODE_VLD << 15) |  /* VLD mode */
				  ((!!vp8_context->post_deblocking_output.bo) << 9)  | /* Post Deblocking Output */
				  ((!!vp8_context->pre_deblocking_output.bo) << 8)  |  /* Pre Deblocking Output */
				  (1 << 4)  | /* encoding mode */
				  (MFX_FORMAT_VP8 << 0));
	OUT_BCS_BATCH(batch, 0);
	OUT_BCS_BATCH(batch, 0);
	OUT_BCS_BATCH(batch, 0);

	ADVANCE_BCS_BATCH(batch);
}

static void
i965_encoder_vp8_pak_surface_state(VADriverContextP ctx,
								   struct object_surface *obj_surface,
								   int id,
								   struct intel_encoder_context *encoder_context)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;

	BEGIN_BCS_BATCH(batch, 6);

	OUT_BCS_BATCH(batch, MFX_SURFACE_STATE | (6 - 2));
	OUT_BCS_BATCH(batch, id);
	OUT_BCS_BATCH(batch,
				  ((obj_surface->orig_height - 1) << 18) |
				  ((obj_surface->orig_width - 1) << 4));
	OUT_BCS_BATCH(batch,
				  (MFX_SURFACE_PLANAR_420_8 << 28) | /* 420 planar YUV surface */
				  (1 << 27) | /* must be 1 for interleave U/V, hardware requirement */
				  ((obj_surface->width - 1) << 3) |  /* pitch */
				  (0 << 2)  | /* must be 0 for interleave U/V */
				  (1 << 1)  | /* must be tiled */
				  (I965_TILEWALK_YMAJOR << 0));  /* tile walk, TILEWALK_YMAJOR */
	OUT_BCS_BATCH(batch,
				  (0 << 16) |            /* must be 0 for interleave U/V */
				  (obj_surface->height));        /* y offset for U(cb) */
	OUT_BCS_BATCH(batch, 0);

	ADVANCE_BCS_BATCH(batch);
}

#define PAK_OUT_BUFFER_2DW(buf_bo, is_target, delta)  do {              \
		if (buf_bo) {                                                   \
			OUT_BCS_RELOC64(batch,                                      \
							buf_bo,                                     \
							I915_GEM_DOMAIN_RENDER,                     \
							is_target ? I915_GEM_DOMAIN_RENDER : 0,     \
							delta);                                     \
		} else {                                                        \
			OUT_BCS_BATCH(batch, 0);                                    \
			OUT_BCS_BATCH(batch, 0);                                    \
		}                                                               \
	} while (0)

#define PAK_OUT_BUFFER_3DW(buf_bo, is_target, delta, attr)  do {        \
		PAK_OUT_BUFFER_2DW(buf_bo, is_target, delta);                   \
		OUT_BCS_BATCH(batch, attr);                                     \
	} while (0)



static void
i965_encoder_vp8_pak_pipe_buf_addr_state(VADriverContextP ctx,
										 struct intel_encoder_context *encoder_context)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	int i;

	BEGIN_BCS_BATCH(batch, 61);

	OUT_BCS_BATCH(batch, MFX_PIPE_BUF_ADDR_STATE | (61 - 2));

	/* the DW1-3 is for pre_deblocking */
	PAK_OUT_BUFFER_3DW(vp8_context->pre_deblocking_output.bo, 1, 0, vp8_context->mocs);

	/* the DW4-6 is for the post_deblocking */
	PAK_OUT_BUFFER_3DW(vp8_context->post_deblocking_output.bo, 1, 0, vp8_context->mocs);

	/* the DW7-9 is for the uncompressed_picture */
	PAK_OUT_BUFFER_3DW(vp8_context->uncompressed_picture_source.bo, 0, 0, vp8_context->mocs);

	/* the DW10-12 is for the mb status */
	PAK_OUT_BUFFER_3DW(vp8_context->pak_stream_out_buffer.bo, 1, 0, vp8_context->mocs);

	/* the DW13-15 is for the intra_row_store_scratch */
	PAK_OUT_BUFFER_3DW(vp8_context->pak_intra_row_store_scratch_buffer.bo, 1, 0, vp8_context->mocs);

	/* the DW16-18 is for the deblocking filter */
	PAK_OUT_BUFFER_3DW(vp8_context->pak_deblocking_filter_row_store_scratch_buffer.bo, 1, 0, vp8_context->mocs);

	/* the DW 19-50 is for Reference pictures*/
	for (i = 0; i < ARRAY_ELEMS(vp8_context->reference_surfaces); i++) {
		PAK_OUT_BUFFER_2DW(vp8_context->reference_surfaces[i].bo, 0, 0);
	}

	/* DW 51 */
	OUT_BCS_BATCH(batch, vp8_context->mocs);

	/* The DW 52-54 is for the MB status buffer */
	PAK_OUT_BUFFER_3DW(NULL, 0, 0, 0);

	/* the DW 55-57 is the ILDB buffer */
	PAK_OUT_BUFFER_3DW(NULL, 0, 0, 0);

	/* the DW 58-60 is the second ILDB buffer */
	PAK_OUT_BUFFER_3DW(NULL, 0, 0, 0);

	ADVANCE_BCS_BATCH(batch);
}

static void
i965_encoder_vp8_pak_ind_obj_base_addr_state(VADriverContextP ctx, struct intel_encoder_context *encoder_context)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	int vme_size = ALIGN((vp8_context->mb_coded_buffer_size - vp8_context->mv_offset), 0x1000);

	BEGIN_BCS_BATCH(batch, 26);

	OUT_BCS_BATCH(batch, MFX_IND_OBJ_BASE_ADDR_STATE | (26 - 2));

	/* the DW1-5 is for the MFX indirect bistream */
	PAK_OUT_BUFFER_3DW(vp8_context->indirect_pak_bse_object.bo, 1, vp8_context->indirect_pak_bse_object.offset, vp8_context->mocs);
	PAK_OUT_BUFFER_2DW(vp8_context->indirect_pak_bse_object.bo, 1, vp8_context->indirect_pak_bse_object.end_offset);

	/* the DW6-10 is for MFX Indirect MV Object Base Address */
	PAK_OUT_BUFFER_3DW(vp8_context->mb_coded_buffer.bo, 0, vp8_context->mv_offset, vp8_context->mocs);
	PAK_OUT_BUFFER_2DW(vp8_context->mb_coded_buffer.bo, 0, (vp8_context->mv_offset + vme_size));

	/* the DW11-15 is for MFX IT-COFF. Not used on encoder */
	PAK_OUT_BUFFER_3DW(NULL, 0, 0, 0);
	PAK_OUT_BUFFER_2DW(NULL, 0, 0);

	/* the DW16-20 is for MFX indirect DBLK. Not used on encoder */
	PAK_OUT_BUFFER_3DW(NULL, 0, 0, 0);
	PAK_OUT_BUFFER_2DW(NULL, 0, 0);

	/* the DW21-25 is for MFC Indirect PAK-BSE Object Base Address for Encoder*/
	PAK_OUT_BUFFER_3DW(vp8_context->indirect_pak_bse_object.bo, 1, vp8_context->indirect_pak_bse_object.offset, vp8_context->mocs);
	PAK_OUT_BUFFER_2DW(vp8_context->indirect_pak_bse_object.bo, 1, vp8_context->indirect_pak_bse_object.end_offset);

	ADVANCE_BCS_BATCH(batch);
}

static void
i965_encoder_vp8_pak_bsp_buf_base_addr_state(VADriverContextP ctx,
											 struct encode_state *encode_state,
											 struct intel_encoder_context *encoder_context)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	int num_partitions = (1 << pic_param->pic_flags.bits.num_token_partitions);
	int offset;
	unsigned int token_size = vp8_context->frame_width * vp8_context->frame_height * 2;
	unsigned int part_size = token_size / num_partitions;
	unsigned int part0_size = (vp8_context->frame_width * vp8_context->frame_height) / 4 + VP8_INTERMEDIATE_PARTITION0_SIZE;

	BEGIN_BCS_BATCH(batch, 32);
	OUT_BCS_BATCH(batch, MFX_VP8_BSP_BUF_BASE_ADDR_STATE | (32 - 2));

	/* The 4th parameter in PAK_OUT_BUFFER_3DW() is not a MOCS index for this command per doc */
	/* DW1-3 */
	PAK_OUT_BUFFER_3DW(vp8_context->pak_frame_header_buffer.bo, 1, 0, 0);
	/* DW4-6 */
	PAK_OUT_BUFFER_3DW(vp8_context->pak_intermediate_buffer.bo, 1, 0, 0);

	/* DW7-DW14 */
	offset = ALIGN(part0_size, 64);
	OUT_BCS_BATCH(batch, offset);
	offset = ALIGN(offset + part_size, 64);
	OUT_BCS_BATCH(batch, offset);
	offset = ALIGN(offset + part_size, 64);
	OUT_BCS_BATCH(batch, offset);
	offset = ALIGN(offset + part_size, 64);
	OUT_BCS_BATCH(batch, offset);
	offset = ALIGN(offset + part_size, 64);
	OUT_BCS_BATCH(batch, offset);
	offset = ALIGN(offset + part_size, 64);
	OUT_BCS_BATCH(batch, offset);
	offset = ALIGN(offset + part_size, 64);
	OUT_BCS_BATCH(batch, offset);
	offset = ALIGN(offset + part_size, 64);
	OUT_BCS_BATCH(batch, offset);

	/* DW15 */
	OUT_BCS_BATCH(batch, token_size + part0_size);

	/* DW16-18 */
	PAK_OUT_BUFFER_3DW(vp8_context->indirect_pak_bse_object.bo, 1, vp8_context->indirect_pak_bse_object.offset, 0);

	/* DW19 */
	OUT_BCS_BATCH(batch, 0);

	/* DW20-22 */
	PAK_OUT_BUFFER_3DW(NULL, 0, 0, 0);

	/* DW23-25 */
	if (vp8_context->repak_pass_iter_val > 0 &&
		vp8_context->frame_type == MPEG_I_PICTURE &&
		vp8_context->repak_pass_iter_val == vp8_context->curr_pass)
		PAK_OUT_BUFFER_3DW(vp8_context->pak_mpu_tpu_key_frame_token_probability_buffer.bo, 1, 0, 0);
	else
		PAK_OUT_BUFFER_3DW(vp8_context->pak_mpu_tpu_coeff_probs_buffer.bo, 1, 0, 0);

	/* DW26-28 */
	PAK_OUT_BUFFER_3DW(vp8_context->pak_mpu_tpu_pak_token_statistics_buffer.bo, 1, 0, 0);

	/* DW29-31 */
	PAK_OUT_BUFFER_3DW(vp8_context->pak_mpc_row_store_scratch_buffer.bo, 1, 0, 0);

	ADVANCE_BCS_BATCH(batch);
}

static void
i965_encoder_vp8_pak_insert_batch_buffers(VADriverContextP ctx, struct intel_encoder_context *encoder_context)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct gpe_mi_batch_buffer_start_parameter batch_param;
	unsigned char brc_enabled = (vp8_context->internal_rate_mode == I965_BRC_CBR ||
								 vp8_context->internal_rate_mode == I965_BRC_VBR);

	memset(&batch_param, 0, sizeof(batch_param));
	batch_param.bo = vp8_context->pak_mpu_tpu_picture_state_buffer.bo;
	batch_param.is_second_level = 1; /* Must be the second batch buffer */
	gpe->mi_batch_buffer_start(ctx, batch, &batch_param);

	if (brc_enabled) {
		batch_param.bo = vp8_context->brc_vp8_cfg_command_write_buffer.bo;

		if (vp8_context->repak_pass_iter_val == 0) {
			batch_param.offset = vp8_context->curr_pass * VP8_BRC_IMG_STATE_SIZE_PER_PASS;
		} else {

			if (vp8_context->repak_pass_iter_val == vp8_context->curr_pass)
				batch_param.offset = 0;
			else
				batch_param.offset = vp8_context->curr_pass * VP8_BRC_IMG_STATE_SIZE_PER_PASS;
		}

		gpe->mi_batch_buffer_start(ctx, batch, &batch_param);
	}

	batch_param.bo = vp8_context->mb_coded_buffer.bo;
	batch_param.offset = 0;
	gpe->mi_batch_buffer_start(ctx, batch, &batch_param);
}

static void
i965_encoder_vp8_pak_picture_level(VADriverContextP ctx,
								   struct encode_state *encode_state,
								   struct intel_encoder_context *encoder_context)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct i965_encoder_vp8_encode_status_buffer *encode_status_buffer = &vp8_context->encode_status_buffer;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct gpe_mi_conditional_batch_buffer_end_parameter mi_param;
	unsigned char brc_enabled = (vp8_context->internal_rate_mode == I965_BRC_CBR ||
								 vp8_context->internal_rate_mode == I965_BRC_VBR);

	if (brc_enabled &&
		vp8_context->curr_pass > 0 &&
		(vp8_context->curr_pass < vp8_context->repak_pass_iter_val ||
		 vp8_context->repak_pass_iter_val == 0)) {
		memset(&mi_param, 0, sizeof(mi_param));
		mi_param.bo = encode_status_buffer->bo;
		mi_param.offset = (encode_status_buffer->base_offset +
						   encode_status_buffer->image_status_mask_offset);
		gpe->mi_conditional_batch_buffer_end(ctx, batch, &mi_param);
	}

	if ((vp8_context->repak_pass_iter_val > 0) && (vp8_context->curr_pass == vp8_context->repak_pass_iter_val)) {
		memset(&mi_param, 0, sizeof(mi_param));
		mi_param.bo = vp8_context->pak_mpu_tpu_repak_decision_buffer.bo;
		mi_param.offset = 0;
		gpe->mi_conditional_batch_buffer_end(ctx, batch, &mi_param);
	}

	i965_encoder_vp8_pak_pipe_mode_select(ctx, encoder_context);
	i965_encoder_vp8_pak_surface_state(ctx, encode_state->reconstructed_object, 0, encoder_context);
	i965_encoder_vp8_pak_surface_state(ctx, encode_state->input_yuv_object, 4, encoder_context);
	i965_encoder_vp8_pak_pipe_buf_addr_state(ctx, encoder_context);
	i965_encoder_vp8_pak_ind_obj_base_addr_state(ctx, encoder_context);
	i965_encoder_vp8_pak_bsp_buf_base_addr_state(ctx, encode_state, encoder_context);
	i965_encoder_vp8_pak_insert_batch_buffers(ctx, encoder_context);
}

static void
i965_encoder_vp8_pak_set_pak_status_in_tpu_curbe(VADriverContextP ctx,
												 struct intel_encoder_context *encoder_context,
												 int ipass)
{
	struct intel_batchbuffer *batch = encoder_context->base.batch;
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct i965_encoder_vp8_tpu_context *tpu_context = &vp8_context->tpu_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *tpu_gpe_context;
	struct gpe_mi_store_data_imm_parameter mi_store_data_imm_param;
	struct gpe_mi_store_register_mem_parameter mi_store_register_mem_param;

	tpu_gpe_context = &tpu_context->gpe_contexts[0];

	memset(&mi_store_data_imm_param, 0, sizeof(mi_store_data_imm_param));
	mi_store_data_imm_param.bo = tpu_gpe_context->curbe.bo;
	mi_store_data_imm_param.offset = tpu_gpe_context->curbe.offset + sizeof(unsigned int) * 6;
	mi_store_data_imm_param.dw0 = (vp8_context->curr_pass + 1) << 8;

	gpe->mi_store_data_imm(ctx, batch, &mi_store_data_imm_param);

	if (ipass == 0) {
		memset(&mi_store_register_mem_param, 0, sizeof(mi_store_register_mem_param));
		mi_store_register_mem_param.bo = tpu_gpe_context->curbe.bo;
		mi_store_register_mem_param.offset = tpu_gpe_context->curbe.offset + sizeof(unsigned int) * 8;
		mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CUMULATIVE_DQ_INDEX01_REG_OFFSET;
		gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

		mi_store_register_mem_param.offset = tpu_gpe_context->curbe.offset + sizeof(unsigned int) * 9;
		mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CUMULATIVE_DQ_INDEX23_REG_OFFSET;
		gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

		mi_store_register_mem_param.offset = tpu_gpe_context->curbe.offset + sizeof(unsigned int) * 10;
		mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CUMULATIVE_D_LOOP_FILTER01_REG_OFFSET;
		gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);

		mi_store_register_mem_param.offset = tpu_gpe_context->curbe.offset + sizeof(unsigned int) * 11;
		mi_store_register_mem_param.mmio_offset = vp8_context->vdbox_mmio_base + VP8_MFX_BRC_CUMULATIVE_D_LOOP_FILTER23_REG_OFFSET;
		gpe->mi_store_register_mem(ctx, batch, &mi_store_register_mem_param);
	}
}

static void
i965_encoder_vp8_pak_slice_level_brc(VADriverContextP ctx,
									 struct intel_encoder_context *encoder_context,
									 int ipass)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	unsigned int *pbuffer;

	i965_encoder_vp8_read_pak_statistics(ctx, encoder_context, ipass);

	pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_picture_state_buffer);

	if (!pbuffer)
		return;

	pbuffer += 38;
	*pbuffer = 0x05000000;
	i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_picture_state_buffer);

	i965_encoder_vp8_pak_set_pak_status_in_tpu_curbe(ctx, encoder_context, ipass);
}

static void
i965_encoder_vp8_pak_slice_level(VADriverContextP ctx,
								 struct encode_state *encode_state,
								 struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	unsigned char brc_enabled = (vp8_context->internal_rate_mode == I965_BRC_CBR ||
								 vp8_context->internal_rate_mode == I965_BRC_VBR);
	unsigned int *pbuffer;

	i965_encoder_vp8_read_encode_status(ctx, encoder_context);

	if (vp8_context->num_brc_pak_passes == VP8_BRC_SINGLE_PASS) {
		if (brc_enabled) {
			i965_encoder_vp8_read_pak_statistics(ctx, encoder_context, vp8_context->curr_pass);

			/* Workaround: */
			pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_picture_state_buffer);

			if (!pbuffer)
				return;

			pbuffer += 38;
			*pbuffer = 0x05000000;
			i965_unmap_gpe_resource(&vp8_context->pak_mpu_tpu_picture_state_buffer);
		}

		vp8_context->submit_batchbuffer = 1;
	} else {
		if ((brc_enabled) &&
			((vp8_context->curr_pass < vp8_context->num_passes && vp8_context->repak_pass_iter_val > 0) ||
			 (vp8_context->curr_pass <= vp8_context->num_passes && vp8_context->repak_pass_iter_val == 0))) {
			i965_encoder_vp8_pak_slice_level_brc(ctx, encoder_context, vp8_context->curr_pass);

			if (vp8_context->tpu_required)
				vp8_context->submit_batchbuffer = 1;
			else
				vp8_context->submit_batchbuffer = 0;
		} else {
			if (brc_enabled) {
				i965_encoder_vp8_read_pak_statistics(ctx, encoder_context, vp8_context->curr_pass);
			}

			pbuffer = i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_picture_state_buffer);

			if (!pbuffer)
				return;

			pbuffer += 38;
			*pbuffer = 0x05000000;
			i965_map_gpe_resource(&vp8_context->pak_mpu_tpu_picture_state_buffer);

			vp8_context->submit_batchbuffer = 1;
		}
	}
}

static void
i965_encoder_vp8_pak_tpu_set_curbe(VADriverContextP ctx,
								   struct encode_state *encode_state,
								   struct intel_encoder_context *encoder_context,
								   struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct vp8_tpu_curbe_data *pcmd = i965_gpe_context_map_curbe(gpe_context);
	VAEncPictureParameterBufferVP8 *pic_param = (VAEncPictureParameterBufferVP8 *)encode_state->pic_param_ext->buffer;
	VAQMatrixBufferVP8 *quant_param = (VAQMatrixBufferVP8 *)encode_state->q_matrix->buffer;

	if (!pcmd)
		return;

	memset(pcmd, 0, sizeof(*pcmd));

	pcmd->dw0.mbs_in_frame = vp8_context->frame_width_in_mbs * vp8_context->frame_height_in_mbs;

	pcmd->dw1.frame_type = pic_param->pic_flags.bits.frame_type;
	pcmd->dw1.enable_segmentation = pic_param->pic_flags.bits.segmentation_enabled;
	pcmd->dw1.rebinarization_frame_hdr = (vp8_context->repak_pass_iter_val ? 1 : 0);

	pcmd->dw1.refresh_entropy_p = pic_param->pic_flags.bits.refresh_entropy_probs;
	pcmd->dw1.mb_no_coeffiscient_skip = pic_param->pic_flags.bits.mb_no_coeff_skip;

	pcmd->dw3.max_qp = pic_param->clamp_qindex_high;
	pcmd->dw3.min_qp = pic_param->clamp_qindex_low;

	pcmd->dw4.loop_filter_level_segment0 = pic_param->loop_filter_level[0];
	pcmd->dw4.loop_filter_level_segment1 = pic_param->loop_filter_level[1];
	pcmd->dw4.loop_filter_level_segment2 = pic_param->loop_filter_level[2];
	pcmd->dw4.loop_filter_level_segment3 = pic_param->loop_filter_level[3];

	pcmd->dw5.quantization_index_segment0 = quant_param->quantization_index[0];
	pcmd->dw5.quantization_index_segment1 = quant_param->quantization_index[1];
	pcmd->dw5.quantization_index_segment2 = quant_param->quantization_index[2];
	pcmd->dw5.quantization_index_segment3 = quant_param->quantization_index[3];

	pcmd->dw6.pak_pass_num = (vp8_context->internal_rate_mode > 0 ? vp8_context->num_brc_pak_passes : 0) << 8;

	if (vp8_context->repak_pass_iter_val > 0) { // TODO: more check
		pcmd->dw7.skip_cost_delta_threshold = 100;
		pcmd->dw7.token_cost_delta_threshold = 50;
	} else {
		pcmd->dw7.skip_cost_delta_threshold = 0;
		pcmd->dw7.token_cost_delta_threshold = 0;
	}

	pcmd->dw12.pak_token_statistics_bti = VP8_BTI_TPU_PAK_TOKEN_STATISTICS;
	pcmd->dw13.token_update_flags_bti = VP8_BTI_TPU_TOKEN_UPDATE_FLAGS;
	pcmd->dw14.entropy_cost_table_bti = VP8_BTI_TPU_ENTROPY_COST_TABLE;
	pcmd->dw15.frame_header_bitstream_bti = VP8_BTI_TPU_HEADER_BITSTREAM;
	pcmd->dw16.default_token_probability_bti = VP8_BTI_TPU_DEFAULT_TOKEN_PROBABILITY;
	pcmd->dw17.picture_state_bti = VP8_BTI_TPU_PICTURE_STATE;
	pcmd->dw18.mpu_curbe_data_bti = VP8_BTI_TPU_MPU_CURBE_DATA;
	pcmd->dw19.header_meta_data_bti = VP8_BTI_TPU_HEADER_METADATA;
	pcmd->dw20.token_probability_bti = VP8_BTI_TPU_TOKEN_PROBABILITY;
	pcmd->dw21.pak_hardware_token_probability_pass1_bti = VP8_BTI_TPU_PAK_HW_PASS1_PROBABILITY;
	pcmd->dw22.key_frame_token_probability_bti = VP8_BTI_TPU_KEY_TOKEN_PROBABILITY;
	pcmd->dw23.updated_token_probability_bti = VP8_BTI_TPU_UPDATED_TOKEN_PROBABILITY;
	pcmd->dw24.pak_hardware_token_probability_pass2_bti = VP8_BTI_TPU_PAK_HW_PASS2_PROBABILITY;
	pcmd->dw25.kernel_debug_dump_bti = VP8_BTI_TPU_VME_DEBUG_STREAMOUT;
	pcmd->dw26.repak_decision_surface_bti = VP8_BTI_TPU_REPAK_DECISION;

	i965_gpe_context_unmap_curbe(gpe_context);
}

static void
i965_encoder_vp8_tpu_add_surfaces(VADriverContextP ctx,
								  struct encode_state *encode_state,
								  struct intel_encoder_context *encoder_context,
								  struct i965_gpe_context *gpe_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	unsigned int size;
	unsigned char brc_enabled = (vp8_context->internal_rate_mode == I965_BRC_CBR ||
								 vp8_context->internal_rate_mode == I965_BRC_VBR);

	// Pak token statistics
	size = VP8_TOKEN_STATISTICS_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_pak_token_statistics_buffer,
								1,
								size,
								0,
								VP8_BTI_TPU_PAK_TOKEN_STATISTICS);

	// Pak token Update flags
	size = VP8_COEFFS_PROPABILITIES_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_pak_token_update_flags_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_TOKEN_UPDATE_FLAGS);

	// Entropy cost
	size = VP8_ENTROPY_COST_TABLE_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_entropy_cost_table_buffer,
								1,
								size,
								0,
								VP8_BTI_TPU_ENTROPY_COST_TABLE);

	// Frame header
	size = VP8_FRAME_HEADER_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_frame_header_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_HEADER_BITSTREAM);

	// Default token token probability
	size = VP8_COEFFS_PROPABILITIES_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_default_token_probability_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_DEFAULT_TOKEN_PROBABILITY);

	// Picture state surface
	size = VP8_PICTURE_STATE_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_picture_state_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_PICTURE_STATE);

	// MPU Curbe info from TPU
	size = VP8_TOKEN_BITS_DATA_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_token_bits_data_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_MPU_CURBE_DATA);

	// Encoder CFG command surface
	size = VP8_HEADER_METADATA_SIZE;

	if (brc_enabled) {
		i965_add_buffer_gpe_surface(ctx,
									gpe_context,
									&vp8_context->brc_vp8_cfg_command_write_buffer,
									0,
									size,
									0,
									VP8_BTI_TPU_HEADER_METADATA);
	} else {
		i965_add_buffer_gpe_surface(ctx,
									gpe_context,
									&vp8_context->pak_mpu_tpu_picture_state_buffer,
									0,
									size,
									VP8_HEADER_METADATA_OFFSET,
									VP8_BTI_TPU_HEADER_METADATA);
	}

	// Current frame token probability
	size = VP8_COEFFS_PROPABILITIES_SIZE;
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_coeff_probs_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_TOKEN_PROBABILITY);

	// Hardware token probability pass 1
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_ref_coeff_probs_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_PAK_HW_PASS1_PROBABILITY);

	// key frame token probability
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_updated_token_probability_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_UPDATED_TOKEN_PROBABILITY);

	// update token probability
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_key_frame_token_probability_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_KEY_TOKEN_PROBABILITY);

	// Hardware token probability pass 2
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_hw_token_probability_pak_pass_2_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_PAK_HW_PASS2_PROBABILITY);

	// Repak Decision
	i965_add_buffer_gpe_surface(ctx,
								gpe_context,
								&vp8_context->pak_mpu_tpu_repak_decision_buffer,
								0,
								size,
								0,
								VP8_BTI_TPU_REPAK_DECISION);
}

static void
i965_encoder_vp8_pak_tpu(VADriverContextP ctx,
						 struct encode_state *encode_state,
						 struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct i965_encoder_vp8_tpu_context *tpu_context = &vp8_context->tpu_context;
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct gpe_media_object_parameter media_object_param;
	struct i965_gpe_context *gpe_context;
	int media_function = VP8_MEDIA_STATE_TPU;

	gpe_context = &tpu_context->gpe_contexts[0];
	/* gpe->context_init(ctx, gpe_context); */
	gpe->reset_binding_table(ctx, gpe_context);

	if (!vp8_context->tpu_curbe_updated_in_brc_update)
		i965_encoder_vp8_pak_tpu_set_curbe(ctx, encode_state, encoder_context, gpe_context);

	i965_encoder_vp8_tpu_add_surfaces(ctx, encode_state, encoder_context, gpe_context);
	gpe->setup_interface_data(ctx, gpe_context);

	memset(&media_object_param, 0, sizeof(media_object_param));
	i965_run_kernel_media_object(ctx, encoder_context, gpe_context, media_function, &media_object_param);
}

#define PAK_REFERENCE_BO(dst_bo, src_bo, is_ref_bo)     \
	do {                                                \
		dri_bo_unreference(dst_bo);                     \
		dst_bo = src_bo;                                \
		if (is_ref_bo)                                  \
			dri_bo_reference(dst_bo);                   \
	} while (0)

static void
i965_encoder_vp8_pak_pipeline_prepare(VADriverContextP ctx,
									  struct encode_state *encode_state,
									  struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct object_surface *obj_surface;
	struct object_buffer *obj_buffer;
	struct i965_coded_buffer_segment *coded_buffer_segment;
	dri_bo *bo;
	int i;

	/* reconstructed surface */
	obj_surface = encode_state->reconstructed_object;
	i965_check_alloc_surface_bo(ctx, obj_surface, 1, VA_FOURCC_NV12, SUBSAMPLE_YUV420);

	PAK_REFERENCE_BO(vp8_context->pre_deblocking_output.bo, obj_surface->bo, 1);
	PAK_REFERENCE_BO(vp8_context->post_deblocking_output.bo, obj_surface->bo, 1);

	/* set vp8 reference frames */
	for (i = 0; i < ARRAY_ELEMS(vp8_context->reference_surfaces); i++) {
		obj_surface = encode_state->reference_objects[i];

		if (obj_surface && obj_surface->bo) {
			PAK_REFERENCE_BO(vp8_context->reference_surfaces[i].bo, obj_surface->bo, 1);
		} else {
			PAK_REFERENCE_BO(vp8_context->reference_surfaces[i].bo, NULL, 0);
		}
	}

	/* input YUV surface */
	obj_surface = encode_state->input_yuv_object;
	PAK_REFERENCE_BO(vp8_context->uncompressed_picture_source.bo, obj_surface->bo, 1);

	/* coded buffer */
	obj_buffer = encode_state->coded_buf_object;
	bo = obj_buffer->buffer_store->bo;
	vp8_context->indirect_pak_bse_object.offset = I965_CODEDBUFFER_HEADER_SIZE;
	vp8_context->indirect_pak_bse_object.end_offset = ALIGN((obj_buffer->size_element - 0x1000), 0x1000);
	PAK_REFERENCE_BO(vp8_context->indirect_pak_bse_object.bo, bo, 1);

	/* set the internal flag to 0 to indicate the coded size is unknown */
	dri_bo_map(bo, 1);

	if (!bo->virtual)
		return;

	coded_buffer_segment = (struct i965_coded_buffer_segment *)bo->virtual;
	coded_buffer_segment->mapped = 0;
	coded_buffer_segment->codec = encoder_context->codec;
	coded_buffer_segment->status_support = 1;
	dri_bo_unmap(bo);
}

static VAStatus
i965_encoder_vp8_pak_pipeline_final(VADriverContextP ctx,
									struct encode_state *encode_state,
									struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct i965_encoder_vp8_tpu_context *tpu_context = &vp8_context->tpu_context;

	dri_bo_unreference(tpu_context->dynamic_buffer);
	tpu_context->dynamic_buffer = NULL;

	return VA_STATUS_SUCCESS;
}

#undef PAK_REFERENCE_BO

static VAStatus
i965_encoder_vp8_pak_pipeline(VADriverContextP ctx,
							  VAProfile profile,
							  struct encode_state *encode_state,
							  struct intel_encoder_context *encoder_context)
{
	struct i965_encoder_vp8_context *vp8_context = encoder_context->mfc_context;
	struct intel_batchbuffer *batch = encoder_context->base.batch;

	i965_encoder_vp8_pak_pipeline_prepare(ctx, encode_state, encoder_context);

	vp8_context->is_render_context = 0;
	vp8_context->submit_batchbuffer = 1;

	for (vp8_context->curr_pass = 0; vp8_context->curr_pass <= vp8_context->num_passes; vp8_context->curr_pass++) {
		vp8_context->tpu_required = ((vp8_context->curr_pass == (vp8_context->num_passes - 1) &&
									  vp8_context->repak_pass_iter_val > 0) ||
									 (vp8_context->curr_pass == vp8_context->num_passes &&
									  vp8_context->repak_pass_iter_val == 0));

		if (vp8_context->submit_batchbuffer)
			intel_batchbuffer_start_atomic_bcs_override(batch, 0x1000, vp8_context->vdbox_idc);

		intel_batchbuffer_emit_mi_flush(batch);
		i965_encoder_vp8_pak_picture_level(ctx, encode_state, encoder_context);
		i965_encoder_vp8_pak_slice_level(ctx, encode_state, encoder_context);

		if (vp8_context->submit_batchbuffer) {
			intel_batchbuffer_end_atomic(batch);
			intel_batchbuffer_flush(batch);
		}

		if (vp8_context->tpu_required) {
			assert(vp8_context->submit_batchbuffer);
			i965_encoder_vp8_pak_tpu(ctx, encode_state, encoder_context);
		}
	}

	if (!vp8_context->is_first_frame && vp8_context->is_first_two_frame)
		vp8_context->is_first_two_frame = 0;

	vp8_context->is_first_frame = 0;
	vp8_context->tpu_curbe_updated_in_brc_update = 0;

	i965_encoder_vp8_pak_pipeline_final(ctx, encode_state, encoder_context);

	return VA_STATUS_SUCCESS;
}

static void
i965_encoder_vp8_pak_tpu_context_init(VADriverContextP ctx,
									  struct i965_encoder_vp8_context *vp8_context,
									  struct i965_encoder_vp8_tpu_context *tpu_context)
{
	struct i965_gpe_table *gpe = vp8_context->gpe_table;
	struct i965_gpe_context *gpe_context = NULL;
	struct vp8_encoder_kernel_parameters kernel_params;
	struct vp8_encoder_scoreboard_parameters scoreboard_params;
	int i;

	kernel_params.curbe_size = sizeof(struct vp8_tpu_curbe_data);
	kernel_params.inline_data_size = 0;
	kernel_params.external_data_size = 0;

	memset(&scoreboard_params, 0, sizeof(scoreboard_params));
	scoreboard_params.mask = 0xFF;
	scoreboard_params.enable = vp8_context->use_hw_scoreboard;
	scoreboard_params.type = vp8_context->use_hw_non_stalling_scoreborad;

	for (i = 0; i < NUM_VP8_TPU; i++) {
		gpe_context = &tpu_context->gpe_contexts[i];
		i965_encoder_vp8_gpe_context_init_once(ctx, gpe_context, &kernel_params, vp8_context->idrt_entry_size);
		i965_encoder_vp8_gpe_context_vfe_scoreboard_init(gpe_context, &scoreboard_params);
		gpe->load_kernels(ctx,
						  gpe_context,
						  &vp8_kernels_tpu[i],
						  1);
	}
}

static void
i965_encoder_vp8_pak_kernels_context_init(VADriverContextP ctx,
										  struct intel_encoder_context *encoder_context,
										  struct i965_encoder_vp8_context *vp8_context)
{
	i965_encoder_vp8_pak_tpu_context_init(ctx, vp8_context, &vp8_context->tpu_context);
}

static VAStatus
i965_encoder_vp8_get_status(VADriverContextP ctx,
							struct intel_encoder_context *encoder_context,
							struct i965_coded_buffer_segment *coded_buffer_segment)
{
	struct vp8_encode_status *encode_state = (struct vp8_encode_status *)coded_buffer_segment->codec_private_data;

	coded_buffer_segment->base.size = encode_state->bitstream_byte_count_per_frame;

	return VA_STATUS_SUCCESS;
}

Bool
i965_encoder_vp8_pak_context_init(VADriverContextP ctx, struct intel_encoder_context *encoder_context)
{
	/* VME & PAK share the same context */
	struct i965_encoder_vp8_context *vp8_context = encoder_context->vme_context;

	assert(vp8_context);
	i965_encoder_vp8_pak_kernels_context_init(ctx, encoder_context, vp8_context);

	encoder_context->mfc_context = vp8_context;
	encoder_context->mfc_context_destroy = i965_encoder_vp8_pak_context_destroy;
	encoder_context->mfc_pipeline = i965_encoder_vp8_pak_pipeline;
	encoder_context->mfc_brc_prepare = i965_encoder_vp8_pak_pre_pipeline;
	encoder_context->get_status = i965_encoder_vp8_get_status;

	return True;
}
