1/*
2 * Copyright © 2008 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Author:
24 *    Zou Nan hai <nanhai.zou@intel.com>
25 *
26 */
27#include "i965_xvmc.h"
28#include "i810_reg.h"
29#include "brw_defines.h"
30#include "brw_structs.h"
31#include "intel_batchbuffer.h"
32#include "i965_hwmc.h"
33#define BATCH_STRUCT(x) intelBatchbufferData(&x, sizeof(x), 0)
34#define URB_SIZE     256        /* XXX */
35
36#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
37
38enum interface {
39    INTRA_INTERFACE = 0,            /* non field intra */
40    NULL_INTERFACE,             /* fill with white, do nothing, for debug */
41    FORWARD_INTERFACE,          /* non field forward predict */
42    BACKWARD_INTERFACE,         /* non field backward predict */
43    F_B_INTERFACE,              /* non field forward and backward predict */
44    FIELD_FORWARD_INTERFACE,    /* field forward predict */
45    FIELD_BACKWARD_INTERFACE,   /* field backward predict */
46    FIELD_F_B_INTERFACE,        /* field forward and backward predict */
47    DUAL_PRIME_INTERFACE
48};
49
50static const uint32_t ipicture_kernel_static[][4] = {
51	#include "shader/mc/ipicture.g4b"
52};
53static const uint32_t null_kernel_static[][4] = {
54	#include "shader/mc/null.g4b"
55};
56static const uint32_t frame_forward_kernel_static[][4] = {
57	#include "shader/mc/frame_forward.g4b"
58};
59static const uint32_t frame_backward_kernel_static[][4] = {
60	#include "shader/mc/frame_backward.g4b"
61};
62static const uint32_t frame_f_b_kernel_static[][4] = {
63	#include "shader/mc/frame_f_b.g4b"
64};
65static const uint32_t field_forward_kernel_static[][4] = {
66	#include "shader/mc/field_forward.g4b"
67};
68static const uint32_t field_backward_kernel_static[][4] = {
69	#include "shader/mc/field_backward.g4b"
70};
71static const uint32_t field_f_b_kernel_static[][4] = {
72	#include "shader/mc/field_f_b.g4b"
73};
74static const uint32_t dual_prime_kernel_static[][4]= {
75	#include "shader/mc/dual_prime.g4b"
76};
77static const uint32_t frame_forward_igd_kernel_static[][4] = {
78	#include "shader/mc/frame_forward_igd.g4b"
79};
80static const uint32_t frame_backward_igd_kernel_static[][4] = {
81	#include "shader/mc/frame_backward_igd.g4b"
82};
83static const uint32_t frame_f_b_igd_kernel_static[][4] = {
84	#include "shader/mc/frame_f_b_igd.g4b"
85};
86static const uint32_t field_forward_igd_kernel_static[][4] = {
87	#include "shader/mc/field_forward_igd.g4b"
88};
89static const uint32_t field_backward_igd_kernel_static[][4] = {
90	#include "shader/mc/field_backward_igd.g4b"
91};
92static const uint32_t field_f_b_igd_kernel_static[][4] = {
93	#include "shader/mc/field_f_b_igd.g4b"
94};
95static const uint32_t dual_prime_igd_kernel_static[][4]= {
96	#include "shader/mc/dual_prime_igd.g4b"
97};
98
99struct kernel_struct{
100	const uint32_t (*bin)[4];
101	uint32_t size;
102};
103
104struct kernel_struct kernels_igd[] = {
105    {ipicture_kernel_static, sizeof(ipicture_kernel_static)},
106    {null_kernel_static, sizeof(null_kernel_static)},
107    {frame_forward_igd_kernel_static, sizeof(frame_forward_igd_kernel_static)},
108    {frame_backward_igd_kernel_static, sizeof(frame_backward_igd_kernel_static)},
109    {frame_f_b_igd_kernel_static, sizeof(frame_f_b_igd_kernel_static)},
110    {field_forward_igd_kernel_static, sizeof(field_forward_igd_kernel_static)},
111    {field_backward_igd_kernel_static, sizeof(field_backward_igd_kernel_static)},
112    {field_f_b_igd_kernel_static, sizeof(field_f_b_igd_kernel_static)},
113    {dual_prime_igd_kernel_static, sizeof(dual_prime_igd_kernel_static)}
114};
115
116struct kernel_struct kernels_965[] = {
117    {ipicture_kernel_static, sizeof(ipicture_kernel_static)},
118    {null_kernel_static, sizeof(null_kernel_static)},
119    {frame_forward_kernel_static, sizeof(frame_forward_kernel_static)},
120    {frame_backward_kernel_static, sizeof(frame_backward_kernel_static)},
121    {frame_f_b_kernel_static, sizeof(frame_f_b_kernel_static)},
122    {field_forward_kernel_static, sizeof(field_forward_kernel_static)},
123    {field_backward_kernel_static, sizeof(field_backward_kernel_static)},
124    {field_f_b_kernel_static, sizeof(field_f_b_kernel_static)},
125    {dual_prime_kernel_static, sizeof(dual_prime_kernel_static)}
126};
127
128#define ALIGN(i,m)    (((i) + (m) - 1) & ~((m) - 1))
129
130#define MAX_SURFACE_NUM	10
131#define DESCRIPTOR_NUM 12
132
133struct media_kernel_obj {
134    dri_bo *bo;
135};
136
137struct interface_descriptor_obj {
138   dri_bo *bo;
139   struct media_kernel_obj kernels[DESCRIPTOR_NUM];
140};
141
142struct vfe_state_obj {
143   dri_bo *bo;
144   struct interface_descriptor_obj interface;
145};
146
147struct surface_obj {
148     dri_bo *bo;
149};
150
151struct surface_state_obj {
152      struct surface_obj surface;
153      dri_bo *bo;
154};
155
156struct binding_table_obj {
157    dri_bo *bo;
158    struct surface_state_obj surface_states[MAX_SURFACE_NUM];
159};
160
161struct indirect_data_obj {
162    dri_bo *bo;
163};
164
165struct media_state {
166    unsigned int  is_g4x:1;
167    unsigned int  is_965_q:1;
168
169    struct vfe_state_obj vfe_state;
170    struct binding_table_obj binding_table;
171    struct indirect_data_obj indirect_data;
172};
173struct media_state media_state;
174
175static int free_object(struct media_state *s)
176{
177    int i;
178#define FREE_ONE_BO(bo) drm_intel_bo_unreference(bo)
179    FREE_ONE_BO(s->vfe_state.bo);
180    FREE_ONE_BO(s->vfe_state.interface.bo);
181    for (i = 0; i < DESCRIPTOR_NUM; i++)
182        FREE_ONE_BO(s->vfe_state.interface.kernels[i].bo);
183    FREE_ONE_BO(s->binding_table.bo);
184    for (i = 0; i < MAX_SURFACE_NUM; i++)
185        FREE_ONE_BO(s->binding_table.surface_states[i].bo);
186    FREE_ONE_BO(s->indirect_data.bo);
187}
188
189static int alloc_object(struct media_state *s)
190{
191    int i;
192
193    for (i = 0; i < MAX_SURFACE_NUM; i++) {
194        s->binding_table.surface_states[i].bo =
195            drm_intel_bo_alloc(xvmc_driver->bufmgr, "surface_state",
196 		sizeof(struct brw_surface_state), 0x1000);
197        if (!s->binding_table.surface_states[i].bo)
198            goto out;
199    }
200    return 0;
201out:
202    free_object(s);
203    return BadAlloc;
204}
205
206
207static Status destroy_context(Display *display, XvMCContext *context)
208{
209    struct i965_xvmc_context *private_context;
210    private_context = context->privData;
211
212    free_object(&media_state);
213    Xfree(private_context);
214    return Success;
215}
216
217#define STRIDE(w)               (w)
218#define SIZE_YUV420(w, h)       (h * (STRIDE(w) + STRIDE(w >> 1)))
219
220static Status create_surface(Display *display,
221	XvMCContext *context, XvMCSurface *surface, int priv_count,
222	CARD32 *priv_data)
223{
224    struct i965_xvmc_surface *priv_surface =
225	(struct i965_xvmc_surface *)priv_data;
226    size_t size = SIZE_YUV420(priv_surface->w, priv_surface->h);
227    surface->privData = priv_data;
228    priv_surface->bo = drm_intel_bo_alloc(xvmc_driver->bufmgr, "surface",
229	    size, 0x1000);
230    return Success;
231}
232
233static Status destroy_surface(Display *display, XvMCSurface *surface)
234{
235    struct i965_xvmc_surface *priv_surface =
236	surface->privData;
237    XSync(display, False);
238
239    drm_intel_bo_unreference(priv_surface->bo);
240    return Success;
241}
242
243static void flush()
244{
245    struct brw_mi_flush flush;
246    memset(&flush, 0, sizeof(flush));
247    flush.opcode = CMD_MI_FLUSH;
248    flush.flags = (1<<1);
249    BATCH_STRUCT(flush);
250}
251
252static void clear_sf_state()
253{
254    struct brw_sf_unit_state sf;
255    memset(&sf, 0, sizeof(sf));
256    /* TODO */
257}
258
259
260/* urb fence must be aligned to cacheline */
261static void align_urb_fence()
262{
263    BATCH_LOCALS;
264    int i, offset_to_next_cacheline;
265    unsigned long batch_offset;
266    BEGIN_BATCH(3);
267    batch_offset = (void *)batch_ptr - xvmc_driver->alloc.ptr;
268    offset_to_next_cacheline = ALIGN(batch_offset, 64) - batch_offset;
269    if (offset_to_next_cacheline <= 12 && offset_to_next_cacheline != 0) {
270	for (i = 0; i < offset_to_next_cacheline/4; i++)
271	    OUT_BATCH(0);
272	ADVANCE_BATCH();
273    }
274}
275
276/* setup urb layout for media */
277static void urb_layout()
278{
279    BATCH_LOCALS;
280    align_urb_fence();
281    BEGIN_BATCH(3);
282    OUT_BATCH(BRW_URB_FENCE |
283	    UF0_VFE_REALLOC |
284	    UF0_CS_REALLOC |
285	    UF0_SF_REALLOC |
286	    UF0_CLIP_REALLOC |
287	    UF0_GS_REALLOC |
288	    UF0_VS_REALLOC |
289	    1);
290    OUT_BATCH((0 << UF1_CLIP_FENCE_SHIFT) |
291	    (0 << UF1_GS_FENCE_SHIFT) |
292	    (0 << UF1_VS_FENCE_SHIFT));
293
294    OUT_BATCH(((URB_SIZE)<< UF2_VFE_FENCE_SHIFT) |	/* VFE_SIZE */
295	    ((URB_SIZE)<< UF2_CS_FENCE_SHIFT));		/* CS_SIZE is 0 */
296    ADVANCE_BATCH();
297}
298
299static void media_state_pointers(struct media_state *media_state)
300{
301    BATCH_LOCALS;
302    BEGIN_BATCH(3);
303    OUT_BATCH(BRW_MEDIA_STATE_POINTERS|1);
304    OUT_BATCH(0);
305    OUT_RELOC(media_state->vfe_state.bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 0);
306    ADVANCE_BATCH();
307}
308
309/* setup 2D surface for media_read or media_write
310 */
311static Status setup_media_surface(struct media_state *media_state,
312	int surface_num, dri_bo *bo, unsigned long offset, int w, int h, Bool write)
313{
314    struct brw_surface_state s, *ss = &s;
315
316    memset(ss, 0, sizeof(struct brw_surface_state));
317    ss->ss0.surface_type = BRW_SURFACE_2D;
318    ss->ss0.surface_format = BRW_SURFACEFORMAT_R8_SINT;
319    ss->ss1.base_addr = offset + bo->offset;
320    ss->ss2.width = w - 1;
321    ss->ss2.height = h - 1;
322    ss->ss3.pitch = w - 1;
323
324    if (media_state->binding_table.surface_states[surface_num].bo)
325        drm_intel_bo_unreference(media_state->binding_table.surface_states[surface_num].bo);
326    media_state->binding_table.surface_states[surface_num].bo =
327            drm_intel_bo_alloc(xvmc_driver->bufmgr, "surface_state",
328 		sizeof(struct brw_surface_state), 0x1000);
329    if (!media_state->binding_table.surface_states[surface_num].bo)
330        return BadAlloc;
331
332    drm_intel_bo_subdata(
333	    media_state->binding_table.surface_states[surface_num].bo,
334	    0, sizeof(*ss), ss);
335
336    drm_intel_bo_emit_reloc(media_state->binding_table.surface_states[surface_num].bo,
337	    offsetof(struct brw_surface_state, ss1),
338	    bo,
339	    offset,
340	    I915_GEM_DOMAIN_RENDER, write?I915_GEM_DOMAIN_RENDER:0);
341
342    return Success;
343}
344
345static Status setup_surfaces(struct media_state *media_state,
346	dri_bo *dst_bo, dri_bo *past_bo, dri_bo *future_bo,
347	int w, int h)
348{
349    Status ret;
350    ret = setup_media_surface(media_state, 0, dst_bo, 0, w, h, TRUE);
351    if (ret != Success)
352        return ret;
353    ret = setup_media_surface(media_state, 1, dst_bo, w*h, w/2, h/2, TRUE);
354    if (ret != Success)
355        return ret;
356    ret = setup_media_surface(media_state, 2, dst_bo, w*h + w*h/4, w/2, h/2, TRUE);
357    if (ret != Success)
358        return ret;
359    if (past_bo) {
360	ret = setup_media_surface(media_state, 4, past_bo, 0, w, h, FALSE);
361        if (ret != Success)
362            return ret;
363	ret = setup_media_surface(media_state, 5, past_bo, w*h, w/2, h/2, FALSE);
364        if (ret != Success)
365            return ret;
366	ret = setup_media_surface(media_state, 6, past_bo, w*h + w*h/4, w/2, h/2, FALSE);
367        if (ret != Success)
368            return ret;
369    }
370    if (future_bo) {
371	ret = setup_media_surface(media_state, 7, future_bo, 0, w, h, FALSE);
372        if (ret != Success)
373            return ret;
374	ret = setup_media_surface(media_state, 8, future_bo, w*h, w/2, h/2, FALSE);
375        if (ret != Success)
376            return ret;
377	ret = setup_media_surface(media_state, 9, future_bo, w*h + w*h/4, w/2, h/2, FALSE);
378        if (ret != Success)
379            return ret;
380    }
381    return Success;
382}
383/* BUFFER SURFACE has a strange format
384 * the size of the surface is in part of w h and d component
385 */
386
387static Status setup_blocks(struct media_state *media_state, unsigned int block_size)
388{
389    union element{
390		struct {
391			unsigned int w:7;
392			unsigned int h:13;
393			unsigned int d:7;
394			unsigned int pad:7;
395		}whd;
396		unsigned int size;
397    }e;
398    struct brw_surface_state ss;
399    memset(&ss, 0, sizeof(struct brw_surface_state));
400    ss.ss0.surface_type = BRW_SURFACE_BUFFER;
401    ss.ss0.surface_format = BRW_SURFACEFORMAT_R8_UINT;
402    ss.ss1.base_addr = media_state->indirect_data.bo->offset;
403
404    e.size = block_size - 1;
405    ss.ss2.width = e.whd.w;
406    ss.ss2.height = e.whd.h;
407    ss.ss3.depth = e.whd.d;
408    ss.ss3.pitch = block_size - 1;
409
410    if (media_state->binding_table.surface_states[3].bo)
411        drm_intel_bo_unreference(media_state->binding_table.surface_states[3].bo);
412
413    media_state->binding_table.surface_states[3].bo =
414            drm_intel_bo_alloc(xvmc_driver->bufmgr, "surface_state",
415 		sizeof(struct brw_surface_state), 0x1000);
416    if (!media_state->binding_table.surface_states[3].bo)
417        return BadAlloc;
418
419    drm_intel_bo_subdata(media_state->binding_table.surface_states[3].bo, 0,
420	    sizeof(ss), &ss);
421
422    drm_intel_bo_emit_reloc(media_state->binding_table.surface_states[3].bo,
423        offsetof(struct brw_surface_state, ss1),
424        media_state->indirect_data.bo, 0,
425        I915_GEM_DOMAIN_SAMPLER, 0);
426    return Success;
427}
428
429/* setup state base address */
430static void state_base_address()
431{
432    BATCH_LOCALS;
433    BEGIN_BATCH(6);
434    OUT_BATCH(BRW_STATE_BASE_ADDRESS | 4);
435    OUT_BATCH(0 | BASE_ADDRESS_MODIFY);
436    OUT_BATCH(0 | BASE_ADDRESS_MODIFY);
437    OUT_BATCH(0 | BASE_ADDRESS_MODIFY);
438    OUT_BATCH(0 | BASE_ADDRESS_MODIFY);
439    OUT_BATCH(0xFFFFF000|BASE_ADDRESS_MODIFY);
440    ADVANCE_BATCH();
441}
442
443/* select media pipeline */
444static void pipeline_select(struct media_state *media_state)
445{
446    BATCH_LOCALS;
447    BEGIN_BATCH(1);
448    if (media_state->is_g4x)
449	    OUT_BATCH(NEW_PIPELINE_SELECT | PIPELINE_SELECT_MEDIA);
450    else
451	    OUT_BATCH(BRW_PIPELINE_SELECT | PIPELINE_SELECT_MEDIA);
452    ADVANCE_BATCH();
453}
454
455/* kick media object to gpu */
456static void send_media_object(XvMCMacroBlock *mb, int offset, enum interface interface)
457{
458    BATCH_LOCALS;
459    BEGIN_BATCH(13);
460    OUT_BATCH(BRW_MEDIA_OBJECT|11);
461    OUT_BATCH(interface);
462    if (media_state.is_965_q) {
463	OUT_BATCH(0);
464	OUT_BATCH(0);
465    }else {
466	OUT_BATCH(6*128);
467        OUT_RELOC(media_state.indirect_data.bo, I915_GEM_DOMAIN_INSTRUCTION, 0, offset);
468    }
469
470    OUT_BATCH(mb->x<<4);                 //g1.0
471    OUT_BATCH(mb->y<<4);
472    OUT_RELOC(media_state.indirect_data.bo, //g1.8
473            I915_GEM_DOMAIN_INSTRUCTION, 0, offset);
474    OUT_BATCH_SHORT(mb->coded_block_pattern);  //g1.12
475    OUT_BATCH_SHORT(mb->PMV[0][0][0]);         //g1.14
476    OUT_BATCH_SHORT(mb->PMV[0][0][1]);         //g1.16
477    OUT_BATCH_SHORT(mb->PMV[0][1][0]);         //g1.18
478    OUT_BATCH_SHORT(mb->PMV[0][1][1]);         //g1.20
479
480    OUT_BATCH_SHORT(mb->PMV[1][0][0]);         //g1.22
481    OUT_BATCH_SHORT(mb->PMV[1][0][1]);         //g1.24
482    OUT_BATCH_SHORT(mb->PMV[1][1][0]);         //g1.26
483    OUT_BATCH_SHORT(mb->PMV[1][1][1]);         //g1.28
484    OUT_BATCH_CHAR(mb->dct_type);              //g1.30
485    OUT_BATCH_CHAR(mb->motion_vertical_field_select);//g1.31
486
487    if (media_state.is_965_q)
488	OUT_BATCH(0x0);
489    else
490	OUT_BATCH(0xffffffff);
491    ADVANCE_BATCH();
492}
493
494static Status binding_tables(struct media_state *media_state)
495{
496    unsigned int binding_table[MAX_SURFACE_NUM];
497    int i;
498
499    if (media_state->binding_table.bo)
500        drm_intel_bo_unreference(media_state->binding_table.bo);
501    media_state->binding_table.bo =
502 	drm_intel_bo_alloc(xvmc_driver->bufmgr, "binding_table",
503 		MAX_SURFACE_NUM*4, 0x1000);
504    if (!media_state->binding_table.bo)
505        return BadAlloc;
506
507    for (i = 0; i < MAX_SURFACE_NUM; i++)
508	binding_table[i] = media_state->binding_table.surface_states[i].bo->offset;
509    drm_intel_bo_subdata(media_state->binding_table.bo, 0, sizeof(binding_table),
510        binding_table);
511
512    for (i = 0; i < MAX_SURFACE_NUM; i++)
513        drm_intel_bo_emit_reloc(media_state->binding_table.bo,
514	    i * sizeof(unsigned int),
515	    media_state->binding_table.surface_states[i].bo, 0,
516	    I915_GEM_DOMAIN_INSTRUCTION, 0);
517     return Success;
518}
519
520static int media_kernels(struct media_state *media_state)
521{
522	struct kernel_struct *kernels;
523	int kernel_array_size, i;
524
525	if (media_state->is_g4x) {
526		kernels = kernels_igd;
527		kernel_array_size = ARRAY_SIZE(kernels_igd);
528	} else {
529		kernels = kernels_965;
530		kernel_array_size = ARRAY_SIZE(kernels_965);
531	}
532
533	for (i = 0; i < kernel_array_size; i++) {
534		media_state->vfe_state.interface.kernels[i].bo =
535			drm_intel_bo_alloc(xvmc_driver->bufmgr, "kernel",
536					kernels[i].size, 0x1000);
537		if (!media_state->vfe_state.interface.kernels[i].bo)
538			goto out;
539	}
540
541	for (i = 0; i < kernel_array_size; i++) {
542		dri_bo *bo = media_state->vfe_state.interface.kernels[i].bo;
543		drm_intel_bo_subdata(bo, 0, kernels[i].size, kernels[i].bin);
544	}
545	return 0;
546out:
547	free_object(media_state);
548	return BadAlloc;
549}
550
551static void setup_interface(struct media_state *media_state,
552	enum interface i)
553{
554    struct brw_interface_descriptor desc;
555    memset(&desc, 0, sizeof(desc));
556
557    desc.desc0.grf_reg_blocks = 15;
558    desc.desc0.kernel_start_pointer =
559        media_state->vfe_state.interface.kernels[i].bo->offset >> 6;
560
561    desc.desc1.floating_point_mode = BRW_FLOATING_POINT_NON_IEEE_754;
562
563    /* use same binding table for all interface
564     * may change this if it affect performance
565     */
566    desc.desc3.binding_table_entry_count = MAX_SURFACE_NUM;
567    desc.desc3.binding_table_pointer = media_state->binding_table.bo->offset >> 5;
568
569    drm_intel_bo_subdata(media_state->vfe_state.interface.bo, i*sizeof(desc),
570	    sizeof(desc), &desc);
571
572    drm_intel_bo_emit_reloc(
573	    media_state->vfe_state.interface.bo,
574	    i * sizeof(desc) +
575	    offsetof(struct brw_interface_descriptor, desc0),
576	    media_state->vfe_state.interface.kernels[i].bo,
577	    desc.desc0.grf_reg_blocks,
578	    I915_GEM_DOMAIN_INSTRUCTION, 0);
579
580    drm_intel_bo_emit_reloc(
581	    media_state->vfe_state.interface.bo,
582	    i * sizeof(desc) +
583	    offsetof(struct brw_interface_descriptor, desc3),
584	    media_state->binding_table.bo,
585	    desc.desc3.binding_table_entry_count,
586	    I915_GEM_DOMAIN_INSTRUCTION, 0);
587}
588
589static Status interface_descriptor(struct media_state *media_state)
590{
591	if (media_state->vfe_state.interface.bo)
592		drm_intel_bo_unreference(media_state->vfe_state.interface.bo);
593	media_state->vfe_state.interface.bo = drm_intel_bo_alloc(xvmc_driver->bufmgr,
594			"interfaces", DESCRIPTOR_NUM*sizeof(struct brw_interface_descriptor),
595			0x1000);
596	if (!media_state->vfe_state.interface.bo)
597		return BadAlloc;
598
599	setup_interface(media_state, INTRA_INTERFACE);
600	setup_interface(media_state, NULL_INTERFACE);
601	setup_interface(media_state, FORWARD_INTERFACE);
602	setup_interface(media_state, FIELD_FORWARD_INTERFACE);
603	setup_interface(media_state, BACKWARD_INTERFACE);
604	setup_interface(media_state, FIELD_BACKWARD_INTERFACE);
605	setup_interface(media_state, F_B_INTERFACE);
606	setup_interface(media_state, FIELD_F_B_INTERFACE);
607	setup_interface(media_state, DUAL_PRIME_INTERFACE);
608	return Success;
609}
610
611static Status vfe_state(struct media_state *media_state)
612{
613	struct brw_vfe_state state;
614	memset(&state, 0, sizeof(state));
615
616	/* no scratch space */
617	state.vfe1.vfe_mode = VFE_GENERIC_MODE;
618	state.vfe1.num_urb_entries = 1;
619	/* XXX TODO */
620	/* should carefully caculate those values for performance */
621	state.vfe1.urb_entry_alloc_size = 2;
622	state.vfe1.max_threads = 31;
623        state.vfe2.interface_descriptor_base =
624		media_state->vfe_state.interface.bo->offset >> 4;
625
626	if (media_state->vfe_state.bo)
627		drm_intel_bo_unreference(media_state->vfe_state.bo);
628	media_state->vfe_state.bo = drm_intel_bo_alloc(xvmc_driver->bufmgr,
629		"vfe state", sizeof(struct brw_vfe_state), 0x1000);
630	if (!media_state->vfe_state.bo)
631		return BadAlloc;
632
633	drm_intel_bo_subdata(media_state->vfe_state.bo, 0, sizeof(state), &state);
634
635	drm_intel_bo_emit_reloc(media_state->vfe_state.bo,
636		offsetof(struct brw_vfe_state, vfe2),
637		media_state->vfe_state.interface.bo, 0,
638		I915_GEM_DOMAIN_INSTRUCTION, 0);
639	return Success;
640}
641
642static Status render_surface(Display *display,
643	XvMCContext *context,
644	unsigned int picture_structure,
645	XvMCSurface *target_surface,
646	XvMCSurface *past_surface,
647	XvMCSurface *future_surface,
648	unsigned int flags,
649	unsigned int num_macroblocks,
650	unsigned int first_macroblock,
651	XvMCMacroBlockArray *macroblock_array,
652	XvMCBlockArray *blocks)
653{
654
655    intel_xvmc_context_ptr intel_ctx;
656    int i, j;
657    struct i965_xvmc_context *i965_ctx;
658    XvMCMacroBlock *mb;
659    struct i965_xvmc_surface *priv_target_surface =
660	target_surface->privData;
661    struct i965_xvmc_surface *priv_past_surface =
662	past_surface?past_surface->privData:0;
663    struct i965_xvmc_surface *priv_future_surface =
664	future_surface?future_surface->privData:0;
665    unsigned short *block_ptr;
666    intel_ctx = intel_xvmc_find_context(context->context_id);
667    i965_ctx = context->privData;
668    if (!intel_ctx) {
669	XVMC_ERR("Can't find intel xvmc context\n");
670	return BadValue;
671    }
672
673    if (media_state.indirect_data.bo) {
674        if (xvmc_driver->kernel_exec_fencing)
675            drm_intel_gem_bo_unmap_gtt(media_state.indirect_data.bo);
676        else
677            drm_intel_bo_unmap(media_state.indirect_data.bo);
678
679        drm_intel_bo_unreference(media_state.indirect_data.bo);
680    }
681    media_state.indirect_data.bo = drm_intel_bo_alloc(xvmc_driver->bufmgr,
682	    "indirect data", 128*6*num_macroblocks, 64);
683    if (!media_state.indirect_data.bo)
684        return BadAlloc;
685    setup_surfaces(&media_state,
686	    priv_target_surface->bo,
687	    past_surface? priv_past_surface->bo:NULL,
688	    future_surface?priv_future_surface->bo:NULL,
689	    context->width, context->height);
690    setup_blocks(&media_state, 128*6*num_macroblocks);
691    binding_tables(&media_state);
692    interface_descriptor(&media_state);
693    vfe_state(&media_state);
694
695    if (xvmc_driver->kernel_exec_fencing)
696        drm_intel_gem_bo_map_gtt(media_state.indirect_data.bo);
697    else
698        drm_intel_bo_map(media_state.indirect_data.bo, 1);
699
700    block_ptr = media_state.indirect_data.bo->virtual;
701    for (i = first_macroblock;
702	    i < num_macroblocks + first_macroblock; i++) {
703	unsigned short *mb_block_ptr;
704	mb = &macroblock_array->macro_blocks[i];
705	mb_block_ptr = &blocks->blocks[(mb->index<<6)];
706	if (mb->coded_block_pattern & 0x20)  {
707	    for (j = 0; j < 8; j++)
708		memcpy(block_ptr + 16*j, mb_block_ptr + 8*j, 16);
709	    mb_block_ptr += 64;
710	}
711
712	if (mb->coded_block_pattern & 0x10)  {
713	    for (j = 0; j < 8; j++)
714		memcpy(block_ptr + 16*j + 8, mb_block_ptr + 8*j, 16);
715	    mb_block_ptr += 64;
716	}
717	block_ptr += 2*64;
718	if (mb->coded_block_pattern & 0x08)  {
719	    for (j = 0; j < 8; j++)
720		memcpy(block_ptr + 16*j, mb_block_ptr + 8*j, 16);
721	    mb_block_ptr += 64;
722	}
723
724	if (mb->coded_block_pattern & 0x04)  {
725	    for (j = 0; j < 8; j++)
726		memcpy(block_ptr + 16*j + 8, mb_block_ptr + 8*j, 16);
727	    mb_block_ptr += 64;
728	}
729
730	block_ptr += 2*64;
731	if (mb->coded_block_pattern & 0x2) {
732	    memcpy(block_ptr, mb_block_ptr, 128);
733	    mb_block_ptr += 64;
734	}
735
736	block_ptr += 64;
737	if (mb->coded_block_pattern & 0x1)
738	    memcpy(block_ptr, mb_block_ptr, 128);
739	block_ptr += 64;
740    }
741    {
742	int block_offset = 0;
743	LOCK_HARDWARE(intel_ctx->hw_context);
744	state_base_address();
745	flush();
746	clear_sf_state();
747	pipeline_select(&media_state);
748	urb_layout();
749	media_state_pointers(&media_state);
750	for (i = first_macroblock;
751		i < num_macroblocks + first_macroblock;
752		i++, block_offset += 128*6) {
753	    mb = &macroblock_array->macro_blocks[i];
754
755	    if (mb->macroblock_type & XVMC_MB_TYPE_INTRA) {
756		send_media_object(mb, block_offset, INTRA_INTERFACE);
757	    } else {
758		if (((mb->motion_type & 3) == XVMC_PREDICTION_FRAME)) {
759		    if ((mb->macroblock_type&XVMC_MB_TYPE_MOTION_FORWARD))
760		    {
761			if (((mb->macroblock_type&XVMC_MB_TYPE_MOTION_BACKWARD)))
762			    send_media_object(mb, block_offset, F_B_INTERFACE);
763			else
764			    send_media_object(mb, block_offset, FORWARD_INTERFACE);
765		    } else if ((mb->macroblock_type&XVMC_MB_TYPE_MOTION_BACKWARD))
766		    {
767			send_media_object(mb, block_offset, BACKWARD_INTERFACE);
768		    }
769		} else if ((mb->motion_type & 3) == XVMC_PREDICTION_FIELD) {
770		    if ((mb->macroblock_type&XVMC_MB_TYPE_MOTION_FORWARD))
771		    {
772			if (((mb->macroblock_type&XVMC_MB_TYPE_MOTION_BACKWARD)))
773			    send_media_object(mb, block_offset, FIELD_F_B_INTERFACE);
774			else
775
776			    send_media_object(mb, block_offset, FIELD_FORWARD_INTERFACE);
777		    } else if ((mb->macroblock_type&XVMC_MB_TYPE_MOTION_BACKWARD))
778		    {
779			send_media_object(mb, block_offset, FIELD_BACKWARD_INTERFACE);
780		    }
781		}else {
782		    send_media_object(mb, block_offset, DUAL_PRIME_INTERFACE);
783		}
784	    }
785	}
786	intelFlushBatch(TRUE);
787	UNLOCK_HARDWARE(intel_ctx->hw_context);
788    }
789    return Success;
790}
791
792static Status put_surface(Display *display,XvMCSurface *surface,
793	Drawable draw, short srcx, short srcy,
794	unsigned short srcw, unsigned short srch,
795	short destx, short desty,
796	unsigned short destw, unsigned short desth,
797	int flags, struct intel_xvmc_command *data)
798{
799	struct i965_xvmc_surface *private_surface =
800		surface->privData;
801	uint32_t handle = 0;
802
803	drm_intel_bo_flink(private_surface->bo, &handle);
804	data->handle = handle;
805
806	return Success;
807}
808
809static Status get_surface_status(Display *display,
810	XvMCSurface *surface, int *stats)
811{
812    *stats = 0;
813    return 0;
814}
815
816static Status create_context(Display *display, XvMCContext *context,
817	int priv_count, CARD32 *priv_data)
818{
819    struct i965_xvmc_context *i965_ctx;
820    i965_ctx = (struct i965_xvmc_context *)priv_data;
821    context->privData = i965_ctx;
822
823    media_state.is_g4x = i965_ctx->is_g4x;
824    media_state.is_965_q = i965_ctx->is_965_q;
825
826    if (alloc_object(&media_state))
827        return BadAlloc;
828    if (media_kernels(&media_state))
829        return BadAlloc;
830    return Success;
831}
832
833struct _intel_xvmc_driver i965_xvmc_mc_driver = {
834    .type               = XVMC_I965_MPEG2_MC,
835    .create_context     = create_context,
836    .destroy_context    = destroy_context,
837    .create_surface     = create_surface,
838    .destroy_surface    = destroy_surface,
839    .render_surface     = render_surface,
840    .put_surface        = put_surface,
841    .get_surface_status = get_surface_status,
842};
843
844