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