OSDN Git Service

084560ff87dfb1387df464ad6e9c37cd5dd918f0
[android-x86/external-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 struct gl_config *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((struct gl_framebuffer **)(&(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    struct gl_framebuffer *mesaBuffer;
241
242    if ( TDFX_DEBUG & DEBUG_VERBOSE_DRI ) {
243       fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *)driDrawPriv );
244    }
245
246    mesaBuffer = (struct gl_framebuffer *) 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    assert(fxMesa);
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(__DRIscreen *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                             GL_TRUE);
390 }
391
392 /**
393  * This is the driver specific part of the createNewScreen entry point.
394  * 
395  * \todo maybe fold this into intelInitDriver
396  *
397  * \return the struct gl_config supported by this driver
398  */
399 static const __DRIconfig **
400 tdfxInitScreen(__DRIscreen *psp)
401 {
402    static const __DRIversion ddx_expected = { 1, 1, 0 };
403    static const __DRIversion dri_expected = { 4, 0, 0 };
404    static const __DRIversion drm_expected = { 1, 0, 0 };
405
406    /* divined from tdfx_dri.c, sketchy */
407    TDFXDRIPtr dri_priv = (TDFXDRIPtr) psp->pDevPriv;
408
409    /* XXX i wish it was like this */
410    /* bpp = dri_priv->bpp */
411    int bpp = (dri_priv->cpp > 2) ? 24 : 16;
412
413    if ( ! driCheckDriDdxDrmVersions2( "tdfx",
414                                       &psp->dri_version, & dri_expected,
415                                       &psp->ddx_version, & ddx_expected,
416                                       &psp->drm_version, & drm_expected ) )
417       return NULL;
418
419    if (!tdfxInitDriver(psp))
420       return NULL;
421       
422    return tdfxFillInModes(psp,
423                           bpp, (bpp == 16) ? 16 : 24,
424                           (bpp == 16) ? 0 : 8,
425                           (dri_priv->backOffset!=dri_priv->depthOffset));
426 }
427
428 const struct __DriverAPIRec driDriverAPI = {
429    .InitScreen      = tdfxInitScreen,
430    .DestroyScreen   = tdfxDestroyScreen,
431    .CreateContext   = tdfxCreateContext,
432    .DestroyContext  = tdfxDestroyContext,
433    .CreateBuffer    = tdfxCreateBuffer,
434    .DestroyBuffer   = tdfxDestroyBuffer,
435    .SwapBuffers     = tdfxSwapBuffers,
436    .MakeCurrent     = tdfxMakeCurrent,
437    .UnbindContext   = tdfxUnbindContext,
438    .GetSwapInfo     = NULL,
439    .GetDrawableMSC  = NULL,
440    .WaitForMSC      = NULL,
441    .WaitForSBC      = NULL,
442    .SwapBuffersMSC  = NULL
443 };
444
445 /* This is the table of extensions that the loader will dlsym() for. */
446 PUBLIC const __DRIextension *__driDriverExtensions[] = {
447     &driCoreExtension.base,
448     &driLegacyExtension.base,
449     NULL
450 };