comment reorg.
[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 width,
1271 dstRowStride, /* dst stride */
1272 width, height,
1273 newWidth, newHeight,
1274 tempImage, destAddr);
1275 } else {
1276 const GLint rawBytes = 4;
1277 GLvoid *rawImage = MALLOC(width * height * rawBytes);
1278 if (!rawImage) {
1279 return GL_FALSE;
1280 }
1281 tempImage = MALLOC(newWidth * newHeight * rawBytes);
1282 if (!tempImage) {
1283 return GL_FALSE;
1284 }
1285 /* unpack image, apply transfer ops and store in rawImage */
1286 _mesa_texstore_rgba8888(ctx, 2, GL_RGBA,
1287 &_mesa_texformat_rgba8888_rev, rawImage,
1288 0, 0, 0, /* dstX/Y/Zoffset */
1289 width * rawBytes, /* dstRowStride */
1290 0, /* dstImageStride */
1291 width, height, 1,
1292 format, type, pixels, packing);
1293 _mesa_rescale_teximage2d(rawBytes,
1294 width,
1295 newWidth * rawBytes, /* dst stride */
1296 width, height, /* src */
1297 newWidth, newHeight, /* dst */
1298 rawImage /*src*/, tempImage /*dst*/ );
1299 texImage->TexFormat->StoreImage(ctx, 2, texImage->Format,
1300 texImage->TexFormat, texImage->Data,
1301 xoffset * mml->wScale, yoffset * mml->hScale, 0, /* dstX/Y/Zoffset */
1302 dstRowStride,
1303 0, /* dstImageStride */
1304 newWidth, newHeight, 1,
1305 GL_RGBA, CHAN_TYPE, tempImage, &ctx->DefaultPacking);
1306 FREE(rawImage);
1307 }
1308
1309 FREE(tempImage);
1310
1311 return GL_TRUE;
1312 }
1313
1314
1315 void
1316 fxDDTexImage2D(GLcontext * ctx, GLenum target, GLint level,
1317 GLint internalFormat, GLint width, GLint height, GLint border,
1318 GLenum format, GLenum type, const GLvoid * pixels,
1319 const struct gl_pixelstore_attrib *packing,
1320 struct gl_texture_object *texObj,
1321 struct gl_texture_image *texImage)
1322 {
1323 fxMesaContext fxMesa = FX_CONTEXT(ctx);
1324 tfxTexInfo *ti;
1325 tfxMipMapLevel *mml;
1326 GLint texelBytes, dstRowStride;
1327
1328 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
1329 fprintf(stderr, "fxDDTexImage2D: id=%d int 0x%x format 0x%x type 0x%x %dx%d\n",
1330 texObj->Name, texImage->IntFormat, format, type,
1331 texImage->Width, texImage->Height);
1332 }
1333
1334 if (!fxIsTexSupported(target, internalFormat, texImage)) {
1335 _mesa_problem(NULL, "fx Driver: unsupported texture in fxDDTexImg()\n");
1336 return;
1337 }
1338
1339 if (!texObj->DriverData) {
1340 texObj->DriverData = fxAllocTexObjData(fxMesa);
1341 if (!texObj->DriverData) {
1342 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1343 return;
1344 }
1345 }
1346 ti = fxTMGetTexInfo(texObj);
1347
1348 if (!texImage->DriverData) {
1349 texImage->DriverData = CALLOC(sizeof(tfxMipMapLevel));
1350 if (!texImage->DriverData) {
1351 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1352 return;
1353 }
1354 }
1355 mml = FX_MIPMAP_DATA(texImage);
1356
1357 fxTexGetInfo(width, height, NULL, NULL, NULL, NULL,
1358 &mml->wScale, &mml->hScale);
1359
1360 mml->width = width * mml->wScale;
1361 mml->height = height * mml->hScale;
1362
1363 #if FX_COMPRESS_S3TC_AS_FXT1_HACK
1364 /* [koolsmoky] substitute FXT1 for DXTn and Legacy S3TC */
1365 if (!ctx->Mesa_DXTn && texImage->IsCompressed) {
1366 switch (internalFormat) {
1367 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1368 case GL_RGB_S3TC:
1369 case GL_RGB4_S3TC:
1370 internalFormat = GL_COMPRESSED_RGB_FXT1_3DFX;
1371 break;
1372 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1373 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1374 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1375 case GL_RGBA_S3TC:
1376 case GL_RGBA4_S3TC:
1377 internalFormat = GL_COMPRESSED_RGBA_FXT1_3DFX;
1378 }
1379 texImage->IntFormat = internalFormat;
1380 }
1381 #endif
1382 #if FX_TC_NAPALM
1383 if (fxMesa->type >= GR_SSTTYPE_Voodoo4) {
1384 GLenum texNapalm = 0;
1385 if (internalFormat == GL_COMPRESSED_RGB) {
1386 texNapalm = GL_COMPRESSED_RGB_FXT1_3DFX;
1387 } else if (internalFormat == GL_COMPRESSED_RGBA) {
1388 texNapalm = GL_COMPRESSED_RGBA_FXT1_3DFX;
1389 }
1390 if (texNapalm) {
1391 texImage->IntFormat = internalFormat = texNapalm;
1392 texImage->IsCompressed = GL_TRUE;
1393 }
1394 }
1395 #endif
1396
1397 /* choose the texture format */
1398 assert(ctx->Driver.ChooseTextureFormat);
1399 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
1400 internalFormat, format, type);
1401 assert(texImage->TexFormat);
1402 texelBytes = texImage->TexFormat->TexelBytes;
1403 /*if (!fxMesa->HaveTexFmt) assert(texelBytes == 1 || texelBytes == 2);*/
1404
1405 mml->glideFormat = fxGlideFormat(texImage->TexFormat->MesaFormat);
1406
1407 /* allocate mipmap buffer */
1408 assert(!texImage->Data);
1409 if (texImage->IsCompressed) {
1410 texImage->CompressedSize = _mesa_compressed_texture_size(ctx,
1411 mml->width,
1412 mml->height,
1413 1,
1414 internalFormat);
1415 dstRowStride = _mesa_compressed_row_stride(internalFormat, mml->width);
1416 texImage->Data = MESA_PBUFFER_ALLOC(texImage->CompressedSize);
1417 } else {
1418 dstRowStride = mml->width * texelBytes;
1419 texImage->Data = MESA_PBUFFER_ALLOC(mml->width * mml->height * texelBytes);
1420 }
1421 if (!texImage->Data) {
1422 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1423 return;
1424 }
1425
1426 if (pixels != NULL) {
1427 if (mml->wScale != 1 || mml->hScale != 1) {
1428 /* rescale image to overcome 1:8 aspect limitation */
1429 if (!adjust2DRatio(ctx,
1430 0, 0,
1431 width, height,
1432 format, type, pixels,
1433 packing,
1434 mml,
1435 texImage,
1436 texelBytes,
1437 dstRowStride)
1438 ) {
1439 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1440 return;
1441 }
1442 }
1443 else {
1444 /* no rescaling needed */
1445 /* unpack image, apply transfer ops and store in texImage->Data */
1446 texImage->TexFormat->StoreImage(ctx, 2, texImage->Format,
1447 texImage->TexFormat, texImage->Data,
1448 0, 0, 0, /* dstX/Y/Zoffset */
1449 dstRowStride,
1450 0, /* dstImageStride */
1451 width, height, 1,
1452 format, type, pixels, packing);
1453 }
1454 #if FX_TC_NCC
1455 if (fxMesa->HaveTexus2) {
1456 GLenum texNCC = 0;
1457 GLuint texSize = mml->width * mml->height;
1458 if (internalFormat == GL_COMPRESSED_RGB) {
1459 texNCC = GR_TEXFMT_YIQ_422;
1460 } else if (internalFormat == GL_COMPRESSED_RGBA) {
1461 texNCC = GR_TEXFMT_AYIQ_8422;
1462 texSize <<= 1;
1463 }
1464 if (texNCC) {
1465 TxMip txMip, pxMip;
1466 GLubyte *tempImage = MESA_PBUFFER_ALLOC(texSize);
1467 if (!tempImage) {
1468 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1469 return;
1470 }
1471 txMip.width = mml->width;
1472 txMip.height = mml->height;
1473 txMip.depth = 1;
1474 txMip.data[0] = texImage->Data;
1475 pxMip.data[0] = tempImage;
1476 fxMesa->Glide.txMipQuantize(&pxMip, &txMip, texNCC, TX_DITHER_ERR, TX_COMPRESSION_HEURISTIC);
1477 if (level == 0) {
1478 fxMesa->Glide.txPalToNcc((GuNccTable *)(&(ti->palette)), pxMip.pal);
1479 }
1480 MESA_PBUFFER_FREE(texImage->Data);
1481 texImage->Data = tempImage;
1482 mml->glideFormat = texNCC;
1483 }
1484 }
1485 #endif
1486
1487 /* GL_SGIS_generate_mipmap */
1488 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1489 GLint mipWidth, mipHeight;
1490 tfxMipMapLevel *mip;
1491 struct gl_texture_image *mipImage;
1492 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1493 const GLint maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
1494
1495 assert(!texImage->IsCompressed);
1496
1497 while (level < texObj->MaxLevel && level < maxLevels - 1) {
1498 mipWidth = width / 2;
1499 if (!mipWidth) {
1500 mipWidth = 1;
1501 }
1502 mipHeight = height / 2;
1503 if (!mipHeight) {
1504 mipHeight = 1;
1505 }
1506 if ((mipWidth == width) && (mipHeight == height)) {
1507 break;
1508 }
1509 _mesa_TexImage2D(target, ++level, internalFormat,
1510 mipWidth, mipHeight, border,
1511 format, type,
1512 NULL);
1513 mipImage = _mesa_select_tex_image(ctx, texUnit, target, level);
1514 mip = FX_MIPMAP_DATA(mipImage);
1515 _mesa_halve2x2_teximage2d(ctx,
1516 texImage,
1517 texelBytes,
1518 mml->width, mml->height,
1519 texImage->Data, mipImage->Data);
1520 texImage = mipImage;
1521 mml = mip;
1522 width = mipWidth;
1523 height = mipHeight;
1524 }
1525 }
1526 }
1527
1528 ti->info.format = mml->glideFormat;
1529 texImage->FetchTexelc = fxFetchFunction(texImage->TexFormat->MesaFormat);
1530
1531 fxTexInvalidate(ctx, texObj);
1532 }
1533
1534
1535 void
1536 fxDDTexSubImage2D(GLcontext * ctx, GLenum target, GLint level,
1537 GLint xoffset, GLint yoffset,
1538 GLsizei width, GLsizei height,
1539 GLenum format, GLenum type, const GLvoid * pixels,
1540 const struct gl_pixelstore_attrib *packing,
1541 struct gl_texture_object *texObj,
1542 struct gl_texture_image *texImage)
1543 {
1544 fxMesaContext fxMesa = FX_CONTEXT(ctx);
1545 tfxTexInfo *ti;
1546 tfxMipMapLevel *mml;
1547 GLint texelBytes, dstRowStride;
1548
1549 /* [dBorca] Hack alert:
1550 * FX_TC_NCC not supported
1551 */
1552
1553 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
1554 fprintf(stderr, "fxDDTexSubImage2D: id=%d\n", texObj->Name);
1555 }
1556
1557 if (!texObj->DriverData) {
1558 _mesa_problem(ctx, "problem in fxDDTexSubImage2D");
1559 return;
1560 }
1561
1562 ti = fxTMGetTexInfo(texObj);
1563 assert(ti);
1564 mml = FX_MIPMAP_DATA(texImage);
1565 assert(mml);
1566
1567 assert(texImage->Data); /* must have an existing texture image! */
1568 assert(texImage->Format);
1569
1570 texelBytes = texImage->TexFormat->TexelBytes;
1571 if (texImage->IsCompressed) {
1572 dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat, mml->width);
1573 } else {
1574 dstRowStride = mml->width * texelBytes;
1575 }
1576
1577 if (mml->wScale != 1 || mml->hScale != 1) {
1578 /* need to rescale subimage to match mipmap level's rescale factors */
1579 if (!adjust2DRatio(ctx,
1580 xoffset, yoffset,
1581 width, height,
1582 format, type, pixels,
1583 packing,
1584 mml,
1585 texImage,
1586 texelBytes,
1587 dstRowStride)
1588 ) {
1589 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
1590 return;
1591 }
1592 }
1593 else {
1594 /* no rescaling needed */
1595 texImage->TexFormat->StoreImage(ctx, 2, texImage->Format,
1596 texImage->TexFormat, (GLubyte *) texImage->Data,
1597 xoffset, yoffset, 0, /* dstX/Y/Zoffset */
1598 dstRowStride,
1599 0, /* dstImageStride */
1600 width, height, 1,
1601 format, type, pixels, packing);
1602 }
1603
1604 /* GL_SGIS_generate_mipmap */
1605 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1606 GLint mipWidth, mipHeight;
1607 tfxMipMapLevel *mip;
1608 struct gl_texture_image *mipImage;
1609 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1610 const GLint maxLevels = _mesa_max_texture_levels(ctx, texObj->Target);
1611
1612 assert(!texImage->IsCompressed);
1613
1614 width = texImage->Width;
1615 height = texImage->Height;
1616 while (level < texObj->MaxLevel && level < maxLevels - 1) {
1617 mipWidth = width / 2;
1618 if (!mipWidth) {
1619 mipWidth = 1;
1620 }
1621 mipHeight = height / 2;
1622 if (!mipHeight) {
1623 mipHeight = 1;
1624 }
1625 if ((mipWidth == width) && (mipHeight == height)) {
1626 break;
1627 }
1628 ++level;
1629 mipImage = _mesa_select_tex_image(ctx, texUnit, target, level);
1630 mip = FX_MIPMAP_DATA(mipImage);
1631 _mesa_halve2x2_teximage2d(ctx,
1632 texImage,
1633 texelBytes,
1634 mml->width, mml->height,
1635 texImage->Data, mipImage->Data);
1636 texImage = mipImage;
1637 mml = mip;
1638 width = mipWidth;
1639 height = mipHeight;
1640 }
1641 }
1642
1643 if (ti->validated && ti->isInTM && !texObj->GenerateMipmap)
1644 fxTMReloadMipMapLevel(fxMesa, texObj, level);
1645 else
1646 fxTexInvalidate(ctx, texObj);
1647 }
1648
1649
1650 void
1651 fxDDCompressedTexImage2D (GLcontext *ctx, GLenum target,
1652 GLint level, GLint internalFormat,
1653 GLsizei width, GLsizei height, GLint border,
1654 GLsizei imageSize, const GLvoid *data,
1655 struct gl_texture_object *texObj,
1656 struct gl_texture_image *texImage)
1657 {
1658 fxMesaContext fxMesa = FX_CONTEXT(ctx);
1659 tfxTexInfo *ti;
1660 tfxMipMapLevel *mml;
1661
1662 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
1663 fprintf(stderr, "fxDDCompressedTexImage2D: id=%d int 0x%x %dx%d\n",
1664 texObj->Name, internalFormat,
1665 width, height);
1666 }
1667
1668 assert(texImage->IsCompressed);
1669
1670 if (!fxIsTexSupported(target, internalFormat, texImage)) {
1671 _mesa_problem(NULL, "fx Driver: unsupported texture in fxDDCompressedTexImg()\n");
1672 return;
1673 }
1674
1675 if (!texObj->DriverData) {
1676 texObj->DriverData = fxAllocTexObjData(fxMesa);
1677 if (!texObj->DriverData) {
1678 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
1679 return;
1680 }
1681 }
1682 ti = fxTMGetTexInfo(texObj);
1683
1684 if (!texImage->DriverData) {
1685 texImage->DriverData = CALLOC(sizeof(tfxMipMapLevel));
1686 if (!texImage->DriverData) {
1687 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
1688 return;
1689 }
1690 }
1691 mml = FX_MIPMAP_DATA(texImage);
1692
1693 fxTexGetInfo(width, height, NULL, NULL, NULL, NULL,
1694 &mml->wScale, &mml->hScale);
1695
1696 mml->width = width * mml->wScale;
1697 mml->height = height * mml->hScale;
1698
1699
1700 /* choose the texture format */
1701 assert(ctx->Driver.ChooseTextureFormat);
1702 texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
1703 internalFormat, -1/*format*/, -1/*type*/);
1704 assert(texImage->TexFormat);
1705
1706 /* Determine the appropriate Glide texel format,
1707 * given the user's internal texture format hint.
1708 */
1709 mml->glideFormat = fxGlideFormat(texImage->TexFormat->MesaFormat);
1710
1711 /* allocate new storage for texture image, if needed */
1712 if (!texImage->Data) {
1713 texImage->CompressedSize = _mesa_compressed_texture_size(ctx,
1714 mml->width,
1715 mml->height,
1716 1,
1717 internalFormat);
1718 texImage->Data = MESA_PBUFFER_ALLOC(texImage->CompressedSize);
1719 if (!texImage->Data) {
1720 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
1721 return;
1722 }
1723 }
1724
1725 /* save the texture data */
1726 if (mml->wScale != 1 || mml->hScale != 1) {
1727 /* [dBorca] Hack alert:
1728 * now we're screwed. We can't decompress,
1729 * unless we do it in HW (via textureBuffer).
1730 * We still have some chances:
1731 * 1) we got FXT1 textures - we CAN decompress, rescale for
1732 * aspectratio, then compress back.
1733 * 2) there is a chance that MIN("s", "t") won't be overflowed.
1734 * Thus, we don't care about textureclamp and we could lower
1735 * MIN("uscale", "vscale") below 32. We still have to have
1736 * our data aligned inside a 8:1 rectangle.
1737 * 3) just in case if MIN("s", "t") gets overflowed with GL_REPEAT,
1738 * we replicate the data over the padded area.
1739 * For now, we take 2) + 3) but texelfetchers will be wrong!
1740 */
1741 GLuint srcRowStride = _mesa_compressed_row_stride(internalFormat, width);
1742
1743 GLuint destRowStride = _mesa_compressed_row_stride(internalFormat,
1744 mml->width);
1745
1746 _mesa_upscale_teximage2d(srcRowStride, (height+3) / 4,
1747 destRowStride, (mml->height+3) / 4,
1748 1, data, srcRowStride,
1749 texImage->Data);
1750 ti->padded = GL_TRUE;
1751 } else {
1752 MEMCPY(texImage->Data, data, texImage->CompressedSize);
1753 }
1754
1755 ti->info.format = mml->glideFormat;
1756 texImage->FetchTexelc = fxFetchFunction(texImage->TexFormat->MesaFormat);
1757
1758 /* GL_SGIS_generate_mipmap */
1759 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1760 assert(!texImage->IsCompressed);
1761 }
1762
1763 fxTexInvalidate(ctx, texObj);
1764 }
1765
1766
1767 void
1768 fxDDCompressedTexSubImage2D( GLcontext *ctx, GLenum target,
1769 GLint level, GLint xoffset,
1770 GLint yoffset, GLsizei width,
1771 GLint height, GLenum format,
1772 GLsizei imageSize, const GLvoid *data,
1773 struct gl_texture_object *texObj,
1774 struct gl_texture_image *texImage )
1775 {
1776 fxMesaContext fxMesa = FX_CONTEXT(ctx);
1777 tfxTexInfo *ti;
1778 tfxMipMapLevel *mml;
1779 GLint destRowStride, srcRowStride;
1780 GLint i, rows;
1781 GLubyte *dest;
1782
1783 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
1784 fprintf(stderr, "fxDDCompressedTexSubImage2D: id=%d\n", texObj->Name);
1785 }
1786
1787 ti = fxTMGetTexInfo(texObj);
1788 assert(ti);
1789 mml = FX_MIPMAP_DATA(texImage);
1790 assert(mml);
1791
1792 srcRowStride = _mesa_compressed_row_stride(texImage->IntFormat, width);
1793
1794 destRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
1795 mml->width);
1796 dest = _mesa_compressed_image_address(xoffset, yoffset, 0,
1797 texImage->IntFormat,
1798 mml->width,
1799 (GLubyte*) texImage->Data);
1800
1801 rows = height / 4; /* hardcoded 4, but works for FXT1/DXTC */
1802
1803 for (i = 0; i < rows; i++) {
1804 MEMCPY(dest, data, srcRowStride);
1805 dest += destRowStride;
1806 data = (GLvoid *)((GLuint)data + (GLuint)srcRowStride);
1807 }
1808
1809 /* [dBorca] Hack alert:
1810 * see fxDDCompressedTexImage2D for caveats
1811 */
1812 if (mml->wScale != 1 || mml->hScale != 1) {
1813 srcRowStride = _mesa_compressed_row_stride(texImage->IntFormat, texImage->Width);
1814
1815 destRowStride = _mesa_compressed_row_stride(texImage->IntFormat,
1816 mml->width);
1817 _mesa_upscale_teximage2d(srcRowStride, texImage->Height / 4,
1818 destRowStride, mml->height / 4,
1819 1, texImage->Data, destRowStride,
1820 texImage->Data);
1821 }
1822
1823 /* GL_SGIS_generate_mipmap */
1824 if (level == texObj->BaseLevel && texObj->GenerateMipmap) {
1825 assert(!texImage->IsCompressed);
1826 }
1827
1828 if (ti->validated && ti->isInTM)
1829 fxTMReloadMipMapLevel(fxMesa, texObj, level);
1830 else
1831 fxTexInvalidate(ctx, texObj);
1832 }
1833
1834
1835 void
1836 fxDDTexImage1D (GLcontext *ctx, GLenum target, GLint level,
1837 GLint internalFormat, GLint width, GLint border,
1838 GLenum format, GLenum type, const GLvoid *pixels,
1839 const struct gl_pixelstore_attrib *packing,
1840 struct gl_texture_object *texObj,
1841 struct gl_texture_image *texImage)
1842 {
1843 fxDDTexImage2D(ctx, target, level,
1844 internalFormat, width, 1, border,
1845 format, type, pixels,
1846 packing,
1847 texObj,
1848 texImage);
1849 }
1850
1851
1852 void
1853 fxDDTexSubImage1D(GLcontext * ctx, GLenum target, GLint level,
1854 GLint xoffset,
1855 GLsizei width,
1856 GLenum format, GLenum type, const GLvoid * pixels,
1857 const struct gl_pixelstore_attrib *packing,
1858 struct gl_texture_object *texObj,
1859 struct gl_texture_image *texImage)
1860 {
1861 fxDDTexSubImage2D(ctx, target, level,
1862 xoffset, 0, width, 1,
1863 format, type, pixels,
1864 packing,
1865 texObj,
1866 texImage);
1867 }
1868
1869
1870 GLboolean
1871 fxDDTestProxyTexImage (GLcontext *ctx, GLenum target,
1872 GLint level, GLint internalFormat,
1873 GLenum format, GLenum type,
1874 GLint width, GLint height,
1875 GLint depth, GLint border)
1876 {
1877 /* XXX todo - maybe through fxTexValidate() */
1878 return _mesa_test_proxy_teximage(ctx, target,
1879 level, internalFormat,
1880 format, type,
1881 width, height,
1882 depth, border);
1883 }
1884
1885
1886 #else /* FX */
1887
1888 /*
1889 * Need this to provide at least one external definition.
1890 */
1891
1892 extern int gl_fx_dummy_function_ddtex(void);
1893 int
1894 gl_fx_dummy_function_ddtex(void)
1895 {
1896 return 0;
1897 }
1898
1899 #endif /* FX */