fc55939198c8e3471268fce21da9c53fda1b9f1a
[mesa.git] / src / mesa / drivers / dri / mach64 / mach64_tex.c
1 /* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */
2 /*
3 * Copyright 2000 Gareth Hughes
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 "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * GARETH HUGHES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /*
26 * Authors:
27 * Gareth Hughes <gareth@valinux.com>
28 * Leif Delgass <ldelgass@retinalburn.net>
29 * José Fonseca <j_r_fonseca@yahoo.co.uk>
30 */
31
32 #include "mach64_context.h"
33 #include "mach64_ioctl.h"
34 #include "mach64_state.h"
35 #include "mach64_vb.h"
36 #include "mach64_tris.h"
37 #include "mach64_tex.h"
38
39 #include "context.h"
40 #include "macros.h"
41 #include "simple_list.h"
42 #include "enums.h"
43 #include "texstore.h"
44 #include "texformat.h"
45 #include "teximage.h"
46 #include "texobj.h"
47 #include "imports.h"
48
49
50 static void mach64SetTexWrap( mach64TexObjPtr t,
51 GLenum swrap, GLenum twrap )
52 {
53 switch ( swrap ) {
54 case GL_CLAMP:
55 case GL_CLAMP_TO_EDGE:
56 case GL_CLAMP_TO_BORDER:
57 t->ClampS = GL_TRUE;
58 break;
59 case GL_REPEAT:
60 t->ClampS = GL_FALSE;
61 break;
62 }
63
64 switch ( twrap ) {
65 case GL_CLAMP:
66 case GL_CLAMP_TO_EDGE:
67 case GL_CLAMP_TO_BORDER:
68 t->ClampT = GL_TRUE;
69 break;
70 case GL_REPEAT:
71 t->ClampT = GL_FALSE;
72 break;
73 }
74 }
75
76 static void mach64SetTexFilter( mach64TexObjPtr t,
77 GLenum minf, GLenum magf )
78 {
79 switch ( minf ) {
80 case GL_NEAREST:
81 case GL_NEAREST_MIPMAP_NEAREST:
82 case GL_NEAREST_MIPMAP_LINEAR:
83 t->BilinearMin = GL_FALSE;
84 break;
85 case GL_LINEAR:
86 case GL_LINEAR_MIPMAP_NEAREST:
87 case GL_LINEAR_MIPMAP_LINEAR:
88 t->BilinearMin = GL_TRUE;
89 break;
90 }
91
92 switch ( magf ) {
93 case GL_NEAREST:
94 t->BilinearMag = GL_FALSE;
95 break;
96 case GL_LINEAR:
97 t->BilinearMag = GL_TRUE;
98 break;
99 }
100 }
101
102 static void mach64SetTexBorderColor( mach64TexObjPtr t, GLubyte c[4] )
103 {
104 #if 0
105 GLuint border = mach64PackColor( 4, c[0], c[1], c[2], c[3] );
106 #endif
107 }
108
109
110 static mach64TexObjPtr
111 mach64AllocTexObj( struct gl_texture_object *texObj )
112 {
113 mach64TexObjPtr t;
114
115 if ( MACH64_DEBUG & DEBUG_VERBOSE_API )
116 fprintf( stderr, "%s( %p )\n", __FUNCTION__, texObj );
117
118 t = (mach64TexObjPtr) CALLOC_STRUCT( mach64_texture_object );
119 if ( !t )
120 return NULL;
121
122 /* Initialize non-image-dependent parts of the state:
123 */
124 t->tObj = texObj;
125
126 t->offset = 0;
127
128 t->dirty = 1;
129
130 make_empty_list( t );
131
132 mach64SetTexWrap( t, texObj->WrapS, texObj->WrapT );
133 /*mach64SetTexMaxAnisotropy( t, texObj->MaxAnisotropy );*/
134 mach64SetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
135 mach64SetTexBorderColor( t, texObj->_BorderChan );
136
137 return t;
138 }
139
140
141 /* Called by the _mesa_store_teximage[123]d() functions. */
142 static const struct gl_texture_format *
143 mach64ChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
144 GLenum format, GLenum type )
145 {
146 mach64ContextPtr mmesa = MACH64_CONTEXT(ctx);
147 (void) format;
148 (void) type;
149
150 switch ( internalFormat ) {
151 case GL_ALPHA:
152 case GL_ALPHA4:
153 case GL_ALPHA8:
154 case GL_ALPHA12:
155 case GL_ALPHA16:
156 case 2:
157 case GL_LUMINANCE_ALPHA:
158 case GL_LUMINANCE4_ALPHA4:
159 case GL_LUMINANCE6_ALPHA2:
160 case GL_LUMINANCE8_ALPHA8:
161 case GL_LUMINANCE12_ALPHA4:
162 case GL_LUMINANCE12_ALPHA12:
163 case GL_LUMINANCE16_ALPHA16:
164 case 4:
165 case GL_RGBA:
166 case GL_RGBA2:
167 if (mmesa->mach64Screen->cpp == 4)
168 return &_mesa_texformat_argb8888;
169 else
170 return &_mesa_texformat_argb4444;
171
172 case GL_RGB5_A1:
173 if (mmesa->mach64Screen->cpp == 4)
174 return &_mesa_texformat_argb8888;
175 else
176 return &_mesa_texformat_argb1555;
177
178 case GL_RGBA8:
179 case GL_RGB10_A2:
180 case GL_RGBA12:
181 case GL_RGBA16:
182 case GL_RGBA4:
183 if (mmesa->mach64Screen->cpp == 4)
184 return &_mesa_texformat_argb8888;
185 else
186 return &_mesa_texformat_argb4444;
187
188 case 3:
189 case GL_RGB:
190 case GL_R3_G3_B2:
191 case GL_RGB4:
192 case GL_RGB5:
193 case GL_RGB8:
194 case GL_RGB10:
195 case GL_RGB12:
196 case GL_RGB16:
197 if (mmesa->mach64Screen->cpp == 4)
198 return &_mesa_texformat_argb8888;
199 else
200 return &_mesa_texformat_rgb565;
201
202 case 1:
203 case GL_LUMINANCE:
204 case GL_LUMINANCE4:
205 case GL_LUMINANCE8:
206 case GL_LUMINANCE12:
207 case GL_LUMINANCE16:
208 if (mmesa->mach64Screen->cpp == 4)
209 return &_mesa_texformat_argb8888; /* inefficient but accurate */
210 else
211 return &_mesa_texformat_argb1555;
212
213 case GL_INTENSITY4:
214 case GL_INTENSITY:
215 case GL_INTENSITY8:
216 case GL_INTENSITY12:
217 case GL_INTENSITY16:
218 if (mmesa->mach64Screen->cpp == 4)
219 return &_mesa_texformat_argb8888; /* inefficient but accurate */
220 else
221 return &_mesa_texformat_argb4444;
222
223 case GL_COLOR_INDEX:
224 case GL_COLOR_INDEX1_EXT:
225 case GL_COLOR_INDEX2_EXT:
226 case GL_COLOR_INDEX4_EXT:
227 case GL_COLOR_INDEX8_EXT:
228 case GL_COLOR_INDEX12_EXT:
229 case GL_COLOR_INDEX16_EXT:
230 return &_mesa_texformat_ci8;
231
232 case GL_YCBCR_MESA:
233 if (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
234 type == GL_UNSIGNED_BYTE)
235 return &_mesa_texformat_ycbcr;
236 else
237 return &_mesa_texformat_ycbcr_rev;
238
239 default:
240 _mesa_problem( ctx, "unexpected format in %s", __FUNCTION__ );
241 return NULL;
242 }
243 }
244
245 static void mach64TexImage1D( GLcontext *ctx, GLenum target, GLint level,
246 GLint internalFormat,
247 GLint width, GLint border,
248 GLenum format, GLenum type, const GLvoid *pixels,
249 const struct gl_pixelstore_attrib *packing,
250 struct gl_texture_object *texObj,
251 struct gl_texture_image *texImage )
252 {
253 mach64ContextPtr mmesa = MACH64_CONTEXT(ctx);
254 mach64TexObjPtr t = (mach64TexObjPtr) texObj->DriverData;
255
256 if ( t ) {
257 mach64SwapOutTexObj( mmesa, t );
258 }
259 else {
260 t = mach64AllocTexObj(texObj);
261 if (!t) {
262 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
263 return;
264 }
265 texObj->DriverData = t;
266 }
267
268 /* Note, this will call mach64ChooseTextureFormat */
269 _mesa_store_teximage1d( ctx, target, level, internalFormat,
270 width, border, format, type,
271 pixels, packing, texObj, texImage );
272
273 mmesa->new_state |= MACH64_NEW_TEXTURE;
274 }
275
276 static void mach64TexSubImage1D( GLcontext *ctx,
277 GLenum target,
278 GLint level,
279 GLint xoffset,
280 GLsizei width,
281 GLenum format, GLenum type,
282 const GLvoid *pixels,
283 const struct gl_pixelstore_attrib *packing,
284 struct gl_texture_object *texObj,
285 struct gl_texture_image *texImage )
286 {
287 mach64ContextPtr mmesa = MACH64_CONTEXT(ctx);
288 mach64TexObjPtr t = (mach64TexObjPtr) texObj->DriverData;
289
290 assert( t ); /* this _should_ be true */
291 if ( t ) {
292 mach64SwapOutTexObj( mmesa, t );
293 }
294 else {
295 t = mach64AllocTexObj(texObj);
296 if (!t) {
297 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
298 return;
299 }
300 texObj->DriverData = t;
301 }
302
303 _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
304 format, type, pixels, packing, texObj,
305 texImage);
306
307 mmesa->new_state |= MACH64_NEW_TEXTURE;
308 }
309
310 static void mach64TexImage2D( GLcontext *ctx, GLenum target, GLint level,
311 GLint internalFormat,
312 GLint width, GLint height, GLint border,
313 GLenum format, GLenum type, const GLvoid *pixels,
314 const struct gl_pixelstore_attrib *packing,
315 struct gl_texture_object *texObj,
316 struct gl_texture_image *texImage )
317 {
318 mach64ContextPtr mmesa = MACH64_CONTEXT(ctx);
319 mach64TexObjPtr t = (mach64TexObjPtr) texObj->DriverData;
320
321 if ( t ) {
322 mach64SwapOutTexObj( mmesa, t );
323 }
324 else {
325 t = mach64AllocTexObj(texObj);
326 if (!t) {
327 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
328 return;
329 }
330 texObj->DriverData = t;
331 }
332
333 /* Note, this will call mach64ChooseTextureFormat */
334 _mesa_store_teximage2d( ctx, target, level, internalFormat,
335 width, height, border, format, type, pixels,
336 &ctx->Unpack, texObj, texImage );
337
338 mmesa->new_state |= MACH64_NEW_TEXTURE;
339 }
340
341 static void mach64TexSubImage2D( GLcontext *ctx,
342 GLenum target,
343 GLint level,
344 GLint xoffset, GLint yoffset,
345 GLsizei width, GLsizei height,
346 GLenum format, GLenum type,
347 const GLvoid *pixels,
348 const struct gl_pixelstore_attrib *packing,
349 struct gl_texture_object *texObj,
350 struct gl_texture_image *texImage )
351 {
352 mach64ContextPtr mmesa = MACH64_CONTEXT(ctx);
353 mach64TexObjPtr t = (mach64TexObjPtr) texObj->DriverData;
354
355 assert( t ); /* this _should_ be true */
356 if ( t ) {
357 mach64SwapOutTexObj( mmesa, t );
358 }
359 else {
360 t = mach64AllocTexObj(texObj);
361 if (!t) {
362 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
363 return;
364 }
365 texObj->DriverData = t;
366 }
367
368 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
369 height, format, type, pixels, packing, texObj,
370 texImage);
371
372 mmesa->new_state |= MACH64_NEW_TEXTURE;
373 }
374
375 /* Due to the way we must program texture state into the Rage Pro,
376 * we must leave these calculations to the absolute last minute.
377 */
378 void mach64EmitTexStateLocked( mach64ContextPtr mmesa,
379 mach64TexObjPtr t0,
380 mach64TexObjPtr t1 )
381 {
382 ATISAREAPrivPtr sarea = mmesa->sarea;
383 mach64_context_regs_t *regs = &(mmesa->setup);
384
385 /* for multitex, both textures must be local or AGP */
386 if ( t0 && t1 )
387 assert(t0->heap == t1->heap);
388
389 if ( t0 ) {
390 if (t0->heap == MACH64_CARD_HEAP) {
391 #if ENABLE_PERF_BOXES
392 mmesa->c_texsrc_card++;
393 #endif
394 mmesa->setup.tex_cntl &= ~MACH64_TEX_SRC_AGP;
395 } else {
396 #if ENABLE_PERF_BOXES
397 mmesa->c_texsrc_agp++;
398 #endif
399 mmesa->setup.tex_cntl |= MACH64_TEX_SRC_AGP;
400 }
401 mmesa->setup.tex_offset = t0->offset;
402 }
403
404 if ( t1 ) {
405 mmesa->setup.secondary_tex_off = t1->offset;
406 }
407
408 memcpy( &sarea->ContextState.tex_size_pitch, &regs->tex_size_pitch,
409 MACH64_NR_TEXTURE_REGS * sizeof(GLuint) );
410 }
411
412
413 /* ================================================================
414 * Device Driver API texture functions
415 */
416
417 static void mach64DDTexEnv( GLcontext *ctx, GLenum target,
418 GLenum pname, const GLfloat *param )
419 {
420 mach64ContextPtr mmesa = MACH64_CONTEXT(ctx);
421 #if 0
422 struct gl_texture_unit *texUnit;
423 GLubyte c[4];
424 #endif
425
426 if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) {
427 fprintf( stderr, "%s( %s )\n",
428 __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
429 }
430
431 switch ( pname ) {
432 case GL_TEXTURE_ENV_MODE:
433 FLUSH_BATCH( mmesa );
434 mmesa->new_state |= MACH64_NEW_TEXTURE | MACH64_NEW_ALPHA;
435 break;
436
437 #if 0
438 case GL_TEXTURE_ENV_COLOR:
439 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
440 CLAMPED_FLOAT_TO_UBYTE( c[0], texUnit->EnvColor[0] );
441 CLAMPED_FLOAT_TO_UBYTE( c[1], texUnit->EnvColor[1] );
442 CLAMPED_FLOAT_TO_UBYTE( c[2], texUnit->EnvColor[2] );
443 CLAMPED_FLOAT_TO_UBYTE( c[3], texUnit->EnvColor[3] );
444 mmesa->env_color = mach64PackColor( 32, c[0], c[1], c[2], c[3] );
445 if ( mmesa->setup.constant_color_c != mmesa->env_color ) {
446 FLUSH_BATCH( mmesa );
447 mmesa->setup.constant_color_c = mmesa->env_color;
448
449 mmesa->new_state |= MACH64_NEW_TEXTURE;
450
451 /* More complex multitexture/multipass fallbacks for GL_BLEND
452 * can be done later, but this allows a single pass GL_BLEND
453 * in some cases (ie. Performer town demo).
454 */
455 mmesa->blend_flags &= ~MACH64_BLEND_ENV_COLOR;
456 if ( mmesa->env_color != 0x00000000 &&
457 mmesa->env_color != 0xff000000 &&
458 mmesa->env_color != 0x00ffffff &&
459 mmesa->env_color != 0xffffffff )) {
460 mmesa->blend_flags |= MACH64_BLEND_ENV_COLOR;
461 }
462 }
463 break;
464 #endif
465
466 default:
467 return;
468 }
469 }
470
471 static void mach64DDTexParameter( GLcontext *ctx, GLenum target,
472 struct gl_texture_object *tObj,
473 GLenum pname, const GLfloat *params )
474 {
475 mach64ContextPtr mmesa = MACH64_CONTEXT(ctx);
476 mach64TexObjPtr t = (mach64TexObjPtr)tObj->DriverData;
477
478 if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) {
479 fprintf( stderr, "%s( %s )\n",
480 __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
481 }
482
483 if ( ( target != GL_TEXTURE_2D ) &&
484 ( target != GL_TEXTURE_1D ) ) {
485 return;
486 }
487
488 if (!t) {
489 t = mach64AllocTexObj(tObj);
490 if (!t) {
491 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexParameter");
492 return;
493 }
494 tObj->DriverData = t;
495 }
496
497 switch ( pname ) {
498 case GL_TEXTURE_MIN_FILTER:
499 case GL_TEXTURE_MAG_FILTER:
500 if ( t->bound ) FLUSH_BATCH( mmesa );
501 mach64SetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
502 break;
503
504 case GL_TEXTURE_WRAP_S:
505 case GL_TEXTURE_WRAP_T:
506 if ( t->bound ) FLUSH_BATCH( mmesa );
507 mach64SetTexWrap( t, tObj->WrapS, tObj->WrapT );
508 break;
509
510 case GL_TEXTURE_BORDER_COLOR:
511 if ( t->bound ) FLUSH_BATCH( mmesa );
512 mach64SetTexBorderColor( t, tObj->_BorderChan );
513 break;
514
515 case GL_TEXTURE_BASE_LEVEL:
516 /* From Radeon/Rage128:
517 * This isn't the most efficient solution but there doesn't appear to
518 * be a nice alternative. Since there's no LOD clamping,
519 * we just have to rely on loading the right subset of mipmap levels
520 * to simulate a clamped LOD.
521 *
522 * For mach64 we're only concerned with the base level
523 * since that's the only texture we upload.
524 */
525 if ( t->bound ) FLUSH_BATCH( mmesa );
526 mach64SwapOutTexObj( mmesa, t );
527 break;
528
529 default:
530 return;
531 }
532
533 mmesa->new_state |= MACH64_NEW_TEXTURE;
534 }
535
536 static void mach64DDBindTexture( GLcontext *ctx, GLenum target,
537 struct gl_texture_object *tObj )
538 {
539 mach64ContextPtr mmesa = MACH64_CONTEXT(ctx);
540 GLint unit = ctx->Texture.CurrentUnit;
541
542 if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) {
543 fprintf( stderr, "%s( %p ) unit=%d\n",
544 __FUNCTION__, tObj, unit );
545 }
546
547 FLUSH_BATCH( mmesa );
548
549 if ( mmesa->CurrentTexObj[unit] ) {
550 mmesa->CurrentTexObj[unit]->bound &= ~(unit+1);
551 mmesa->CurrentTexObj[unit] = NULL;
552 }
553
554 mmesa->new_state |= MACH64_NEW_TEXTURE;
555 }
556
557 static void mach64DDDeleteTexture( GLcontext *ctx,
558 struct gl_texture_object *tObj )
559 {
560 mach64ContextPtr mmesa = MACH64_CONTEXT(ctx);
561 mach64TexObjPtr t = (mach64TexObjPtr)tObj->DriverData;
562
563 if ( t ) {
564 if ( t->bound && mmesa ) {
565 FLUSH_BATCH( mmesa );
566
567 mmesa->CurrentTexObj[t->bound-1] = 0;
568 mmesa->new_state |= MACH64_NEW_TEXTURE;
569 }
570
571 mach64DestroyTexObj( mmesa, t );
572 tObj->DriverData = NULL;
573 /* Free mipmap images and the texture object itself */
574 _mesa_delete_texture_object(ctx, tObj);
575
576 }
577 }
578
579 static GLboolean mach64DDIsTextureResident( GLcontext *ctx,
580 struct gl_texture_object *tObj )
581 {
582 mach64TexObjPtr t = (mach64TexObjPtr)tObj->DriverData;
583
584 return ( t && t->memBlock );
585 }
586
587
588 void mach64InitTextureFuncs( struct dd_function_table *functions )
589 {
590 functions->TexEnv = mach64DDTexEnv;
591 functions->ChooseTextureFormat = mach64ChooseTextureFormat;
592 functions->TexImage1D = mach64TexImage1D;
593 functions->TexSubImage1D = mach64TexSubImage1D;
594 functions->TexImage2D = mach64TexImage2D;
595 functions->TexSubImage2D = mach64TexSubImage2D;
596 functions->TexImage3D = _mesa_store_teximage3d;
597 functions->TexSubImage3D = _mesa_store_texsubimage3d;
598 functions->CopyTexImage1D = _swrast_copy_teximage1d;
599 functions->CopyTexImage2D = _swrast_copy_teximage2d;
600 functions->CopyTexSubImage1D = _swrast_copy_texsubimage1d;
601 functions->CopyTexSubImage2D = _swrast_copy_texsubimage2d;
602 functions->CopyTexSubImage3D = _swrast_copy_texsubimage3d;
603 functions->TexParameter = mach64DDTexParameter;
604 functions->BindTexture = mach64DDBindTexture;
605 functions->DeleteTexture = mach64DDDeleteTexture;
606 functions->UpdateTexturePalette = NULL;
607 functions->ActiveTexture = NULL;
608 functions->IsTextureResident = mach64DDIsTextureResident;
609 functions->PrioritizeTexture = NULL;
610 }