/*
 * Copyright © 2006 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, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Authors:
 *    Xiang Haihao <haihao.xiang@intel.com>
 *
 */

#include <sys/ioctl.h>

#include "i915_xvmc.h"
#include "i915_structs.h"
#include "i915_program.h"

#define YOFFSET(surface)        (surface->srf.offset)
#define UOFFSET(surface)        (surface->srf.offset + \
                                 SIZE_Y420(surface->width, surface->height) + \
                                 SIZE_UV420(surface->width, surface->height))
#define VOFFSET(surface)        (surface->srf.offset + \
                                 SIZE_Y420(surface->width, surface->height))

typedef union {
    int16_t component[2];
    int32_t v;
} vector_t;

#if 0
static int findOverlap(unsigned int width, unsigned int height,
                       short *dstX, short *dstY,
                       short *srcX, short *srcY,
                       unsigned short *areaW, unsigned short *areaH)
{
    int w, h;
    unsigned int mWidth, mHeight;

    w = *areaW;
    h = *areaH;

    if ((*dstX >= width) || (*dstY >= height))
        return 1;

    if (*dstX < 0) {
        w += *dstX;
        *srcX -= *dstX;
        *dstX = 0;
    }

    if (*dstY < 0) {
        h += *dstY;
        *srcY -= *dstY;
        *dstY = 0;
    }

    if ((w <= 0) || ((h <= 0)))
        return 1;

    mWidth = width - *dstX;
    mHeight = height - *dstY;
    *areaW = (w <= mWidth) ? w : mWidth;
    *areaH = (h <= mHeight) ? h : mHeight;
    return 0;
}
#endif

static void i915_inst_arith(unsigned int *inst,
                            unsigned int op,
                            unsigned int dest,
                            unsigned int mask,
                            unsigned int saturate,
                            unsigned int src0, unsigned int src1, unsigned int src2)
{
    dest = UREG(GET_UREG_TYPE(dest), GET_UREG_NR(dest));
    *inst = (op | A0_DEST(dest) | mask | saturate | A0_SRC0(src0));
    inst++;
    *inst = (A1_SRC0(src0) | A1_SRC1(src1));
    inst++;
    *inst = (A2_SRC1(src1) | A2_SRC2(src2));
}

static void i915_inst_decl(unsigned int *inst,
                           unsigned int type,
                           unsigned int nr,
                           unsigned int d0_flags)
{
    unsigned int reg = UREG(type, nr);

    *inst = (D0_DCL | D0_DEST(reg) | d0_flags);
    inst++;
    *inst = D1_MBZ;
    inst++;
    *inst = D2_MBZ;
}

static void i915_inst_texld(unsigned int *inst,
                              unsigned int op,
                              unsigned int dest,
                              unsigned int coord,
                              unsigned int sampler)
{
   dest = UREG(GET_UREG_TYPE(dest), GET_UREG_NR(dest));
   *inst = (op | T0_DEST(dest) | T0_SAMPLER(sampler));
   inst++;
   *inst = T1_ADDRESS_REG(coord);
   inst++;
   *inst = T2_MBZ;
}

static void i915_emit_batch(void *data, int size, int flag)
{
    intelBatchbufferData(data, size, flag);
}

/* one time context initialization buffer */
static uint32_t *one_time_load_state_imm1;
static uint32_t *one_time_load_indirect;
static int one_time_load_state_imm1_size, one_time_load_indirect_size;

/* load indirect buffer for mc rendering */
static uint32_t *mc_render_load_indirect;
static int mc_render_load_indirect_size;

static void i915_mc_one_time_context_init(XvMCContext *context)
{
    unsigned int dest, src0, src1, src2;
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)context->privData;
    int i;
    struct i915_3dstate_sampler_state *sampler_state;
    struct i915_3dstate_pixel_shader_program *pixel_shader_program;
    struct i915_3dstate_pixel_shader_constants *pixel_shader_constants;

    /* sampler static state */
    sampler_state = (struct i915_3dstate_sampler_state *)pI915XvMC->ssb.map;
    /* pixel shader static state */
    pixel_shader_program = (struct i915_3dstate_pixel_shader_program *)pI915XvMC->psp.map;
    /* pixel shader contant static state */
    pixel_shader_constants = (struct i915_3dstate_pixel_shader_constants *)pI915XvMC->psc.map;

    memset(sampler_state, 0, sizeof(*sampler_state));
    sampler_state->dw0.type = CMD_3D;
    sampler_state->dw0.opcode = OPC_3DSTATE_SAMPLER_STATE;
    sampler_state->dw0.length = 6;
    sampler_state->dw1.sampler_masker = SAMPLER_SAMPLER0 | SAMPLER_SAMPLER1;

    sampler_state->sampler0.ts0.reverse_gamma = 0;
    sampler_state->sampler0.ts0.planar2packet = 0;
    sampler_state->sampler0.ts0.color_conversion = 0;
    sampler_state->sampler0.ts0.chromakey_index = 0;
    sampler_state->sampler0.ts0.base_level = 0;
    sampler_state->sampler0.ts0.mip_filter = MIPFILTER_NONE;        /* NONE */
    sampler_state->sampler0.ts0.mag_filter = MAPFILTER_LINEAR;      /* LINEAR */
    sampler_state->sampler0.ts0.min_filter = MAPFILTER_LINEAR;      /* LINEAR */
    sampler_state->sampler0.ts0.lod_bias = 0;       /* 0.0 */
    sampler_state->sampler0.ts0.shadow_enable = 0;
    sampler_state->sampler0.ts0.max_anisotropy = ANISORATIO_2;
    sampler_state->sampler0.ts0.shadow_function = PREFILTEROP_ALWAYS;
    sampler_state->sampler0.ts1.min_lod = 0;        /* 0.0 Maximum Mip Level */
    sampler_state->sampler0.ts1.kill_pixel = 0;
    sampler_state->sampler0.ts1.keyed_texture_filter = 0;
    sampler_state->sampler0.ts1.chromakey_enable = 0;
    sampler_state->sampler0.ts1.tcx_control = TEXCOORDMODE_CLAMP;
    sampler_state->sampler0.ts1.tcy_control = TEXCOORDMODE_CLAMP;
    sampler_state->sampler0.ts1.tcz_control = TEXCOORDMODE_CLAMP;
    sampler_state->sampler0.ts1.normalized_coor = 0;
    sampler_state->sampler0.ts1.map_index = 0;
    sampler_state->sampler0.ts1.east_deinterlacer = 0;
    sampler_state->sampler0.ts2.default_color = 0;

    sampler_state->sampler1.ts0.reverse_gamma = 0;
    sampler_state->sampler1.ts0.planar2packet = 0;
    sampler_state->sampler1.ts0.color_conversion = 0;
    sampler_state->sampler1.ts0.chromakey_index = 0;
    sampler_state->sampler1.ts0.base_level = 0;
    sampler_state->sampler1.ts0.mip_filter = MIPFILTER_NONE;        /* NONE */
    sampler_state->sampler1.ts0.mag_filter = MAPFILTER_LINEAR;      /* LINEAR */
    sampler_state->sampler1.ts0.min_filter = MAPFILTER_LINEAR;      /* LINEAR */
    sampler_state->sampler1.ts0.lod_bias = 0;       /* 0.0 */
    sampler_state->sampler1.ts0.shadow_enable = 0;
    sampler_state->sampler1.ts0.max_anisotropy = ANISORATIO_2;
    sampler_state->sampler1.ts0.shadow_function = PREFILTEROP_ALWAYS;
    sampler_state->sampler1.ts1.min_lod = 0;        /* 0.0 Maximum Mip Level */
    sampler_state->sampler1.ts1.kill_pixel = 0;
    sampler_state->sampler1.ts1.keyed_texture_filter = 0;
    sampler_state->sampler1.ts1.chromakey_enable = 0;
    sampler_state->sampler1.ts1.tcx_control = TEXCOORDMODE_CLAMP;
    sampler_state->sampler1.ts1.tcy_control = TEXCOORDMODE_CLAMP;
    sampler_state->sampler1.ts1.tcz_control = TEXCOORDMODE_CLAMP;
    sampler_state->sampler1.ts1.normalized_coor = 0;
    sampler_state->sampler1.ts1.map_index = 1;
    sampler_state->sampler1.ts1.east_deinterlacer = 0;
    sampler_state->sampler1.ts2.default_color = 0;

    memset(pixel_shader_program, 0, sizeof(*pixel_shader_program));
    pixel_shader_program->shader0.type = CMD_3D;
    pixel_shader_program->shader0.opcode = OPC_3DSTATE_PIXEL_SHADER_PROGRAM;
    pixel_shader_program->shader0.retain = 1;
    pixel_shader_program->shader0.length = 2; /* 1 inst */
    i = 0;

    dest = UREG(REG_TYPE_OC, 0);
    src0 = UREG(REG_TYPE_CONST, 0);
    src1 = 0;
    src2 = 0;
    i915_inst_arith(&pixel_shader_program->inst0[i], A0_MOV,
	    dest, A0_DEST_CHANNEL_ALL, A0_DEST_SATURATE, src0, src1, src2);

    pixel_shader_program->shader1.type = CMD_3D;
    pixel_shader_program->shader1.opcode = OPC_3DSTATE_PIXEL_SHADER_PROGRAM;
    pixel_shader_program->shader1.retain = 1;
    pixel_shader_program->shader1.length = 14; /* 5 inst */
    i = 0;
    /* dcl t0.xy */
    i915_inst_decl(&pixel_shader_program->inst1[i], REG_TYPE_T, T_TEX0, D0_CHANNEL_XY);
    i+=3;
    /* dcl t1.xy */
    i915_inst_decl(&pixel_shader_program->inst1[i], REG_TYPE_T, T_TEX1, D0_CHANNEL_XY);
    /* dcl_2D s0 */
    i += 3;
    i915_inst_decl(&pixel_shader_program->inst1[i], REG_TYPE_S, 0, D0_SAMPLE_TYPE_2D);
    /* texld r0, t0, s0 */
    i += 3;
    dest = UREG(REG_TYPE_R, 0);
    src0 = UREG(REG_TYPE_T, 0); /* COORD */
    src1 = UREG(REG_TYPE_S, 0); /* SAMPLER */
    i915_inst_texld(&pixel_shader_program->inst1[i], T0_TEXLD, dest, src0, src1);
    /* mov oC, r0 */
    i += 3;
    dest = UREG(REG_TYPE_OC, 0);
    src0 = UREG(REG_TYPE_R, 0);
    src1 = src2 = 0;
    i915_inst_arith(&pixel_shader_program->inst1[i], A0_MOV, dest, A0_DEST_CHANNEL_ALL,
                    A0_DEST_SATURATE, src0, src1, src2);


    pixel_shader_program->shader2.type = CMD_3D;
    pixel_shader_program->shader2.opcode = OPC_3DSTATE_PIXEL_SHADER_PROGRAM;
    pixel_shader_program->shader2.retain = 1;
    pixel_shader_program->shader2.length = 14; /* 5 inst */
    i = 0;
    /* dcl t2.xy */
    i915_inst_decl(&pixel_shader_program->inst2[i], REG_TYPE_T, T_TEX2, D0_CHANNEL_XY);
    /* dcl t3.xy */
    i += 3;
    i915_inst_decl(&pixel_shader_program->inst2[i], REG_TYPE_T, T_TEX3, D0_CHANNEL_XY);
    /* dcl_2D s1 */
    i += 3;
    i915_inst_decl(&pixel_shader_program->inst2[i], REG_TYPE_S, 1, D0_SAMPLE_TYPE_2D);
    /* texld r0, t2, s1 */
    i += 3;
    dest = UREG(REG_TYPE_R, 0);
    src0 = UREG(REG_TYPE_T, 2); /* COORD */
    src1 = UREG(REG_TYPE_S, 1); /* SAMPLER */
    i915_inst_texld(&pixel_shader_program->inst2[i], T0_TEXLD, dest, src0, src1);
    /* mov oC, r0 */
    i += 3;
    dest = UREG(REG_TYPE_OC, 0);
    src0 = UREG(REG_TYPE_R, 0);
    src1 = src2 = 0;
    i915_inst_arith(&pixel_shader_program->inst2[i], A0_MOV, dest, A0_DEST_CHANNEL_ALL,
                    A0_DEST_SATURATE, src0, src1, src2);

    /* Shader 3 */
    pixel_shader_program->shader3.type = CMD_3D;
    pixel_shader_program->shader3.opcode = OPC_3DSTATE_PIXEL_SHADER_PROGRAM;
    pixel_shader_program->shader3.retain = 1;
    pixel_shader_program->shader3.length = 29; /* 10 inst */
    i = 0;
    /* dcl t0.xy */
    i915_inst_decl(&pixel_shader_program->inst3[i], REG_TYPE_T, T_TEX0, D0_CHANNEL_XY);
    /* dcl t1.xy */
    i += 3;
    i915_inst_decl(&pixel_shader_program->inst3[i], REG_TYPE_T, T_TEX1, D0_CHANNEL_XY);
    /* dcl t2.xy */
    i += 3;
    i915_inst_decl(&pixel_shader_program->inst3[i], REG_TYPE_T, T_TEX2, D0_CHANNEL_XY);
    /* dcl t3.xy */
    i += 3;
    i915_inst_decl(&pixel_shader_program->inst3[i], REG_TYPE_T, T_TEX3, D0_CHANNEL_XY);
    /* dcl_2D s0 */
    i += 3;
    i915_inst_decl(&pixel_shader_program->inst3[i], REG_TYPE_S, 0, D0_SAMPLE_TYPE_2D);
    /* dcl_2D s1 */
    i += 3;
    i915_inst_decl(&pixel_shader_program->inst3[i], REG_TYPE_S, 1, D0_SAMPLE_TYPE_2D);
    /* texld r0, t0, s0 */
    i += 3;
    dest = UREG(REG_TYPE_R, 0);
    src0 = UREG(REG_TYPE_T, 0); /* COORD */
    src1 = UREG(REG_TYPE_S, 0); /* SAMPLER */
    i915_inst_texld(&pixel_shader_program->inst3[i], T0_TEXLD, dest, src0, src1);
    /* texld r1, t2, s1 */
    i += 3;
    dest = UREG(REG_TYPE_R, 1);
    src0 = UREG(REG_TYPE_T, 2); /* COORD */
    src1 = UREG(REG_TYPE_S, 1); /* SAMPLER */
    i915_inst_texld(&pixel_shader_program->inst3[i], T0_TEXLD, dest, src0, src1);
    /* add r0, r0, r1 */
    i += 3;
    dest = UREG(REG_TYPE_R, 0);
    src0 = UREG(REG_TYPE_R, 0);
    src1 = UREG(REG_TYPE_R, 1);
    src2 = 0;
    i915_inst_arith(&pixel_shader_program->inst3[i], A0_ADD, dest, A0_DEST_CHANNEL_ALL,
                    0 /* A0_DEST_SATURATE */, src0, src1, src2);
    /* mul oC, r0, c0 */
    i += 3;
    dest = UREG(REG_TYPE_OC, 0);
    src0 = UREG(REG_TYPE_R, 0);
    src1 = UREG(REG_TYPE_CONST, 0);
    src2 = 0;
    i915_inst_arith(&pixel_shader_program->inst3[i], A0_MUL, dest, A0_DEST_CHANNEL_ALL,
                    A0_DEST_SATURATE, src0, src1, src2);

    memset(pixel_shader_constants, 0, sizeof(*pixel_shader_constants));
    pixel_shader_constants->dw0.type = CMD_3D;
    pixel_shader_constants->dw0.opcode = OPC_3DSTATE_PIXEL_SHADER_CONSTANTS;
    pixel_shader_constants->dw0.length = 4;
    pixel_shader_constants->dw1.reg_mask = REG_CR0;
    pixel_shader_constants->value.x = 0.5;
    pixel_shader_constants->value.y = 0.5;
    pixel_shader_constants->value.z = 0.5;
    pixel_shader_constants->value.w = 0.5;

}

static void i915_mc_one_time_state_init(XvMCContext *context)
{
    struct s3_dword *s3 = NULL;
    struct s6_dword *s6 = NULL;
    dis_state *dis = NULL;
    ssb_state *ssb = NULL;
    psp_state *psp = NULL;
    psc_state *psc = NULL;
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)context->privData;
    struct i915_3dstate_load_state_immediate_1 *load_state_immediate_1;
    struct i915_3dstate_load_indirect *load_indirect;
    int mem_select;

    /* 3DSTATE_LOAD_STATE_IMMEDIATE_1 */
    one_time_load_state_imm1_size = sizeof(*load_state_immediate_1) + sizeof(*s3) + sizeof(*s6);
    one_time_load_state_imm1 = calloc(1, one_time_load_state_imm1_size);
    load_state_immediate_1 = (struct i915_3dstate_load_state_immediate_1 *)one_time_load_state_imm1;
    load_state_immediate_1->dw0.type = CMD_3D;
    load_state_immediate_1->dw0.opcode = OPC_3DSTATE_LOAD_STATE_IMMEDIATE_1;
    load_state_immediate_1->dw0.load_s3 = 1;
    load_state_immediate_1->dw0.load_s6 = 1;
    load_state_immediate_1->dw0.length = (one_time_load_state_imm1_size >> 2) - 2;

    s3 = (struct s3_dword *)(++load_state_immediate_1);
    s3->set0_pcd = 1;
    s3->set1_pcd = 1;
    s3->set2_pcd = 1;
    s3->set3_pcd = 1;
    s3->set4_pcd = 1;
    s3->set5_pcd = 1;
    s3->set6_pcd = 1;
    s3->set7_pcd = 1;

    s6 = (struct s6_dword *)(++s3);
    s6->alpha_test_enable = 0;
    s6->alpha_test_function = 0;
    s6->alpha_reference_value = 0;
    s6->depth_test_enable = 1;
    s6->depth_test_function = 0;
    s6->color_buffer_blend = 0;
    s6->color_blend_function = 0;
    s6->src_blend_factor = 1;
    s6->dest_blend_factor = 1;
    s6->depth_buffer_write = 0;
    s6->color_buffer_write = 1;
    s6->triangle_pv = 0;

    /* 3DSTATE_LOAD_INDIRECT */
    one_time_load_indirect_size = sizeof(*load_indirect) + sizeof(*dis) + sizeof(*ssb) + sizeof(*psp) + sizeof(*psc);
    one_time_load_indirect = calloc(1, one_time_load_indirect_size);
    load_indirect = (struct i915_3dstate_load_indirect *)one_time_load_indirect;
    load_indirect->dw0.type = CMD_3D;
    load_indirect->dw0.opcode = OPC_3DSTATE_LOAD_INDIRECT;
    load_indirect->dw0.block_mask = BLOCK_DIS | BLOCK_SSB | BLOCK_PSP | BLOCK_PSC;
    load_indirect->dw0.length = (one_time_load_indirect_size >> 2) - 2;

    if (pI915XvMC->deviceID == PCI_CHIP_I915_G ||
        pI915XvMC->deviceID == PCI_CHIP_I915_GM)
	mem_select = 0; /* use physical address */
    else
	mem_select = 1; /* use gfx address */

    load_indirect->dw0.mem_select = mem_select;


    /* Dynamic indirect state buffer */
    dis = (dis_state *)(++load_indirect);
    dis->dw0.valid = 0;
    dis->dw0.reset = 0;
    dis->dw0.buffer_address = 0;

    /* Sample state buffer */
    ssb = (ssb_state *)(++dis);
    ssb->dw0.valid = 1;
    ssb->dw0.force = 1;
    ssb->dw1.length = 7; /* 8 - 1 */

    if (mem_select)
        ssb->dw0.buffer_address = (pI915XvMC->ssb.offset >> 2);
    else
	ssb->dw0.buffer_address = (pI915XvMC->ssb.bus_addr >> 2);

    /* Pixel shader program buffer */
    psp = (psp_state *)(++ssb);
    psp->dw0.valid = 1;
    psp->dw0.force = 1;
    psp->dw1.length = 66; /* 4 + 16 + 16 + 31 - 1 */

    if (mem_select)
	psp->dw0.buffer_address = (pI915XvMC->psp.offset >> 2);
    else
	psp->dw0.buffer_address = (pI915XvMC->psp.bus_addr >> 2);

    /* Pixel shader constant buffer */
    psc = (psc_state *)(++psp);
    psc->dw0.valid = 1;
    psc->dw0.force = 1;
    psc->dw1.length = 5; /* 6 - 1 */

    if (mem_select)
        psc->dw0.buffer_address = (pI915XvMC->psc.offset >> 2);
    else
        psc->dw0.buffer_address = (pI915XvMC->psc.bus_addr >> 2);
}

static void i915_mc_one_time_state_emit(void)
{
    i915_emit_batch(one_time_load_state_imm1, one_time_load_state_imm1_size, 0);
    i915_emit_batch(one_time_load_indirect, one_time_load_indirect_size, 0);
}

static void i915_mc_static_indirect_state_init(XvMCContext *context)
{
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)context->privData;
    struct i915_mc_static_indirect_state_buffer *buffer_info =
	(struct i915_mc_static_indirect_state_buffer *)pI915XvMC->sis.map;

    memset(buffer_info, 0, sizeof(*buffer_info));
    /* dest Y */
    buffer_info->dest_y.dw0.type = CMD_3D;
    buffer_info->dest_y.dw0.opcode = OPC_3DSTATE_BUFFER_INFO;
    buffer_info->dest_y.dw0.length = 1;
    buffer_info->dest_y.dw1.aux_id = 0;
    buffer_info->dest_y.dw1.buffer_id = BUFFERID_COLOR_BACK;
    buffer_info->dest_y.dw1.fence_regs = 0;    /* disabled */ /* FIXME: tiled y for performance */
    buffer_info->dest_y.dw1.tiled_surface = 0; /* linear */
    buffer_info->dest_y.dw1.walk = TILEWALK_XMAJOR;

    /* dest U */
    buffer_info->dest_u.dw0.type = CMD_3D;
    buffer_info->dest_u.dw0.opcode = OPC_3DSTATE_BUFFER_INFO;
    buffer_info->dest_u.dw0.length = 1;
    buffer_info->dest_u.dw1.aux_id = 0;
    buffer_info->dest_u.dw1.buffer_id = BUFFERID_COLOR_AUX;
    buffer_info->dest_u.dw1.fence_regs = 0;
    buffer_info->dest_u.dw1.tiled_surface = 0;
    buffer_info->dest_u.dw1.walk = TILEWALK_XMAJOR;

    /* dest V */
    buffer_info->dest_v.dw0.type = CMD_3D;
    buffer_info->dest_v.dw0.opcode = OPC_3DSTATE_BUFFER_INFO;
    buffer_info->dest_v.dw0.length = 1;
    buffer_info->dest_v.dw1.aux_id = 1;
    buffer_info->dest_v.dw1.buffer_id = BUFFERID_COLOR_AUX;
    buffer_info->dest_v.dw1.fence_regs = 0;
    buffer_info->dest_v.dw1.tiled_surface = 0;
    buffer_info->dest_v.dw1.walk = TILEWALK_XMAJOR;

    buffer_info->dest_buf.dw0.type = CMD_3D;
    buffer_info->dest_buf.dw0.opcode = OPC_3DSTATE_DEST_BUFFER_VARIABLES;
    buffer_info->dest_buf.dw0.length = 0;
    buffer_info->dest_buf.dw1.dest_v_bias = 8; /* 0.5 */
    buffer_info->dest_buf.dw1.dest_h_bias = 8; /* 0.5 */
    buffer_info->dest_buf.dw1.color_fmt = COLORBUFFER_8BIT;
    buffer_info->dest_buf.dw1.v_ls = 0; /* fill later */
    buffer_info->dest_buf.dw1.v_ls_offset = 0; /* fill later */

    buffer_info->dest_buf_mpeg.dw0.type = CMD_3D;
    buffer_info->dest_buf_mpeg.dw0.opcode = OPC_3DSTATE_DEST_BUFFER_VARIABLES_MPEG;
    buffer_info->dest_buf_mpeg.dw0.length = 1;
    buffer_info->dest_buf_mpeg.dw1.decode_mode = MPEG_DECODE_MC;
    buffer_info->dest_buf_mpeg.dw1.rcontrol = 0;               /* for MPEG-1/MPEG-2 */
    buffer_info->dest_buf_mpeg.dw1.bidir_avrg_control = 0;     /* for MPEG-1/MPEG-2/MPEG-4 */
    buffer_info->dest_buf_mpeg.dw1.abort_on_error = 1;
    buffer_info->dest_buf_mpeg.dw1.intra8 = 0;         /* 16-bit formatted correction data */
    buffer_info->dest_buf_mpeg.dw1.tff = 1; /* fill later */

    buffer_info->dest_buf_mpeg.dw1.v_subsample_factor = MC_SUB_1V;
    buffer_info->dest_buf_mpeg.dw1.h_subsample_factor = MC_SUB_1H;

    buffer_info->corr.dw0.type = CMD_3D;
    buffer_info->corr.dw0.opcode = OPC_3DSTATE_BUFFER_INFO;
    buffer_info->corr.dw0.length = 1;
    buffer_info->corr.dw1.aux_id = 0;
    buffer_info->corr.dw1.buffer_id = BUFFERID_MC_INTRA_CORR;
    buffer_info->corr.dw1.aux_id = 0;
    buffer_info->corr.dw1.fence_regs = 0;
    buffer_info->corr.dw1.tiled_surface = 0;
    buffer_info->corr.dw1.walk = 0;
    buffer_info->corr.dw1.pitch = 0;
    buffer_info->corr.dw2.base_address = (pI915XvMC->corrdata.offset >> 2);  /* starting DWORD address */
}

static void i915_mc_static_indirect_state_set(XvMCContext *context, XvMCSurface *dest,
	unsigned int picture_structure, unsigned int flags, unsigned int picture_coding_type)
{
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)context->privData;
    i915XvMCSurface *pI915Surface = (i915XvMCSurface *)dest->privData;
    struct i915_mc_static_indirect_state_buffer *buffer_info =
	(struct i915_mc_static_indirect_state_buffer *)pI915XvMC->sis.map;
    unsigned int w = dest->width;

    buffer_info->dest_y.dw1.pitch = (pI915Surface->yStride >> 2);      /* in DWords */
    buffer_info->dest_y.dw2.base_address = (YOFFSET(pI915Surface) >> 2);    /* starting DWORD address */
    buffer_info->dest_u.dw1.pitch = (pI915Surface->uvStride >> 2);      /* in DWords */
    buffer_info->dest_u.dw2.base_address = (UOFFSET(pI915Surface) >> 2);      /* starting DWORD address */
    buffer_info->dest_v.dw1.pitch = (pI915Surface->uvStride >> 2);      /* in Dwords */
    buffer_info->dest_v.dw2.base_address = (VOFFSET(pI915Surface) >> 2);      /* starting DWORD address */

    if ((picture_structure & XVMC_FRAME_PICTURE) == XVMC_FRAME_PICTURE) {
        ;
    } else if ((picture_structure & XVMC_FRAME_PICTURE) == XVMC_TOP_FIELD) {
        buffer_info->dest_buf.dw1.v_ls = 1;
    } else if ((picture_structure & XVMC_FRAME_PICTURE) == XVMC_BOTTOM_FIELD) {
        buffer_info->dest_buf.dw1.v_ls = 1;
        buffer_info->dest_buf.dw1.v_ls_offset = 1;
    }

    if (picture_structure & XVMC_FRAME_PICTURE) {
        ;
    } else if (picture_structure & XVMC_TOP_FIELD) {
        if (flags & XVMC_SECOND_FIELD)
            buffer_info->dest_buf_mpeg.dw1.tff = 0;
        else
            buffer_info->dest_buf_mpeg.dw1.tff = 1;
    } else if (picture_structure & XVMC_BOTTOM_FIELD) {
        if (flags & XVMC_SECOND_FIELD)
            buffer_info->dest_buf_mpeg.dw1.tff = 1;
        else
            buffer_info->dest_buf_mpeg.dw1.tff = 0;
    }

    buffer_info->dest_buf_mpeg.dw1.picture_width = (dest->width >> 4);     /* in macroblocks */
    buffer_info->dest_buf_mpeg.dw2.picture_coding_type = picture_coding_type;
}

static void i915_mc_map_state_init(XvMCContext *context)
{
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)context->privData;
    unsigned int w = context->width;
    unsigned int h = context->height;
    struct i915_mc_map_state *map_state;

    map_state = (struct i915_mc_map_state *)pI915XvMC->msb.map;

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

    /* 3DSATE_MAP_STATE: Y */
    map_state->y_map.dw0.type = CMD_3D;
    map_state->y_map.dw0.opcode = OPC_3DSTATE_MAP_STATE;
    map_state->y_map.dw0.retain = 1;
    map_state->y_map.dw0.length = 6;
    map_state->y_map.dw1.map_mask = MAP_MAP0 | MAP_MAP1;

    /* Y Forward (Past) */
    map_state->y_forward.tm0.v_ls_offset = 0;
    map_state->y_forward.tm0.v_ls = 0;
    map_state->y_forward.tm1.tile_walk = TILEWALK_XMAJOR;
    map_state->y_forward.tm1.tiled_surface = 0;
    map_state->y_forward.tm1.utilize_fence_regs = 0;
    map_state->y_forward.tm1.texel_fmt = 0;      /* 8bit */
    map_state->y_forward.tm1.surface_fmt = 1;    /* 8bit */
    map_state->y_forward.tm1.width = w - 1;
    map_state->y_forward.tm1.height = h - 1;
    map_state->y_forward.tm2.depth = 0;
    map_state->y_forward.tm2.max_lod = 0;
    map_state->y_forward.tm2.cube_face = 0;

    /* Y Backward (Future) */
    map_state->y_backward.tm0.v_ls_offset = 0;
    map_state->y_backward.tm0.v_ls = 0;
    map_state->y_backward.tm1.tile_walk = TILEWALK_XMAJOR;
    map_state->y_backward.tm1.tiled_surface = 0;
    map_state->y_backward.tm1.utilize_fence_regs = 0;
    map_state->y_backward.tm1.texel_fmt = 0;      /* 8bit */
    map_state->y_backward.tm1.surface_fmt = 1;    /* 8bit */
    map_state->y_backward.tm1.width = w - 1;
    map_state->y_backward.tm1.height = h - 1;
    map_state->y_backward.tm2.depth = 0;
    map_state->y_backward.tm2.max_lod = 0;
    map_state->y_backward.tm2.cube_face = 0;

    /* 3DSATE_MAP_STATE: U */
    map_state->u_map.dw0.type = CMD_3D;
    map_state->u_map.dw0.opcode = OPC_3DSTATE_MAP_STATE;
    map_state->u_map.dw0.retain = 1;
    map_state->u_map.dw0.length = 6;
    map_state->u_map.dw1.map_mask = MAP_MAP0 | MAP_MAP1;

    /* U Forward */
    map_state->u_forward.tm0.v_ls_offset = 0;
    map_state->u_forward.tm0.v_ls = 0;
    map_state->u_forward.tm1.tile_walk = TILEWALK_XMAJOR;
    map_state->u_forward.tm1.tiled_surface = 0;
    map_state->u_forward.tm1.utilize_fence_regs = 0;
    map_state->u_forward.tm1.texel_fmt = 0;      /* 8bit */
    map_state->u_forward.tm1.surface_fmt = 1;    /* 8bit */
    map_state->u_forward.tm1.width = (w >> 1) - 1;
    map_state->u_forward.tm1.height = (h >> 1) - 1;
    map_state->u_forward.tm2.depth = 0;
    map_state->u_forward.tm2.max_lod = 0;
    map_state->u_forward.tm2.cube_face = 0;

    /* U Backward */
    map_state->u_backward.tm0.v_ls_offset = 0;
    map_state->u_backward.tm0.v_ls = 0;
    map_state->u_backward.tm1.tile_walk = TILEWALK_XMAJOR;
    map_state->u_backward.tm1.tiled_surface = 0;
    map_state->u_backward.tm1.utilize_fence_regs = 0;
    map_state->u_backward.tm1.texel_fmt = 0;
    map_state->u_backward.tm1.surface_fmt = 1;
    map_state->u_backward.tm1.width = (w >> 1) - 1;
    map_state->u_backward.tm1.height = (h >> 1) - 1;
    map_state->u_backward.tm2.depth = 0;
    map_state->u_backward.tm2.max_lod = 0;
    map_state->u_backward.tm2.cube_face = 0;

    /* 3DSATE_MAP_STATE: V */
    map_state->v_map.dw0.type = CMD_3D;
    map_state->v_map.dw0.opcode = OPC_3DSTATE_MAP_STATE;
    map_state->v_map.dw0.retain = 1;
    map_state->v_map.dw0.length = 6;
    map_state->v_map.dw1.map_mask = MAP_MAP0 | MAP_MAP1;

    /* V Forward */
    map_state->v_forward.tm0.v_ls_offset = 0;
    map_state->v_forward.tm0.v_ls = 0;
    map_state->v_forward.tm1.tile_walk = TILEWALK_XMAJOR;
    map_state->v_forward.tm1.tiled_surface = 0;
    map_state->v_forward.tm1.utilize_fence_regs = 0;
    map_state->v_forward.tm1.texel_fmt = 0;
    map_state->v_forward.tm1.surface_fmt = 1;
    map_state->v_forward.tm1.width = (w >> 1) - 1;
    map_state->v_forward.tm1.height = (h >> 1) - 1;
    map_state->v_forward.tm2.depth = 0;
    map_state->v_forward.tm2.max_lod = 0;
    map_state->v_forward.tm2.cube_face = 0;

    /* V Backward */
    map_state->v_backward.tm0.v_ls_offset = 0;
    map_state->v_backward.tm0.v_ls = 0;
    map_state->v_backward.tm1.tile_walk = TILEWALK_XMAJOR;
    map_state->v_backward.tm1.tiled_surface = 0;
    map_state->v_backward.tm1.utilize_fence_regs = 0;
    map_state->v_backward.tm1.texel_fmt = 0;
    map_state->v_backward.tm1.surface_fmt = 1;
    map_state->v_backward.tm1.width = (w >> 1) - 1;
    map_state->v_backward.tm1.height = (h >> 1) - 1;
    map_state->v_backward.tm2.depth = 0;
    map_state->v_backward.tm2.max_lod = 0;
    map_state->v_backward.tm2.cube_face = 0;
}

static void i915_mc_map_state_set(XvMCContext *context,
	i915XvMCSurface *privPast,
	i915XvMCSurface *privFuture)
{
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)context->privData;
    struct i915_mc_map_state *map_state;

    map_state = (struct i915_mc_map_state *)pI915XvMC->msb.map;

    map_state->y_forward.tm0.base_address = (YOFFSET(privPast) >> 2);
    map_state->y_forward.tm2.pitch = (privPast->yStride >> 2) - 1;       /* in DWords - 1 */
    map_state->y_backward.tm0.base_address = (YOFFSET(privFuture) >> 2);
    map_state->y_backward.tm2.pitch = (privFuture->yStride >> 2) - 1;
    map_state->u_forward.tm0.base_address = (UOFFSET(privPast) >> 2);
    map_state->u_forward.tm2.pitch = (privPast->uvStride >> 2) - 1;       /* in DWords - 1 */
    map_state->u_backward.tm0.base_address = (UOFFSET(privFuture) >> 2);
    map_state->u_backward.tm2.pitch = (privFuture->uvStride >> 2) - 1;
    map_state->v_forward.tm0.base_address = (VOFFSET(privPast) >> 2);
    map_state->v_forward.tm2.pitch = (privPast->uvStride >> 2) - 1;       /* in DWords - 1 */
    map_state->v_backward.tm0.base_address = (VOFFSET(privFuture) >> 2);
    map_state->v_backward.tm2.pitch = (privFuture->uvStride >> 2) - 1;
}

static void i915_flush(int map, int render)
{
    struct i915_mi_flush mi_flush;

    memset(&mi_flush, 0, sizeof(mi_flush));
    mi_flush.dw0.type = CMD_MI;
    mi_flush.dw0.opcode = OPC_MI_FLUSH;
    mi_flush.dw0.map_cache_invalidate = map;
    mi_flush.dw0.render_cache_flush_inhibit = render;

    intelBatchbufferData(&mi_flush, sizeof(mi_flush), 0);
}

static void i915_mc_load_indirect_render_init(XvMCContext *context)
{
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)context->privData;
    sis_state *sis;
    msb_state *msb;
    struct i915_3dstate_load_indirect *load_indirect;
    int mem_select;

    mc_render_load_indirect_size = sizeof(*load_indirect) + sizeof(*sis)
					+ sizeof(*msb);
    mc_render_load_indirect = calloc(1, mc_render_load_indirect_size);

    load_indirect = (struct i915_3dstate_load_indirect *)mc_render_load_indirect;
    load_indirect->dw0.type = CMD_3D;
    load_indirect->dw0.opcode = OPC_3DSTATE_LOAD_INDIRECT;
    load_indirect->dw0.block_mask = BLOCK_SIS | BLOCK_MSB;
    load_indirect->dw0.length = (mc_render_load_indirect_size >> 2) - 2;

    if (pI915XvMC->deviceID == PCI_CHIP_I915_G ||
        pI915XvMC->deviceID == PCI_CHIP_I915_GM)
        mem_select = 0;
    else
	mem_select = 1;

    load_indirect->dw0.mem_select = mem_select;

    /* Static Indirect state buffer (dest buffer info) */
    sis = (sis_state *)(++load_indirect);
    sis->dw0.valid = 1;
    sis->dw0.force = 1;
    sis->dw1.length = 16; /* 4 * 3 + 2 + 3 - 1 */

    if (mem_select)
	sis->dw0.buffer_address = (pI915XvMC->sis.offset >> 2);
    else
	sis->dw0.buffer_address = (pI915XvMC->sis.bus_addr >> 2);

    /* Map state buffer (reference buffer info) */
    msb = (msb_state *)(++sis);
    msb->dw0.valid = 1;
    msb->dw0.force = 1;
    msb->dw1.length = 23; /* 3 * 8 - 1 */

    if (mem_select)
	msb->dw0.buffer_address = (pI915XvMC->msb.offset >> 2);
    else
	msb->dw0.buffer_address = (pI915XvMC->msb.bus_addr >> 2);
}

static void i915_mc_load_indirect_render_emit(void)
{
    i915_emit_batch(mc_render_load_indirect, mc_render_load_indirect_size, 0);
}

static void i915_mc_mpeg_set_origin(XvMCContext *context, XvMCMacroBlock *mb)
{
    struct i915_3dmpeg_set_origin set_origin;

    /* 3DMPEG_SET_ORIGIN */
    memset(&set_origin, 0, sizeof(set_origin));
    set_origin.dw0.type = CMD_3D;
    set_origin.dw0.opcode = OPC_3DMPEG_SET_ORIGIN;
    set_origin.dw0.length = 0;
    set_origin.dw1.h_origin = mb->x;
    set_origin.dw1.v_origin = mb->y;

    intelBatchbufferData(&set_origin, sizeof(set_origin), 0);
}

static void i915_mc_mpeg_macroblock_ipicture(XvMCContext *context, XvMCMacroBlock *mb)
{
    struct i915_3dmpeg_macroblock_ipicture macroblock_ipicture;

    /* 3DMPEG_MACROBLOCK_IPICTURE */
    memset(&macroblock_ipicture, 0, sizeof(macroblock_ipicture));
    macroblock_ipicture.dw0.type = CMD_3D;
    macroblock_ipicture.dw0.opcode = OPC_3DMPEG_MACROBLOCK_IPICTURE;
    macroblock_ipicture.dw0.dct_type = (mb->dct_type == XVMC_DCT_TYPE_FIELD);

    intelBatchbufferData(&macroblock_ipicture, sizeof(macroblock_ipicture), 0);
}

#if 0
static void i915_mc_mpeg_macroblock_0mv(XvMCContext *context, XvMCMacroBlock *mb)
{
    struct i915_3dmpeg_macroblock_0mv macroblock_0mv;

    /* 3DMPEG_MACROBLOCK(0mv) */
    memset(&macroblock_0mv, 0, sizeof(macroblock_0mv));
    macroblock_0mv.header.dw0.type = CMD_3D;
    macroblock_0mv.header.dw0.opcode = OPC_3DMPEG_MACROBLOCK;
    macroblock_0mv.header.dw0.length = 0;
    macroblock_0mv.header.dw1.mb_intra = 1;     /* should be 1 */
    macroblock_0mv.header.dw1.forward = 0;      /* should be 0 */
    macroblock_0mv.header.dw1.backward = 0;     /* should be 0 */
    macroblock_0mv.header.dw1.h263_4mv = 0;     /* should be 0 */
    macroblock_0mv.header.dw1.dct_type = (mb->dct_type == XVMC_DCT_TYPE_FIELD);

/*
    if (!mb->coded_block_pattern)
        macroblock_0mv.header.dw1.dct_type = XVMC_DCT_TYPE_FRAME;
*/

    macroblock_0mv.header.dw1.motion_type = 0; // (mb->motion_type & 0x3);
    macroblock_0mv.header.dw1.vertical_field_select = 0; // mb->motion_vertical_field_select & 0xf;
    macroblock_0mv.header.dw1.coded_block_pattern = mb->coded_block_pattern;
    macroblock_0mv.header.dw1.skipped_macroblocks = 0;

    intelBatchbufferData(&macroblock_0mv, sizeof(macroblock_0mv), 0);
}
#endif

static void i915_mc_mpeg_macroblock_1fbmv(XvMCContext *context, XvMCMacroBlock *mb)
{
    struct i915_3dmpeg_macroblock_1fbmv macroblock_1fbmv;
    vector_t mv0[2];

    /* 3DMPEG_MACROBLOCK(1fbmv) */
    memset(&macroblock_1fbmv, 0, sizeof(macroblock_1fbmv));
    macroblock_1fbmv.header.dw0.type = CMD_3D;
    macroblock_1fbmv.header.dw0.opcode = OPC_3DMPEG_MACROBLOCK;
    macroblock_1fbmv.header.dw0.length = 2;
    macroblock_1fbmv.header.dw1.mb_intra = 0;   /* should be 0 */
    macroblock_1fbmv.header.dw1.forward = ((mb->macroblock_type & XVMC_MB_TYPE_MOTION_FORWARD) ? 1 : 0);
    macroblock_1fbmv.header.dw1.backward = ((mb->macroblock_type & XVMC_MB_TYPE_MOTION_BACKWARD) ? 1 : 0);
    macroblock_1fbmv.header.dw1.h263_4mv = 0;   /* should be 0 */
    macroblock_1fbmv.header.dw1.dct_type = (mb->dct_type == XVMC_DCT_TYPE_FIELD);

    if (!(mb->coded_block_pattern & 0x3f))
        macroblock_1fbmv.header.dw1.dct_type = XVMC_DCT_TYPE_FRAME;

    macroblock_1fbmv.header.dw1.motion_type = (mb->motion_type & 0x03);
    macroblock_1fbmv.header.dw1.vertical_field_select = (mb->motion_vertical_field_select & 0x0f);
    macroblock_1fbmv.header.dw1.coded_block_pattern = mb->coded_block_pattern;
    macroblock_1fbmv.header.dw1.skipped_macroblocks = 0;

    mv0[0].component[0] = mb->PMV[0][0][0];
    mv0[0].component[1] = mb->PMV[0][0][1];
    mv0[1].component[0] = mb->PMV[0][1][0];
    mv0[1].component[1] = mb->PMV[0][1][1];

    macroblock_1fbmv.dw2 = mv0[0].v;
    macroblock_1fbmv.dw3 = mv0[1].v;

    intelBatchbufferData(&macroblock_1fbmv, sizeof(macroblock_1fbmv), 0);
}

static void i915_mc_mpeg_macroblock_2fbmv(XvMCContext *context, XvMCMacroBlock *mb, unsigned int ps)
{
    struct i915_3dmpeg_macroblock_2fbmv macroblock_2fbmv;
    vector_t mv0[2];
    vector_t mv1[2];

    /* 3DMPEG_MACROBLOCK(2fbmv) */
    memset(&macroblock_2fbmv, 0, sizeof(macroblock_2fbmv));
    macroblock_2fbmv.header.dw0.type = CMD_3D;
    macroblock_2fbmv.header.dw0.opcode = OPC_3DMPEG_MACROBLOCK;
    macroblock_2fbmv.header.dw0.length = 4;
    macroblock_2fbmv.header.dw1.mb_intra = 0;   /* should be 0 */
    macroblock_2fbmv.header.dw1.forward = ((mb->macroblock_type & XVMC_MB_TYPE_MOTION_FORWARD) ? 1 : 0);
    macroblock_2fbmv.header.dw1.backward = ((mb->macroblock_type & XVMC_MB_TYPE_MOTION_BACKWARD) ? 1 : 0);
    macroblock_2fbmv.header.dw1.h263_4mv = 0;   /* should be 0 */
    macroblock_2fbmv.header.dw1.dct_type = (mb->dct_type == XVMC_DCT_TYPE_FIELD);

    if (!(mb->coded_block_pattern & 0x3f))
        macroblock_2fbmv.header.dw1.dct_type = XVMC_DCT_TYPE_FRAME;

    macroblock_2fbmv.header.dw1.motion_type = (mb->motion_type & 0x03);
    macroblock_2fbmv.header.dw1.vertical_field_select = (mb->motion_vertical_field_select & 0x0f);
    macroblock_2fbmv.header.dw1.coded_block_pattern = mb->coded_block_pattern;
    macroblock_2fbmv.header.dw1.skipped_macroblocks = 0;

    mv0[0].component[0] = mb->PMV[0][0][0];
    mv0[0].component[1] = mb->PMV[0][0][1];
    mv0[1].component[0] = mb->PMV[0][1][0];
    mv0[1].component[1] = mb->PMV[0][1][1];
    mv1[0].component[0] = mb->PMV[1][0][0];
    mv1[0].component[1] = mb->PMV[1][0][1];
    mv1[1].component[0] = mb->PMV[1][1][0];
    mv1[1].component[1] = mb->PMV[1][1][1];

    if ((ps & XVMC_FRAME_PICTURE) == XVMC_FRAME_PICTURE) {
        if ((mb->motion_type & 3) == XVMC_PREDICTION_FIELD) {
            mv0[0].component[1] = mb->PMV[0][0][1] >> 1;
            mv0[1].component[1] = mb->PMV[0][1][1] >> 1;
            mv1[0].component[1] = mb->PMV[1][0][1] >> 1;
            mv1[1].component[1] = mb->PMV[1][1][1] >> 1;
        } else if ((mb->motion_type & 3) == XVMC_PREDICTION_DUAL_PRIME) {
            mv0[0].component[1] = mb->PMV[0][0][1] >> 1;
            mv0[1].component[1] = mb->PMV[0][1][1] >> 1;  // MPEG2 MV[0][1] isn't used
            mv1[0].component[1] = mb->PMV[1][0][1] >> 1;
            mv1[1].component[1] = mb->PMV[1][1][1] >> 1;
        }
    }

    macroblock_2fbmv.dw2 = mv0[0].v;
    macroblock_2fbmv.dw3 = mv0[1].v;
    macroblock_2fbmv.dw4 = mv1[0].v;
    macroblock_2fbmv.dw5 = mv1[1].v;

    intelBatchbufferData(&macroblock_2fbmv, sizeof(macroblock_2fbmv), 0);
}

#if 0
static void i915_mc_invalidate_subcontext_buffers(XvMCContext *context, unsigned int mask)
{
    struct i915_3dstate_load_indirect *load_indirect = NULL;
    sis_state *sis = NULL;
    dis_state *dis = NULL;
    ssb_state *ssb = NULL;
    msb_state *msb = NULL;
    psp_state *psp = NULL;
    psc_state *psc = NULL;
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)context->privData;
    unsigned int size;
    void *base = NULL, *ptr = NULL;

    size = sizeof(*load_indirect);
    if (mask & BLOCK_SIS)
        size += sizeof(*sis);
    if (mask & BLOCK_DIS)
        size += sizeof(*dis);
    if (mask & BLOCK_SSB)
        size += sizeof(*ssb);
    if (mask & BLOCK_MSB)
        size += sizeof(*msb);
    if (mask & BLOCK_PSP)
        size += sizeof(*psp);
    if (mask & BLOCK_PSC)
        size += sizeof(*psc);

    if (size == sizeof(*load_indirect)) {
        XVMC_ERR("There must be at least one bit set\n");
        return;
    }

    /* 3DSTATE_LOAD_INDIRECT */
    base = calloc(1, size);
    load_indirect = (struct i915_3dstate_load_indirect *)base;
    load_indirect->dw0.type = CMD_3D;
    load_indirect->dw0.opcode = OPC_3DSTATE_LOAD_INDIRECT;

    if (pI915XvMC->deviceID == PCI_CHIP_I915_G ||
        pI915XvMC->deviceID == PCI_CHIP_I915_GM ||
        pI915XvMC->deviceID == PCI_CHIP_I945_G ||
        pI915XvMC->deviceID == PCI_CHIP_I945_GM)
        load_indirect->dw0.mem_select = 0;
    else
        load_indirect->dw0.mem_select = 1;

    load_indirect->dw0.block_mask = mask;
    load_indirect->dw0.length = (size >> 2) - 2;
    ptr = ++load_indirect;

    /* SIS */
    if (mask & BLOCK_SIS) {
        sis = (sis_state *)ptr;
        sis->dw0.valid = 0;
        sis->dw0.buffer_address = 0;
        sis->dw1.length = 0;
        ptr = ++sis;
    }

    /* DIS */
    if (mask & BLOCK_DIS) {
        dis = (dis_state *)ptr;
        dis->dw0.valid = 0;
        dis->dw0.reset = 0;
        dis->dw0.buffer_address = 0;
        ptr = ++dis;
    }

    /* SSB */
    if (mask & BLOCK_SSB) {
        ssb = (ssb_state *)ptr;
        ssb->dw0.valid = 0;
        ssb->dw0.buffer_address = 0;
        ssb->dw1.length = 0;
        ptr = ++ssb;
    }

    /* MSB */
    if (mask & BLOCK_MSB) {
        msb = (msb_state *)ptr;
        msb->dw0.valid = 0;
        msb->dw0.buffer_address = 0;
        msb->dw1.length = 0;
        ptr = ++msb;
    }

    /* PSP */
    if (mask & BLOCK_PSP) {
        psp = (psp_state *)ptr;
        psp->dw0.valid = 0;
        psp->dw0.buffer_address = 0;
        psp->dw1.length = 0;
        ptr = ++psp;
    }

    /* PSC */
    if (mask & BLOCK_PSC) {
        psc = (psc_state *)ptr;
        psc->dw0.valid = 0;
        psc->dw0.buffer_address = 0;
        psc->dw1.length = 0;
        ptr = ++psc;
    }

    intelBatchbufferData(base, size, 0);
    free(base);
}
#endif

static int i915_xvmc_map_buffers(i915XvMCContext *pI915XvMC)
{
    if (drmMap(xvmc_driver->fd,
               pI915XvMC->sis.handle,
               pI915XvMC->sis.size,
               (drmAddress *)&pI915XvMC->sis.map) != 0) {
        return -1;
    }

    if (drmMap(xvmc_driver->fd,
               pI915XvMC->ssb.handle,
               pI915XvMC->ssb.size,
               (drmAddress *)&pI915XvMC->ssb.map) != 0) {
        return -1;
    }

    if (drmMap(xvmc_driver->fd,
               pI915XvMC->msb.handle,
               pI915XvMC->msb.size,
               (drmAddress *)&pI915XvMC->msb.map) != 0) {
        return -1;
    }

    if (drmMap(xvmc_driver->fd,
               pI915XvMC->psp.handle,
               pI915XvMC->psp.size,
               (drmAddress *)&pI915XvMC->psp.map) != 0) {
        return -1;
    }

    if (drmMap(xvmc_driver->fd,
               pI915XvMC->psc.handle,
               pI915XvMC->psc.size,
               (drmAddress *)&pI915XvMC->psc.map) != 0) {
        return -1;
    }

    if (drmMap(xvmc_driver->fd,
               pI915XvMC->corrdata.handle,
               pI915XvMC->corrdata.size,
               (drmAddress *)&pI915XvMC->corrdata.map) != 0) {
        return -1;
    }

    return 0;
}

static void i915_xvmc_unmap_buffers(i915XvMCContext *pI915XvMC)
{
    if (pI915XvMC->sis.map) {
        drmUnmap(pI915XvMC->sis.map, pI915XvMC->sis.size);
        pI915XvMC->sis.map = NULL;
    }

    if (pI915XvMC->ssb.map) {
        drmUnmap(pI915XvMC->ssb.map, pI915XvMC->ssb.size);
        pI915XvMC->ssb.map = NULL;
    }

    if (pI915XvMC->msb.map) {
        drmUnmap(pI915XvMC->msb.map, pI915XvMC->msb.size);
        pI915XvMC->msb.map = NULL;
    }

    if (pI915XvMC->psp.map) {
        drmUnmap(pI915XvMC->psp.map, pI915XvMC->psp.size);
        pI915XvMC->psp.map = NULL;
    }

    if (pI915XvMC->psc.map) {
        drmUnmap(pI915XvMC->psc.map, pI915XvMC->psc.size);
        pI915XvMC->psc.map = NULL;
    }

    if (pI915XvMC->corrdata.map) {
        drmUnmap(pI915XvMC->corrdata.map, pI915XvMC->corrdata.size);
        pI915XvMC->corrdata.map = NULL;
    }
}

#if 0
/*
 * Video post processing
 */
static void i915_yuv2rgb_map_state_buffer(XvMCSurface *target_surface)
{
    struct i915_3dstate_map_state *map_state;
    struct texture_map *tm;
    i915XvMCSurface *privTarget = NULL;
    i915XvMCContext *pI915XvMC = NULL;
    unsigned int w = target_surface->width, h = target_surface->height;

    privTarget = (i915XvMCSurface *)target_surface->privData;
    pI915XvMC = (i915XvMCContext *)privTarget->privContext;
    /* 3DSATE_MAP_STATE */
    map_state = (struct i915_3dstate_map_state *)pI915XvMC->msb.map;
    memset(map_state, 0, sizeof(*map_state));
    map_state->dw0.type = CMD_3D;
    map_state->dw0.opcode = OPC_3DSTATE_MAP_STATE;
    map_state->dw0.retain = 0;
    map_state->dw0.length = 9;
    map_state->dw1.map_mask = MAP_MAP0 | MAP_MAP1 | MAP_MAP2;

    /* texture map 0: V Plane */
    tm = (struct texture_map *)(++map_state);
    memset(tm, 0, sizeof(*tm));
    tm->tm0.v_ls_offset = 0;
    tm->tm0.v_ls = 0;
    tm->tm0.base_address = VOFFSET(privTarget);
    tm->tm1.tile_walk = TILEWALK_XMAJOR;
    tm->tm1.tiled_surface = 0;
    tm->tm1.utilize_fence_regs = 1;
    tm->tm1.texel_fmt = 0;
    tm->tm1.surface_fmt = 1;
    tm->tm1.width = (w >> 1) - 1;
    tm->tm1.height = (h >> 1) - 1;
    tm->tm2.depth = 0;
    tm->tm2.max_lod = 0;
    tm->tm2.cube_face = 0;
    tm->tm2.pitch = (privTarget->uvStride >> 2) - 1;    /* in DWords - 1 */

    /* texture map 1: Y Plane */
    ++tm;
    memset(tm, 0, sizeof(*tm));
    tm->tm0.v_ls_offset = 0;
    tm->tm0.v_ls = 0;
    tm->tm0.base_address = YOFFSET(privTarget);
    tm->tm1.tile_walk = TILEWALK_XMAJOR;
    tm->tm1.tiled_surface = 0;
    tm->tm1.utilize_fence_regs = 1;
    tm->tm1.texel_fmt = 0;
    tm->tm1.surface_fmt = 1;
    tm->tm1.width = w - 1;
    tm->tm1.height = h - 1;
    tm->tm2.depth = 0;
    tm->tm2.max_lod = 0;
    tm->tm2.cube_face = 0;
    tm->tm2.pitch = (privTarget->yStride >> 2) - 1;     /* in DWords - 1 */

    /* texture map 2: U Plane */
    ++tm;
    memset(tm, 0, sizeof(*tm));
    tm->tm0.v_ls_offset = 0;
    tm->tm0.v_ls = 0;
    tm->tm0.base_address = UOFFSET(privTarget);
    tm->tm1.tile_walk = TILEWALK_XMAJOR;
    tm->tm1.tiled_surface = 0;
    tm->tm1.utilize_fence_regs = 1;
    tm->tm1.texel_fmt = 0;
    tm->tm1.surface_fmt = 1;
    tm->tm1.width = (w >> 1) - 1;
    tm->tm1.height = (h >> 1) - 1;
    tm->tm2.depth = 0;
    tm->tm2.max_lod = 0;
    tm->tm2.cube_face = 0;
    tm->tm2.pitch = (privTarget->uvStride >> 2) - 1;    /* in DWords - 1 */
}
#endif

#if 0
static void i915_yuv2rgb_sampler_state_buffer(XvMCSurface *surface)
{
    struct i915_3dstate_sampler_state *sampler_state;
    struct texture_sampler *ts;
    i915XvMCSurface *privSurface = (i915XvMCSurface *)surface->privData;
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)privSurface->privContext;

    /* 3DSATE_SAMPLER_STATE */
    sampler_state = (struct i915_3dstate_sampler_state *)pI915XvMC->ssb.map;
    memset(sampler_state, 0, sizeof(*sampler_state));
    sampler_state->dw0.type = CMD_3D;
    sampler_state->dw0.opcode = OPC_3DSTATE_SAMPLER_STATE;
    sampler_state->dw0.length = 9;
    sampler_state->dw1.sampler_masker = SAMPLER_SAMPLER0 | SAMPLER_SAMPLER1 | SAMPLER_SAMPLER2;

    /* Sampler 0 */
    ts = (struct texture_sampler *)(++sampler_state);
    memset(ts, 0, sizeof(*ts));
    ts->ts0.reverse_gamma = 0;
    ts->ts0.planar2packet = 1;
    ts->ts0.color_conversion = 1;
    ts->ts0.chromakey_index = 0;
    ts->ts0.base_level = 0;
    ts->ts0.mip_filter = MIPFILTER_NONE;        /* NONE */
    ts->ts0.mag_filter = MAPFILTER_LINEAR;      /* LINEAR */
    ts->ts0.min_filter = MAPFILTER_LINEAR;      /* LINEAR */
    ts->ts0.lod_bias = 0;
    ts->ts0.shadow_enable = 0;
    ts->ts0.max_anisotropy = ANISORATIO_2;
    ts->ts0.shadow_function = PREFILTEROP_ALWAYS;
    ts->ts1.min_lod = 0;        /* Maximum Mip Level */
    ts->ts1.kill_pixel = 0;
    ts->ts1.keyed_texture_filter = 0;
    ts->ts1.chromakey_enable = 0;
    ts->ts1.tcx_control = TEXCOORDMODE_CLAMP;
    ts->ts1.tcy_control = TEXCOORDMODE_CLAMP;
    ts->ts1.tcz_control = TEXCOORDMODE_CLAMP;
    ts->ts1.normalized_coor = 0;
    ts->ts1.map_index = 0;
    ts->ts1.east_deinterlacer = 0;
    ts->ts2.default_color = 0;

    /* Sampler 1 */
    ++ts;
    memset(ts, 0, sizeof(*ts));
    ts->ts0.reverse_gamma = 0;
    ts->ts0.planar2packet = 1;
    ts->ts0.color_conversion = 1;
    ts->ts0.chromakey_index = 0;
    ts->ts0.base_level = 0;
    ts->ts0.mip_filter = MIPFILTER_NONE;        /* NONE */
    ts->ts0.mag_filter = MAPFILTER_LINEAR;      /* LINEAR */
    ts->ts0.min_filter = MAPFILTER_LINEAR;      /* LINEAR */
    ts->ts0.lod_bias = 0;
    ts->ts0.shadow_enable = 0;
    ts->ts0.max_anisotropy = ANISORATIO_2;
    ts->ts0.shadow_function = PREFILTEROP_ALWAYS;
    ts->ts1.min_lod = 0;        /* Maximum Mip Level */
    ts->ts1.kill_pixel = 0;
    ts->ts1.keyed_texture_filter = 0;
    ts->ts1.chromakey_enable = 0;
    ts->ts1.tcx_control = TEXCOORDMODE_CLAMP;
    ts->ts1.tcy_control = TEXCOORDMODE_CLAMP;
    ts->ts1.tcz_control = TEXCOORDMODE_CLAMP;
    ts->ts1.normalized_coor = 0;
    ts->ts1.map_index = 1;
    ts->ts1.east_deinterlacer = 0;
    ts->ts2.default_color = 0;

    /* Sampler 2 */
    ++ts;
    memset(ts, 0, sizeof(*ts));
    ts->ts0.reverse_gamma = 0;
    ts->ts0.planar2packet = 1;
    ts->ts0.color_conversion = 1;
    ts->ts0.chromakey_index = 0;
    ts->ts0.base_level = 0;
    ts->ts0.mip_filter = MIPFILTER_NONE;        /* NONE */
    ts->ts0.mag_filter = MAPFILTER_LINEAR;      /* LINEAR */
    ts->ts0.min_filter = MAPFILTER_LINEAR;      /* LINEAR */
    ts->ts0.lod_bias = 0;
    ts->ts0.shadow_enable = 0;
    ts->ts0.max_anisotropy = ANISORATIO_2;
    ts->ts0.shadow_function = PREFILTEROP_ALWAYS;
    ts->ts1.min_lod = 0;        /* Maximum Mip Level */
    ts->ts1.kill_pixel = 0;
    ts->ts1.keyed_texture_filter = 0;
    ts->ts1.chromakey_enable = 0;
    ts->ts1.tcx_control = TEXCOORDMODE_CLAMP;
    ts->ts1.tcy_control = TEXCOORDMODE_CLAMP;
    ts->ts1.tcz_control = TEXCOORDMODE_CLAMP;
    ts->ts1.normalized_coor = 0;
    ts->ts1.map_index = 2;
    ts->ts1.east_deinterlacer = 0;
    ts->ts2.default_color = 0;
}
#endif

#if 0
static void i915_yuv2rgb_static_indirect_state_buffer(XvMCSurface *surface,
                                                      unsigned int dstaddr,
                                                      int dstpitch)
{
    struct i915_3dstate_buffer_info *buffer_info;
    struct i915_3dstate_dest_buffer_variables *dest_buffer_variables;
    i915XvMCSurface *privSurface = (i915XvMCSurface *)surface->privData;
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)privSurface->privContext;

    /* 3DSTATE_BUFFER_INFO */
    buffer_info = (struct i915_3dstate_buffer_info *)pI915XvMC->sis.map;
    memset(buffer_info, 0, sizeof(*buffer_info));
    buffer_info->dw0.type = CMD_3D;
    buffer_info->dw0.opcode = OPC_3DSTATE_BUFFER_INFO;
    buffer_info->dw0.length = 1;
    buffer_info->dw1.aux_id = 0;
    buffer_info->dw1.buffer_id = BUFFERID_COLOR_BACK;
    buffer_info->dw1.fence_regs = 1;
    buffer_info->dw1.tiled_surface = 0;   /* linear */
    buffer_info->dw1.walk = TILEWALK_XMAJOR;
    buffer_info->dw1.pitch = dstpitch;
    buffer_info->dw2.base_address = dstaddr;

    /* 3DSTATE_DEST_BUFFER_VARIABLES */
    dest_buffer_variables = (struct i915_3dstate_dest_buffer_variables *)(++buffer_info);
    memset(dest_buffer_variables, 0, sizeof(*dest_buffer_variables));
    dest_buffer_variables->dw0.type = CMD_3D;
    dest_buffer_variables->dw0.opcode = OPC_3DSTATE_DEST_BUFFER_VARIABLES;
    dest_buffer_variables->dw0.length = 0;
    dest_buffer_variables->dw1.dest_v_bias = 8; /* FIXME 0x1000 .5 ??? */
    dest_buffer_variables->dw1.dest_h_bias = 8;
    dest_buffer_variables->dw1.color_fmt = COLORBUFFER_A8R8G8B8;  /* FIXME */
}
#endif

#if 0
static void i915_yuv2rgb_pixel_shader_program_buffer(XvMCSurface *surface)
{
    struct i915_3dstate_pixel_shader_program *pixel_shader_program;
    i915XvMCSurface *privSurface = (i915XvMCSurface *)surface->privData;
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)privSurface->privContext;
    unsigned int *inst;
    unsigned int dest, src0, src1;

    /* Shader 0 */
    pixel_shader_program = (struct i915_3dstate_pixel_shader_program *)pI915XvMC->psp.map;
    memset(pixel_shader_program, 0, sizeof(*pixel_shader_program));
    pixel_shader_program->dw0.type = CMD_3D;
    pixel_shader_program->dw0.opcode = OPC_3DSTATE_PIXEL_SHADER_PROGRAM;
    pixel_shader_program->dw0.retain = 0;
    pixel_shader_program->dw0.length = 23;
    /* dcl      t0.xy */
    inst = (unsigned int*)(++pixel_shader_program);
    i915_inst_decl(inst, REG_TYPE_T, T_TEX0, D0_CHANNEL_XY);
    /* dcl         t1.xy */
    inst += 3;
    i915_inst_decl(inst, REG_TYPE_T, T_TEX1, D0_CHANNEL_XY);
    /* dcl_2D   s0 */
    inst += 3;
    i915_inst_decl(inst, REG_TYPE_S, 0, D0_SAMPLE_TYPE_2D);
    /* dcl_2D   s1 */
    inst += 3;
    i915_inst_decl(inst, REG_TYPE_S, 1, D0_SAMPLE_TYPE_2D);
    /* dcl_2D   s2 */
    inst += 3;
    i915_inst_decl(inst, REG_TYPE_S, 2, D0_SAMPLE_TYPE_2D);
    /* texld    r0 t1 s0 */
    inst += 3;
    dest = UREG(REG_TYPE_R, 0);
    src0 = UREG(REG_TYPE_T, 1); /* COORD */
    src1 = UREG(REG_TYPE_S, 0); /* SAMPLER */
    i915_inst_texld(inst, T0_TEXLD, dest, src0, src1);
    /* texld    r0 t0 s1 */
    inst += 3;
    dest = UREG(REG_TYPE_R, 0);
    src0 = UREG(REG_TYPE_T, 0); /* COORD */
    src1 = UREG(REG_TYPE_S, 1); /* SAMPLER */
    i915_inst_texld(inst, T0_TEXLD, dest, src0, src1);
    /* texld    oC t1 s2 */
    inst += 3;
    dest = UREG(REG_TYPE_OC, 0);
    src0 = UREG(REG_TYPE_T, 1); /* COORD */
    src1 = UREG(REG_TYPE_S, 2); /* SAMPLER */
    i915_inst_texld(inst, T0_TEXLD, dest, src0, src1);
}
#endif

#if 0
static void i915_yuv2rgb_proc(XvMCSurface *surface)
{
    i915XvMCSurface *privSurface = (i915XvMCSurface *)surface->privData;
    i915XvMCContext *pI915XvMC = (i915XvMCContext *)privSurface->privContext;
    struct i915_3dstate_load_state_immediate_1 *load_state_immediate_1 = NULL;
    struct s2_dword *s2 = NULL;
    struct s3_dword *s3 = NULL;
    struct s4_dword *s4 = NULL;
    struct s5_dword *s5 = NULL;
    struct s6_dword *s6 = NULL;
    struct s7_dword *s7 = NULL;
    struct i915_3dstate_scissor_rectangle scissor_rectangle;
    struct i915_3dstate_load_indirect *load_indirect = NULL;
    sis_state *sis = NULL;
    ssb_state *ssb = NULL;
    msb_state *msb = NULL;
    psp_state *psp = NULL;
    struct i915_3dprimitive *_3dprimitive = NULL;
    struct vertex_data *vd = NULL;
    unsigned int size;
    void *base = NULL;

    /* 3DSTATE_LOAD_STATE_IMMEDIATE_1 */
    size = sizeof(*load_state_immediate_1) + sizeof(*s2) + sizeof(*s3) +
        sizeof(*s4) + sizeof(*s5) + sizeof(*s6) + sizeof(*s7);
    base = calloc(1, size);
    load_state_immediate_1 = (struct i915_3dstate_load_state_immediate_1 *)base;
    load_state_immediate_1->dw0.type = CMD_3D;
    load_state_immediate_1->dw0.opcode = OPC_3DSTATE_LOAD_STATE_IMMEDIATE_1;
    load_state_immediate_1->dw0.load_s2 = 1;
    load_state_immediate_1->dw0.load_s3 = 1;
    load_state_immediate_1->dw0.load_s4 = 1;
    load_state_immediate_1->dw0.load_s5 = 1;
    load_state_immediate_1->dw0.load_s6 = 1;
    load_state_immediate_1->dw0.load_s7 = 1;
    load_state_immediate_1->dw0.length = 5;

    s2 = (struct s2_dword *)(++load_state_immediate_1);
    s2->set0_texcoord_fmt = TEXCOORDFMT_2FP;
    s2->set1_texcoord_fmt = TEXCOORDFMT_2FP;
    s2->set2_texcoord_fmt = TEXCOORDFMT_NOT_PRESENT;
    s2->set3_texcoord_fmt = TEXCOORDFMT_NOT_PRESENT;
    s2->set4_texcoord_fmt = TEXCOORDFMT_NOT_PRESENT;
    s2->set5_texcoord_fmt = TEXCOORDFMT_NOT_PRESENT;
    s2->set6_texcoord_fmt = TEXCOORDFMT_NOT_PRESENT;
    s2->set7_texcoord_fmt = TEXCOORDFMT_NOT_PRESENT;

    s3 = (struct s3_dword *)(++s2);
    s4 = (struct s4_dword *)(++s3);
    s4->position_mask = VERTEXHAS_XY;
    s4->cull_mode = CULLMODE_NONE;
    s4->color_shade_mode = SHADEMODE_FLAT;
    s4->specular_shade_mode = SHADEMODE_FLAT;
    s4->fog_shade_mode = SHADEMODE_FLAT;
    s4->alpha_shade_mode = SHADEMODE_FLAT;
    s4->line_width = 0x2;     /* FIXME: 1.0??? */
    s4->point_width = 0x1;

    s5 = (struct s5_dword *)(++s4);
    s6 = (struct s6_dword *)(++s5);
    s6->src_blend_factor = 1;
    s6->dest_blend_factor = 1;
    s6->color_buffer_write = 1;

    s7 = (struct s7_dword *)(++s6);
    intelBatchbufferData(base, size, 0);
    free(base);

    /* 3DSTATE_3DSTATE_SCISSOR_RECTANGLE */
    scissor_rectangle.dw0.type = CMD_3D;
    scissor_rectangle.dw0.opcode = OPC_3DSTATE_SCISSOR_RECTANGLE;
    scissor_rectangle.dw0.length = 1;
    scissor_rectangle.dw1.min_x = 0;
    scissor_rectangle.dw1.min_y = 0;
    scissor_rectangle.dw2.max_x = 2047;
    scissor_rectangle.dw2.max_y = 2047;
    intelBatchbufferData(&scissor_rectangle, sizeof(scissor_rectangle), 0);

    /* 3DSTATE_LOAD_INDIRECT */
    size = sizeof(*load_indirect) + sizeof(*sis) + sizeof(*ssb) + sizeof(*msb) + sizeof(*psp);
    base = calloc(1, size);
    load_indirect = (struct i915_3dstate_load_indirect *)base;
    load_indirect->dw0.type = CMD_3D;
    load_indirect->dw0.opcode = OPC_3DSTATE_LOAD_INDIRECT;
    load_indirect->dw0.mem_select = 1;  /* Bearlake only */
    load_indirect->dw0.block_mask = BLOCK_SIS | BLOCK_SSB | BLOCK_MSB | BLOCK_PSP;
    load_indirect->dw0.length = 7;

    /* SIS */
    sis = (sis_state *)(++load_indirect);
    sis->dw0.valid = 1;
    sis->dw0.buffer_address = pI915XvMC->sis.offset;
    sis->dw1.length = ((sizeof(struct i915_3dstate_buffer_info) +
                        sizeof(struct i915_3dstate_dest_buffer_variables)) >> 2) - 1;

    /* SSB */
    ssb = (ssb_state *)(++sis);
    ssb->dw0.valid = 1;
    ssb->dw0.buffer_address = pI915XvMC->ssb.offset;
    ssb->dw1.length = ((sizeof(struct i915_3dstate_sampler_state) +
                        sizeof(struct texture_sampler) * 3) >> 2) - 1;

    /* MSB */
    msb = (msb_state *)(++ssb);
    msb->dw0.valid = 1;
    msb->dw0.buffer_address = pI915XvMC->msb.offset;
    msb->dw1.length = ((sizeof(struct i915_3dstate_map_state) +
                        sizeof(struct texture_map) * 3) >> 2) - 1;

    /* PSP */
    psp = (psp_state *)(++msb);
    psp->dw0.valid = 1;
    psp->dw0.buffer_address = pI915XvMC->psp.offset;
    psp->dw1.length = ((sizeof(struct i915_3dstate_pixel_shader_program) +
                        sizeof(union shader_inst)) >> 2) - 1;

    intelBatchbufferData(base, size, 0);
    free(base);

    /* 3DPRIMITIVE */
    size = sizeof(*_3dprimitive) + sizeof(*vd) * 3;
    base = calloc(1, size);
    _3dprimitive = (struct i915_3dprimitive *)base;
    _3dprimitive->dw0.inline_prim.type = CMD_3D;
    _3dprimitive->dw0.inline_prim.opcode = OPC_3DPRIMITIVE;
    _3dprimitive->dw0.inline_prim.vertex_location = VERTEX_INLINE;
    _3dprimitive->dw0.inline_prim.prim = PRIM_RECTLIST;
    _3dprimitive->dw0.inline_prim.length = size - 2;

    vd = (struct vertex_data *)(++_3dprimitive);
    vd->x = 0;          /* FIXME!!! */
    vd->x = 0;          /* FIXME */
    vd->tc0.tcx = 0;
    vd->tc0.tcy = 0;
    vd->tc1.tcx = 0;
    vd->tc1.tcy = 0;

    ++vd;
    vd->x = 0;          /* FIXME!!! */
    vd->x = 0;          /* FIXME */
    vd->tc0.tcx = 0;
    vd->tc0.tcy = 0;
    vd->tc1.tcx = 0;
    vd->tc1.tcy = 0;

    ++vd;
    vd->x = 0;          /* FIXME!!! */
    vd->x = 0;          /* FIXME */
    vd->tc0.tcx = 0;
    vd->tc0.tcy = 0;
    vd->tc1.tcx = 0;
    vd->tc1.tcy = 0;

    intelBatchbufferData(base, size, 0);
    free(base);
}
#endif

/*
 * Function: i915_release_resource
 */
static void i915_release_resource(Display *display, XvMCContext *context)
{
    i915XvMCContext *pI915XvMC;

    if (!(pI915XvMC = context->privData))
        return;

    pI915XvMC->ref--;
    i915_xvmc_unmap_buffers(pI915XvMC);

    free(pI915XvMC);
    context->privData = NULL;
}

static Status i915_xvmc_mc_create_context(Display *display, XvMCContext *context,
	int priv_count, CARD32 *priv_data)
{
    i915XvMCContext *pI915XvMC = NULL;
    I915XvMCCreateContextRec *tmpComm = NULL;

    XVMC_DBG("%s\n", __FUNCTION__);

    if (priv_count != (sizeof(I915XvMCCreateContextRec) >> 2)) {
        XVMC_ERR("_xvmc_create_context() returned incorrect data size!");
        XVMC_INFO("\tExpected %d, got %d",
               (int)(sizeof(I915XvMCCreateContextRec) >> 2),priv_count);
        _xvmc_destroy_context(display, context);
        XFree(priv_data);
        context->privData = NULL;
        return BadValue;
    }

    context->privData = (void *)calloc(1, sizeof(i915XvMCContext));
    if (!context->privData) {
        XVMC_ERR("Unable to allocate resources for XvMC context.");
        return BadAlloc;
    }
    pI915XvMC = (i915XvMCContext *)context->privData;

    tmpComm = (I915XvMCCreateContextRec *)priv_data;
    pI915XvMC->ctxno = tmpComm->ctxno;
    pI915XvMC->deviceID = tmpComm->deviceID;
    pI915XvMC->sis.handle = tmpComm->sis.handle;
    pI915XvMC->sis.offset = tmpComm->sis.offset;
    pI915XvMC->sis.size = tmpComm->sis.size;
    pI915XvMC->ssb.handle = tmpComm->ssb.handle;
    pI915XvMC->ssb.offset = tmpComm->ssb.offset;
    pI915XvMC->ssb.size = tmpComm->ssb.size;
    pI915XvMC->msb.handle = tmpComm->msb.handle;
    pI915XvMC->msb.offset = tmpComm->msb.offset;
    pI915XvMC->msb.size = tmpComm->msb.size;
    pI915XvMC->psp.handle = tmpComm->psp.handle;
    pI915XvMC->psp.offset = tmpComm->psp.offset;
    pI915XvMC->psp.size = tmpComm->psp.size;
    pI915XvMC->psc.handle = tmpComm->psc.handle;
    pI915XvMC->psc.offset = tmpComm->psc.offset;
    pI915XvMC->psc.size = tmpComm->psc.size;

    if (pI915XvMC->deviceID == PCI_CHIP_I915_G ||
        pI915XvMC->deviceID == PCI_CHIP_I915_GM) {
        pI915XvMC->sis.bus_addr = tmpComm->sis.bus_addr;
        pI915XvMC->ssb.bus_addr = tmpComm->ssb.bus_addr;
        pI915XvMC->msb.bus_addr = tmpComm->msb.bus_addr;
        pI915XvMC->psp.bus_addr = tmpComm->psp.bus_addr;
        pI915XvMC->psc.bus_addr = tmpComm->psc.bus_addr;
    }

    pI915XvMC->corrdata.handle = tmpComm->corrdata.handle;
    pI915XvMC->corrdata.offset = tmpComm->corrdata.offset;
    pI915XvMC->corrdata.size = tmpComm->corrdata.size;

    /* Must free the private data we were passed from X */
    XFree(priv_data);
    priv_data = NULL;

    if (i915_xvmc_map_buffers(pI915XvMC)) {
        i915_xvmc_unmap_buffers(pI915XvMC);
        free(pI915XvMC);
        context->privData = NULL;
        return BadAlloc;
    }

    /* Initialize private context values */
    pI915XvMC->yStride = STRIDE(context->width);
    pI915XvMC->uvStride = STRIDE(context->width >> 1);
    pI915XvMC->haveXv = 0;
    pI915XvMC->dual_prime = 0;
    pI915XvMC->last_flip = 0;
    pI915XvMC->port = context->port;
    pI915XvMC->ref = 1;

    /* pre-init state buffers */
    i915_mc_one_time_context_init(context);
    i915_mc_one_time_state_init(context);

    i915_mc_static_indirect_state_init(context);

    i915_mc_map_state_init(context);

    i915_mc_load_indirect_render_init(context);
    return Success;
}

static int i915_xvmc_mc_destroy_context(Display *display, XvMCContext *context)
{
    i915XvMCContext *pI915XvMC;

    if (!(pI915XvMC = context->privData))
        return XvMCBadContext;

    /* Pass Control to the X server to destroy the drm_context_t */
    i915_release_resource(display,context);

    free(one_time_load_state_imm1);
    free(one_time_load_indirect);
    free(mc_render_load_indirect);
    return Success;
}

static Status i915_xvmc_mc_create_surface(Display *display,
	XvMCContext *context, XvMCSurface *surface, int priv_count,
	CARD32 *priv_data)
{
    i915XvMCContext *pI915XvMC;
    i915XvMCSurface *pI915Surface;
    I915XvMCCreateSurfaceRec *tmpComm = NULL;

    if (!(pI915XvMC = context->privData))
        return XvMCBadContext;

    XVMC_DBG("%s\n", __FUNCTION__);

    if (priv_count != (sizeof(I915XvMCCreateSurfaceRec) >> 2)) {
        XVMC_ERR("_xvmc_create_surface() returned incorrect data size!");
        XVMC_INFO("\tExpected %d, got %d",
               (int)(sizeof(I915XvMCCreateSurfaceRec) >> 2), priv_count);
        _xvmc_destroy_surface(display, surface);
        XFree(priv_data);
        return BadAlloc;
    }

    PPTHREAD_MUTEX_LOCK();
    surface->privData = (i915XvMCSurface *)malloc(sizeof(i915XvMCSurface));

    if (!(pI915Surface = surface->privData)) {
        PPTHREAD_MUTEX_UNLOCK();
        return BadAlloc;
    }

    /* Initialize private values */
    pI915Surface->last_render = 0;
    pI915Surface->last_flip = 0;
    pI915Surface->yStride = pI915XvMC->yStride;
    pI915Surface->uvStride = pI915XvMC->uvStride;
    pI915Surface->width = context->width;
    pI915Surface->height = context->height;
    pI915Surface->privContext = pI915XvMC;
    pI915Surface->privSubPic = NULL;
    pI915Surface->srf.map = NULL;

    tmpComm = (I915XvMCCreateSurfaceRec *)priv_data;

    pI915Surface->srfNo = tmpComm->srfno;
    pI915Surface->srf.handle = tmpComm->srf.handle;
    pI915Surface->srf.offset = tmpComm->srf.offset;
    pI915Surface->srf.size = tmpComm->srf.size;

    XFree(priv_data);

    if (drmMap(xvmc_driver->fd,
               pI915Surface->srf.handle,
               pI915Surface->srf.size,
               (drmAddress *)&pI915Surface->srf.map) != 0) {
	XVMC_ERR("mapping surface memory failed!\n");
        _xvmc_destroy_surface(display, surface);
        free(pI915Surface);
        surface->privData = NULL;
        PPTHREAD_MUTEX_UNLOCK();
        return BadAlloc;
    }

    pI915XvMC->ref++;
    PPTHREAD_MUTEX_UNLOCK();
    return 0;
}


static int i915_xvmc_mc_destroy_surface(Display *display, XvMCSurface *surface)
{
    i915XvMCSurface *pI915Surface;
    i915XvMCContext *pI915XvMC;

    if (!display || !surface)
        return BadValue;

    if (!(pI915Surface = surface->privData))
        return XvMCBadSurface;

    if (!(pI915XvMC = pI915Surface->privContext))
        return XvMCBadSurface;

    if (pI915Surface->last_flip)
        XvMCSyncSurface(display,surface);

    if (pI915Surface->srf.map)
        drmUnmap(pI915Surface->srf.map, pI915Surface->srf.size);

    free(pI915Surface);
    surface->privData = NULL;
    pI915XvMC->ref--;

    return Success;
}


static int i915_xvmc_mc_render_surface(Display *display, XvMCContext *context,
                         unsigned int picture_structure,
                         XvMCSurface *target_surface,
                         XvMCSurface *past_surface,
                         XvMCSurface *future_surface,
                         unsigned int flags,
                         unsigned int num_macroblocks,
                         unsigned int first_macroblock,
                         XvMCMacroBlockArray *macroblock_array,
                         XvMCBlockArray *blocks)
{
    int i;
    int picture_coding_type = MPEG_I_PICTURE;
    /* correction data buffer */
    char *corrdata_ptr;
    int corrdata_size = 0;

    /* Block Pointer */
    short *block_ptr;
    /* Current Macroblock Pointer */
    XvMCMacroBlock *mb;

    intel_xvmc_context_ptr intel_ctx;

    i915XvMCSurface *privTarget = NULL;
    i915XvMCSurface *privFuture = NULL;
    i915XvMCSurface *privPast = NULL;
    i915XvMCContext *pI915XvMC = NULL;

    XVMC_DBG("%s\n", __FUNCTION__);

    /* Check Parameters for validity */
    if (!display || !context || !target_surface) {
        XVMC_ERR("Invalid Display, Context or Target!");
        return BadValue;
    }

    if (!num_macroblocks)
        return Success;

    if (!macroblock_array || !blocks) {
        XVMC_ERR("Invalid block data!");
        return BadValue;
    }

    if (macroblock_array->num_blocks < (num_macroblocks + first_macroblock)) {
        XVMC_ERR("Too many macroblocks requested for MB array size.");
        return BadValue;
    }

    if (!(pI915XvMC = context->privData))
        return XvMCBadContext;

    if (!(privTarget = target_surface->privData))
        return XvMCBadSurface;

    if (context->surface_type_id >= SURFACE_TYPE_MAX) {
        XVMC_ERR("Unsupprted surface_type_id %d.", context->surface_type_id);
        return BadValue;
    }

    intel_ctx = intel_xvmc_find_context(context->context_id);
    if (!intel_ctx) {
	XVMC_ERR("Can't find intel xvmc context\n");
	return BadValue;
    }

    /* P Frame Test */
    if (!past_surface) {
        /* Just to avoid some ifs later. */
        privPast = privTarget;
    } else {
        if (!(privPast = past_surface->privData)) {
            XVMC_ERR("Invalid Past Surface!");
            return XvMCBadSurface;
        }
        picture_coding_type = MPEG_P_PICTURE;
    }

    /* B Frame Test */
    if (!future_surface) {
        privFuture = privPast; // privTarget;
    } else {
        if (!past_surface) {
            XVMC_ERR("No Past Surface!");
            return BadValue;
        }

        if (!(privFuture = future_surface->privData)) {
            XVMC_ERR("Invalid Future Surface!");
            return XvMCBadSurface;
        }

        picture_coding_type = MPEG_B_PICTURE;
    }

    LOCK_HARDWARE(intel_ctx->hw_context);
    corrdata_ptr = pI915XvMC->corrdata.map;
    corrdata_size = 0;

    for (i = first_macroblock; i < (num_macroblocks + first_macroblock); i++) {
        int bspm = 0;
        mb = &macroblock_array->macro_blocks[i];
        block_ptr = &(blocks->blocks[mb->index << 6]);

        /* Lockup can happen if the coordinates are too far out of range */
        if (mb->x > (target_surface->width >> 4)) {
            mb->x = 0;
            XVMC_INFO("reset x");
        }

        if (mb->y > (target_surface->height >> 4)) {
            mb->y = 0;
            XVMC_INFO("reset y");
        }

        /* Catch no pattern case */
        if (!(mb->macroblock_type & XVMC_MB_TYPE_PATTERN) &&
            !(mb->macroblock_type & XVMC_MB_TYPE_INTRA) &&
            mb->coded_block_pattern) {
            mb->coded_block_pattern = 0;
            XVMC_INFO("no coded blocks present!");
        }

        bspm = mb_bytes_420[mb->coded_block_pattern];

        if (!bspm)
            continue;

        corrdata_size += bspm;

        if (corrdata_size > pI915XvMC->corrdata.size) {
            XVMC_ERR("correction data buffer overflow.");
            break;
        }
        memcpy(corrdata_ptr, block_ptr, bspm);
        corrdata_ptr += bspm;
    }

    i915_flush(1, 0);
    // i915_mc_invalidate_subcontext_buffers(context, BLOCK_SIS | BLOCK_DIS | BLOCK_SSB
    // | BLOCK_MSB | BLOCK_PSP | BLOCK_PSC);

    i915_mc_one_time_state_emit();

    i915_mc_static_indirect_state_set(context, target_surface, picture_structure,
	    flags, picture_coding_type);
    /* setup reference surfaces */
    i915_mc_map_state_set(context, privPast, privFuture);

    i915_mc_load_indirect_render_emit();

    i915_mc_mpeg_set_origin(context, &macroblock_array->macro_blocks[first_macroblock]);

    for (i = first_macroblock; i < (num_macroblocks + first_macroblock); i++) {
        mb = &macroblock_array->macro_blocks[i];

        /* Intra Blocks */
        if (mb->macroblock_type & XVMC_MB_TYPE_INTRA) {
            i915_mc_mpeg_macroblock_ipicture(context, mb);
        } else if ((picture_structure & XVMC_FRAME_PICTURE) == XVMC_FRAME_PICTURE) {
	    /* Frame Picture */
            switch (mb->motion_type & 3) {
            case XVMC_PREDICTION_FIELD: /* Field Based */
                i915_mc_mpeg_macroblock_2fbmv(context, mb, picture_structure);
                break;

            case XVMC_PREDICTION_FRAME: /* Frame Based */
                i915_mc_mpeg_macroblock_1fbmv(context, mb);
                break;

            case XVMC_PREDICTION_DUAL_PRIME:    /* Dual Prime */
                i915_mc_mpeg_macroblock_2fbmv(context, mb, picture_structure);
                break;

            default:    /* No Motion Type */
		XVMC_ERR("Invalid Macroblock Parameters found.");
                break;
            }
        } else {        /* Field Picture */
            switch (mb->motion_type & 3) {
            case XVMC_PREDICTION_FIELD: /* Field Based */
                i915_mc_mpeg_macroblock_1fbmv(context, mb);
                break;

            case XVMC_PREDICTION_16x8:  /* 16x8 MC */
                i915_mc_mpeg_macroblock_2fbmv(context, mb, picture_structure);
                break;

            case XVMC_PREDICTION_DUAL_PRIME:    /* Dual Prime */
                i915_mc_mpeg_macroblock_1fbmv(context, mb);
                break;

            default:    /* No Motion Type */
		XVMC_ERR("Invalid Macroblock Parameters found.");
                break;
            }
        }
    }

    intelFlushBatch(TRUE);
    xvmc_driver->last_render = xvmc_driver->alloc.irq_emitted;
    privTarget->last_render = xvmc_driver->last_render;

    UNLOCK_HARDWARE(intel_ctx->hw_context);
    return 0;
}

static int i915_xvmc_mc_put_surface(Display *display,XvMCSurface *surface,
                      Drawable draw, short srcx, short srcy,
                      unsigned short srcw, unsigned short srch,
                      short destx, short desty,
                      unsigned short destw, unsigned short desth,
                      int flags, struct intel_xvmc_command *data)
{
    i915XvMCContext *pI915XvMC;
    i915XvMCSurface *pI915Surface;
    i915XvMCSubpicture *pI915SubPic;

    if (!(pI915Surface = surface->privData))
        return XvMCBadSurface;

    if (!(pI915XvMC = pI915Surface->privContext))
        return XvMCBadSurface;

    PPTHREAD_MUTEX_LOCK();

    data->command = INTEL_XVMC_COMMAND_DISPLAY;
    data->ctxNo = pI915XvMC->ctxno;
    data->srfNo = pI915Surface->srfNo;
    pI915SubPic = pI915Surface->privSubPic;
    data->subPicNo = (!pI915SubPic ? 0 : pI915SubPic->srfNo);
    data->real_id = FOURCC_YV12;
    data->flags = flags;

    PPTHREAD_MUTEX_UNLOCK();

    return 0;
}

static int i915_xvmc_mc_get_surface_status(Display *display,
	XvMCSurface *surface, int *stat)
{
    i915XvMCSurface *pI915Surface;
    i915XvMCContext *pI915XvMC;

    if (!display || !surface || !stat)
        return BadValue;

    *stat = 0;

    if (!(pI915Surface = surface->privData))
        return XvMCBadSurface;

    if (!(pI915XvMC = pI915Surface->privContext))
        return XvMCBadSurface;

    PPTHREAD_MUTEX_LOCK();
    if (pI915Surface->last_flip) {
        /* This can not happen */
        if (pI915XvMC->last_flip < pI915Surface->last_flip) {
            XVMC_ERR("Context last flip is less than surface last flip.");
            PPTHREAD_MUTEX_UNLOCK();
            return BadValue;
        }

        /*
          If the context has 2 or more flips after this surface it
          cannot be displaying. Don't bother to check.
        */
        if (!(pI915XvMC->last_flip > (pI915Surface->last_flip + 1))) {
            /*
              If this surface was the last flipped it is either displaying
              or about to be so don't bother checking.
            */
            if (pI915XvMC->last_flip == pI915Surface->last_flip) {
                *stat |= XVMC_DISPLAYING;
            }
        }
    }

    PPTHREAD_MUTEX_UNLOCK();
    return 0;
}

/* XXX WIP code */
#if 0
Status XvMCHideSurface(Display *display, XvMCSurface *surface)
{
    i915XvMCSurface *pI915Surface;
    i915XvMCContext *pI915XvMC;
    int stat = 0, ret;

    if (!display || !surface)
        return BadValue;

    if (!(pI915Surface = surface->privData))
        return XvMCBadSurface;

    /* Get the associated context pointer */
    if (!(pI915XvMC = pI915Surface->privContext))
        return XvMCBadSurface;

    XvMCSyncSurface(display, surface);

    /*
      Get the status of the surface, if it is not currently displayed
      we don't need to worry about it.
    */
    if ((ret = XvMCGetSurfaceStatus(display, surface, &stat)) != Success)
        return ret;

    if (!(stat & XVMC_DISPLAYING))
        return Success;

    /* FIXME: */
    return Success;
}

Status i915_xvmc_create_subpict(Display *display, XvMCContext *context,
                            XvMCSubpicture *subpicture,
                            unsigned short width, unsigned short height,
                            int xvimage_id)
{
    Status ret;
    i915XvMCContext *pI915XvMC;
    i915XvMCSubpicture *pI915Subpicture;
    I915XvMCCreateSurfaceRec *tmpComm = NULL;
    int priv_count;
    uint *priv_data;

    if (!subpicture || !context || !display)
        return BadValue;

    pI915XvMC = (i915XvMCContext *)context->privData;

    if (!pI915XvMC)
        return XvMCBadContext;

    subpicture->privData =
        (i915XvMCSubpicture *)malloc(sizeof(i915XvMCSubpicture));

    if (!subpicture->privData)
        return BadAlloc;

    PPTHREAD_MUTEX_LOCK();
    subpicture->context_id = context->context_id;
    subpicture->xvimage_id = xvimage_id;
    subpicture->width = width;
    subpicture->height = height;
    pI915Subpicture = (i915XvMCSubpicture *)subpicture->privData;

    XLockDisplay(display);
    if ((ret = _xvmc_create_subpicture(display, context, subpicture,
                                       &priv_count, &priv_data))) {
        XUnlockDisplay(display);
        XVMC_ERR("Unable to create XvMCSubpicture.");
        free(pI915Subpicture);
        subpicture->privData = NULL;
        PPTHREAD_MUTEX_UNLOCK();
        return ret;
    }
    XUnlockDisplay(display);

    if (priv_count != (sizeof(I915XvMCCreateSurfaceRec) >> 2)) {
        XVMC_ERR("_xvmc_create_subpicture() returned incorrect data size!");
        XVMC_INFO("\tExpected %d, got %d",
               (int)(sizeof(I915XvMCCreateSurfaceRec) >> 2), priv_count);
        XLockDisplay(display);
        _xvmc_destroy_subpicture(display, subpicture);
        XUnlockDisplay(display);
        XFree(priv_data);
        free(pI915Subpicture);
        subpicture->privData = NULL;
        PPTHREAD_MUTEX_UNLOCK();
        return BadAlloc;
    }

    tmpComm = (I915XvMCCreateSurfaceRec *)priv_data;
    pI915Subpicture->srfNo = tmpComm->srfno;
    pI915Subpicture->srf.handle = tmpComm->srf.handle;
    pI915Subpicture->srf.offset = tmpComm->srf.offset;
    pI915Subpicture->srf.size = tmpComm->srf.size;
    XFree(priv_data);

    if (drmMap(pI915XvMC->fd,
               pI915Subpicture->srf.handle,
               pI915Subpicture->srf.size,
               (drmAddress *)&pI915Subpicture->srf.map) != 0) {
        XLockDisplay(display);
        _xvmc_destroy_subpicture(display, subpicture);
        XUnlockDisplay(display);
        free(pI915Subpicture);
        subpicture->privData = NULL;
        PPTHREAD_MUTEX_UNLOCK();
        return BadAlloc;
    }

    /* subpicture */
    subpicture->num_palette_entries = I915_SUBPIC_PALETTE_SIZE;
    subpicture->entry_bytes = 3;
    strncpy(subpicture->component_order, "YUV", 4);

    /* Initialize private values */
    pI915Subpicture->privContext = pI915XvMC;
    pI915Subpicture->last_render= 0;
    pI915Subpicture->last_flip = 0;
    pI915Subpicture->pitch = ((subpicture->width + 3) & ~3);

    switch(subpicture->xvimage_id) {
    case FOURCC_IA44:
    case FOURCC_AI44:
        break;

    default:
        drmUnmap(pI915Subpicture->srf.map, pI915Subpicture->srf.size);
        XLockDisplay(display);
        _xvmc_destroy_subpicture(display, subpicture);
        XUnlockDisplay(display);
        free(pI915Subpicture);
        subpicture->privData = NULL;
        PPTHREAD_MUTEX_UNLOCK();
        return BadMatch;
    }

    pI915XvMC->ref++;
    PPTHREAD_MUTEX_UNLOCK();
    return Success;
}

Status i915_xvmc_clear_subpict(Display *display, XvMCSubpicture *subpicture,
                           short x, short y,
                           unsigned short width, unsigned short height,
                           unsigned int color)
{
    i915XvMCContext *pI915XvMC;
    i915XvMCSubpicture *pI915Subpicture;

    if (!display || !subpicture)
        return BadValue;

    if (!(pI915Subpicture = subpicture->privData))
        return XvMCBadSubpicture;

    if (!(pI915XvMC = pI915Subpicture->privContext))
        return XvMCBadSubpicture;

    if ((x < 0) || (x + width) > subpicture->width)
        return BadValue;

    if ((y < 0) || (y + height) > subpicture->height)
        return BadValue;

    /* FIXME: clear the area */

    return Success;
}

Status i915_xvmc_composite_subpict(Display *display, XvMCSubpicture *subpicture,
                               XvImage *image,
                               short srcx, short srcy,
                               unsigned short width, unsigned short height,
                               short dstx, short dsty)
{
    i915XvMCContext *pI915XvMC;
    i915XvMCSubpicture *pI915Subpicture;

    if (!display || !subpicture)
        return BadValue;

    if (!(pI915Subpicture = subpicture->privData))
        return XvMCBadSubpicture;

    if (!(pI915XvMC = pI915Subpicture->privContext))
        return XvMCBadSubpicture;

    if ((srcx < 0) || (srcx + width) > subpicture->width)
        return BadValue;

    if ((srcy < 0) || (srcy + height) > subpicture->height)
        return BadValue;

    if ((dstx < 0) || (dstx + width) > subpicture->width)
        return BadValue;

    if ((dsty < 0) || (dsty + width) > subpicture->height)
        return BadValue;

    if (image->id != subpicture->xvimage_id)
        return BadMatch;

    /* FIXME */
    return Success;
}


Status i915_xvmc_destroy_subpict(Display *display, XvMCSubpicture *subpicture)
{
    i915XvMCSubpicture *pI915Subpicture;
    i915XvMCContext *pI915XvMC;

    if (!display || !subpicture)
        return BadValue;

    if (!(pI915Subpicture = subpicture->privData))
        return XvMCBadSubpicture;

    if (!(pI915XvMC = pI915Subpicture->privContext))
        return XvMCBadSubpicture;

    if (pI915Subpicture->last_render)
        XvMCSyncSubpicture(display, subpicture);

    if (pI915Subpicture->srf.map)
        drmUnmap(pI915Subpicture->srf.map, pI915Subpicture->srf.size);

    PPTHREAD_MUTEX_LOCK();
    XLockDisplay(display);
    _xvmc_destroy_subpicture(display,subpicture);
    XUnlockDisplay(display);

    free(pI915Subpicture);
    subpicture->privData = NULL;
    pI915XvMC->ref--;
    PPTHREAD_MUTEX_UNLOCK();

    return Success;
}


Status i915_xvmc_set_subpict_palette(Display *display,
	XvMCSubpicture *subpicture,
	unsigned char *palette)
{
    i915XvMCSubpicture *pI915Subpicture;
    int i, j;

    if (!display || !subpicture)
        return BadValue;

    if (!(pI915Subpicture = subpicture->privData))
        return XvMCBadSubpicture;

    j = 0;
    for (i = 0; i < 16; i++) {
        pI915Subpicture->palette[0][i] = palette[j++];
        pI915Subpicture->palette[1][i] = palette[j++];
        pI915Subpicture->palette[2][i] = palette[j++];
    }

    /* FIXME: Update the subpicture with the new palette */
    return Success;
}

Status i915_xvmc_blend_subpict(Display *display, XvMCSurface *target_surface,
                           XvMCSubpicture *subpicture,
                           short subx, short suby,
                           unsigned short subw, unsigned short subh,
                           short surfx, short surfy,
                           unsigned short surfw, unsigned short surfh)
{
    i915XvMCSubpicture *pI915Subpicture;
    i915XvMCSurface *privTargetSurface;

    if (!display || !target_surface)
        return BadValue;

    if (!(privTargetSurface = target_surface->privData))
        return XvMCBadSurface;

    if (subpicture) {
        if (!(pI915Subpicture = subpicture->privData))
            return XvMCBadSubpicture;

        if ((FOURCC_AI44 != subpicture->xvimage_id) &&
            (FOURCC_IA44 != subpicture->xvimage_id))
            return XvMCBadSubpicture;

        privTargetSurface->privSubPic = pI915Subpicture;
    } else {
        privTargetSurface->privSubPic = NULL;
    }

    return Success;
}

Status i915_xvmc_blend_subpict2(Display *display,
                            XvMCSurface *source_surface,
                            XvMCSurface *target_surface,
                            XvMCSubpicture *subpicture,
                            short subx, short suby,
                            unsigned short subw, unsigned short subh,
                            short surfx, short surfy,
                            unsigned short surfw, unsigned short surfh)
{
    i915XvMCContext *pI915XvMC;
    i915XvMCSubpicture *pI915Subpicture;
    i915XvMCSurface *privSourceSurface;
    i915XvMCSurface *privTargetSurface;

    if (!display || !source_surface || !target_surface)
        return BadValue;

    if (!(privSourceSurface = source_surface->privData))
        return XvMCBadSurface;

    if (!(privTargetSurface = target_surface->privData))
        return XvMCBadSurface;

    if (!(pI915XvMC = privTargetSurface->privContext))
        return XvMCBadSurface;

    if (((surfx + surfw) > privTargetSurface->width) ||
        ((surfy + surfh) > privTargetSurface->height))
        return BadValue;

    if ((privSourceSurface->width != privTargetSurface->width) ||
        (privTargetSurface->height != privTargetSurface->height))
        return BadValue;

    if (XvMCSyncSurface(display, source_surface))
        return BadValue;

    /* FIXME: update Target Surface */

    if (subpicture) {
        if (((subx + subw) > subpicture->width) ||
            ((suby + subh) > subpicture->height))
            return BadValue;

        if (!(pI915Subpicture = subpicture->privData))
            return XvMCBadSubpicture;

        if ((FOURCC_AI44 != subpicture->xvimage_id) &&
            (FOURCC_IA44 != subpicture->xvimage_id))
            return XvMCBadSubpicture;

        privTargetSurface->privSubPic = pI915Subpicture;
    } else {
        privTargetSurface->privSubPic = NULL;
    }

    return Success;
}

Status i915_xvmc_sync_subpict(Display *display, XvMCSubpicture *subpicture)
{
    Status ret;
    int stat = 0;

    if (!display || !subpicture)
        return BadValue;

    do {
        ret = XvMCGetSubpictureStatus(display, subpicture, &stat);
    } while(!ret && (stat & XVMC_RENDERING));

    return ret;
}

Status i915_xvmc_flush_subpict(Display *display, XvMCSubpicture *subpicture)
{
    i915XvMCSubpicture *pI915Subpicture;

    if (!display || !subpicture)
        return BadValue;

    if (!(pI915Subpicture = subpicture->privData))
        return XvMCBadSubpicture;

    return Success;
}

Status i915_xvmc_get_subpict_status(Display *display, XvMCSubpicture *subpicture,
                               int *stat)
{
    i915XvMCSubpicture *pI915Subpicture;
    i915XvMCContext *pI915XvMC;

    if (!display || !subpicture || stat)
        return BadValue;

    *stat = 0;

    if (!(pI915Subpicture = subpicture->privData))
        return XvMCBadSubpicture;

    if (!(pI915XvMC = pI915Subpicture->privContext))
        return XvMCBadSubpicture;

    PPTHREAD_MUTEX_LOCK();
    
    PPTHREAD_MUTEX_UNLOCK();
    return Success;
}

#endif

struct _intel_xvmc_driver i915_xvmc_mc_driver = {
    .type		= XVMC_I915_MPEG2_MC,
    .num_ctx		= 0,
    .ctx_list		= NULL,
    .create_context	= i915_xvmc_mc_create_context,
    .destroy_context	= i915_xvmc_mc_destroy_context,
    .create_surface	= i915_xvmc_mc_create_surface,
    .destroy_surface	= i915_xvmc_mc_destroy_surface,
    .render_surface	= i915_xvmc_mc_render_surface,
    .put_surface	= i915_xvmc_mc_put_surface,
    .get_surface_status	= i915_xvmc_mc_get_surface_status,
};
