Add new void *addr and __DRIdrawablePrivate parameters to
[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
77 if (sPriv->devPrivSize != sizeof(TDFXDRIRec)) {
78 fprintf(stderr,"\nERROR! sizeof(TDFXDRIRec) does not match passed size from device driver\n");
79 return GL_FALSE;
80 }
81
82 /* Allocate the private area */
83 fxScreen = (tdfxScreenPrivate *) CALLOC( sizeof(tdfxScreenPrivate) );
84 if ( !fxScreen )
85 return GL_FALSE;
86
87 /* parse information in __driConfigOptions */
88 driParseOptionInfo (&fxScreen->optionCache,
89 __driConfigOptions, __driNConfigOptions);
90
91 fxScreen->driScrnPriv = sPriv;
92 sPriv->private = (void *) fxScreen;
93
94 fxScreen->regs.handle = fxDRIPriv->regs;
95 fxScreen->regs.size = fxDRIPriv->regsSize;
96 fxScreen->deviceID = fxDRIPriv->deviceID;
97 fxScreen->width = fxDRIPriv->width;
98 fxScreen->height = fxDRIPriv->height;
99 fxScreen->mem = fxDRIPriv->mem;
100 fxScreen->cpp = fxDRIPriv->cpp;
101 fxScreen->stride = fxDRIPriv->stride;
102 fxScreen->fifoOffset = fxDRIPriv->fifoOffset;
103 fxScreen->fifoSize = fxDRIPriv->fifoSize;
104 fxScreen->fbOffset = fxDRIPriv->fbOffset;
105 fxScreen->backOffset = fxDRIPriv->backOffset;
106 fxScreen->depthOffset = fxDRIPriv->depthOffset;
107 fxScreen->textureOffset = fxDRIPriv->textureOffset;
108 fxScreen->textureSize = fxDRIPriv->textureSize;
109 fxScreen->sarea_priv_offset = fxDRIPriv->sarea_priv_offset;
110
111 if ( drmMap( sPriv->fd, fxScreen->regs.handle,
112 fxScreen->regs.size, &fxScreen->regs.map ) ) {
113 return GL_FALSE;
114 }
115
116 return GL_TRUE;
117 }
118
119
120 static void
121 tdfxDestroyScreen( __DRIscreenPrivate *sPriv )
122 {
123 tdfxScreenPrivate *fxScreen = (tdfxScreenPrivate *) sPriv->private;
124
125 if (!fxScreen)
126 return;
127
128 drmUnmap( fxScreen->regs.map, fxScreen->regs.size );
129
130 /* free all option information */
131 driDestroyOptionInfo (&fxScreen->optionCache);
132
133 FREE( fxScreen );
134 sPriv->private = NULL;
135 }
136
137
138 static GLboolean
139 tdfxInitDriver( __DRIscreenPrivate *sPriv )
140 {
141 if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
142 fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *)sPriv );
143 }
144
145 if ( !tdfxCreateScreen( sPriv ) ) {
146 tdfxDestroyScreen( sPriv );
147 return GL_FALSE;
148 }
149
150 return GL_TRUE;
151 }
152
153
154 static GLboolean
155 tdfxCreateBuffer( __DRIscreenPrivate *driScrnPriv,
156 __DRIdrawablePrivate *driDrawPriv,
157 const __GLcontextModes *mesaVis,
158 GLboolean isPixmap )
159 {
160 tdfxScreenPrivate *screen = (tdfxScreenPrivate *) driScrnPriv->private;
161
162 if (isPixmap) {
163 return GL_FALSE; /* not implemented */
164 }
165 else {
166 struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
167
168 {
169 driRenderbuffer *frontRb
170 = driNewRenderbuffer(GL_RGBA, NULL, screen->cpp,
171 screen->fbOffset, screen->width, driDrawPriv);
172 tdfxSetSpanFunctions(frontRb, mesaVis);
173 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base);
174 }
175
176 if (mesaVis->doubleBufferMode) {
177 driRenderbuffer *backRb
178 = driNewRenderbuffer(GL_RGBA, NULL, screen->cpp,
179 screen->backOffset, screen->width,
180 driDrawPriv);
181 tdfxSetSpanFunctions(backRb, mesaVis);
182 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base);
183 }
184
185 if (mesaVis->depthBits == 16) {
186 driRenderbuffer *depthRb
187 = driNewRenderbuffer(GL_DEPTH_COMPONENT16, NULL, screen->cpp,
188 screen->depthOffset, screen->width,
189 driDrawPriv);
190 tdfxSetSpanFunctions(depthRb, mesaVis);
191 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
192 }
193 else if (mesaVis->depthBits == 24) {
194 driRenderbuffer *depthRb
195 = driNewRenderbuffer(GL_DEPTH_COMPONENT24, 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
202 if (mesaVis->stencilBits > 0) {
203 driRenderbuffer *stencilRb
204 = driNewRenderbuffer(GL_STENCIL_INDEX8_EXT, NULL, screen->cpp,
205 screen->depthOffset, screen->width,
206 driDrawPriv);
207 tdfxSetSpanFunctions(stencilRb, mesaVis);
208 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &stencilRb->Base);
209 }
210
211 _mesa_add_soft_renderbuffers(fb,
212 GL_FALSE, /* color */
213 GL_FALSE, /* depth */
214 GL_FALSE, /*swStencil,*/
215 mesaVis->accumRedBits > 0,
216 GL_FALSE, /* alpha */
217 GL_FALSE /* aux */);
218 driDrawPriv->driverPrivate = (void *) fb;
219
220 return (driDrawPriv->driverPrivate != NULL);
221 }
222 }
223
224
225 static void
226 tdfxDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
227 {
228 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
229 }
230
231
232 static void
233 tdfxSwapBuffers( __DRIdrawablePrivate *driDrawPriv )
234
235 {
236 GET_CURRENT_CONTEXT(ctx);
237 tdfxContextPtr fxMesa = 0;
238 GLframebuffer *mesaBuffer;
239
240 if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
241 fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *)driDrawPriv );
242 }
243
244 mesaBuffer = (GLframebuffer *) driDrawPriv->driverPrivate;
245 if ( !mesaBuffer->Visual.doubleBufferMode )
246 return; /* can't swap a single-buffered window */
247
248 /* If the current context's drawable matches the given drawable
249 * we have to do a glFinish (per the GLX spec).
250 */
251 if ( ctx ) {
252 __DRIdrawablePrivate *curDrawPriv;
253 fxMesa = TDFX_CONTEXT(ctx);
254 curDrawPriv = fxMesa->driContext->driDrawablePriv;
255
256 if ( curDrawPriv == driDrawPriv ) {
257 /* swapping window bound to current context, flush first */
258 _mesa_notifySwapBuffers( ctx );
259 LOCK_HARDWARE( fxMesa );
260 }
261 else {
262 /* find the fxMesa context previously bound to the window */
263 fxMesa = (tdfxContextPtr) driDrawPriv->driContextPriv->driverPrivate;
264 if (!fxMesa)
265 return;
266 LOCK_HARDWARE( fxMesa );
267 fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
268 printf("SwapBuf SetState 1\n");
269 fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
270 }
271 }
272
273 #ifdef STATS
274 {
275 int stalls;
276 static int prevStalls = 0;
277
278 stalls = fxMesa->Glide.grFifoGetStalls();
279
280 fprintf( stderr, "%s:\n", __FUNCTION__ );
281 if ( stalls != prevStalls ) {
282 fprintf( stderr, " %d stalls occurred\n",
283 stalls - prevStalls );
284 prevStalls = stalls;
285 }
286 if ( fxMesa && fxMesa->texSwaps ) {
287 fprintf( stderr, " %d texture swaps occurred\n",
288 fxMesa->texSwaps );
289 fxMesa->texSwaps = 0;
290 }
291 }
292 #endif
293
294 if (fxMesa->scissoredClipRects) {
295 /* restore clip rects without scissor box */
296 fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
297 driDrawPriv->w, driDrawPriv->h,
298 driDrawPriv->numClipRects,
299 driDrawPriv->pClipRects );
300 }
301
302 fxMesa->Glide.grDRIBufferSwap( fxMesa->Glide.SwapInterval );
303
304 if (fxMesa->scissoredClipRects) {
305 /* restore clip rects WITH scissor box */
306 fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
307 driDrawPriv->w, driDrawPriv->h,
308 fxMesa->numClipRects, fxMesa->pClipRects );
309 }
310
311
312 #if 0
313 {
314 FxI32 result;
315 do {
316 FxI32 result;
317 fxMesa->Glide.grGet(GR_PENDING_BUFFERSWAPS, 4, &result);
318 } while ( result > fxMesa->maxPendingSwapBuffers );
319 }
320 #endif
321
322 fxMesa->stats.swapBuffer++;
323
324 if (ctx) {
325 if (ctx->DriverCtx != fxMesa) {
326 fxMesa = TDFX_CONTEXT(ctx);
327 fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
328 printf("SwapBuf SetState 2\n");
329 fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
330 }
331 UNLOCK_HARDWARE( fxMesa );
332 }
333 }
334
335
336 static const struct __DriverAPIRec tdfxAPI = {
337 .InitDriver = tdfxInitDriver,
338 .DestroyScreen = tdfxDestroyScreen,
339 .CreateContext = tdfxCreateContext,
340 .DestroyContext = tdfxDestroyContext,
341 .CreateBuffer = tdfxCreateBuffer,
342 .DestroyBuffer = tdfxDestroyBuffer,
343 .SwapBuffers = tdfxSwapBuffers,
344 .MakeCurrent = tdfxMakeCurrent,
345 .UnbindContext = tdfxUnbindContext,
346 .GetSwapInfo = NULL,
347 .GetMSC = NULL,
348 .WaitForMSC = NULL,
349 .WaitForSBC = NULL,
350 .SwapBuffersMSC = NULL
351 };
352
353
354 static __GLcontextModes *tdfxFillInModes(unsigned pixel_bits,
355 unsigned depth_bits,
356 unsigned stencil_bits,
357 GLboolean have_back_buffer)
358 {
359 __GLcontextModes *modes;
360 __GLcontextModes *m;
361 unsigned num_modes;
362 unsigned vis[2] = { GLX_TRUE_COLOR, GLX_DIRECT_COLOR };
363 unsigned deep = (depth_bits > 17);
364 unsigned i, db, depth, accum, stencil;
365
366 /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
367 * enough to add support. Basically, if a context is created with an
368 * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
369 * will never be used.
370 */
371
372 num_modes = (depth_bits == 16) ? 32 : 16;
373
374 modes = (*dri_interface->createContextModes)(num_modes, sizeof(__GLcontextModes));
375 m = modes;
376
377 for (i = 0; i <= 1; i++) {
378 for (db = 0; db <= 1; db++) {
379 for (depth = 0; depth <= 1; depth++) {
380 for (accum = 0; accum <= 1; accum++) {
381 for (stencil = 0; stencil <= !deep; stencil++) {
382 if (deep) stencil = depth;
383 m->redBits = deep ? 8 : 5;
384 m->greenBits = deep ? 8 : 6;
385 m->blueBits = deep ? 8 : 5;
386 m->alphaBits = deep ? 8 : 0;
387 m->redMask = deep ?0xFF000000 :0x0000F800;
388 m->greenMask = deep ?0x00FF0000 :0x000007E0;
389 m->blueMask = deep ?0x0000FF00 :0x0000001F;
390 m->alphaMask = deep ? 0x000000FF : 0;
391 m->rgbBits = m->redBits + m->greenBits +
392 m->blueBits + m->alphaBits;
393 m->accumRedBits = accum ? 16 : 0;
394 m->accumGreenBits = accum ? 16 : 0;
395 m->accumBlueBits = accum ? 16 : 0;
396 m->accumAlphaBits = accum ? 16 : 0;
397 m->stencilBits = stencil ? 8 : 0;
398 m->depthBits = deep
399 ? (depth ? 24 : 0)
400 : (depth ? 0 : depth_bits);
401 m->visualType = vis[i];
402 m->renderType = GLX_RGBA_BIT;
403 m->drawableType = GLX_WINDOW_BIT;
404 m->rgbMode = GL_TRUE;
405 m->doubleBufferMode = db ? GL_TRUE : GL_FALSE;
406 if (db)
407 m->swapMethod = GLX_SWAP_UNDEFINED_OML;
408 m->visualRating = ((stencil && !deep) || accum)
409 ? GLX_SLOW_CONFIG
410 : GLX_NONE;
411 m = m->next;
412 if (deep) stencil = 0;
413 }
414 }
415 }
416 }
417 }
418
419 return modes;
420 }
421
422 /**
423 * This is the bootstrap function for the driver. libGL supplies all of the
424 * requisite information about the system, and the driver initializes itself.
425 * This routine also fills in the linked list pointed to by \c driver_modes
426 * with the \c __GLcontextModes that the driver can support for windows or
427 * pbuffers.
428 *
429 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
430 * failure.
431 */
432 PUBLIC
433 void * __driCreateNewScreen_20050727( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
434 const __GLcontextModes * modes,
435 const __DRIversion * ddx_version,
436 const __DRIversion * dri_version,
437 const __DRIversion * drm_version,
438 const __DRIframebuffer * frame_buffer,
439 drmAddress pSAREA, int fd,
440 int internal_api_version,
441 const __DRIinterfaceMethods * interface,
442 __GLcontextModes ** driver_modes )
443 {
444 __DRIscreenPrivate *psp;
445 static const __DRIversion ddx_expected = { 1, 1, 0 };
446 static const __DRIversion dri_expected = { 4, 0, 0 };
447 static const __DRIversion drm_expected = { 1, 0, 0 };
448
449 dri_interface = interface;
450
451 if ( ! driCheckDriDdxDrmVersions2( "tdfx",
452 dri_version, & dri_expected,
453 ddx_version, & ddx_expected,
454 drm_version, & drm_expected ) ) {
455 return NULL;
456 }
457
458 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
459 ddx_version, dri_version, drm_version,
460 frame_buffer, pSAREA, fd,
461 internal_api_version, &tdfxAPI);
462
463 if (psp != NULL) {
464 /* divined from tdfx_dri.c, sketchy */
465 TDFXDRIPtr dri_priv = (TDFXDRIPtr) psp->pDevPriv;
466 int bpp = (dri_priv->cpp > 2) ? 24 : 16;
467
468 /* XXX i wish it was like this */
469 /* bpp = dri_priv->bpp */
470
471 *driver_modes = tdfxFillInModes(bpp, (bpp == 16) ? 16 : 24,
472 (bpp == 16) ? 0 : 8,
473 (dri_priv->backOffset!=dri_priv->depthOffset));
474
475 /* Calling driInitExtensions here, with a NULL context pointer, does not actually
476 * enable the extensions. It just makes sure that all the dispatch offsets for all
477 * the extensions that *might* be enables are known. This is needed because the
478 * dispatch offsets need to be known when _mesa_context_create is called, but we can't
479 * enable the extensions until we have a context pointer.
480 *
481 * Hello chicken. Hello egg. How are you two today?
482 */
483 driInitExtensions( NULL, card_extensions, GL_FALSE );
484 driInitExtensions( NULL, napalm_extensions, GL_FALSE );
485 }
486
487 return (void *)psp;
488 }