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