i810_dri.c revision 03b705cf
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <errno.h>
6#include <stdio.h>
7#include <string.h>
8#include <assert.h>
9
10#include "xf86.h"
11#include "xf86_OSproc.h"
12
13#include "xf86Pci.h"
14
15#include "windowstr.h"
16#include "shadow.h"
17#include "shadowfb.h"
18
19#include "i810.h"
20#include "i810_dri.h"
21
22static char I810KernelDriverName[] = "i810";
23static char I810ClientDriverName[] = "i810";
24
25static Bool I810CreateContext(ScreenPtr pScreen, VisualPtr visual,
26			      drm_context_t hwContext, void *pVisualConfigPriv,
27			      DRIContextType contextStore);
28static void I810DestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
29			       DRIContextType contextStore);
30static void I810DRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
31			       DRIContextType readContextType,
32			       void *readContextStore,
33			       DRIContextType writeContextType,
34			       void *writeContextStore);
35static void I810DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index);
36static void I810DRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg,
37			       RegionPtr prgnSrc, CARD32 index);
38
39
40static void I810EnablePageFlip(ScreenPtr pScreen);
41static void I810DisablePageFlip(ScreenPtr pScreen);
42static void I810DRITransitionSingleToMulti3d(ScreenPtr pScreen);
43static void I810DRITransitionMultiToSingle3d(ScreenPtr pScreen);
44static void I810DRITransitionTo3d(ScreenPtr pScreen);
45static void I810DRITransitionTo2d(ScreenPtr pScreen);
46
47static void I810DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox);
48
49static int i810_pitches[] = {
50   512,
51   1024,
52   2048,
53   4096,
54   0
55};
56
57static int i810_pitch_flags[] = {
58   0x0,
59   0x1,
60   0x2,
61   0x3,
62   0
63};
64
65static unsigned int i810_drm_version = 0;
66
67Bool
68I810CleanupDma(ScrnInfoPtr pScrn)
69{
70   I810Ptr pI810 = I810PTR(pScrn);
71   drmI810Init info;
72
73   memset(&info, 0, sizeof(drmI810Init));
74   info.func = I810_CLEANUP_DMA;
75
76   if (drmCommandWrite(pI810->drmSubFD, DRM_I810_INIT,
77		       &info, sizeof(drmI810Init))) {
78      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
79		 "[dri] I810 Dma Cleanup Failed\n");
80      return FALSE;
81   }
82
83   return TRUE;
84}
85
86Bool
87I810InitDma(ScrnInfoPtr pScrn)
88{
89   I810Ptr pI810 = I810PTR(pScrn);
90   I810RingBuffer *ring = pI810->LpRing;
91   I810DRIPtr pI810DRI = (I810DRIPtr) pI810->pDRIInfo->devPrivate;
92   drmI810Init info;
93
94   memset(&info, 0, sizeof(drmI810Init));
95
96   info.ring_start = ring->mem.Start;
97   info.ring_end = ring->mem.End;
98   info.ring_size = ring->mem.Size;
99   info.mmio_offset = (unsigned int)pI810DRI->regs;
100   info.buffers_offset = (unsigned int)pI810->buffer_map;
101   info.sarea_priv_offset = sizeof(XF86DRISAREARec);
102
103   info.front_offset = 0;
104   info.back_offset = pI810->BackBuffer.Start;
105   info.depth_offset = pI810->DepthBuffer.Start;
106   info.overlay_offset = pI810->OverlayStart;
107   info.overlay_physical = pI810->OverlayPhysical;
108   info.w = pScrn->virtualX;
109   info.h = pScrn->virtualY;
110   info.pitch = pI810->auxPitch;
111   info.pitch_bits = pI810->auxPitchBits;
112
113   /* We require DRM v1.2 or greater. Since DRM v1.2 broke compatibility
114    * we created a new v1.4 that supports a new init function. Eventually the
115    * old init function will go away. If you change the drm interface, make a
116    * new init type too so that we can detect the new client.
117    */
118   switch(i810_drm_version) {
119   case ((1<<16) | 0):
120   case ((1<<16) | 1):
121   case ((1<<16) | 2):
122   case ((1<<16) | 3):
123      /* Use OLD drm < 1.4 init */
124      info.func = I810_INIT_DMA;
125      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Init PRE v1.4 interface.\n");
126      break;
127   default:
128   case ((1<<16) | 4):
129      /*  DRM version 1.3 or greater init */
130      info.func = I810_INIT_DMA_1_4;
131      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[drm] Init v1.4 interface.\n");
132      break;
133   }
134
135   if (drmCommandWrite(pI810->drmSubFD, DRM_I810_INIT,
136		       &info, sizeof(drmI810Init))) {
137      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
138		 "[drm] I810 Dma Initialization failed.\n");
139      return FALSE;
140   }
141
142   return TRUE;
143}
144
145static unsigned int
146mylog2(unsigned int n)
147{
148   unsigned int log2 = 1;
149
150   while (n > 1)
151      n >>= 1, log2++;
152   return log2;
153}
154
155Bool
156I810DRIScreenInit(ScreenPtr pScreen)
157{
158   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
159   I810Ptr pI810 = I810PTR(pScrn);
160   DRIInfoPtr pDRIInfo;
161   I810DRIPtr pI810DRI;
162   unsigned long tom;
163   drm_handle_t agpHandle;
164   drm_handle_t dcacheHandle;
165   int sysmem_size = 0;
166   int back_size = 0;
167   unsigned int pitch_idx = 0;
168   int bufs;
169   int width = pScrn->displayWidth * pI810->cpp;
170   int i;
171
172   /* Hardware 3D rendering only implemented for 16bpp */
173   /* And it only works for 5:6:5 (Mark) */
174   if (pScrn->depth != 16)
175      return FALSE;
176
177   /* Check that the DRI, and DRM modules have been loaded by testing
178    * for known symbols in each module. */
179   if (!xf86LoaderCheckSymbol("drmAvailable"))
180      return FALSE;
181   if (!xf86LoaderCheckSymbol("DRIQueryVersion")) {
182      xf86DrvMsg(pScreen->myNum, X_ERROR,
183		 "[dri] I810DRIScreenInit failed (libdri.a too old)\n");
184      return FALSE;
185   }
186
187   /* adjust width first */
188#define Elements(x) sizeof(x)/sizeof(*x)
189   for (pitch_idx = 0; pitch_idx < Elements(i810_pitches); pitch_idx++)
190      if (width <= i810_pitches[pitch_idx])
191	 break;
192
193   if (pitch_idx == Elements(i810_pitches)) {
194      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
195		 "[dri] Couldn't find depth/back buffer pitch");
196      DRICloseScreen(pScreen);
197      return FALSE;
198   } else {
199      /* for tiled memory to work, the buffer needs to have the
200       * number of lines as a multiple of 16 (the tile size),
201       *  - airlied */
202      int lines = (pScrn->virtualY + 15) / 16 * 16;
203      back_size = i810_pitches[pitch_idx] * lines;
204      back_size = ((back_size + 4096 - 1) / 4096) * 4096;
205   }
206
207   pScrn->displayWidth = i810_pitches[pitch_idx] / pI810->cpp;
208
209   /* Check the DRI version */
210   {
211      int major, minor, patch;
212
213      DRIQueryVersion(&major, &minor, &patch);
214      if (major != DRIINFO_MAJOR_VERSION || minor < DRIINFO_MINOR_VERSION) {
215	 xf86DrvMsg(pScreen->myNum, X_ERROR,
216		    "[dri] I810DRIScreenInit failed because of a version mismatch.\n"
217		    "[dri] libdri version is %d.%d.%d bug version %d.%d.x is needed.\n"
218		    "[dri] Disabling DRI.\n", major, minor, patch,
219                    DRIINFO_MAJOR_VERSION, DRIINFO_MINOR_VERSION);
220	 return FALSE;
221      }
222   }
223
224   pDRIInfo = DRICreateInfoRec();
225   if (!pDRIInfo) {
226      xf86DrvMsg(pScreen->myNum, X_ERROR,
227		 "[dri] DRICreateInfoRec failed.  Disabling DRI.\n");
228      return FALSE;
229   }
230
231/*     pDRIInfo->wrap.ValidateTree = 0;    */
232/*     pDRIInfo->wrap.PostValidateTree = 0;    */
233
234   pI810->pDRIInfo = pDRIInfo;
235   pI810->LockHeld = 0;
236
237   pDRIInfo->drmDriverName = I810KernelDriverName;
238   pDRIInfo->clientDriverName = I810ClientDriverName;
239   if (xf86LoaderCheckSymbol("DRICreatePCIBusID")) {
240      pDRIInfo->busIdString = DRICreatePCIBusID(pI810->PciInfo);
241   } else {
242      pDRIInfo->busIdString = malloc(64);
243      if (pDRIInfo->busIdString)
244	 sprintf(pDRIInfo->busIdString, "PCI:%d:%d:%d",
245		 ((pI810->PciInfo->domain << 8) | pI810->PciInfo->bus),
246		 pI810->PciInfo->dev, pI810->PciInfo->func
247		);
248   }
249   if (!pDRIInfo->busIdString) {
250      DRIDestroyInfoRec(pI810->pDRIInfo);
251      pI810->pDRIInfo = NULL;
252      return FALSE;
253   }
254   pDRIInfo->ddxDriverMajorVersion = I810_MAJOR_VERSION;
255   pDRIInfo->ddxDriverMinorVersion = I810_MINOR_VERSION;
256   pDRIInfo->ddxDriverPatchVersion = I810_PATCHLEVEL;
257   pDRIInfo->frameBufferPhysicalAddress = (pointer) pI810->LinearAddr;
258   pDRIInfo->frameBufferSize = (((pScrn->displayWidth *
259				  pScrn->virtualY * pI810->cpp) +
260				 4096 - 1) / 4096) * 4096;
261
262   pDRIInfo->frameBufferStride = pScrn->displayWidth * pI810->cpp;
263   pDRIInfo->ddxDrawableTableEntry = I810_MAX_DRAWABLES;
264
265   if (SAREA_MAX_DRAWABLES < I810_MAX_DRAWABLES)
266      pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES;
267   else
268      pDRIInfo->maxDrawableTableEntry = I810_MAX_DRAWABLES;
269
270   /* For now the mapping works by using a fixed size defined
271    * in the SAREA header
272    */
273   if (sizeof(XF86DRISAREARec) + sizeof(I810SAREARec) > SAREA_MAX) {
274      xf86DrvMsg(pScreen->myNum, X_ERROR,
275		 "[dri] Data does not fit in SAREA\n");
276      return FALSE;
277   }
278   pDRIInfo->SAREASize = SAREA_MAX;
279
280   if (!(pI810DRI = (I810DRIPtr) calloc(sizeof(I810DRIRec), 1))) {
281      DRIDestroyInfoRec(pI810->pDRIInfo);
282      pI810->pDRIInfo = NULL;
283      return FALSE;
284   }
285   pDRIInfo->devPrivate = pI810DRI;
286   pDRIInfo->devPrivateSize = sizeof(I810DRIRec);
287   pDRIInfo->contextSize = sizeof(I810DRIContextRec);
288
289   pDRIInfo->CreateContext = I810CreateContext;
290   pDRIInfo->DestroyContext = I810DestroyContext;
291   pDRIInfo->SwapContext = I810DRISwapContext;
292   pDRIInfo->InitBuffers = I810DRIInitBuffers;
293   pDRIInfo->MoveBuffers = I810DRIMoveBuffers;
294   pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
295   pDRIInfo->TransitionTo2d = I810DRITransitionTo2d;
296   pDRIInfo->TransitionTo3d = I810DRITransitionTo3d;
297   pDRIInfo->TransitionSingleToMulti3D = I810DRITransitionSingleToMulti3d;
298   pDRIInfo->TransitionMultiToSingle3D = I810DRITransitionMultiToSingle3d;
299
300   pDRIInfo->createDummyCtx = TRUE;
301   pDRIInfo->createDummyCtxPriv = FALSE;
302
303   /* This adds the framebuffer as a drm map *before* we have asked agp
304    * to allocate it.  Scary stuff, hold on...
305    */
306   if (!DRIScreenInit(pScreen, pDRIInfo, &pI810->drmSubFD)) {
307      xf86DrvMsg(pScreen->myNum, X_ERROR,
308		 "[dri] DRIScreenInit failed.  Disabling DRI.\n");
309      free(pDRIInfo->devPrivate);
310      pDRIInfo->devPrivate = NULL;
311      DRIDestroyInfoRec(pI810->pDRIInfo);
312      pI810->pDRIInfo = NULL;
313      return FALSE;
314   }
315
316   /* Check the i810 DRM versioning */
317   {
318      drmVersionPtr version;
319
320      /* Check the DRM lib version.
321       * drmGetLibVersion was not supported in version 1.0, so check for
322       * symbol first to avoid possible crash or hang.
323       */
324      if (xf86LoaderCheckSymbol("drmGetLibVersion")) {
325	 version = drmGetLibVersion(pI810->drmSubFD);
326      } else
327      {
328	 /* drmlib version 1.0.0 didn't have the drmGetLibVersion
329	  * entry point.  Fake it by allocating a version record
330	  * via drmGetVersion and changing it to version 1.0.0
331	  */
332	 version = drmGetVersion(pI810->drmSubFD);
333	 version->version_major = 1;
334	 version->version_minor = 0;
335	 version->version_patchlevel = 0;
336      }
337
338#define REQ_MAJ 1
339#define REQ_MIN 1
340      if (version) {
341	 if (version->version_major != REQ_MAJ ||
342	     version->version_minor < REQ_MIN) {
343	    /* incompatible drm library version */
344	    xf86DrvMsg(pScreen->myNum, X_ERROR,
345		       "[dri] I810DRIScreenInit failed because of a version mismatch.\n"
346		       "[dri] libdrm.a module version is %d.%d.%d but version %d.%d.x is needed.\n"
347		       "[dri] Disabling DRI.\n",
348		       version->version_major,
349		       version->version_minor, version->version_patchlevel,
350		       REQ_MAJ, REQ_MIN);
351	    drmFreeVersion(version);
352	    I810DRICloseScreen(pScreen);
353	    return FALSE;
354	 }
355	 drmFreeVersion(version);
356      }
357
358      /* Check the i810 DRM version */
359      version = drmGetVersion(pI810->drmSubFD);
360      if (version) {
361	i810_drm_version = (version->version_major<<16) |
362	                    version->version_minor;
363	 if (version->version_major != 1 || version->version_minor < 2) {
364	    /* incompatible drm version */
365	    xf86DrvMsg(pScreen->myNum, X_ERROR,
366		       "[dri] I810DRIScreenInit failed because of a version mismatch.\n"
367		       "[dri] i810.o kernel module version is %d.%d.%d but version 1.2.0 or greater is needed.\n"
368		       "[dri] Disabling DRI.\n",
369		       version->version_major,
370		       version->version_minor, version->version_patchlevel);
371	    I810DRICloseScreen(pScreen);
372	    drmFreeVersion(version);
373	    return FALSE;
374	 }
375         pI810->drmMinor = version->version_minor;
376	 drmFreeVersion(version);
377      }
378   }
379
380   pI810DRI->regsSize = I810_REG_SIZE;
381   if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->MMIOAddr,
382		 pI810DRI->regsSize, DRM_REGISTERS, 0,
383		 (drmAddress) &pI810DRI->regs) < 0) {
384      xf86DrvMsg(pScreen->myNum, X_ERROR, "[drm] drmAddMap(regs) failed\n");
385      DRICloseScreen(pScreen);
386      return FALSE;
387   }
388   xf86DrvMsg(pScreen->myNum, X_INFO, "[drm] Registers = 0x%08x\n",
389	      (int)pI810DRI->regs);
390
391   pI810->backHandle = DRM_AGP_NO_HANDLE;
392   pI810->zHandle = DRM_AGP_NO_HANDLE;
393   pI810->cursorHandle = DRM_AGP_NO_HANDLE;
394   pI810->xvmcHandle = DRM_AGP_NO_HANDLE;
395   pI810->sysmemHandle = DRM_AGP_NO_HANDLE;
396   pI810->agpAcquired = FALSE;
397   pI810->dcacheHandle = DRM_AGP_NO_HANDLE;
398
399   /* Agp Support - Need this just to get the framebuffer.
400    */
401   if (drmAgpAcquire(pI810->drmSubFD) < 0) {
402      xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpAquire failed\n");
403      DRICloseScreen(pScreen);
404      return FALSE;
405   }
406   pI810->agpAcquired = TRUE;
407
408   if (drmAgpEnable(pI810->drmSubFD, 0) < 0) {
409      xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] drmAgpEnable failed\n");
410      DRICloseScreen(pScreen);
411      return FALSE;
412   }
413
414   memset(&pI810->DcacheMem, 0, sizeof(I810MemRange));
415   memset(&pI810->BackBuffer, 0, sizeof(I810MemRange));
416   memset(&pI810->DepthBuffer, 0, sizeof(I810MemRange));
417   pI810->CursorPhysical = 0;
418   pI810->CursorARGBPhysical = 0;
419
420   /* Dcache - half the speed of normal ram, but has use as a Z buffer
421    * under the DRI.
422    */
423
424   drmAgpAlloc(pI810->drmSubFD, 4096 * 1024, 1, NULL,
425	       (drmAddress) &dcacheHandle);
426   pI810->dcacheHandle = dcacheHandle;
427
428   xf86DrvMsg(pScreen->myNum, X_INFO, "[agp] dcacheHandle : 0x%x\n",
429	      (int)dcacheHandle);
430
431   sysmem_size = pScrn->videoRam * 1024;
432   if (dcacheHandle != DRM_AGP_NO_HANDLE) {
433      if (back_size > 4 * 1024 * 1024) {
434	 xf86DrvMsg(pScreen->myNum, X_INFO,
435		    "[dri] Backsize is larger then 4 meg\n");
436	 sysmem_size = sysmem_size - 2 * back_size;
437	 drmAgpFree(pI810->drmSubFD, dcacheHandle);
438	 pI810->dcacheHandle = dcacheHandle = DRM_AGP_NO_HANDLE;
439      } else {
440	 sysmem_size = sysmem_size - back_size;
441      }
442   } else {
443      sysmem_size = sysmem_size - 2 * back_size;
444   }
445
446   /* Max size is 48 without XvMC, 41 with 6 surfaces, 40 with 7 surfaces */
447   if (pI810->numSurfaces && (pI810->numSurfaces == 6)) {
448      if (sysmem_size > (pI810->FbMapSize - 7 * 1024 * 1024)) {
449	 sysmem_size = (pI810->FbMapSize - 7 * 1024 * 1024);
450	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
451		    "User requested more memory then fits in the agp aperture\n"
452		    "Truncating to %d bytes of memory\n", sysmem_size);
453      }
454   }
455   if (pI810->numSurfaces && (pI810->numSurfaces == 7)) {
456      if (sysmem_size > (pI810->FbMapSize - 8 * 1024 * 1024)) {
457	 sysmem_size = (pI810->FbMapSize - 8 * 1024 * 1024);
458	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
459		    "User requested more memory then fits in the agp aperture\n"
460		    "Truncating to %d bytes of memory\n", sysmem_size);
461      }
462   }
463
464   if (sysmem_size > pI810->FbMapSize) {
465      sysmem_size = pI810->FbMapSize;
466
467      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
468		 "[dri] User requested more memory then fits in the agp"
469		 " aperture\n\tTruncating to %d bytes of memory\n",
470		 sysmem_size);
471   }
472
473   sysmem_size -= 4096;			/* remove 4k for the hw cursor */
474   sysmem_size -= 16384;		/* remove 16k for the ARGB hw cursor */
475
476   pI810->SysMem.Start = 0;
477   pI810->SysMem.Size = sysmem_size;
478   pI810->SysMem.End = sysmem_size;
479   tom = sysmem_size;
480
481   pI810->SavedSysMem = pI810->SysMem;
482
483   if (dcacheHandle != DRM_AGP_NO_HANDLE) {
484      if (drmAgpBind(pI810->drmSubFD, dcacheHandle, pI810->DepthOffset) == 0) {
485	 memset(&pI810->DcacheMem, 0, sizeof(I810MemRange));
486	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
487		    "[agp] GART: Found 4096K Z buffer memory\n");
488	 pI810->DcacheMem.Start = pI810->DepthOffset;
489	 pI810->DcacheMem.Size = 1024 * 4096;
490	 pI810->DcacheMem.End =
491	       pI810->DcacheMem.Start + pI810->DcacheMem.Size;
492	 if (!I810AllocLow
493	     (&(pI810->DepthBuffer), &(pI810->DcacheMem), back_size)) {
494	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
495		       "[agp] Depth buffer allocation failed\n");
496	    DRICloseScreen(pScreen);
497	    return FALSE;
498	 }
499      } else {
500	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
501		    "[agp] GART: dcache bind failed\n");
502	 drmAgpFree(pI810->drmSubFD, dcacheHandle);
503	 pI810->dcacheHandle = dcacheHandle = DRM_AGP_NO_HANDLE;
504      }
505   } else {
506      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
507		 "[agp] GART: no dcache memory found\n");
508   }
509
510   drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL,
511	       (drmAddress) &agpHandle);
512   pI810->backHandle = agpHandle;
513
514   if (agpHandle != DRM_AGP_NO_HANDLE) {
515      if (drmAgpBind(pI810->drmSubFD, agpHandle, pI810->BackOffset) == 0) {
516	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
517		    "[agp] Bound backbuffer memory\n");
518
519	 pI810->BackBuffer.Start = pI810->BackOffset;
520	 pI810->BackBuffer.Size = back_size;
521	 pI810->BackBuffer.End = (pI810->BackBuffer.Start +
522				  pI810->BackBuffer.Size);
523      } else {
524	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
525		    "[agp] Unable to bind backbuffer.  Disabling DRI.\n");
526	 DRICloseScreen(pScreen);
527	 return FALSE;
528      }
529   } else {
530      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
531		 "[dri] Unable to allocate backbuffer memory.  Disabling DRI.\n");
532      DRICloseScreen(pScreen);
533      return FALSE;
534   }
535
536   if (dcacheHandle == DRM_AGP_NO_HANDLE) {
537     drmAgpAlloc(pI810->drmSubFD, back_size, 0, NULL,
538		 (drmAddress) &agpHandle);
539
540      pI810->zHandle = agpHandle;
541
542      if (agpHandle != DRM_AGP_NO_HANDLE) {
543	 if (drmAgpBind(pI810->drmSubFD, agpHandle, pI810->DepthOffset) == 0) {
544	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
545		       "[agp] Bound depthbuffer memory\n");
546	    pI810->DepthBuffer.Start = pI810->DepthOffset;
547	    pI810->DepthBuffer.Size = back_size;
548	    pI810->DepthBuffer.End = (pI810->DepthBuffer.Start +
549				      pI810->DepthBuffer.Size);
550	 } else {
551	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
552		       "[agp] Unable to bind depthbuffer.  Disabling DRI.\n");
553	    DRICloseScreen(pScreen);
554	    return FALSE;
555	 }
556      } else {
557	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
558		    "[agp] Unable to allocate depthbuffer memory.  Disabling DRI.\n");
559	 DRICloseScreen(pScreen);
560	 return FALSE;
561      }
562   }
563
564   /* Now allocate and bind the agp space.  This memory will include the
565    * regular framebuffer as well as texture memory.
566    */
567   drmAgpAlloc(pI810->drmSubFD, sysmem_size, 0, NULL,
568	       (drmAddress)&agpHandle);
569   pI810->sysmemHandle = agpHandle;
570
571   if (agpHandle != DRM_AGP_NO_HANDLE) {
572      if (drmAgpBind(pI810->drmSubFD, agpHandle, 0) == 0) {
573	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
574		   "[agp] Bound System Texture Memory\n");
575      } else {
576          xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Unable to bind system texture memory. Disabling DRI.\n");
577	  DRICloseScreen(pScreen);
578	  return FALSE;
579      }
580   } else {
581      xf86DrvMsg(pScreen->myNum, X_ERROR, "[agp] Unable to allocate system texture memory. Disabling DRI.\n");
582      DRICloseScreen(pScreen);
583      return FALSE;
584   }
585
586/* Allocate 7 or 8MB for XvMC this is setup as follows to best use tiled
587   regions and required surface pitches. (Numbers are adjusted if the
588   AGP region is only 32MB
589   For numSurfaces == 6
590   44 - 48MB = 4MB Fence, 8 Tiles wide
591   43 - 44MB = 1MB Fence, 8 Tiles wide
592   42 - 43MB = 1MB Fence, 4 Tiles wide
593   41 - 42MB = 1MB Fence, 4 Tiles wide
594   For numSurfaces == 7
595   44 - 48MB   = 4MB Fence, 8 Tiles wide
596   43 - 44MB   = 1MB Fence, 8 Tiles wide
597   42.5 - 43MB = 0.5MB Fence, 8 Tiles wide
598   42 - 42.5MB = 0.5MB Fence, 4 Tiles wide
599   40 - 42MB   = 2MB Fence, 4 Tiles wide
600 */
601   if (pI810->numSurfaces) {
602      if (pI810->numSurfaces == 6) {
603	 pI810->MC.Size = 7 * 1024 * 1024;
604	 pI810->MC.Start = pI810->FbMapSize - 7 * 1024 * 1024;
605
606      }
607      if (pI810->numSurfaces == 7) {
608	 pI810->MC.Size = 8 * 1024 * 1024;
609	 pI810->MC.Start = pI810->FbMapSize - 8 * 1024 * 1024;
610      }
611      drmAgpAlloc(pI810->drmSubFD, pI810->MC.Size, 0, NULL,
612		  (drmAddress) &agpHandle);
613
614      pI810->xvmcHandle = agpHandle;
615
616      if (agpHandle != DRM_AGP_NO_HANDLE) {
617	 if (drmAgpBind(pI810->drmSubFD, agpHandle, pI810->MC.Start) == 0) {
618	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
619		       "GART: Allocated 7MB for HWMC\n");
620	    pI810->MC.End = pI810->MC.Start + pI810->MC.Size;
621	 } else {
622	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "GART: HWMC bind failed\n");
623	    pI810->MC.Start = 0;
624	    pI810->MC.Size = 0;
625	    pI810->MC.End = 0;
626	 }
627      } else {
628	 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "GART: HWMC alloc failed\n");
629	 pI810->MC.Start = 0;
630	 pI810->MC.Size = 0;
631	 pI810->MC.End = 0;
632      }
633      pI810->xvmcContext = 0;
634   }
635
636   drmAgpAlloc(pI810->drmSubFD, 4096, 2,
637	       (unsigned long *)&pI810->CursorPhysical,
638	       (drmAddress) &agpHandle);
639
640   pI810->cursorHandle = agpHandle;
641
642   if (agpHandle != DRM_AGP_NO_HANDLE) {
643      tom = sysmem_size;
644
645      if (drmAgpBind(pI810->drmSubFD, agpHandle, tom) == 0) {
646	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
647		    "[agp] GART: Allocated 4K for mouse cursor image\n");
648	 pI810->CursorStart = tom;
649	 tom += 4096;
650      } else {
651	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
652		    "[agp] GART: cursor bind failed\n");
653	 pI810->CursorPhysical = 0;
654      }
655   } else {
656      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
657		 "[agp] GART: cursor alloc failed\n");
658      pI810->CursorPhysical = 0;
659   }
660
661   drmAgpAlloc(pI810->drmSubFD, 16384, 2,
662	       (unsigned long *)&pI810->CursorARGBPhysical,
663	       (drmAddress) &agpHandle);
664
665   pI810->cursorARGBHandle = agpHandle;
666
667   if (agpHandle != DRM_AGP_NO_HANDLE) {
668      if (drmAgpBind(pI810->drmSubFD, agpHandle, tom) == 0) {
669	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
670		    "[agp] GART: Allocated 16K for ARGB mouse cursor image\n");
671	 pI810->CursorARGBStart = tom;
672	 tom += 16384;
673      } else {
674	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
675		    "[agp] GART: ARGB cursor bind failed\n");
676	 pI810->CursorARGBPhysical = 0;
677      }
678   } else {
679      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
680		 "[agp] GART: ARGB cursor alloc failed\n");
681      pI810->CursorARGBPhysical = 0;
682   }
683
684   /* Steal some of the excess cursor space for the overlay regs.
685    */
686   pI810->OverlayPhysical = pI810->CursorPhysical + 1024;
687   pI810->OverlayStart = pI810->CursorStart + 1024;
688
689   I810SetTiledMemory(pScrn, 1,
690		      pI810->DepthBuffer.Start,
691		      i810_pitches[pitch_idx], 8 * 1024 * 1024);
692
693   I810SetTiledMemory(pScrn, 2,
694		      pI810->BackBuffer.Start,
695		      i810_pitches[pitch_idx], 8 * 1024 * 1024);
696
697   /* These are for HWMC surfaces */
698   if (pI810->numSurfaces == 6) {
699      I810SetTiledMemory(pScrn, 3, pI810->MC.Start, 512, 1024 * 1024);
700
701      I810SetTiledMemory(pScrn, 4,
702			 pI810->MC.Start + 1024 * 1024, 512, 1024 * 1024);
703
704      I810SetTiledMemory(pScrn, 5,
705			 pI810->MC.Start + 1024 * 1024 * 2,
706			 1024, 1024 * 1024);
707
708      I810SetTiledMemory(pScrn, 6,
709			 pI810->MC.Start + 1024 * 1024 * 3,
710			 1024, 4 * 1024 * 1024);
711   }
712   if (pI810->numSurfaces == 7) {
713      I810SetTiledMemory(pScrn, 3, pI810->MC.Start, 512, 2 * 1024 * 1024);
714
715      I810SetTiledMemory(pScrn, 4,
716			 pI810->MC.Start + 2 * 1024 * 1024, 512, 512 * 1024);
717
718      I810SetTiledMemory(pScrn, 5,
719			 pI810->MC.Start + 2 * 1024 * 1024 + 512 * 1024,
720			 1024, 512 * 1024);
721
722      I810SetTiledMemory(pScrn, 6,
723			 pI810->MC.Start + 3 * 1024 * 1024,
724			 1024, 1 * 1024 * 1024);
725
726      I810SetTiledMemory(pScrn, 7,
727			 pI810->MC.Start + 4 * 1024 * 1024,
728			 1024, 4 * 1024 * 1024);
729
730   }
731
732   pI810->auxPitch = i810_pitches[pitch_idx];
733   pI810->auxPitchBits = i810_pitch_flags[pitch_idx];
734   pI810->SavedDcacheMem = pI810->DcacheMem;
735   pI810DRI->backbufferSize = pI810->BackBuffer.Size;
736
737   if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->BackBuffer.Start,
738		 pI810->BackBuffer.Size, DRM_AGP, 0,
739		 (drmAddress) &pI810DRI->backbuffer) < 0) {
740      xf86DrvMsg(pScreen->myNum, X_ERROR,
741		 "[drm] drmAddMap(backbuffer) failed.  Disabling DRI\n");
742      DRICloseScreen(pScreen);
743      return FALSE;
744   }
745
746   pI810DRI->depthbufferSize = pI810->DepthBuffer.Size;
747   if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->DepthBuffer.Start,
748		 pI810->DepthBuffer.Size, DRM_AGP, 0,
749		 (drmAddress) &pI810DRI->depthbuffer) < 0) {
750      xf86DrvMsg(pScreen->myNum, X_ERROR,
751		 "[drm] drmAddMap(depthbuffer) failed.  Disabling DRI.\n");
752      DRICloseScreen(pScreen);
753      return FALSE;
754   }
755
756   /* Allocate FrontBuffer etc. */
757   if (!I810AllocateFront(pScrn)) {
758      DRICloseScreen(pScreen);
759      return FALSE;
760   }
761
762   /* Allocate buffer memory */
763   I810AllocHigh(&(pI810->BufferMem), &(pI810->SysMem),
764		 I810_DMA_BUF_NR * I810_DMA_BUF_SZ);
765
766   xf86DrvMsg(pScreen->myNum, X_INFO, "[dri] Buffer map : %lx\n",
767	      pI810->BufferMem.Start);
768
769   if (pI810->BufferMem.Start == 0 ||
770       pI810->BufferMem.End - pI810->BufferMem.Start >
771       I810_DMA_BUF_NR * I810_DMA_BUF_SZ) {
772      xf86DrvMsg(pScreen->myNum, X_ERROR,
773		 "[dri] Not enough memory for dma buffers.  Disabling DRI.\n");
774      DRICloseScreen(pScreen);
775      return FALSE;
776   }
777   if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->BufferMem.Start,
778		 pI810->BufferMem.Size, DRM_AGP, 0,
779		 (drmAddress) &pI810->buffer_map) < 0) {
780      xf86DrvMsg(pScreen->myNum, X_ERROR,
781		 "[drm] drmAddMap(buffer_map) failed.  Disabling DRI.\n");
782      DRICloseScreen(pScreen);
783      return FALSE;
784   }
785
786   pI810DRI->agp_buffers = pI810->buffer_map;
787   pI810DRI->agp_buf_size = pI810->BufferMem.Size;
788
789   if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->LpRing->mem.Start,
790		 pI810->LpRing->mem.Size, DRM_AGP, 0,
791		 (drmAddress) &pI810->ring_map) < 0) {
792      xf86DrvMsg(pScreen->myNum, X_ERROR,
793		 "[drm] drmAddMap(ring_map) failed.  Disabling DRI.\n");
794      DRICloseScreen(pScreen);
795      return FALSE;
796   }
797
798   /* Use the rest of memory for textures. */
799   pI810DRI->textureSize = pI810->SysMem.Size;
800
801   i = mylog2(pI810DRI->textureSize / I810_NR_TEX_REGIONS);
802
803   if (i < I810_LOG_MIN_TEX_REGION_SIZE)
804      i = I810_LOG_MIN_TEX_REGION_SIZE;
805
806   pI810DRI->logTextureGranularity = i;
807   pI810DRI->textureSize = (pI810DRI->textureSize >> i) << i;	/* truncate */
808
809   if (pI810DRI->textureSize < 512 * 1024) {
810      xf86DrvMsg(pScreen->myNum, X_ERROR,
811		 "[drm] Less then 512k memory left for textures.  Disabling DRI.\n");
812      DRICloseScreen(pScreen);
813      return FALSE;
814   }
815
816   if (!I810AllocLow(&(pI810->TexMem), &(pI810->SysMem), pI810DRI->textureSize)) {
817      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
818		 "[agp] Texure memory allocation failed\n");
819      DRICloseScreen(pScreen);
820      return FALSE;
821   }
822
823   if (drmAddMap(pI810->drmSubFD, (drm_handle_t) pI810->TexMem.Start,
824		 pI810->TexMem.Size, DRM_AGP, 0,
825		 (drmAddress) &pI810DRI->textures) < 0) {
826      xf86DrvMsg(pScreen->myNum, X_ERROR,
827		 "[drm] drmAddMap(textures) failed.  Disabling DRI.\n");
828      DRICloseScreen(pScreen);
829      return FALSE;
830   }
831
832   if ((bufs = drmAddBufs(pI810->drmSubFD,
833			  I810_DMA_BUF_NR,
834			  I810_DMA_BUF_SZ,
835			  DRM_AGP_BUFFER, pI810->BufferMem.Start)) <= 0) {
836      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
837		 "[drm] failure adding %d %d byte DMA buffers.  Disabling DRI.\n",
838		 I810_DMA_BUF_NR, I810_DMA_BUF_SZ);
839      DRICloseScreen(pScreen);
840      return FALSE;
841   }
842
843   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
844	      "[drm] added %d %d byte DMA buffers\n", bufs, I810_DMA_BUF_SZ);
845
846   I810InitDma(pScrn);
847
848   /* Okay now initialize the dma engine */
849
850   if (!pI810DRI->irq) {
851      pI810DRI->irq = drmGetInterruptFromBusID(pI810->drmSubFD,
852					       ((pI810->PciInfo->domain << 8) |
853						pI810->PciInfo->bus),
854					       pI810->PciInfo->dev,
855					       pI810->PciInfo->func
856					       );
857      if ((drmCtlInstHandler(pI810->drmSubFD, pI810DRI->irq)) != 0) {
858	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
859		    "[drm] failure adding irq handler, there is a device "
860		    "already using that irq\n Consider rearranging your "
861		    "PCI cards.  Disabling DRI.\n");
862	 DRICloseScreen(pScreen);
863	 return FALSE;
864      }
865   }
866
867   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
868	      "[drm] dma control initialized, using IRQ %d\n", pI810DRI->irq);
869
870   pI810DRI->deviceID = pI810->PciInfo->device_id;
871   pI810DRI->width = pScrn->virtualX;
872   pI810DRI->height = pScrn->virtualY;
873   pI810DRI->mem = pScrn->videoRam * 1024;
874   pI810DRI->cpp = pI810->cpp;
875
876   pI810DRI->fbOffset = pI810->FrontBuffer.Start;
877   pI810DRI->fbStride = pI810->auxPitch;
878
879   pI810DRI->bitsPerPixel = pScrn->bitsPerPixel;
880
881   pI810DRI->textureOffset = pI810->TexMem.Start;
882
883   pI810DRI->backOffset = pI810->BackBuffer.Start;
884   pI810DRI->depthOffset = pI810->DepthBuffer.Start;
885
886   pI810DRI->ringOffset = pI810->LpRing->mem.Start;
887   pI810DRI->ringSize = pI810->LpRing->mem.Size;
888
889   pI810DRI->auxPitch = pI810->auxPitch;
890   pI810DRI->auxPitchBits = pI810->auxPitchBits;
891   pI810DRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
892
893   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
894	      "[dri] visual configs initialized.\n");
895   pI810->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
896
897   return TRUE;
898}
899
900void
901I810DRICloseScreen(ScreenPtr pScreen)
902{
903   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
904   I810Ptr pI810 = I810PTR(pScrn);
905
906   if (pI810->pDRIInfo) {
907       I810DRIPtr pI810DRI = (I810DRIPtr) pI810->pDRIInfo->devPrivate;
908
909       if (pI810DRI) {
910	   if (pI810DRI->irq) {
911	       drmCtlUninstHandler(pI810->drmSubFD);
912	       pI810DRI->irq = 0;
913	   }
914
915	   free(pI810->pDRIInfo->devPrivate);
916	   pI810->pDRIInfo->devPrivate = NULL;
917       }
918
919       I810CleanupDma(pScrn);
920
921       DRICloseScreen(pScreen);
922       DRIDestroyInfoRec(pI810->pDRIInfo);
923       pI810->pDRIInfo = NULL;
924   }
925
926   if (pI810->dcacheHandle!=DRM_AGP_NO_HANDLE)
927       drmAgpFree(pI810->drmSubFD, pI810->dcacheHandle);
928   if (pI810->backHandle!=DRM_AGP_NO_HANDLE)
929       drmAgpFree(pI810->drmSubFD, pI810->backHandle);
930   if (pI810->zHandle!=DRM_AGP_NO_HANDLE)
931       drmAgpFree(pI810->drmSubFD, pI810->zHandle);
932   if (pI810->cursorHandle!=DRM_AGP_NO_HANDLE)
933       drmAgpFree(pI810->drmSubFD, pI810->cursorHandle);
934   if (pI810->xvmcHandle!=DRM_AGP_NO_HANDLE)
935       drmAgpFree(pI810->drmSubFD, pI810->xvmcHandle);
936   if (pI810->sysmemHandle!=DRM_AGP_NO_HANDLE)
937       drmAgpFree(pI810->drmSubFD, pI810->sysmemHandle);
938
939   if (pI810->agpAcquired == TRUE)
940       drmAgpRelease(pI810->drmSubFD);
941
942   pI810->backHandle = DRM_AGP_NO_HANDLE;
943   pI810->zHandle = DRM_AGP_NO_HANDLE;
944   pI810->cursorHandle = DRM_AGP_NO_HANDLE;
945   pI810->xvmcHandle = DRM_AGP_NO_HANDLE;
946   pI810->sysmemHandle = DRM_AGP_NO_HANDLE;
947   pI810->agpAcquired = FALSE;
948   pI810->dcacheHandle = DRM_AGP_NO_HANDLE;
949}
950
951static Bool
952I810CreateContext(ScreenPtr pScreen, VisualPtr visual,
953		  drm_context_t hwContext, void *pVisualConfigPriv,
954		  DRIContextType contextStore)
955{
956   return TRUE;
957}
958
959static void
960I810DestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
961		   DRIContextType contextStore)
962{
963}
964
965Bool
966I810DRIFinishScreenInit(ScreenPtr pScreen)
967{
968   I810SAREARec *sPriv = (I810SAREARec *) DRIGetSAREAPrivate(pScreen);
969   ScrnInfoPtr        pScrn = xf86ScreenToScrn(pScreen);
970   I810Ptr info  = I810PTR(pScrn);
971
972   memset(sPriv, 0, sizeof(*sPriv));
973
974   /* Have shadow run only while there is 3d active.
975    */
976   if (info->allowPageFlip && info->drmMinor >= 3) {
977     ShadowFBInit( pScreen, I810DRIRefreshArea );
978   }
979   else
980     info->allowPageFlip = 0;
981   return DRIFinishScreenInit(pScreen);
982}
983
984void
985I810DRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
986		   DRIContextType oldContextType, void *oldContext,
987		   DRIContextType newContextType, void *newContext)
988{
989   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
990   I810Ptr pI810 = I810PTR(pScrn);
991
992   if (syncType == DRI_3D_SYNC &&
993       oldContextType == DRI_2D_CONTEXT && newContextType == DRI_2D_CONTEXT) {
994      if (I810_DEBUG & DEBUG_VERBOSE_DRI)
995	 ErrorF("I810DRISwapContext (in)\n");
996
997      if (!pScrn->vtSema)
998	  return;
999      pI810->LockHeld = 1;
1000      I810RefreshRing(pScrn);
1001   } else if (syncType == DRI_2D_SYNC &&
1002	      oldContextType == DRI_NO_CONTEXT &&
1003	      newContextType == DRI_2D_CONTEXT) {
1004      pI810->LockHeld = 0;
1005      if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1006	 ErrorF("I810DRISwapContext (out)\n");
1007   } else if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1008      ErrorF("I810DRISwapContext (other)\n");
1009}
1010
1011static void
1012I810DRISetNeedSync(ScrnInfoPtr pScrn)
1013{
1014#ifdef HAVE_XAA_H
1015   I810Ptr pI810 = I810PTR(pScrn);
1016   if (pI810->AccelInfoRec)
1017	pI810->AccelInfoRec->NeedToSync = TRUE;
1018#endif
1019}
1020
1021static void
1022I810DRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 index)
1023{
1024   ScreenPtr pScreen = pWin->drawable.pScreen;
1025   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1026   BoxPtr pbox = REGION_RECTS(prgn);
1027   int nbox = REGION_NUM_RECTS(prgn);
1028
1029   if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1030      ErrorF("I810DRIInitBuffers\n");
1031
1032   I810SetupForSolidFill(pScrn, 0, GXcopy, -1);
1033   while (nbox--) {
1034      I810SelectBuffer(pScrn, I810_SELECT_BACK);
1035      I810SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1,
1036				  pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
1037      pbox++;
1038   }
1039
1040   /* Clear the depth buffer - uses 0xffff rather than 0.
1041    */
1042   pbox = REGION_RECTS(prgn);
1043   nbox = REGION_NUM_RECTS(prgn);
1044   I810SelectBuffer(pScrn, I810_SELECT_DEPTH);
1045   I810SetupForSolidFill(pScrn, 0xffff, GXcopy, -1);
1046   while (nbox--) {
1047      I810SubsequentSolidFillRect(pScrn, pbox->x1, pbox->y1,
1048				  pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
1049      pbox++;
1050   }
1051   I810SelectBuffer(pScrn, I810_SELECT_FRONT);
1052
1053   I810DRISetNeedSync(pScrn);
1054}
1055
1056/* This routine is a modified form of XAADoBitBlt with the calls to
1057 * ScreenToScreenBitBlt built in. My routine has the prgnSrc as source
1058 * instead of destination. My origin is upside down so the ydir cases
1059 * are reversed.
1060 *
1061 * KW: can you believe that this is called even when a 2d window moves?
1062 */
1063static void
1064I810DRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg,
1065		   RegionPtr prgnSrc, CARD32 index)
1066{
1067   ScreenPtr pScreen = pParent->drawable.pScreen;
1068   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1069   BoxPtr pboxTmp, pboxNext, pboxBase;
1070   DDXPointPtr pptTmp, pptNew2 = NULL;
1071   int xdir, ydir;
1072
1073   int screenwidth = pScrn->virtualX;
1074   int screenheight = pScrn->virtualY;
1075
1076   BoxPtr pbox = REGION_RECTS(prgnSrc);
1077   int nbox = REGION_NUM_RECTS(prgnSrc);
1078
1079   BoxPtr pboxNew1 = NULL;
1080   BoxPtr pboxNew2 = NULL;
1081   DDXPointPtr pptNew1 = NULL;
1082   DDXPointPtr pptSrc = &ptOldOrg;
1083
1084   int dx = pParent->drawable.x - ptOldOrg.x;
1085   int dy = pParent->drawable.y - ptOldOrg.y;
1086
1087   /* If the copy will overlap in Y, reverse the order */
1088   if (dy > 0) {
1089      ydir = -1;
1090
1091      if (nbox > 1) {
1092	 /* Keep ordering in each band, reverse order of bands */
1093	 pboxNew1 = (BoxPtr) malloc(sizeof(BoxRec) * nbox);
1094	 if (!pboxNew1)
1095	    return;
1096	 pptNew1 = (DDXPointPtr) malloc(sizeof(DDXPointRec) * nbox);
1097	 if (!pptNew1) {
1098	    free(pboxNew1);
1099	    return;
1100	 }
1101	 pboxBase = pboxNext = pbox + nbox - 1;
1102	 while (pboxBase >= pbox) {
1103	    while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1))
1104	       pboxNext--;
1105	    pboxTmp = pboxNext + 1;
1106	    pptTmp = pptSrc + (pboxTmp - pbox);
1107	    while (pboxTmp <= pboxBase) {
1108	       *pboxNew1++ = *pboxTmp++;
1109	       *pptNew1++ = *pptTmp++;
1110	    }
1111	    pboxBase = pboxNext;
1112	 }
1113	 pboxNew1 -= nbox;
1114	 pbox = pboxNew1;
1115	 pptNew1 -= nbox;
1116	 pptSrc = pptNew1;
1117      }
1118   } else {
1119      /* No changes required */
1120      ydir = 1;
1121   }
1122
1123   /* If the regions will overlap in X, reverse the order */
1124   if (dx > 0) {
1125      xdir = -1;
1126
1127      if (nbox > 1) {
1128	 /*reverse orderof rects in each band */
1129	 pboxNew2 = (BoxPtr) malloc(sizeof(BoxRec) * nbox);
1130	 pptNew2 = (DDXPointPtr) malloc(sizeof(DDXPointRec) * nbox);
1131	 if (!pboxNew2 || !pptNew2) {
1132	    if (pptNew2)
1133	       free(pptNew2);
1134	    if (pboxNew2)
1135	       free(pboxNew2);
1136	    if (pboxNew1) {
1137	       free(pptNew1);
1138	       free(pboxNew1);
1139	    }
1140	    return;
1141	 }
1142	 pboxBase = pboxNext = pbox;
1143	 while (pboxBase < pbox + nbox) {
1144	    while ((pboxNext < pbox + nbox) && (pboxNext->y1 == pboxBase->y1))
1145	       pboxNext++;
1146	    pboxTmp = pboxNext;
1147	    pptTmp = pptSrc + (pboxTmp - pbox);
1148	    while (pboxTmp != pboxBase) {
1149	       *pboxNew2++ = *--pboxTmp;
1150	       *pptNew2++ = *--pptTmp;
1151	    }
1152	    pboxBase = pboxNext;
1153	 }
1154	 pboxNew2 -= nbox;
1155	 pbox = pboxNew2;
1156	 pptNew2 -= nbox;
1157	 pptSrc = pptNew2;
1158      }
1159   } else {
1160      /* No changes are needed */
1161      xdir = 1;
1162   }
1163
1164   /* SelectBuffer isn't really a good concept for the i810.
1165    */
1166   I810EmitFlush(pScrn);
1167   I810SetupForScreenToScreenCopy(pScrn, xdir, ydir, GXcopy, -1, -1);
1168   for (; nbox--; pbox++) {
1169
1170      int x1 = pbox->x1;
1171      int y1 = pbox->y1;
1172      int destx = x1 + dx;
1173      int desty = y1 + dy;
1174      int w = pbox->x2 - x1 + 1;
1175      int h = pbox->y2 - y1 + 1;
1176
1177      if (destx < 0)
1178	 x1 -= destx, w += destx, destx = 0;
1179      if (desty < 0)
1180	 y1 -= desty, h += desty, desty = 0;
1181      if (destx + w > screenwidth)
1182	 w = screenwidth - destx;
1183      if (desty + h > screenheight)
1184	 h = screenheight - desty;
1185      if (w <= 0)
1186	 continue;
1187      if (h <= 0)
1188	 continue;
1189
1190      if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1191	 ErrorF("MoveBuffers %d,%d %dx%d dx: %d dy: %d\n",
1192		x1, y1, w, h, dx, dy);
1193
1194      I810SelectBuffer(pScrn, I810_SELECT_BACK);
1195      I810SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h);
1196      I810SelectBuffer(pScrn, I810_SELECT_DEPTH);
1197      I810SubsequentScreenToScreenCopy(pScrn, x1, y1, destx, desty, w, h);
1198   }
1199   I810SelectBuffer(pScrn, I810_SELECT_FRONT);
1200   I810EmitFlush(pScrn);
1201
1202   if (pboxNew2) {
1203      free(pptNew2);
1204      free(pboxNew2);
1205   }
1206   if (pboxNew1) {
1207      free(pptNew1);
1208      free(pboxNew1);
1209   }
1210
1211   I810DRISetNeedSync(pScrn);
1212}
1213
1214
1215/* Use the miext/shadow module to maintain a list of dirty rectangles.
1216 * These are blitted to the back buffer to keep both buffers clean
1217 * during page-flipping when the 3d application isn't fullscreen.
1218 *
1219 * Unlike most use of the shadow code, both buffers are in video memory.
1220 *
1221 * An alternative to this would be to organize for all on-screen drawing
1222 * operations to be duplicated for the two buffers.  That might be
1223 * faster, but seems like a lot more work...
1224 */
1225
1226
1227/* This should be done *before* XAA syncs or fires its buffer.
1228 * Otherwise will have to fire it again???
1229 */
1230static void I810DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
1231{
1232    I810Ptr pI810 = I810PTR(pScrn);
1233    int i;
1234    I810SAREAPtr  pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen);
1235    unsigned int br13;
1236    int cpp=2;
1237
1238
1239    /* Don't want to do this when no 3d is active and pages are
1240     * right-way-round
1241     */
1242    if (!pSAREAPriv->pf_active && pSAREAPriv->pf_current_page == 0)
1243      return;
1244
1245    br13 = (pI810->auxPitch) | (0xcc << 16);
1246
1247    for (i = 0 ; i < num ; i++, pbox++) {
1248      unsigned int w = min(pbox->y2, pScrn->virtualY-1) - max(pbox->y1, 0) + 1;
1249      unsigned int h = min(pbox->x2, pScrn->virtualX-1) - max(pbox->x1, 0) + 1;
1250      unsigned int dst = max(pbox->x1, 0)*cpp + (max(pbox->y1, 0)*pI810->auxPitch);
1251
1252      BEGIN_LP_RING(6);
1253
1254      OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4);
1255      OUT_RING(br13);
1256      OUT_RING( (h<<16) | (w*cpp) );
1257      OUT_RING(pI810->BackBuffer.Start + dst);
1258      OUT_RING(br13 & 0xffff);
1259      OUT_RING(dst);
1260
1261      ADVANCE_LP_RING();
1262    }
1263
1264}
1265
1266static void I810EnablePageFlip(ScreenPtr pScreen)
1267{
1268    ScrnInfoPtr         pScrn      = xf86ScreenToScrn(pScreen);
1269    I810Ptr       pI810       = I810PTR(pScrn);
1270    I810SAREAPtr  pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1271    int cpp=2;
1272    pSAREAPriv->pf_enabled = pI810->allowPageFlip;
1273    pSAREAPriv->pf_active = 0;
1274
1275   if (pI810->allowPageFlip) {
1276      unsigned int br13 = pI810->auxPitch | (0xcc << 16);
1277
1278      BEGIN_LP_RING(6);
1279
1280      OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4);
1281      OUT_RING(br13);
1282      OUT_RING((pScrn->virtualY << 16) | (pScrn->virtualX*cpp));
1283      OUT_RING(pI810->BackBuffer.Start);
1284      OUT_RING(br13 & 0xFFFF);
1285      OUT_RING(0);
1286      ADVANCE_LP_RING();
1287
1288      pSAREAPriv->pf_active = 1;
1289   }
1290
1291}
1292
1293static void I810DisablePageFlip(ScreenPtr pScreen)
1294{
1295    I810SAREAPtr  pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1296
1297    pSAREAPriv->pf_active=0;
1298}
1299
1300static void I810DRITransitionSingleToMulti3d(ScreenPtr pScreen)
1301{
1302    /* Tell the clients not to pageflip.  How?
1303     *   -- Field in sarea, plus bumping the window counters.
1304     *   -- DRM needs to cope with Front-to-Back swapbuffers.
1305     */
1306    I810DisablePageFlip(pScreen);
1307}
1308
1309static void I810DRITransitionMultiToSingle3d(ScreenPtr pScreen)
1310{
1311    /* Let the remaining 3d app start page flipping again */
1312    I810EnablePageFlip(pScreen);
1313}
1314
1315static void I810DRITransitionTo3d(ScreenPtr pScreen)
1316{
1317    ScrnInfoPtr    pScrn = xf86ScreenToScrn(pScreen);
1318    I810Ptr  pI810  = I810PTR(pScrn);
1319
1320    I810EnablePageFlip(pScreen);
1321    pI810->have3DWindows = 1;
1322}
1323
1324static void I810DRITransitionTo2d(ScreenPtr pScreen)
1325{
1326    ScrnInfoPtr         pScrn      = xf86ScreenToScrn(pScreen);
1327    I810Ptr       pI810       = I810PTR(pScrn);
1328    I810SAREAPtr  pSAREAPriv = DRIGetSAREAPrivate(pScreen);
1329
1330    /* Try flipping back to the front page if necessary */
1331    if (pSAREAPriv->pf_current_page == 1)
1332	drmCommandNone(pI810->drmSubFD, DRM_I810_FLIP);
1333
1334    /* Shut down shadowing if we've made it back to the front page */
1335    if (pSAREAPriv->pf_current_page == 0) {
1336	I810DisablePageFlip(pScreen);
1337    }
1338    pI810->have3DWindows = 0;
1339}
1340
1341Bool
1342I810DRILeave(ScrnInfoPtr pScrn)
1343{
1344   I810Ptr pI810 = I810PTR(pScrn);
1345
1346   if (pI810->directRenderingEnabled) {
1347      if (pI810->dcacheHandle != 0)
1348	 if (drmAgpUnbind(pI810->drmSubFD, pI810->dcacheHandle) != 0) {
1349	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno));
1350	    return FALSE;
1351	 }
1352      if (pI810->backHandle != 0)
1353	 if (drmAgpUnbind(pI810->drmSubFD, pI810->backHandle) != 0) {
1354	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno));
1355 	    return FALSE;
1356	 }
1357      if (pI810->zHandle != 0)
1358	 if (drmAgpUnbind(pI810->drmSubFD, pI810->zHandle) != 0) {
1359	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno));
1360  	    return FALSE;
1361	 }
1362      if (pI810->sysmemHandle != 0)
1363	 if (drmAgpUnbind(pI810->drmSubFD, pI810->sysmemHandle) != 0) {
1364	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno));
1365  	    return FALSE;
1366	 }
1367      if (pI810->xvmcHandle != 0)
1368	 if (drmAgpUnbind(pI810->drmSubFD, pI810->xvmcHandle) != 0) {
1369	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno));
1370  	    return FALSE;
1371	 }
1372      if (pI810->cursorHandle != 0)
1373	 if (drmAgpUnbind(pI810->drmSubFD, pI810->cursorHandle) != 0) {
1374	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno));
1375	    return FALSE;
1376	 }
1377      if (pI810->cursorARGBHandle != 0)
1378	  if (drmAgpUnbind(pI810->drmSubFD, pI810->cursorARGBHandle) != 0) {
1379	      xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"%s\n",strerror(errno));
1380	      return FALSE;
1381	  }
1382      if (pI810->agpAcquired == TRUE)
1383	 drmAgpRelease(pI810->drmSubFD);
1384      pI810->agpAcquired = FALSE;
1385   }
1386   return TRUE;
1387}
1388
1389Bool
1390I810DRIEnter(ScrnInfoPtr pScrn)
1391{
1392   I810Ptr pI810 = I810PTR(pScrn);
1393
1394   if (pI810->directRenderingEnabled) {
1395
1396      if (pI810->agpAcquired == FALSE)
1397	 drmAgpAcquire(pI810->drmSubFD);
1398      pI810->agpAcquired = TRUE;
1399      if (pI810->dcacheHandle != 0)
1400	 if (drmAgpBind(pI810->drmSubFD, pI810->dcacheHandle,
1401			pI810->DepthOffset) != 0)
1402	    return FALSE;
1403      if (pI810->backHandle != 0)
1404	 if (drmAgpBind(pI810->drmSubFD, pI810->backHandle,
1405			pI810->BackOffset) != 0)
1406	    return FALSE;
1407      if (pI810->zHandle != 0)
1408	 if (drmAgpBind(pI810->drmSubFD, pI810->zHandle,
1409			pI810->DepthOffset) != 0)
1410	    return FALSE;
1411      if (pI810->sysmemHandle != 0)
1412	 if (drmAgpBind(pI810->drmSubFD, pI810->sysmemHandle, 0) != 0)
1413	    return FALSE;
1414      if (pI810->xvmcHandle != 0)
1415	 if (drmAgpBind(pI810->drmSubFD, pI810->xvmcHandle,
1416			pI810->MC.Start) != 0)
1417	    return FALSE;
1418      if (pI810->cursorHandle != 0)
1419	 if (drmAgpBind(pI810->drmSubFD, pI810->cursorHandle,
1420			pI810->CursorStart) != 0)
1421	    return FALSE;
1422      if (pI810->cursorARGBHandle != 0)
1423	 if (drmAgpBind(pI810->drmSubFD, pI810->cursorARGBHandle,
1424			pI810->CursorARGBStart) != 0)
1425	    return FALSE;
1426   }
1427
1428   I810SelectBuffer(pScrn, I810_SELECT_FRONT);
1429   return TRUE;
1430}
1431