Before calling _mesa_create_context(), initialize a dd_function_table struct
[mesa.git] / src / mesa / drivers / dri / i830 / i830_tex.c
1 /**************************************************************************
2
3 Copyright 2001 2d3d Inc., Delray Beach, FL
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 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
21 ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /* $XFree86: xc/lib/GL/mesa/src/drv/i830/i830_tex.c,v 1.5 2003/05/07 21:56:31 dawes Exp $ */
29
30 /*
31 * Author:
32 * Jeff Hartmann <jhartmann@2d3d.com>
33 *
34 * Heavily based on the I810 driver, which was written by:
35 * Keith Whitwell <keithw@tungstengraphics.com>
36 */
37
38 #include "glheader.h"
39 #include "mtypes.h"
40 #include "imports.h"
41 #include "simple_list.h"
42 #include "enums.h"
43 #include "texstore.h"
44 #include "teximage.h"
45 #include "texformat.h"
46 #include "texmem.h"
47 #include "swrast/swrast.h"
48 #include "texobj.h"
49 #include "mm.h"
50
51 #include "i830_screen.h"
52 #include "i830_dri.h"
53 #include "i830_context.h"
54 #include "i830_tex.h"
55 #include "i830_state.h"
56 #include "i830_ioctl.h"
57
58 /*
59 * Compute the 'S2.4' lod bias factor from the floating point OpenGL bias.
60 */
61 static void i830ComputeLodBias( i830ContextPtr imesa, unsigned unit,
62 GLfloat bias )
63 {
64 int b;
65
66 b = (int) (bias * 16.0);
67 if(b > 63) b = 63;
68 else if (b < -64) b = -64;
69 imesa->LodBias[ unit ] = ((b << TM0S3_LOD_BIAS_SHIFT) &
70 TM0S3_LOD_BIAS_MASK);
71 }
72
73
74 /**
75 * Set the texture wrap modes.
76 *
77 * The i830M (and related graphics cores) do not support GL_CLAMP. The Intel
78 * drivers for "other operating systems" implement GL_CLAMP as
79 * GL_CLAMP_TO_EDGE, so the same is done here.
80 *
81 * \param t Texture object whose wrap modes are to be set
82 * \param swrap Wrap mode for the \a s texture coordinate
83 * \param twrap Wrap mode for the \a t texture coordinate
84 */
85
86 static void i830SetTexWrapping(i830TextureObjectPtr tex,
87 GLenum swrap, GLenum twrap)
88 {
89 tex->Setup[I830_TEXREG_MCS] &= ~(TEXCOORD_ADDR_U_MASK|TEXCOORD_ADDR_V_MASK);
90
91 switch( swrap ) {
92 case GL_REPEAT:
93 tex->Setup[I830_TEXREG_MCS] |= TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_WRAP);
94 break;
95 case GL_CLAMP:
96 case GL_CLAMP_TO_EDGE:
97 tex->Setup[I830_TEXREG_MCS] |= TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP);
98 break;
99 case GL_CLAMP_TO_BORDER:
100 tex->Setup[I830_TEXREG_MCS] |=
101 TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP_BORDER);
102 break;
103 case GL_MIRRORED_REPEAT:
104 tex->Setup[I830_TEXREG_MCS] |=
105 TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_MIRROR);
106 break;
107 default:
108 _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
109 }
110
111 switch( twrap ) {
112 case GL_REPEAT:
113 tex->Setup[I830_TEXREG_MCS] |= TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_WRAP);
114 break;
115 case GL_CLAMP:
116 case GL_CLAMP_TO_EDGE:
117 tex->Setup[I830_TEXREG_MCS] |= TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP);
118 break;
119 case GL_CLAMP_TO_BORDER:
120 tex->Setup[I830_TEXREG_MCS] |=
121 TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP_BORDER);
122 break;
123 case GL_MIRRORED_REPEAT:
124 tex->Setup[I830_TEXREG_MCS] |=
125 TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_MIRROR);
126 break;
127 default:
128 _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
129 }
130 }
131
132 static void i830SetTexMaxAnisotropy( i830TextureObjectPtr t, GLfloat max )
133 {
134 t->max_anisotropy = max;
135 }
136
137
138 /**
139 * Set the texture magnification and minification modes.
140 *
141 * \param t Texture whose filter modes are to be set
142 * \param minf Texture minification mode
143 * \param magf Texture magnification mode
144 * \param bias LOD bias for this texture unit.
145 */
146
147 static void i830SetTexFilter( i830TextureObjectPtr t,
148 GLenum minf, GLenum magf )
149 {
150 int minFilt = 0, mipFilt = 0, magFilt = 0;
151
152 if(I830_DEBUG&DEBUG_DRI)
153 fprintf(stderr, "%s\n", __FUNCTION__);
154
155 if ( t->max_anisotropy > 1.0 ) {
156 minFilt = FILTER_ANISOTROPIC;
157 magFilt = FILTER_ANISOTROPIC;
158 }
159 else {
160 switch (minf) {
161 case GL_NEAREST:
162 minFilt = FILTER_NEAREST;
163 mipFilt = MIPFILTER_NONE;
164 break;
165 case GL_LINEAR:
166 minFilt = FILTER_LINEAR;
167 mipFilt = MIPFILTER_NONE;
168 break;
169 case GL_NEAREST_MIPMAP_NEAREST:
170 minFilt = FILTER_NEAREST;
171 mipFilt = MIPFILTER_NEAREST;
172 break;
173 case GL_LINEAR_MIPMAP_NEAREST:
174 minFilt = FILTER_LINEAR;
175 mipFilt = MIPFILTER_NEAREST;
176 break;
177 case GL_NEAREST_MIPMAP_LINEAR:
178 minFilt = FILTER_NEAREST;
179 mipFilt = MIPFILTER_LINEAR;
180 break;
181 case GL_LINEAR_MIPMAP_LINEAR:
182 minFilt = FILTER_LINEAR;
183 mipFilt = MIPFILTER_LINEAR;
184 break;
185 default:
186 _mesa_problem(NULL, "%s: Unsupported min. filter %d", __FUNCTION__,
187 (int) minf );
188 break;
189 }
190
191 switch (magf) {
192 case GL_NEAREST:
193 magFilt = FILTER_NEAREST;
194 break;
195 case GL_LINEAR:
196 magFilt = FILTER_LINEAR;
197 break;
198 default:
199 _mesa_problem(NULL, "%s: Unsupported mag. filter %d", __FUNCTION__,
200 (int) magf );
201 break;
202 }
203 }
204
205 t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MIN_FILTER_MASK;
206 t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MIP_FILTER_MASK;
207 t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MAG_FILTER_MASK;
208 t->Setup[I830_TEXREG_TM0S3] |= ((minFilt << TM0S3_MIN_FILTER_SHIFT) |
209 (mipFilt << TM0S3_MIP_FILTER_SHIFT) |
210 (magFilt << TM0S3_MAG_FILTER_SHIFT));
211 }
212
213 static void i830SetTexBorderColor(i830TextureObjectPtr t, GLubyte color[4])
214 {
215 if(I830_DEBUG&DEBUG_DRI)
216 fprintf(stderr, "%s\n", __FUNCTION__);
217
218 t->Setup[I830_TEXREG_TM0S4] =
219 I830PACKCOLOR8888(color[0],color[1],color[2],color[3]);
220 }
221
222
223 /**
224 * Allocate space for and load the mesa images into the texture memory block.
225 * This will happen before drawing with a new texture, or drawing with a
226 * texture after it was swapped out or teximaged again.
227 */
228
229 static i830TextureObjectPtr i830AllocTexObj( struct gl_texture_object *texObj )
230 {
231 i830TextureObjectPtr t;
232
233 t = CALLOC_STRUCT( i830_texture_object_t );
234 texObj->DriverData = t;
235 if ( t != NULL ) {
236 /* Initialize non-image-dependent parts of the state:
237 */
238 t->base.tObj = texObj;
239
240 t->Setup[I830_TEXREG_TM0LI] = STATE3D_LOAD_STATE_IMMEDIATE_2;
241 t->Setup[I830_TEXREG_TM0S0] = TM0S0_USE_FENCE;
242 t->Setup[I830_TEXREG_TM0S1] = 0;
243 t->Setup[I830_TEXREG_TM0S2] = 0;
244 t->Setup[I830_TEXREG_TM0S3] = 0;
245
246 t->Setup[I830_TEXREG_NOP0] = 0;
247 t->Setup[I830_TEXREG_NOP1] = 0;
248 t->Setup[I830_TEXREG_NOP2] = 0;
249
250 t->Setup[I830_TEXREG_MCS] = (STATE3D_MAP_COORD_SET_CMD |
251 MAP_UNIT(0) |
252 ENABLE_TEXCOORD_PARAMS |
253 TEXCOORDS_ARE_NORMAL |
254 TEXCOORDTYPE_CARTESIAN |
255 ENABLE_ADDR_V_CNTL |
256 TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_WRAP) |
257 ENABLE_ADDR_U_CNTL |
258 TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_WRAP));
259
260 make_empty_list( & t->base );
261
262 i830SetTexWrapping( t, texObj->WrapS, texObj->WrapT );
263 i830SetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
264 i830SetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
265 i830SetTexBorderColor( t, texObj->_BorderChan );
266 }
267
268 return t;
269 }
270
271
272 static void i830TexParameter( GLcontext *ctx, GLenum target,
273 struct gl_texture_object *tObj,
274 GLenum pname, const GLfloat *params )
275 {
276 i830ContextPtr imesa = I830_CONTEXT(ctx);
277 i830TextureObjectPtr t = (i830TextureObjectPtr) tObj->DriverData;
278 GLuint unit = ctx->Texture.CurrentUnit;
279
280 assert(t);
281
282 if ( target != GL_TEXTURE_2D )
283 return;
284
285 /* Can't do the update now as we don't know whether to flush
286 * vertices or not. Setting imesa->NewGLState means that
287 * i830UpdateTextureState() will be called before any triangles are
288 * rendered. If a statechange has occurred, it will be detected at
289 * that point, and buffered vertices flushed.
290 */
291 switch (pname) {
292 case GL_TEXTURE_MIN_FILTER:
293 case GL_TEXTURE_MAG_FILTER:
294 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
295 i830SetTexMaxAnisotropy( t, tObj->MaxAnisotropy );
296 i830SetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
297 break;
298
299 case GL_TEXTURE_WRAP_S:
300 case GL_TEXTURE_WRAP_T:
301 i830SetTexWrapping( t, tObj->WrapS, tObj->WrapT );
302 break;
303
304 case GL_TEXTURE_BORDER_COLOR:
305 i830SetTexBorderColor( t, tObj->_BorderChan );
306 break;
307
308 case GL_TEXTURE_BASE_LEVEL:
309 case GL_TEXTURE_MAX_LEVEL:
310 case GL_TEXTURE_MIN_LOD:
311 case GL_TEXTURE_MAX_LOD:
312 /* The i830 and its successors can do a lot of this without
313 * reloading the textures. A project for someone?
314 */
315 I830_FIREVERTICES( I830_CONTEXT(ctx) );
316 driSwapOutTextureObject( (driTextureObject *) t );
317 break;
318
319 default:
320 return;
321 }
322
323 if (t == imesa->CurrentTexObj[unit]) {
324 I830_STATECHANGE( imesa, I830_UPLOAD_TEX0 );
325 }
326 }
327
328
329 static void i830TexEnv( GLcontext *ctx, GLenum target,
330 GLenum pname, const GLfloat *param )
331 {
332 i830ContextPtr imesa = I830_CONTEXT( ctx );
333 GLuint unit = ctx->Texture.CurrentUnit;
334
335 /* Only one env color. Need a fallback if env colors are different
336 * and texture setup references env color in both units.
337 */
338 switch (pname) {
339 case GL_TEXTURE_ENV_COLOR:
340 case GL_TEXTURE_ENV_MODE:
341 case GL_COMBINE_RGB_EXT:
342 case GL_COMBINE_ALPHA_EXT:
343 case GL_SOURCE0_RGB_EXT:
344 case GL_SOURCE1_RGB_EXT:
345 case GL_SOURCE2_RGB_EXT:
346 case GL_SOURCE0_ALPHA_EXT:
347 case GL_SOURCE1_ALPHA_EXT:
348 case GL_SOURCE2_ALPHA_EXT:
349 case GL_OPERAND0_RGB_EXT:
350 case GL_OPERAND1_RGB_EXT:
351 case GL_OPERAND2_RGB_EXT:
352 case GL_OPERAND0_ALPHA_EXT:
353 case GL_OPERAND1_ALPHA_EXT:
354 case GL_OPERAND2_ALPHA_EXT:
355 case GL_RGB_SCALE_EXT:
356 case GL_ALPHA_SCALE:
357 imesa->TexEnvImageFmt[unit] = 0; /* force recalc of env state */
358 break;
359
360 case GL_TEXTURE_LOD_BIAS_EXT:
361 i830ComputeLodBias( imesa, unit, *param );
362 I830_STATECHANGE( imesa, I830_UPLOAD_TEX_N(unit) );
363 break;
364
365 default:
366 break;
367 }
368 }
369
370 static void i830TexImage2D( GLcontext *ctx, GLenum target, GLint level,
371 GLint internalFormat,
372 GLint width, GLint height, GLint border,
373 GLenum format, GLenum type, const GLvoid *pixels,
374 const struct gl_pixelstore_attrib *packing,
375 struct gl_texture_object *texObj,
376 struct gl_texture_image *texImage )
377 {
378 driTextureObject * t = (driTextureObject *) texObj->DriverData;
379 assert(t);
380 if (t) {
381 I830_FIREVERTICES( I830_CONTEXT(ctx) );
382 driSwapOutTextureObject( t );
383 }
384 else {
385 t = (driTextureObject *) i830AllocTexObj( texObj );
386 if (!t) {
387 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
388 return;
389 }
390 }
391
392 _mesa_store_teximage2d( ctx, target, level, internalFormat,
393 width, height, border, format, type,
394 pixels, packing, texObj, texImage );
395 }
396
397 static void i830TexSubImage2D( GLcontext *ctx,
398 GLenum target,
399 GLint level,
400 GLint xoffset, GLint yoffset,
401 GLsizei width, GLsizei height,
402 GLenum format, GLenum type,
403 const GLvoid *pixels,
404 const struct gl_pixelstore_attrib *packing,
405 struct gl_texture_object *texObj,
406 struct gl_texture_image *texImage )
407 {
408 driTextureObject * t = (driTextureObject *) texObj->DriverData;
409 assert(t);
410 if (t) {
411 I830_FIREVERTICES( I830_CONTEXT(ctx) );
412 driSwapOutTextureObject( t );
413 }
414 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
415 height, format, type, pixels, packing, texObj,
416 texImage);
417
418 }
419
420
421 #if 0
422 /* no longer needed */
423 static void i830BindTexture( GLcontext *ctx, GLenum target,
424 struct gl_texture_object *tObj )
425 {
426 if (!tObj->DriverData) {
427 i830AllocTexObj( tObj );
428 }
429 }
430 #endif
431
432
433 static void i830DeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
434 {
435 driTextureObject * t = (driTextureObject *) tObj->DriverData;
436 assert(t);
437 if ( t != NULL ) {
438 i830ContextPtr imesa = I830_CONTEXT( ctx );
439
440 if ( imesa ) {
441 I830_FIREVERTICES( imesa );
442 }
443
444 driDestroyTextureObject( t );
445 }
446 /* Free mipmap images and the texture object itself */
447 _mesa_delete_texture_object(ctx, tObj);
448 }
449
450
451 static const struct gl_texture_format *
452 i830ChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
453 GLenum format, GLenum type )
454 {
455 i830ContextPtr imesa = I830_CONTEXT( ctx );
456 const GLboolean do32bpt = ( imesa->i830Screen->cpp == 4 &&
457 imesa->i830Screen->textureSize > 4*1024*1024);
458
459 switch ( internalFormat ) {
460 case 4:
461 case GL_RGBA:
462 case GL_COMPRESSED_RGBA:
463 if ( format == GL_BGRA ) {
464 if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) {
465 return &_mesa_texformat_argb8888;
466 }
467 else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) {
468 return &_mesa_texformat_argb4444;
469 }
470 else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) {
471 return &_mesa_texformat_argb1555;
472 }
473 }
474 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
475
476 case 3:
477 case GL_RGB:
478 case GL_COMPRESSED_RGB:
479 if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) {
480 return &_mesa_texformat_rgb565;
481 }
482 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
483
484 case GL_RGBA8:
485 case GL_RGB10_A2:
486 case GL_RGBA12:
487 case GL_RGBA16:
488 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
489
490 case GL_RGBA4:
491 case GL_RGBA2:
492 return &_mesa_texformat_argb4444;
493
494 case GL_RGB5_A1:
495 return &_mesa_texformat_argb1555;
496
497 case GL_RGB8:
498 case GL_RGB10:
499 case GL_RGB12:
500 case GL_RGB16:
501 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
502
503 case GL_RGB5:
504 case GL_RGB4:
505 case GL_R3_G3_B2:
506 return &_mesa_texformat_rgb565;
507
508 case GL_ALPHA:
509 case GL_ALPHA4:
510 case GL_ALPHA8:
511 case GL_ALPHA12:
512 case GL_ALPHA16:
513 case GL_COMPRESSED_ALPHA:
514 return &_mesa_texformat_al88;
515
516 case 1:
517 case GL_LUMINANCE:
518 case GL_LUMINANCE4:
519 case GL_LUMINANCE8:
520 case GL_LUMINANCE12:
521 case GL_LUMINANCE16:
522 case GL_COMPRESSED_LUMINANCE:
523 return &_mesa_texformat_l8;
524
525 case 2:
526 case GL_LUMINANCE_ALPHA:
527 case GL_LUMINANCE4_ALPHA4:
528 case GL_LUMINANCE6_ALPHA2:
529 case GL_LUMINANCE8_ALPHA8:
530 case GL_LUMINANCE12_ALPHA4:
531 case GL_LUMINANCE12_ALPHA12:
532 case GL_LUMINANCE16_ALPHA16:
533 case GL_COMPRESSED_LUMINANCE_ALPHA:
534 return &_mesa_texformat_al88;
535
536 case GL_INTENSITY:
537 case GL_INTENSITY4:
538 case GL_INTENSITY8:
539 case GL_INTENSITY12:
540 case GL_INTENSITY16:
541 case GL_COMPRESSED_INTENSITY:
542 return &_mesa_texformat_i8;
543
544 case GL_YCBCR_MESA:
545 if (type == GL_UNSIGNED_SHORT_8_8_MESA ||
546 type == GL_UNSIGNED_BYTE)
547 return &_mesa_texformat_ycbcr;
548 else
549 return &_mesa_texformat_ycbcr_rev;
550
551 default:
552 fprintf(stderr, "unexpected texture format in %s\n", __FUNCTION__);
553 return NULL;
554 }
555
556 return NULL; /* never get here */
557 }
558
559 /**
560 * Allocate a new texture object.
561 * Called via ctx->Driver.NewTextureObject.
562 * Note: this function will be called during context creation to
563 * allocate the default texture objects.
564 */
565 static struct gl_texture_object *
566 i830NewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
567 {
568 struct gl_texture_object *obj;
569 driTextureObject *t;
570 obj = _mesa_new_texture_object(ctx, name, target);
571 if (!obj)
572 return NULL;
573 t = (driTextureObject *) i830AllocTexObj( obj );
574 if (!t) {
575 _mesa_delete_texture_object(ctx, obj);
576 return NULL;
577 }
578 return obj;
579 }
580
581 void i830InitTextureFuncs( struct dd_function_table *functions )
582 {
583 functions->NewTextureObject = i830NewTextureObject;
584 functions->DeleteTexture = i830DeleteTexture;
585 functions->ChooseTextureFormat = i830ChooseTextureFormat;
586 functions->TexImage2D = i830TexImage2D;
587 functions->TexSubImage2D = i830TexSubImage2D;
588 /*functions->BindTexture = i830BindTexture;*/
589 functions->TexParameter = i830TexParameter;
590 functions->TexEnv = i830TexEnv;
591 functions->IsTextureResident = driIsTextureResident;
592 }