1/***************************************************************************
2
3Copyright 2001 Intel Corporation.  All Rights Reserved.
4
5Permission is hereby granted, free of charge, to any person obtaining a
6copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sub license, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice (including the
14next paragraph) shall be included in all copies or substantial portions
15of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
23THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25**************************************************************************/
26
27/*************************************************************************
28** File libI810XvMC.c
29**
30** Authors:
31**      Matt Sottek <matthew.j.sottek@intel.com>
32**      Bob Paauwe  <bob.j.paauwe@intel.com>
33**
34**
35***************************************************************************/
36#include <stdio.h>
37#include <stdlib.h>
38#include <unistd.h>
39#include <errno.h>
40#include <signal.h>
41#include <fcntl.h>
42#include <dirent.h>
43#include <string.h>
44
45#include <sys/ioctl.h>
46#include <X11/Xlibint.h>
47#include <fourcc.h>
48#include <X11/extensions/Xv.h>
49#include <X11/extensions/Xvlib.h>
50#include <X11/extensions/XvMC.h>
51#include <X11/extensions/XvMClib.h>
52#include "I810XvMC.h"
53
54static int error_base;
55static int event_base;
56
57/***************************************************************************
58// Function: i810_get_free_buffer
59// Description: Allocates a free dma page using kernel ioctls, then
60//   programs the data into the already allocated dma buffer list.
61// Arguments: pI810XvMC private data structure from the current context.
62// Notes: We faked the drmMapBufs for the i810's security so now we have
63//   to insert an allocated page into the correct spot in the faked
64//   list to keep up appearences.
65//   Concept for this function was taken from Mesa sources.
66// Returns: drmBufPtr containing the information about the allocated page.
67***************************************************************************/
68drmBufPtr i810_get_free_buffer(i810XvMCContext *pI810XvMC) {
69   drmI810DMA dma;
70   drmBufPtr buf;
71
72   dma.granted = 0;
73   dma.request_size = 4096;
74   while(!dma.granted) {
75     if(GET_BUFFER(pI810XvMC, dma) || !dma.granted)
76       FLUSH(pI810XvMC);
77   } /* No DMA granted */
78
79   buf = &(pI810XvMC->dmabufs->list[dma.request_idx]);
80   buf->idx = dma.request_idx;
81   buf->used = 0;
82   buf->total = dma.request_size;
83   buf->address = (drmAddress)dma.virtual;
84   return buf;
85}
86
87/***************************************************************************
88// Function: free_privContext
89// Description: Free's the private context structure if the reference
90//  count is 0.
91***************************************************************************/
92void i810_free_privContext(i810XvMCContext *pI810XvMC) {
93
94  I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT);
95
96
97  pI810XvMC->ref--;
98  if(!pI810XvMC->ref) {
99    drmUnmapBufs(pI810XvMC->dmabufs);
100    drmUnmap(pI810XvMC->overlay.address,pI810XvMC->overlay.size);
101    drmUnmap(pI810XvMC->surfaces.address,pI810XvMC->surfaces.size);
102    drmClose(pI810XvMC->fd);
103
104    free(pI810XvMC->dmabufs->list);
105    free(pI810XvMC);
106  }
107
108  I810_UNLOCK(pI810XvMC);
109}
110
111
112/***************************************************************************
113// Function: XvMCCreateContext
114// Description: Create a XvMC context for the given surface parameters.
115// Arguments:
116//   display - Connection to the X server.
117//   port - XvPortID to use as avertised by the X connection.
118//   surface_type_id - Unique identifier for the Surface type.
119//   width - Width of the surfaces.
120//   height - Height of the surfaces.
121//   flags - one or more of the following
122//      XVMC_DIRECT - A direct rendered context is requested.
123//
124// Notes: surface_type_id and width/height parameters must match those
125//        returned by XvMCListSurfaceTypes.
126// Returns: Status
127***************************************************************************/
128_X_EXPORT Status XvMCCreateContext(Display *display, XvPortID port,
129			 int surface_type_id, int width, int height, int flags,
130			 XvMCContext *context) {
131  i810XvMCContext *pI810XvMC;
132  int priv_count;
133  uint *priv_data;
134  uint magic;
135  Status ret;
136  int major, minor;
137
138  /* Verify Obvious things first */
139  if(context == NULL) {
140    return XvMCBadContext;
141  }
142
143  if(!(flags & XVMC_DIRECT)) {
144    /* Indirect */
145    printf("Indirect Rendering not supported!\nUsing Direct.");
146  }
147
148  /* Limit use to root for now */
149  if(geteuid()) {
150    printf("Use of XvMC on i810 is currently limited to root\n");
151    return BadAccess;
152  }
153
154  /* FIXME: Check $DISPLAY for legal values here */
155
156  context->surface_type_id = surface_type_id;
157  context->width = (unsigned short)width;
158  context->height = (unsigned short)height;
159  context->flags = flags;
160  context->port = port;
161  /*
162     Width, Height, and flags are checked against surface_type_id
163     and port for validity inside the X server, no need to check
164     here.
165  */
166
167  /* Allocate private Context data */
168  context->privData = (void *)malloc(sizeof(i810XvMCContext));
169  if(!context->privData) {
170    printf("Unable to allocate resources for XvMC context.\n");
171    return BadAlloc;
172  }
173  pI810XvMC = (i810XvMCContext *)context->privData;
174
175
176  /* Verify the XvMC extension exists */
177  if(! XvMCQueryExtension(display, &event_base,
178			  &error_base)) {
179    printf("XvMC Extension is not available!\n");
180    return BadAlloc;
181  }
182  /* Verify XvMC version */
183  ret = XvMCQueryVersion(display, &major, &minor);
184  if(ret) {
185    printf("XvMCQuery Version Failed, unable to determine protocol version\n");
186  }
187  /* FIXME: Check Major and Minor here */
188
189  /* Check for drm */
190  if(! drmAvailable()) {
191    printf("Direct Rendering is not avilable on this system!\n");
192    return BadAlloc;
193  }
194
195  /*
196     Build the Attribute Atoms, and Initialize the ones that exist
197     in Xv.
198  */
199  pI810XvMC->xv_colorkey = XInternAtom(display,"XV_COLORKEY",0);
200  if(!pI810XvMC->xv_colorkey) {
201    return XvBadPort;
202  }
203  ret = XvGetPortAttribute(display,port,pI810XvMC->xv_colorkey,
204			   &pI810XvMC->colorkey);
205  if(ret) {
206    return ret;
207  }
208  pI810XvMC->xv_brightness = XInternAtom(display,"XV_BRIGHTNESS",0);
209  pI810XvMC->xv_saturation = XInternAtom(display,"XV_SATURATION",0);
210  pI810XvMC->xv_contrast = XInternAtom(display,"XV_CONTRAST",0);
211  pI810XvMC->brightness = 0;
212  pI810XvMC->saturation = 0x80;  /* 1.0 in 3.7 format */
213  pI810XvMC->contrast = 0x40; /* 1.0 in 3.6 format */
214
215  /* Open DRI Device */
216  if((pI810XvMC->fd = drmOpen("i810",NULL)) < 0) {
217    printf("DRM Device for i810 could not be opened.\n");
218    free(pI810XvMC);
219    return BadAccess;
220  } /* !pI810XvMC->fd */
221
222  /* Get magic number and put it in privData for passing */
223  drmGetMagic(pI810XvMC->fd,&magic);
224  context->flags = (unsigned long)magic;
225
226  /*
227    Pass control to the X server to create a drm_context_t for us and
228    validate the with/height and flags.
229  */
230  if((ret = _xvmc_create_context(display, context, &priv_count, &priv_data))) {
231    printf("Unable to create XvMC Context.\n");
232    return ret;
233  }
234
235  /*
236     X server returns a structure like this:
237     drm_context_t
238     fbBase
239     OverlayOffset
240     OverlaySize
241     SurfacesOffset
242     SurfacesSize
243     busIdString = 9 char + 1
244  */
245  if(priv_count != 9) {
246    printf("_xvmc_create_context() returned incorrect data size!\n");
247    printf("\tExpected 9, got %d\n",priv_count);
248    _xvmc_destroy_context(display, context);
249    free(pI810XvMC);
250    return BadAlloc;
251  }
252  pI810XvMC->drmcontext = priv_data[0];
253  pI810XvMC->fb_base = priv_data[1];
254  pI810XvMC->overlay.offset = priv_data[2] + priv_data[1];
255  pI810XvMC->overlay.size = priv_data[3];
256  pI810XvMC->surfaces.offset = priv_data[4] + priv_data[1];
257  pI810XvMC->surfaces.size = priv_data[5];
258  strncpy(pI810XvMC->busIdString,(char *)&priv_data[6],9);
259  pI810XvMC->busIdString[9] = '\0';
260
261  /* Must free the private data we were passed from X */
262  free(priv_data);
263
264  /* Initialize private context values */
265  pI810XvMC->current = 0;
266  pI810XvMC->lock = 0;
267  pI810XvMC->last_flip = 0;
268  pI810XvMC->dual_prime = 0;
269
270  /*
271     Map dma Buffers: Not really, this would be a drmMapBufs
272     but due to the i810 security model we have to just create an
273     empty data structure to fake it.
274  */
275  pI810XvMC->dmabufs = (drmBufMapPtr)malloc(sizeof(drmBufMap));
276  if(pI810XvMC->dmabufs == NULL) {
277    printf("Dma Bufs could not be mapped.\n");
278    _xvmc_destroy_context(display, context);
279    free(pI810XvMC);
280    return BadAlloc;
281  } /* pI810XvMC->dmabufs == NULL */
282  memset(pI810XvMC->dmabufs, 0, sizeof(drmBufMap));
283  pI810XvMC->dmabufs->list = (drmBufPtr)malloc(sizeof(drmBuf) *
284					       I810_DMA_BUF_NR);
285  if(pI810XvMC->dmabufs->list == NULL) {
286    printf("Dma Bufs could not be mapped.\n");
287    _xvmc_destroy_context(display, context);
288    free(pI810XvMC);
289    return BadAlloc;
290  } /* pI810XvMC->dmabufs->list == NULL */
291  memset(pI810XvMC->dmabufs->list, 0, sizeof(drmBuf) * I810_DMA_BUF_NR);
292
293  /* Map the Overlay memory */
294  if(drmMap(pI810XvMC->fd,pI810XvMC->overlay.offset,
295	    pI810XvMC->overlay.size,&(pI810XvMC->overlay.address)) < 0) {
296    printf("Unable to map Overlay at offset 0x%x and size 0x%x\n",
297	   (unsigned int)pI810XvMC->overlay.offset,pI810XvMC->overlay.size);
298    _xvmc_destroy_context(display, context);
299    free(pI810XvMC->dmabufs->list);
300    free(pI810XvMC);
301    return BadAlloc;
302  } /* drmMap() < 0 */
303
304  /* Overlay Regs are offset 1024 into Overlay Map */
305  pI810XvMC->oregs = (i810OverlayRec *)
306    ((unsigned char *)pI810XvMC->overlay.address + 1024);
307
308  /* Map Surfaces */
309  if(drmMap(pI810XvMC->fd,pI810XvMC->surfaces.offset,
310	    pI810XvMC->surfaces.size,&(pI810XvMC->surfaces.address)) < 0) {
311    printf("Unable to map XvMC Surfaces.\n");
312    _xvmc_destroy_context(display, context);
313    free(pI810XvMC->dmabufs->list);
314    free(pI810XvMC);
315    return BadAlloc;
316  } /* drmMap() < 0 */
317
318  /*
319    There is a tiny chance that someone was using the overlay and
320    issued a flip that hasn't finished. To be 100% sure I'll just
321    take the lock and sleep for the worst case time for a flip.
322  */
323  I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT);
324  usleep(20000);  /* 1/50th Sec for 50hz refresh */
325
326  /* Set up Overlay regs with Initial Values */
327  pI810XvMC->oregs->YRGB_VPH = 0;
328  pI810XvMC->oregs->UV_VPH = 0;
329  pI810XvMC->oregs->HORZ_PH = 0;
330  pI810XvMC->oregs->INIT_PH = 0;
331  pI810XvMC->oregs->DWINPOS = 0;
332  pI810XvMC->oregs->DWINSZ = (I810_XVMC_MAXHEIGHT << 16) |
333    I810_XVMC_MAXWIDTH;
334  pI810XvMC->oregs->SWID =  I810_XVMC_MAXWIDTH | (I810_XVMC_MAXWIDTH << 15);
335  pI810XvMC->oregs->SWIDQW = (I810_XVMC_MAXWIDTH >> 3) |
336    (I810_XVMC_MAXWIDTH << 12);
337  pI810XvMC->oregs->SHEIGHT = I810_XVMC_MAXHEIGHT |
338    (I810_XVMC_MAXHEIGHT << 15);
339  pI810XvMC->oregs->YRGBSCALE = 0x80004000; /* scale factor 1 */
340  pI810XvMC->oregs->UVSCALE = 0x80004000;   /* scale factor 1 */
341  pI810XvMC->oregs->OV0CLRC0 = 0x4000;      /* brightness: 0 contrast: 1.0 */
342  pI810XvMC->oregs->OV0CLRC1 = 0x80;        /* saturation: bypass */
343
344  /* Destination Colorkey Setup */
345  pI810XvMC->oregs->DCLRKV = RGB16ToColorKey(pI810XvMC->colorkey);
346  pI810XvMC->oregs->DCLRKM = 0x80070307;
347
348
349  pI810XvMC->oregs->SCLRKVH = 0;
350  pI810XvMC->oregs->SCLRKVL = 0;
351  pI810XvMC->oregs->SCLRKM = 0; /* source color key disable */
352  pI810XvMC->oregs->OV0CONF = 0; /* two 720 pixel line buffers */
353
354  pI810XvMC->oregs->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION |
355    Y_ADJUST | YUV_420;
356
357  pI810XvMC->ref = 1;
358
359  I810_UNLOCK(pI810XvMC);
360
361  return Success;
362
363}
364
365/***************************************************************************
366// Function: XvMCDestroyContext
367// Description: Destorys the specified context.
368//
369// Arguments:
370//   display - Specifies the connection to the server.
371//   context - The context to be destroyed.
372//
373// Returns: Status
374***************************************************************************/
375_X_EXPORT Status XvMCDestroyContext(Display *display, XvMCContext *context) {
376  i810XvMCContext *pI810XvMC;
377
378  if(context == NULL) {
379    return (error_base + XvMCBadContext);
380  }
381  if(context->privData == NULL) {
382    return (error_base + XvMCBadContext);
383  }
384  pI810XvMC = (i810XvMCContext *)context->privData;
385
386  /* Turn off the overlay */
387  if(pI810XvMC->last_flip) {
388    I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT);
389
390    /* Make sure last flip is done */
391    BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current);
392
393    pI810XvMC->oregs->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION |
394      Y_ADJUST;
395    pI810XvMC->current = !pI810XvMC->current;
396    if(pI810XvMC->current == 1) {
397      pI810XvMC->oregs->OV0CMD |= BUFFER1_FIELD0;
398    }
399    else {
400      pI810XvMC->oregs->OV0CMD |= BUFFER0_FIELD0;
401    }
402    OVERLAY_FLIP(pI810XvMC);
403    pI810XvMC->last_flip++;
404
405    /* Wait for the flip */
406    BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current);
407
408    I810_UNLOCK(pI810XvMC);
409  }
410
411  /* Pass Control to the X server to destroy the drm_context_t */
412  _xvmc_destroy_context(display, context);
413
414  i810_free_privContext(pI810XvMC);
415  context->privData = NULL;
416
417  return Success;
418}
419
420
421/***************************************************************************
422// Function: XvMCCreateSurface
423***************************************************************************/
424_X_EXPORT Status XvMCCreateSurface( Display *display, XvMCContext *context,
425			  XvMCSurface *surface) {
426  i810XvMCContext *pI810XvMC;
427  i810XvMCSurface *pI810Surface;
428  int priv_count;
429  uint *priv_data;
430  Status ret;
431
432  if((surface == NULL) || (context == NULL) || (display == NULL)){
433    return BadValue;
434  }
435
436  pI810XvMC = (i810XvMCContext *)context->privData;
437  if(pI810XvMC == NULL) {
438    return (error_base + XvMCBadContext);
439  }
440
441
442  surface->privData = (i810XvMCSurface *)malloc(sizeof(i810XvMCSurface));
443  if(!surface->privData) {
444    return BadAlloc;
445  }
446  pI810Surface = (i810XvMCSurface *)surface->privData;
447
448  /* Initialize private values */
449  pI810Surface->privContext = pI810XvMC;
450  pI810Surface->last_render = 0;
451  pI810Surface->last_flip = 0;
452  pI810Surface->second_field = 0;
453
454  if((ret = _xvmc_create_surface(display, context, surface,
455				&priv_count, &priv_data))) {
456    free(pI810Surface);
457    printf("Unable to create XvMCSurface.\n");
458    return ret;
459  }
460
461  /*
462    _xvmc_create_subpicture returns 2 uints with the offset into
463    the DRM map for the Y surface and UV surface.
464  */
465  if(priv_count != 2) {
466    printf("_xvmc_create_surface() return incorrect data size.\n");
467    printf("Expected 2 got %d\n",priv_count);
468    free(priv_data);
469    free(pI810Surface);
470    return BadAlloc;
471  }
472  /* Data == Client Address, offset == Physical address offset */
473  pI810Surface->data = pI810XvMC->surfaces.address;
474  pI810Surface->offset = pI810XvMC->surfaces.offset;
475
476
477  /*
478     i810's MC Engine needs surfaces of 2^x (x= 9,10,11,12) pitch
479     and the Tiler need 512k aligned surfaces, basically we are
480     stuck with fixed memory with pitch 1024 for Y data. UV = 512.
481  */
482  pI810Surface->pitch = 10;
483  if((surface->surface_type_id == FOURCC_UYVY) ||
484     (surface->surface_type_id == FOURCC_YUY2)) {
485    /* This is not implemented server side. */
486    pI810Surface->pitch++;
487  }
488
489  /*
490    offsets[0,1,2] == Offsets from either data or offset for the Y
491    U and V surfaces.
492  */
493  pI810Surface->offsets[0] = priv_data[0];
494  if(((unsigned long)pI810Surface->data + pI810Surface->offsets[0]) & 4095) {
495    printf("XvMCCreateSurface: Surface offset 0 is not 4096 aligned\n");
496  }
497
498  if((surface->surface_type_id == FOURCC_UYVY) ||
499     (surface->surface_type_id == FOURCC_YUY2)) {
500    /* Packed surface, not fully implemented */
501    pI810Surface->offsets[1] = 0;
502    pI810Surface->offsets[2] = 0;
503  }
504  else {
505    /* Planar surface */
506    pI810Surface->offsets[1] = priv_data[1];
507    if(((unsigned long)pI810Surface->data + pI810Surface->offsets[1]) & 2047) {
508      printf("XvMCCreateSurface: Surface offset 1 is not 2048 aligned\n");
509    }
510
511    pI810Surface->offsets[2] = ((unsigned long)pI810Surface->offsets[1] +
512				(1<<(pI810Surface->pitch - 1)) * 288);
513    if(((unsigned long)pI810Surface->data + pI810Surface->offsets[2]) & 2047) {
514      printf("XvMCCreateSurface: Surface offset 2 is not 2048 aligned\n");
515    }
516
517  }
518
519  /* Free data returned from xvmc_create_surface */
520  free(priv_data);
521
522  /* Clear the surface to 0 */
523  memset((void *)((unsigned long)pI810Surface->data + (unsigned long)pI810Surface->offsets[0]),
524	 0, ((1<<pI810Surface->pitch) * surface->height));
525
526  switch(surface->surface_type_id) {
527  case FOURCC_YV12:
528  case FOURCC_I420:
529    /* Destination buffer info command */
530    pI810Surface->dbi1y = ((((unsigned int)pI810Surface->offset +
531			     pI810Surface->offsets[0]) & ~0xfc000fff) |
532			   (pI810Surface->pitch - 9));
533    pI810Surface->dbi1u = ((((unsigned int)pI810Surface->offset +
534			     pI810Surface->offsets[1]) & ~0xfc000fff) |
535			   (pI810Surface->pitch - 10));
536    pI810Surface->dbi1v = ((((unsigned int)pI810Surface->offset +
537			     pI810Surface->offsets[2]) & ~0xfc000fff) |
538			   (pI810Surface->pitch - 10));
539
540    /* Destination buffer variables command */
541    pI810Surface->dbv1 = (0x8<<20) | (0x8<<16);
542    /* Map info command */
543    pI810Surface->mi1y = (0x1<<24) | (1<<9) | (pI810Surface->pitch - 3);
544    pI810Surface->mi1u = (0x1<<24) | (1<<9) | (pI810Surface->pitch - 4);
545    pI810Surface->mi1v = (0x1<<24) | (1<<9) | (pI810Surface->pitch - 4);
546
547    pI810Surface->mi2y = (((unsigned int)surface->height - 1)<<16) |
548      ((unsigned int)surface->width - 1);
549    pI810Surface->mi2u = (((unsigned int)surface->height - 1)<<15) |
550      (((unsigned int)surface->width - 1)>>1);
551    pI810Surface->mi2v = pI810Surface->mi2u;
552
553    pI810Surface->mi3y = ((unsigned int)pI810Surface->offset +
554			  pI810Surface->offsets[0]) & ~0x0000000f;
555    pI810Surface->mi3u = ((unsigned int)pI810Surface->offset +
556			  pI810Surface->offsets[1]) & ~0x0000000f;
557    pI810Surface->mi3v = ((unsigned int)pI810Surface->offset +
558			  pI810Surface->offsets[2]) & ~0x0000000f;
559    break;
560  case FOURCC_UYVY:
561  case FOURCC_YUY2:
562  default:
563    /* Destination buffer info command */
564    pI810Surface->dbi1y = ((((unsigned int)pI810Surface->offset +
565			     pI810Surface->offsets[0]) & ~0xfc000fff) |
566			   (pI810Surface->pitch - 9));
567    /* Destination buffer variables command */
568    if(surface->surface_type_id == FOURCC_YUY2) {
569      pI810Surface->dbv1 = 0x5<<8;
570      pI810Surface->mi1y = 0x5<<24 | pI810Surface->pitch | 0x1<<21;
571    }
572    else {
573      pI810Surface->dbv1 = 0x4<<8;
574      pI810Surface->mi1y = 0x5<<24 | (pI810Surface->pitch - 3);
575    }
576    pI810Surface->mi2y = (((unsigned int)surface->width - 1)<<16) |
577      ((unsigned int)surface->height - 1);
578    pI810Surface->mi3y = ((unsigned int)pI810Surface->offset +
579			  pI810Surface->offsets[0]) & ~0xfc000fff;
580    break;
581  }
582  pI810XvMC->ref++;
583
584  return Success;
585}
586
587
588/***************************************************************************
589// Function: XvMCDestroySurface
590***************************************************************************/
591_X_EXPORT Status XvMCDestroySurface(Display *display, XvMCSurface *surface) {
592  i810XvMCSurface *pI810Surface;
593  i810XvMCContext *pI810XvMC;
594
595  if((display == NULL) || (surface == NULL)) {
596    return BadValue;
597  }
598  if(surface->privData == NULL) {
599    return (error_base + XvMCBadSurface);
600  }
601
602  pI810Surface = (i810XvMCSurface *)surface->privData;
603  if(pI810Surface->last_flip) {
604    XvMCSyncSurface(display,surface);
605  }
606  pI810XvMC = (i810XvMCContext *)pI810Surface->privContext;
607
608  _xvmc_destroy_surface(display,surface);
609
610  i810_free_privContext(pI810XvMC);
611
612  free(pI810Surface);
613  surface->privData = NULL;
614  return Success;
615}
616
617/***************************************************************************
618// Function: XvMCCreateBlocks
619***************************************************************************/
620_X_EXPORT Status XvMCCreateBlocks(Display *display, XvMCContext *context,
621			unsigned int num_blocks,
622			XvMCBlockArray *block) {
623
624  if((display == NULL) || (context == NULL) || (num_blocks == 0)) {
625    return BadValue;
626  }
627
628  block->blocks = (short *)malloc(num_blocks<<6 * sizeof(short));
629  if(block->blocks == NULL) {
630    return BadAlloc;
631  }
632
633  block->num_blocks = num_blocks;
634  block->context_id = context->context_id;
635
636  block->privData = NULL;
637
638  return Success;
639}
640
641/***************************************************************************
642// Function: XvMCDestroyBlocks
643***************************************************************************/
644_X_EXPORT Status XvMCDestroyBlocks(Display *display, XvMCBlockArray *block) {
645  if(display == NULL) {
646    return BadValue;
647  }
648
649  free(block->blocks);
650  block->num_blocks = 0;
651  block->context_id = 0;
652  block->privData = NULL;
653  return Success;
654}
655
656/***************************************************************************
657// Function: XvMCCreateMacroBlocks
658***************************************************************************/
659_X_EXPORT Status XvMCCreateMacroBlocks(Display *display, XvMCContext *context,
660			     unsigned int num_blocks,
661			     XvMCMacroBlockArray *blocks) {
662
663  if((display == NULL) || (context == NULL) || (blocks == NULL) ||
664      (num_blocks == 0)) {
665    return BadValue;
666  }
667  memset(blocks,0,sizeof(XvMCMacroBlockArray));
668  blocks->context_id = context->context_id;
669  blocks->privData = NULL;
670
671  blocks->macro_blocks = (XvMCMacroBlock *)
672    malloc(num_blocks * sizeof(XvMCMacroBlock));
673  if(blocks->macro_blocks == NULL) {
674    return BadAlloc;
675  }
676  blocks->num_blocks = num_blocks;
677
678  return Success;
679}
680
681/***************************************************************************
682// Function: XvMCDestroyMacroBlocks
683***************************************************************************/
684_X_EXPORT Status XvMCDestroyMacroBlocks(Display *display, XvMCMacroBlockArray *block) {
685  if((display == NULL) || (block == NULL)) {
686    return BadValue;
687  }
688  if(block->macro_blocks) {
689    free(block->macro_blocks);
690  }
691  block->context_id = 0;
692  block->num_blocks = 0;
693  block->privData = NULL;
694
695  return Success;
696}
697
698
699/***************************************************************************
700// Function: dp (Debug Print)
701// Description: This function prints out in hex i * uint32_t at the address
702//  supplied. This enables you to print out the dma buffers from
703//  within the debugger even though they are not in your address space.
704***************************************************************************/
705void dp(unsigned int *address, unsigned int i) {
706  int j;
707
708  printf("DebugPrint:\n");
709  for(j=0; j<i; j++) {
710    printf("0x%8.8x ",address[j]);
711    if(j && !(j & 7)) { printf("\n");}
712  }
713}
714
715/***************************************************************************
716// Macro: PACK_*
717// Description: Packs 16bit signed data from blocks into either 8bit unsigned
718//  intra data or 16bit signed correction data, both packed into
719//  32 bit integers.
720***************************************************************************/
721#define PACK_INTRA_DATA(d,b,n)                  \
722  do {                                          \
723   char *dp = (char *)d;                        \
724   char *bp = (char *)b;                        \
725   int counter;                                 \
726   for(counter = 0; counter < n; counter++) {   \
727     *dp++ = *bp;                               \
728     bp += 2;                                   \
729   }                                            \
730  }while(0);
731
732#define PACK_CORR_DATA(d,b,n)          \
733            memcpy(d,b,n);             \
734            d = (uint *)((unsigned long)d + n);
735
736#define MARK_CORR_DATA(d,n)                          \
737            do {                                     \
738              uint* q = (uint*)((unsigned long)d - n);        \
739              while((unsigned long)q < (unsigned long)d) {             \
740               *q++ += 0x00330033;                   \
741              }                                      \
742	    }while(0);
743
744#define MARK_INTRA_BLOCK(d)         \
745           do {                     \
746             int q;                 \
747             for(q=0; q<16; q++) {  \
748               d[q] += 0x33333333;  \
749             }                      \
750	    }while(0);
751
752/*
753  Used for DCT 1 when we need DCT 0. Instead
754  of reading from one block we read from two and
755  interlace.
756*/
757#define PACK_CORR_DATA_1to0(d,top,bottom)            \
758            do {                                     \
759              short *t = top,*b = bottom;            \
760              PACK_CORR_DATA(d,t,16);                \
761              t = (short *)((unsigned long)t + 16);           \
762              PACK_CORR_DATA(d,b,16);                \
763              b = (short *)((unsigned long)b + 16);           \
764              PACK_CORR_DATA(d,t,16);                \
765              t = (short *)((unsigned long)t + 16);           \
766              PACK_CORR_DATA(d,b,16);                \
767              b = (short *)((unsigned long)b + 16);           \
768              PACK_CORR_DATA(d,t,16);                \
769              t = (short *)((unsigned long)t + 16);           \
770              PACK_CORR_DATA(d,b,16);                \
771              b = (short *)((unsigned long)b + 16);           \
772              PACK_CORR_DATA(d,t,16);                \
773              t = (short *)((unsigned long)t + 16);           \
774              PACK_CORR_DATA(d,b,16);                \
775              b = (short *)((unsigned long)b + 16);           \
776            }while(0);
777
778/* Used for DCT 0 when we need DCT 1. */
779#define PACK_CORR_DATA_0to1(d,top,bottom)            \
780            do{                                      \
781              short *t = top,*b = bottom;            \
782              PACK_CORR_DATA(d,t,16);                \
783              t = (short *)((unsigned long)t + 32);           \
784              PACK_CORR_DATA(d,t,16);                \
785              t = (short *)((unsigned long)t + 32);           \
786              PACK_CORR_DATA(d,t,16);                \
787              t = (short *)((unsigned long)t + 32);           \
788              PACK_CORR_DATA(d,t,16);                \
789              t = (short *)((unsigned long)t + 32);           \
790              PACK_CORR_DATA(d,b,16);                \
791              b = (short *)((unsigned long)b + 32);           \
792              PACK_CORR_DATA(d,b,16);                \
793              b = (short *)((unsigned long)b + 32);           \
794              PACK_CORR_DATA(d,b,16);                \
795              b = (short *)((unsigned long)b + 32);           \
796              PACK_CORR_DATA(d,b,16);                \
797              b = (short *)((unsigned long)b + 32);           \
798            }while(0);
799
800#define PACK_CORR_DATA_SHORT(d,block)                \
801            do {                                     \
802              short *b = block;                      \
803              PACK_CORR_DATA(d,b,16);                \
804              b = (short *)((unsigned long)b + 32);           \
805              PACK_CORR_DATA(d,b,16);                \
806              b = (short *)((unsigned long)b + 32);           \
807              PACK_CORR_DATA(d,b,16);                \
808              b = (short *)((unsigned long)b + 32);           \
809              PACK_CORR_DATA(d,b,16);                \
810              b = (short *)((unsigned long)b + 32);           \
811            }while(0);
812
813/* Lookup tables to speed common calculations */
814static unsigned int drps_table[] = {2<<6,3<<6};
815
816static unsigned int mvfs_table[] = {
817  0x12,
818  0x1a,
819  0x13,
820  0x1b
821};
822
823static unsigned int type_table[] = {
824  0x1<<12,   /* This is an error so make it Forward motion */
825  0x1<<12,
826  0x1<<12,
827  0x1<<12,
828  0x2<<12,
829  0x2<<12,
830  0x3<<12,
831  0x3<<12,
832  0x1<<12,  /* Pattern but no Motion, Make motion Forward */
833  0x1<<12,
834  0x1<<12,
835  0x1<<12,
836  0x2<<12,
837  0x2<<12,
838  0x3<<12,
839  0x3<<12
840};
841
842static unsigned int y_frame_bytes[] = {
843  0,0,0,0,128,128,128,128,
844  128,128,128,128,256,256,256,256,
845  128,128,128,128,256,256,256,256,
846  256,256,256,256,384,384,384,384,
847  128,128,128,128,256,256,256,256,
848  256,256,256,256,384,384,384,384,
849  256,256,256,256,384,384,384,384,
850  384,384,384,384,512,512,512,512
851};
852
853static unsigned int u_frame_bytes[] = {
854  0,0,128,128,0,0,128,128,
855  0,0,128,128,0,0,128,128,
856  0,0,128,128,0,0,128,128,
857  0,0,128,128,0,0,128,128,
858  0,0,128,128,0,0,128,128,
859  0,0,128,128,0,0,128,128,
860  0,0,128,128,0,0,128,128,
861  0,0,128,128,0,0,128,128
862};
863
864static unsigned int v_frame_bytes[] = {
865  0,128,0,128,0,128,0,128,
866  0,128,0,128,0,128,0,128,
867  0,128,0,128,0,128,0,128,
868  0,128,0,128,0,128,0,128,
869  0,128,0,128,0,128,0,128,
870  0,128,0,128,0,128,0,128,
871  0,128,0,128,0,128,0,128,
872  0,128,0,128,0,128,0,128
873};
874
875static unsigned int y_first_field_bytes[] = {
876  0,0,0,0,0,0,0,0,
877  0,0,0,0,0,0,0,0,
878  128,128,128,128,128,128,128,128,
879  128,128,128,128,128,128,128,128,
880  128,128,128,128,128,128,128,128,
881  128,128,128,128,128,128,128,128,
882  256,256,256,256,256,256,256,256,
883  256,256,256,256,256,256,256,256
884};
885
886static unsigned int y_second_field_bytes[] = {
887  0,0,0,0,128,128,128,128,
888  128,128,128,128,256,256,256,256,
889  0,0,0,0,128,128,128,128,
890  128,128,128,128,256,256,256,256,
891  0,0,0,0,128,128,128,128,
892  128,128,128,128,256,256,256,256,
893  0,0,0,0,128,128,128,128,
894  128,128,128,128,256,256,256,256
895};
896
897static unsigned int y_dct0_field_bytes[] = {
898  0,0,0,0,128,128,128,128,
899  128,128,128,128,256,256,256,256,
900  128,128,128,128,128,128,128,128,
901  256,256,256,256,256,256,256,256,
902  128,128,128,128,256,256,256,256,
903  128,128,128,128,256,256,256,256,
904  256,256,256,256,256,256,256,256,
905  256,256,256,256,256,256,256,256
906};
907
908static unsigned int y_dct1_frame_bytes[] = {
909  0,0,0,0,256,256,256,256,
910  256,256,256,256,512,512,512,512,
911  256,256,256,256,256,256,256,256,
912  512,512,512,512,512,512,512,512,
913  256,256,256,256,512,512,512,512,
914  256,256,256,256,512,512,512,512,
915  512,512,512,512,512,512,512,512,
916  512,512,512,512,512,512,512,512
917};
918
919static unsigned int u_field_bytes[] = {
920  0,0,64,64,0,0,64,64,
921  0,0,64,64,0,0,64,64,
922  0,0,64,64,0,0,64,64,
923  0,0,64,64,0,0,64,64,
924  0,0,64,64,0,0,64,64,
925  0,0,64,64,0,0,64,64,
926  0,0,64,64,0,0,64,64,
927  0,0,64,64,0,0,64,64
928};
929
930static unsigned int v_field_bytes[] = {
931  0,64,0,64,0,64,0,64,
932  0,64,0,64,0,64,0,64,
933  0,64,0,64,0,64,0,64,
934  0,64,0,64,0,64,0,64,
935  0,64,0,64,0,64,0,64,
936  0,64,0,64,0,64,0,64,
937  0,64,0,64,0,64,0,64,
938  0,64,0,64,0,64,0,64
939};
940
941static short empty_block[] = {
942  0,0,0,0,0,0,0,0,
943  0,0,0,0,0,0,0,0,
944  0,0,0,0,0,0,0,0,
945  0,0,0,0,0,0,0,0,
946  0,0,0,0,0,0,0,0,
947  0,0,0,0,0,0,0,0,
948  0,0,0,0,0,0,0,0,
949  0,0,0,0,0,0,0,0
950};
951
952
953/***************************************************************************
954// Function: dispatchYContext
955// Description: Allocate a DMA buffer write the Y MC Context info in it,
956//  and dispatch it to hardware.
957***************************************************************************/
958
959static __inline__ void dispatchYContext(i810XvMCSurface *privTarget,
960					i810XvMCSurface *privPast,
961					i810XvMCSurface *privFuture,
962					i810XvMCContext *pI810XvMC) {
963  uint *data;
964  drmBufPtr pDMA;
965  drm_i810_mc_t mc;
966
967  pDMA = i810_get_free_buffer(pI810XvMC);
968  data = pDMA->address;
969  *data++ = CMD_FLUSH;
970  *data++ = BOOLEAN_ENA_2;
971  *data++ = CMD_FLUSH;
972  *data++ = DEST_BUFFER_INFO;
973  *data++ = privTarget->dbi1y;
974  *data++ = DEST_BUFFER_VAR;
975  *data++ = privTarget->dbv1;
976  /* Past Surface */
977  *data++ = CMD_MAP_INFO;
978  *data++ = privPast->mi1y;
979  *data++ = privPast->mi2y;
980  *data++ = privPast->mi3y;
981  /* Future Surface */
982  *data++ = CMD_MAP_INFO;
983  *data++ = privFuture->mi1y | 0x1<<28;
984  *data++ = privFuture->mi2y;
985  *data++ = privFuture->mi3y;
986
987  mc.idx = pDMA->idx;
988  mc.used = (unsigned long)data - (unsigned long)pDMA->address;
989  mc.last_render = ++pI810XvMC->last_render;
990  privTarget->last_render = pI810XvMC->last_render;
991  I810_MC(pI810XvMC,mc);
992}
993
994static __inline__ void renderError(void) {
995  printf("Invalid Macroblock Parameters found.\n");
996  return;
997}
998
999/***************************************************************************
1000// Function: renderIntrainFrame
1001// Description: inline function that sets hardware parameters for an Intra
1002//  encoded macroblock in a Frame picture.
1003***************************************************************************/
1004static __inline__ void renderIntrainFrame(uint **datay,uint **datau,
1005					  uint **datav,
1006					  XvMCMacroBlock *mb,
1007					  short *block_ptr) {
1008
1009  register uint *dy = *datay;
1010  register uint *du = *datau;
1011  register uint *dv = *datav;
1012
1013  /* Y Blocks */
1014  *dy++ = GFXBLOCK + 68;
1015  *dy++ = (1<<30) | (3<<28) | (0xf<<24);
1016  *dy++ = ((uint)mb->x<<20) | ((uint)mb->y<<4);
1017  *dy++ = (16<<16) | 16;
1018  *dy++ = 0;
1019  *dy++ = 0;
1020  PACK_INTRA_DATA(dy,block_ptr,256);
1021  dy += 64;
1022  block_ptr += 256;
1023  /* End Y Blocks */
1024
1025  /* U Block */
1026  *du++ = GFXBLOCK + 20;
1027  *du++ = (2<<30) | (1<<28) | (1<<23);
1028  *du++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3);
1029  *du++ = (8<<16) | 8;
1030  *du++ = 0;
1031  *du++ = 0;
1032  PACK_INTRA_DATA(du,block_ptr,64);
1033  du += 16;
1034  block_ptr += 64;
1035
1036  /* V Block */
1037  *dv++ = GFXBLOCK + 20;
1038  *dv++ = (3<<30) | (1<<28) | (1<<22);
1039  *dv++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3);
1040  *dv++ = (8<<16) | 8;
1041  *dv++ = 0;
1042  *dv++ = 0;
1043  PACK_INTRA_DATA(dv,block_ptr,64);
1044  dv += 16;
1045  block_ptr += 64;
1046
1047  *datay = dy;
1048  *datau = du;
1049  *datav = dv;
1050}
1051
1052/***************************************************************************
1053// Function: renderIntrainFrameDCT1
1054// Description: inline function that sets hardware parameters for an Intra
1055//  encoded macroblock in a Frame picture with DCT type 1.
1056***************************************************************************/
1057static __inline__ void renderIntrainFrameDCT1(uint **datay,uint **datau,
1058					      uint **datav,XvMCMacroBlock *mb,
1059					      short *block_ptr,uint flags) {
1060
1061  register uint *dy = *datay;
1062  register uint *du = *datau;
1063  register uint *dv = *datav;
1064
1065
1066  /* Y Blocks */
1067  *dy++ = GFXBLOCK + 36;
1068  *dy++ = (1<<30) | (2<<28) | (0x3<<26) | (0x2<<6);
1069  *dy++ = ((uint)mb->x<<20) | ((uint)mb->y<<3);
1070  *dy++ = (8<<16) | 16;
1071  *dy++ = 0;
1072  *dy++ = 0;
1073  PACK_INTRA_DATA(dy,block_ptr,128);
1074  dy += 32;
1075  block_ptr += 128;
1076
1077  /* Second Y block */
1078  *dy++ = GFXBLOCK + 36;
1079  *dy++ = (1<<30) | (2<<28) | (0x3<<26) | (0x3<<6);
1080  *dy++ = ((uint)mb->x<<20) | ((uint)mb->y<<3);
1081  *dy++ = (8<<16) | 16;
1082  *dy++ = 0;
1083  *dy++ = 0;
1084  PACK_INTRA_DATA(dy,block_ptr,128);
1085  dy += 32;
1086  block_ptr += 128;
1087  /* End Y Blocks */
1088
1089
1090  /* U Block */
1091  *du++ = GFXBLOCK + 20;
1092  *du++ = (2<<30) | (1<<28) | (1<<23);
1093  *du++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3);
1094  *du++ = (8<<16) | 8;
1095  *du++ = 0;
1096  *du++ = 0;
1097  PACK_INTRA_DATA(du,block_ptr,64);
1098  du += 16;
1099  block_ptr += 64;
1100
1101  /* V Block */
1102  *dv++ = GFXBLOCK + 20;
1103  *dv++ = (3<<30) | (1<<28) | (1<<22);
1104  *dv++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3);
1105  *dv++ = (8<<16) | 8;
1106  *dv++ = 0;
1107  *dv++ = 0;
1108  PACK_INTRA_DATA(dv,block_ptr,64);
1109  dv += 16;
1110  block_ptr += 64;
1111
1112  *datay = dy;
1113  *datau = du;
1114  *datav = dv;
1115}
1116
1117
1118/***************************************************************************
1119// Function: renderIntrainField
1120// Description: inline function that sets hardware parameters for an Intra
1121//  encoded macroblock in Field pictures.
1122***************************************************************************/
1123static __inline__ void renderIntrainField(uint **datay,uint **datau,
1124					  uint **datav,
1125					  XvMCMacroBlock *mb,short *block_ptr,
1126					  uint ps) {
1127
1128  register uint *dy = *datay;
1129  register uint *du = *datau;
1130  register uint *dv = *datav;
1131
1132  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4);
1133  uint dw1 = drps_table[~ps & 0x1];
1134
1135  /* Y Blocks */
1136  *dy++ = GFXBLOCK + 68;
1137  *dy++ = (1<<30) | (3<<28) | (0xf<<24) | dw1;
1138  *dy++ = xy;
1139  *dy++ = (16<<16) | 16;
1140  *dy++ = 0;
1141  *dy++ = 0;
1142  PACK_INTRA_DATA(dy,block_ptr,256);
1143  dy += 64;
1144  block_ptr += 256;
1145  /* End Y Blocks */
1146
1147  xy >>= 1;
1148
1149  /* U Block */
1150  *du++ = GFXBLOCK + 20;
1151  *du++ = (2<<30) | (1<<28) | (1<<23) | dw1;
1152  *du++ = xy;
1153  *du++ = (8<<16) | 8;
1154  *du++ = 0;
1155  *du++ = 0;
1156  PACK_INTRA_DATA(du,block_ptr,64);
1157  du += 16;
1158  block_ptr += 64;
1159
1160  /* V Block */
1161  *dv++ = GFXBLOCK + 20;
1162  *dv++ = (3<<30) | (1<<28) | (1<<22) | dw1;
1163  *dv++ = xy;
1164  *dv++ = (8<<16) | 8;
1165  *dv++ = 0;
1166  *dv++ = 0;
1167  PACK_INTRA_DATA(dv,block_ptr,64);
1168  dv += 16;
1169  block_ptr += 64;
1170
1171  *datay = dy;
1172  *datau = du;
1173  *datav = dv;
1174}
1175
1176
1177/***************************************************************************
1178// Function: renderFieldinField
1179// Description: inline function that sets hardware parameters for a Field
1180//  encoded macroblock in a Field Picture.
1181***************************************************************************/
1182static __inline__ void renderFieldinField(uint **datay,uint **datau,
1183					  uint **datav,
1184					  XvMCMacroBlock *mb,short *block_ptr,
1185					  uint ps, uint flags) {
1186
1187  register uint *dy = *datay;
1188  register uint *du = *datau;
1189  register uint *dv = *datav;
1190
1191  /* Motion Vectors */
1192  short fmv[2];
1193  short bmv[2];
1194  /* gfxblock dword 1 */
1195  uint dw1;
1196
1197  uint parity = ~ps & XVMC_TOP_FIELD;
1198
1199  uint ysize = y_frame_bytes[mb->coded_block_pattern];
1200  uint usize = u_frame_bytes[mb->coded_block_pattern];
1201  uint vsize = v_frame_bytes[mb->coded_block_pattern];
1202
1203  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4);
1204
1205  /* i810 Specific flag used to identify the second field in a P frame */
1206  if(flags & 0x80000000) {
1207    /* P Frame */
1208    if((mb->motion_vertical_field_select & XVMC_SELECT_FIRST_FORWARD) ==
1209      parity) {
1210      /* Same parity, use reference field (map0) */
1211      dw1 = 1<<12 | ((0x2 + parity)<<6) | ((0x2 + parity)<<3) |
1212	(((uint)mb->coded_block_pattern)<<22);
1213      fmv[0] = mb->PMV[0][0][1];
1214      fmv[1] = mb->PMV[0][0][0];
1215      bmv[0] = 0;
1216      bmv[1] = 0;
1217    }
1218    else {
1219      /*
1220	Opposite parity, set up as if it were backward
1221	motion and use map1.
1222      */
1223      dw1 = 2<<12 | ((0x2 + parity)<<6) | (0x3 - parity) |
1224	(((uint)mb->coded_block_pattern)<<22);
1225      bmv[0] = mb->PMV[0][0][1];
1226      bmv[1] = mb->PMV[0][0][0];
1227      fmv[0] = 0;
1228      fmv[1] = 0;
1229    }
1230  }
1231  else {
1232    dw1 = type_table[mb->macroblock_type & 0xf] |
1233      drps_table[~ps & 0x1] |
1234      mvfs_table[mb->motion_vertical_field_select & 3] |
1235      (((uint)mb->coded_block_pattern)<<22);
1236
1237    fmv[0] = mb->PMV[0][0][1];
1238    fmv[1] = mb->PMV[0][0][0];
1239
1240    bmv[0] = mb->PMV[0][1][1];
1241    bmv[1] = mb->PMV[0][1][0];
1242  }
1243
1244  /* Y Block */
1245  *dy++ = GFXBLOCK + 4 + (ysize>>2);
1246  *dy++ = (1<<30) | (3<<28) | dw1;
1247  *dy++ = xy;
1248  *dy++ = (16<<16) | 16;
1249  *dy++ = *(uint *)fmv;
1250  *dy++ = *(uint *)bmv;
1251  PACK_CORR_DATA(dy,block_ptr,ysize);
1252  block_ptr = (short *)((unsigned long)block_ptr + ysize);
1253  /* End Y Blocks */
1254
1255  fmv[0] /= 2;
1256  fmv[1] /= 2;
1257  bmv[0] /= 2;
1258  bmv[1] /= 2;
1259  xy >>= 1;
1260
1261  /* U Block */
1262  *du++ = GFXBLOCK + 4 + (usize>>2);
1263  *du++ = (2<<30) | (1<<28) | dw1;
1264  *du++ = xy;
1265  *du++ = (8<<16) | 8;
1266  *du++ = *(uint *)fmv;
1267  *du++ = *(uint *)bmv;
1268  PACK_CORR_DATA(du,block_ptr,usize);
1269  block_ptr = (short *)((unsigned long)block_ptr + usize);
1270
1271  /* V Block */
1272  *dv++ = GFXBLOCK + 4 + (vsize>>2);
1273  *dv++ = (3<<30) | (1<<28) | dw1;
1274  *dv++ = xy;
1275  *dv++ = (8<<16) | 8;
1276  *dv++ = *(uint *)fmv;
1277  *dv++ = *(uint *)bmv;
1278  PACK_CORR_DATA(dv,block_ptr,vsize);
1279  block_ptr = (short *)((unsigned long)block_ptr + vsize);
1280
1281  *datay = dy;
1282  *datau = du;
1283  *datav = dv;
1284}
1285
1286/***************************************************************************
1287// Function: render16x8inField
1288// Description: inline function that sets hardware parameters for a 16x8
1289//  encoded macroblock in a field picture.
1290***************************************************************************/
1291static __inline__ void render16x8inField(uint **datay,uint **datau,
1292					 uint **datav,
1293					 XvMCMacroBlock *mb,short *block_ptr,
1294					 uint ps, uint flags) {
1295
1296  register uint *dy = *datay;
1297  register uint *du = *datau;
1298  register uint *dv = *datav;
1299
1300  /* Motion Vectors */
1301  short fmv[4];
1302  short bmv[4];
1303  /* gfxblock dword 1 */
1304  uint dw1[2];
1305
1306  uint y1size = y_first_field_bytes[mb->coded_block_pattern];
1307  uint y2size = y_second_field_bytes[mb->coded_block_pattern];
1308  uint usize = u_field_bytes[mb->coded_block_pattern];
1309  uint vsize = v_field_bytes[mb->coded_block_pattern];
1310
1311  uint parity = ~ps & XVMC_TOP_FIELD;
1312
1313  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4);
1314
1315  /* i810 Specific flag used to identify the second field in a P frame */
1316  if(flags & 0x80000000) {
1317    /* P Frame */
1318    if((mb->motion_vertical_field_select & XVMC_SELECT_FIRST_FORWARD) ==
1319      parity) {
1320      /* Same parity, use reference field (map0) */
1321      dw1[0] = 1<<12 | ((0x2 + parity)<<6) | ((0x2 + parity)<<3) |
1322	(((uint)mb->coded_block_pattern)<<22);
1323
1324      fmv[0] = mb->PMV[0][0][1];
1325      fmv[1] = mb->PMV[0][0][0];
1326      bmv[0] = 0;
1327      bmv[1] = 0;
1328    }
1329    else {
1330      /*
1331	Opposite parity, set up as if it were backward
1332	motion and use map1.
1333      */
1334      dw1[0] = 2<<12 | ((0x2 + parity)<<6) | (0x3 - parity) |
1335	(((uint)mb->coded_block_pattern)<<22);
1336
1337      bmv[0] = mb->PMV[0][0][1];
1338      bmv[1] = mb->PMV[0][0][0];
1339      fmv[0] = 0;
1340      fmv[1] = 0;
1341    }
1342    if((mb->motion_vertical_field_select & XVMC_SELECT_SECOND_FORWARD) ==
1343       (parity<<2)) {
1344      /* Same parity, use reference field (map0) */
1345      dw1[1] = 1<<12 | ((0x2 + parity)<<6) | ((0x2 + parity)<<3) |
1346	((((uint)mb->coded_block_pattern<<22) & (0x3<<22)) |
1347	 (((uint)mb->coded_block_pattern<<24) & (0x3<<26)));
1348
1349      fmv[2] = mb->PMV[1][0][1];
1350      fmv[3] = mb->PMV[1][0][0];
1351      bmv[2] = 0;
1352      bmv[3] = 0;
1353    }
1354    else {
1355      /*
1356	 Opposite parity, set up as if it were backward
1357	 motion and use map1.
1358      */
1359      dw1[1] = 2<<12 | ((0x2 + parity)<<6) | (0x3 - parity) |
1360	((((uint)mb->coded_block_pattern<<22) & (0x3<<22)) |
1361	 (((uint)mb->coded_block_pattern<<24) & (0x3<<26)));
1362
1363      bmv[2] = mb->PMV[1][0][1];
1364      bmv[3] = mb->PMV[1][0][0];
1365      fmv[2] = 0;
1366      fmv[3] = 0;
1367    }
1368  }
1369  else {
1370    dw1[0] = type_table[mb->macroblock_type & 0xf] |
1371      drps_table[~ps & 0x1] |
1372      mvfs_table[mb->motion_vertical_field_select & 3] |
1373      (((uint)mb->coded_block_pattern)<<22);
1374
1375    dw1[1] = type_table[mb->macroblock_type & 0xf] |
1376      drps_table[~ps & 0x1] |
1377      mvfs_table[(mb->motion_vertical_field_select>>2) & 0x3] |
1378      ((((uint)mb->coded_block_pattern<<22) & (0x3<<22)) |
1379       (((uint)mb->coded_block_pattern<<24) & (0x3<<26)));
1380
1381    fmv[0] = mb->PMV[0][0][1];
1382    fmv[1] = mb->PMV[0][0][0];
1383    fmv[2] = mb->PMV[1][0][1];
1384    fmv[3] = mb->PMV[1][0][0];
1385
1386    bmv[0] = mb->PMV[0][1][1];
1387    bmv[1] = mb->PMV[0][1][0];
1388    bmv[2] = mb->PMV[1][1][1];
1389    bmv[3] = mb->PMV[1][1][0];
1390  }
1391
1392  /* First Y Block */
1393  *dy++ = GFXBLOCK + 4 + (y1size>>2);
1394  *dy++ = (1<<30) | (2<<28) | dw1[0];
1395  *dy++ = xy;
1396  *dy++ = (8<<16) | 16;
1397  *dy++ = *(uint *)fmv;
1398  *dy++ = *(uint *)bmv;
1399  PACK_CORR_DATA(dy,block_ptr,y1size);
1400  block_ptr = (short *)((unsigned long)block_ptr + y1size);
1401
1402  /* Second Y Block */
1403  *dy++ = GFXBLOCK + 4 + (y2size>>2);
1404  *dy++ = (1<<30) | (2<<28) | dw1[1];
1405  *dy++ = (xy + 8);
1406  *dy++ = (8<<16) | 16;
1407  *dy++ = *(uint *)&fmv[2];
1408  *dy++ = *(uint *)&bmv[2];
1409  PACK_CORR_DATA(dy,block_ptr,y2size);
1410  block_ptr = (short *)((unsigned long)block_ptr + y2size);
1411  /* End Y Blocks */
1412
1413  fmv[0] /= 2;
1414  fmv[1] /= 2;
1415  fmv[2] /= 2;
1416  fmv[3] /= 2;
1417
1418  bmv[0] /= 2;
1419  bmv[1] /= 2;
1420  bmv[2] /= 2;
1421  bmv[3] /= 2;
1422
1423  xy >>= 1;
1424
1425  /* U Blocks */
1426  *du++ = GFXBLOCK + 4 + (usize>>2);
1427  *du++ = (2<<30) | (1<<28) | dw1[0];
1428  *du++ = xy;
1429  *du++ = (4<<16) | 8;
1430  *du++ = *(uint *)fmv;
1431  *du++ = *(uint *)bmv;
1432  PACK_CORR_DATA(du,block_ptr,usize);
1433  block_ptr = (short *)((unsigned long)block_ptr + usize);
1434
1435  /* Second U block */
1436  *du++ = GFXBLOCK + 4 + (usize>>2);
1437  *du++ = (2<<30) | (1<<28) | dw1[1];
1438  *du++ = (xy + 4);
1439  *du++ = (4<<16) | 8;
1440  *du++ = *(uint *)&fmv[2];
1441  *du++ = *(uint *)&bmv[2];
1442  PACK_CORR_DATA(du,block_ptr,usize);
1443  block_ptr = (short *)((unsigned long)block_ptr + usize);
1444  /* End U Blocks */
1445
1446  /* V Blocks */
1447  *dv++ = GFXBLOCK + 4 + (vsize>>2);
1448  *dv++ = (3<<30) | (1<<28) | dw1[0];
1449  *dv++ = xy;
1450  *dv++ = (4<<16) | 8;
1451  *dv++ = *(uint *)fmv;
1452  *dv++ = *(uint *)bmv;
1453  PACK_CORR_DATA(dv,block_ptr,vsize);
1454  block_ptr = (short *)((unsigned long)block_ptr + vsize);
1455
1456  /* Second V Block */
1457  *dv++ = GFXBLOCK + 4 + (vsize>>2);
1458  *dv++ = (3<<30) | (1<<28) | dw1[1];
1459  *dv++ = (xy + 4);
1460  *dv++ = (4<<16) | 8;
1461  *dv++ = *(uint *)&fmv[2];
1462  *dv++ = *(uint *)&bmv[2];
1463  PACK_CORR_DATA(dv,block_ptr,vsize);
1464  block_ptr = (short *)((unsigned long)block_ptr + vsize);
1465  /* End V Blocks */
1466
1467  *datay = dy;
1468  *datau = du;
1469  *datav = dv;
1470}
1471
1472/***************************************************************************
1473// Function: renderDualPrimeinField
1474// Description: inline function that sets hardware parameters for a Dual
1475//  prime encoded macroblock in a field picture.
1476***************************************************************************/
1477static __inline__ void renderDualPrimeinField(uint **datay,uint **datau,
1478					      uint **datav,XvMCMacroBlock *mb,
1479					      short *block_ptr,uint ps,
1480					      uint flags) {
1481
1482  register uint *dy = *datay;
1483  register uint *du = *datau;
1484  register uint *dv = *datav;
1485
1486  /* Motion Vectors */
1487  short fmv[2];
1488  short bmv[2];
1489  /* gfxblock dword 1 */
1490  uint dw1;
1491
1492
1493  uint ysize = y_frame_bytes[mb->coded_block_pattern];
1494  uint usize = u_frame_bytes[mb->coded_block_pattern];
1495  uint vsize = v_frame_bytes[mb->coded_block_pattern];
1496
1497  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4);
1498
1499
1500  if(ps & XVMC_TOP_FIELD) {
1501    dw1 = (mb->coded_block_pattern<<22) | 3<<12 | 2<<6 | 2<<3 | 3;
1502  }
1503  else {
1504    dw1 = (mb->coded_block_pattern<<22) | 3<<12 | 3<<6 | 3<<3 | 2;
1505  }
1506  fmv[0] = mb->PMV[0][0][1];
1507  fmv[1] = mb->PMV[0][0][0];
1508  bmv[0] = mb->PMV[0][1][1];
1509  bmv[1] = mb->PMV[0][1][0];
1510
1511  /* Y Block */
1512  *dy++ = GFXBLOCK + 4 + (ysize>>2);
1513  *dy++ = (1<<30) | (3<<28) | dw1;
1514  *dy++ = xy;
1515  *dy++ = (16<<16) | 16;
1516  *dy++ = *(uint *)fmv;
1517  *dy++ = *(uint *)bmv;
1518  PACK_CORR_DATA(dy,block_ptr,ysize);
1519  block_ptr = (short *)((unsigned long)block_ptr + ysize);
1520  /* End Y Blocks */
1521
1522  fmv[0] /= 2;
1523  fmv[1] /= 2;
1524  bmv[0] /= 2;
1525  bmv[1] /= 2;
1526  xy >>= 1;
1527
1528  /* U Block */
1529  *du++ = GFXBLOCK + 4 + (usize>>2);
1530  *du++ = (2<<30) | (1<<28) | dw1;
1531  *du++ = xy;
1532  *du++ = (8<<16) | 8;
1533  *du++ = *(uint *)fmv;
1534  *du++ = *(uint *)bmv;
1535  PACK_CORR_DATA(du,block_ptr,usize);
1536  block_ptr = (short *)((unsigned long)block_ptr + usize);
1537
1538  /* V Block */
1539  *dv++ = GFXBLOCK + 4 + (vsize>>2);
1540  *dv++ = (3<<30) | (1<<28) | dw1;
1541  *dv++ = xy;
1542  *dv++ = (8<<16) | 8;
1543  *dv++ = *(uint *)fmv;
1544  *dv++ = *(uint *)bmv;
1545  PACK_CORR_DATA(dv,block_ptr,vsize);
1546  block_ptr = (short *)((unsigned long)block_ptr + vsize);
1547
1548  *datay = dy;
1549  *datau = du;
1550  *datav = dv;
1551}
1552
1553/***************************************************************************
1554// Function: renderFieldinFrame
1555// Description: inline function that sets hardware parameters for a Field
1556//  encoded macroblock in a frame picture.
1557***************************************************************************/
1558typedef union {
1559  short	s[4];
1560  uint  u[2];
1561} su_t;
1562
1563static __inline__ void renderFieldinFrame(uint **datay,uint **datau,
1564					  uint **datav,
1565					  XvMCMacroBlock *mb,short *block_ptr,
1566					  uint flags) {
1567
1568  register uint *dy = *datay;
1569  register uint *du = *datau;
1570  register uint *dv = *datav;
1571
1572  /* Motion Vectors */
1573  su_t fmv;
1574  su_t bmv;
1575  /* gfxblock dword 1 */
1576  uint dw1[2];
1577
1578  uint y1size = y_first_field_bytes[mb->coded_block_pattern];
1579  uint y2size = y_second_field_bytes[mb->coded_block_pattern];
1580  uint usize = u_field_bytes[mb->coded_block_pattern];
1581  uint vsize = v_field_bytes[mb->coded_block_pattern];
1582
1583  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3);
1584
1585  dw1[0] = type_table[mb->macroblock_type & 0xf] | (0x2<<6) |
1586    mvfs_table[mb->motion_vertical_field_select & 3] |
1587    (((uint)mb->coded_block_pattern)<<22);
1588
1589  dw1[1] = type_table[mb->macroblock_type & 0xf] | (0x3<<6) |
1590    mvfs_table[mb->motion_vertical_field_select>>2] |
1591    (((mb->coded_block_pattern & 0x3) |
1592      ((mb->coded_block_pattern & 0xc)<<2))<<22);
1593
1594  fmv.s[0] = mb->PMV[0][0][1]/2;
1595  fmv.s[1] = mb->PMV[0][0][0];
1596  fmv.s[2] = mb->PMV[1][0][1]/2;
1597  fmv.s[3] = mb->PMV[1][0][0];
1598
1599  bmv.s[0] = mb->PMV[0][1][1]/2;
1600  bmv.s[1] = mb->PMV[0][1][0];
1601  bmv.s[2] = mb->PMV[1][1][1]/2;
1602  bmv.s[3] = mb->PMV[1][1][0];
1603
1604  /* First Y Block */
1605  *dy++ = GFXBLOCK + 4 + (y1size>>2);
1606  *dy++ = (1<<30) | (2<<28) | dw1[0];
1607  *dy++ = xy;
1608  *dy++ = (8<<16) | 16;
1609  *dy++ = fmv.u[0];
1610  *dy++ = bmv.u[0];
1611  PACK_CORR_DATA(dy,block_ptr,y1size);
1612  block_ptr = (short *)((unsigned long)block_ptr + y1size);
1613
1614  /* Second Y Block */
1615  *dy++ = GFXBLOCK + 4 + (y2size>>2);
1616  *dy++ = (1<<30) | (2<<28) | dw1[1];
1617  *dy++ = xy;
1618  *dy++ = (8<<16) | 16;
1619  *dy++ = fmv.u[1];
1620  *dy++ = bmv.u[1];
1621  PACK_CORR_DATA(dy,block_ptr,y2size);
1622  block_ptr = (short *)((unsigned long)block_ptr + y2size);
1623  /* End Y Blocks */
1624
1625  fmv.s[0] /= 2;
1626  fmv.s[1] /= 2;
1627  fmv.s[2] /= 2;
1628  fmv.s[3] /= 2;
1629
1630  bmv.s[0] /= 2;
1631  bmv.s[1] /= 2;
1632  bmv.s[2] /= 2;
1633  bmv.s[3] /= 2;
1634
1635  xy >>= 1;
1636
1637  /* U Blocks */
1638  *du++ = GFXBLOCK + 4 + (usize>>2);
1639  *du++ = (2<<30) | (1<<28) | dw1[0];
1640  *du++ = xy;
1641  *du++ = (4<<16) | 8;
1642  *du++ = fmv.u[0];
1643  *du++ = bmv.u[0];
1644  if(usize) {
1645    PACK_CORR_DATA_SHORT(du,block_ptr);
1646  }
1647
1648  /* Second U Block */
1649  *du++ = GFXBLOCK + 4 + (usize>>2);
1650  *du++ = (2<<30) | (1<<28) | dw1[1];
1651  *du++ = xy;
1652  *du++ = (4<<16) | 8;
1653  *du++ = fmv.u[1];
1654  *du++ = bmv.u[1];
1655  if(usize) {
1656    block_ptr = (short *)((unsigned long)block_ptr + 16);
1657    PACK_CORR_DATA_SHORT(du,block_ptr);
1658    block_ptr = (short *)((unsigned long)block_ptr + 112);
1659  }
1660  /* End U Blocks */
1661
1662  /* V Blocks */
1663  *dv++ = GFXBLOCK + 4 + (vsize>>2);
1664  *dv++ = (3<<30) | (1<<28) | dw1[0];
1665  *dv++ = xy;
1666  *dv++ = (4<<16) | 8;
1667  *dv++ = fmv.u[0];
1668  *dv++ = bmv.u[0];
1669  if(vsize) {
1670    PACK_CORR_DATA_SHORT(dv,block_ptr);
1671  }
1672
1673  /* Second V Block */
1674  *dv++ = GFXBLOCK + 4 + (vsize>>2);
1675  *dv++ = (3<<30) | (1<<28) | dw1[1];
1676  *dv++ = xy;
1677  *dv++ = (4<<16) | 8;
1678  *dv++ = fmv.u[1];
1679  *dv++ = bmv.u[1];
1680  if(vsize) {
1681    block_ptr = (short *)((unsigned long)block_ptr + 16);
1682    PACK_CORR_DATA_SHORT(dv,block_ptr);
1683    block_ptr = (short *)((unsigned long)block_ptr + 112);
1684  }
1685  /* End V Blocks */
1686
1687  *datay = dy;
1688  *datau = du;
1689  *datav = dv;
1690}
1691
1692/***************************************************************************
1693// Function: renderFieldinFrameDCT0
1694// Description: inline function that sets hardware parameters for a Field
1695//  encoded macroblock in a frame picture with DCT0.
1696***************************************************************************/
1697static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau,
1698					      uint **datav,XvMCMacroBlock *mb,
1699					      short *block_ptr,uint flags) {
1700
1701  register uint *dy = *datay;
1702  register uint *du = *datau;
1703  register uint *dv = *datav;
1704
1705  /* Motion Vectors */
1706  su_t fmv;
1707  su_t bmv;
1708  /* CBP */
1709  uint cbp = (uint)mb->coded_block_pattern;
1710  /* gfxblock dword 1 */
1711  uint dw1[2];
1712
1713  short * top_left_b = NULL;
1714  short * top_right_b = NULL;
1715  short * bottom_left_b = NULL;
1716  short * bottom_right_b = NULL;
1717
1718  unsigned int ysize = y_dct0_field_bytes[cbp];
1719  unsigned int usize = u_field_bytes[cbp];
1720  unsigned int vsize = v_field_bytes[cbp];
1721
1722  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3);
1723
1724  dw1[0] = type_table[mb->macroblock_type & 0xf] | (0x2<<6) |
1725    mvfs_table[mb->motion_vertical_field_select & 3] |
1726    ((cbp | ((cbp<<2) & 0x30))<<22);
1727
1728  dw1[1] = type_table[mb->macroblock_type & 0xf] | (0x3<<6) |
1729    mvfs_table[mb->motion_vertical_field_select>>2] |
1730    ((cbp | ((cbp<<2) & 0x30))<<22);
1731
1732
1733  fmv.s[0] = mb->PMV[0][0][1]/2;
1734  fmv.s[1] = mb->PMV[0][0][0];
1735  fmv.s[2] = mb->PMV[1][0][1]/2;
1736  fmv.s[3] = mb->PMV[1][0][0];
1737
1738  bmv.s[0] = mb->PMV[0][1][1]/2;
1739  bmv.s[1] = mb->PMV[0][1][0];
1740  bmv.s[2] = mb->PMV[1][1][1]/2;
1741  bmv.s[3] = mb->PMV[1][1][0];
1742
1743  /*
1744    The i810 cannot use DCT0 directly with field motion, we have to
1745    interlace the data for it. We use a zero block when the CBP has
1746    one half of the to-be-interlaced data but not the other half.
1747  */
1748  top_left_b = &empty_block[0];
1749  if(cbp & 0x20) {
1750    top_left_b = block_ptr;
1751    block_ptr += 64;
1752  }
1753
1754  top_right_b = &empty_block[0];
1755  if(cbp & 0x10) {
1756    top_right_b = block_ptr;
1757    block_ptr += 64;
1758  }
1759
1760  bottom_left_b = &empty_block[0];
1761  if(cbp & 0x8) {
1762    bottom_left_b = block_ptr;
1763    block_ptr += 64;
1764  }
1765
1766  bottom_right_b = &empty_block[0];
1767  if(cbp & 0x4) {
1768    bottom_right_b = block_ptr;
1769    block_ptr += 64;
1770  }
1771
1772  /* First Y Block */
1773  *dy++ = GFXBLOCK + 4 + (ysize>>2);
1774  *dy++ = (1<<30) | (2<<28) | dw1[0];
1775  *dy++ = xy;
1776  *dy++ = (8<<16) | 16;
1777  *dy++ = fmv.u[0];
1778  *dy++ = bmv.u[0];
1779  if(dw1[0] & (1<<27)) {
1780    PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b);
1781  }
1782  if(dw1[0] & (1<<26)) {
1783    PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b);
1784  }
1785
1786  /* Second Y Block */
1787  *dy++ = GFXBLOCK + 4 + (ysize>>2);
1788  *dy++ = (1<<30) | (2<<28) | dw1[1];
1789  *dy++ = xy;
1790  *dy++ = (8<<16) | 16;
1791  *dy++ = fmv.u[1];
1792  *dy++ = bmv.u[1];
1793  if(dw1[1] & (1<<27)) {
1794    top_left_b = (short *)((unsigned long)top_left_b + 16);
1795    bottom_left_b = (short *)((unsigned long)bottom_left_b + 16);
1796    PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b);
1797  }
1798  if(dw1[1] & (1<<26)) {
1799    top_right_b = (short *)((unsigned long)top_right_b + 16);
1800    bottom_right_b = (short *)((unsigned long)bottom_right_b + 16);
1801    PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b);
1802  }
1803  /* End Y Blocks */
1804
1805  fmv.s[0] /= 2;
1806  fmv.s[1] /= 2;
1807  fmv.s[2] /= 2;
1808  fmv.s[3] /= 2;
1809
1810  bmv.s[0] /= 2;
1811  bmv.s[1] /= 2;
1812  bmv.s[2] /= 2;
1813  bmv.s[3] /= 2;
1814
1815  xy >>= 1;
1816
1817  /* U Blocks */
1818  *du++ = GFXBLOCK + 4 + (usize>>2);
1819  *du++ = (2<<30) | (1<<28) | dw1[0];
1820  *du++ = xy;
1821  *du++ = (4<<16) | 8;
1822  *du++ = fmv.u[0];
1823  *du++ = bmv.u[0];
1824  if(usize) {
1825    PACK_CORR_DATA_SHORT(du,block_ptr);
1826  }
1827
1828  /* Second U Block */
1829  *du++ = GFXBLOCK + 4 + (usize>>2);
1830  *du++ = (2<<30) | (1<<28) | dw1[1];
1831  *du++ = xy;
1832  *du++ = (4<<16) | 8;
1833  *du++ = fmv.u[1];
1834  *du++ = bmv.u[1];
1835  if(usize) {
1836    block_ptr = (short *)((unsigned long)block_ptr + 16);
1837    PACK_CORR_DATA_SHORT(du,block_ptr);
1838    block_ptr = (short *)((unsigned long)block_ptr + 112);
1839  }
1840  /* End U Blocks */
1841
1842  /* V Blocks */
1843  *dv++ = GFXBLOCK + 4 + (vsize>>2);
1844  *dv++ = (3<<30) | (1<<28) | dw1[0];
1845  *dv++ = xy;
1846  *dv++ = (4<<16) | 8;
1847  *dv++ = fmv.u[0];
1848  *dv++ = bmv.u[0];
1849  if(vsize) {
1850    PACK_CORR_DATA_SHORT(dv,block_ptr);
1851  }
1852
1853  /* Second V Block */
1854  *dv++ = GFXBLOCK + 4 + (vsize>>2);
1855  *dv++ = (3<<30) | (1<<28) | dw1[1];
1856  *dv++ = xy;
1857  *dv++ = (4<<16) | 8;
1858  *dv++ = fmv.u[1];
1859  *dv++ = bmv.u[1];
1860  if(vsize) {
1861    block_ptr = (short *)((unsigned long)block_ptr + 16);
1862    PACK_CORR_DATA_SHORT(dv,block_ptr);
1863    block_ptr = (short *)((unsigned long)block_ptr + 112);
1864  }
1865  /* End V Blocks */
1866
1867  *datay = dy;
1868  *datau = du;
1869  *datav = dv;
1870}
1871
1872/***************************************************************************
1873// Function: renderFrameinFrame
1874// Description: inline function that sets hardware parameters for a Frame
1875//  encoded macroblock in a frame picture.
1876***************************************************************************/
1877static __inline__ void renderFrameinFrame(uint **datay,uint **datau,
1878					  uint **datav,
1879					  XvMCMacroBlock *mb,short *block_ptr,
1880					  uint flags) {
1881
1882  register uint *dy = *datay;
1883  register uint *du = *datau;
1884  register uint *dv = *datav;
1885
1886  /* Motion Vectors */
1887  su_t fmv;
1888  su_t bmv;
1889  /* gfxblock dword 1 */
1890  uint dw1;
1891
1892  unsigned int ysize = y_frame_bytes[mb->coded_block_pattern];
1893  unsigned int usize = u_frame_bytes[mb->coded_block_pattern];
1894  unsigned int vsize = v_frame_bytes[mb->coded_block_pattern];
1895
1896  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4);
1897
1898  dw1 = type_table[mb->macroblock_type & 0xf] |
1899    (((uint)mb->coded_block_pattern)<<22);
1900
1901
1902  fmv.s[0] = mb->PMV[0][0][1];
1903  fmv.s[1] = mb->PMV[0][0][0];
1904
1905  bmv.s[0] = mb->PMV[0][1][1];
1906  bmv.s[1] = mb->PMV[0][1][0];
1907
1908  /* Y Block */
1909  *dy++ = GFXBLOCK + 4 + (ysize>>2);
1910  *dy++ = (1<<30) | (3<<28) | dw1;
1911  *dy++ = xy;
1912  *dy++ = (16<<16) | 16;
1913  *dy++ = fmv.u[0];
1914  *dy++ = bmv.u[0];
1915  PACK_CORR_DATA(dy,block_ptr,ysize);
1916  block_ptr = (short *)((unsigned long)block_ptr + ysize);
1917  /* End Y Blocks */
1918
1919  fmv.s[0] /= 2;
1920  fmv.s[1] /= 2;
1921
1922  bmv.s[0] /= 2;
1923  bmv.s[1] /= 2;
1924
1925  xy >>= 1;
1926
1927  /* U Block */
1928  *du++ = GFXBLOCK + 4 + (usize>>2);
1929  *du++ = (2<<30) | (1<<28) | dw1;
1930  *du++ = xy;
1931  *du++ = (8<<16) | 8;
1932  *du++ = fmv.u[0];
1933  *du++ = bmv.u[0];
1934  PACK_CORR_DATA(du,block_ptr,usize);
1935  block_ptr = (short *)((unsigned long)block_ptr + usize);
1936  /* End U Block */
1937
1938  /* V Block */
1939  *dv++ = GFXBLOCK + 4 + (vsize>>2);
1940  *dv++ = (3<<30) | (1<<28) | dw1;
1941  *dv++ = xy;
1942  *dv++ = (8<<16) | 8;
1943  *dv++ = fmv.u[0];
1944  *dv++ = bmv.u[0];
1945  PACK_CORR_DATA(dv,block_ptr,vsize);
1946  block_ptr = (short *)((unsigned long)block_ptr + vsize);
1947  /* End V Block */
1948
1949  *datay = dy;
1950  *datau = du;
1951  *datav = dv;
1952}
1953
1954/***************************************************************************
1955// Function: renderFrameinFrameDCT1
1956// Description: inline function that sets hardware parameters for a Frame
1957//  encoded macroblock in a frame picture with DCT type 1.
1958***************************************************************************/
1959static __inline__ void renderFrameinFrameDCT1(uint **datay,uint **datau,
1960					      uint **datav,XvMCMacroBlock *mb,
1961					      short *block_ptr,uint flags) {
1962
1963  register uint *dy = *datay;
1964  register uint *du = *datau;
1965  register uint *dv = *datav;
1966
1967  /* Motion Vectors */
1968  su_t fmv;
1969  su_t bmv;
1970
1971  short * top_left_b = NULL;
1972  short * top_right_b = NULL;
1973  short * bottom_left_b = NULL;
1974  short * bottom_right_b = NULL;
1975
1976  uint temp_bp = 0;
1977
1978  uint ysize = y_dct1_frame_bytes[mb->coded_block_pattern];
1979  uint usize = u_frame_bytes[mb->coded_block_pattern];
1980  uint vsize = v_frame_bytes[mb->coded_block_pattern];
1981
1982  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4);
1983
1984  uint dw1 = type_table[mb->macroblock_type & 0xf] |
1985    (((uint)mb->coded_block_pattern)<<22);
1986
1987  fmv.s[0] = mb->PMV[0][0][1];
1988  fmv.s[1] = mb->PMV[0][0][0];
1989
1990  bmv.s[0] = mb->PMV[0][1][1];
1991  bmv.s[1] = mb->PMV[0][1][0];
1992
1993  /*
1994    It is easiest to find out what blocks are in need of reading first
1995    rather than as we go.
1996  */
1997  top_left_b = &empty_block[0];
1998  if(dw1 & (1<<27)) {
1999    temp_bp |= (1<<25);
2000    top_left_b = block_ptr;
2001    block_ptr += 64;
2002  }
2003
2004  top_right_b = &empty_block[0];
2005  if(dw1 & (1<<26)) {
2006    temp_bp |= (1<<24);
2007    top_right_b = block_ptr;
2008    block_ptr += 64;
2009  }
2010
2011  bottom_left_b = &empty_block[0];
2012  if(dw1 & (1<<25)) {
2013    temp_bp |= (1<<27);
2014    bottom_left_b = block_ptr;
2015    block_ptr += 64;
2016  }
2017
2018  bottom_right_b = &empty_block[0];
2019  if(dw1 & (1<<24)) {
2020    temp_bp |= (1<<26);
2021    bottom_right_b = block_ptr;
2022    block_ptr += 64;
2023  }
2024  dw1 |= temp_bp;
2025
2026  /* Y Block */
2027  *dy++ = GFXBLOCK + 4 + (ysize>>2);
2028  *dy++ = (1<<30) | (3<<28) | dw1;
2029  *dy++ = xy;
2030  *dy++ = (16<<16) | 16;
2031  *dy++ = fmv.u[0];
2032  *dy++ = bmv.u[0];
2033  if(dw1 & (1<<27)) {
2034    PACK_CORR_DATA_1to0(dy,top_left_b,bottom_left_b);
2035    top_left_b = (short *)((unsigned long)top_left_b + 64);
2036    bottom_left_b = (short *)((unsigned long)bottom_left_b + 64);
2037  }
2038  if(dw1 & (1<<26)) {
2039    PACK_CORR_DATA_1to0(dy,top_right_b,bottom_right_b);
2040    top_right_b = (short *)((unsigned long)top_right_b + 64);
2041    bottom_right_b = (short *)((unsigned long)bottom_right_b + 64);
2042  }
2043  if(dw1 & (1<<27)) {
2044    PACK_CORR_DATA_1to0(dy,top_left_b,bottom_left_b);
2045  }
2046  if(dw1 & (1<<26)) {
2047    PACK_CORR_DATA_1to0(dy,top_right_b,bottom_right_b);
2048  }
2049  /* End Y Block */
2050
2051  fmv.s[0] /= 2;
2052  fmv.s[1] /= 2;
2053
2054  bmv.s[0] /= 2;
2055  bmv.s[1] /= 2;
2056
2057  xy >>= 1;
2058
2059  /* U Block */
2060  *du++ = GFXBLOCK + 4 + (usize>>2);
2061  *du++ = (2<<30) | (1<<28) | dw1;
2062  *du++ = xy;
2063  *du++ = (8<<16) | 8;
2064  *du++ = fmv.u[0];
2065  *du++ = bmv.u[0];
2066  PACK_CORR_DATA(du,block_ptr,usize);
2067  block_ptr = (short *)((unsigned long)block_ptr + usize);
2068
2069  /* V Block */
2070  *dv++ = GFXBLOCK + 4 + (vsize>>2);
2071  *dv++ = (3<<30) | (1<<28) | dw1;
2072  *dv++ = xy;
2073  *dv++ = (8<<16) | 8;
2074  *dv++ = fmv.u[0];
2075  *dv++ = bmv.u[0];
2076  PACK_CORR_DATA(dv,block_ptr,vsize);
2077  block_ptr = (short *)((unsigned long)block_ptr + vsize);
2078
2079  *datay = dy;
2080  *datau = du;
2081  *datav = dv;
2082}
2083
2084/***************************************************************************
2085// Function: renderDualPrimeinFrame
2086// Description: inline function that sets hardware parameters for a Dual
2087//  Prime encoded macroblock in a frame picture with dct 1.
2088***************************************************************************/
2089static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau,
2090					      uint **datav,XvMCMacroBlock *mb,
2091					      short *block_ptr,uint flags) {
2092
2093  register uint *dy = *datay;
2094  register uint *du = *datau;
2095  register uint *dv = *datav;
2096
2097  /* Motion Vectors */
2098  su_t fmv;
2099  su_t bmv;
2100  /* gfxblock dword 1 */
2101  uint dw1[2];
2102
2103  uint y1size = y_first_field_bytes[mb->coded_block_pattern];
2104  uint y2size = y_second_field_bytes[mb->coded_block_pattern];
2105  uint usize = u_field_bytes[mb->coded_block_pattern];
2106  uint vsize = v_field_bytes[mb->coded_block_pattern];
2107
2108  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3);
2109
2110  /*
2111    Past Surface (map 0) is used for same parity prediction,
2112    Future surface (map 1) is used for opposite.
2113  */
2114  dw1[0] = (((uint)mb->coded_block_pattern)<<22) |
2115    3<<12 | 2<<6 | 2<<3 | 3;
2116  dw1[1] = (((mb->coded_block_pattern & 0x3) |
2117	     ((mb->coded_block_pattern & 0xc)<<2))<<22) |
2118    3<<12 | 3<<6 | 3<<3 | 2;
2119
2120  fmv.s[0] = mb->PMV[0][0][1];
2121  fmv.s[1] = mb->PMV[0][0][0];
2122  bmv.s[0] = mb->PMV[1][0][1];
2123  bmv.s[1] = mb->PMV[1][0][0];
2124
2125  fmv.s[2] = mb->PMV[0][0][1];
2126  fmv.s[3] = mb->PMV[0][0][0];
2127  bmv.s[2] = mb->PMV[1][1][1];
2128  bmv.s[3] = mb->PMV[1][1][0];
2129
2130  /* First Y Block */
2131  *dy++ = GFXBLOCK + 4 + (y1size>>2);
2132  *dy++ = (1<<30) | (2<<28) | dw1[0];
2133  *dy++ = xy;
2134  *dy++ = (8<<16) | 16;
2135  *dy++ = fmv.u[0];
2136  *dy++ = bmv.u[0];;
2137  PACK_CORR_DATA(dy,block_ptr,y1size);
2138  block_ptr = (short *)((unsigned long)block_ptr + y1size);
2139
2140  /* Second Y Block */
2141  *dy++ = GFXBLOCK + 4 + (y2size>>2);
2142  *dy++ = (1<<30) | (2<<28) | dw1[1];
2143  *dy++ = xy;
2144  *dy++ = (8<<16) | 16;
2145  *dy++ = fmv.u[1];
2146  *dy++ = bmv.u[1];
2147  PACK_CORR_DATA(dy,block_ptr,y2size);
2148  block_ptr = (short *)((unsigned long)block_ptr + y2size);
2149
2150  fmv.s[0] /= 2;
2151  fmv.s[1] /= 2;
2152  bmv.s[0] /= 2;
2153  bmv.s[1] /= 2;
2154
2155  fmv.s[2] /= 2;
2156  fmv.s[3] /= 2;
2157  bmv.s[2] /= 2;
2158  bmv.s[3] /= 2;
2159
2160  xy >>= 1;
2161
2162  /* U Blocks */
2163  *du++ = GFXBLOCK + 4 + (usize>>2);
2164  *du++ = (2<<30) | (1<<28) | dw1[0];
2165  *du++ = xy;
2166  *du++ = (4<<16) | 8;
2167  *du++ = fmv.u[0];
2168  *du++ = bmv.u[0];
2169  if(dw1[0] & (1<<23)) {
2170    PACK_CORR_DATA_SHORT(du,block_ptr);
2171  }
2172
2173  /* Second U Block */
2174  *du++ = GFXBLOCK + 4 + (usize>>2);
2175  *du++ = (2<<30) | (1<<28) | dw1[1];
2176  *du++ = xy;
2177  *du++ = (4<<16) | 8;
2178  *du++ = fmv.u[1];
2179  *du++ = bmv.u[1];
2180  if(dw1[1] & (1<<23)) {
2181    block_ptr = (short *)((unsigned long)block_ptr + 16);
2182    PACK_CORR_DATA_SHORT(du,block_ptr);
2183    block_ptr = (short *)((unsigned long)block_ptr + 112);
2184  }
2185  /* End U Blocks */
2186
2187  /* V Blocks */
2188  *dv++ = GFXBLOCK + 4 + (vsize>>2);
2189  *dv++ = (3<<30) | (1<<28) | dw1[0];
2190  *dv++ = xy;
2191  *dv++ = (4<<16) | 8;
2192  *dv++ = fmv.u[0];
2193  *dv++ = bmv.u[0];
2194  if(dw1[0] & (1<<22)) {
2195    PACK_CORR_DATA_SHORT(dv,block_ptr);
2196  }
2197
2198  /* Second V Block */
2199  *dv++ = GFXBLOCK + 4 + (vsize>>2);
2200  *dv++ = (3<<30) | (1<<28) | dw1[1];
2201  *dv++ = xy;
2202  *dv++ = (4<<16) | 8;
2203  *dv++ = fmv.u[1];
2204  *dv++ = bmv.u[1];
2205  if(dw1[1] & (1<<22)) {
2206    block_ptr = (short *)((unsigned long)block_ptr + 16);
2207    PACK_CORR_DATA_SHORT(dv,block_ptr);
2208    block_ptr = (short *)((unsigned long)block_ptr + 112);
2209  }
2210  /* End V Blocks */
2211
2212  *datay = dy;
2213  *datau = du;
2214  *datav = dv;
2215}
2216
2217/***************************************************************************
2218// Function: renderDualPrimeinFrameDCT0
2219// Description: inline function that sets hardware parameters for a Dual
2220//  Prime encoded macroblock in a frame picture with dct 0.
2221***************************************************************************/
2222static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau,
2223						  uint **datav,
2224						  XvMCMacroBlock *mb,
2225						  short *block_ptr,
2226						  uint flags) {
2227
2228  register uint *dy = *datay;
2229  register uint *du = *datau;
2230  register uint *dv = *datav;
2231
2232  /* Motion Vectors */
2233  su_t fmv;
2234  su_t bmv;
2235  /* gfxblock dword 1 */
2236  uint dw1[2];
2237
2238  short * top_left_b = NULL;
2239  short * top_right_b = NULL;
2240  short * bottom_left_b = NULL;
2241  short * bottom_right_b = NULL;
2242
2243  uint cbp = (uint)mb->coded_block_pattern;
2244
2245  uint ysize = y_dct0_field_bytes[cbp];
2246  uint usize = u_field_bytes[cbp];
2247  uint vsize = v_field_bytes[cbp];
2248
2249  uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3);
2250
2251  /*
2252    Past Surface (map 0) is used for same parity prediction,
2253    Future surface (map 1) is used for opposite.
2254  */
2255  dw1[0] = ((cbp | ((cbp<<2) & 0x30))<<22) |
2256    3<<12 | 2<<6 | 2<<3 | 3;
2257  dw1[1] = ((cbp | ((cbp<<2) & 0x30))<<22) |
2258    3<<12 | 3<<6 | 3<<3 | 2;
2259
2260  fmv.s[0] = mb->PMV[0][0][1];
2261  fmv.s[1] = mb->PMV[0][0][0];
2262  bmv.s[0] = mb->PMV[1][0][1];
2263  bmv.s[1] = mb->PMV[1][0][0];
2264
2265  fmv.s[2] = mb->PMV[0][0][1];
2266  fmv.s[3] = mb->PMV[0][0][0];
2267  bmv.s[2] = mb->PMV[1][1][1];
2268  bmv.s[3] = mb->PMV[1][1][0];
2269
2270  /*
2271    The i810 cannot use DCT0 directly with field motion, we have to
2272    interlace the data for it. We use a zero block when the CBP has
2273    one half of the to-be-interlaced data but not the other half.
2274  */
2275  top_left_b = &empty_block[0];
2276  if(cbp & 0x20) {
2277    top_left_b = block_ptr;
2278    block_ptr += 64;
2279  }
2280
2281  top_right_b = &empty_block[0];
2282  if(cbp & 0x10) {
2283    top_right_b = block_ptr;
2284    block_ptr += 64;
2285  }
2286
2287  bottom_left_b = &empty_block[0];
2288  if(cbp & 0x8) {
2289    bottom_left_b = block_ptr;
2290    block_ptr += 64;
2291  }
2292
2293  bottom_right_b = &empty_block[0];
2294  if(cbp & 0x4) {
2295    bottom_right_b = block_ptr;
2296    block_ptr += 64;
2297  }
2298
2299  /* First Y Block */
2300  *dy++ = GFXBLOCK + 4 + (ysize>>2);
2301  *dy++ = (1<<30) | (2<<28) | dw1[0];
2302  *dy++ = xy;
2303  *dy++ = (8<<16) | 16;
2304  *dy++ = fmv.u[0];
2305  *dy++ = bmv.u[0];
2306  if(cbp & 0x20) {
2307    PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b);
2308  }
2309  if(cbp & 0x10) {
2310    PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b);
2311  }
2312
2313  /* Second Y Block */
2314  *dy++ = GFXBLOCK + 4 + (ysize>>2);
2315  *dy++ = (1<<30) | (2<<28) | dw1[1];
2316  *dy++ = xy;
2317  *dy++ = (8<<16) | 16;
2318  *dy++ = fmv.u[1];
2319  *dy++ = bmv.u[1];
2320  if(cbp & 0x20) {
2321    top_left_b = (short *)((unsigned long)top_left_b + 16);
2322    bottom_left_b = (short *)((unsigned long)bottom_left_b + 16);
2323    PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b);
2324  }
2325  if(cbp & 0x10) {
2326    top_right_b = (short *)((unsigned long)top_right_b + 16);
2327    bottom_right_b = (short *)((unsigned long)bottom_right_b + 16);
2328    PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b);
2329  }
2330  /* End Y Blocks */
2331
2332
2333  fmv.s[0] /= 2;
2334  fmv.s[1] /= 2;
2335  bmv.s[0] /= 2;
2336  bmv.s[1] /= 2;
2337
2338  fmv.s[2] /= 2;
2339  fmv.s[3] /= 2;
2340  bmv.s[2] /= 2;
2341  bmv.s[3] /= 2;
2342
2343  xy >>= 1;
2344
2345  /* U Blocks */
2346  *du++ = GFXBLOCK + 4 + (usize>>2);
2347  *du++ = (2<<30) | (1<<28) | dw1[0];
2348  *du++ = xy;
2349  *du++ = (4<<16) | 8;
2350  *du++ = fmv.u[0];
2351  *du++ = bmv.u[0];
2352  if(cbp & (1<<23)) {
2353    PACK_CORR_DATA_SHORT(du,block_ptr);
2354  }
2355
2356  /* Second U Block */
2357  *du++ = GFXBLOCK + 4 + (usize>>2);
2358  *du++ = (2<<30) | (1<<28) | dw1[1];
2359  *du++ = xy;
2360  *du++ = (4<<16) | 8;
2361  *du++ = fmv.u[1];
2362  *du++ = bmv.u[1];
2363  if(cbp & (1<<23)) {
2364    block_ptr = (short *)((unsigned long)block_ptr + 16);
2365    PACK_CORR_DATA_SHORT(du,block_ptr);
2366    block_ptr = (short *)((unsigned long)block_ptr + 112);
2367  }
2368  /* End U Blocks */
2369
2370  /* V Blocks */
2371  *dv++ = GFXBLOCK + 4 + (vsize>>2);
2372  *dv++ = (3<<30) | (1<<28) | dw1[0];
2373  *dv++ = xy;
2374  *dv++ = (4<<16) | 8;
2375  *dv++ = fmv.u[0];
2376  *dv++ = bmv.u[0];
2377  if(cbp & (1<<22)) {
2378    PACK_CORR_DATA_SHORT(dv,block_ptr);
2379  }
2380
2381  /* Second V Block */
2382  *dv++ = GFXBLOCK + 4 + (vsize>>2);
2383  *dv++ = (3<<30) | (1<<28) | dw1[1];
2384  *dv++ = xy;
2385  *dv++ = (4<<16) | 8;
2386  *dv++ = fmv.u[1];
2387  *dv++ = bmv.u[1];
2388  if(cbp & (1<<22)) {
2389    block_ptr = (short *)((unsigned long)block_ptr + 16);
2390    PACK_CORR_DATA_SHORT(dv,block_ptr);
2391    block_ptr = (short *)((unsigned long)block_ptr + 112);
2392  }
2393  /* End V Blocks */
2394
2395  *datay = dy;
2396  *datau = du;
2397  *datav = dv;
2398}
2399
2400
2401/***************************************************************************
2402// Function: XvMCRenderSurface
2403// Description: This function does the actual HWMC. Given a list of
2404//  macroblock structures it dispatched the hardware commands to execute
2405//  them. DMA buffer containing Y data are dispatched as they fill up
2406//  U and V DMA buffers are queued until all Y's are done. This minimizes
2407//  the context flipping and flushing required when switching between Y
2408//  U and V surfaces.
2409***************************************************************************/
2410#define UV_QUEUE 14
2411_X_EXPORT Status XvMCRenderSurface(Display *display, XvMCContext *context,
2412			 unsigned int picture_structure,
2413			 XvMCSurface *target_surface,
2414			 XvMCSurface *past_surface,
2415			 XvMCSurface *future_surface,
2416			 unsigned int flags,
2417			 unsigned int num_macroblocks,
2418			 unsigned int first_macroblock,
2419			 XvMCMacroBlockArray *macroblock_array,
2420			 XvMCBlockArray *blocks) {
2421  /* Dma Data Structures */
2422  drmBufPtr pDMAy = NULL,pDMAu[UV_QUEUE],pDMAv[UV_QUEUE];
2423  int u_index = 0,v_index = 0;
2424  int dirty_context = 1;
2425
2426  /* Block Pointer */
2427  short *block_ptr;
2428  /* Current Macroblock Pointer */
2429  XvMCMacroBlock *mb;
2430
2431  drm_i810_mc_t mc;
2432  int i,j;
2433  i810XvMCSurface *privTarget;
2434  i810XvMCSurface *privFuture = NULL;
2435  i810XvMCSurface *privPast = NULL;
2436  i810XvMCContext *pI810XvMC;
2437
2438  /* DMA Pointers set to NULL */
2439  uint *datay = NULL;
2440  uint *datau = NULL;
2441  uint *datav = NULL;
2442
2443
2444  /* Check Parameters for validity */
2445  if((target_surface == NULL) || (context == NULL) || (display == NULL)) {
2446    printf("Error, Invalid Target,Context, or DIsplay!\n");
2447    return BadValue;
2448  }
2449
2450  if(num_macroblocks == 0) {return Success;}
2451  if((macroblock_array == NULL) || (blocks == NULL)) {return BadValue;}
2452  if(context->privData == NULL) {return BadValue;}
2453  pI810XvMC = (i810XvMCContext *)context->privData;
2454
2455
2456  if(target_surface->privData == NULL) {
2457    printf("Error, Invalid Target Surface!\n");
2458    return BadValue;
2459  }
2460  privTarget = (i810XvMCSurface *)target_surface->privData;
2461
2462  if(macroblock_array->num_blocks < (num_macroblocks + first_macroblock)) {
2463    printf("Error, Too many macroblocks requested for MB array size.\n");
2464    return BadValue;
2465  }
2466
2467  /* Test For YV12 Surface */
2468  if(context->surface_type_id != FOURCC_YV12) {
2469    printf("Error, HWMC only possible on YV12 Surfaces\n");
2470    return BadValue;
2471  }
2472
2473  /* P Frame Test */
2474  if(past_surface == NULL) {
2475    /* Just to avoid some ifs later. */
2476    privPast = privTarget;
2477  }
2478  else {
2479    if(past_surface->privData == NULL) {
2480      printf("Error, Invalid Past Surface!\n");
2481      return BadValue;
2482    }
2483    privPast = (i810XvMCSurface *)past_surface->privData;
2484  }
2485
2486
2487  /* B Frame Test */
2488  if(future_surface == NULL) {
2489    privFuture = privTarget;
2490    if(pI810XvMC->dual_prime) {
2491      privFuture = privPast;
2492      /* I810 Specific flag for marking when dual prime is in use. */
2493      flags |= 0x40000000;
2494    }
2495
2496    /*
2497      References are different for the Second Field Picture. The
2498      i810 needs to know if it is the second field picture in a
2499      P picture. We use a Private flag to mark this.
2500    */
2501    if(flags & XVMC_SECOND_FIELD) {
2502      /* I810 Specific flag for marking second fields. */
2503      flags |= 0x80000000;
2504    }
2505  }
2506  else {
2507    if((future_surface->privData == NULL) || (past_surface == NULL)) {
2508      printf("Error, Invalid Future Surface or No Past Surface!\n");
2509      return BadValue;
2510    }
2511    privFuture = (i810XvMCSurface *)future_surface->privData;
2512
2513    /*
2514      Undo Second Field flag since the second field in B frames is just like
2515      the first.
2516    */
2517    flags &= ~0x80000000;
2518  }
2519
2520  /* Lock For DMA */
2521  I810_LOCK(pI810XvMC,0);
2522
2523  for(i=first_macroblock; i<(num_macroblocks + first_macroblock); i++) {
2524    /* Set up values needed for each macroblock */
2525    mb = &macroblock_array->macro_blocks[i];
2526    block_ptr = &(blocks->blocks[mb->index<<6]);
2527
2528    /* Lockup can happen if the coordinates are too far out of range */
2529    if(mb->x > target_surface->width>>4) {
2530      mb->x = 0;
2531    }
2532    if(mb->y > target_surface->height>>4) {
2533      mb->y = 0;
2534    }
2535
2536    /* If buffers are almost full dispatch them */
2537    if(datay) {
2538      pDMAy->used = (unsigned long)datay - (unsigned long)pDMAy->address;
2539      if(pDMAy->used  > 3520) {
2540	if(dirty_context) {
2541	  dispatchYContext(privTarget,privPast,privFuture,pI810XvMC);
2542	}
2543	dirty_context = 0;
2544	mc.idx = pDMAy->idx;
2545	mc.used = pDMAy->used;
2546	datay = NULL;
2547	mc.last_render = ++pI810XvMC->last_render;
2548	privTarget->last_render = pI810XvMC->last_render;
2549	I810_MC(pI810XvMC,mc);
2550      } /* datay near full */
2551    } /* if(datay) */
2552    if(datau) {
2553      pDMAu[u_index]->used = (unsigned long)datau - (unsigned long)pDMAu[u_index]->address;
2554      if(pDMAu[u_index]->used > 3904) {
2555	u_index++;
2556	datau = NULL;
2557	if(u_index == UV_QUEUE) {
2558	  for(j=0; j<UV_QUEUE; j++) {
2559	    mc.idx = pDMAu[j]->idx;
2560	    mc.used = pDMAu[j]->used;
2561	    mc.last_render = ++pI810XvMC->last_render;
2562	    privTarget->last_render = pI810XvMC->last_render;
2563	    I810_MC(pI810XvMC,mc);
2564	  }
2565	  u_index = 0;
2566	  dirty_context = 1;
2567	} /* if(u_index == UV_QUEUE) */
2568      } /* datau near full */
2569    } /* if(datau) */
2570    if(datav) {
2571      pDMAv[v_index]->used = (unsigned long)datav - (unsigned long)pDMAv[v_index]->address;
2572      if(pDMAv[v_index]->used > 3904) {
2573	v_index++;
2574	datav = NULL;
2575	if(v_index == UV_QUEUE) {
2576	  for(j=0; j<UV_QUEUE; j++) {
2577	    mc.idx = pDMAv[j]->idx;
2578	    mc.used = pDMAv[j]->used;
2579	    mc.last_render = ++pI810XvMC->last_render;
2580	    privTarget->last_render = pI810XvMC->last_render;
2581	    I810_MC(pI810XvMC,mc);
2582	  }
2583	  v_index = 0;
2584	  dirty_context = 1;
2585	} /* if(v_index == UV_QUEUE) */
2586      } /* datav near full */
2587    } /* if(datav) */
2588
2589    /* Allocate buffers if this is the first loop,or if we just dispatched */
2590    if(datay == NULL) {
2591      pDMAy = i810_get_free_buffer(pI810XvMC);
2592      datay = pDMAy->address;
2593    }/* if(datay == NULL) */
2594    if(datau == NULL) {
2595      pDMAu[u_index] = i810_get_free_buffer(pI810XvMC);
2596      datau = pDMAu[u_index]->address;
2597      if(u_index == 0) {
2598	*datau++ = CMD_FLUSH;
2599	*datau++ = BOOLEAN_ENA_2;
2600	*datau++ = CMD_FLUSH;
2601	*datau++ = DEST_BUFFER_INFO;
2602	*datau++ = privTarget->dbi1u;
2603	*datau++ = DEST_BUFFER_VAR;
2604	*datau++ = privTarget->dbv1;
2605	/* Past Surface */
2606	*datau++ = CMD_MAP_INFO;
2607	*datau++ = privPast->mi1u;
2608	*datau++ = privPast->mi2u;
2609	*datau++ = privPast->mi3u;
2610	/* Future Surface */
2611	*datau++ = CMD_MAP_INFO;
2612	*datau++ = privFuture->mi1u | 0x1<<28;
2613	*datau++ = privFuture->mi2u;
2614	*datau++ = privFuture->mi3u;
2615      }
2616    } /* if(datau == NULL) */
2617    if(datav == NULL) {
2618      pDMAv[v_index] = i810_get_free_buffer(pI810XvMC);
2619      datav = pDMAv[v_index]->address;
2620      if(v_index == 0) {
2621	*datav++ = CMD_FLUSH;
2622	*datav++ = BOOLEAN_ENA_2;
2623	*datav++ = CMD_FLUSH;
2624	*datav++ = DEST_BUFFER_INFO;
2625	*datav++ = privTarget->dbi1v;
2626	*datav++ = DEST_BUFFER_VAR;
2627	*datav++ = privTarget->dbv1;
2628	/* Past Surface */
2629	*datav++ = CMD_MAP_INFO;
2630	*datav++ = privPast->mi1v;
2631	*datav++ = privPast->mi2v;
2632	*datav++ = privPast->mi3v;
2633	/* Future Surface */
2634	*datav++ = CMD_MAP_INFO;
2635	*datav++ = privFuture->mi1v | 0x1<<28;
2636	*datav++ = privFuture->mi2v;
2637	*datav++ = privFuture->mi3v;
2638      }
2639    }/* if(datav == NULL) */
2640
2641    /* Catch no pattern case */
2642    if(!(mb->macroblock_type & 0x8)) {
2643      mb->coded_block_pattern = 0;
2644    }
2645
2646
2647    if(mb->motion_type == XVMC_PREDICTION_DUAL_PRIME) {
2648      /*
2649	By default the maps will not be set up for dual
2650	prime. We have to change them.
2651      */
2652      if(!pI810XvMC->dual_prime) {
2653	pI810XvMC->dual_prime = 1;
2654	privFuture = privPast;
2655	/* Y */
2656	*datay++ = CMD_MAP_INFO;
2657	*datay++ = privFuture->mi1y | 0x1<<28;
2658	*datay++ = privFuture->mi2y;
2659	*datay++ = privFuture->mi3y;
2660	/* U */
2661	*datau++ = CMD_MAP_INFO;
2662	*datau++ = privFuture->mi1u | 0x1<<28;
2663	*datau++ = privFuture->mi2u;
2664	*datau++ = privFuture->mi3u;
2665	/* V */
2666	*datav++ = CMD_MAP_INFO;
2667	*datav++ = privFuture->mi1v | 0x1<<28;
2668	*datav++ = privFuture->mi2v;
2669	*datav++ = privFuture->mi3v;
2670      }
2671    }
2672    if((pI810XvMC->dual_prime) &&
2673       (mb->motion_type != XVMC_PREDICTION_DUAL_PRIME)) {
2674      	pI810XvMC->dual_prime = 0;
2675	privFuture = privTarget;
2676	/* Y */
2677	*datay++ = CMD_MAP_INFO;
2678	*datay++ = privFuture->mi1y | 0x1<<28;
2679	*datay++ = privFuture->mi2y;
2680	*datay++ = privFuture->mi3y;
2681	/* U */
2682	*datau++ = CMD_MAP_INFO;
2683	*datau++ = privFuture->mi1u | 0x1<<28;
2684	*datau++ = privFuture->mi2u;
2685	*datau++ = privFuture->mi3u;
2686	/* V */
2687	*datav++ = CMD_MAP_INFO;
2688	*datav++ = privFuture->mi1v | 0x1<<28;
2689	*datav++ = privFuture->mi2v;
2690	*datav++ = privFuture->mi3v;
2691    }
2692
2693
2694    /* Frame Picture */
2695    if((picture_structure & XVMC_FRAME_PICTURE) == XVMC_FRAME_PICTURE) {
2696      /* Intra Blocks */
2697      if(mb->macroblock_type & XVMC_MB_TYPE_INTRA) {
2698	if(mb->dct_type) {
2699	  renderIntrainFrameDCT1(&datay,&datau,&datav,mb,block_ptr,flags);
2700	  continue;
2701	}
2702	renderIntrainFrame(&datay,&datau,&datav,mb,block_ptr);
2703	continue;
2704      }
2705      switch((mb->motion_type & 0x3) | (mb->dct_type<<2)) {
2706      case 0x2:  /* Frame DCT0 */
2707	renderFrameinFrame(&datay,&datau,&datav,mb,block_ptr,flags);
2708	continue;
2709      case 0x5:  /* Field DCT1 */
2710	renderFieldinFrame(&datay,&datau,&datav,mb,block_ptr,flags);
2711	continue;
2712      case 0x6: /* Frame DCT1 */
2713	renderFrameinFrameDCT1(&datay,&datau,&datav,mb,block_ptr,flags);
2714	continue;
2715      case 0x1: /* Field DCT0 */
2716	renderFieldinFrameDCT0(&datay,&datau,&datav,mb,block_ptr,flags);
2717	continue;
2718      case 0x3:  /* Dual Prime DCT0 */
2719	renderDualPrimeinFrame(&datay,&datau,&datav,mb,block_ptr,flags);
2720	continue;
2721      case 0x7:  /* Dual Prime DCT1 */
2722	renderDualPrimeinFrameDCT0(&datay,&datau,&datav,mb,block_ptr,flags);
2723	continue;
2724      default:  /* No Motion Type */
2725	renderError();
2726	continue;
2727      } /* Switch */
2728    } /* Frame Picture */
2729
2730    /* Field Pictures */
2731    if(mb->macroblock_type & XVMC_MB_TYPE_INTRA) {
2732      renderIntrainField(&datay,&datau,&datav,mb,block_ptr,picture_structure);
2733      continue;
2734    }
2735    switch(mb->motion_type & 0x3) {
2736    case 0x1: /* Field Motion */
2737      renderFieldinField(&datay,&datau,&datav,mb,block_ptr,picture_structure,
2738			 flags);
2739      continue;
2740    case 0x2: /* 16x8 Motion */
2741      render16x8inField(&datay,&datau,&datav,mb,block_ptr,picture_structure,
2742			flags);
2743      continue;
2744    case 0x3: /* Dual Prime */
2745      renderDualPrimeinField(&datay,&datau,&datav,mb,block_ptr,
2746			     picture_structure,flags);
2747      continue;
2748    default:  /* No Motion Type */
2749      renderError();
2750      continue;
2751    }
2752    continue;
2753
2754  } /* for each Macroblock */
2755
2756  /* Dispatch remaining DMA buffers */
2757  if(dirty_context) {
2758    dispatchYContext(privTarget,privPast,privFuture,pI810XvMC);
2759  }
2760  mc.idx = pDMAy->idx;
2761  mc.used = (unsigned long)datay - (unsigned long)pDMAy->address;
2762  mc.last_render = ++pI810XvMC->last_render;
2763  privTarget->last_render = pI810XvMC->last_render;
2764  I810_MC(pI810XvMC,mc);
2765
2766  pDMAu[u_index]->used = (unsigned long)datau - (unsigned long)pDMAu[u_index]->address;
2767  for(j=0; j<=u_index; j++) {
2768    mc.idx = pDMAu[j]->idx;
2769    mc.used = pDMAu[j]->used;
2770    mc.last_render = ++pI810XvMC->last_render;
2771    privTarget->last_render = pI810XvMC->last_render;
2772    I810_MC(pI810XvMC,mc);
2773  }
2774  pDMAv[v_index]->used = (unsigned long)datav - (unsigned long)pDMAv[v_index]->address;
2775  for(j=0; j<=v_index; j++) {
2776    mc.idx = pDMAv[j]->idx;
2777    mc.used = pDMAv[j]->used;
2778    mc.last_render = ++pI810XvMC->last_render;
2779    privTarget->last_render = pI810XvMC->last_render;
2780    I810_MC(pI810XvMC,mc);
2781  }
2782
2783  I810_UNLOCK(pI810XvMC);
2784
2785  return Success;
2786}
2787
2788/***************************************************************************
2789// Function: XvMCPutSurface
2790// Description:
2791// Arguments:
2792//  display: Connection to X server
2793//  surface: Surface to be displayed
2794//  draw: X Drawable on which to display the surface
2795//  srcx: X coordinate of the top left corner of the region to be
2796//          displayed within the surface.
2797//  srcy: Y coordinate of the top left corner of the region to be
2798//          displayed within the surface.
2799//  srcw: Width of the region to be displayed.
2800//  srch: Height of the region to be displayed.
2801//  destx: X cordinate of the top left corner of the destination region
2802//         in the drawable coordinates.
2803//  desty: Y cordinate of the top left corner of the destination region
2804//         in the drawable coordinates.
2805//  destw: Width of the destination region.
2806//  desth: Height of the destination region.
2807//  flags: One or more of the following.
2808//     XVMC_TOP_FIELD - Display only the Top field of the surface.
2809//     XVMC_BOTTOM_FIELD - Display only the Bottom Field of the surface.
2810//     XVMC_FRAME_PICTURE - Display both fields or frame.
2811//
2812// Info: Portions of this function derived from i810_video.c (XFree86)
2813//
2814//   This function is organized so that we wait as long as possible before
2815//   touching the overlay registers. Since we don't know that the last
2816//   flip has happened yet we want to give the overlay as long as
2817//   possible to catch up before we have to check on its progress. This
2818//   makes it unlikely that we have to wait on the last flip.
2819***************************************************************************/
2820_X_EXPORT Status XvMCPutSurface(Display *display,XvMCSurface *surface,
2821		      Drawable draw, short srcx, short srcy,
2822		      unsigned short srcw, unsigned short srch,
2823		      short destx, short desty,
2824		      unsigned short destw, unsigned short desth,
2825		      int flags) {
2826  i810XvMCContext *pI810XvMC;
2827  i810XvMCSurface *pI810Surface;
2828  i810OverlayRecPtr pORegs;
2829  unsigned int ysrc_offset,uvsrc_offset;
2830  Box extents;
2831  uint window_width,window_height;
2832  unsigned int xscaleInt = 0,xscaleFract = 0,yscaleInt = 0,yscaleFract = 0;
2833  unsigned int xscaleFractUV = 0,xscaleIntUV = 0,yscaleFractUV = 0;
2834  unsigned int yscaleIntUV = 0,yPitch = 0,uvPitch = 0;
2835  unsigned int ovcmd = 0;
2836  uint d;
2837  double xscale,yscale;
2838  int diff;
2839  int clipped_srcx, clipped_srcy, clipped_destx, clipped_desty;
2840  int clipped_srcw, clipped_srch, clipped_destw, clipped_desth;
2841  uint x1,y1,root_width,root_height;
2842  int x2 = 0, y2 = 0,unused;
2843  uint nChilds;
2844  int stat;
2845  Window win,root,parent,*pChilds;
2846
2847
2848  if((display == NULL) || (surface == NULL)) {
2849    return BadValue;
2850  }
2851
2852  if(surface->privData == NULL) {
2853    return (error_base + XvMCBadSurface);
2854  }
2855  pI810Surface = (i810XvMCSurface *)surface->privData;
2856  pI810XvMC = (i810XvMCContext *)pI810Surface->privContext;
2857  pORegs = (i810OverlayRecPtr)pI810XvMC->oregs;
2858
2859
2860  switch(surface->surface_type_id) {
2861  case FOURCC_YV12:
2862  case FOURCC_I420:
2863    yPitch = (srcw + 7) & ~7;
2864    uvPitch = ((srcw>>1) + 7) & ~7;
2865    if((flags & XVMC_FRAME_PICTURE) != XVMC_FRAME_PICTURE) {
2866      srch = srch>>1;
2867    }
2868    break;
2869  case FOURCC_UYVY:
2870  case FOURCC_YUY2:
2871  default:
2872    /* FIXME: Non Planar not fully implemented. */
2873    return BadValue;
2874    yPitch = ((srcw + 7) & ~7) << 1;
2875    break;
2876  }/* switch(surface->surface_type_id) */
2877
2878  /*
2879    FIXME: This should be using the DRI's clip rect but that isn't
2880    all hooked up yet. This has some latency but we get by.
2881  */
2882  win = draw;
2883  XQueryTree(display,win,&root,&parent,&pChilds,&nChilds);
2884  if(nChilds) XFree(pChilds);
2885  XGetGeometry(display,win, &root, &x2, &y2, &window_width,
2886	       &window_height, &d, &d);
2887  x1 = x2;
2888  y1 = y2;
2889  win = parent;
2890  do {
2891    XQueryTree(display,win,&root,&parent,&pChilds,&nChilds);
2892    if(nChilds) XFree(pChilds);
2893    XGetGeometry(display,win, &root, &x2, &y2, &d, &d, &d, &d);
2894    x1 += x2;
2895    y1 += y2;
2896    win = parent;
2897  }while(win != root);
2898  XGetGeometry(display,root, &root, &unused, &unused,
2899               &root_width, &root_height, &d, &d);
2900
2901  /* Left edge of Video window clipped to screen */
2902  extents.x1 = 0;
2903  if(x1 > extents.x1) {
2904    extents.x1 = x1;
2905  }
2906  /* Right edge of Video window clipped to screen */
2907  extents.x2 = root_width;
2908  if(extents.x2 > (x1 + window_width)) {
2909    extents.x2 = x1 + window_width;
2910  }
2911  /* Top edge of Video window clipped to screen */
2912  extents.y1 = 0;
2913  if(y1 > extents.y1) {
2914    extents.y1 = y1;
2915  }
2916  /* Bottom edge of Video window clipped to screen */
2917  extents.y2 = root_height;
2918  if(extents.y2 > (y1 + window_height)) {
2919    extents.y2 = y1 + window_height;
2920  }
2921
2922  /*
2923    Clipping is more difficult than is seems. We need to keep the
2924    scaling factors even if the destination window needs to be clipped.
2925    We clip the destination window first then apply a scaled version
2926    to the source window.
2927  */
2928
2929  /* Put destination coords in screen coords */
2930  destx += x1;
2931  desty += y1;
2932
2933  /* Scale factors requested */
2934  xscale = (double)srcw / (double)destw;
2935  yscale = (double)srch / (double)desth;
2936
2937  /*
2938    If destination window needs to be clipped we actually adjust both
2939    the src and dest window so as to keep the scaling that was requested
2940  */
2941  clipped_srcx = srcx;
2942  clipped_srcy = srcy;
2943  clipped_destx = destx;
2944  clipped_desty = desty;
2945  clipped_srcw = srcw;
2946  clipped_srch = srch;
2947  clipped_destw = destw;
2948  clipped_desth = desth;
2949
2950  /* Clip to the source surface boundaries */
2951  if(clipped_srcx < 0) {
2952    clipped_destx += (0 - clipped_srcx) / xscale;
2953    clipped_srcw -= clipped_srcx;
2954    clipped_destw -= clipped_srcx / xscale;
2955    clipped_srcx = 0;
2956  }
2957  if((clipped_srcw + clipped_srcx) > surface->width) {
2958    clipped_srcw = surface->width - clipped_srcx;
2959    clipped_destw -= (clipped_srcw - srcw) / xscale;
2960  }
2961  if(clipped_srcy < 0) {
2962    clipped_desty += (0 - clipped_srcy) / yscale;
2963    clipped_srch -= clipped_srcy;
2964    clipped_desth -= clipped_srcy / yscale;
2965    clipped_srcy = 0;
2966  }
2967  if((clipped_srch + clipped_srcy) > surface->height) {
2968    clipped_srch = surface->height - clipped_srcy;
2969    clipped_desth -= (clipped_srch - srch) / yscale;
2970  }
2971
2972  /* Clip to the extents */
2973  if(clipped_destx < extents.x1) {
2974    diff = extents.x1 - clipped_destx;
2975    clipped_srcx += diff * xscale;
2976    clipped_srcw -= diff * xscale;
2977    clipped_destw -= diff;
2978    clipped_destx = extents.x1;
2979  }
2980
2981  diff = (clipped_destx + clipped_destw) - extents.x2;
2982  if(diff > 0) {
2983    clipped_destw -= diff;
2984    clipped_srcw -= diff * xscale;
2985  }
2986
2987  if(clipped_desty < extents.y1) {
2988    diff = extents.y1 - clipped_desty;
2989    clipped_srcy += diff * yscale;
2990    clipped_srch -= diff * yscale;
2991    clipped_desth -= diff;
2992    clipped_desty = 0;
2993  }
2994
2995  diff = (clipped_desty + clipped_desth) - extents.y2;
2996  if(diff > 0) {
2997    clipped_desth -= diff;
2998    clipped_srch -= diff * yscale;
2999  }
3000
3001  /* If the whole window is clipped turn off the overlay */
3002  if((clipped_destx + clipped_destw < extents.x1) ||
3003     (clipped_desty + clipped_desth < extents.y1) ||
3004     (clipped_destx > extents.x2) ||
3005     (clipped_desty > extents.y2)) {
3006    return XvMCHideSurface(display, surface);
3007  }
3008
3009  /*
3010    Adjust the source offset width and height according to the clipped
3011    destination window.
3012  */
3013  ysrc_offset = ((clipped_srcx + 1) & ~1) +
3014    ((clipped_srcy + 1) & ~1) * (1<<pI810Surface->pitch);
3015  uvsrc_offset = (clipped_srcx>>1) +
3016    (clipped_srcy>>1) * (1<<(pI810Surface->pitch - 1));
3017
3018  /*
3019    Initially, YCbCr and Overlay Enable and
3020    vertical chrominance up interpolation and horozontal chrominance
3021    up interpolation
3022  */
3023  ovcmd = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION |
3024    Y_ADJUST | OVERLAY_ENABLE;
3025
3026  if ((clipped_destw != clipped_srcw) ||
3027      (clipped_desth != clipped_srch)) {
3028    xscaleInt = (clipped_srcw / clipped_destw) & 0x3;
3029    xscaleFract = (clipped_srcw << 12) / clipped_destw;
3030    yscaleInt = (clipped_srch / clipped_desth) & 0x3;
3031    yscaleFract = (clipped_srch << 12) / clipped_desth;
3032
3033    if (clipped_destw > clipped_srcw) {
3034      /* horizontal up-scaling */
3035      ovcmd &= ~HORIZONTAL_CHROMINANCE_FILTER;
3036      ovcmd &= ~HORIZONTAL_LUMINANCE_FILTER;
3037      ovcmd |= (HC_UP_INTERPOLATION | HL_UP_INTERPOLATION);
3038    }
3039
3040    if (clipped_desth > clipped_srch) {
3041      /* vertical up-scaling */
3042      ovcmd &= ~VERTICAL_CHROMINANCE_FILTER;
3043      ovcmd &= ~VERTICAL_LUMINANCE_FILTER;
3044      ovcmd |= (VC_UP_INTERPOLATION | VL_UP_INTERPOLATION);
3045    }
3046
3047    if (clipped_destw < clipped_srcw) {
3048      /* horizontal down-scaling */
3049      ovcmd &= ~HORIZONTAL_CHROMINANCE_FILTER;
3050      ovcmd &= ~HORIZONTAL_LUMINANCE_FILTER;
3051      ovcmd |= (HC_DOWN_INTERPOLATION | HL_DOWN_INTERPOLATION);
3052    }
3053
3054    if (clipped_desth < clipped_srch) {
3055      /* vertical down-scaling */
3056      ovcmd &= ~VERTICAL_CHROMINANCE_FILTER;
3057      ovcmd &= ~VERTICAL_LUMINANCE_FILTER;
3058      ovcmd |= (VC_DOWN_INTERPOLATION | VL_DOWN_INTERPOLATION);
3059    }
3060
3061    /* now calculate the UV scaling factor */
3062    if (xscaleFract) {
3063      xscaleFractUV = xscaleFract >> MINUV_SCALE;
3064      ovcmd &= ~HC_DOWN_INTERPOLATION;
3065      ovcmd |= HC_UP_INTERPOLATION;
3066    }
3067
3068    if (xscaleInt) {
3069      xscaleIntUV = xscaleInt >> MINUV_SCALE;
3070      if (xscaleIntUV) {
3071	ovcmd &= ~HC_UP_INTERPOLATION;
3072      }
3073    }
3074
3075    if (yscaleFract) {
3076      yscaleFractUV = yscaleFract >> MINUV_SCALE;
3077      ovcmd &= ~VC_DOWN_INTERPOLATION;
3078      ovcmd |= VC_UP_INTERPOLATION;
3079    }
3080
3081    if (yscaleInt) {
3082      yscaleIntUV = yscaleInt >> MINUV_SCALE;
3083      if (yscaleIntUV) {
3084	ovcmd &= ~VC_UP_INTERPOLATION;
3085	ovcmd |= VC_DOWN_INTERPOLATION;
3086      }
3087    }
3088
3089  }/* if((destw != srcw) || (desth != srch)) */
3090
3091  /* Lock the DRM */
3092  I810_LOCK(pI810XvMC,0);
3093
3094  /* Block until rendering on this surface is finished */
3095  stat = XVMC_RENDERING;
3096  while(stat & XVMC_RENDERING) {
3097    XvMCGetSurfaceStatus(display,surface,&stat);
3098  }
3099  /* Block until the last flip is finished */
3100  if(pI810XvMC->last_flip) {
3101    BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current);
3102  }
3103
3104  pI810XvMC->current = !pI810XvMC->current;
3105  pORegs->OV0CMD = ovcmd;
3106
3107  if ((clipped_destw != clipped_srcw) ||
3108      (clipped_desth != clipped_srch)) {
3109    pORegs->YRGBSCALE = (xscaleInt << 15) |
3110      ((xscaleFract & 0xFFF) << 3) | (yscaleInt) |
3111      ((yscaleFract & 0xFFF) << 20);
3112
3113    pORegs->UVSCALE = yscaleIntUV | ((xscaleFractUV & 0xFFF) << 3) |
3114      ((yscaleFractUV & 0xFFF) << 20);
3115  }
3116  else {
3117    /* Normal 1:1 scaling */
3118    pORegs->YRGBSCALE = 0x80004000;
3119    pORegs->UVSCALE = 0x80004000;
3120  }
3121
3122  pORegs->SHEIGHT = clipped_srch | (clipped_srch << 15);
3123  pORegs->DWINPOS = (clipped_desty << 16) | clipped_destx;
3124  pORegs->DWINSZ = ((clipped_desth<< 16) | (clipped_destw));
3125
3126  /* Attributes */
3127  pORegs->OV0CLRC0 = ((pI810XvMC->contrast & 0x1ff)<<8) |
3128    (pI810XvMC->brightness & 0xff);
3129  pORegs->OV0CLRC1 = (pI810XvMC->saturation & 0x3ff);
3130
3131  /* Destination Colorkey Setup */
3132  pI810XvMC->oregs->DCLRKV = RGB16ToColorKey(pI810XvMC->colorkey);
3133
3134  /* buffer locations, add the offset from the clipping */
3135  if(pI810XvMC->current) {
3136    pORegs->OBUF_1Y = (unsigned long)pI810Surface->offset +
3137      (unsigned long)pI810Surface->offsets[0] + ysrc_offset;
3138    pORegs->OBUF_1V = (unsigned long)pI810Surface->offset +
3139      (unsigned long)pI810Surface->offsets[2] + uvsrc_offset;
3140    pORegs->OBUF_1U = (unsigned long)pI810Surface->offset +
3141      (unsigned long)pI810Surface->offsets[1] + uvsrc_offset;
3142  }
3143  else {
3144    pORegs->OBUF_0Y = (unsigned long)pI810Surface->offset +
3145      (unsigned long)pI810Surface->offsets[0] + ysrc_offset;
3146    pORegs->OBUF_0V = (unsigned long)pI810Surface->offset +
3147      (unsigned long)pI810Surface->offsets[2] + uvsrc_offset;
3148    pORegs->OBUF_0U = (unsigned long)pI810Surface->offset +
3149      (unsigned long)pI810Surface->offsets[1] + uvsrc_offset;
3150  }
3151
3152  switch(surface->surface_type_id) {
3153  case FOURCC_YV12:
3154  case FOURCC_I420:
3155    pORegs->SWID = (uvPitch << 16) | yPitch;
3156    pORegs->SWIDQW = (uvPitch << 13) | (yPitch >> 3);
3157    pORegs->OV0STRIDE = (1<<pI810Surface->pitch) |
3158      ((1<<pI810Surface->pitch) << 15);
3159    pORegs->OV0CMD &= ~SOURCE_FORMAT;
3160    pORegs->OV0CMD |= YUV_420;
3161    if((flags & XVMC_FRAME_PICTURE) != XVMC_FRAME_PICTURE) {
3162      /* Top Field Only */
3163      if(flags & XVMC_TOP_FIELD) {
3164	if(pI810XvMC->current == 1) {
3165	  pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD |
3166			     BUFFER1_FIELD0);
3167	}
3168	else {
3169	  pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD |
3170			     BUFFER0_FIELD0);
3171	}
3172	pORegs->YRGB_VPH = 1<<15 | 1<<31;
3173	pORegs->UV_VPH = 3<<14 | 3<<30;
3174	pORegs->INIT_PH = 0x06 | 0x18;
3175      }
3176      /* Bottom Field Only */
3177      else {
3178	if(pI810XvMC->current == 1) {
3179	  pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD |
3180			     BUFFER1_FIELD1);
3181	}
3182	else {
3183	  pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD |
3184			     BUFFER0_FIELD1);
3185	}
3186	pORegs->YRGB_VPH = 0;
3187	pORegs->UV_VPH = 7<<29 | 7<<13;
3188	pORegs->INIT_PH = 0x06;
3189      }
3190    }
3191    /* Frame Picture */
3192    else {
3193      if(pI810XvMC->current == 1) {
3194	pORegs->OV0CMD |= BUFFER1_FIELD0;
3195      }
3196      else {
3197	pORegs->OV0CMD |= BUFFER0_FIELD0;
3198      }
3199      pORegs->YRGB_VPH = 0;
3200      pORegs->UV_VPH = 0;
3201      pORegs->INIT_PH = 0;
3202    }
3203    break;
3204  case FOURCC_UYVY:
3205  case FOURCC_YUY2:
3206  default:
3207    pORegs->SWID = srcw;
3208    pORegs->SWIDQW = srcw >> 3;
3209    pORegs->OV0STRIDE = pI810Surface->pitch;
3210    pORegs->OV0CMD &= ~SOURCE_FORMAT;
3211    pORegs->OV0CMD |= YUV_422;
3212    pORegs->OV0CMD &= ~OV_BYTE_ORDER;
3213    if (surface->surface_type_id == FOURCC_UYVY) {
3214      pORegs->OV0CMD |= Y_SWAP;
3215    }
3216
3217    pORegs->OV0CMD &= ~BUFFER_AND_FIELD;
3218    if(pI810XvMC->current == 1) {
3219      pORegs->OV0CMD |= BUFFER1_FIELD0;
3220    }
3221    else {
3222      pORegs->OV0CMD |= BUFFER0_FIELD0;
3223    }
3224
3225    break;
3226  } /* switch(surface->surface_type_id) */
3227
3228
3229
3230  OVERLAY_FLIP(pI810XvMC);
3231
3232  /*
3233    The Overlay only flips when it knows you changed
3234    something. So the first time change stuff while it
3235    is watching to be sure.
3236  */
3237  if(!pI810XvMC->last_flip) {
3238    pORegs->OV0CMD &= ~0x4;
3239    if(pI810XvMC->current == 1) {
3240      pORegs->OV0CMD |= BUFFER1_FIELD0;
3241    }
3242    else {
3243      pORegs->OV0CMD |= BUFFER0_FIELD0;
3244    }
3245  }
3246  pI810Surface->last_flip = ++pI810XvMC->last_flip;
3247  I810_UNLOCK(pI810XvMC);
3248
3249  return Success;
3250}
3251
3252/***************************************************************************
3253// Function: XvMCSyncSurface
3254// Arguments:
3255//   display - Connection to the X server
3256//   surface - The surface to synchronize
3257// Info:
3258// Returns: Status
3259***************************************************************************/
3260_X_EXPORT Status XvMCSyncSurface(Display *display,XvMCSurface *surface) {
3261  Status ret;
3262  int stat=0;
3263  /*
3264    FIXME: Perhaps a timer here to prevent lockup?
3265    FIXME: Perhaps a usleep to not be busy waiting?
3266  */
3267  do {
3268    ret = XvMCGetSurfaceStatus(display,surface,&stat);
3269  }while(!ret && (stat & XVMC_RENDERING));
3270  return ret;
3271}
3272
3273/***************************************************************************
3274// Function: XvMCFlushSurface
3275// Description:
3276//   This function commits pending rendering requests to ensure that they
3277//   wll be completed in a finite amount of time.
3278// Arguments:
3279//   display - Connection to X server
3280//   surface - Surface to flush
3281// Info:
3282//   This command is a noop for i810 becuase we always dispatch buffers in
3283//   render. There is little gain to be had with 4k buffers.
3284// Returns: Status
3285***************************************************************************/
3286_X_EXPORT Status XvMCFlushSurface(Display * display, XvMCSurface *surface) {
3287  return Success;
3288}
3289
3290/***************************************************************************
3291// Function: XvMCGetSurfaceStatus
3292// Description:
3293// Arguments:
3294//  display: connection to X server
3295//  surface: The surface to query
3296//  stat: One of the Following
3297//    XVMC_RENDERING - The last XvMCRenderSurface command has not
3298//                     completed.
3299//    XVMC_DISPLAYING - The surface is currently being displayed or a
3300//                     display is pending.
3301***************************************************************************/
3302_X_EXPORT Status XvMCGetSurfaceStatus(Display *display, XvMCSurface *surface,
3303			    int *stat) {
3304  i810XvMCSurface *privSurface;
3305  i810XvMCContext *pI810XvMC;
3306  int temp;
3307
3308  if((display == NULL) || (surface == NULL) || (stat == NULL)) {
3309    return BadValue;
3310  }
3311  if(surface->privData == NULL) {
3312    return BadValue;
3313  }
3314  *stat = 0;
3315  privSurface = surface->privData;
3316
3317  pI810XvMC = privSurface->privContext;
3318  if(pI810XvMC == NULL) {
3319    return (error_base + XvMCBadSurface);
3320  }
3321
3322  I810_LOCK(pI810XvMC,0);
3323  if(privSurface->last_flip) {
3324    /* This can not happen */
3325    if(pI810XvMC->last_flip < privSurface->last_flip) {
3326      printf("Error: Context last flip is less than surface last flip.\n");
3327      return BadValue;
3328    }
3329    /*
3330      If the context has 2 or more flips after this surface it
3331      cannot be displaying. Don't bother to check.
3332    */
3333    if(!(pI810XvMC->last_flip > (privSurface->last_flip + 1))) {
3334      /*
3335	If this surface was the last flipped it is either displaying
3336	or about to be so don't bother checking.
3337      */
3338      if(pI810XvMC->last_flip == privSurface->last_flip) {
3339	*stat |= XVMC_DISPLAYING;
3340      }
3341      else {
3342	/*
3343	  In this case there has been one more flip since our surface's
3344	  but we need to check if it is finished or not.
3345	*/
3346	temp = GET_FSTATUS(pI810XvMC);
3347	if(((temp & (1<<20))>>20) != pI810XvMC->current) {
3348	  *stat |= XVMC_DISPLAYING;
3349	}
3350      }
3351    }
3352  }
3353
3354  if(privSurface->last_render &&
3355      (privSurface->last_render > GET_RSTATUS(pI810XvMC))) {
3356    *stat |= XVMC_RENDERING;
3357  }
3358  I810_UNLOCK(pI810XvMC);
3359
3360  return Success;
3361}
3362
3363/***************************************************************************
3364//
3365//  Surface manipulation functions
3366//
3367***************************************************************************/
3368
3369/***************************************************************************
3370// Function: XvMCHideSurface
3371// Description: Stops the display of a surface.
3372// Arguments:
3373//   display - Connection to the X server.
3374//   surface - surface to be hidden.
3375//
3376// Returns: Status
3377***************************************************************************/
3378_X_EXPORT Status XvMCHideSurface(Display *display, XvMCSurface *surface) {
3379  i810XvMCSurface *pI810Surface;
3380  i810XvMCContext *pI810XvMC;
3381  int ss, xx;
3382
3383  /* Did we get a good display and surface passed into us? */
3384  if(display == NULL) {
3385    return BadValue;
3386  }
3387
3388  if(surface == NULL) {
3389    return (error_base + XvMCBadSurface);
3390  }
3391
3392  XvMCSyncSurface(display, surface);
3393
3394  /* Get surface private data pointer */
3395  if(surface->privData == NULL) {
3396    return (error_base + XvMCBadSurface);
3397  }
3398  pI810Surface = (i810XvMCSurface *)surface->privData;
3399
3400  /*
3401    Get the status of the surface, if it is not currently displayed
3402    we don't need to worry about it.
3403  */
3404  if((xx = XvMCGetSurfaceStatus(display, surface, &ss)) != Success) {
3405    return xx;
3406  }
3407  if(! (ss & XVMC_DISPLAYING)) {
3408    return Success;
3409  }
3410
3411  /* Get the associated context pointer */
3412  pI810XvMC = (i810XvMCContext *)pI810Surface->privContext;
3413  if(pI810XvMC == NULL) {
3414    return (error_base + XvMCBadSurface);
3415  }
3416
3417  if(pI810XvMC->last_flip) {
3418    I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT);
3419
3420    /* Make sure last flip is done */
3421    BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current);
3422
3423    /* Set the registers to turn the overlay off */
3424    pI810XvMC->oregs->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION |
3425      Y_ADJUST;
3426    pI810XvMC->current = !pI810XvMC->current;
3427    if(pI810XvMC->current == 1) {
3428      pI810XvMC->oregs->OV0CMD |= BUFFER1_FIELD0;
3429    }
3430    else {
3431      pI810XvMC->oregs->OV0CMD |= BUFFER0_FIELD0;
3432    }
3433    OVERLAY_FLIP(pI810XvMC);
3434    /*
3435      Increment the context flip but not the surface. This way no
3436      surface has the last flip #.
3437    */
3438    pI810XvMC->last_flip++;
3439
3440
3441    /* Now wait until the hardware reads the registers and makes the change. */
3442    BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current)
3443
3444      I810_UNLOCK(pI810XvMC);
3445  }
3446
3447  return Success;
3448}
3449
3450
3451
3452
3453/***************************************************************************
3454//
3455// Functions that deal with subpictures
3456//
3457***************************************************************************/
3458
3459
3460
3461/***************************************************************************
3462// Function: XvMCCreateSubpicture
3463// Description: This creates a subpicture by filling out the XvMCSubpicture
3464//              structure passed to it and returning Success.
3465// Arguments:
3466//   display - Connection to the X server.
3467//   context - The context to create the subpicture for.
3468//   subpicture - Pre-allocated XvMCSubpicture structure to be filled in.
3469//   width - of subpicture
3470//   height - of subpicture
3471//   xvimage_id - The id describing the XvImage format.
3472//
3473// Returns: Status
3474***************************************************************************/
3475_X_EXPORT Status XvMCCreateSubpicture(Display *display, XvMCContext *context,
3476                          XvMCSubpicture *subpicture,
3477                          unsigned short width, unsigned short height,
3478                          int xvimage_id) {
3479  i810XvMCContext *pI810XvMC;
3480  i810XvMCSubpicture *pI810Subpicture;
3481  int priv_count;
3482  uint *priv_data;
3483  Status ret;
3484
3485  if((subpicture == NULL) || (context == NULL) || (display == NULL)){
3486    return BadValue;
3487  }
3488
3489  pI810XvMC = (i810XvMCContext *)context->privData;
3490  if(pI810XvMC == NULL) {
3491    return (error_base + XvMCBadContext);
3492  }
3493
3494
3495  subpicture->context_id = context->context_id;
3496  subpicture->xvimage_id = xvimage_id;
3497
3498  /* These need to be checked to make sure they are not too big! */
3499  subpicture->width = width;
3500  subpicture->height = height;
3501
3502  subpicture->privData =
3503    (i810XvMCSubpicture *)malloc(sizeof(i810XvMCSubpicture));
3504
3505  if(!subpicture->privData) {
3506    return BadAlloc;
3507  }
3508  pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData;
3509
3510
3511  if((ret = _xvmc_create_subpicture(display, context, subpicture,
3512				    &priv_count, &priv_data))) {
3513    printf("Unable to create XvMCSubpicture.\n");
3514    return ret;
3515  }
3516
3517  if(priv_count != 1) {
3518    printf("_xvmc_create_subpicture() returned incorrect data size.\n");
3519    printf("Expected 1 got %d\n",priv_count);
3520    free(priv_data);
3521    return BadAlloc;
3522  }
3523  /* Data == Client Address, offset == Physical address offset */
3524  pI810Subpicture->data = pI810XvMC->surfaces.address;
3525  pI810Subpicture->offset = pI810XvMC->surfaces.offset;
3526
3527  /* Initialize private values */
3528  pI810Subpicture->privContext = pI810XvMC;
3529
3530  pI810Subpicture->last_render = 0;
3531  pI810Subpicture->last_flip = 0;
3532
3533  /* Based on the xvimage_id we will need to set the other values */
3534  subpicture->num_palette_entries = 16;
3535  subpicture->entry_bytes = 3;
3536  strcpy(subpicture->component_order,"YUV");
3537
3538  /*
3539    i810's MC Engine needs surfaces of 2^x (x= 9,10,11,12) pitch
3540    and the Tiler need 512k aligned surfaces, basically we are
3541    stuck with fixed memory with pitch 1024.
3542  */
3543  pI810Subpicture->pitch = 10;
3544
3545  /*
3546     offsets[0] == offset into the map described by either
3547     address (Client memeory address) or offset (physical offset from fb base)
3548  */
3549  pI810Subpicture->offsets[0] = priv_data[0];
3550  if(((unsigned long)pI810Subpicture->data + pI810Subpicture->offsets[0]) & 4095) {
3551    printf("XvMCCreateSubpicture: Subpicture offset 0 is not 4096 aligned\n");
3552  }
3553
3554  /* Free data returned from xvmc_create_surface */
3555  free(priv_data);
3556
3557  /* Clear the surface to 0 */
3558  memset((void *)((unsigned long)pI810Subpicture->data + (unsigned long)pI810Subpicture->offsets[0]),
3559	 0, ((1<<pI810Subpicture->pitch) * subpicture->height));
3560
3561  switch(subpicture->xvimage_id) {
3562  case FOURCC_IA44:
3563  case FOURCC_AI44:
3564    /* Destination buffer info command */
3565    pI810Subpicture->dbi1 = ((((unsigned int)pI810Subpicture->offset +
3566			       pI810Subpicture->offsets[0]) & ~0xfc000fff) |
3567			     (pI810Subpicture->pitch - 9));
3568
3569    /* Destination buffer variables command */
3570    pI810Subpicture->dbv1 = (0x8<<20) | (0x8<<16);
3571
3572    /* Map info command */
3573    pI810Subpicture->mi1 = (0x0<<24) | (3<<21) | (1<<9) |
3574      (pI810Subpicture->pitch - 3);
3575
3576    pI810Subpicture->mi2 = (((unsigned int)subpicture->height - 1)<<16) |
3577      ((unsigned int)subpicture->width - 1);
3578
3579    pI810Subpicture->mi3 = ((unsigned int)pI810Subpicture->offset +
3580			 pI810Subpicture->offsets[0]) & ~0xfc00000f;
3581    break;
3582  default:
3583    free(subpicture->privData);
3584    return BadMatch;
3585  }
3586
3587  pI810XvMC->ref++;
3588  return Success;
3589}
3590
3591
3592
3593/***************************************************************************
3594// Function: XvMCClearSubpicture
3595// Description: Clear the area of the given subpicture to "color".
3596//              structure passed to it and returning Success.
3597// Arguments:
3598//   display - Connection to the X server.
3599//   subpicture - Subpicture to clear.
3600//   x, y, width, height - rectangle in the subpicture to clear.
3601//   color - The data to file the rectangle with.
3602//
3603// Returns: Status
3604***************************************************************************/
3605_X_EXPORT Status XvMCClearSubpicture(Display *display, XvMCSubpicture *subpicture,
3606                          short x, short y,
3607                          unsigned short width, unsigned short height,
3608                          unsigned int color) {
3609
3610  i810XvMCContext *pI810XvMC;
3611  i810XvMCSubpicture *pI810Subpicture;
3612  int i;
3613
3614  if((subpicture == NULL) || (display == NULL)){
3615    return BadValue;
3616  }
3617
3618  if(!subpicture->privData) {
3619    return (error_base + XvMCBadSubpicture);
3620  }
3621  pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData;
3622
3623  pI810XvMC = (i810XvMCContext *)pI810Subpicture->privContext;
3624  if(pI810XvMC == NULL) {
3625    return (error_base + XvMCBadSubpicture);
3626  }
3627
3628  if((x < 0) || (x + width > subpicture->width)) {
3629    return BadValue;
3630  }
3631
3632  if((y < 0) || (y + height > subpicture->height)) {
3633    return BadValue;
3634  }
3635
3636  for(i=y; i<y + height; i++) {
3637    memset((void *)((unsigned long)pI810Subpicture->data +
3638		    (unsigned long)pI810Subpicture->offsets[0] + x +
3639		    (1<<pI810Subpicture->pitch) * i),(char)color,width);
3640  }
3641
3642  return Success;
3643}
3644
3645/***************************************************************************
3646// Function: XvMCCompositeSubpicture
3647// Description: Composite the XvImae on the subpicture. This composit uses
3648//              non-premultiplied alpha. Destination alpha is utilized
3649//              except for with indexed subpictures. Indexed subpictures
3650//              use a simple "replace".
3651// Arguments:
3652//   display - Connection to the X server.
3653//   subpicture - Subpicture to clear.
3654//   image - the XvImage to be used as the source of the composite.
3655//   srcx, srcy, width, height - The rectangle from the image to be used.
3656//   dstx, dsty - location in the subpicture to composite the source.
3657//
3658// Returns: Status
3659***************************************************************************/
3660_X_EXPORT Status XvMCCompositeSubpicture(Display *display, XvMCSubpicture *subpicture,
3661                               XvImage *image,
3662                               short srcx, short srcy,
3663                               unsigned short width, unsigned short height,
3664                               short dstx, short dsty) {
3665
3666  i810XvMCContext *pI810XvMC;
3667  i810XvMCSubpicture *pI810Subpicture;
3668  int i;
3669
3670  if((subpicture == NULL) || (display == NULL)){
3671    return BadValue;
3672  }
3673
3674  if(!subpicture->privData) {
3675    return (error_base + XvMCBadSubpicture);
3676  }
3677  pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData;
3678
3679  pI810XvMC = (i810XvMCContext *)pI810Subpicture->privContext;
3680  if(pI810XvMC == NULL) {
3681    return (error_base + XvMCBadSubpicture);
3682  }
3683
3684  if((srcx < 0) || (srcx + width > image->width)) {
3685    return BadValue;
3686  }
3687
3688  if((dstx < 0) || (dstx + width > subpicture->width)) {
3689    return BadValue;
3690  }
3691
3692  if((srcy < 0) || (srcy + height > image->height)) {
3693    return BadValue;
3694  }
3695
3696  if((dsty < 0) || (dsty + height > subpicture->height)) {
3697    return BadValue;
3698  }
3699
3700  for(i=0; i<height; i++) {
3701    memcpy((void *)((unsigned long)pI810Subpicture->data +
3702		    (unsigned long)pI810Subpicture->offsets[0] + dstx +
3703		    (1<<pI810Subpicture->pitch) * (i + dsty)),
3704	   (void *)((unsigned long)image->data +
3705		    (unsigned long)image->offsets[0] + srcx +
3706		    image->pitches[0] * (i + srcy))
3707	   ,width);
3708  }
3709
3710  return Success;
3711
3712}
3713
3714
3715/***************************************************************************
3716// Function: XvMCDestroySubpicture
3717// Description: Destroys the specified subpicture.
3718// Arguments:
3719//   display - Connection to the X server.
3720//   subpicture - Subpicture to be destroyed.
3721//
3722// Returns: Status
3723***************************************************************************/
3724_X_EXPORT Status XvMCDestroySubpicture(Display *display, XvMCSubpicture *subpicture) {
3725
3726  i810XvMCSubpicture *pI810Subpicture;
3727  i810XvMCContext *pI810XvMC;
3728
3729  if((display == NULL) || (subpicture == NULL)) {
3730    return BadValue;
3731  }
3732  if(!subpicture->privData) {
3733    return (error_base + XvMCBadSubpicture);
3734  }
3735  pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData;
3736
3737  pI810XvMC = (i810XvMCContext *)pI810Subpicture->privContext;
3738  if(!pI810XvMC) {
3739    return (error_base + XvMCBadSubpicture);
3740  }
3741
3742
3743  if(pI810Subpicture->last_render) {
3744    XvMCSyncSubpicture(display,subpicture);
3745  }
3746
3747  _xvmc_destroy_subpicture(display,subpicture);
3748
3749  i810_free_privContext(pI810XvMC);
3750
3751  free(pI810Subpicture);
3752  subpicture->privData = NULL;
3753  return Success;
3754}
3755
3756
3757/***************************************************************************
3758// Function: XvMCSetSubpicturePalette
3759// Description: Set the subpictures palette
3760// Arguments:
3761//   display - Connection to the X server.
3762//   subpicture - Subpiture to set palette for.
3763//   palette - A pointer to an array holding the palette data. The array
3764//     is num_palette_entries * entry_bytes in size.
3765// Returns: Status
3766***************************************************************************/
3767
3768_X_EXPORT Status XvMCSetSubpicturePalette(Display *display, XvMCSubpicture *subpicture,
3769				unsigned char *palette) {
3770 i810XvMCSubpicture *privSubpicture;
3771 int i,j;
3772
3773 if((display == NULL) || (subpicture == NULL)) {
3774   return BadValue;
3775 }
3776 if(subpicture->privData == NULL) {
3777   return (error_base + XvMCBadSubpicture);
3778 }
3779 privSubpicture = (i810XvMCSubpicture *)subpicture->privData;
3780
3781 j=0;
3782 for(i=0; i<16; i++) {
3783   privSubpicture->palette[0][i] = palette[j++];
3784   privSubpicture->palette[1][i] = palette[j++];
3785   privSubpicture->palette[2][i] = palette[j++];
3786 }
3787 return Success;
3788}
3789
3790/***************************************************************************
3791// Function: XvMCBlendSubpicture
3792// Description:
3793//    The behavior of this function is different depending on whether
3794//    or not the XVMC_BACKEND_SUBPICTURE flag is set in the XvMCSurfaceInfo.
3795//    i810 only support frontend behavior.
3796//
3797//    XVMC_BACKEND_SUBPICTURE not set ("frontend" behavior):
3798//
3799//    XvMCBlendSubpicture is a no-op in this case.
3800//
3801// Arguments:
3802//   display - Connection to the X server.
3803//   subpicture - The subpicture to be blended into the video.
3804//   target_surface - The surface to be displayed with the blended subpic.
3805//   source_surface - Source surface prior to blending.
3806//   subx, suby, subw, subh - The rectangle from the subpicture to use.
3807//   surfx, surfy, surfw, surfh - The rectangle in the surface to blend
3808//      blend the subpicture rectangle into. Scaling can ocure if
3809//      XVMC_SUBPICTURE_INDEPENDENT_SCALING is set.
3810//
3811// Returns: Status
3812***************************************************************************/
3813_X_EXPORT Status XvMCBlendSubpicture(Display *display, XvMCSurface *target_surface,
3814                         XvMCSubpicture *subpicture,
3815                         short subx, short suby,
3816                         unsigned short subw, unsigned short subh,
3817                         short surfx, short surfy,
3818                         unsigned short surfw, unsigned short surfh) {
3819
3820  return BadMatch;
3821}
3822
3823
3824
3825/***************************************************************************
3826// Function: XvMCBlendSubpicture2
3827// Description:
3828//    The behavior of this function is different depending on whether
3829//    or not the XVMC_BACKEND_SUBPICTURE flag is set in the XvMCSurfaceInfo.
3830//    i810 only supports frontend blending.
3831//
3832//    XVMC_BACKEND_SUBPICTURE not set ("frontend" behavior):
3833//
3834//    XvMCBlendSubpicture2 blends the source_surface and subpicture and
3835//    puts it in the target_surface.  This does not effect the status of
3836//    the source surface but will cause the target_surface to query
3837//    XVMC_RENDERING until the blend is completed.
3838//
3839// Arguments:
3840//   display - Connection to the X server.
3841//   subpicture - The subpicture to be blended into the video.
3842//   target_surface - The surface to be displayed with the blended subpic.
3843//   source_surface - Source surface prior to blending.
3844//   subx, suby, subw, subh - The rectangle from the subpicture to use.
3845//   surfx, surfy, surfw, surfh - The rectangle in the surface to blend
3846//      blend the subpicture rectangle into. Scaling can ocure if
3847//      XVMC_SUBPICTURE_INDEPENDENT_SCALING is set.
3848//
3849// Returns: Status
3850***************************************************************************/
3851_X_EXPORT Status XvMCBlendSubpicture2(Display *display,
3852                          XvMCSurface *source_surface,
3853                          XvMCSurface *target_surface,
3854                          XvMCSubpicture *subpicture,
3855                          short subx, short suby,
3856                          unsigned short subw, unsigned short subh,
3857                          short surfx, short surfy,
3858                          unsigned short surfw, unsigned short surfh) {
3859  drmBufPtr pDMA;
3860  unsigned int *data;
3861  i810XvMCContext *pI810XvMC;
3862  i810XvMCSubpicture *privSubpicture;
3863  i810XvMCSurface *privTarget;
3864  i810XvMCSurface *privSource;
3865  drm_i810_mc_t mc;
3866  int i,j;
3867
3868  if(display == NULL) {
3869    return BadValue;
3870  }
3871
3872  if(subpicture == NULL) {
3873    return (error_base + XvMCBadSubpicture);
3874  }
3875
3876  if((target_surface == NULL) || (source_surface == NULL)) {
3877    return (error_base + XvMCBadSurface);
3878  }
3879
3880  if((subpicture->xvimage_id != FOURCC_AI44) &&
3881     (subpicture->xvimage_id != FOURCC_IA44)) {
3882      return (error_base + XvMCBadSubpicture);
3883  }
3884
3885  if(!subpicture->privData) {
3886    return (error_base + XvMCBadSubpicture);
3887  }
3888  privSubpicture = (i810XvMCSubpicture *)subpicture->privData;
3889
3890  pI810XvMC = (i810XvMCContext *)privSubpicture->privContext;
3891  if(pI810XvMC == NULL) {
3892    return (error_base + XvMCBadSubpicture);
3893  }
3894
3895  if(!target_surface->privData) {
3896    return (error_base + XvMCBadSurface);
3897  }
3898  privTarget = (i810XvMCSurface *)target_surface->privData;
3899
3900  if(!source_surface->privData) {
3901    return (error_base + XvMCBadSurface);
3902  }
3903  privSource = (i810XvMCSurface *)source_surface->privData;
3904
3905
3906  /* Check that size isn't bigger than subpicture */
3907  if((subx + subw) > subpicture->width) {
3908    return BadValue;
3909  }
3910  if((suby + subh) > subpicture->height) {
3911    return BadValue;
3912  }
3913  /* Check that dest isn't bigger than surface */
3914  if((surfx + surfw) > target_surface->width) {
3915    return BadValue;
3916  }
3917  if((surfy + surfh) > target_surface->height) {
3918    return BadValue;
3919  }
3920  /* Make sure surfaces match */
3921  if(target_surface->width != source_surface->width) {
3922    return BadValue;
3923  }
3924  if(target_surface->height != source_surface->height) {
3925    return BadValue;
3926  }
3927
3928  /* Lock For DMA */
3929  I810_LOCK(pI810XvMC,0);
3930
3931  /* Allocate DMA buffer */
3932  pDMA = i810_get_free_buffer(pI810XvMC);
3933  data = pDMA->address;
3934
3935  /* Copy Y data first */
3936  /* SOURCE_COPY_BLT */
3937  *data++ = (2<<29) | (0x43<<22) | 0x4;
3938  *data++ = (0xcc<<16) | (1<<26) | (1<<privTarget->pitch);
3939  *data++ = (target_surface->height<<16) | target_surface->width;
3940  *data++ = privTarget->offset + privTarget->offsets[0];
3941  *data++ = (1<<privSource->pitch);
3942  *data++ = privSource->offset + privSource->offsets[0];
3943
3944  /* Select Context 1 for loading */
3945  *data++ = CMD_FLUSH;
3946  *data++ = (5<<23) | (1<<17) | (1<<8);
3947  *data++ = CMD_FLUSH;
3948
3949  /* Load Palette */
3950  *data++ = MAP_PALETTE_LOAD;
3951  /* 16 levels of alpha for each Y */
3952  switch(subpicture->xvimage_id) {
3953  case FOURCC_IA44:
3954    for(i=0; i<16; i++) {
3955      for(j=0; j<16; j++) {
3956        *data++ = (j<<12) | (j<<8) | privSubpicture->palette[0][i];
3957      }
3958    }
3959    break;
3960  case FOURCC_AI44:
3961    for(i=0; i<16; i++) {
3962      for(j=0; j<16; j++) {
3963        *data++ = (i<<12) | (i<<8) | privSubpicture->palette[0][j];
3964      }
3965    }
3966    break;
3967  }
3968  /* TARGET */
3969  /* *data++ = CMD_FLUSH; */
3970  /* *data++ = BOOLEAN_ENA_2; */
3971  *data++ = CMD_FLUSH;
3972  *data++ = DEST_BUFFER_INFO;
3973  *data++ = privTarget->dbi1y;
3974  *data++ = DEST_BUFFER_VAR;
3975  *data++ = privTarget->dbv1;
3976
3977  /* ALPHA */
3978  *data++ = CMD_MAP_INFO;
3979  *data++ = privSubpicture->mi1;
3980  *data++ = privSubpicture->mi2;
3981  *data++ = privSubpicture->mi3;
3982
3983  *data++ = VERTEX_FORMAT | (1<<8) | (3<<1);
3984  *data++ = BOOLEAN_ENA_1;
3985  *data++ = SRC_DEST_BLEND_MONO | (0x940);
3986  /* Map Filter */
3987  *data++ = (3<<29) | (0x1c<<24) | (2<<19) | (0x224);
3988
3989  /* Use context 1 */
3990  *data++ = CMD_FLUSH;
3991  *data++ = (5<<23) | (1<<16) | 1;
3992  *data++ = CMD_FLUSH;
3993
3994  /* Drawing Rect Info */
3995  *data++ = DRAWING_RECT_INFO;
3996  *data++ = 0x0;
3997  *data++ = 0x0;
3998  *data++ = 0x0;
3999  *data++ = 0x0;
4000  *data++ = 0x0;
4001
4002  /* GFXPRIMITIVE RECTANGLE */
4003  *data++ = (3<<29) | (0x1f<<24) | (0x7<<18) | 11;
4004  /* Bottom Right Vertex */
4005  *(float *)data++ = (float) (surfx + surfw);
4006  *(float *)data++ = (float) (surfy + surfh);
4007  *(float *)data++ = (float) (subx + subw);
4008  *(float *)data++ = (float) (suby + subh);
4009  /* Bottom Left Vertex */
4010  *(float *)data++ = (float) surfx;
4011  *(float *)data++ = (float) (surfy + surfh);
4012  *(float *)data++ = (float) subx;
4013  *(float *)data++ = (float) (suby + subh);
4014  /* Top Left Vertex */
4015  *(float *)data++ = (float) surfx;
4016  *(float *)data++ = (float) surfy;
4017  *(float *)data++ = (float) subx;
4018  *(float *)data++ = (float) suby;
4019
4020  /* Load and Use Context 0 */
4021  *data++ = CMD_FLUSH;
4022  *data++ = (5<<23) | (1<<17) | (1<<16);
4023  *data++ = CMD_FLUSH;
4024
4025  /* U data */
4026  /* SOURCE_COPY_BLT */
4027  *data++ = (2<<29) | (0x43<<22) | 0x4;
4028  *data++ = (0xcc<<16) | (1<<26) | (1<<(privTarget->pitch - 1));
4029  *data++ = (target_surface->height<<15) | (target_surface->width>>1);
4030  *data++ = (unsigned long)privTarget->offset + (unsigned long)privTarget->offsets[1];
4031  *data++ = (1<<(privSource->pitch - 1));
4032  *data++ = (unsigned long)privSource->offset + (unsigned long)privSource->offsets[1];
4033
4034  /* Context 1 select */
4035  *data++ = CMD_FLUSH;
4036  *data++ = (5<<23) | (1<<17) | (1<<8);
4037  *data++ = CMD_FLUSH;
4038  /* ALPHA PALETTE */
4039  *data++ = MAP_PALETTE_LOAD;
4040  /* 16 levels of alpha for each Y */
4041  switch(subpicture->xvimage_id) {
4042  case FOURCC_IA44:
4043    for(i=0; i<16; i++) {
4044      for(j=0; j<16; j++) {
4045        *data++ = (j<<12) | (j<<8) | privSubpicture->palette[2][i];
4046      }
4047    }
4048    break;
4049  case FOURCC_AI44:
4050    for(i=0; i<16; i++) {
4051      for(j=0; j<16; j++) {
4052        *data++ = (i<<12) | (i<<8) | privSubpicture->palette[2][j];
4053      }
4054    }
4055    break;
4056  }
4057  /* TARGET */
4058  *data++ = CMD_FLUSH;
4059  *data++ = BOOLEAN_ENA_2;
4060  *data++ = CMD_FLUSH;
4061  *data++ = DEST_BUFFER_INFO;
4062  *data++ = privTarget->dbi1u;
4063  *data++ = DEST_BUFFER_VAR;
4064  *data++ = privTarget->dbv1;
4065
4066  /* ALPHA */
4067  *data++ = CMD_MAP_INFO;
4068  *data++ = privSubpicture->mi1;
4069  *data++ = privSubpicture->mi2;
4070  *data++ = privSubpicture->mi3;
4071
4072  *data++ = VERTEX_FORMAT | (1<<8) | (3<<1);
4073  *data++ = BOOLEAN_ENA_1;
4074  *data++ = SRC_DEST_BLEND_MONO | (0x940);
4075  /* Map Filter */
4076  *data++ = (3<<29) | (0x1c<<24) | (2<<19) | (1<<16) | (0x224);
4077
4078  /* Use context 1 */
4079  *data++ = CMD_FLUSH;
4080  *data++ = (5<<23) | (1<<16) | 1;
4081  *data++ = CMD_FLUSH;
4082
4083  /* Drawing Rect Info */
4084  *data++ = (3<<29) | (0x1d<<24) | (0x80<<16) | 3;
4085  *data++ = 0;
4086  *data++ = 0;
4087  *data++ = 0;
4088  *data++ = 0;
4089  *data++ = 0;
4090
4091  /* Rectangle */
4092  *data++ = (3<<29) | (0x1f<<24) | (0x7<<18) | 11;
4093  /* Bottom Right */
4094  *(float *)data++ = (float) ((surfx + surfw)>>1);
4095  *(float *)data++ = (float) ((surfy + surfh)>>1);
4096  *(float *)data++ = (float) subx + subw;
4097  *(float *)data++ = (float) suby + subh;
4098  /* Bottom Left */
4099  *(float *)data++ = (float) (surfx>>1);
4100  *(float *)data++ = (float) ((surfy + surfh)>>1);
4101  *(float *)data++ = (float) subx;
4102  *(float *)data++ = (float) suby + subh;
4103  /* Top Left */
4104  *(float *)data++ = (float) (surfx>>1);
4105  *(float *)data++ = (float) (surfy>>1);
4106  *(float *)data++ = (float) subx;
4107  *(float *)data++ = (float) suby;
4108
4109  /* Load and Use Context 0 */
4110  *data++ = CMD_FLUSH;
4111  *data++ = (5<<23) | (1<<17) | (1<<16);
4112  *data++ = CMD_FLUSH;
4113
4114  /* V data */
4115  /* SOURCE_COPY_BLT */
4116  *data++ = (2<<29) | (0x43<<22) | 0x4;
4117  *data++ = (0xcc<<16) | (1<<26) | (1<<(privTarget->pitch - 1));
4118  *data++ = (target_surface->height<<15) | (target_surface->width>>1);
4119  *data++ = (unsigned long)privTarget->offset + (unsigned long)privTarget->offsets[2];
4120  *data++ = (1<<(privSource->pitch - 1));
4121  *data++ = (unsigned long)privSource->offset + (unsigned long)privSource->offsets[2];
4122
4123  /* Context 1 select */
4124  *data++ = CMD_FLUSH;
4125  *data++ = (5<<23) | (1<<17) | (1<<8);
4126  *data++ = CMD_FLUSH;
4127
4128  /* ALPHA PALETTE */
4129  *data++ = MAP_PALETTE_LOAD;
4130  /* 16 levels of alpha for each Y */
4131  switch(subpicture->xvimage_id) {
4132  case FOURCC_IA44:
4133    for(i=0; i<16; i++) {
4134      for(j=0; j<16; j++) {
4135        *data++ = (j<<12) | (j<<8) | privSubpicture->palette[1][i];
4136      }
4137    }
4138    break;
4139  case FOURCC_AI44:
4140    for(i=0; i<16; i++) {
4141      for(j=0; j<16; j++) {
4142        *data++ = (i<<12) | (i<<8) | privSubpicture->palette[1][j];
4143      }
4144    }
4145    break;
4146  }
4147  /* TARGET */
4148  *data++ = CMD_FLUSH;
4149  *data++ = BOOLEAN_ENA_2;
4150  *data++ = CMD_FLUSH;
4151  *data++ = DEST_BUFFER_INFO;
4152  *data++ = privTarget->dbi1v;
4153  *data++ = DEST_BUFFER_VAR;
4154  *data++ = privTarget->dbv1;
4155
4156  /* ALPHA */
4157  *data++ = CMD_MAP_INFO;
4158  *data++ = privSubpicture->mi1;
4159  *data++ = privSubpicture->mi2;
4160  *data++ = privSubpicture->mi3;
4161
4162  *data++ = VERTEX_FORMAT | (1<<8) | (3<<1);
4163  *data++ = BOOLEAN_ENA_1;
4164  *data++ = SRC_DEST_BLEND_MONO | (0x940);
4165  /* Map Filter */
4166  *data++ = (3<<29) | (0x1c<<24) | (2<<19) | (1<<16) | (0x224);
4167
4168  /* Use context 1 */
4169  *data++ = CMD_FLUSH;
4170  *data++ = (5<<23) | (1<<16) | 1;
4171  *data++ = CMD_FLUSH;
4172
4173  /* Drawing Rect Info */
4174  *data++ = (3<<29) | (0x1d<<24) | (0x80<<16) | 3;
4175  *data++ = 0;
4176  *data++ = 0;
4177  *data++ = 0;
4178  *data++ = 0;
4179  *data++ = 0;
4180
4181  /* Rectangle */
4182  *data++ = (3<<29) | (0x1f<<24) | (0x7<<18) | 11;
4183  /* Bottom Right */
4184  *(float *)data++ = (float) ((surfx + surfw)>>1);
4185  *(float *)data++ = (float) ((surfy + surfh)>>1);
4186  *(float *)data++ = (float) subx + subw;
4187  *(float *)data++ = (float) suby + subh;
4188  /* Bottom Left */
4189  *(float *)data++ = (float) (surfx>>1);
4190  *(float *)data++ = (float) ((surfy + surfh)>>1);
4191  *(float *)data++ = (float) subx;
4192  *(float *)data++ = (float) suby + subh;
4193  /* Top Left */
4194  *(float *)data++ = (float) (surfx>>1);
4195  *(float *)data++ = (float) (surfy>>1);
4196  *(float *)data++ = (float) subx;
4197  *(float *)data++ = (float) suby;
4198
4199  /* Load and Use Context 0 */
4200  *data++ = CMD_FLUSH;
4201  *data++ = (5<<23) | (1<<17) | (1<<16);
4202  *data++ = CMD_FLUSH;
4203
4204
4205  /* Dispatch */
4206  pDMA->used = (unsigned long)data - (unsigned long)pDMA->address;
4207  mc.idx = pDMA->idx;
4208  mc.used = pDMA->used;
4209  mc.last_render = ++pI810XvMC->last_render;
4210  privTarget->last_render = pI810XvMC->last_render;
4211  I810_MC(pI810XvMC,mc);
4212
4213  I810_UNLOCK(pI810XvMC);
4214  return Success;
4215}
4216
4217
4218
4219/***************************************************************************
4220// Function: XvMCSyncSubpicture
4221// Description: This function blocks until all composite/clear requests on
4222//              the subpicture have been complete.
4223// Arguments:
4224//   display - Connection to the X server.
4225//   subpicture - The subpicture to synchronize
4226//
4227// Returns: Status
4228***************************************************************************/
4229_X_EXPORT Status XvMCSyncSubpicture(Display *display, XvMCSubpicture *subpicture) {
4230  Status ret;
4231  int stat=0;
4232  do {
4233    ret = XvMCGetSubpictureStatus(display,subpicture,&stat);
4234  }while(!ret && (stat & XVMC_RENDERING));
4235  return ret;
4236}
4237
4238
4239
4240/***************************************************************************
4241// Function: XvMCFlushSubpicture
4242// Description: This function commits pending composite/clear requests to
4243//              ensure that they will be completed in a finite amount of
4244//              time.
4245// Arguments:
4246//   display - Connection to the X server.
4247//   subpicture - The subpicture whos compsiting should be flushed
4248//
4249// Returns: Status
4250// NOTES: i810 always dispatches commands so flush is a no-op
4251***************************************************************************/
4252_X_EXPORT Status XvMCFlushSubpicture(Display *display, XvMCSubpicture *subpicture) {
4253  if(display == NULL) {
4254    return BadValue;
4255  }
4256  if(subpicture == NULL) {
4257    return (error_base + XvMCBadSubpicture);
4258  }
4259
4260  return Success;
4261}
4262
4263
4264
4265/***************************************************************************
4266// Function: XvMCGetSubpictureStatus
4267// Description: This function gets the current status of a subpicture
4268//
4269// Arguments:
4270//   display - Connection to the X server.
4271//   subpicture - The subpicture whos status is being queried
4272//   stat - The status of the subpicture. It can be any of the following
4273//          OR'd together:
4274//          XVMC_RENDERING  - Last composite or clear request not completed
4275//          XVMC_DISPLAYING - Suppicture currently being displayed.
4276//
4277// Returns: Status
4278// Notes: i810 always blends into a third surface so the subpicture is
4279//  never actually displaying, only a copy of it is displaying. We only
4280//  have to worry about the rendering case.
4281***************************************************************************/
4282_X_EXPORT Status XvMCGetSubpictureStatus(Display *display, XvMCSubpicture *subpicture,
4283                             int *stat) {
4284
4285  i810XvMCSubpicture *privSubpicture;
4286  i810XvMCContext *pI810XvMC;
4287
4288  if((display == NULL) || (stat == NULL)) {
4289    return BadValue;
4290  }
4291  if((subpicture == NULL) || (subpicture->privData == NULL)) {
4292    return (error_base + XvMCBadSubpicture);
4293  }
4294  *stat = 0;
4295  privSubpicture = (i810XvMCSubpicture *)subpicture->privData;
4296
4297  pI810XvMC = (i810XvMCContext *)privSubpicture->privContext;
4298  if(pI810XvMC == NULL) {
4299    return (error_base + XvMCBadSubpicture);
4300  }
4301
4302  I810_LOCK(pI810XvMC,0);
4303
4304  if(privSubpicture->last_render &&
4305      (privSubpicture->last_render > GET_RSTATUS(pI810XvMC))) {
4306    *stat |= XVMC_RENDERING;
4307  }
4308  I810_UNLOCK(pI810XvMC);
4309
4310  return Success;
4311}
4312
4313#define NUM_XVMC_ATTRIBUTES 4
4314static XvAttribute I810_XVMC_ATTRIBUTES[] = {
4315  {XvGettable | XvSettable, 0, 0xffffff, "XV_COLORKEY"},
4316  {XvGettable | XvSettable, -127, +127, "XV_BRIGHTNESS"},
4317  {XvGettable | XvSettable, 0, 0x1ff, "XV_CONTRAST"},
4318  {XvGettable | XvSettable, 0, 0x3ff, "XV_SATURATION"}
4319};
4320
4321
4322/***************************************************************************
4323// Function: XvMCQueryAttributes
4324// Description: An array of XvAttributes of size "number" is returned by
4325//   this function. If there are no attributes, NULL is returned and number
4326//   is set to 0. The array may be freed with xfree().
4327//
4328// Arguments:
4329//   display - Connection to the X server.
4330//   context - The context whos attributes we are querying.
4331//   number - The number of returned atoms.
4332//
4333// Returns:
4334//  An array of XvAttributes.
4335// Notes:
4336//   For i810 we support these Attributes:
4337//    XV_COLORKEY: The colorkey value, initialized from the Xv value at
4338//                 context creation time.
4339//    XV_BRIGHTNESS
4340//    XV_CONTRAST
4341//    XV_SATURATION
4342***************************************************************************/
4343_X_EXPORT XvAttribute *XvMCQueryAttributes(Display *display, XvMCContext *context,
4344				 int *number) {
4345  i810XvMCContext *pI810XvMC;
4346  XvAttribute *attributes;
4347
4348  if(number == NULL) {
4349    return NULL;
4350  }
4351  if(display == NULL) {
4352    *number = 0;
4353    return NULL;
4354  }
4355  if(context == NULL) {
4356    *number = 0;
4357    return NULL;
4358  }
4359  pI810XvMC = context->privData;
4360  if(pI810XvMC == NULL) {
4361    *number = 0;
4362    return NULL;
4363  }
4364
4365  attributes = (XvAttribute *)malloc(NUM_XVMC_ATTRIBUTES *
4366				     sizeof(XvAttribute));
4367  if(attributes == NULL) {
4368    *number = 0;
4369    return NULL;
4370  }
4371
4372  memcpy(attributes,I810_XVMC_ATTRIBUTES,(NUM_XVMC_ATTRIBUTES *
4373					  sizeof(XvAttribute)));
4374
4375  *number = NUM_XVMC_ATTRIBUTES;
4376  return attributes;
4377}
4378
4379/***************************************************************************
4380// Function: XvMCSetAttribute
4381// Description: This function sets a context-specific attribute.
4382//
4383// Arguments:
4384//   display - Connection to the X server.
4385//   context - The context whos attributes we are querying.
4386//   attribute - The X atom of the attribute to be changed.
4387//   value - The new value for the attribute.
4388//
4389// Returns:
4390//  Status
4391// Notes:
4392//   For i810 we support these Attributes:
4393//    XV_COLORKEY: The colorkey value, initialized from the Xv value at
4394//                 context creation time.
4395//    XV_BRIGHTNESS
4396//    XV_CONTRAST
4397//    XV_SATURATION
4398***************************************************************************/
4399_X_EXPORT Status XvMCSetAttribute(Display *display, XvMCContext *context,
4400			Atom attribute, int value) {
4401  i810XvMCContext *pI810XvMC;
4402
4403  if(display == NULL) {
4404    return BadValue;
4405  }
4406  if(context == NULL) {
4407    return (error_base + XvMCBadContext);
4408  }
4409  pI810XvMC = context->privData;
4410  if(pI810XvMC == NULL) {
4411    return (error_base + XvMCBadContext);
4412  }
4413
4414  if(attribute == pI810XvMC->xv_colorkey) {
4415    if((value < I810_XVMC_ATTRIBUTES[0].min_value) ||
4416       (value > I810_XVMC_ATTRIBUTES[0].max_value)) {
4417      return BadValue;
4418    }
4419    pI810XvMC->colorkey = value;
4420    return Success;
4421  }
4422  if(attribute == pI810XvMC->xv_brightness) {
4423    if((value < I810_XVMC_ATTRIBUTES[1].min_value) ||
4424       (value > I810_XVMC_ATTRIBUTES[1].max_value)) {
4425      return BadValue;
4426    }
4427    pI810XvMC->brightness = value;
4428    return Success;
4429  }
4430  if(attribute == pI810XvMC->xv_saturation) {
4431    if((value < I810_XVMC_ATTRIBUTES[2].min_value) ||
4432       (value > I810_XVMC_ATTRIBUTES[2].max_value)) {
4433      return BadValue;
4434    }
4435    pI810XvMC->saturation = value;
4436    return Success;
4437  }
4438  if(attribute == pI810XvMC->xv_contrast) {
4439    if((value < I810_XVMC_ATTRIBUTES[3].min_value) ||
4440       (value > I810_XVMC_ATTRIBUTES[3].max_value)) {
4441      return BadValue;
4442    }
4443    pI810XvMC->contrast = value;
4444    return Success;
4445  }
4446  return BadValue;
4447}
4448
4449/***************************************************************************
4450// Function: XvMCGetAttribute
4451// Description: This function queries a context-specific attribute and
4452//   returns the value.
4453//
4454// Arguments:
4455//   display - Connection to the X server.
4456//   context - The context whos attributes we are querying.
4457//   attribute - The X atom of the attribute to be queried
4458//   value - The returned attribute value
4459//
4460// Returns:
4461//  Status
4462// Notes:
4463//   For i810 we support these Attributes:
4464//    XV_COLORKEY: The colorkey value, initialized from the Xv value at
4465//                 context creation time.
4466//    XV_BRIGHTNESS
4467//    XV_CONTRAST
4468//    XV_SATURATION
4469***************************************************************************/
4470_X_EXPORT Status XvMCGetAttribute(Display *display, XvMCContext *context,
4471			Atom attribute, int *value) {
4472  i810XvMCContext *pI810XvMC;
4473
4474  if(display == NULL) {
4475    return BadValue;
4476  }
4477  if(context == NULL) {
4478    return (error_base + XvMCBadContext);
4479  }
4480  pI810XvMC = context->privData;
4481  if(pI810XvMC == NULL) {
4482    return (error_base + XvMCBadContext);
4483  }
4484  if(value == NULL) {
4485    return BadValue;
4486  }
4487
4488  if(attribute == pI810XvMC->xv_colorkey) {
4489    *value = pI810XvMC->colorkey;
4490    return Success;
4491  }
4492  if(attribute == pI810XvMC->xv_brightness) {
4493    *value = pI810XvMC->brightness;
4494    return Success;
4495  }
4496  if(attribute == pI810XvMC->xv_saturation) {
4497    *value = pI810XvMC->saturation;
4498    return Success;
4499  }
4500  if(attribute == pI810XvMC->xv_contrast) {
4501    *value = pI810XvMC->contrast;
4502    return Success;
4503  }
4504  return BadValue;
4505}
4506
4507
4508
4509
4510