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