(Stephane Marchesin, me) add hyperz support to radeon and r200 drivers. Only fast...
[mesa.git] / src / mesa / drivers / dri / ffb / ffb_xmesa.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/ffb/ffb_xmesa.c,v 1.4 2002/02/22 21:32:59 dawes Exp $
2 *
3 * GLX Hardware Device Driver for Sun Creator/Creator3D
4 * Copyright (C) 2000, 2001 David S. Miller
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * DAVID MILLER, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
22 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 *
25 * David S. Miller <davem@redhat.com>
26 */
27
28 #ifdef GLX_DIRECT_RENDERING
29
30 #include "ffb_xmesa.h"
31 #include "context.h"
32 #include "matrix.h"
33 #include "simple_list.h"
34 #include "imports.h"
35
36 #include "swrast/swrast.h"
37 #include "swrast_setup/swrast_setup.h"
38 #include "tnl/tnl.h"
39 #include "tnl/t_pipeline.h"
40 #include "array_cache/acache.h"
41 #include "drivers/common/driverfuncs.h"
42
43 #include "ffb_context.h"
44 #include "ffb_dd.h"
45 #include "ffb_span.h"
46 #include "ffb_depth.h"
47 #include "ffb_stencil.h"
48 #include "ffb_clear.h"
49 #include "ffb_vb.h"
50 #include "ffb_tris.h"
51 #include "ffb_lines.h"
52 #include "ffb_points.h"
53 #include "ffb_state.h"
54 #include "ffb_tex.h"
55 #include "ffb_lock.h"
56 #include "ffb_vtxfmt.h"
57 #include "ffb_bitmap.h"
58
59 #include "drm_sarea.h"
60
61 static GLboolean
62 ffbInitDriver(__DRIscreenPrivate *sPriv)
63 {
64 ffbScreenPrivate *ffbScreen;
65 FFBDRIPtr gDRIPriv = (FFBDRIPtr) sPriv->pDevPriv;
66
67 if (getenv("LIBGL_FORCE_XSERVER"))
68 return GL_FALSE;
69
70 /* Allocate the private area. */
71 ffbScreen = (ffbScreenPrivate *) MALLOC(sizeof(ffbScreenPrivate));
72 if (!ffbScreen)
73 return GL_FALSE;
74
75 /* Map FBC registers. */
76 if (drmMap(sPriv->fd,
77 gDRIPriv->hFbcRegs,
78 gDRIPriv->sFbcRegs,
79 &gDRIPriv->mFbcRegs)) {
80 FREE(ffbScreen);
81 return GL_FALSE;
82 }
83 ffbScreen->regs = (ffb_fbcPtr) gDRIPriv->mFbcRegs;
84
85 /* Map ramdac registers. */
86 if (drmMap(sPriv->fd,
87 gDRIPriv->hDacRegs,
88 gDRIPriv->sDacRegs,
89 &gDRIPriv->mDacRegs)) {
90 drmUnmap(gDRIPriv->mFbcRegs, gDRIPriv->sFbcRegs);
91 FREE(ffbScreen);
92 return GL_FALSE;
93 }
94 ffbScreen->dac = (ffb_dacPtr) gDRIPriv->mDacRegs;
95
96 /* Map "Smart" framebuffer views. */
97 if (drmMap(sPriv->fd,
98 gDRIPriv->hSfb8r,
99 gDRIPriv->sSfb8r,
100 &gDRIPriv->mSfb8r)) {
101 drmUnmap(gDRIPriv->mFbcRegs, gDRIPriv->sFbcRegs);
102 drmUnmap(gDRIPriv->mDacRegs, gDRIPriv->sDacRegs);
103 FREE(ffbScreen);
104 return GL_FALSE;
105 }
106 ffbScreen->sfb8r = (volatile char *) gDRIPriv->mSfb8r;
107
108 if (drmMap(sPriv->fd,
109 gDRIPriv->hSfb32,
110 gDRIPriv->sSfb32,
111 &gDRIPriv->mSfb32)) {
112 drmUnmap(gDRIPriv->mFbcRegs, gDRIPriv->sFbcRegs);
113 drmUnmap(gDRIPriv->mDacRegs, gDRIPriv->sDacRegs);
114 drmUnmap(gDRIPriv->mSfb8r, gDRIPriv->sSfb8r);
115 FREE(ffbScreen);
116 return GL_FALSE;
117 }
118 ffbScreen->sfb32 = (volatile char *) gDRIPriv->mSfb32;
119
120 if (drmMap(sPriv->fd,
121 gDRIPriv->hSfb64,
122 gDRIPriv->sSfb64,
123 &gDRIPriv->mSfb64)) {
124 drmUnmap(gDRIPriv->mFbcRegs, gDRIPriv->sFbcRegs);
125 drmUnmap(gDRIPriv->mDacRegs, gDRIPriv->sDacRegs);
126 drmUnmap(gDRIPriv->mSfb8r, gDRIPriv->sSfb8r);
127 drmUnmap(gDRIPriv->mSfb32, gDRIPriv->sSfb32);
128 FREE(ffbScreen);
129 return GL_FALSE;
130 }
131 ffbScreen->sfb64 = (volatile char *) gDRIPriv->mSfb64;
132
133 ffbScreen->fifo_cache = 0;
134 ffbScreen->rp_active = 0;
135
136 ffbScreen->sPriv = sPriv;
137 sPriv->private = (void *) ffbScreen;
138
139 ffbDDLinefuncInit();
140 ffbDDPointfuncInit();
141
142 return GL_TRUE;
143 }
144
145
146 static void
147 ffbDestroyScreen(__DRIscreenPrivate *sPriv)
148 {
149 ffbScreenPrivate *ffbScreen = sPriv->private;
150 FFBDRIPtr gDRIPriv = (FFBDRIPtr) sPriv->pDevPriv;
151
152 drmUnmap(gDRIPriv->mFbcRegs, gDRIPriv->sFbcRegs);
153 drmUnmap(gDRIPriv->mDacRegs, gDRIPriv->sDacRegs);
154 drmUnmap(gDRIPriv->mSfb8r, gDRIPriv->sSfb8r);
155 drmUnmap(gDRIPriv->mSfb32, gDRIPriv->sSfb32);
156 drmUnmap(gDRIPriv->mSfb64, gDRIPriv->sSfb64);
157
158 FREE(ffbScreen);
159 }
160
161 static const struct tnl_pipeline_stage *ffb_pipeline[] = {
162 &_tnl_vertex_transform_stage,
163 &_tnl_normal_transform_stage,
164 &_tnl_lighting_stage,
165 /* REMOVE: fog coord stage */
166 &_tnl_texgen_stage,
167 &_tnl_texture_transform_stage,
168 /* REMOVE: point attenuation stage */
169 &_tnl_render_stage,
170 0,
171 };
172
173 /* Create and initialize the Mesa and driver specific context data */
174 static GLboolean
175 ffbCreateContext(const __GLcontextModes *mesaVis,
176 __DRIcontextPrivate *driContextPriv,
177 void *sharedContextPrivate)
178 {
179 ffbContextPtr fmesa;
180 GLcontext *ctx, *shareCtx;
181 __DRIscreenPrivate *sPriv;
182 ffbScreenPrivate *ffbScreen;
183 char *debug;
184 struct dd_function_table functions;
185
186 /* Allocate ffb context */
187 fmesa = (ffbContextPtr) CALLOC(sizeof(ffbContextRec));
188 if (!fmesa)
189 return GL_FALSE;
190
191 _mesa_init_driver_functions(&functions);
192
193 /* Allocate Mesa context */
194 if (sharedContextPrivate)
195 shareCtx = ((ffbContextPtr) sharedContextPrivate)->glCtx;
196 else
197 shareCtx = NULL;
198 fmesa->glCtx = _mesa_create_context(mesaVis, shareCtx,
199 &functions, fmesa);
200 if (!fmesa->glCtx) {
201 FREE(fmesa);
202 return GL_FALSE;
203 }
204 driContextPriv->driverPrivate = fmesa;
205 ctx = fmesa->glCtx;
206
207 sPriv = driContextPriv->driScreenPriv;
208 ffbScreen = (ffbScreenPrivate *) sPriv->private;
209
210 /* Dri stuff. */
211 fmesa->hHWContext = driContextPriv->hHWContext;
212 fmesa->driFd = sPriv->fd;
213 fmesa->driHwLock = &sPriv->pSAREA->lock;
214
215 fmesa->ffbScreen = ffbScreen;
216 fmesa->driScreen = sPriv;
217 fmesa->ffb_sarea = FFB_DRISHARE(sPriv->pSAREA);
218
219 /* Register and framebuffer hw pointers. */
220 fmesa->regs = ffbScreen->regs;
221 fmesa->sfb32 = ffbScreen->sfb32;
222
223 ffbDDInitContextHwState(ctx);
224
225 /* Default clear and depth colors. */
226 {
227 GLubyte r = (GLint) (ctx->Color.ClearColor[0] * 255.0F);
228 GLubyte g = (GLint) (ctx->Color.ClearColor[1] * 255.0F);
229 GLubyte b = (GLint) (ctx->Color.ClearColor[2] * 255.0F);
230
231 fmesa->clear_pixel = ((r << 0) |
232 (g << 8) |
233 (b << 16));
234 }
235 fmesa->clear_depth = Z_FROM_MESA(ctx->Depth.Clear * 4294967295.0f);
236 fmesa->clear_stencil = ctx->Stencil.Clear & 0xf;
237
238 /* No wide points. */
239 ctx->Const.MinPointSize = 1.0;
240 ctx->Const.MinPointSizeAA = 1.0;
241 ctx->Const.MaxPointSize = 1.0;
242 ctx->Const.MaxPointSizeAA = 1.0;
243
244 /* Disable wide lines as we can't antialias them correctly in
245 * hardware.
246 */
247 ctx->Const.MinLineWidth = 1.0;
248 ctx->Const.MinLineWidthAA = 1.0;
249 ctx->Const.MaxLineWidth = 1.0;
250 ctx->Const.MaxLineWidthAA = 1.0;
251 ctx->Const.LineWidthGranularity = 1.0;
252
253 /* Instead of having GCC emit these constants a zillion times
254 * everywhere in the driver, put them here.
255 */
256 fmesa->ffb_2_30_fixed_scale = __FFB_2_30_FIXED_SCALE;
257 fmesa->ffb_one_over_2_30_fixed_scale = (1.0 / __FFB_2_30_FIXED_SCALE);
258 fmesa->ffb_16_16_fixed_scale = __FFB_16_16_FIXED_SCALE;
259 fmesa->ffb_one_over_16_16_fixed_scale = (1.0 / __FFB_16_16_FIXED_SCALE);
260 fmesa->ffb_ubyte_color_scale = 255.0f;
261 fmesa->ffb_zero = 0.0f;
262
263 fmesa->debugFallbacks = GL_FALSE;
264 debug = getenv("LIBGL_DEBUG");
265 if (debug && strstr(debug, "fallbacks"))
266 fmesa->debugFallbacks = GL_TRUE;
267
268 /* Initialize the software rasterizer and helper modules. */
269 _swrast_CreateContext( ctx );
270 _ac_CreateContext( ctx );
271 _tnl_CreateContext( ctx );
272 _swsetup_CreateContext( ctx );
273
274 /* All of this need only be done once for a new context. */
275 /* XXX these should be moved right after the
276 * _mesa_init_driver_functions() call above.
277 */
278 ffbDDExtensionsInit(ctx);
279 ffbDDInitDriverFuncs(ctx);
280 ffbDDInitStateFuncs(ctx);
281 ffbDDInitSpanFuncs(ctx);
282 ffbDDInitDepthFuncs(ctx);
283 ffbDDInitStencilFuncs(ctx);
284 ffbDDInitRenderFuncs(ctx);
285 /*ffbDDInitTexFuncs(ctx); not needed */
286 ffbDDInitBitmapFuncs(ctx);
287 ffbInitVB(ctx);
288
289 #if 0
290 ffbInitTnlModule(ctx);
291 #endif
292
293 _tnl_destroy_pipeline(ctx);
294 _tnl_install_pipeline(ctx, ffb_pipeline);
295
296 return GL_TRUE;
297 }
298
299 static void
300 ffbDestroyContext(__DRIcontextPrivate *driContextPriv)
301 {
302 ffbContextPtr fmesa = (ffbContextPtr) driContextPriv->driverPrivate;
303
304 if (fmesa) {
305 ffbFreeVB(fmesa->glCtx);
306
307 _swsetup_DestroyContext( fmesa->glCtx );
308 _tnl_DestroyContext( fmesa->glCtx );
309 _ac_DestroyContext( fmesa->glCtx );
310 _swrast_DestroyContext( fmesa->glCtx );
311
312 /* free the Mesa context */
313 fmesa->glCtx->DriverCtx = NULL;
314 _mesa_destroy_context(fmesa->glCtx);
315
316 FREE(fmesa);
317 }
318 }
319
320 /* Create and initialize the Mesa and driver specific pixmap buffer data */
321 static GLboolean
322 ffbCreateBuffer(__DRIscreenPrivate *driScrnPriv,
323 __DRIdrawablePrivate *driDrawPriv,
324 const __GLcontextModes *mesaVis,
325 GLboolean isPixmap )
326 {
327 if (isPixmap) {
328 return GL_FALSE; /* not implemented */
329 }
330 else {
331 driDrawPriv->driverPrivate = (void *)
332 _mesa_create_framebuffer(mesaVis,
333 GL_FALSE, /* software depth buffer? */
334 mesaVis->stencilBits > 0,
335 mesaVis->accumRedBits > 0,
336 mesaVis->alphaBits > 0);
337 return (driDrawPriv->driverPrivate != NULL);
338 }
339 }
340
341
342 static void
343 ffbDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
344 {
345 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
346 }
347
348
349 #define USE_FAST_SWAP
350
351 static void
352 ffbSwapBuffers( __DRIdrawablePrivate *dPriv )
353 {
354 ffbContextPtr fmesa = (ffbContextPtr) dPriv->driContextPriv->driverPrivate;
355 unsigned int fbc, wid, wid_reg_val, dac_db_bit;
356 unsigned int shadow_dac_addr, active_dac_addr;
357 ffb_fbcPtr ffb;
358 ffb_dacPtr dac;
359
360 if (fmesa == NULL ||
361 fmesa->glCtx->Visual.doubleBufferMode == 0)
362 return;
363
364 /* Flush pending rendering commands */
365 _mesa_notifySwapBuffers(fmesa->glCtx);
366
367 ffb = fmesa->regs;
368 dac = fmesa->ffbScreen->dac;
369
370 fbc = fmesa->fbc;
371 wid = fmesa->wid;
372
373 /* Swap the buffer we render into and read pixels from. */
374 fmesa->back_buffer ^= 1;
375
376 /* If we are writing into both buffers, don't mess with
377 * the WB setting.
378 */
379 if ((fbc & FFB_FBC_WB_AB) != FFB_FBC_WB_AB) {
380 if ((fbc & FFB_FBC_WB_A) != 0)
381 fbc = (fbc & ~FFB_FBC_WB_A) | FFB_FBC_WB_B;
382 else
383 fbc = (fbc & ~FFB_FBC_WB_B) | FFB_FBC_WB_A;
384 }
385
386 /* But either way, we must flip the read buffer setting. */
387 if ((fbc & FFB_FBC_RB_A) != 0)
388 fbc = (fbc & ~FFB_FBC_RB_A) | FFB_FBC_RB_B;
389 else
390 fbc = (fbc & ~FFB_FBC_RB_B) | FFB_FBC_RB_A;
391
392 LOCK_HARDWARE(fmesa);
393
394 if (fmesa->fbc != fbc) {
395 FFBFifo(fmesa, 1);
396 ffb->fbc = fmesa->fbc = fbc;
397 fmesa->ffbScreen->rp_active = 1;
398 }
399
400 /* And swap the buffer displayed in the WID. */
401 if (fmesa->ffb_sarea->flags & FFB_DRI_PAC1) {
402 shadow_dac_addr = FFBDAC_PAC1_SPWLUT(wid);
403 active_dac_addr = FFBDAC_PAC1_APWLUT(wid);
404 dac_db_bit = FFBDAC_PAC1_WLUT_DB;
405 } else {
406 shadow_dac_addr = FFBDAC_PAC2_SPWLUT(wid);
407 active_dac_addr = FFBDAC_PAC2_APWLUT(wid);
408 dac_db_bit = FFBDAC_PAC2_WLUT_DB;
409 }
410
411 FFBWait(fmesa, ffb);
412
413 wid_reg_val = DACCFG_READ(dac, active_dac_addr);
414 if (fmesa->back_buffer == 0)
415 wid_reg_val |= dac_db_bit;
416 else
417 wid_reg_val &= ~dac_db_bit;
418 #ifdef USE_FAST_SWAP
419 DACCFG_WRITE(dac, active_dac_addr, wid_reg_val);
420 #else
421 DACCFG_WRITE(dac, shadow_dac_addr, wid_reg_val);
422
423 /* Schedule the window transfer. */
424 DACCFG_WRITE(dac, FFBDAC_CFG_WTCTRL,
425 (FFBDAC_CFG_WTCTRL_TCMD | FFBDAC_CFG_WTCTRL_TE));
426
427 {
428 int limit = 1000000;
429 while (limit--) {
430 unsigned int wtctrl = DACCFG_READ(dac, FFBDAC_CFG_WTCTRL);
431
432 if ((wtctrl & FFBDAC_CFG_WTCTRL_DS) == 0)
433 break;
434 }
435 }
436 #endif
437
438 UNLOCK_HARDWARE(fmesa);
439 }
440
441 static void ffb_init_wid(ffbContextPtr fmesa, unsigned int wid)
442 {
443 ffb_dacPtr dac = fmesa->ffbScreen->dac;
444 unsigned int wid_reg_val, dac_db_bit, active_dac_addr;
445 unsigned int shadow_dac_addr;
446
447 if (fmesa->ffb_sarea->flags & FFB_DRI_PAC1) {
448 shadow_dac_addr = FFBDAC_PAC1_SPWLUT(wid);
449 active_dac_addr = FFBDAC_PAC1_APWLUT(wid);
450 dac_db_bit = FFBDAC_PAC1_WLUT_DB;
451 } else {
452 shadow_dac_addr = FFBDAC_PAC2_SPWLUT(wid);
453 active_dac_addr = FFBDAC_PAC2_APWLUT(wid);
454 dac_db_bit = FFBDAC_PAC2_WLUT_DB;
455 }
456
457 wid_reg_val = DACCFG_READ(dac, active_dac_addr);
458 wid_reg_val &= ~dac_db_bit;
459 #ifdef USE_FAST_SWAP
460 DACCFG_WRITE(dac, active_dac_addr, wid_reg_val);
461 #else
462 DACCFG_WRITE(dac, shadow_dac_addr, wid_reg_val);
463
464 /* Schedule the window transfer. */
465 DACCFG_WRITE(dac, FFBDAC_CFG_WTCTRL,
466 (FFBDAC_CFG_WTCTRL_TCMD | FFBDAC_CFG_WTCTRL_TE));
467
468 {
469 int limit = 1000000;
470 while (limit--) {
471 unsigned int wtctrl = DACCFG_READ(dac, FFBDAC_CFG_WTCTRL);
472
473 if ((wtctrl & FFBDAC_CFG_WTCTRL_DS) == 0)
474 break;
475 }
476 }
477 #endif
478 }
479
480 /* Force the context `c' to be the current context and associate with it
481 buffer `b' */
482 static GLboolean
483 ffbMakeCurrent(__DRIcontextPrivate *driContextPriv,
484 __DRIdrawablePrivate *driDrawPriv,
485 __DRIdrawablePrivate *driReadPriv)
486 {
487 if (driContextPriv) {
488 ffbContextPtr fmesa = (ffbContextPtr) driContextPriv->driverPrivate;
489 int first_time;
490
491 fmesa->driDrawable = driDrawPriv;
492
493 _mesa_make_current2(fmesa->glCtx,
494 (GLframebuffer *) driDrawPriv->driverPrivate,
495 (GLframebuffer *) driReadPriv->driverPrivate);
496
497 first_time = 0;
498 if (fmesa->wid == ~0) {
499 first_time = 1;
500 if (getenv("LIBGL_SOFTWARE_RENDERING"))
501 FALLBACK( fmesa->glCtx, FFB_BADATTR_SWONLY, GL_TRUE );
502 }
503
504 LOCK_HARDWARE(fmesa);
505 if (first_time) {
506 fmesa->wid = fmesa->ffb_sarea->wid_table[driDrawPriv->index];
507 ffb_init_wid(fmesa, fmesa->wid);
508 }
509
510 fmesa->state_dirty |= FFB_STATE_ALL;
511 fmesa->state_fifo_ents = fmesa->state_all_fifo_ents;
512 ffbSyncHardware(fmesa);
513 UNLOCK_HARDWARE(fmesa);
514
515 if (first_time) {
516 /* Also, at the first switch to a new context,
517 * we need to clear all the hw buffers.
518 */
519 ffbDDClear(fmesa->glCtx,
520 (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT |
521 DD_DEPTH_BIT | DD_STENCIL_BIT),
522 1, 0, 0, 0, 0);
523 }
524 } else {
525 _mesa_make_current(NULL, NULL);
526 }
527
528 return GL_TRUE;
529 }
530
531 /* Force the context `c' to be unbound from its buffer */
532 static GLboolean
533 ffbUnbindContext(__DRIcontextPrivate *driContextPriv)
534 {
535 return GL_TRUE;
536 }
537
538 void ffbXMesaUpdateState(ffbContextPtr fmesa)
539 {
540 __DRIdrawablePrivate *dPriv = fmesa->driDrawable;
541 __DRIscreenPrivate *sPriv = fmesa->driScreen;
542 int stamp = dPriv->lastStamp;
543
544 DRI_VALIDATE_DRAWABLE_INFO(sPriv, dPriv);
545
546 if (dPriv->lastStamp != stamp) {
547 GLcontext *ctx = fmesa->glCtx;
548
549 ffbCalcViewport(ctx);
550 if (ctx->Polygon.StippleFlag)
551 ffbXformAreaPattern(fmesa,
552 (const GLubyte *)ctx->PolygonStipple);
553 }
554 }
555
556
557 static struct __DriverAPIRec ffbAPI = {
558 ffbInitDriver,
559 ffbDestroyScreen,
560 ffbCreateContext,
561 ffbDestroyContext,
562 ffbCreateBuffer,
563 ffbDestroyBuffer,
564 ffbSwapBuffers,
565 ffbMakeCurrent,
566 ffbUnbindContext
567 };
568
569
570
571 /*
572 * This is the bootstrap function for the driver.
573 * The __driCreateScreen name is the symbol that libGL.so fetches.
574 * Return: pointer to a __DRIscreenPrivate.
575 */
576 void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
577 int numConfigs, __GLXvisualConfig *config)
578 {
579 __DRIscreenPrivate *psp;
580 psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &ffbAPI);
581 return (void *) psp;
582 }
583
584
585 #endif /* GLX_DIRECT_RENDERING */