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