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