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