dri: Add DRI entrypoints to create a context for a given API
[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( gl_api api,
170 const __GLcontextModes *mesaVis,
171 __DRIcontext *driContextPriv,
172 void *sharedContextPrivate )
173 {
174 GLcontext *ctx, *shareCtx;
175 i810ContextPtr imesa;
176 __DRIscreen *sPriv = driContextPriv->driScreenPriv;
177 i810ScreenPrivate *i810Screen = (i810ScreenPrivate *)sPriv->private;
178 I810SAREAPtr saPriv = (I810SAREAPtr)
179 (((GLubyte *)sPriv->pSAREA) + i810Screen->sarea_priv_offset);
180 struct dd_function_table functions;
181
182 /* Allocate i810 context */
183 imesa = (i810ContextPtr) CALLOC_STRUCT(i810_context_t);
184 if (!imesa) {
185 return GL_FALSE;
186 }
187
188 driContextPriv->driverPrivate = imesa;
189
190 imesa->i810Screen = i810Screen;
191 imesa->driScreen = sPriv;
192 imesa->sarea = saPriv;
193 imesa->glBuffer = NULL;
194
195 /* Init default driver functions then plug in our I810-specific functions
196 * (the texture functions are especially important)
197 */
198 _mesa_init_driver_functions( &functions );
199 i810InitIoctlFuncs( &functions );
200 i810InitTextureFuncs( &functions );
201
202
203 /* Allocate the Mesa context */
204 if (sharedContextPrivate)
205 shareCtx = ((i810ContextPtr) sharedContextPrivate)->glCtx;
206 else
207 shareCtx = NULL;
208 imesa->glCtx = _mesa_create_context(mesaVis, shareCtx,
209 &functions, (void*) imesa);
210 if (!imesa->glCtx) {
211 FREE(imesa);
212 return GL_FALSE;
213 }
214
215 (void) memset( imesa->texture_heaps, 0, sizeof( imesa->texture_heaps ) );
216 make_empty_list( & imesa->swapped );
217
218 imesa->nr_heaps = 1;
219 imesa->texture_heaps[0] = driCreateTextureHeap( 0, imesa,
220 i810Screen->textureSize,
221 12,
222 I810_NR_TEX_REGIONS,
223 imesa->sarea->texList,
224 (unsigned *) & imesa->sarea->texAge, /* XXX we shouldn't cast! */
225 & imesa->swapped,
226 sizeof( struct i810_texture_object_t ),
227 (destroy_texture_object_t *) i810DestroyTexObj );
228
229
230
231 /* Set the maximum texture size small enough that we can guarentee
232 * that both texture units can bind a maximal texture and have them
233 * in memory at once.
234 */
235
236
237
238 ctx = imesa->glCtx;
239 ctx->Const.MaxTextureUnits = 2;
240 ctx->Const.MaxTextureImageUnits = 2;
241 ctx->Const.MaxTextureCoordUnits = 2;
242
243
244 /* FIXME: driCalcualteMaxTextureLevels assumes that mipmaps are tightly
245 * FIXME: packed, but they're not in Intel graphics hardware.
246 */
247 driCalculateMaxTextureLevels( imesa->texture_heaps,
248 imesa->nr_heaps,
249 & ctx->Const,
250 4,
251 11, /* max 2D texture size is 2048x2048 */
252 0, /* 3D textures unsupported */
253 0, /* cube textures unsupported. */
254 0, /* texture rectangles unsupported. */
255 12,
256 GL_FALSE,
257 0 );
258
259 ctx->Const.MinLineWidth = 1.0;
260 ctx->Const.MinLineWidthAA = 1.0;
261 ctx->Const.MaxLineWidth = 3.0;
262 ctx->Const.MaxLineWidthAA = 3.0;
263 ctx->Const.LineWidthGranularity = 1.0;
264
265 ctx->Const.MinPointSize = 1.0;
266 ctx->Const.MinPointSizeAA = 1.0;
267 ctx->Const.MaxPointSize = 3.0;
268 ctx->Const.MaxPointSizeAA = 3.0;
269 ctx->Const.PointSizeGranularity = 1.0;
270
271 /* reinitialize the context point state.
272 * It depend on constants in __GLcontextRec::Const
273 */
274 _mesa_init_point(ctx);
275
276 ctx->Driver.GetBufferSize = i810BufferSize;
277 ctx->Driver.GetString = i810GetString;
278
279 /* Who owns who?
280 */
281 ctx->DriverCtx = (void *) imesa;
282 imesa->glCtx = ctx;
283
284 /* Initialize the software rasterizer and helper modules.
285 */
286 _swrast_CreateContext( ctx );
287 _vbo_CreateContext( ctx );
288 _tnl_CreateContext( ctx );
289 _swsetup_CreateContext( ctx );
290
291 /* Install the customized pipeline:
292 */
293 _tnl_destroy_pipeline( ctx );
294 _tnl_install_pipeline( ctx, i810_pipeline );
295
296 /* Configure swrast and T&L to match hardware characteristics:
297 */
298 _swrast_allow_pixel_fog( ctx, GL_FALSE );
299 _swrast_allow_vertex_fog( ctx, GL_TRUE );
300 _tnl_allow_pixel_fog( ctx, GL_FALSE );
301 _tnl_allow_vertex_fog( ctx, GL_TRUE );
302
303 /* Dri stuff
304 */
305 imesa->hHWContext = driContextPriv->hHWContext;
306 imesa->driFd = sPriv->fd;
307 imesa->driHwLock = &sPriv->pSAREA->lock;
308
309 imesa->stipple_in_hw = 1;
310 imesa->RenderIndex = ~0;
311 imesa->dirty = I810_UPLOAD_CTX|I810_UPLOAD_BUFFERS;
312 imesa->upload_cliprects = GL_TRUE;
313
314 imesa->CurrentTexObj[0] = 0;
315 imesa->CurrentTexObj[1] = 0;
316
317 _math_matrix_ctr( &imesa->ViewportMatrix );
318
319 driInitExtensions( ctx, card_extensions, GL_TRUE );
320 /* XXX these should really go right after _mesa_init_driver_functions() */
321 i810InitStateFuncs( ctx );
322 i810InitTriFuncs( ctx );
323 i810InitSpanFuncs( ctx );
324 i810InitVB( ctx );
325 i810InitState( ctx );
326
327 #if DO_DEBUG
328 I810_DEBUG = driParseDebugString( getenv( "I810_DEBUG" ),
329 debug_control );
330 I810_DEBUG |= driParseDebugString( getenv( "INTEL_DEBUG" ),
331 debug_control );
332 #endif
333
334 return GL_TRUE;
335 }
336
337 void
338 i810DestroyContext(__DRIcontext *driContextPriv)
339 {
340 i810ContextPtr imesa = (i810ContextPtr) driContextPriv->driverPrivate;
341
342 assert(imesa); /* should never be null */
343 if (imesa) {
344 GLboolean release_texture_heaps;
345
346
347 release_texture_heaps = (imesa->glCtx->Shared->RefCount == 1);
348 _swsetup_DestroyContext( imesa->glCtx );
349 _tnl_DestroyContext( imesa->glCtx );
350 _vbo_DestroyContext( imesa->glCtx );
351 _swrast_DestroyContext( imesa->glCtx );
352
353 i810FreeVB( imesa->glCtx );
354
355 /* free the Mesa context */
356 imesa->glCtx->DriverCtx = NULL;
357 _mesa_destroy_context(imesa->glCtx);
358 if ( release_texture_heaps ) {
359 /* This share group is about to go away, free our private
360 * texture object data.
361 */
362 unsigned int i;
363
364 for ( i = 0 ; i < imesa->nr_heaps ; i++ ) {
365 driDestroyTextureHeap( imesa->texture_heaps[ i ] );
366 imesa->texture_heaps[ i ] = NULL;
367 }
368
369 assert( is_empty_list( & imesa->swapped ) );
370 }
371
372 FREE(imesa);
373 }
374 }
375
376
377 void i810XMesaSetFrontClipRects( i810ContextPtr imesa )
378 {
379 __DRIdrawable *dPriv = imesa->driDrawable;
380
381 imesa->numClipRects = dPriv->numClipRects;
382 imesa->pClipRects = dPriv->pClipRects;
383 imesa->drawX = dPriv->x;
384 imesa->drawY = dPriv->y;
385
386 i810EmitDrawingRectangle( imesa );
387 imesa->upload_cliprects = GL_TRUE;
388 }
389
390
391 void i810XMesaSetBackClipRects( i810ContextPtr imesa )
392 {
393 __DRIdrawable *dPriv = imesa->driDrawable;
394
395 if (imesa->sarea->pf_enabled == 0 && dPriv->numBackClipRects == 0)
396 {
397 imesa->numClipRects = dPriv->numClipRects;
398 imesa->pClipRects = dPriv->pClipRects;
399 imesa->drawX = dPriv->x;
400 imesa->drawY = dPriv->y;
401 } else {
402 imesa->numClipRects = dPriv->numBackClipRects;
403 imesa->pClipRects = dPriv->pBackClipRects;
404 imesa->drawX = dPriv->backX;
405 imesa->drawY = dPriv->backY;
406 }
407
408 i810EmitDrawingRectangle( imesa );
409 imesa->upload_cliprects = GL_TRUE;
410 }
411
412
413 static void i810XMesaWindowMoved( i810ContextPtr imesa )
414 {
415 /* Determine current color drawing buffer */
416 switch (imesa->glCtx->DrawBuffer->_ColorDrawBufferIndexes[0]) {
417 case BUFFER_FRONT_LEFT:
418 i810XMesaSetFrontClipRects( imesa );
419 break;
420 case BUFFER_BACK_LEFT:
421 i810XMesaSetBackClipRects( imesa );
422 break;
423 default:
424 /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */
425 i810XMesaSetFrontClipRects( imesa );
426 }
427 }
428
429
430 GLboolean
431 i810UnbindContext(__DRIcontext *driContextPriv)
432 {
433 i810ContextPtr imesa = (i810ContextPtr) driContextPriv->driverPrivate;
434 if (imesa) {
435 imesa->dirty = I810_UPLOAD_CTX|I810_UPLOAD_BUFFERS;
436 if (imesa->CurrentTexObj[0]) imesa->dirty |= I810_UPLOAD_TEX0;
437 if (imesa->CurrentTexObj[1]) imesa->dirty |= I810_UPLOAD_TEX1;
438 }
439
440 return GL_TRUE;
441 }
442
443
444 GLboolean
445 i810MakeCurrent(__DRIcontext *driContextPriv,
446 __DRIdrawable *driDrawPriv,
447 __DRIdrawable *driReadPriv)
448 {
449 if (driContextPriv) {
450 i810ContextPtr imesa = (i810ContextPtr) driContextPriv->driverPrivate;
451
452 /* Shouldn't the readbuffer be stored also?
453 */
454 imesa->driDrawable = driDrawPriv;
455
456 _mesa_make_current(imesa->glCtx,
457 (GLframebuffer *) driDrawPriv->driverPrivate,
458 (GLframebuffer *) driReadPriv->driverPrivate);
459
460 /* Are these necessary?
461 */
462 i810XMesaWindowMoved( imesa );
463 }
464 else {
465 _mesa_make_current(NULL, NULL, NULL);
466 }
467
468 return GL_TRUE;
469 }
470
471 static void
472 i810UpdatePageFlipping( i810ContextPtr imesa )
473 {
474 GLcontext *ctx = imesa->glCtx;
475 int front = 0;
476
477 /* Determine current color drawing buffer */
478 switch (ctx->DrawBuffer->_ColorDrawBufferIndexes[0]) {
479 case BUFFER_FRONT_LEFT:
480 front = 1;
481 break;
482 case BUFFER_BACK_LEFT:
483 front = 0;
484 break;
485 default:
486 return;
487 }
488
489 if ( imesa->sarea->pf_current_page == 1 )
490 front ^= 1;
491
492 driFlipRenderbuffers(ctx->WinSysDrawBuffer, front);
493
494 if (front) {
495 imesa->BufferSetup[I810_DESTREG_DI1] = imesa->i810Screen->fbOffset | imesa->i810Screen->backPitchBits;
496 } else {
497 imesa->BufferSetup[I810_DESTREG_DI1] = imesa->i810Screen->backOffset | imesa->i810Screen->backPitchBits;
498 }
499
500 imesa->dirty |= I810_UPLOAD_BUFFERS;
501 }
502
503 void i810GetLock( i810ContextPtr imesa, GLuint flags )
504 {
505 __DRIdrawable *dPriv = imesa->driDrawable;
506 __DRIscreen *sPriv = imesa->driScreen;
507 I810SAREAPtr sarea = imesa->sarea;
508 int me = imesa->hHWContext;
509 unsigned i;
510
511 drmGetLock(imesa->driFd, imesa->hHWContext, flags);
512
513 /* If the window moved, may need to set a new cliprect now.
514 *
515 * NOTE: This releases and regains the hw lock, so all state
516 * checking must be done *after* this call:
517 */
518 DRI_VALIDATE_DRAWABLE_INFO(sPriv, dPriv);
519
520
521 /* If we lost context, need to dump all registers to hardware.
522 * Note that we don't care about 2d contexts, even if they perform
523 * accelerated commands, so the DRI locking in the X server is even
524 * more broken than usual.
525 */
526 if (sarea->ctxOwner != me) {
527 driUpdateFramebufferSize(imesa->glCtx, dPriv);
528 imesa->upload_cliprects = GL_TRUE;
529 imesa->dirty = I810_UPLOAD_CTX|I810_UPLOAD_BUFFERS;
530 if (imesa->CurrentTexObj[0]) imesa->dirty |= I810_UPLOAD_TEX0;
531 if (imesa->CurrentTexObj[1]) imesa->dirty |= I810_UPLOAD_TEX1;
532 sarea->ctxOwner = me;
533 }
534
535 /* Shared texture managment - if another client has played with
536 * texture space, figure out which if any of our textures have been
537 * ejected, and update our global LRU.
538 */
539 for ( i = 0 ; i < imesa->nr_heaps ; i++ ) {
540 DRI_AGE_TEXTURES( imesa->texture_heaps[ i ] );
541 }
542
543 if (imesa->lastStamp != dPriv->lastStamp) {
544 i810UpdatePageFlipping( imesa );
545 i810XMesaWindowMoved( imesa );
546 imesa->lastStamp = dPriv->lastStamp;
547 }
548 }
549
550
551 void
552 i810SwapBuffers( __DRIdrawable *dPriv )
553 {
554 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
555 i810ContextPtr imesa;
556 GLcontext *ctx;
557 imesa = (i810ContextPtr) dPriv->driContextPriv->driverPrivate;
558 ctx = imesa->glCtx;
559 if (ctx->Visual.doubleBufferMode) {
560 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
561 if ( imesa->sarea->pf_active ) {
562 i810PageFlip( dPriv );
563 } else {
564 i810CopyBuffer( dPriv );
565 }
566 }
567 }
568 else {
569 /* XXX this shouldn't be an error but we can't handle it for now */
570 _mesa_problem(NULL, "i810SwapBuffers: drawable has no context!\n");
571 }
572 }
573