Merge branch 'mesa_7_7_branch'
[mesa.git] / src / mesa / drivers / dri / i810 / i810context.c
1 /**************************************************************************
2
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4 All Rights Reserved.
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sub license, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
16 of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Keith Whitwell <keith@tungstengraphics.com>
31 *
32 */
33
34
35 #include "main/glheader.h"
36 #include "main/context.h"
37 #include "main/simple_list.h"
38 #include "main/imports.h"
39 #include "main/points.h"
40
41 #include "swrast/swrast.h"
42 #include "swrast_setup/swrast_setup.h"
43 #include "tnl/tnl.h"
44 #include "vbo/vbo.h"
45
46 #include "tnl/t_pipeline.h"
47
48 #include "drivers/common/driverfuncs.h"
49
50 #include "i810screen.h"
51 #include "i810_dri.h"
52
53 #include "i810state.h"
54 #include "i810tex.h"
55 #include "i810span.h"
56 #include "i810tris.h"
57 #include "i810vb.h"
58 #include "i810ioctl.h"
59
60 #include "drirenderbuffer.h"
61 #include "utils.h"
62
63 #ifndef I810_DEBUG
64 int I810_DEBUG = (0);
65 #endif
66
67 PUBLIC const char __driConfigOptions[] = { 0 };
68 const GLuint __driNConfigOptions = 0;
69
70 #define DRIVER_DATE "20050821"
71
72 static const GLubyte *i810GetString( GLcontext *ctx, GLenum name )
73 {
74 static char buffer[128];
75
76 switch (name) {
77 case GL_VENDOR:
78 return (GLubyte *)"Keith Whitwell";
79 case GL_RENDERER: {
80 i810ContextPtr imesa = I810_CONTEXT(ctx);
81 const char * chipset;
82
83 switch (imesa->i810Screen->deviceID) {
84 case PCI_CHIP_I810: chipset = "i810"; break;
85 case PCI_CHIP_I810_DC100: chipset = "i810 DC-100"; break;
86 case PCI_CHIP_I810_E: chipset = "i810E"; break;
87 case PCI_CHIP_I815: chipset = "i815"; break;
88 default: chipset = "Unknown i810-class Chipset"; break;
89 }
90
91 (void) driGetRendererString( buffer, chipset, DRIVER_DATE, 0 );
92 return (GLubyte *) buffer;
93 }
94 default:
95 return 0;
96 }
97 }
98
99 static void i810BufferSize(GLframebuffer *buffer, GLuint *width, GLuint *height)
100 {
101 GET_CURRENT_CONTEXT(ctx);
102 i810ContextPtr imesa = I810_CONTEXT(ctx);
103
104 /* Need to lock to make sure the driDrawable is uptodate. This
105 * information is used to resize Mesa's software buffers, so it has
106 * to be correct.
107 */
108 LOCK_HARDWARE(imesa);
109 *width = imesa->driDrawable->w;
110 *height = imesa->driDrawable->h;
111 UNLOCK_HARDWARE(imesa);
112 }
113
114 /* Extension strings exported by the i810 driver.
115 */
116 static const struct dri_extension card_extensions[] =
117 {
118 { "GL_ARB_multitexture", NULL },
119 { "GL_ARB_texture_env_add", NULL },
120 { "GL_ARB_texture_env_combine", NULL },
121 { "GL_ARB_texture_env_crossbar", NULL },
122 { "GL_ARB_texture_mirrored_repeat", NULL },
123 { "GL_EXT_stencil_wrap", NULL },
124 { "GL_EXT_texture_edge_clamp", NULL },
125 { "GL_EXT_texture_env_combine", NULL },
126 { "GL_EXT_texture_lod_bias", NULL },
127 { "GL_EXT_texture_rectangle", NULL },
128 { "GL_MESA_ycbcr_texture", NULL },
129 { "GL_NV_blend_square", NULL },
130 { "GL_SGIS_generate_mipmap", NULL },
131 { NULL, NULL }
132 };
133
134 extern const struct tnl_pipeline_stage _i810_render_stage;
135
136 static const struct tnl_pipeline_stage *i810_pipeline[] = {
137 &_tnl_vertex_transform_stage,
138 &_tnl_normal_transform_stage,
139 &_tnl_lighting_stage,
140 &_tnl_fog_coordinate_stage,
141 &_tnl_texgen_stage,
142 &_tnl_texture_transform_stage,
143 /* REMOVE: point attenuation stage */
144 #if 1
145 &_i810_render_stage, /* ADD: unclipped rastersetup-to-dma */
146 #endif
147 &_tnl_render_stage,
148 0,
149 };
150
151 static const struct dri_debug_control debug_control[] =
152 {
153 { "fall", DEBUG_FALLBACKS },
154 { "tex", DEBUG_TEXTURE },
155 { "ioctl", DEBUG_IOCTL },
156 { "prim", DEBUG_PRIMS },
157 { "vert", DEBUG_VERTS },
158 { "state", DEBUG_STATE },
159 { "verb", DEBUG_VERBOSE },
160 { "dri", DEBUG_DRI },
161 { "dma", DEBUG_DMA },
162 { "san", DEBUG_SANITY },
163 { "sync", DEBUG_SYNC },
164 { "sleep", DEBUG_SLEEP },
165 { NULL, 0 }
166 };
167
168 GLboolean
169 i810CreateContext( const __GLcontextModes *mesaVis,
170 __DRIcontext *driContextPriv,
171 void *sharedContextPrivate )
172 {
173 GLcontext *ctx, *shareCtx;
174 i810ContextPtr imesa;
175 __DRIscreen *sPriv = driContextPriv->driScreenPriv;
176 i810ScreenPrivate *i810Screen = (i810ScreenPrivate *)sPriv->private;
177 I810SAREAPtr saPriv = (I810SAREAPtr)
178 (((GLubyte *)sPriv->pSAREA) + i810Screen->sarea_priv_offset);
179 struct dd_function_table functions;
180
181 /* Allocate i810 context */
182 imesa = (i810ContextPtr) CALLOC_STRUCT(i810_context_t);
183 if (!imesa) {
184 return GL_FALSE;
185 }
186
187 driContextPriv->driverPrivate = imesa;
188
189 imesa->i810Screen = i810Screen;
190 imesa->driScreen = sPriv;
191 imesa->sarea = saPriv;
192 imesa->glBuffer = NULL;
193
194 /* Init default driver functions then plug in our I810-specific functions
195 * (the texture functions are especially important)
196 */
197 _mesa_init_driver_functions( &functions );
198 i810InitIoctlFuncs( &functions );
199 i810InitTextureFuncs( &functions );
200
201
202 /* Allocate the Mesa context */
203 if (sharedContextPrivate)
204 shareCtx = ((i810ContextPtr) sharedContextPrivate)->glCtx;
205 else
206 shareCtx = NULL;
207 imesa->glCtx = _mesa_create_context(mesaVis, shareCtx,
208 &functions, (void*) imesa);
209 if (!imesa->glCtx) {
210 FREE(imesa);
211 return GL_FALSE;
212 }
213
214 (void) memset( imesa->texture_heaps, 0, sizeof( imesa->texture_heaps ) );
215 make_empty_list( & imesa->swapped );
216
217 imesa->nr_heaps = 1;
218 imesa->texture_heaps[0] = driCreateTextureHeap( 0, imesa,
219 i810Screen->textureSize,
220 12,
221 I810_NR_TEX_REGIONS,
222 imesa->sarea->texList,
223 (unsigned *) & imesa->sarea->texAge, /* XXX we shouldn't cast! */
224 & imesa->swapped,
225 sizeof( struct i810_texture_object_t ),
226 (destroy_texture_object_t *) i810DestroyTexObj );
227
228
229
230 /* Set the maximum texture size small enough that we can guarentee
231 * that both texture units can bind a maximal texture and have them
232 * in memory at once.
233 */
234
235
236
237 ctx = imesa->glCtx;
238 ctx->Const.MaxTextureUnits = 2;
239 ctx->Const.MaxTextureImageUnits = 2;
240 ctx->Const.MaxTextureCoordUnits = 2;
241
242
243 /* FIXME: driCalcualteMaxTextureLevels assumes that mipmaps are tightly
244 * FIXME: packed, but they're not in Intel graphics hardware.
245 */
246 driCalculateMaxTextureLevels( imesa->texture_heaps,
247 imesa->nr_heaps,
248 & ctx->Const,
249 4,
250 11, /* max 2D texture size is 2048x2048 */
251 0, /* 3D textures unsupported */
252 0, /* cube textures unsupported. */
253 0, /* texture rectangles unsupported. */
254 12,
255 GL_FALSE,
256 0 );
257
258 ctx->Const.MinLineWidth = 1.0;
259 ctx->Const.MinLineWidthAA = 1.0;
260 ctx->Const.MaxLineWidth = 3.0;
261 ctx->Const.MaxLineWidthAA = 3.0;
262 ctx->Const.LineWidthGranularity = 1.0;
263
264 ctx->Const.MinPointSize = 1.0;
265 ctx->Const.MinPointSizeAA = 1.0;
266 ctx->Const.MaxPointSize = 3.0;
267 ctx->Const.MaxPointSizeAA = 3.0;
268 ctx->Const.PointSizeGranularity = 1.0;
269
270 /* reinitialize the context point state.
271 * It depend on constants in __GLcontextRec::Const
272 */
273 _mesa_init_point(ctx);
274
275 ctx->Driver.GetBufferSize = i810BufferSize;
276 ctx->Driver.GetString = i810GetString;
277
278 /* Who owns who?
279 */
280 ctx->DriverCtx = (void *) imesa;
281 imesa->glCtx = ctx;
282
283 /* Initialize the software rasterizer and helper modules.
284 */
285 _swrast_CreateContext( ctx );
286 _vbo_CreateContext( ctx );
287 _tnl_CreateContext( ctx );
288 _swsetup_CreateContext( ctx );
289
290 /* Install the customized pipeline:
291 */
292 _tnl_destroy_pipeline( ctx );
293 _tnl_install_pipeline( ctx, i810_pipeline );
294
295 /* Configure swrast and T&L to match hardware characteristics:
296 */
297 _swrast_allow_pixel_fog( ctx, GL_FALSE );
298 _swrast_allow_vertex_fog( ctx, GL_TRUE );
299 _tnl_allow_pixel_fog( ctx, GL_FALSE );
300 _tnl_allow_vertex_fog( ctx, GL_TRUE );
301
302 /* Dri stuff
303 */
304 imesa->hHWContext = driContextPriv->hHWContext;
305 imesa->driFd = sPriv->fd;
306 imesa->driHwLock = &sPriv->pSAREA->lock;
307
308 imesa->stipple_in_hw = 1;
309 imesa->RenderIndex = ~0;
310 imesa->dirty = I810_UPLOAD_CTX|I810_UPLOAD_BUFFERS;
311 imesa->upload_cliprects = GL_TRUE;
312
313 imesa->CurrentTexObj[0] = 0;
314 imesa->CurrentTexObj[1] = 0;
315
316 _math_matrix_ctr( &imesa->ViewportMatrix );
317
318 driInitExtensions( ctx, card_extensions, GL_TRUE );
319 /* XXX these should really go right after _mesa_init_driver_functions() */
320 i810InitStateFuncs( ctx );
321 i810InitTriFuncs( ctx );
322 i810InitSpanFuncs( ctx );
323 i810InitVB( ctx );
324 i810InitState( ctx );
325
326 #if DO_DEBUG
327 I810_DEBUG = driParseDebugString( getenv( "I810_DEBUG" ),
328 debug_control );
329 I810_DEBUG |= driParseDebugString( getenv( "INTEL_DEBUG" ),
330 debug_control );
331 #endif
332
333 return GL_TRUE;
334 }
335
336 void
337 i810DestroyContext(__DRIcontext *driContextPriv)
338 {
339 i810ContextPtr imesa = (i810ContextPtr) driContextPriv->driverPrivate;
340
341 assert(imesa); /* should never be null */
342 if (imesa) {
343 GLboolean release_texture_heaps;
344
345
346 release_texture_heaps = (imesa->glCtx->Shared->RefCount == 1);
347 _swsetup_DestroyContext( imesa->glCtx );
348 _tnl_DestroyContext( imesa->glCtx );
349 _vbo_DestroyContext( imesa->glCtx );
350 _swrast_DestroyContext( imesa->glCtx );
351
352 i810FreeVB( imesa->glCtx );
353
354 /* free the Mesa context */
355 imesa->glCtx->DriverCtx = NULL;
356 _mesa_destroy_context(imesa->glCtx);
357 if ( release_texture_heaps ) {
358 /* This share group is about to go away, free our private
359 * texture object data.
360 */
361 unsigned int i;
362
363 for ( i = 0 ; i < imesa->nr_heaps ; i++ ) {
364 driDestroyTextureHeap( imesa->texture_heaps[ i ] );
365 imesa->texture_heaps[ i ] = NULL;
366 }
367
368 assert( is_empty_list( & imesa->swapped ) );
369 }
370
371 FREE(imesa);
372 }
373 }
374
375
376 void i810XMesaSetFrontClipRects( i810ContextPtr imesa )
377 {
378 __DRIdrawable *dPriv = imesa->driDrawable;
379
380 imesa->numClipRects = dPriv->numClipRects;
381 imesa->pClipRects = dPriv->pClipRects;
382 imesa->drawX = dPriv->x;
383 imesa->drawY = dPriv->y;
384
385 i810EmitDrawingRectangle( imesa );
386 imesa->upload_cliprects = GL_TRUE;
387 }
388
389
390 void i810XMesaSetBackClipRects( i810ContextPtr imesa )
391 {
392 __DRIdrawable *dPriv = imesa->driDrawable;
393
394 if (imesa->sarea->pf_enabled == 0 && dPriv->numBackClipRects == 0)
395 {
396 imesa->numClipRects = dPriv->numClipRects;
397 imesa->pClipRects = dPriv->pClipRects;
398 imesa->drawX = dPriv->x;
399 imesa->drawY = dPriv->y;
400 } else {
401 imesa->numClipRects = dPriv->numBackClipRects;
402 imesa->pClipRects = dPriv->pBackClipRects;
403 imesa->drawX = dPriv->backX;
404 imesa->drawY = dPriv->backY;
405 }
406
407 i810EmitDrawingRectangle( imesa );
408 imesa->upload_cliprects = GL_TRUE;
409 }
410
411
412 static void i810XMesaWindowMoved( i810ContextPtr imesa )
413 {
414 /* Determine current color drawing buffer */
415 switch (imesa->glCtx->DrawBuffer->_ColorDrawBufferIndexes[0]) {
416 case BUFFER_FRONT_LEFT:
417 i810XMesaSetFrontClipRects( imesa );
418 break;
419 case BUFFER_BACK_LEFT:
420 i810XMesaSetBackClipRects( imesa );
421 break;
422 default:
423 /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */
424 i810XMesaSetFrontClipRects( imesa );
425 }
426 }
427
428
429 GLboolean
430 i810UnbindContext(__DRIcontext *driContextPriv)
431 {
432 i810ContextPtr imesa = (i810ContextPtr) driContextPriv->driverPrivate;
433 if (imesa) {
434 imesa->dirty = I810_UPLOAD_CTX|I810_UPLOAD_BUFFERS;
435 if (imesa->CurrentTexObj[0]) imesa->dirty |= I810_UPLOAD_TEX0;
436 if (imesa->CurrentTexObj[1]) imesa->dirty |= I810_UPLOAD_TEX1;
437 }
438
439 return GL_TRUE;
440 }
441
442
443 GLboolean
444 i810MakeCurrent(__DRIcontext *driContextPriv,
445 __DRIdrawable *driDrawPriv,
446 __DRIdrawable *driReadPriv)
447 {
448 if (driContextPriv) {
449 i810ContextPtr imesa = (i810ContextPtr) driContextPriv->driverPrivate;
450
451 /* Shouldn't the readbuffer be stored also?
452 */
453 imesa->driDrawable = driDrawPriv;
454
455 _mesa_make_current(imesa->glCtx,
456 (GLframebuffer *) driDrawPriv->driverPrivate,
457 (GLframebuffer *) driReadPriv->driverPrivate);
458
459 /* Are these necessary?
460 */
461 i810XMesaWindowMoved( imesa );
462 }
463 else {
464 _mesa_make_current(NULL, NULL, NULL);
465 }
466
467 return GL_TRUE;
468 }
469
470 static void
471 i810UpdatePageFlipping( i810ContextPtr imesa )
472 {
473 GLcontext *ctx = imesa->glCtx;
474 int front = 0;
475
476 /* Determine current color drawing buffer */
477 switch (ctx->DrawBuffer->_ColorDrawBufferIndexes[0]) {
478 case BUFFER_FRONT_LEFT:
479 front = 1;
480 break;
481 case BUFFER_BACK_LEFT:
482 front = 0;
483 break;
484 default:
485 return;
486 }
487
488 if ( imesa->sarea->pf_current_page == 1 )
489 front ^= 1;
490
491 driFlipRenderbuffers(ctx->WinSysDrawBuffer, front);
492
493 if (front) {
494 imesa->BufferSetup[I810_DESTREG_DI1] = imesa->i810Screen->fbOffset | imesa->i810Screen->backPitchBits;
495 } else {
496 imesa->BufferSetup[I810_DESTREG_DI1] = imesa->i810Screen->backOffset | imesa->i810Screen->backPitchBits;
497 }
498
499 imesa->dirty |= I810_UPLOAD_BUFFERS;
500 }
501
502 void i810GetLock( i810ContextPtr imesa, GLuint flags )
503 {
504 __DRIdrawable *dPriv = imesa->driDrawable;
505 __DRIscreen *sPriv = imesa->driScreen;
506 I810SAREAPtr sarea = imesa->sarea;
507 int me = imesa->hHWContext;
508 unsigned i;
509
510 drmGetLock(imesa->driFd, imesa->hHWContext, flags);
511
512 /* If the window moved, may need to set a new cliprect now.
513 *
514 * NOTE: This releases and regains the hw lock, so all state
515 * checking must be done *after* this call:
516 */
517 DRI_VALIDATE_DRAWABLE_INFO(sPriv, dPriv);
518
519
520 /* If we lost context, need to dump all registers to hardware.
521 * Note that we don't care about 2d contexts, even if they perform
522 * accelerated commands, so the DRI locking in the X server is even
523 * more broken than usual.
524 */
525 if (sarea->ctxOwner != me) {
526 driUpdateFramebufferSize(imesa->glCtx, dPriv);
527 imesa->upload_cliprects = GL_TRUE;
528 imesa->dirty = I810_UPLOAD_CTX|I810_UPLOAD_BUFFERS;
529 if (imesa->CurrentTexObj[0]) imesa->dirty |= I810_UPLOAD_TEX0;
530 if (imesa->CurrentTexObj[1]) imesa->dirty |= I810_UPLOAD_TEX1;
531 sarea->ctxOwner = me;
532 }
533
534 /* Shared texture managment - if another client has played with
535 * texture space, figure out which if any of our textures have been
536 * ejected, and update our global LRU.
537 */
538 for ( i = 0 ; i < imesa->nr_heaps ; i++ ) {
539 DRI_AGE_TEXTURES( imesa->texture_heaps[ i ] );
540 }
541
542 if (imesa->lastStamp != dPriv->lastStamp) {
543 i810UpdatePageFlipping( imesa );
544 i810XMesaWindowMoved( imesa );
545 imesa->lastStamp = dPriv->lastStamp;
546 }
547 }
548
549
550 void
551 i810SwapBuffers( __DRIdrawable *dPriv )
552 {
553 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
554 i810ContextPtr imesa;
555 GLcontext *ctx;
556 imesa = (i810ContextPtr) dPriv->driContextPriv->driverPrivate;
557 ctx = imesa->glCtx;
558 if (ctx->Visual.doubleBufferMode) {
559 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
560 if ( imesa->sarea->pf_active ) {
561 i810PageFlip( dPriv );
562 } else {
563 i810CopyBuffer( dPriv );
564 }
565 }
566 }
567 else {
568 /* XXX this shouldn't be an error but we can't handle it for now */
569 _mesa_problem(NULL, "i810SwapBuffers: drawable has no context!\n");
570 }
571 }
572