7896811d997cc4e10c6c3a50d6300d7cb833426c
[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_tris.h"
42 #include "utils.h"
43
44
45 #ifdef DEBUG_LOCKING
46 char *prevLockFile = 0;
47 int prevLockLine = 0;
48 #endif
49
50 #ifndef TDFX_DEBUG
51 int TDFX_DEBUG = (0
52 /* | DEBUG_ALWAYS_SYNC */
53 /* | DEBUG_VERBOSE_API */
54 /* | DEBUG_VERBOSE_MSG */
55 /* | DEBUG_VERBOSE_LRU */
56 /* | DEBUG_VERBOSE_DRI */
57 /* | DEBUG_VERBOSE_IOCTL */
58 /* | DEBUG_VERBOSE_2D */
59 );
60 #endif
61
62
63
64 static GLboolean
65 tdfxCreateScreen( __DRIscreenPrivate *sPriv )
66 {
67 tdfxScreenPrivate *fxScreen;
68 TDFXDRIPtr fxDRIPriv = (TDFXDRIPtr) sPriv->pDevPriv;
69
70 /* Allocate the private area */
71 fxScreen = (tdfxScreenPrivate *) CALLOC( sizeof(tdfxScreenPrivate) );
72 if ( !fxScreen )
73 return GL_FALSE;
74
75 fxScreen->driScrnPriv = sPriv;
76 sPriv->private = (void *) fxScreen;
77
78 fxScreen->regs.handle = fxDRIPriv->regs;
79 fxScreen->regs.size = fxDRIPriv->regsSize;
80 fxScreen->deviceID = fxDRIPriv->deviceID;
81 fxScreen->width = fxDRIPriv->width;
82 fxScreen->height = fxDRIPriv->height;
83 fxScreen->mem = fxDRIPriv->mem;
84 fxScreen->cpp = fxDRIPriv->cpp;
85 fxScreen->stride = fxDRIPriv->stride;
86 fxScreen->fifoOffset = fxDRIPriv->fifoOffset;
87 fxScreen->fifoSize = fxDRIPriv->fifoSize;
88 fxScreen->fbOffset = fxDRIPriv->fbOffset;
89 fxScreen->backOffset = fxDRIPriv->backOffset;
90 fxScreen->depthOffset = fxDRIPriv->depthOffset;
91 fxScreen->textureOffset = fxDRIPriv->textureOffset;
92 fxScreen->textureSize = fxDRIPriv->textureSize;
93 fxScreen->sarea_priv_offset = fxDRIPriv->sarea_priv_offset;
94
95 if ( drmMap( sPriv->fd, fxScreen->regs.handle,
96 fxScreen->regs.size, &fxScreen->regs.map ) ) {
97 return GL_FALSE;
98 }
99
100 return GL_TRUE;
101 }
102
103
104 static void
105 tdfxDestroyScreen( __DRIscreenPrivate *sPriv )
106 {
107 tdfxScreenPrivate *fxScreen = (tdfxScreenPrivate *) sPriv->private;
108
109 if ( fxScreen ) {
110 drmUnmap( fxScreen->regs.map, fxScreen->regs.size );
111
112 FREE( fxScreen );
113 sPriv->private = NULL;
114 }
115 }
116
117
118 static GLboolean
119 tdfxInitDriver( __DRIscreenPrivate *sPriv )
120 {
121 if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
122 fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *)sPriv );
123 }
124
125 if ( !tdfxCreateScreen( sPriv ) ) {
126 tdfxDestroyScreen( sPriv );
127 return GL_FALSE;
128 }
129
130 return GL_TRUE;
131 }
132
133
134 static GLboolean
135 tdfxCreateBuffer( __DRIscreenPrivate *driScrnPriv,
136 __DRIdrawablePrivate *driDrawPriv,
137 const __GLcontextModes *mesaVis,
138 GLboolean isPixmap )
139 {
140 if (isPixmap) {
141 return GL_FALSE; /* not implemented */
142 }
143 else {
144 driDrawPriv->driverPrivate = (void *)
145 _mesa_create_framebuffer( mesaVis,
146 GL_FALSE, /* software depth buffer? */
147 mesaVis->stencilBits > 0,
148 mesaVis->accumRedBits > 0,
149 GL_FALSE /* software alpha channel? */ );
150 return (driDrawPriv->driverPrivate != NULL);
151 }
152 }
153
154
155 static void
156 tdfxDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
157 {
158 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
159 }
160
161
162 static void
163 tdfxSwapBuffers( __DRIdrawablePrivate *driDrawPriv )
164
165 {
166 GET_CURRENT_CONTEXT(ctx);
167 tdfxContextPtr fxMesa = 0;
168 GLframebuffer *mesaBuffer;
169
170 if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
171 fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *)driDrawPriv );
172 }
173
174 mesaBuffer = (GLframebuffer *) driDrawPriv->driverPrivate;
175 if ( !mesaBuffer->Visual.doubleBufferMode )
176 return; /* can't swap a single-buffered window */
177
178 /* If the current context's drawable matches the given drawable
179 * we have to do a glFinish (per the GLX spec).
180 */
181 if ( ctx ) {
182 __DRIdrawablePrivate *curDrawPriv;
183 fxMesa = TDFX_CONTEXT(ctx);
184 curDrawPriv = fxMesa->driContext->driDrawablePriv;
185
186 if ( curDrawPriv == driDrawPriv ) {
187 /* swapping window bound to current context, flush first */
188 _mesa_notifySwapBuffers( ctx );
189 LOCK_HARDWARE( fxMesa );
190 }
191 else {
192 /* find the fxMesa context previously bound to the window */
193 fxMesa = (tdfxContextPtr) driDrawPriv->driContextPriv->driverPrivate;
194 if (!fxMesa)
195 return;
196 LOCK_HARDWARE( fxMesa );
197 fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
198 printf("SwapBuf SetState 1\n");
199 fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
200 }
201 }
202
203 #ifdef STATS
204 {
205 int stalls;
206 static int prevStalls = 0;
207
208 stalls = fxMesa->Glide.grFifoGetStalls();
209
210 fprintf( stderr, "%s:\n", __FUNCTION__ );
211 if ( stalls != prevStalls ) {
212 fprintf( stderr, " %d stalls occurred\n",
213 stalls - prevStalls );
214 prevStalls = stalls;
215 }
216 if ( fxMesa && fxMesa->texSwaps ) {
217 fprintf( stderr, " %d texture swaps occurred\n",
218 fxMesa->texSwaps );
219 fxMesa->texSwaps = 0;
220 }
221 }
222 #endif
223
224 if (fxMesa->scissoredClipRects) {
225 /* restore clip rects without scissor box */
226 fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
227 driDrawPriv->w, driDrawPriv->h,
228 driDrawPriv->numClipRects,
229 driDrawPriv->pClipRects );
230 }
231
232 fxMesa->Glide.grDRIBufferSwap( fxMesa->Glide.SwapInterval );
233
234 if (fxMesa->scissoredClipRects) {
235 /* restore clip rects WITH scissor box */
236 fxMesa->Glide.grDRIPosition( driDrawPriv->x, driDrawPriv->y,
237 driDrawPriv->w, driDrawPriv->h,
238 fxMesa->numClipRects, fxMesa->pClipRects );
239 }
240
241
242 #if 0
243 {
244 FxI32 result;
245 do {
246 FxI32 result;
247 fxMesa->Glide.grGet(GR_PENDING_BUFFERSWAPS, 4, &result);
248 } while ( result > fxMesa->maxPendingSwapBuffers );
249 }
250 #endif
251
252 fxMesa->stats.swapBuffer++;
253
254 if (ctx) {
255 if (ctx->DriverCtx != fxMesa) {
256 fxMesa = TDFX_CONTEXT(ctx);
257 fxMesa->Glide.grSstSelect( fxMesa->Glide.Board );
258 printf("SwapBuf SetState 2\n");
259 fxMesa->Glide.grGlideSetState(fxMesa->Glide.State );
260 }
261 UNLOCK_HARDWARE( fxMesa );
262 }
263 }
264
265
266 static const struct __DriverAPIRec tdfxAPI = {
267 .InitDriver = tdfxInitDriver,
268 .DestroyScreen = tdfxDestroyScreen,
269 .CreateContext = tdfxCreateContext,
270 .DestroyContext = tdfxDestroyContext,
271 .CreateBuffer = tdfxCreateBuffer,
272 .DestroyBuffer = tdfxDestroyBuffer,
273 .SwapBuffers = tdfxSwapBuffers,
274 .MakeCurrent = tdfxMakeCurrent,
275 .UnbindContext = tdfxUnbindContext,
276 .GetSwapInfo = NULL,
277 .GetMSC = NULL,
278 .WaitForMSC = NULL,
279 .WaitForSBC = NULL,
280 .SwapBuffersMSC = NULL
281 };
282
283 #ifdef USE_NEW_INTERFACE
284 /*
285 * new interface code, derived from radeon_screen.c
286 * XXX this may still be wrong
287 */
288 static PFNGLXCREATECONTEXTMODES create_context_modes = NULL;
289
290 static __GLcontextModes *tdfxFillInModes(unsigned pixel_bits,
291 unsigned depth_bits,
292 unsigned stencil_bits,
293 GLboolean have_back_buffer)
294 {
295 __GLcontextModes *modes;
296 __GLcontextModes *m;
297 unsigned num_modes;
298 unsigned vis[2] = { GLX_TRUE_COLOR, GLX_DIRECT_COLOR };
299 unsigned deep = (depth_bits > 17);
300 unsigned i, db, depth, accum, stencil;
301
302 /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
303 * enough to add support. Basically, if a context is created with an
304 * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
305 * will never be used.
306 */
307
308 num_modes = (depth_bits == 16) ? 32 : 16;
309
310 modes = (*create_context_modes)(num_modes, sizeof(__GLcontextModes));
311 m = modes;
312
313 for (i = 0; i <= 1; i++) {
314 for (db = 0; db <= 1; db++) {
315 for (depth = 0; depth <= 1; depth++) {
316 for (accum = 0; accum <= 1; accum++) {
317 for (stencil = 0; stencil <= !deep; stencil++) {
318 if (deep) stencil = depth;
319 m->redBits = deep ? 8 : 5;
320 m->greenBits = deep ? 8 : 6;
321 m->blueBits = deep ? 8 : 5;
322 m->alphaBits = deep ? 8 : 0;
323 m->redMask = deep ?0xFF000000 :0x0000F800;
324 m->greenMask = deep ?0x00FF0000 :0x000007E0;
325 m->blueMask = deep ?0x0000FF00 :0x0000001F;
326 m->alphaMask = deep ? 0x000000FF : 0;
327 m->rgbBits = m->redBits + m->greenBits +
328 m->blueBits + m->alphaBits;
329 m->accumRedBits = accum ? 16 : 0;
330 m->accumGreenBits = accum ? 16 : 0;
331 m->accumBlueBits = accum ? 16 : 0;
332 m->accumAlphaBits = accum ? 16 : 0;
333 m->stencilBits = stencil ? 8 : 0;
334 m->depthBits = deep
335 ? (depth ? 24 : 0)
336 : (depth ? 0 : depth_bits);
337 m->visualType = vis[i];
338 m->renderType = GLX_RGBA_BIT;
339 m->drawableType = GLX_WINDOW_BIT;
340 m->rgbMode = GL_TRUE;
341 m->doubleBufferMode = db ? GL_TRUE : GL_FALSE;
342 if (db)
343 m->swapMethod = GLX_SWAP_UNDEFINED_OML;
344 m->visualRating = ((stencil && !deep) || accum)
345 ? GLX_SLOW_CONFIG
346 : GLX_NONE;
347 m = m->next;
348 if (deep) stencil = 0;
349 }
350 }
351 }
352 }
353 }
354
355 return modes;
356 }
357
358 /**
359 * This is the bootstrap function for the driver. libGL supplies all of the
360 * requisite information about the system, and the driver initializes itself.
361 * This routine also fills in the linked list pointed to by \c driver_modes
362 * with the \c __GLcontextModes that the driver can support for windows or
363 * pbuffers.
364 *
365 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
366 * failure.
367 */
368 PUBLIC
369 void * __driCreateNewScreen( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
370 const __GLcontextModes * modes,
371 const __DRIversion * ddx_version,
372 const __DRIversion * dri_version,
373 const __DRIversion * drm_version,
374 const __DRIframebuffer * frame_buffer,
375 drmAddress pSAREA, int fd,
376 int internal_api_version,
377 __GLcontextModes ** driver_modes )
378 {
379 __DRIscreenPrivate *psp;
380 static const __DRIversion ddx_expected = { 1, 0, 0 };
381 static const __DRIversion dri_expected = { 4, 0, 0 };
382 static const __DRIversion drm_expected = { 1, 0, 0 };
383
384 if ( ! driCheckDriDdxDrmVersions2( "tdfx",
385 dri_version, & dri_expected,
386 ddx_version, & ddx_expected,
387 drm_version, & drm_expected ) ) {
388 return NULL;
389 }
390
391 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
392 ddx_version, dri_version, drm_version,
393 frame_buffer, pSAREA, fd,
394 internal_api_version, &tdfxAPI);
395
396 create_context_modes = (PFNGLXCREATECONTEXTMODES)
397 glXGetProcAddress((const GLubyte *)"__glXCreateContextModes");
398
399 if (create_context_modes != NULL) {
400 /* divined from tdfx_dri.c, sketchy */
401 TDFXDRIPtr dri_priv = (TDFXDRIPtr) psp->pDevPriv;
402 int bpp = (dri_priv->cpp > 2) ? 24 : 16;
403
404 /* XXX i wish it was like this */
405 /* bpp = dri_priv->bpp */
406
407 *driver_modes = tdfxFillInModes(bpp, (bpp == 16) ? 16 : 24,
408 (bpp == 16) ? 0 : 8,
409 (dri_priv->backOffset!=dri_priv->depthOffset));
410 }
411
412 return (void *)psp;
413 }
414 #endif /* USE_NEW_INTERFACE */
415
416
417 /*
418 * This is the bootstrap function for the driver.
419 * The __driCreateScreen name is the symbol that libGL.so fetches.
420 * Return: pointer to a __DRIscreenPrivate.
421 */
422 #if !defined(DRI_NEW_INTERFACE_ONLY)
423 void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
424 int numConfigs, __GLXvisualConfig *config)
425 {
426 __DRIscreenPrivate *psp;
427 psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &tdfxAPI);
428 return (void *) psp;
429 }
430 #endif /* !defined(DRI_NEW_INTERFACE_ONLY) */