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