Merge commit 'origin/gallium-0.1' into gallium-0.2
[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
27 /*
28 * Original rewrite:
29 * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
30 *
31 * Authors:
32 * Gareth Hughes <gareth@valinux.com>
33 *
34 */
35
36 #include "tdfx_dri.h"
37 #include "tdfx_context.h"
38 #include "tdfx_lock.h"
39 #include "tdfx_vb.h"
40 #include "tdfx_span.h"
41 #include "tdfx_tris.h"
42
43 #include "framebuffer.h"
44 #include "renderbuffer.h"
45 #include "xmlpool.h"
46
47 #include "utils.h"
48
49 #ifdef DEBUG_LOCKING
50 char *prevLockFile = 0;
51 int prevLockLine = 0;
52 #endif
53
54 #ifndef TDFX_DEBUG
55 int TDFX_DEBUG = 0;
56 #endif
57
58 PUBLIC const char __driConfigOptions[] =
59 DRI_CONF_BEGIN
60 DRI_CONF_SECTION_DEBUG
61 DRI_CONF_NO_RAST(false)
62 DRI_CONF_SECTION_END
63 DRI_CONF_END;
64
65 static const __DRIextension *tdfxExtensions[] = {
66 &driReadDrawableExtension,
67 };
68
69 static const GLuint __driNConfigOptions = 1;
70
71 extern const struct dri_extension card_extensions[];
72 extern const struct dri_extension napalm_extensions[];
73
74 static GLboolean
75 tdfxCreateScreen( __DRIscreenPrivate *sPriv )
76 {
77 tdfxScreenPrivate *fxScreen;
78 TDFXDRIPtr fxDRIPriv = (TDFXDRIPtr) sPriv->pDevPriv;
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 sPriv->extensions = tdfxExtensions;
120
121 return GL_TRUE;
122 }
123
124
125 static void
126 tdfxDestroyScreen( __DRIscreenPrivate *sPriv )
127 {
128 tdfxScreenPrivate *fxScreen = (tdfxScreenPrivate *) sPriv->private;
129
130 if (!fxScreen)
131 return;
132
133 drmUnmap( fxScreen->regs.map, fxScreen->regs.size );
134
135 /* free all option information */
136 driDestroyOptionInfo (&fxScreen->optionCache);
137
138 FREE( fxScreen );
139 sPriv->private = NULL;
140 }
141
142
143 static GLboolean
144 tdfxInitDriver( __DRIscreenPrivate *sPriv )
145 {
146 if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
147 fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *)sPriv );
148 }
149
150 if ( !tdfxCreateScreen( sPriv ) ) {
151 tdfxDestroyScreen( sPriv );
152 return GL_FALSE;
153 }
154
155 return GL_TRUE;
156 }
157
158
159 static GLboolean
160 tdfxCreateBuffer( __DRIscreenPrivate *driScrnPriv,
161 __DRIdrawablePrivate *driDrawPriv,
162 const __GLcontextModes *mesaVis,
163 GLboolean isPixmap )
164 {
165 tdfxScreenPrivate *screen = (tdfxScreenPrivate *) driScrnPriv->private;
166
167 if (isPixmap) {
168 return GL_FALSE; /* not implemented */
169 }
170 else {
171 struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
172
173 {
174 driRenderbuffer *frontRb
175 = driNewRenderbuffer(GL_RGBA, NULL, screen->cpp,
176 screen->fbOffset, screen->width, driDrawPriv);
177 tdfxSetSpanFunctions(frontRb, mesaVis);
178 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base);
179 }
180
181 if (mesaVis->doubleBufferMode) {
182 driRenderbuffer *backRb
183 = driNewRenderbuffer(GL_RGBA, NULL, screen->cpp,
184 screen->backOffset, screen->width,
185 driDrawPriv);
186 tdfxSetSpanFunctions(backRb, mesaVis);
187 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base);
188 backRb->backBuffer = GL_TRUE;
189 }
190
191 if (mesaVis->depthBits == 16) {
192 driRenderbuffer *depthRb
193 = driNewRenderbuffer(GL_DEPTH_COMPONENT16, NULL, screen->cpp,
194 screen->depthOffset, screen->width,
195 driDrawPriv);
196 tdfxSetSpanFunctions(depthRb, mesaVis);
197 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
198 }
199 else if (mesaVis->depthBits == 24) {
200 driRenderbuffer *depthRb
201 = driNewRenderbuffer(GL_DEPTH_COMPONENT24, NULL, screen->cpp,
202 screen->depthOffset, screen->width,
203 driDrawPriv);
204 tdfxSetSpanFunctions(depthRb, mesaVis);
205 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
206 }
207
208 if (mesaVis->stencilBits > 0) {
209 driRenderbuffer *stencilRb
210 = driNewRenderbuffer(GL_STENCIL_INDEX8_EXT, NULL, screen->cpp,
211 screen->depthOffset, screen->width,
212 driDrawPriv);
213 tdfxSetSpanFunctions(stencilRb, mesaVis);
214 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &stencilRb->Base);
215 }
216
217 _mesa_add_soft_renderbuffers(fb,
218 GL_FALSE, /* color */
219 GL_FALSE, /* depth */
220 GL_FALSE, /*swStencil,*/
221 mesaVis->accumRedBits > 0,
222 GL_FALSE, /* alpha */
223 GL_FALSE /* aux */);
224 driDrawPriv->driverPrivate = (void *) fb;
225
226 return (driDrawPriv->driverPrivate != NULL);
227 }
228 }
229
230
231 static void
232 tdfxDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
233 {
234 _mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate)));
235 }
236
237
238 static void
239 tdfxSwapBuffers( __DRIdrawablePrivate *driDrawPriv )
240
241 {
242 GET_CURRENT_CONTEXT(ctx);
243 tdfxContextPtr fxMesa = 0;
244 GLframebuffer *mesaBuffer;
245
246 if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
247 fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *)driDrawPriv );
248 }
249
250 mesaBuffer = (GLframebuffer *) driDrawPriv->driverPrivate;
251 if ( !mesaBuffer->Visual.doubleBufferMode )
252 return; /* can't swap a single-buffered window */
253
254 /* If the current context's drawable matches the given drawable
255 * we have to do a glFinish (per the GLX spec).
256 */
257 if ( ctx ) {
258 __DRIdrawablePrivate *curDrawPriv;
259 fxMesa = TDFX_CONTEXT(ctx);
260 curDrawPriv = fxMesa->driContext->driDrawablePriv;
261
262 if ( curDrawPriv == driDrawPriv ) {
263 /* swapping window bound to current context, flush first */
264 _mesa_notifySwapBuffers( ctx );
265 LOCK_HARDWARE( fxMesa );
266 }
267 else {
268 /* find the fxMesa context previously bound to the window */
269 fxMesa = (tdfxContextPtr) driDrawPriv->driContextPriv->driverPrivate;
270 if (!fxMesa)
271 return;
272 LOCK_HARDWARE( fxMesa );
273 fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
274 #ifdef DEBUG
275 printf("SwapBuf SetState 1\n");
276 #endif
277 fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
278 }
279 }
280
281 #ifdef STATS
282 {
283 int stalls;
284 static int prevStalls = 0;
285
286 stalls = fxMesa->Glide.grFifoGetStalls();
287
288 fprintf( stderr, "%s:\n", __FUNCTION__ );
289 if ( stalls != prevStalls ) {
290 fprintf( stderr, " %d stalls occurred\n",
291 stalls - prevStalls );
292 prevStalls = stalls;
293 }
294 if ( fxMesa && fxMesa->texSwaps ) {
295 fprintf( stderr, " %d texture swaps occurred\n",
296 fxMesa->texSwaps );
297 fxMesa->texSwaps = 0;
298 }
299 }
300 #endif
301
302 if (fxMesa->scissoredClipRects) {
303 /* restore clip rects without scissor box */
304 fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
305 driDrawPriv->w, driDrawPriv->h,
306 driDrawPriv->numClipRects,
307 driDrawPriv->pClipRects );
308 }
309
310 fxMesa->Glide.grDRIBufferSwap( fxMesa->Glide.SwapInterval );
311
312 if (fxMesa->scissoredClipRects) {
313 /* restore clip rects WITH scissor box */
314 fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
315 driDrawPriv->w, driDrawPriv->h,
316 fxMesa->numClipRects, fxMesa->pClipRects );
317 }
318
319
320 #if 0
321 {
322 FxI32 result;
323 do {
324 FxI32 result;
325 fxMesa->Glide.grGet(GR_PENDING_BUFFERSWAPS, 4, &result);
326 } while ( result > fxMesa->maxPendingSwapBuffers );
327 }
328 #endif
329
330 fxMesa->stats.swapBuffer++;
331
332 if (ctx) {
333 if (ctx->DriverCtx != fxMesa) {
334 fxMesa = TDFX_CONTEXT(ctx);
335 fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
336 #ifdef DEBUG
337 printf("SwapBuf SetState 2\n");
338 #endif
339 fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
340 }
341 UNLOCK_HARDWARE( fxMesa );
342 }
343 }
344
345 static const __DRIconfig **
346 tdfxFillInModes(__DRIscreenPrivate *psp,
347 unsigned pixel_bits,
348 unsigned depth_bits,
349 unsigned stencil_bits,
350 GLboolean have_back_buffer)
351 {
352 __DRIconfig **configs, **c;
353 __GLcontextModes *m;
354 unsigned num_modes;
355 unsigned vis[2] = { GLX_TRUE_COLOR, GLX_DIRECT_COLOR };
356 unsigned deep = (depth_bits > 17);
357 unsigned i, db, depth, accum, stencil;
358
359 /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
360 * enough to add support. Basically, if a context is created with an
361 * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
362 * will never be used.
363 */
364
365 num_modes = (depth_bits == 16) ? 32 : 16;
366
367 configs = _mesa_malloc(num_modes * sizeof *configs);
368 c = configs;
369
370 for (i = 0; i <= 1; i++) {
371 for (db = 0; db <= 1; db++) {
372 for (depth = 0; depth <= 1; depth++) {
373 for (accum = 0; accum <= 1; accum++) {
374 for (stencil = 0; stencil <= !deep; stencil++) {
375 *c = _mesa_malloc(sizeof **c);
376 m = &(*c++)->modes;
377 if (deep) stencil = depth;
378 m->redBits = deep ? 8 : 5;
379 m->greenBits = deep ? 8 : 6;
380 m->blueBits = deep ? 8 : 5;
381 m->alphaBits = deep ? 8 : 0;
382 m->redMask = deep ?0xFF000000 :0x0000F800;
383 m->greenMask = deep ?0x00FF0000 :0x000007E0;
384 m->blueMask = deep ?0x0000FF00 :0x0000001F;
385 m->alphaMask = deep ? 0x000000FF : 0;
386 m->rgbBits = m->redBits + m->greenBits +
387 m->blueBits + m->alphaBits;
388 m->accumRedBits = accum ? 16 : 0;
389 m->accumGreenBits = accum ? 16 : 0;
390 m->accumBlueBits = accum ? 16 : 0;
391 m->accumAlphaBits = (accum && deep) ? 16 : 0;
392 m->stencilBits = stencil ? 8 : 0;
393 m->depthBits = deep
394 ? (depth ? 24 : 0)
395 : (depth ? 0 : depth_bits);
396 m->visualType = vis[i];
397 m->renderType = GLX_RGBA_BIT;
398 m->drawableType = GLX_WINDOW_BIT;
399 m->rgbMode = GL_TRUE;
400 m->doubleBufferMode = db ? GL_TRUE : GL_FALSE;
401 if (db)
402 m->swapMethod = GLX_SWAP_UNDEFINED_OML;
403 m->visualRating = ((stencil && !deep) || accum)
404 ? GLX_SLOW_CONFIG
405 : GLX_NONE;
406 if (deep) stencil = 0;
407 }
408 }
409 }
410 }
411 }
412
413 return (const __DRIconfig **) configs;
414 }
415
416 /**
417 * This is the driver specific part of the createNewScreen entry point.
418 *
419 * \todo maybe fold this into intelInitDriver
420 *
421 * \return the __GLcontextModes supported by this driver
422 */
423 static const __DRIconfig **
424 tdfxInitScreen(__DRIscreen *psp)
425 {
426 static const __DRIversion ddx_expected = { 1, 1, 0 };
427 static const __DRIversion dri_expected = { 4, 0, 0 };
428 static const __DRIversion drm_expected = { 1, 0, 0 };
429
430 /* divined from tdfx_dri.c, sketchy */
431 TDFXDRIPtr dri_priv = (TDFXDRIPtr) psp->pDevPriv;
432
433 /* XXX i wish it was like this */
434 /* bpp = dri_priv->bpp */
435 int bpp = (dri_priv->cpp > 2) ? 24 : 16;
436
437 if ( ! driCheckDriDdxDrmVersions2( "tdfx",
438 &psp->dri_version, & dri_expected,
439 &psp->ddx_version, & ddx_expected,
440 &psp->drm_version, & drm_expected ) )
441 return NULL;
442
443 /* Calling driInitExtensions here, with a NULL context pointer,
444 * does not actually enable the extensions. It just makes sure
445 * that all the dispatch offsets for all the extensions that
446 * *might* be enables are known. This is needed because the
447 * dispatch offsets need to be known when _mesa_context_create is
448 * called, but we can't enable the extensions until we have a
449 * context pointer.
450 *
451 * Hello chicken. Hello egg. How are you two today?
452 */
453 driInitExtensions( NULL, card_extensions, GL_FALSE );
454 driInitExtensions( NULL, napalm_extensions, GL_FALSE );
455
456 if (!tdfxInitDriver(psp))
457 return NULL;
458
459 return tdfxFillInModes(psp,
460 bpp, (bpp == 16) ? 16 : 24,
461 (bpp == 16) ? 0 : 8,
462 (dri_priv->backOffset!=dri_priv->depthOffset));
463 }
464
465 const struct __DriverAPIRec driDriverAPI = {
466 .InitScreen = tdfxInitScreen,
467 .DestroyScreen = tdfxDestroyScreen,
468 .CreateContext = tdfxCreateContext,
469 .DestroyContext = tdfxDestroyContext,
470 .CreateBuffer = tdfxCreateBuffer,
471 .DestroyBuffer = tdfxDestroyBuffer,
472 .SwapBuffers = tdfxSwapBuffers,
473 .MakeCurrent = tdfxMakeCurrent,
474 .UnbindContext = tdfxUnbindContext,
475 .GetSwapInfo = NULL,
476 .GetDrawableMSC = NULL,
477 .WaitForMSC = NULL,
478 .WaitForSBC = NULL,
479 .SwapBuffersMSC = NULL
480 };