Merge branch 'nouveau-import'
[mesa.git] / src / mesa / drivers / dri / tdfx / tdfx_screen.c
1 /* -*- mode: c; c-basic-offset: 3 -*-
2 *
3 * Copyright 2000 VA Linux Systems Inc., Fremont, California.
4 *
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
23 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26 /* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_screen.c,v 1.3 2002/02/22 21:45:03 dawes Exp $ */
27
28 /*
29 * Original rewrite:
30 * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
31 *
32 * Authors:
33 * Gareth Hughes <gareth@valinux.com>
34 *
35 */
36
37 #include "tdfx_dri.h"
38 #include "tdfx_context.h"
39 #include "tdfx_lock.h"
40 #include "tdfx_vb.h"
41 #include "tdfx_span.h"
42 #include "tdfx_tris.h"
43
44 #include "framebuffer.h"
45 #include "renderbuffer.h"
46 #include "xmlpool.h"
47
48 #include "utils.h"
49
50 #ifdef DEBUG_LOCKING
51 char *prevLockFile = 0;
52 int prevLockLine = 0;
53 #endif
54
55 #ifndef TDFX_DEBUG
56 int TDFX_DEBUG = 0;
57 #endif
58
59 PUBLIC const char __driConfigOptions[] =
60 DRI_CONF_BEGIN
61 DRI_CONF_SECTION_DEBUG
62 DRI_CONF_NO_RAST(false)
63 DRI_CONF_SECTION_END
64 DRI_CONF_END;
65
66 static const GLuint __driNConfigOptions = 1;
67
68 extern const struct dri_extension card_extensions[];
69 extern const struct dri_extension napalm_extensions[];
70
71 static GLboolean
72 tdfxCreateScreen( __DRIscreenPrivate *sPriv )
73 {
74 tdfxScreenPrivate *fxScreen;
75 TDFXDRIPtr fxDRIPriv = (TDFXDRIPtr) sPriv->pDevPriv;
76 PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension =
77 (PFNGLXSCRENABLEEXTENSIONPROC) (*dri_interface->getProcAddress("glxEnableExtension"));
78 void *const psc = sPriv->psc->screenConfigs;
79
80 if (sPriv->devPrivSize != sizeof(TDFXDRIRec)) {
81 fprintf(stderr,"\nERROR! sizeof(TDFXDRIRec) does not match passed size from device driver\n");
82 return GL_FALSE;
83 }
84
85 /* Allocate the private area */
86 fxScreen = (tdfxScreenPrivate *) CALLOC( sizeof(tdfxScreenPrivate) );
87 if ( !fxScreen )
88 return GL_FALSE;
89
90 /* parse information in __driConfigOptions */
91 driParseOptionInfo (&fxScreen->optionCache,
92 __driConfigOptions, __driNConfigOptions);
93
94 fxScreen->driScrnPriv = sPriv;
95 sPriv->private = (void *) fxScreen;
96
97 fxScreen->regs.handle = fxDRIPriv->regs;
98 fxScreen->regs.size = fxDRIPriv->regsSize;
99 fxScreen->deviceID = fxDRIPriv->deviceID;
100 fxScreen->width = fxDRIPriv->width;
101 fxScreen->height = fxDRIPriv->height;
102 fxScreen->mem = fxDRIPriv->mem;
103 fxScreen->cpp = fxDRIPriv->cpp;
104 fxScreen->stride = fxDRIPriv->stride;
105 fxScreen->fifoOffset = fxDRIPriv->fifoOffset;
106 fxScreen->fifoSize = fxDRIPriv->fifoSize;
107 fxScreen->fbOffset = fxDRIPriv->fbOffset;
108 fxScreen->backOffset = fxDRIPriv->backOffset;
109 fxScreen->depthOffset = fxDRIPriv->depthOffset;
110 fxScreen->textureOffset = fxDRIPriv->textureOffset;
111 fxScreen->textureSize = fxDRIPriv->textureSize;
112 fxScreen->sarea_priv_offset = fxDRIPriv->sarea_priv_offset;
113
114 if ( drmMap( sPriv->fd, fxScreen->regs.handle,
115 fxScreen->regs.size, &fxScreen->regs.map ) ) {
116 return GL_FALSE;
117 }
118
119 if (glx_enable_extension != NULL) {
120 (*glx_enable_extension)(psc, "GLX_SGI_make_current_read");
121 }
122
123 return GL_TRUE;
124 }
125
126
127 static void
128 tdfxDestroyScreen( __DRIscreenPrivate *sPriv )
129 {
130 tdfxScreenPrivate *fxScreen = (tdfxScreenPrivate *) sPriv->private;
131
132 if (!fxScreen)
133 return;
134
135 drmUnmap( fxScreen->regs.map, fxScreen->regs.size );
136
137 /* free all option information */
138 driDestroyOptionInfo (&fxScreen->optionCache);
139
140 FREE( fxScreen );
141 sPriv->private = NULL;
142 }
143
144
145 static GLboolean
146 tdfxInitDriver( __DRIscreenPrivate *sPriv )
147 {
148 if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
149 fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *)sPriv );
150 }
151
152 if ( !tdfxCreateScreen( sPriv ) ) {
153 tdfxDestroyScreen( sPriv );
154 return GL_FALSE;
155 }
156
157 return GL_TRUE;
158 }
159
160
161 static GLboolean
162 tdfxCreateBuffer( __DRIscreenPrivate *driScrnPriv,
163 __DRIdrawablePrivate *driDrawPriv,
164 const __GLcontextModes *mesaVis,
165 GLboolean isPixmap )
166 {
167 tdfxScreenPrivate *screen = (tdfxScreenPrivate *) driScrnPriv->private;
168
169 if (isPixmap) {
170 return GL_FALSE; /* not implemented */
171 }
172 else {
173 struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
174
175 {
176 driRenderbuffer *frontRb
177 = driNewRenderbuffer(GL_RGBA, NULL, screen->cpp,
178 screen->fbOffset, screen->width, driDrawPriv);
179 tdfxSetSpanFunctions(frontRb, mesaVis);
180 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base);
181 }
182
183 if (mesaVis->doubleBufferMode) {
184 driRenderbuffer *backRb
185 = driNewRenderbuffer(GL_RGBA, NULL, screen->cpp,
186 screen->backOffset, screen->width,
187 driDrawPriv);
188 tdfxSetSpanFunctions(backRb, mesaVis);
189 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base);
190 backRb->backBuffer = GL_TRUE;
191 }
192
193 if (mesaVis->depthBits == 16) {
194 driRenderbuffer *depthRb
195 = driNewRenderbuffer(GL_DEPTH_COMPONENT16, NULL, screen->cpp,
196 screen->depthOffset, screen->width,
197 driDrawPriv);
198 tdfxSetSpanFunctions(depthRb, mesaVis);
199 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
200 }
201 else if (mesaVis->depthBits == 24) {
202 driRenderbuffer *depthRb
203 = driNewRenderbuffer(GL_DEPTH_COMPONENT24, NULL, screen->cpp,
204 screen->depthOffset, screen->width,
205 driDrawPriv);
206 tdfxSetSpanFunctions(depthRb, mesaVis);
207 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
208 }
209
210 if (mesaVis->stencilBits > 0) {
211 driRenderbuffer *stencilRb
212 = driNewRenderbuffer(GL_STENCIL_INDEX8_EXT, NULL, screen->cpp,
213 screen->depthOffset, screen->width,
214 driDrawPriv);
215 tdfxSetSpanFunctions(stencilRb, mesaVis);
216 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &stencilRb->Base);
217 }
218
219 _mesa_add_soft_renderbuffers(fb,
220 GL_FALSE, /* color */
221 GL_FALSE, /* depth */
222 GL_FALSE, /*swStencil,*/
223 mesaVis->accumRedBits > 0,
224 GL_FALSE, /* alpha */
225 GL_FALSE /* aux */);
226 driDrawPriv->driverPrivate = (void *) fb;
227
228 return (driDrawPriv->driverPrivate != NULL);
229 }
230 }
231
232
233 static void
234 tdfxDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
235 {
236 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
237 }
238
239
240 static void
241 tdfxSwapBuffers( __DRIdrawablePrivate *driDrawPriv )
242
243 {
244 GET_CURRENT_CONTEXT(ctx);
245 tdfxContextPtr fxMesa = 0;
246 GLframebuffer *mesaBuffer;
247
248 if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
249 fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *)driDrawPriv );
250 }
251
252 mesaBuffer = (GLframebuffer *) driDrawPriv->driverPrivate;
253 if ( !mesaBuffer->Visual.doubleBufferMode )
254 return; /* can't swap a single-buffered window */
255
256 /* If the current context's drawable matches the given drawable
257 * we have to do a glFinish (per the GLX spec).
258 */
259 if ( ctx ) {
260 __DRIdrawablePrivate *curDrawPriv;
261 fxMesa = TDFX_CONTEXT(ctx);
262 curDrawPriv = fxMesa->driContext->driDrawablePriv;
263
264 if ( curDrawPriv == driDrawPriv ) {
265 /* swapping window bound to current context, flush first */
266 _mesa_notifySwapBuffers( ctx );
267 LOCK_HARDWARE( fxMesa );
268 }
269 else {
270 /* find the fxMesa context previously bound to the window */
271 fxMesa = (tdfxContextPtr) driDrawPriv->driContextPriv->driverPrivate;
272 if (!fxMesa)
273 return;
274 LOCK_HARDWARE( fxMesa );
275 fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
276 #ifdef DEBUG
277 printf("SwapBuf SetState 1\n");
278 #endif
279 fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
280 }
281 }
282
283 #ifdef STATS
284 {
285 int stalls;
286 static int prevStalls = 0;
287
288 stalls = fxMesa->Glide.grFifoGetStalls();
289
290 fprintf( stderr, "%s:\n", __FUNCTION__ );
291 if ( stalls != prevStalls ) {
292 fprintf( stderr, " %d stalls occurred\n",
293 stalls - prevStalls );
294 prevStalls = stalls;
295 }
296 if ( fxMesa && fxMesa->texSwaps ) {
297 fprintf( stderr, " %d texture swaps occurred\n",
298 fxMesa->texSwaps );
299 fxMesa->texSwaps = 0;
300 }
301 }
302 #endif
303
304 if (fxMesa->scissoredClipRects) {
305 /* restore clip rects without scissor box */
306 fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
307 driDrawPriv->w, driDrawPriv->h,
308 driDrawPriv->numClipRects,
309 driDrawPriv->pClipRects );
310 }
311
312 fxMesa->Glide.grDRIBufferSwap( fxMesa->Glide.SwapInterval );
313
314 if (fxMesa->scissoredClipRects) {
315 /* restore clip rects WITH scissor box */
316 fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
317 driDrawPriv->w, driDrawPriv->h,
318 fxMesa->numClipRects, fxMesa->pClipRects );
319 }
320
321
322 #if 0
323 {
324 FxI32 result;
325 do {
326 FxI32 result;
327 fxMesa->Glide.grGet(GR_PENDING_BUFFERSWAPS, 4, &result);
328 } while ( result > fxMesa->maxPendingSwapBuffers );
329 }
330 #endif
331
332 fxMesa->stats.swapBuffer++;
333
334 if (ctx) {
335 if (ctx->DriverCtx != fxMesa) {
336 fxMesa = TDFX_CONTEXT(ctx);
337 fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
338 #ifdef DEBUG
339 printf("SwapBuf SetState 2\n");
340 #endif
341 fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
342 }
343 UNLOCK_HARDWARE( fxMesa );
344 }
345 }
346
347
348 static const struct __DriverAPIRec tdfxAPI = {
349 .InitDriver = tdfxInitDriver,
350 .DestroyScreen = tdfxDestroyScreen,
351 .CreateContext = tdfxCreateContext,
352 .DestroyContext = tdfxDestroyContext,
353 .CreateBuffer = tdfxCreateBuffer,
354 .DestroyBuffer = tdfxDestroyBuffer,
355 .SwapBuffers = tdfxSwapBuffers,
356 .MakeCurrent = tdfxMakeCurrent,
357 .UnbindContext = tdfxUnbindContext,
358 .GetSwapInfo = NULL,
359 .GetMSC = NULL,
360 .WaitForMSC = NULL,
361 .WaitForSBC = NULL,
362 .SwapBuffersMSC = NULL
363 };
364
365
366 static __GLcontextModes *tdfxFillInModes(unsigned pixel_bits,
367 unsigned depth_bits,
368 unsigned stencil_bits,
369 GLboolean have_back_buffer)
370 {
371 __GLcontextModes *modes;
372 __GLcontextModes *m;
373 unsigned num_modes;
374 unsigned vis[2] = { GLX_TRUE_COLOR, GLX_DIRECT_COLOR };
375 unsigned deep = (depth_bits > 17);
376 unsigned i, db, depth, accum, stencil;
377
378 /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
379 * enough to add support. Basically, if a context is created with an
380 * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
381 * will never be used.
382 */
383
384 num_modes = (depth_bits == 16) ? 32 : 16;
385
386 modes = (*dri_interface->createContextModes)(num_modes, sizeof(__GLcontextModes));
387 m = modes;
388
389 for (i = 0; i <= 1; i++) {
390 for (db = 0; db <= 1; db++) {
391 for (depth = 0; depth <= 1; depth++) {
392 for (accum = 0; accum <= 1; accum++) {
393 for (stencil = 0; stencil <= !deep; stencil++) {
394 if (deep) stencil = depth;
395 m->redBits = deep ? 8 : 5;
396 m->greenBits = deep ? 8 : 6;
397 m->blueBits = deep ? 8 : 5;
398 m->alphaBits = deep ? 8 : 0;
399 m->redMask = deep ?0xFF000000 :0x0000F800;
400 m->greenMask = deep ?0x00FF0000 :0x000007E0;
401 m->blueMask = deep ?0x0000FF00 :0x0000001F;
402 m->alphaMask = deep ? 0x000000FF : 0;
403 m->rgbBits = m->redBits + m->greenBits +
404 m->blueBits + m->alphaBits;
405 m->accumRedBits = accum ? 16 : 0;
406 m->accumGreenBits = accum ? 16 : 0;
407 m->accumBlueBits = accum ? 16 : 0;
408 m->accumAlphaBits = (accum && deep) ? 16 : 0;
409 m->stencilBits = stencil ? 8 : 0;
410 m->depthBits = deep
411 ? (depth ? 24 : 0)
412 : (depth ? 0 : depth_bits);
413 m->visualType = vis[i];
414 m->renderType = GLX_RGBA_BIT;
415 m->drawableType = GLX_WINDOW_BIT;
416 m->rgbMode = GL_TRUE;
417 m->doubleBufferMode = db ? GL_TRUE : GL_FALSE;
418 if (db)
419 m->swapMethod = GLX_SWAP_UNDEFINED_OML;
420 m->visualRating = ((stencil && !deep) || accum)
421 ? GLX_SLOW_CONFIG
422 : GLX_NONE;
423 m = m->next;
424 if (deep) stencil = 0;
425 }
426 }
427 }
428 }
429 }
430
431 return modes;
432 }
433
434 /**
435 * This is the bootstrap function for the driver. libGL supplies all of the
436 * requisite information about the system, and the driver initializes itself.
437 * This routine also fills in the linked list pointed to by \c driver_modes
438 * with the \c __GLcontextModes that the driver can support for windows or
439 * pbuffers.
440 *
441 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
442 * failure.
443 */
444 PUBLIC
445 void * __driCreateNewScreen_20050727( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
446 const __GLcontextModes * modes,
447 const __DRIversion * ddx_version,
448 const __DRIversion * dri_version,
449 const __DRIversion * drm_version,
450 const __DRIframebuffer * frame_buffer,
451 drmAddress pSAREA, int fd,
452 int internal_api_version,
453 const __DRIinterfaceMethods * interface,
454 __GLcontextModes ** driver_modes )
455 {
456 __DRIscreenPrivate *psp;
457 static const __DRIversion ddx_expected = { 1, 1, 0 };
458 static const __DRIversion dri_expected = { 4, 0, 0 };
459 static const __DRIversion drm_expected = { 1, 0, 0 };
460
461 dri_interface = interface;
462
463 if ( ! driCheckDriDdxDrmVersions2( "tdfx",
464 dri_version, & dri_expected,
465 ddx_version, & ddx_expected,
466 drm_version, & drm_expected ) ) {
467 return NULL;
468 }
469
470 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
471 ddx_version, dri_version, drm_version,
472 frame_buffer, pSAREA, fd,
473 internal_api_version, &tdfxAPI);
474
475 if (psp != NULL) {
476 /* divined from tdfx_dri.c, sketchy */
477 TDFXDRIPtr dri_priv = (TDFXDRIPtr) psp->pDevPriv;
478 int bpp = (dri_priv->cpp > 2) ? 24 : 16;
479
480 /* XXX i wish it was like this */
481 /* bpp = dri_priv->bpp */
482
483 *driver_modes = tdfxFillInModes(bpp, (bpp == 16) ? 16 : 24,
484 (bpp == 16) ? 0 : 8,
485 (dri_priv->backOffset!=dri_priv->depthOffset));
486
487 /* Calling driInitExtensions here, with a NULL context pointer, does not actually
488 * enable the extensions. It just makes sure that all the dispatch offsets for all
489 * the extensions that *might* be enables are known. This is needed because the
490 * dispatch offsets need to be known when _mesa_context_create is called, but we can't
491 * enable the extensions until we have a context pointer.
492 *
493 * Hello chicken. Hello egg. How are you two today?
494 */
495 driInitExtensions( NULL, card_extensions, GL_FALSE );
496 driInitExtensions( NULL, napalm_extensions, GL_FALSE );
497 }
498
499 return (void *)psp;
500 }