Some fixes that bring me closer to surviving to the 2nd X server generation.
[nouveau] / src / nv_dri.c
1 /*
2  * Copyright 2006 Stephane Marchesin
3  * Copyright 2006 Ben Skeggs
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23
24 #include "nv_include.h"
25
26 #define _XF86DRI_SERVER_
27 #include "GL/glxint.h"
28 #include "GL/glxtokens.h"
29 #include "sarea.h"
30 #include "xf86drm.h"
31 #include "dri.h"
32 #include "nv_dripriv.h"
33 #include "nv_dri.h"
34 #include "drmmode_display.h"
35
36 static Bool NVCreateContext(ScreenPtr pScreen, VisualPtr visual,
37                 drm_context_t hwContext, void *pVisualConfigPriv,
38                 DRIContextType contextStore)
39 {
40         return TRUE;
41 }
42
43
44 static void NVDestroyContext(ScreenPtr pScreen, drm_context_t hwContext,
45                 DRIContextType contextStore)
46 {
47         return;
48 }
49
50 static void NVDRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
51                 DRIContextType oldContextType,
52                 void *oldContext,
53                 DRIContextType newContextType,
54                 void *newContext)
55 {
56         /* we really should do something here */
57         return;
58 }
59
60 static void NVDRIInitBuffers(WindowPtr pWin, RegionPtr prgn, CARD32 indx)
61 {   
62         return;
63 }
64
65 static void NVDRIMoveBuffers(WindowPtr pParent, DDXPointRec ptOldOrg,
66                 RegionPtr prgnSrc, CARD32 indx)
67 {
68         return;
69 }       
70
71 static void NVDRITransitionTo2d(ScreenPtr pScreen)
72 {
73         return;
74 }
75
76 static void NVDRITransitionTo3d(ScreenPtr pScreen)
77 {
78         return;
79 }
80
81 static void NVDRITransitionSingleToMulti3d(ScreenPtr pScreen)
82 {           
83         return;
84 }           
85         
86 static void NVDRITransitionMultiToSingle3d(ScreenPtr pScreen)
87 {       
88         return;
89 }
90
91 static Bool NVDRIInitVisualConfigs(ScreenPtr pScreen)
92 {
93         ScrnInfoPtr pScrn=xf86Screens[pScreen->myNum];
94         __GLXvisualConfig* pConfigs = NULL;
95         NVConfigPrivPtr pNVConfigs = NULL;
96         NVConfigPrivPtr* pNVConfigPtrs = NULL;
97         int db,depth,alpha,stencil;
98         int depths[]={24,16,0};
99         int num_configs,i;
100
101         switch(pScrn->depth)
102         {
103                 case 16:
104                 case 24:
105                         num_configs=2*3*((pScrn->depth==24)?2:1)*2; /* db*depth*alpha*stencil */
106                         if (!(pConfigs=(__GLXvisualConfig*)xcalloc(sizeof(__GLXvisualConfig),num_configs)))
107                                 return FALSE;
108                         if (!(pNVConfigs=(NVConfigPrivPtr)xcalloc(sizeof(NVConfigPrivRec), num_configs))) {
109                                 xfree(pConfigs);
110                                 return FALSE;
111                         }
112                         if (!(pNVConfigPtrs=(NVConfigPrivPtr *)xcalloc(sizeof(NVConfigPrivPtr),num_configs))) {
113                                 xfree(pConfigs);
114                                 xfree(pNVConfigs);
115                                 return FALSE;
116                         }
117
118                         i = 0;
119                         for(db=1;db>=0;db--)
120                         for(depth=0;depth<3;depth++)
121                         for(alpha=0;alpha<((pScrn->depth==24)?2:1);alpha++)
122                         for(stencil=0;stencil<2;stencil++)
123                         {
124                                 pConfigs[i].vid                = (VisualID)(-1);
125                                 pConfigs[i].class              = -1;
126                                 pConfigs[i].rgba               = TRUE;
127                                 if (pScrn->depth==16)
128                                 {                                       
129                                         pConfigs[i].redSize            = 5;
130                                         pConfigs[i].greenSize          = 6;
131                                         pConfigs[i].blueSize           = 5;
132                                         pConfigs[i].alphaSize          = 0;
133                                         pConfigs[i].redMask            = 0x0000F800;
134                                         pConfigs[i].greenMask          = 0x000007E0;
135                                         pConfigs[i].blueMask           = 0x0000001F;
136                                         pConfigs[i].alphaMask          = 0x00000000;
137                                 } else {
138                                         pConfigs[i].redSize            = 8;
139                                         pConfigs[i].greenSize          = 8;
140                                         pConfigs[i].blueSize           = 8;
141                                         pConfigs[i].redMask            = 0x00FF0000;
142                                         pConfigs[i].greenMask          = 0x0000FF00;
143                                         pConfigs[i].blueMask           = 0x000000FF;
144                                         if (alpha) {
145                                                 pConfigs[i].alphaSize          = 8;
146                                                 pConfigs[i].alphaMask          = 0xFF000000;
147                                         } else {
148                                                 pConfigs[i].alphaSize          = 0;
149                                                 pConfigs[i].alphaMask          = 0x00000000;
150                                         }
151                                 }
152
153                                 pConfigs[i].accumRedSize   = 0;
154                                 pConfigs[i].accumGreenSize = 0;
155                                 pConfigs[i].accumBlueSize  = 0;
156                                 pConfigs[i].accumAlphaSize = 0;
157                                 if (db)
158                                         pConfigs[i].doubleBuffer   = TRUE;
159                                 else
160                                         pConfigs[i].doubleBuffer   = FALSE;
161                                 pConfigs[i].stereo             = FALSE;
162                                 pConfigs[i].bufferSize         = pScrn->depth;
163                                 if (depths[depth] == 24 && stencil) {
164                                         pConfigs[i].depthSize          = depths[depth];
165                                         pConfigs[i].stencilSize        = 8;
166                                 } else {
167                                         pConfigs[i].depthSize          = depths[depth];
168                                         pConfigs[i].stencilSize        = 0;
169                                 }
170                                 pConfigs[i].auxBuffers         = 0;
171                                 pConfigs[i].level              = 0;
172                                 pConfigs[i].visualRating       = GLX_NONE;
173                                 pConfigs[i].transparentPixel   = GLX_NONE;
174                                 pConfigs[i].transparentRed     = 0;
175                                 pConfigs[i].transparentGreen   = 0;
176                                 pConfigs[i].transparentBlue    = 0;
177                                 pConfigs[i].transparentAlpha   = 0;
178                                 pConfigs[i].transparentIndex   = 0;
179                                 i++;
180                         }
181                         break;
182                 default:
183                         xf86DrvMsg(pScreen->myNum, X_ERROR, "[dri] no DRI at %d bpp ",pScrn->depth);
184                         return FALSE;
185         }
186         GlxSetVisualConfigs(num_configs, pConfigs, (void**)pNVConfigPtrs);
187         return TRUE;
188 }
189
190 Bool NVDRIGetVersion(ScrnInfoPtr pScrn)
191 {
192         NVPtr pNv = NVPTR(pScrn);
193         char *busId;
194         int fd = 0;
195
196 #ifdef XF86DRM_MODE
197         /* drm already open */
198         if (pNv->drmmode) {
199                 drmmode_ptr drmmode = pNv->drmmode;
200                 fd = drmmode->fd;
201         }
202 #endif
203
204         {
205                 pointer ret;
206                 int errmaj, errmin;
207
208                 ret = LoadSubModule(pScrn->module, "dri", NULL, NULL, NULL,
209                                     NULL, &errmaj, &errmin);
210                 if (!ret) {
211                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
212                                         "error %d\n", errmaj);
213                         LoaderErrorMsg(pScrn->name, "dri", errmaj, errmin);
214                 }
215
216                 if (!ret && errmaj != LDR_ONCEONLY)
217                         return FALSE;
218         }
219
220         xf86LoaderReqSymLists(drmSymbols, NULL);
221         xf86LoaderReqSymLists(driSymbols, NULL);
222         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Loaded DRI module\n");
223
224         if (!fd) {
225                 busId = DRICreatePCIBusID(pNv->PciInfo);
226
227                 fd = drmOpen("nouveau", busId);
228                 xfree(busId);
229         }
230         if (fd < 0) {
231                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
232                         "[dri] Failed to open the DRM\n");
233                 return FALSE;
234         }
235
236         /* Check the lib version */
237         if (xf86LoaderCheckSymbol("drmGetLibVersion"))
238                 pNv->pLibDRMVersion = drmGetLibVersion(0);
239         if (pNv->pLibDRMVersion == NULL) {
240                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
241                 "NVDRIGetVersion failed because libDRM is really "
242                 "way to old to even get a version number out of it.\n"
243                 "[dri] Disabling DRI.\n");
244                 return FALSE;
245         }
246
247         pNv->pKernelDRMVersion = drmGetVersion(fd);
248 #ifdef XF86DRM_MODE
249         if (!pNv->drmmode) /* drmmode still needs the file descriptor */
250 #endif
251         {
252                 drmClose(fd);
253         }
254
255         if (pNv->pKernelDRMVersion == NULL) {
256                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
257                         "failed to get DRM version\n");
258                 return FALSE;
259         }
260         
261         /* temporary lock step versioning */
262 #if NOUVEAU_DRM_HEADER_PATCHLEVEL != 11
263 #error nouveau_drm.h does not match expected patchlevel, update libdrm.
264 #endif
265         if (pNv->pKernelDRMVersion->version_patchlevel !=
266                         NOUVEAU_DRM_HEADER_PATCHLEVEL) {
267                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
268                         "wrong DRM version\n");
269                 return FALSE;
270         }
271
272         return TRUE;
273 }
274
275 Bool NVDRICheckModules(ScrnInfoPtr pScrn)
276 {
277         if (!xf86LoaderCheckSymbol("GlxSetVisualConfigs")) {
278                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
279                            "[dri] GlxSetVisualConfigs not found.\n");
280                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
281                            "      NVIDIA's glx present, or glx not loaded.\n");
282                 return FALSE;
283         }
284
285         return TRUE;
286 }
287
288 Bool NVDRIScreenInit(ScrnInfoPtr pScrn)
289 {
290         DRIInfoPtr     pDRIInfo;
291         NOUVEAUDRIPtr  pNOUVEAUDRI;
292         NVPtr pNv = NVPTR(pScrn);
293         ScreenPtr pScreen;
294         pScreen = screenInfo.screens[pScrn->scrnIndex];
295         int drm_page_size;
296         int drm_fd;
297
298 #ifdef XF86DRM_MODE
299         /* drm already open, reuse it */
300         if (pNv->drmmode) {
301                 drmmode_ptr drmmode = pNv->drmmode;
302                 drm_fd = drmmode->fd;
303         }
304 #endif
305
306         if (!NVDRICheckModules(pScrn))
307                 return FALSE;
308
309         drm_page_size = getpagesize();
310         if (!(pDRIInfo = DRICreateInfoRec())) return FALSE;
311
312         pNv->pDRIInfo                        = pDRIInfo;
313         pDRIInfo->drmDriverName              = "nouveau";
314         pDRIInfo->clientDriverName           = "nouveau";
315         pDRIInfo->busIdString                = DRICreatePCIBusID(pNv->PciInfo);
316
317         pDRIInfo->ddxDriverMajorVersion      = NV_MAJOR_VERSION;
318         pDRIInfo->ddxDriverMinorVersion      = NV_MINOR_VERSION;
319         pDRIInfo->ddxDriverPatchVersion      = NV_PATCHLEVEL;
320
321         /*
322          * We set the FB to be in the higher half of VRAM. If we don't, any
323          * VRAM allocations before the FB is mapped will change that map
324          * and we fail.
325          * We should detect when the DRM decides to change the FB area
326          * but we currently don't know how to.
327          */
328         pDRIInfo->frameBufferSize            = pNv->VRAMPhysicalSize / 2;
329         pDRIInfo->frameBufferPhysicalAddress = (void *)pNv->VRAMPhysical;
330         pDRIInfo->frameBufferStride          = pScrn->displayWidth * pScrn->bitsPerPixel/8;
331
332         pDRIInfo->ddxDrawableTableEntry      = 1;
333         pDRIInfo->maxDrawableTableEntry      = 1;
334
335         if (!(pNOUVEAUDRI = (NOUVEAUDRIPtr)xcalloc(sizeof(NOUVEAUDRIRec), 1))) {
336                 DRIDestroyInfoRec(pDRIInfo);
337                 pNv->pDRIInfo = NULL;
338                 return FALSE;
339         }
340         pDRIInfo->devPrivate                 = pNOUVEAUDRI; 
341         pDRIInfo->devPrivateSize             = sizeof(NOUVEAUDRIRec);
342         pDRIInfo->contextSize                = sizeof(NVDRIContextRec);
343         pDRIInfo->SAREASize                  = (drm_page_size > SAREA_MAX) ? drm_page_size : SAREA_MAX;
344
345         pDRIInfo->CreateContext              = NVCreateContext;
346         pDRIInfo->DestroyContext             = NVDestroyContext;
347         pDRIInfo->SwapContext                = NVDRISwapContext;
348         pDRIInfo->InitBuffers                = NVDRIInitBuffers;
349         pDRIInfo->MoveBuffers                = NVDRIMoveBuffers;
350         pDRIInfo->bufferRequests             = DRI_ALL_WINDOWS;
351         pDRIInfo->TransitionTo2d             = NVDRITransitionTo2d;
352         pDRIInfo->TransitionTo3d             = NVDRITransitionTo3d;
353         pDRIInfo->TransitionSingleToMulti3D  = NVDRITransitionSingleToMulti3d;
354         pDRIInfo->TransitionMultiToSingle3D  = NVDRITransitionMultiToSingle3d;
355
356         pDRIInfo->createDummyCtx     = FALSE;
357         pDRIInfo->createDummyCtxPriv = FALSE;
358
359         if (!DRIScreenInit(pScreen, pDRIInfo, &drm_fd)) {
360                 xf86DrvMsg(pScreen->myNum, X_ERROR,
361                                 "[dri] DRIScreenInit failed.  Disabling DRI.\n");
362                 xfree(pDRIInfo->devPrivate);
363                 pDRIInfo->devPrivate = NULL;
364                 DRIDestroyInfoRec(pDRIInfo);
365                 pDRIInfo = NULL;
366                 return FALSE;
367         }
368
369         if (!NVDRIInitVisualConfigs(pScreen)) {
370                 xf86DrvMsg(pScreen->myNum, X_ERROR,
371                                 "[dri] NVDRIInitVisualConfigs failed.  Disabling DRI.\n");
372                 xfree(pDRIInfo->devPrivate);
373                 pDRIInfo->devPrivate = NULL;
374                 DRIDestroyInfoRec(pDRIInfo);
375                 pDRIInfo = NULL;
376                 return FALSE;
377         }
378
379         /* need_close = 0, because DRICloseScreen() will handle the closing. */
380         if (nouveau_device_open_existing(&pNv->dev, 0, drm_fd, 0)) {
381                 xf86DrvMsg(pScreen->myNum, X_ERROR, "Error creating device\n");
382                 xfree(pDRIInfo->devPrivate);
383                 pDRIInfo->devPrivate = NULL;
384                 DRIDestroyInfoRec(pDRIInfo);
385                 pDRIInfo = NULL;
386                 return FALSE;
387         }
388
389         return TRUE;
390 }
391
392 Bool NVDRIFinishScreenInit(ScrnInfoPtr pScrn)
393 {
394         ScreenPtr      pScreen = screenInfo.screens[pScrn->scrnIndex];
395         NVPtr          pNv = NVPTR(pScrn);
396         NOUVEAUDRIPtr  pNOUVEAUDRI;
397
398         if (!DRIFinishScreenInit(pScreen)) {
399                 return FALSE;
400         }
401
402         pNOUVEAUDRI                     = (NOUVEAUDRIPtr)pNv->pDRIInfo->devPrivate;
403
404         pNOUVEAUDRI->device_id          = pNv->Chipset;
405
406         pNOUVEAUDRI->width              = pScrn->virtualX;
407         pNOUVEAUDRI->height             = pScrn->virtualY;
408         pNOUVEAUDRI->depth              = pScrn->depth;
409         pNOUVEAUDRI->bpp                = pScrn->bitsPerPixel;
410
411         pNOUVEAUDRI->front_offset       = pNv->FB->offset;
412         pNOUVEAUDRI->front_pitch        = pScrn->displayWidth;
413         /* back/depth buffers will likely be allocated on a per-drawable
414          * basis, but these may be useful if we want to support shared back
415          * buffers at some point.
416          */
417         pNOUVEAUDRI->back_offset        = 0;
418         pNOUVEAUDRI->back_pitch         = 0;
419         pNOUVEAUDRI->depth_offset       = 0;
420         pNOUVEAUDRI->depth_pitch        = 0;
421
422         return TRUE;
423 }
424
425 void NVDRICloseScreen(ScrnInfoPtr pScrn)
426 {
427         ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
428         NVPtr pNv = NVPTR(pScrn);
429
430         /* close fifo channel so it won't fail on open for next server generation. */ 
431         nouveau_channel_free(&pNv->chan);
432
433         /* this may not work for kernel modesetting, so i'm leaving a note. */
434         nouveau_device_close(&pNv->dev);
435
436         DRICloseScreen(pScreen);
437
438         if (pNv->pDRIInfo) {
439                 if (pNv->pDRIInfo->devPrivate) {
440                         xfree(pNv->pDRIInfo->devPrivate);
441                         pNv->pDRIInfo->devPrivate = NULL;
442                 }
443                 DRIDestroyInfoRec(pNv->pDRIInfo);
444                 pNv->pDRIInfo = NULL;
445         }
446 }
447