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