diff options
Diffstat (limited to 'xvmc/i915_xvmc.c')
-rw-r--r-- | xvmc/i915_xvmc.c | 1225 |
1 files changed, 1225 insertions, 0 deletions
diff --git a/xvmc/i915_xvmc.c b/xvmc/i915_xvmc.c new file mode 100644 index 00000000..fbd4555e --- /dev/null +++ b/xvmc/i915_xvmc.c @@ -0,0 +1,1225 @@ +/* + * 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 ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1)) + +#define STRIDE(w) (ALIGN((w), 1024)) +#define SIZE_Y420(w, h) (h * STRIDE(w)) +#define SIZE_UV420(w, h) ((h >> 1) * STRIDE(w >> 1)) +#define SIZE_YUV420(w, h) (SIZE_Y420(w,h) + SIZE_UV420(w,h) * 2) +#define UOFFSET(context) (SIZE_Y420(context->width, context->height)) +#define VOFFSET(context) (SIZE_Y420(context->width, context->height) + \ + SIZE_UV420(context->width, context->height)) + +typedef union { + int16_t component[2]; + int32_t v; +} vector_t; + +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_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 */ + drm_intel_gem_bo_map_gtt(pI915XvMC->ssb_bo); + sampler_state = pI915XvMC->ssb_bo->virtual; + + 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; + + drm_intel_gem_bo_unmap_gtt(pI915XvMC->ssb_bo); + + /* pixel shader static state */ + drm_intel_gem_bo_map_gtt(pI915XvMC->psp_bo); + pixel_shader_program = pI915XvMC->psp_bo->virtual; + + 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); + + drm_intel_gem_bo_unmap_gtt(pI915XvMC->psp_bo); + + /* pixel shader contant static state */ + drm_intel_gem_bo_map_gtt(pI915XvMC->psc_bo); + pixel_shader_constants = pI915XvMC->psc_bo->virtual; + + 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; + + drm_intel_gem_bo_unmap_gtt(pI915XvMC->psc_bo); +} + +static void i915_mc_one_time_state_emit(XvMCContext * context) +{ + i915XvMCContext *pI915XvMC = (i915XvMCContext *) context->privData; + uint32_t load_state_immediate_1, load_indirect, s3_dword, s6_dword; + int mem_select; + BATCH_LOCALS; + + /* 3DSTATE_LOAD_STATE_IMMEDIATE_1 */ + BEGIN_BATCH(3 + 8); + load_state_immediate_1 = OP_3D_LOAD_STATE_IMMEDIATE_1; + load_state_immediate_1 |= OP_3D_LOAD_STATE_IMM_LOAD_S3; + load_state_immediate_1 |= OP_3D_LOAD_STATE_IMM_LOAD_S6; + load_state_immediate_1 |= 3 - 2; /* length */ + OUT_BATCH(load_state_immediate_1); + + s3_dword = S3_SET0_PCD | S3_SET1_PCD | + S3_SET2_PCD | S3_SET3_PCD | + S3_SET4_PCD | S3_SET5_PCD | + S3_SET6_PCD | S3_SET7_PCD; + OUT_BATCH(s3_dword); + + s6_dword = S6_COLOR_BUFFER_WRITE | S6_DEPTH_TEST_ENABLE; + s6_dword |= 1 << S6_SRC_BLEND_FACTOR_SHIFT; + s6_dword |= 1 << S6_DST_BLEND_FACTOR_SHIFT; + OUT_BATCH(s6_dword); + + /* 3DSTATE_LOAD_INDIRECT */ + load_indirect = OP_3D_LOAD_INDIRECT; + load_indirect |= (BLOCK_DIS | BLOCK_SSB | BLOCK_PSP | BLOCK_PSC) + << BLOCK_MASK_SHIFT; + load_indirect |= 8 - 2; /* length */ + + if (pI915XvMC->use_phys_addr) + mem_select = 0; /* use physical address */ + else { + load_indirect |= OP_3D_LOAD_INDIRECT_GFX_ADDR; + mem_select = 1; /* use gfx address */ + } + + OUT_BATCH(load_indirect); + + /* Dynamic indirect state buffer */ + OUT_BATCH(0); /* no dynamic indirect state */ + + /* Sample state buffer */ + OUT_RELOC(pI915XvMC->ssb_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, + STATE_VALID | STATE_FORCE); + OUT_BATCH(7); /* 8 - 1 */ + + /* Pixel shader program buffer */ + OUT_RELOC(pI915XvMC->psp_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, + STATE_VALID | STATE_FORCE); + OUT_BATCH(66); /* 4 + 16 + 16 + 31 - 1 */ + + /* Pixel shader constant buffer */ + OUT_RELOC(pI915XvMC->psc_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, + STATE_VALID | STATE_FORCE); + OUT_BATCH(5); /* 6 - 1 */ + ADVANCE_BATCH(); +} + +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; + struct intel_xvmc_surface *intel_surf = dest->privData; + struct i915_mc_static_indirect_state_buffer *buffer_info; + + drm_intel_gem_bo_map_gtt(pI915XvMC->sis_bo); + buffer_info = pI915XvMC->sis_bo->virtual; + + 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; + buffer_info->dest_y.dw1.pitch = (pI915XvMC->yStride >> 2); /* in DWords */ + buffer_info->dest_y.dw2.base_address = intel_surf->bo->offset >> 2; /* starting DWORD address */ + drm_intel_bo_emit_reloc(pI915XvMC->sis_bo, + offsetof(typeof(*buffer_info),dest_y.dw2), + intel_surf->bo, 0, + I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER); + + /* 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; + buffer_info->dest_u.dw1.pitch = (pI915XvMC->uvStride >> 2); /* in DWords */ + buffer_info->dest_u.dw2.base_address = + (intel_surf->bo->offset + UOFFSET(context)) >> 2; + drm_intel_bo_emit_reloc(pI915XvMC->sis_bo, + offsetof(typeof(*buffer_info),dest_u.dw2), + intel_surf->bo, UOFFSET(context), + I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER); + + /* 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_v.dw1.pitch = (pI915XvMC->uvStride >> 2); /* in Dwords */ + buffer_info->dest_v.dw2.base_address = + (intel_surf->bo->offset + VOFFSET(context)) >> 2; + drm_intel_bo_emit_reloc(pI915XvMC->sis_bo, + offsetof(typeof(*buffer_info),dest_v.dw2), + intel_surf->bo, VOFFSET(context), + I915_GEM_DOMAIN_RENDER, + I915_GEM_DOMAIN_RENDER); + + /* Dest buffer parameters */ + 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 */ + 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; + } + + /* MPEG buffer parameters */ + 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; + + 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; + + 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_bo->offset >> 2; /* starting DWORD address */ + drm_intel_bo_emit_reloc(pI915XvMC->sis_bo, + offsetof(typeof(*buffer_info),corr.dw2), + pI915XvMC->corrdata_bo, 0, + I915_GEM_DOMAIN_RENDER, 0); + + drm_intel_gem_bo_unmap_gtt(pI915XvMC->sis_bo); +} + +static void i915_mc_map_state_set(XvMCContext * context, + struct intel_xvmc_surface * privPast, + struct intel_xvmc_surface * privFuture) +{ + i915XvMCContext *pI915XvMC = (i915XvMCContext *) context->privData; + struct i915_mc_map_state *map_state; + unsigned int w = context->width; + unsigned int h = context->height; + + drm_intel_gem_bo_map_gtt(pI915XvMC->msb_bo); + map_state = pI915XvMC->msb_bo->virtual; + + 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; + map_state->y_forward.tm0.base_address = privPast->bo->offset >> 2; + drm_intel_bo_emit_reloc(pI915XvMC->msb_bo, + offsetof(typeof(*map_state),y_forward.tm0), + privPast->bo, 0, + I915_GEM_DOMAIN_SAMPLER, 0); + map_state->y_forward.tm2.pitch = (pI915XvMC->yStride >> 2) - 1; /* in DWords - 1 */ + + /* 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; + map_state->y_backward.tm0.base_address = privFuture->bo->offset >> 2; + drm_intel_bo_emit_reloc(pI915XvMC->msb_bo, + offsetof(typeof(*map_state),y_backward.tm0), + privFuture->bo, 0, + I915_GEM_DOMAIN_SAMPLER, 0); + map_state->y_backward.tm2.pitch = (pI915XvMC->yStride >> 2) - 1; + + /* 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; + map_state->u_forward.tm0.base_address = + (privPast->bo->offset + UOFFSET(context)) >> 2; + drm_intel_bo_emit_reloc(pI915XvMC->msb_bo, + offsetof(typeof(*map_state),u_forward.tm0), + privPast->bo, UOFFSET(context), + I915_GEM_DOMAIN_SAMPLER, 0); + map_state->u_forward.tm2.pitch = (pI915XvMC->uvStride >> 2) - 1; /* in DWords - 1 */ + + /* 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; + map_state->u_backward.tm0.base_address = + (privFuture->bo->offset + UOFFSET(context)) >> 2; + drm_intel_bo_emit_reloc(pI915XvMC->msb_bo, + offsetof(typeof(*map_state),u_backward.tm0), + privFuture->bo, UOFFSET(context), + I915_GEM_DOMAIN_SAMPLER, 0); + map_state->u_backward.tm2.pitch = (pI915XvMC->uvStride >> 2) - 1; + + /* 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; + map_state->v_forward.tm0.base_address = + (privPast->bo->offset + VOFFSET(context)) >> 2; + drm_intel_bo_emit_reloc(pI915XvMC->msb_bo, + offsetof(typeof(*map_state),v_forward.tm0), + privPast->bo, VOFFSET(context), + I915_GEM_DOMAIN_SAMPLER, 0); + map_state->v_forward.tm2.pitch = (pI915XvMC->uvStride >> 2) - 1; /* in DWords - 1 */ + + /* 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; + map_state->v_backward.tm0.base_address = + (privFuture->bo->offset + VOFFSET(context)) >> 2; + drm_intel_bo_emit_reloc(pI915XvMC->msb_bo, + offsetof(typeof(*map_state),v_backward.tm0), + privFuture->bo, VOFFSET(context), + I915_GEM_DOMAIN_SAMPLER, 0); + map_state->v_backward.tm2.pitch = (pI915XvMC->uvStride >> 2) - 1; + + drm_intel_gem_bo_unmap_gtt(pI915XvMC->msb_bo); +} + +static void i915_mc_load_indirect_render_emit(XvMCContext * context) +{ + i915XvMCContext *pI915XvMC = (i915XvMCContext *) context->privData; + int mem_select; + uint32_t load_indirect; + BATCH_LOCALS; + + BEGIN_BATCH(5); + load_indirect = OP_3D_LOAD_INDIRECT; + load_indirect |= (BLOCK_SIS | BLOCK_MSB) << BLOCK_MASK_SHIFT; + load_indirect |= 5 - 2; /* length */ + + if (pI915XvMC->use_phys_addr) + mem_select = 0; /* use physical address */ + else { + load_indirect |= OP_3D_LOAD_INDIRECT_GFX_ADDR; + mem_select = 1; /* use gfx address */ + } + OUT_BATCH(load_indirect); + + /* Static Indirect state buffer (dest buffer info) */ + OUT_RELOC(pI915XvMC->sis_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, + STATE_VALID | STATE_FORCE); + OUT_BATCH(16); /* 4 * 3 + 2 + 3 - 1 */ + + /* Map state buffer (reference buffer info) */ + OUT_RELOC(pI915XvMC->msb_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, + STATE_VALID | STATE_FORCE); + OUT_BATCH(23); /* 3 * 8 - 1 */ + ADVANCE_BATCH(); +} + +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(¯oblock_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(¯oblock_ipicture, sizeof(macroblock_ipicture), + 0); +} + +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(¯oblock_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(¯oblock_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(¯oblock_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(¯oblock_2fbmv, sizeof(macroblock_2fbmv), 0); +} + +static int i915_xvmc_alloc_one_time_buffers(i915XvMCContext *pI915XvMC) +{ + pI915XvMC->ssb_bo = drm_intel_bo_alloc(xvmc_driver->bufmgr, + "ssb", + GTT_PAGE_SIZE, + GTT_PAGE_SIZE); + if (!pI915XvMC->ssb_bo) + return 0; + + pI915XvMC->psp_bo = drm_intel_bo_alloc(xvmc_driver->bufmgr, + "psp", + GTT_PAGE_SIZE, + GTT_PAGE_SIZE); + if (!pI915XvMC->psp_bo) + return 0; + + pI915XvMC->psc_bo = drm_intel_bo_alloc(xvmc_driver->bufmgr, + "psc", + GTT_PAGE_SIZE, + GTT_PAGE_SIZE); + if (!pI915XvMC->psc_bo) + return 0; + + return 1; +} + +static void i915_xvmc_free_one_time_buffers(i915XvMCContext *pI915XvMC) +{ + drm_intel_bo_unreference(pI915XvMC->ssb_bo); + drm_intel_bo_unreference(pI915XvMC->psp_bo); + drm_intel_bo_unreference(pI915XvMC->psc_bo); +} + +/* + * Function: i915_release_resource + */ +static void i915_release_resource(Display * display, XvMCContext * context) +{ + i915XvMCContext *pI915XvMC; + + if (!(pI915XvMC = context->privData)) + return; + + i915_xvmc_free_one_time_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; + struct intel_xvmc_hw_context *tmpComm = NULL; + + if (priv_count != (sizeof(struct intel_xvmc_hw_context) >> 2)) { + XVMC_ERR + ("_xvmc_create_context() returned incorrect data size!"); + XVMC_INFO("\tExpected %d, got %d", + (int)(sizeof(struct intel_xvmc_hw_context) >> 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 = (struct intel_xvmc_hw_context *) priv_data; + pI915XvMC->use_phys_addr = tmpComm->i915.use_phys_addr; + pI915XvMC->comm.surface_bo_size = SIZE_YUV420(context->width, + context->height); + + /* Must free the private data we were passed from X */ + XFree(priv_data); + priv_data = NULL; + + if (!i915_xvmc_alloc_one_time_buffers(pI915XvMC)) + goto free_one_time_buffers; + + /* Initialize private context values */ + pI915XvMC->yStride = STRIDE(context->width); + pI915XvMC->uvStride = STRIDE(context->width >> 1); + + /* pre-init state buffers */ + i915_mc_one_time_context_init(context); + + return Success; + +free_one_time_buffers: + i915_xvmc_free_one_time_buffers(pI915XvMC); + free(pI915XvMC); + context->privData = NULL; + return BadAlloc; +} + +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); + + return Success; +} + +static int i915_xvmc_alloc_render_state_buffers(i915XvMCContext *pI915XvMC) +{ + pI915XvMC->sis_bo = drm_intel_bo_alloc(xvmc_driver->bufmgr, + "sis", + GTT_PAGE_SIZE, + GTT_PAGE_SIZE); + if (!pI915XvMC->sis_bo) + return 0; + + pI915XvMC->msb_bo = drm_intel_bo_alloc(xvmc_driver->bufmgr, + "msb", + GTT_PAGE_SIZE, + GTT_PAGE_SIZE); + if (!pI915XvMC->msb_bo) + return 0; + + pI915XvMC->corrdata_bo = drm_intel_bo_alloc(xvmc_driver->bufmgr, + "corrdata", + CORRDATA_SIZE, + GTT_PAGE_SIZE); + if (!pI915XvMC->corrdata_bo) + return 0; + + return 1; +} + +static void i915_xvmc_free_render_state_buffers(i915XvMCContext *pI915XvMC) +{ + drm_intel_bo_unreference(pI915XvMC->sis_bo); + drm_intel_bo_unreference(pI915XvMC->msb_bo); + drm_intel_bo_unreference(pI915XvMC->corrdata_bo); +} + +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; + + struct intel_xvmc_surface *privTarget = NULL; + struct intel_xvmc_surface *privFuture = NULL; + struct intel_xvmc_surface *privPast = NULL; + i915XvMCContext *pI915XvMC = NULL; + + /* 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 (!i915_xvmc_alloc_render_state_buffers(pI915XvMC)) + return BadAlloc; + + intel_ctx = context->privData; + 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)) { + 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); + drm_intel_gem_bo_map_gtt(pI915XvMC->corrdata_bo); + corrdata_ptr = pI915XvMC->corrdata_bo->virtual; + corrdata_size = 0; + + for (i = first_macroblock; i < (num_macroblocks + first_macroblock); + i++) { + int bspm = 0; + mb = ¯oblock_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 > CORRDATA_SIZE) { + XVMC_ERR("correction data buffer overflow."); + break; + } + memcpy(corrdata_ptr, block_ptr, bspm); + corrdata_ptr += bspm; + } + + drm_intel_gem_bo_unmap_gtt(pI915XvMC->corrdata_bo); + + // i915_mc_invalidate_subcontext_buffers(context, BLOCK_SIS | BLOCK_DIS | BLOCK_SSB + // | BLOCK_MSB | BLOCK_PSP | BLOCK_PSC); + + i915_mc_one_time_state_emit(context); + + 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(context); + + i915_mc_mpeg_set_origin(context, + ¯oblock_array->macro_blocks + [first_macroblock]); + + for (i = first_macroblock; i < (num_macroblocks + first_macroblock); + i++) { + mb = ¯oblock_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); + + i915_xvmc_free_render_state_buffers(pI915XvMC); + + UNLOCK_HARDWARE(intel_ctx->hw_context); + return 0; +} + +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, + .render_surface = i915_xvmc_mc_render_surface, +}; |