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