add the i830 driver - no kernel driver yet
[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
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 if (!t)
280 return;
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 if (t) {
380 I830_FIREVERTICES( I830_CONTEXT(ctx) );
381 driSwapOutTextureObject( t );
382 }
383 else {
384 t = (driTextureObject *) i830AllocTexObj( texObj );
385 if (!t) {
386 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
387 return;
388 }
389 }
390
391 _mesa_store_teximage2d( ctx, target, level, internalFormat,
392 width, height, border, format, type,
393 pixels, packing, texObj, texImage );
394 }
395
396 static void i830TexSubImage2D( GLcontext *ctx,
397 GLenum target,
398 GLint level,
399 GLint xoffset, GLint yoffset,
400 GLsizei width, GLsizei height,
401 GLenum format, GLenum type,
402 const GLvoid *pixels,
403 const struct gl_pixelstore_attrib *packing,
404 struct gl_texture_object *texObj,
405 struct gl_texture_image *texImage )
406 {
407 driTextureObject * t = (driTextureObject *) texObj->DriverData;
408 if (t) {
409 I830_FIREVERTICES( I830_CONTEXT(ctx) );
410 driSwapOutTextureObject( t );
411 }
412 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
413 height, format, type, pixels, packing, texObj,
414 texImage);
415
416 }
417
418
419 static void i830BindTexture( GLcontext *ctx, GLenum target,
420 struct gl_texture_object *tObj )
421 {
422 if (!tObj->DriverData) {
423 i830AllocTexObj( tObj );
424 }
425 }
426
427
428 static void i830DeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
429 {
430 driTextureObject * t = (driTextureObject *) tObj->DriverData;
431
432 if ( t != NULL ) {
433 i830ContextPtr imesa = I830_CONTEXT( ctx );
434
435 if ( imesa ) {
436 I830_FIREVERTICES( imesa );
437 }
438
439 driDestroyTextureObject( t );
440 }
441 }
442
443
444 static const struct gl_texture_format *
445 i830ChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
446 GLenum format, GLenum type )
447 {
448 i830ContextPtr imesa = I830_CONTEXT( ctx );
449 const GLboolean do32bpt = ( imesa->i830Screen->cpp == 4 &&
450 imesa->i830Screen->textureSize > 4*1024*1024);
451
452 switch ( internalFormat ) {
453 case 4:
454 case GL_RGBA:
455 case GL_COMPRESSED_RGBA:
456 if ( format == GL_BGRA ) {
457 if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) {
458 return &_mesa_texformat_argb8888;
459 }
460 else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) {
461 return &_mesa_texformat_argb4444;
462 }
463 else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) {
464 return &_mesa_texformat_argb1555;
465 }
466 }
467 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
468
469 case 3:
470 case GL_RGB:
471 case GL_COMPRESSED_RGB:
472 if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) {
473 return &_mesa_texformat_rgb565;
474 }
475 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
476
477 case GL_RGBA8:
478 case GL_RGB10_A2:
479 case GL_RGBA12:
480 case GL_RGBA16:
481 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
482
483 case GL_RGBA4:
484 case GL_RGBA2:
485 return &_mesa_texformat_argb4444;
486
487 case GL_RGB5_A1:
488 return &_mesa_texformat_argb1555;
489
490 case GL_RGB8:
491 case GL_RGB10:
492 case GL_RGB12:
493 case GL_RGB16:
494 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
495
496 case GL_RGB5:
497 case GL_RGB4:
498 case GL_R3_G3_B2:
499 return &_mesa_texformat_rgb565;
500
501 case GL_ALPHA:
502 case GL_ALPHA4:
503 case GL_ALPHA8:
504 case GL_ALPHA12:
505 case GL_ALPHA16:
506 case GL_COMPRESSED_ALPHA:
507 return &_mesa_texformat_al88;
508
509 case 1:
510 case GL_LUMINANCE:
511 case GL_LUMINANCE4:
512 case GL_LUMINANCE8:
513 case GL_LUMINANCE12:
514 case GL_LUMINANCE16:
515 case GL_COMPRESSED_LUMINANCE:
516 return &_mesa_texformat_l8;
517
518 case 2:
519 case GL_LUMINANCE_ALPHA:
520 case GL_LUMINANCE4_ALPHA4:
521 case GL_LUMINANCE6_ALPHA2:
522 case GL_LUMINANCE8_ALPHA8:
523 case GL_LUMINANCE12_ALPHA4:
524 case GL_LUMINANCE12_ALPHA12:
525 case GL_LUMINANCE16_ALPHA16:
526 case GL_COMPRESSED_LUMINANCE_ALPHA:
527 return &_mesa_texformat_al88;
528
529 case GL_INTENSITY:
530 case GL_INTENSITY4:
531 case GL_INTENSITY8:
532 case GL_INTENSITY12:
533 case GL_INTENSITY16:
534 case GL_COMPRESSED_INTENSITY:
535 return &_mesa_texformat_i8;
536
537 case GL_YCBCR_MESA:
538 if (type == GL_UNSIGNED_SHORT_8_8_MESA ||
539 type == GL_UNSIGNED_BYTE)
540 return &_mesa_texformat_ycbcr;
541 else
542 return &_mesa_texformat_ycbcr_rev;
543
544 default:
545 fprintf(stderr, "unexpected texture format in %s\n", __FUNCTION__);
546 return NULL;
547 }
548
549 return NULL; /* never get here */
550 }
551
552 void i830DDInitTextureFuncs( GLcontext *ctx )
553 {
554 i830ContextPtr imesa = I830_CONTEXT(ctx);
555
556 ctx->Driver.TexEnv = i830TexEnv;
557 ctx->Driver.ChooseTextureFormat = i830ChooseTextureFormat;
558 ctx->Driver.TexImage1D = _mesa_store_teximage1d;
559 ctx->Driver.TexImage2D = i830TexImage2D;
560 ctx->Driver.TexImage3D = _mesa_store_teximage3d;
561 ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
562 ctx->Driver.TexSubImage2D = i830TexSubImage2D;
563 ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
564 ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d;
565 ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d;
566 ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d;
567 ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d;
568 ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d;
569 ctx->Driver.BindTexture = i830BindTexture;
570 ctx->Driver.DeleteTexture = i830DeleteTexture;
571 ctx->Driver.TexParameter = i830TexParameter;
572 ctx->Driver.UpdateTexturePalette = NULL;
573 ctx->Driver.IsTextureResident = driIsTextureResident;
574 ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage;
575
576 driInitTextureObjects( ctx, & imesa->swapped,
577 DRI_TEXMGR_DO_TEXTURE_2D
578 | DRI_TEXMGR_DO_TEXTURE_RECT );
579 }