0aa09e733befa3063055e0a354d9c49aa868a699
[mesa.git] / src / mesa / drivers / dri / tdfx / tdfx_tex.c
1 /* -*- mode: c; c-basic-offset: 3 -*-
2 *
3 * Copyright 2000 VA Linux Systems Inc., Fremont, California.
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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * 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 NONINFRINGEMENT. IN NO EVENT SHALL
21 * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
23 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27 /*
28 * New fixes:
29 * Daniel Borca <dborca@users.sourceforge.net>, 19 Jul 2004
30 *
31 * Original rewrite:
32 * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
33 *
34 * Authors:
35 * Gareth Hughes <gareth@valinux.com>
36 * Brian Paul <brianp@valinux.com>
37 *
38 */
39
40
41 #include "main/enums.h"
42 #include "main/image.h"
43 #include "main/mipmap.h"
44 #include "main/texcompress.h"
45 #include "main/teximage.h"
46 #include "main/texstore.h"
47 #include "main/texobj.h"
48 #include "tdfx_context.h"
49 #include "tdfx_tex.h"
50 #include "tdfx_texman.h"
51
52
53 /* no borders! can't halve 1x1! (stride > width * comp) not allowed */
54 static void
55 _mesa_halve2x2_teximage2d ( GLcontext *ctx,
56 struct gl_texture_image *texImage,
57 GLuint bytesPerPixel,
58 GLint srcWidth, GLint srcHeight,
59 const GLvoid *srcImage, GLvoid *dstImage )
60 {
61 GLint i, j, k;
62 GLint dstWidth = srcWidth / 2;
63 GLint dstHeight = srcHeight / 2;
64 GLint srcRowStride = srcWidth * bytesPerPixel;
65 GLubyte *src = (GLubyte *)srcImage;
66 GLubyte *dst = dstImage;
67 GLuint dstImageOffsets = 0;
68
69 GLuint bpt = 0;
70 GLubyte *_s = NULL;
71 GLubyte *_d = NULL;
72 GLenum _t = 0;
73
74 if (texImage->TexFormat == MESA_FORMAT_RGB565) {
75 _t = GL_UNSIGNED_SHORT_5_6_5_REV;
76 bpt = bytesPerPixel;
77 } else if (texImage->TexFormat == MESA_FORMAT_ARGB4444) {
78 _t = GL_UNSIGNED_SHORT_4_4_4_4_REV;
79 bpt = bytesPerPixel;
80 } else if (texImage->TexFormat == MESA_FORMAT_ARGB1555) {
81 _t = GL_UNSIGNED_SHORT_1_5_5_5_REV;
82 bpt = bytesPerPixel;
83 }
84 if (bpt) {
85 bytesPerPixel = 4;
86 srcRowStride = srcWidth * bytesPerPixel;
87 if (dstWidth == 0) {
88 dstWidth = 1;
89 }
90 if (dstHeight == 0) {
91 dstHeight = 1;
92 }
93 _s = src = MALLOC(srcRowStride * srcHeight);
94 _d = dst = MALLOC(dstWidth * bytesPerPixel * dstHeight);
95 _mesa_texstore(ctx, 2, GL_RGBA,
96 MESA_FORMAT_RGBA8888_REV, src,
97 0, 0, 0, /* dstX/Y/Zoffset */
98 srcRowStride, /* dstRowStride */
99 &dstImageOffsets,
100 srcWidth, srcHeight, 1,
101 texImage->_BaseFormat, _t, srcImage, &ctx->DefaultPacking);
102 }
103
104 if (srcHeight == 1) {
105 for (i = 0; i < dstWidth; i++) {
106 for (k = 0; k < bytesPerPixel; k++) {
107 dst[0] = (src[0] + src[bytesPerPixel] + 1) / 2;
108 src++;
109 dst++;
110 }
111 src += bytesPerPixel;
112 }
113 } else if (srcWidth == 1) {
114 for (j = 0; j < dstHeight; j++) {
115 for (k = 0; k < bytesPerPixel; k++) {
116 dst[0] = (src[0] + src[srcRowStride] + 1) / 2;
117 src++;
118 dst++;
119 }
120 src += srcRowStride;
121 }
122 } else {
123 for (j = 0; j < dstHeight; j++) {
124 for (i = 0; i < dstWidth; i++) {
125 for (k = 0; k < bytesPerPixel; k++) {
126 dst[0] = (src[0] +
127 src[bytesPerPixel] +
128 src[srcRowStride] +
129 src[srcRowStride + bytesPerPixel] + 2) / 4;
130 src++;
131 dst++;
132 }
133 src += bytesPerPixel;
134 }
135 src += srcRowStride;
136 }
137 }
138
139 if (bpt) {
140 src = _s;
141 dst = _d;
142 _mesa_texstore(ctx, 2, texImage->_BaseFormat,
143 texImage->TexFormat, dstImage,
144 0, 0, 0, /* dstX/Y/Zoffset */
145 dstWidth * bpt,
146 &dstImageOffsets,
147 dstWidth, dstHeight, 1,
148 GL_BGRA, CHAN_TYPE, dst, &ctx->DefaultPacking);
149 FREE(dst);
150 FREE(src);
151 }
152 }
153
154
155 static int
156 logbase2(int n)
157 {
158 GLint i = 1;
159 GLint log2 = 0;
160
161 if (n < 0) {
162 return -1;
163 }
164
165 while (n > i) {
166 i *= 2;
167 log2++;
168 }
169 if (i != n) {
170 return -1;
171 }
172 else {
173 return log2;
174 }
175 }
176
177
178 static void
179 tdfxGenerateMipmap(GLcontext *ctx, GLenum target,
180 struct gl_texture_object *texObj)
181 {
182 GLint mipWidth, mipHeight;
183 tdfxMipMapLevel *mip;
184 struct gl_texture_image *mipImage; /* the new/next image */
185 struct gl_texture_image *texImage;
186 const GLint maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
187 GLint level = texObj->BaseLevel;
188 GLsizei width, height, texelBytes;
189 const tdfxMipMapLevel *mml;
190
191 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
192 texelBytes = _mesa_get_format_bytes(texImage->TexFormat);
193
194 mml = TDFX_TEXIMAGE_DATA(texImage);
195
196 width = texImage->Width;
197 height = texImage->Height;
198 while (level < texObj->MaxLevel && level < maxLevels - 1) {
199 mipWidth = width / 2;
200 if (!mipWidth) {
201 mipWidth = 1;
202 }
203 mipHeight = height / 2;
204 if (!mipHeight) {
205 mipHeight = 1;
206 }
207 if ((mipWidth == width) && (mipHeight == height)) {
208 break;
209 }
210 ++level;
211 mipImage = _mesa_select_tex_image(ctx, texObj, target, level);
212 mip = TDFX_TEXIMAGE_DATA(mipImage);
213 _mesa_halve2x2_teximage2d(ctx,
214 texImage,
215 texelBytes,
216 mml->width, mml->height,
217 texImage->Data, mipImage->Data);
218 texImage = mipImage;
219 mml = mip;
220 width = mipWidth;
221 height = mipHeight;
222 }
223 }
224
225
226 /*
227 * Compute various texture image parameters.
228 * Input: w, h - source texture width and height
229 * Output: lodlevel - Glide lod level token for the larger texture dimension
230 * aspectratio - Glide aspect ratio token
231 * sscale - S scale factor used during triangle setup
232 * tscale - T scale factor used during triangle setup
233 * wscale - OpenGL -> Glide image width scale factor
234 * hscale - OpenGL -> Glide image height scale factor
235 *
236 * Sample results:
237 * w h lodlevel aspectRatio
238 * 128 128 GR_LOD_LOG2_128 (=7) GR_ASPECT_LOG2_1x1 (=0)
239 * 64 64 GR_LOD_LOG2_64 (=6) GR_ASPECT_LOG2_1x1 (=0)
240 * 64 32 GR_LOD_LOG2_64 (=6) GR_ASPECT_LOG2_2x1 (=1)
241 * 32 64 GR_LOD_LOG2_64 (=6) GR_ASPECT_LOG2_1x2 (=-1)
242 * 32 32 GR_LOD_LOG2_32 (=5) GR_ASPECT_LOG2_1x1 (=0)
243 */
244 static void
245 tdfxTexGetInfo(const GLcontext *ctx, int w, int h,
246 GrLOD_t *lodlevel, GrAspectRatio_t *aspectratio,
247 float *sscale, float *tscale,
248 int *wscale, int *hscale)
249 {
250 int logw, logh, ar, lod, ws, hs;
251 float s, t;
252
253 ASSERT(w >= 1);
254 ASSERT(h >= 1);
255
256 logw = logbase2(w);
257 logh = logbase2(h);
258 ar = logw - logh; /* aspect ratio = difference in log dimensions */
259 s = t = 256.0;
260 ws = hs = 1;
261
262 /* Hardware only allows a maximum aspect ratio of 8x1, so handle
263 |ar| > 3 by scaling the image and using an 8x1 aspect ratio */
264 if (ar >= 0) {
265 ASSERT(w >= h);
266 lod = logw;
267 if (ar <= GR_ASPECT_LOG2_8x1) {
268 t = 256 >> ar;
269 }
270 else {
271 /* have to stretch image height */
272 t = 32.0;
273 hs = 1 << (ar - 3);
274 ar = GR_ASPECT_LOG2_8x1;
275 }
276 }
277 else {
278 ASSERT(w < h);
279 lod = logh;
280 if (ar >= GR_ASPECT_LOG2_1x8) {
281 s = 256 >> -ar;
282 }
283 else {
284 /* have to stretch image width */
285 s = 32.0;
286 ws = 1 << (-ar - 3);
287 ar = GR_ASPECT_LOG2_1x8;
288 }
289 }
290
291 if (lodlevel)
292 *lodlevel = (GrLOD_t) lod;
293 if (aspectratio)
294 *aspectratio = (GrAspectRatio_t) ar;
295 if (sscale)
296 *sscale = s;
297 if (tscale)
298 *tscale = t;
299 if (wscale)
300 *wscale = ws;
301 if (hscale)
302 *hscale = hs;
303 }
304
305
306 /*
307 * We need to call this when a texture object's minification filter
308 * or texture image sizes change.
309 */
310 static void RevalidateTexture(GLcontext *ctx, struct gl_texture_object *tObj)
311 {
312 tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
313 GLint minl, maxl;
314
315 if (!ti)
316 return;
317
318 minl = maxl = tObj->BaseLevel;
319
320 if (tObj->Image[0][minl]) {
321 maxl = MIN2(tObj->MaxLevel, tObj->Image[0][minl]->MaxLog2);
322
323 /* compute largeLodLog2, aspect ratio and texcoord scale factors */
324 tdfxTexGetInfo(ctx, tObj->Image[0][minl]->Width, tObj->Image[0][minl]->Height,
325 &ti->info.largeLodLog2,
326 &ti->info.aspectRatioLog2,
327 &(ti->sScale), &(ti->tScale), NULL, NULL);
328 }
329
330 if (tObj->Image[0][maxl] && (tObj->MinFilter != GL_NEAREST) && (tObj->MinFilter != GL_LINEAR)) {
331 /* mipmapping: need to compute smallLodLog2 */
332 tdfxTexGetInfo(ctx, tObj->Image[0][maxl]->Width,
333 tObj->Image[0][maxl]->Height,
334 &ti->info.smallLodLog2, NULL,
335 NULL, NULL, NULL, NULL);
336 }
337 else {
338 /* not mipmapping: smallLodLog2 = largeLodLog2 */
339 ti->info.smallLodLog2 = ti->info.largeLodLog2;
340 maxl = minl;
341 }
342
343 ti->minLevel = minl;
344 ti->maxLevel = maxl;
345 ti->info.data = NULL;
346
347 /* this is necessary because of fxDDCompressedTexImage2D */
348 if (ti->padded) {
349 struct gl_texture_image *texImage = tObj->Image[0][minl];
350 tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
351 if (mml->wScale != 1 || mml->hScale != 1) {
352 ti->sScale /= mml->wScale;
353 ti->tScale /= mml->hScale;
354 }
355 }
356 }
357
358
359 static tdfxTexInfo *
360 fxAllocTexObjData(tdfxContextPtr fxMesa)
361 {
362 tdfxTexInfo *ti;
363
364 if (!(ti = CALLOC(sizeof(tdfxTexInfo)))) {
365 _mesa_problem(NULL, "tdfx driver: out of memory");
366 return NULL;
367 }
368
369 ti->isInTM = GL_FALSE;
370
371 ti->whichTMU = TDFX_TMU_NONE;
372
373 ti->tm[TDFX_TMU0] = NULL;
374 ti->tm[TDFX_TMU1] = NULL;
375
376 ti->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
377 ti->magFilt = GR_TEXTUREFILTER_BILINEAR;
378
379 ti->sClamp = GR_TEXTURECLAMP_WRAP;
380 ti->tClamp = GR_TEXTURECLAMP_WRAP;
381
382 ti->mmMode = GR_MIPMAP_NEAREST;
383 ti->LODblend = FXFALSE;
384
385 return ti;
386 }
387
388
389 /*
390 * Called via glBindTexture.
391 */
392 static void
393 tdfxBindTexture(GLcontext * ctx, GLenum target,
394 struct gl_texture_object *tObj)
395 {
396 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
397 tdfxTexInfo *ti;
398
399 if (MESA_VERBOSE & VERBOSE_DRIVER) {
400 fprintf(stderr, "fxmesa: fxDDTexBind(%d,%p)\n", tObj->Name,
401 tObj->DriverData);
402 }
403
404 if ((target != GL_TEXTURE_1D) && (target != GL_TEXTURE_2D))
405 return;
406
407 if (!tObj->DriverData) {
408 tObj->DriverData = fxAllocTexObjData(fxMesa);
409 }
410
411 ti = TDFX_TEXTURE_DATA(tObj);
412 ti->lastTimeUsed = fxMesa->texBindNumber++;
413
414 fxMesa->new_state |= TDFX_NEW_TEXTURE;
415 }
416
417
418 /*
419 * Called via glTexEnv.
420 */
421 static void
422 tdfxTexEnv(GLcontext * ctx, GLenum target, GLenum pname,
423 const GLfloat * param)
424 {
425 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
426
427 if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) {
428 if (param)
429 fprintf(stderr, "fxmesa: texenv(%x,%x)\n", pname,
430 (GLint) (*param));
431 else
432 fprintf(stderr, "fxmesa: texenv(%x)\n", pname);
433 }
434
435 /* XXX this is a bit of a hack to force the Glide texture
436 * state to be updated.
437 */
438 fxMesa->TexState.EnvMode[ctx->Texture.CurrentUnit] = 0;
439
440 fxMesa->new_state |= TDFX_NEW_TEXTURE;
441 }
442
443
444 /*
445 * Called via glTexParameter.
446 */
447 static void
448 tdfxTexParameter(GLcontext * ctx, GLenum target,
449 struct gl_texture_object *tObj,
450 GLenum pname, const GLfloat * params)
451 {
452 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
453 GLenum param = (GLenum) (GLint) params[0];
454 tdfxTexInfo *ti;
455
456 if (MESA_VERBOSE & VERBOSE_DRIVER) {
457 fprintf(stderr, "fxmesa: fxDDTexParam(%d,%p,%x,%x)\n", tObj->Name,
458 tObj->DriverData, pname, param);
459 }
460
461 if ((target != GL_TEXTURE_1D) && (target != GL_TEXTURE_2D))
462 return;
463
464 if (!tObj->DriverData)
465 tObj->DriverData = fxAllocTexObjData(fxMesa);
466
467 ti = TDFX_TEXTURE_DATA(tObj);
468
469 switch (pname) {
470 case GL_TEXTURE_MIN_FILTER:
471 switch (param) {
472 case GL_NEAREST:
473 ti->mmMode = GR_MIPMAP_DISABLE;
474 ti->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
475 ti->LODblend = FXFALSE;
476 break;
477 case GL_LINEAR:
478 ti->mmMode = GR_MIPMAP_DISABLE;
479 ti->minFilt = GR_TEXTUREFILTER_BILINEAR;
480 ti->LODblend = FXFALSE;
481 break;
482 case GL_NEAREST_MIPMAP_LINEAR:
483 if (!fxMesa->Glide.HaveCombineExt) {
484 if (fxMesa->haveTwoTMUs) {
485 ti->mmMode = GR_MIPMAP_NEAREST;
486 ti->LODblend = FXTRUE;
487 }
488 else {
489 ti->mmMode = GR_MIPMAP_NEAREST_DITHER;
490 ti->LODblend = FXFALSE;
491 }
492 ti->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
493 break;
494 }
495 /* XXX Voodoo3/Banshee mipmap blending seems to produce
496 * incorrectly filtered colors for the smallest mipmap levels.
497 * To work-around we fall-through here and use a different filter.
498 */
499 case GL_NEAREST_MIPMAP_NEAREST:
500 ti->mmMode = GR_MIPMAP_NEAREST;
501 ti->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
502 ti->LODblend = FXFALSE;
503 break;
504 case GL_LINEAR_MIPMAP_LINEAR:
505 if (!fxMesa->Glide.HaveCombineExt) {
506 if (fxMesa->haveTwoTMUs) {
507 ti->mmMode = GR_MIPMAP_NEAREST;
508 ti->LODblend = FXTRUE;
509 }
510 else {
511 ti->mmMode = GR_MIPMAP_NEAREST_DITHER;
512 ti->LODblend = FXFALSE;
513 }
514 ti->minFilt = GR_TEXTUREFILTER_BILINEAR;
515 break;
516 }
517 /* XXX Voodoo3/Banshee mipmap blending seems to produce
518 * incorrectly filtered colors for the smallest mipmap levels.
519 * To work-around we fall-through here and use a different filter.
520 */
521 case GL_LINEAR_MIPMAP_NEAREST:
522 ti->mmMode = GR_MIPMAP_NEAREST;
523 ti->minFilt = GR_TEXTUREFILTER_BILINEAR;
524 ti->LODblend = FXFALSE;
525 break;
526 default:
527 break;
528 }
529 ti->reloadImages = GL_TRUE;
530 RevalidateTexture(ctx, tObj);
531 fxMesa->new_state |= TDFX_NEW_TEXTURE;
532 break;
533
534 case GL_TEXTURE_MAG_FILTER:
535 switch (param) {
536 case GL_NEAREST:
537 ti->magFilt = GR_TEXTUREFILTER_POINT_SAMPLED;
538 break;
539 case GL_LINEAR:
540 ti->magFilt = GR_TEXTUREFILTER_BILINEAR;
541 break;
542 default:
543 break;
544 }
545 fxMesa->new_state |= TDFX_NEW_TEXTURE;
546 break;
547
548 case GL_TEXTURE_WRAP_S:
549 switch (param) {
550 case GL_CLAMP_TO_BORDER:
551 case GL_CLAMP_TO_EDGE:
552 case GL_CLAMP:
553 ti->sClamp = GR_TEXTURECLAMP_CLAMP;
554 break;
555 case GL_REPEAT:
556 ti->sClamp = GR_TEXTURECLAMP_WRAP;
557 break;
558 case GL_MIRRORED_REPEAT:
559 ti->sClamp = GR_TEXTURECLAMP_MIRROR_EXT;
560 break;
561 default:
562 break;
563 }
564 fxMesa->new_state |= TDFX_NEW_TEXTURE;
565 break;
566
567 case GL_TEXTURE_WRAP_T:
568 switch (param) {
569 case GL_CLAMP_TO_BORDER:
570 case GL_CLAMP_TO_EDGE:
571 case GL_CLAMP:
572 ti->tClamp = GR_TEXTURECLAMP_CLAMP;
573 break;
574 case GL_REPEAT:
575 ti->tClamp = GR_TEXTURECLAMP_WRAP;
576 break;
577 case GL_MIRRORED_REPEAT:
578 ti->tClamp = GR_TEXTURECLAMP_MIRROR_EXT;
579 break;
580 default:
581 break;
582 }
583 fxMesa->new_state |= TDFX_NEW_TEXTURE;
584 break;
585
586 case GL_TEXTURE_BORDER_COLOR:
587 /* TO DO */
588 break;
589 case GL_TEXTURE_MIN_LOD:
590 /* TO DO */
591 break;
592 case GL_TEXTURE_MAX_LOD:
593 /* TO DO */
594 break;
595 case GL_TEXTURE_BASE_LEVEL:
596 RevalidateTexture(ctx, tObj);
597 break;
598 case GL_TEXTURE_MAX_LEVEL:
599 RevalidateTexture(ctx, tObj);
600 break;
601
602 default:
603 break;
604 }
605 }
606
607
608 /*
609 * Called via glDeleteTextures to delete a texture object.
610 * Here, we delete the Glide data associated with the texture.
611 */
612 static void
613 tdfxDeleteTexture(GLcontext * ctx, struct gl_texture_object *tObj)
614 {
615 if (ctx && ctx->DriverCtx) {
616 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
617 tdfxTMFreeTexture(fxMesa, tObj);
618 fxMesa->new_state |= TDFX_NEW_TEXTURE;
619 /* Free mipmap images and the texture object itself */
620 _mesa_delete_texture_object(ctx, tObj);
621 }
622 }
623
624
625 /*
626 * Return true if texture is resident, false otherwise.
627 */
628 static GLboolean
629 tdfxIsTextureResident(GLcontext *ctx, struct gl_texture_object *tObj)
630 {
631 tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
632 return (GLboolean) (ti && ti->isInTM);
633 }
634
635
636
637 /*
638 * Convert a gl_color_table texture palette to Glide's format.
639 */
640 static GrTexTable_t
641 convertPalette(FxU32 data[256], const struct gl_color_table *table)
642 {
643 const GLubyte *tableUB = table->TableUB;
644 GLint width = table->Size;
645 FxU32 r, g, b, a;
646 GLint i;
647
648 switch (table->_BaseFormat) {
649 case GL_INTENSITY:
650 for (i = 0; i < width; i++) {
651 r = tableUB[i];
652 g = tableUB[i];
653 b = tableUB[i];
654 a = tableUB[i];
655 data[i] = (a << 24) | (r << 16) | (g << 8) | b;
656 }
657 return GR_TEXTABLE_PALETTE_6666_EXT;
658 case GL_LUMINANCE:
659 for (i = 0; i < width; i++) {
660 r = tableUB[i];
661 g = tableUB[i];
662 b = tableUB[i];
663 a = 255;
664 data[i] = (a << 24) | (r << 16) | (g << 8) | b;
665 }
666 return GR_TEXTABLE_PALETTE;
667 case GL_ALPHA:
668 for (i = 0; i < width; i++) {
669 r = g = b = 255;
670 a = tableUB[i];
671 data[i] = (a << 24) | (r << 16) | (g << 8) | b;
672 }
673 return GR_TEXTABLE_PALETTE_6666_EXT;
674 case GL_LUMINANCE_ALPHA:
675 for (i = 0; i < width; i++) {
676 r = g = b = tableUB[i * 2 + 0];
677 a = tableUB[i * 2 + 1];
678 data[i] = (a << 24) | (r << 16) | (g << 8) | b;
679 }
680 return GR_TEXTABLE_PALETTE_6666_EXT;
681 case GL_RGB:
682 for (i = 0; i < width; i++) {
683 r = tableUB[i * 3 + 0];
684 g = tableUB[i * 3 + 1];
685 b = tableUB[i * 3 + 2];
686 a = 255;
687 data[i] = (a << 24) | (r << 16) | (g << 8) | b;
688 }
689 return GR_TEXTABLE_PALETTE;
690 case GL_RGBA:
691 for (i = 0; i < width; i++) {
692 r = tableUB[i * 4 + 0];
693 g = tableUB[i * 4 + 1];
694 b = tableUB[i * 4 + 2];
695 a = tableUB[i * 4 + 3];
696 data[i] = (a << 24) | (r << 16) | (g << 8) | b;
697 }
698 return GR_TEXTABLE_PALETTE_6666_EXT;
699 default:
700 /* XXX fixme: how can this happen? */
701 _mesa_error(NULL, GL_INVALID_ENUM, "convertPalette: table->Format == %s",
702 _mesa_lookup_enum_by_nr(table->Format));
703 return GR_TEXTABLE_PALETTE;
704 }
705 }
706
707
708
709 static void
710 tdfxUpdateTexturePalette(GLcontext * ctx, struct gl_texture_object *tObj)
711 {
712 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
713
714 if (tObj) {
715 /* per-texture palette */
716 tdfxTexInfo *ti;
717
718 /* This might be a proxy texture. */
719 if (!tObj->Palette.TableUB)
720 return;
721
722 if (!tObj->DriverData)
723 tObj->DriverData = fxAllocTexObjData(fxMesa);
724 ti = TDFX_TEXTURE_DATA(tObj);
725 assert(ti);
726 ti->paltype = convertPalette(ti->palette.data, &tObj->Palette);
727 /*tdfxTexInvalidate(ctx, tObj);*/
728 }
729 else {
730 /* global texture palette */
731 fxMesa->TexPalette.Type = convertPalette(fxMesa->glbPalette.data, &ctx->Texture.Palette);
732 fxMesa->TexPalette.Data = &(fxMesa->glbPalette.data);
733 fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
734 }
735 fxMesa->new_state |= TDFX_NEW_TEXTURE; /* XXX too heavy-handed */
736 }
737
738
739 /**********************************************************************/
740 /**** NEW TEXTURE IMAGE FUNCTIONS ****/
741 /**********************************************************************/
742
743 #if 000
744 static FxBool TexusFatalError = FXFALSE;
745 static FxBool TexusError = FXFALSE;
746
747 #define TX_DITHER_NONE 0x00000000
748
749 static void
750 fxTexusError(const char *string, FxBool fatal)
751 {
752 _mesa_problem(NULL, string);
753 /*
754 * Just propagate the fatal value up.
755 */
756 TexusError = FXTRUE;
757 TexusFatalError = fatal;
758 }
759 #endif
760
761
762 static gl_format
763 tdfxChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
764 GLenum srcFormat, GLenum srcType )
765 {
766 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
767 const GLboolean allow32bpt = TDFX_IS_NAPALM(fxMesa);
768
769 switch (internalFormat) {
770 case GL_ALPHA:
771 case GL_ALPHA4:
772 case GL_ALPHA8:
773 case GL_ALPHA12:
774 case GL_ALPHA16:
775 case GL_COMPRESSED_ALPHA:
776 return MESA_FORMAT_A8;
777 case 1:
778 case GL_LUMINANCE:
779 case GL_LUMINANCE4:
780 case GL_LUMINANCE8:
781 case GL_LUMINANCE12:
782 case GL_LUMINANCE16:
783 case GL_COMPRESSED_LUMINANCE:
784 return MESA_FORMAT_L8;
785 case 2:
786 case GL_LUMINANCE_ALPHA:
787 case GL_LUMINANCE4_ALPHA4:
788 case GL_LUMINANCE6_ALPHA2:
789 case GL_LUMINANCE8_ALPHA8:
790 case GL_LUMINANCE12_ALPHA4:
791 case GL_LUMINANCE12_ALPHA12:
792 case GL_LUMINANCE16_ALPHA16:
793 case GL_COMPRESSED_LUMINANCE_ALPHA:
794 return MESA_FORMAT_AL88;
795 case GL_INTENSITY:
796 case GL_INTENSITY4:
797 case GL_INTENSITY8:
798 case GL_INTENSITY12:
799 case GL_INTENSITY16:
800 case GL_COMPRESSED_INTENSITY:
801 return MESA_FORMAT_I8;
802 case GL_R3_G3_B2:
803 case GL_RGB4:
804 case GL_RGB5:
805 return MESA_FORMAT_RGB565;
806 case GL_COMPRESSED_RGB:
807 /* intentional fall-through */
808 case 3:
809 case GL_RGB:
810 if ( srcFormat == GL_RGB && srcType == GL_UNSIGNED_SHORT_5_6_5 ) {
811 return MESA_FORMAT_RGB565;
812 }
813 /* intentional fall through */
814 case GL_RGB8:
815 case GL_RGB10:
816 case GL_RGB12:
817 case GL_RGB16:
818 return (allow32bpt) ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_RGB565;
819 case GL_RGBA2:
820 case GL_RGBA4:
821 return MESA_FORMAT_ARGB4444;
822 case GL_COMPRESSED_RGBA:
823 /* intentional fall-through */
824 case 4:
825 case GL_RGBA:
826 if ( srcFormat == GL_BGRA ) {
827 if ( srcType == GL_UNSIGNED_INT_8_8_8_8_REV ) {
828 return MESA_FORMAT_ARGB8888;
829 }
830 else if ( srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV ) {
831 return MESA_FORMAT_ARGB4444;
832 }
833 else if ( srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV ) {
834 return MESA_FORMAT_ARGB1555;
835 }
836 }
837 /* intentional fall through */
838 case GL_RGBA8:
839 case GL_RGB10_A2:
840 case GL_RGBA12:
841 case GL_RGBA16:
842 return allow32bpt ? MESA_FORMAT_ARGB8888 : MESA_FORMAT_ARGB4444;
843 case GL_RGB5_A1:
844 return MESA_FORMAT_ARGB1555;
845 case GL_COLOR_INDEX:
846 case GL_COLOR_INDEX1_EXT:
847 case GL_COLOR_INDEX2_EXT:
848 case GL_COLOR_INDEX4_EXT:
849 case GL_COLOR_INDEX8_EXT:
850 case GL_COLOR_INDEX12_EXT:
851 case GL_COLOR_INDEX16_EXT:
852 return MESA_FORMAT_CI8;
853 /* GL_EXT_texture_compression_s3tc */
854 /* GL_S3_s3tc */
855 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
856 case GL_RGB_S3TC:
857 case GL_RGB4_S3TC:
858 return MESA_FORMAT_RGB_DXT1;
859 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
860 return MESA_FORMAT_RGBA_DXT1;
861 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
862 case GL_RGBA_S3TC:
863 case GL_RGBA4_S3TC:
864 return MESA_FORMAT_RGBA_DXT3;
865 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
866 return MESA_FORMAT_RGBA_DXT5;
867 /* GL_3DFX_texture_compression_FXT1 */
868 case GL_COMPRESSED_RGB_FXT1_3DFX:
869 return MESA_FORMAT_RGB_FXT1;
870 case GL_COMPRESSED_RGBA_FXT1_3DFX:
871 return MESA_FORMAT_RGBA_FXT1;
872 default:
873 _mesa_problem(ctx, "unexpected format in tdfxChooseTextureFormat");
874 return MESA_FORMAT_NONE;
875 }
876 }
877
878
879 /*
880 * Return the Glide format for the given mesa texture format.
881 */
882 static GrTextureFormat_t
883 fxGlideFormat(GLint mesaFormat)
884 {
885 switch (mesaFormat) {
886 case MESA_FORMAT_I8:
887 return GR_TEXFMT_ALPHA_8;
888 case MESA_FORMAT_A8:
889 return GR_TEXFMT_ALPHA_8;
890 case MESA_FORMAT_L8:
891 return GR_TEXFMT_INTENSITY_8;
892 case MESA_FORMAT_CI8:
893 return GR_TEXFMT_P_8;
894 case MESA_FORMAT_AL88:
895 return GR_TEXFMT_ALPHA_INTENSITY_88;
896 case MESA_FORMAT_RGB565:
897 return GR_TEXFMT_RGB_565;
898 case MESA_FORMAT_ARGB4444:
899 return GR_TEXFMT_ARGB_4444;
900 case MESA_FORMAT_ARGB1555:
901 return GR_TEXFMT_ARGB_1555;
902 case MESA_FORMAT_ARGB8888:
903 return GR_TEXFMT_ARGB_8888;
904 case MESA_FORMAT_RGB_FXT1:
905 case MESA_FORMAT_RGBA_FXT1:
906 return GR_TEXFMT_ARGB_CMP_FXT1;
907 case MESA_FORMAT_RGB_DXT1:
908 case MESA_FORMAT_RGBA_DXT1:
909 return GR_TEXFMT_ARGB_CMP_DXT1;
910 case MESA_FORMAT_RGBA_DXT3:
911 return GR_TEXFMT_ARGB_CMP_DXT3;
912 case MESA_FORMAT_RGBA_DXT5:
913 return GR_TEXFMT_ARGB_CMP_DXT5;
914 default:
915 _mesa_problem(NULL, "Unexpected format in fxGlideFormat");
916 return 0;
917 }
918 }
919
920
921 /* Texel-fetch functions for software texturing and glGetTexImage().
922 * We should have been able to use some "standard" fetch functions (which
923 * may get defined in texutil.c) but we have to account for scaled texture
924 * images on tdfx hardware (the 8:1 aspect ratio limit).
925 * Hence, we need special functions here.
926 */
927 extern void
928 fxt1_decode_1 (const void *texture, int width,
929 int i, int j, unsigned char *rgba);
930
931 static void
932 fetch_intensity8(const struct gl_texture_image *texImage,
933 GLint i, GLint j, GLint k, GLchan * rgba)
934 {
935 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
936 const GLubyte *texel;
937
938 i = i * mml->wScale;
939 j = j * mml->hScale;
940
941 texel = ((GLubyte *) texImage->Data) + j * mml->width + i;
942 rgba[RCOMP] = *texel;
943 rgba[GCOMP] = *texel;
944 rgba[BCOMP] = *texel;
945 rgba[ACOMP] = *texel;
946 }
947
948
949 static void
950 fetch_luminance8(const struct gl_texture_image *texImage,
951 GLint i, GLint j, GLint k, GLchan * rgba)
952 {
953 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
954 const GLubyte *texel;
955
956 i = i * mml->wScale;
957 j = j * mml->hScale;
958
959 texel = ((GLubyte *) texImage->Data) + j * mml->width + i;
960 rgba[RCOMP] = *texel;
961 rgba[GCOMP] = *texel;
962 rgba[BCOMP] = *texel;
963 rgba[ACOMP] = 255;
964 }
965
966
967 static void
968 fetch_alpha8(const struct gl_texture_image *texImage,
969 GLint i, GLint j, GLint k, GLchan * rgba)
970 {
971 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
972 const GLubyte *texel;
973
974 i = i * mml->wScale;
975 j = j * mml->hScale;
976
977 texel = ((GLubyte *) texImage->Data) + j * mml->width + i;
978 rgba[RCOMP] = 255;
979 rgba[GCOMP] = 255;
980 rgba[BCOMP] = 255;
981 rgba[ACOMP] = *texel;
982 }
983
984
985 static void
986 fetch_index8(const struct gl_texture_image *texImage,
987 GLint i, GLint j, GLint k, GLchan * indexOut)
988 {
989 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
990 const GLubyte *texel;
991
992 i = i * mml->wScale;
993 j = j * mml->hScale;
994
995 texel = ((GLubyte *) texImage->Data) + j * mml->width + i;
996 *indexOut = *texel;
997 }
998
999
1000 static void
1001 fetch_luminance8_alpha8(const struct gl_texture_image *texImage,
1002 GLint i, GLint j, GLint k, GLchan * rgba)
1003 {
1004 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1005 const GLubyte *texel;
1006
1007 i = i * mml->wScale;
1008 j = j * mml->hScale;
1009
1010 texel = ((GLubyte *) texImage->Data) + (j * mml->width + i) * 2;
1011 rgba[RCOMP] = texel[0];
1012 rgba[GCOMP] = texel[0];
1013 rgba[BCOMP] = texel[0];
1014 rgba[ACOMP] = texel[1];
1015 }
1016
1017
1018 static void
1019 fetch_r5g6b5(const struct gl_texture_image *texImage,
1020 GLint i, GLint j, GLint k, GLchan * rgba)
1021 {
1022 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1023 const GLushort *texel;
1024
1025 i = i * mml->wScale;
1026 j = j * mml->hScale;
1027
1028 texel = ((GLushort *) texImage->Data) + j * mml->width + i;
1029 rgba[RCOMP] = (((*texel) >> 11) & 0x1f) * 255 / 31;
1030 rgba[GCOMP] = (((*texel) >> 5) & 0x3f) * 255 / 63;
1031 rgba[BCOMP] = (((*texel) >> 0) & 0x1f) * 255 / 31;
1032 rgba[ACOMP] = 255;
1033 }
1034
1035
1036 static void
1037 fetch_r4g4b4a4(const struct gl_texture_image *texImage,
1038 GLint i, GLint j, GLint k, GLchan * rgba)
1039 {
1040 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1041 const GLushort *texel;
1042
1043 i = i * mml->wScale;
1044 j = j * mml->hScale;
1045
1046 texel = ((GLushort *) texImage->Data) + j * mml->width + i;
1047 rgba[RCOMP] = (((*texel) >> 12) & 0xf) * 255 / 15;
1048 rgba[GCOMP] = (((*texel) >> 8) & 0xf) * 255 / 15;
1049 rgba[BCOMP] = (((*texel) >> 4) & 0xf) * 255 / 15;
1050 rgba[ACOMP] = (((*texel) >> 0) & 0xf) * 255 / 15;
1051 }
1052
1053
1054 static void
1055 fetch_r5g5b5a1(const struct gl_texture_image *texImage,
1056 GLint i, GLint j, GLint k, GLchan * rgba)
1057 {
1058 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1059 const GLushort *texel;
1060
1061 i = i * mml->wScale;
1062 j = j * mml->hScale;
1063
1064 texel = ((GLushort *) texImage->Data) + j * mml->width + i;
1065 rgba[RCOMP] = (((*texel) >> 11) & 0x1f) * 255 / 31;
1066 rgba[GCOMP] = (((*texel) >> 6) & 0x1f) * 255 / 31;
1067 rgba[BCOMP] = (((*texel) >> 1) & 0x1f) * 255 / 31;
1068 rgba[ACOMP] = (((*texel) >> 0) & 0x01) * 255;
1069 }
1070
1071
1072 static void
1073 fetch_a8r8g8b8(const struct gl_texture_image *texImage,
1074 GLint i, GLint j, GLint k, GLchan * rgba)
1075 {
1076 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1077 const GLuint *texel;
1078
1079 i = i * mml->wScale;
1080 j = j * mml->hScale;
1081
1082 texel = ((GLuint *) texImage->Data) + j * mml->width + i;
1083 rgba[RCOMP] = (((*texel) >> 16) & 0xff);
1084 rgba[GCOMP] = (((*texel) >> 8) & 0xff);
1085 rgba[BCOMP] = (((*texel) ) & 0xff);
1086 rgba[ACOMP] = (((*texel) >> 24) & 0xff);
1087 }
1088
1089
1090 static void
1091 fetch_rgb_fxt1(const struct gl_texture_image *texImage,
1092 GLint i, GLint j, GLint k, GLchan *rgba)
1093 {
1094 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1095
1096 i = i * mml->wScale;
1097 j = j * mml->hScale;
1098
1099 fxt1_decode_1(texImage->Data, mml->width, i, j, rgba);
1100 rgba[ACOMP] = 255;
1101 }
1102
1103
1104 static void
1105 fetch_rgba_fxt1(const struct gl_texture_image *texImage,
1106 GLint i, GLint j, GLint k, GLchan *rgba)
1107 {
1108 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1109
1110 i = i * mml->wScale;
1111 j = j * mml->hScale;
1112
1113 fxt1_decode_1(texImage->Data, mml->width, i, j, rgba);
1114 }
1115
1116
1117 static void
1118 fetch_rgb_dxt1(const struct gl_texture_image *texImage,
1119 GLint i, GLint j, GLint k, GLchan *rgba)
1120 {
1121 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1122
1123 i = i * mml->wScale;
1124 j = j * mml->hScale;
1125
1126 /* XXX Get fetch func from _mesa_get_texel_fetch_func()
1127 _mesa_texformat_rgb_dxt1.FetchTexel2D(texImage, i, j, k, rgba);
1128 */
1129 }
1130
1131
1132 static void
1133 fetch_rgba_dxt1(const struct gl_texture_image *texImage,
1134 GLint i, GLint j, GLint k, GLchan *rgba)
1135 {
1136 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1137
1138 i = i * mml->wScale;
1139 j = j * mml->hScale;
1140
1141 /* XXX Get fetch func from _mesa_get_texel_fetch_func()
1142 _mesa_texformat_rgba_dxt1.FetchTexel2D(texImage, i, j, k, rgba);
1143 */
1144 }
1145
1146
1147 static void
1148 fetch_rgba_dxt3(const struct gl_texture_image *texImage,
1149 GLint i, GLint j, GLint k, GLchan *rgba)
1150 {
1151 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1152
1153 i = i * mml->wScale;
1154 j = j * mml->hScale;
1155
1156 /* XXX Get fetch func from _mesa_get_texel_fetch_func()
1157 _mesa_texformat_rgba_dxt3.FetchTexel2D(texImage, i, j, k, rgba);
1158 */
1159 }
1160
1161
1162 static void
1163 fetch_rgba_dxt5(const struct gl_texture_image *texImage,
1164 GLint i, GLint j, GLint k, GLchan *rgba)
1165 {
1166 const tdfxMipMapLevel *mml = TDFX_TEXIMAGE_DATA(texImage);
1167
1168 i = i * mml->wScale;
1169 j = j * mml->hScale;
1170
1171 /* XXX Get fetch func from _mesa_get_texel_fetch_func()
1172 _mesa_texformat_rgba_dxt5.FetchTexel2D(texImage, i, j, k, rgba);
1173 */
1174 }
1175
1176
1177 static FetchTexelFuncC
1178 fxFetchFunction(GLint mesaFormat)
1179 {
1180 switch (mesaFormat) {
1181 case MESA_FORMAT_I8:
1182 return &fetch_intensity8;
1183 case MESA_FORMAT_A8:
1184 return &fetch_alpha8;
1185 case MESA_FORMAT_L8:
1186 return &fetch_luminance8;
1187 case MESA_FORMAT_CI8:
1188 return &fetch_index8;
1189 case MESA_FORMAT_AL88:
1190 return &fetch_luminance8_alpha8;
1191 case MESA_FORMAT_RGB565:
1192 return &fetch_r5g6b5;
1193 case MESA_FORMAT_ARGB4444:
1194 return &fetch_r4g4b4a4;
1195 case MESA_FORMAT_ARGB1555:
1196 return &fetch_r5g5b5a1;
1197 case MESA_FORMAT_ARGB8888:
1198 return &fetch_a8r8g8b8;
1199 case MESA_FORMAT_RGB_FXT1:
1200 return &fetch_rgb_fxt1;
1201 case MESA_FORMAT_RGBA_FXT1:
1202 return &fetch_rgba_fxt1;
1203 case MESA_FORMAT_RGB_DXT1:
1204 return &fetch_rgb_dxt1;
1205 case MESA_FORMAT_RGBA_DXT1:
1206 return &fetch_rgba_dxt1;
1207 case MESA_FORMAT_RGBA_DXT3:
1208 return &fetch_rgba_dxt3;
1209 case MESA_FORMAT_RGBA_DXT5:
1210 return &fetch_rgba_dxt5;
1211 default:
1212 _mesa_problem(NULL, "Unexpected format in fxFetchFunction");
1213 return NULL;
1214 }
1215 }
1216
1217
1218 static GLboolean
1219 adjust2DRatio (GLcontext *ctx,
1220 GLint xoffset, GLint yoffset,
1221 GLint width, GLint height,
1222 GLenum format, GLenum type, const GLvoid *pixels,
1223 const struct gl_pixelstore_attrib *packing,
1224 tdfxMipMapLevel *mml,
1225 struct gl_texture_image *texImage,
1226 GLint texelBytes,
1227 GLint dstRowStride)
1228 {
1229 const GLint newWidth = width * mml->wScale;
1230 const GLint newHeight = height * mml->hScale;
1231 GLvoid *tempImage;
1232 GLuint dstImageOffsets = 0;
1233
1234 if (!_mesa_is_format_compressed(texImage->TexFormat)) {
1235 GLubyte *destAddr;
1236
1237 tempImage = MALLOC(width * height * texelBytes);
1238 if (!tempImage) {
1239 return GL_FALSE;
1240 }
1241
1242 _mesa_texstore(ctx, 2, texImage->_BaseFormat,
1243 texImage->TexFormat, tempImage,
1244 0, 0, 0, /* dstX/Y/Zoffset */
1245 width * texelBytes, /* dstRowStride */
1246 &dstImageOffsets,
1247 width, height, 1,
1248 format, type, pixels, packing);
1249
1250 /* now rescale */
1251 /* compute address of dest subimage within the overal tex image */
1252 destAddr = (GLubyte *) texImage->Data
1253 + (yoffset * mml->hScale * mml->width
1254 + xoffset * mml->wScale) * texelBytes;
1255
1256 _mesa_rescale_teximage2d(texelBytes,
1257 width,
1258 dstRowStride, /* dst stride */
1259 width, height,
1260 newWidth, newHeight,
1261 tempImage, destAddr);
1262 } else {
1263 const GLint rawBytes = 4;
1264 GLvoid *rawImage = MALLOC(width * height * rawBytes);
1265
1266 if (!rawImage) {
1267 return GL_FALSE;
1268 }
1269 tempImage = MALLOC(newWidth * newHeight * rawBytes);
1270 if (!tempImage) {
1271 FREE(rawImage);
1272 return GL_FALSE;
1273 }
1274 /* unpack image, apply transfer ops and store in rawImage */
1275 _mesa_texstore(ctx, 2, GL_RGBA,
1276 MESA_FORMAT_RGBA8888_REV, rawImage,
1277 0, 0, 0, /* dstX/Y/Zoffset */
1278 width * rawBytes, /* dstRowStride */
1279 &dstImageOffsets,
1280 width, height, 1,
1281 format, type, pixels, packing);
1282 _mesa_rescale_teximage2d(rawBytes,
1283 width,
1284 newWidth * rawBytes, /* dst stride */
1285 width, height, /* src */
1286 newWidth, newHeight, /* dst */
1287 rawImage /*src*/, tempImage /*dst*/ );
1288 _mesa_texstore(ctx, 2, texImage->_BaseFormat,
1289 texImage->TexFormat, texImage->Data,
1290 xoffset * mml->wScale, yoffset * mml->hScale, 0, /* dstX/Y/Zoffset */
1291 dstRowStride,
1292 &dstImageOffsets,
1293 newWidth, newHeight, 1,
1294 GL_RGBA, CHAN_TYPE, tempImage, &ctx->DefaultPacking);
1295 FREE(rawImage);
1296 }
1297
1298 FREE(tempImage);
1299
1300 return GL_TRUE;
1301 }
1302
1303
1304 static void
1305 tdfxTexImage2D(GLcontext *ctx, GLenum target, GLint level,
1306 GLint internalFormat, GLint width, GLint height, GLint border,
1307 GLenum format, GLenum type, const GLvoid *pixels,
1308 const struct gl_pixelstore_attrib *packing,
1309 struct gl_texture_object *texObj,
1310 struct gl_texture_image *texImage)
1311 {
1312 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1313 tdfxTexInfo *ti;
1314 tdfxMipMapLevel *mml;
1315 GLint texelBytes, dstRowStride;
1316 GLuint mesaFormat;
1317
1318 /*
1319 printf("TexImage id=%d int 0x%x format 0x%x type 0x%x %dx%d\n",
1320 texObj->Name, texImage->InternalFormat, format, type,
1321 texImage->Width, texImage->Height);
1322 */
1323
1324 ti = TDFX_TEXTURE_DATA(texObj);
1325 if (!ti) {
1326 texObj->DriverData = fxAllocTexObjData(fxMesa);
1327 if (!texObj->DriverData) {
1328 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1329 return;
1330 }
1331 ti = TDFX_TEXTURE_DATA(texObj);
1332 }
1333 assert(ti);
1334
1335 mml = TDFX_TEXIMAGE_DATA(texImage);
1336 if (!mml) {
1337 texImage->DriverData = CALLOC(sizeof(tdfxMipMapLevel));
1338 if (!texImage->DriverData) {
1339 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1340 return;
1341 }
1342 mml = TDFX_TEXIMAGE_DATA(texImage);
1343 }
1344
1345 /* Determine width and height scale factors for texture.
1346 * Remember, Glide is limited to 8:1 aspect ratios.
1347 */
1348 tdfxTexGetInfo(ctx,
1349 texImage->Width, texImage->Height,
1350 NULL, /* lod level */
1351 NULL, /* aspect ratio */
1352 NULL, NULL, /* sscale, tscale */
1353 &mml->wScale, &mml->hScale);
1354
1355 /* rescaled size: */
1356 mml->width = width * mml->wScale;
1357 mml->height = height * mml->hScale;
1358
1359 #if FX_COMPRESS_S3TC_AS_FXT1_HACK
1360 /* [koolsmoky] substitute FXT1 for DXTn and Legacy S3TC */
1361 /* [dBorca] we should update texture's attribute, then,
1362 * because if the application asks us to decompress, we
1363 * have to know the REAL format! Also, DXT3/5 might not
1364 * be correct, since it would mess with "compressedSize".
1365 * Ditto for GL_RGBA[4]_S3TC, which is always mapped to DXT3.
1366 */
1367 if (_mesa_is_format_compressed(texImage->TexFormat)) {
1368 switch (internalFormat) {
1369 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1370 case GL_RGB_S3TC:
1371 case GL_RGB4_S3TC:
1372 internalFormat = GL_COMPRESSED_RGB_FXT1_3DFX;
1373 break;
1374 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1375 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1376 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1377 case GL_RGBA_S3TC:
1378 case GL_RGBA4_S3TC:
1379 internalFormat = GL_COMPRESSED_RGBA_FXT1_3DFX;
1380 }
1381 texImage->InternalFormat = internalFormat;
1382 }
1383 #endif
1384 #if FX_TC_NAPALM
1385 if (fxMesa->type >= GR_SSTTYPE_Voodoo4) {
1386 GLenum texNapalm = 0;
1387 if (internalFormat == GL_COMPRESSED_RGB) {
1388 texNapalm = GL_COMPRESSED_RGB_FXT1_3DFX;
1389 } else if (internalFormat == GL_COMPRESSED_RGBA) {
1390 texNapalm = GL_COMPRESSED_RGBA_FXT1_3DFX;
1391 }
1392 if (texNapalm) {
1393 texImage->InternalFormat = internalFormat = texNapalm;
1394 _mesa_is_format_compressed(texImage->TexFormat) = GL_TRUE;
1395 }
1396 }
1397 #endif
1398
1399 mesaFormat = texImage->TexFormat;
1400 mml->glideFormat = fxGlideFormat(mesaFormat);
1401 ti->info.format = mml->glideFormat;
1402 texImage->FetchTexelc = fxFetchFunction(mesaFormat);
1403 texelBytes = _mesa_get_format_bytes(texImage->TexFormat);
1404
1405 if (_mesa_is_format_compressed(texImage->TexFormat)) {
1406 GLuint compressedSize = _mesa_format_image_size(mesaFormat, mml->width,
1407 mml->height, 1);
1408 dstRowStride = _mesa_format_row_stride(texImage->TexFormat, mml->width);
1409 texImage->Data = _mesa_alloc_texmemory(compressedSize);
1410 } else {
1411 dstRowStride = mml->width * texelBytes;
1412 texImage->Data = _mesa_alloc_texmemory(mml->width * mml->height * texelBytes);
1413 }
1414 if (!texImage->Data) {
1415 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1416 return;
1417 }
1418
1419 if (pixels != NULL) {
1420 if (mml->wScale != 1 || mml->hScale != 1) {
1421 /* rescale image to overcome 1:8 aspect limitation */
1422 if (!adjust2DRatio(ctx,
1423 0, 0,
1424 width, height,
1425 format, type, pixels,
1426 packing,
1427 mml,
1428 texImage,
1429 texelBytes,
1430 dstRowStride)
1431 ) {
1432 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1433 return;
1434 }
1435 }
1436 else {
1437 /* no rescaling needed */
1438 /* unpack image, apply transfer ops and store in texImage->Data */
1439 _mesa_texstore(ctx, 2, texImage->_BaseFormat,
1440 texImage->TexFormat, texImage->Data,
1441 0, 0, 0, /* dstX/Y/Zoffset */
1442 dstRowStride,
1443 texImage->ImageOffsets,
1444 width, height, 1,
1445 format, type, pixels, packing);
1446 }
1447 }
1448
1449 RevalidateTexture(ctx, texObj);
1450
1451 ti->reloadImages = GL_TRUE;
1452 fxMesa->new_state |= TDFX_NEW_TEXTURE;
1453 }
1454
1455
1456 static void
1457 tdfxTexSubImage2D(GLcontext *ctx, GLenum target, GLint level,
1458 GLint xoffset, GLint yoffset,
1459 GLsizei width, GLsizei height,
1460 GLenum format, GLenum type,
1461 const GLvoid *pixels,
1462 const struct gl_pixelstore_attrib *packing,
1463 struct gl_texture_object *texObj,
1464 struct gl_texture_image *texImage )
1465 {
1466 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1467 tdfxTexInfo *ti;
1468 tdfxMipMapLevel *mml;
1469 GLint texelBytes, dstRowStride;
1470
1471 if (!texObj->DriverData) {
1472 _mesa_problem(ctx, "problem in fxDDTexSubImage2D");
1473 return;
1474 }
1475
1476 ti = TDFX_TEXTURE_DATA(texObj);
1477 assert(ti);
1478 mml = TDFX_TEXIMAGE_DATA(texImage);
1479 assert(mml);
1480
1481 assert(texImage->Data); /* must have an existing texture image! */
1482 assert(texImage->_BaseFormat);
1483
1484 texelBytes = _mesa_get_format_bytes(texImage->TexFormat);
1485 if (_mesa_is_format_compressed(texImage->TexFormat)) {
1486 dstRowStride = _mesa_format_row_stride(texImage->TexFormat, mml->width);
1487 } else {
1488 dstRowStride = mml->width * texelBytes;
1489 }
1490
1491 if (mml->wScale != 1 || mml->hScale != 1) {
1492 /* need to rescale subimage to match mipmap level's rescale factors */
1493 if (!adjust2DRatio(ctx,
1494 xoffset, yoffset,
1495 width, height,
1496 format, type, pixels,
1497 packing,
1498 mml,
1499 texImage,
1500 texelBytes,
1501 dstRowStride)
1502 ) {
1503 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
1504 return;
1505 }
1506 }
1507 else {
1508 /* no rescaling needed */
1509 _mesa_texstore(ctx, 2, texImage->_BaseFormat,
1510 texImage->TexFormat, texImage->Data,
1511 xoffset, yoffset, 0,
1512 dstRowStride,
1513 texImage->ImageOffsets,
1514 width, height, 1,
1515 format, type, pixels, packing);
1516 }
1517
1518 ti->reloadImages = GL_TRUE; /* signal the image needs to be reloaded */
1519 fxMesa->new_state |= TDFX_NEW_TEXTURE; /* XXX this might be a bit much */
1520 }
1521
1522
1523 static void
1524 tdfxTexImage1D(GLcontext *ctx, GLenum target, GLint level,
1525 GLint internalFormat, GLint width, GLint border,
1526 GLenum format, GLenum type, const GLvoid *pixels,
1527 const struct gl_pixelstore_attrib *packing,
1528 struct gl_texture_object *texObj,
1529 struct gl_texture_image *texImage)
1530 {
1531 tdfxTexImage2D(ctx, target, level,
1532 internalFormat, width, 1, border,
1533 format, type, pixels,
1534 packing,
1535 texObj,
1536 texImage);
1537 }
1538
1539 static void
1540 tdfxTexSubImage1D(GLcontext *ctx, GLenum target, GLint level,
1541 GLint xoffset,
1542 GLsizei width,
1543 GLenum format, GLenum type,
1544 const GLvoid *pixels,
1545 const struct gl_pixelstore_attrib *packing,
1546 struct gl_texture_object *texObj,
1547 struct gl_texture_image *texImage )
1548 {
1549 tdfxTexSubImage2D(ctx, target, level,
1550 xoffset, 0,
1551 width, 1,
1552 format, type,
1553 pixels,
1554 packing,
1555 texObj,
1556 texImage);
1557 }
1558
1559 /**********************************************************************/
1560 /**** COMPRESSED TEXTURE IMAGE FUNCTIONS ****/
1561 /**********************************************************************/
1562
1563 static void
1564 tdfxCompressedTexImage2D (GLcontext *ctx, GLenum target,
1565 GLint level, GLint internalFormat,
1566 GLsizei width, GLsizei height, GLint border,
1567 GLsizei imageSize, const GLvoid *data,
1568 struct gl_texture_object *texObj,
1569 struct gl_texture_image *texImage)
1570 {
1571 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1572 tdfxTexInfo *ti;
1573 tdfxMipMapLevel *mml;
1574 gl_format mesaFormat;
1575 GLuint compressedSize;
1576
1577 if (TDFX_DEBUG & DEBUG_VERBOSE_DRI) {
1578 fprintf(stderr, "tdfxCompressedTexImage2D: id=%d int 0x%x %dx%d\n",
1579 texObj->Name, internalFormat,
1580 width, height);
1581 }
1582
1583 if ((target != GL_TEXTURE_1D && target != GL_TEXTURE_2D) || texImage->Border > 0) {
1584 _mesa_problem(NULL, "tdfx: unsupported texture in tdfxCompressedTexImg()\n");
1585 return;
1586 }
1587
1588 ti = TDFX_TEXTURE_DATA(texObj);
1589 if (!ti) {
1590 texObj->DriverData = fxAllocTexObjData(fxMesa);
1591 if (!texObj->DriverData) {
1592 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
1593 return;
1594 }
1595 ti = TDFX_TEXTURE_DATA(texObj);
1596 }
1597 assert(ti);
1598
1599 mml = TDFX_TEXIMAGE_DATA(texImage);
1600 if (!mml) {
1601 texImage->DriverData = CALLOC(sizeof(tdfxMipMapLevel));
1602 if (!texImage->DriverData) {
1603 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
1604 return;
1605 }
1606 mml = TDFX_TEXIMAGE_DATA(texImage);
1607 }
1608
1609 tdfxTexGetInfo(ctx, width, height, NULL, NULL, NULL, NULL,
1610 &mml->wScale, &mml->hScale);
1611
1612 mml->width = width * mml->wScale;
1613 mml->height = height * mml->hScale;
1614
1615
1616 /* Determine the appropriate Glide texel format,
1617 * given the user's internal texture format hint.
1618 */
1619 mesaFormat = texImage->TexFormat;
1620 mml->glideFormat = fxGlideFormat(mesaFormat);
1621 ti->info.format = mml->glideFormat;
1622 texImage->FetchTexelc = fxFetchFunction(mesaFormat);
1623
1624 /* allocate new storage for texture image, if needed */
1625 if (!texImage->Data) {
1626 compressedSize = _mesa_format_image_size(mesaFormat, mml->width,
1627 mml->height, 1);
1628 texImage->Data = _mesa_alloc_texmemory(compressedSize);
1629 if (!texImage->Data) {
1630 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
1631 return;
1632 }
1633 }
1634
1635 /* save the texture data */
1636 if (mml->wScale != 1 || mml->hScale != 1) {
1637 /* [dBorca] Hack alert:
1638 * now we're screwed. We can't decompress,
1639 * unless we do it in HW (via textureBuffer).
1640 * We still have some chances:
1641 * 1) we got FXT1 textures - we CAN decompress, rescale for
1642 * aspectratio, then compress back.
1643 * 2) there is a chance that MIN("s", "t") won't be overflowed.
1644 * Thus, we don't care about textureclamp and we could lower
1645 * MIN("uscale", "vscale") below 32. We still have to have
1646 * our data aligned inside a 8:1 rectangle.
1647 * 3) just in case if MIN("s", "t") gets overflowed with GL_REPEAT,
1648 * we replicate the data over the padded area.
1649 * For now, we take 2) + 3) but texelfetchers will be wrong!
1650 */
1651 const GLuint mesaFormat = texImage->TexFormat;
1652 GLuint srcRowStride = _mesa_format_row_stride(mesaFormat, width);
1653
1654 GLuint destRowStride = _mesa_format_row_stride(mesaFormat,
1655 mml->width);
1656
1657 _mesa_upscale_teximage2d(srcRowStride, (height+3) / 4,
1658 destRowStride, (mml->height+3) / 4,
1659 1, data, srcRowStride,
1660 texImage->Data);
1661 ti->padded = GL_TRUE;
1662 } else {
1663 MEMCPY(texImage->Data, data, compressedSize);
1664 }
1665
1666 RevalidateTexture(ctx, texObj);
1667
1668 ti->reloadImages = GL_TRUE;
1669 fxMesa->new_state |= TDFX_NEW_TEXTURE;
1670 }
1671
1672
1673 static void
1674 tdfxCompressedTexSubImage2D( GLcontext *ctx, GLenum target,
1675 GLint level, GLint xoffset,
1676 GLint yoffset, GLsizei width,
1677 GLint height, GLenum format,
1678 GLsizei imageSize, const GLvoid *data,
1679 struct gl_texture_object *texObj,
1680 struct gl_texture_image *texImage )
1681 {
1682 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1683 tdfxTexInfo *ti;
1684 tdfxMipMapLevel *mml;
1685 GLint destRowStride, srcRowStride;
1686 GLint i, rows;
1687 GLubyte *dest;
1688 const GLuint mesaFormat = texImage->TexFormat;
1689
1690 if (TDFX_DEBUG & DEBUG_VERBOSE_DRI) {
1691 fprintf(stderr, "tdfxCompressedTexSubImage2D: id=%d\n", texObj->Name);
1692 }
1693
1694 ti = TDFX_TEXTURE_DATA(texObj);
1695 assert(ti);
1696 mml = TDFX_TEXIMAGE_DATA(texImage);
1697 assert(mml);
1698
1699 srcRowStride = _mesa_format_row_stride(mesaFormat, width);
1700
1701 destRowStride = _mesa_format_row_stride(mesaFormat, mml->width);
1702 dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
1703 mesaFormat,
1704 mml->width,
1705 (GLubyte*) texImage->Data);
1706
1707 rows = height / 4; /* [dBorca] hardcoded 4, but works for FXT1/DXTC */
1708
1709 for (i = 0; i < rows; i++) {
1710 MEMCPY(dest, data, srcRowStride);
1711 dest += destRowStride;
1712 data = (GLvoid *)((intptr_t)data + (intptr_t)srcRowStride);
1713 }
1714
1715 /* [dBorca] Hack alert:
1716 * see fxDDCompressedTexImage2D for caveats
1717 */
1718 if (mml->wScale != 1 || mml->hScale != 1) {
1719 srcRowStride = _mesa_format_row_stride(mesaFormat, texImage->Width);
1720
1721 destRowStride = _mesa_format_row_stride(mesaFormat, mml->width);
1722 _mesa_upscale_teximage2d(srcRowStride, texImage->Height / 4,
1723 destRowStride, mml->height / 4,
1724 1, texImage->Data, destRowStride,
1725 texImage->Data);
1726 }
1727
1728 RevalidateTexture(ctx, texObj);
1729
1730 ti->reloadImages = GL_TRUE;
1731 fxMesa->new_state |= TDFX_NEW_TEXTURE;
1732 }
1733
1734
1735 #if 0
1736 static void
1737 PrintTexture(int w, int h, int c, const GLubyte * data)
1738 {
1739 int i, j;
1740 for (i = 0; i < h; i++) {
1741 for (j = 0; j < w; j++) {
1742 if (c == 2)
1743 printf("%02x %02x ", data[0], data[1]);
1744 else if (c == 3)
1745 printf("%02x %02x %02x ", data[0], data[1], data[2]);
1746 data += c;
1747 }
1748 printf("\n");
1749 }
1750 }
1751 #endif
1752
1753
1754 GLboolean
1755 tdfxTestProxyTexImage(GLcontext *ctx, GLenum target,
1756 GLint level, GLint internalFormat,
1757 GLenum format, GLenum type,
1758 GLint width, GLint height,
1759 GLint depth, GLint border)
1760 {
1761 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1762 struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
1763 struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
1764
1765 switch (target) {
1766 case GL_PROXY_TEXTURE_1D:
1767 /*JJJ wrong*/
1768 case GL_PROXY_TEXTURE_2D:
1769 {
1770 struct gl_texture_object *tObj;
1771 tdfxTexInfo *ti;
1772 int memNeeded;
1773
1774 tObj = ctx->Texture.ProxyTex[TEXTURE_2D_INDEX];
1775 if (!tObj->DriverData)
1776 tObj->DriverData = fxAllocTexObjData(fxMesa);
1777 ti = TDFX_TEXTURE_DATA(tObj);
1778 assert(ti);
1779
1780 /* assign the parameters to test against */
1781 tObj->Image[0][level]->Width = width;
1782 tObj->Image[0][level]->Height = height;
1783 tObj->Image[0][level]->Border = border;
1784 #if 0
1785 tObj->Image[0][level]->InternalFormat = internalFormat;
1786 #endif
1787 if (level == 0) {
1788 /* don't use mipmap levels > 0 */
1789 tObj->MinFilter = tObj->MagFilter = GL_NEAREST;
1790 }
1791 else {
1792 /* test with all mipmap levels */
1793 tObj->MinFilter = GL_LINEAR_MIPMAP_LINEAR;
1794 tObj->MagFilter = GL_NEAREST;
1795 }
1796 RevalidateTexture(ctx, tObj);
1797
1798 /*
1799 printf("small lodlog2 0x%x\n", ti->info.smallLodLog2);
1800 printf("large lodlog2 0x%x\n", ti->info.largeLodLog2);
1801 printf("aspect ratio 0x%x\n", ti->info.aspectRatioLog2);
1802 printf("glide format 0x%x\n", ti->info.format);
1803 printf("data %p\n", ti->info.data);
1804 printf("lodblend %d\n", (int) ti->LODblend);
1805 */
1806
1807 /* determine where texture will reside */
1808 if (ti->LODblend && !shared->umaTexMemory) {
1809 /* XXX GR_MIPMAPLEVELMASK_BOTH might not be right, but works */
1810 memNeeded = fxMesa->Glide.grTexTextureMemRequired(
1811 GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
1812 }
1813 else {
1814 /* XXX GR_MIPMAPLEVELMASK_BOTH might not be right, but works */
1815 memNeeded = fxMesa->Glide.grTexTextureMemRequired(
1816 GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
1817 }
1818 /*
1819 printf("Proxy test %d > %d\n", memNeeded, shared->totalTexMem[0]);
1820 */
1821 if (memNeeded > shared->totalTexMem[0])
1822 return GL_FALSE;
1823 else
1824 return GL_TRUE;
1825 }
1826 case GL_PROXY_TEXTURE_3D:
1827 return GL_TRUE; /* software rendering */
1828 default:
1829 return GL_TRUE; /* never happens, silence compiler */
1830 }
1831 }
1832
1833
1834 /**
1835 * Allocate a new texture object.
1836 * Called via ctx->Driver.NewTextureObject.
1837 * Note: this function will be called during context creation to
1838 * allocate the default texture objects.
1839 * Note: we could use containment here to 'derive' the driver-specific
1840 * texture object from the core mesa gl_texture_object. Not done at this time.
1841 */
1842 static struct gl_texture_object *
1843 tdfxNewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
1844 {
1845 struct gl_texture_object *obj;
1846 obj = _mesa_new_texture_object(ctx, name, target);
1847 return obj;
1848 }
1849
1850
1851 void tdfxInitTextureFuncs( struct dd_function_table *functions )
1852 {
1853 functions->BindTexture = tdfxBindTexture;
1854 functions->NewTextureObject = tdfxNewTextureObject;
1855 functions->DeleteTexture = tdfxDeleteTexture;
1856 functions->TexEnv = tdfxTexEnv;
1857 functions->TexParameter = tdfxTexParameter;
1858 functions->ChooseTextureFormat = tdfxChooseTextureFormat;
1859 functions->TexImage1D = tdfxTexImage1D;
1860 functions->TexSubImage1D = tdfxTexSubImage1D;
1861 functions->TexImage2D = tdfxTexImage2D;
1862 functions->TexSubImage2D = tdfxTexSubImage2D;
1863 functions->IsTextureResident = tdfxIsTextureResident;
1864 functions->CompressedTexImage2D = tdfxCompressedTexImage2D;
1865 functions->CompressedTexSubImage2D = tdfxCompressedTexSubImage2D;
1866 functions->UpdateTexturePalette = tdfxUpdateTexturePalette;
1867 functions->GenerateMipmap = tdfxGenerateMipmap;
1868 }