Fixed texture tiling format for 8bit texels on ProSavage and Twister.
[mesa.git] / src / mesa / drivers / dri / savage / savagetex.c
1 /*
2 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include <stdlib.h>
27 #include <stdio.h>
28
29 #include <GL/gl.h>
30
31 #include "mm.h"
32 #include "savagecontext.h"
33 #include "savagetex.h"
34 #include "savagetris.h"
35 #include "savageioctl.h"
36 #include "simple_list.h"
37 #include "enums.h"
38 #include "savage_bci.h"
39
40 #include "macros.h"
41 #include "texformat.h"
42 #include "texstore.h"
43 #include "texobj.h"
44
45 #include "swrast/swrast.h"
46
47 /* Size 1, 2 and 4 images are packed into the last subtile. Each image
48 * is repeated to fill a 4x4 pixel area. The figure below shows the
49 * layout of those 4x4 pixel areas in the 8x8 subtile.
50 *
51 * 4 2
52 * x 1
53 */
54 static const savageTileInfo tileInfo_pro[5] = {
55 {64, 64, 8, 8, 8, 8, {0x12, 0x02}}, /* 4-bit */
56 {64, 32, 16, 4, 4, 8, {0x30, 0x20}}, /* 8-bit */
57 {64, 16, 8, 2, 8, 8, {0x48, 0x08}}, /* 16-bit */
58 { 0, 0, 0, 0, 0, 0, {0x00, 0x00}}, /* 24-bit */
59 {32, 16, 4, 2, 8, 8, {0x90, 0x10}}, /* 32-bit */
60 };
61
62 /* Size 1, 2 and 4 images are packed into the last two subtiles. Each
63 * image is repeated to fill a 4x4 pixel area. The figures below show
64 * the layout of those 4x4 pixel areas in the two 4x8 subtiles.
65 *
66 * second last subtile: 4 last subtile: 2
67 * x 1
68 */
69 static const savageTileInfo tileInfo_s3d_s4[5] = {
70 {64, 64, 16, 8, 4, 8, {0x18, 0x10}}, /* 4-bit */
71 {64, 32, 16, 4, 4, 8, {0x30, 0x20}}, /* 8-bit */
72 {64, 16, 16, 2, 4, 8, {0x60, 0x40}}, /* 16-bit */
73 { 0, 0, 0, 0, 0, 0, {0x00, 0x00}}, /* 24-bit */
74 {32, 16, 8, 2, 4, 8, {0xc0, 0x80}}, /* 32-bit */
75 };
76
77 /** \brief Upload a complete tile from src (srcStride) to dest
78 *
79 * \param tileInfo Pointer to tiling information
80 * \param wInSub Width of source/dest image in subtiles
81 * \param hInSub Height of source/dest image in subtiles
82 * \param bpp Bytes per pixel
83 * \param src Pointer to source data
84 * \param srcStride Byte stride of rows in the source data
85 * \param dest Pointer to destination
86 *
87 * Processes rows of source data linearly and scatters them into the
88 * subtiles.
89 *
90 * For a complete tile wInSub and hInSub are set to the same values as
91 * in tileInfo. If the source image is smaller than a whole tile in
92 * one or both dimensions then they are set to the values of the
93 * source image. This only works as long as the source image is bigger
94 * than 8x8 pixels.
95 */
96 static void savageUploadTile (const savageTileInfo *tileInfo,
97 GLuint wInSub, GLuint hInSub, GLuint bpp,
98 GLubyte *src, GLuint srcStride, GLubyte *dest) {
99 GLuint destStride = tileInfo->subWidth * tileInfo->subHeight * bpp;
100 GLuint subStride = tileInfo->subWidth * bpp;
101 GLubyte *srcRow = src, *destSRow = dest, *destRow = dest;
102 GLuint sx, sy, y;
103 /* iterate over subtile rows */
104 for (sy = 0; sy < hInSub; ++sy) {
105 destRow = destSRow;
106 /* iterate over pixel rows within the subtile row */
107 for (y = 0; y < tileInfo->subHeight; ++y) {
108 src = srcRow;
109 dest = destRow;
110 /* iterate over subtile columns */
111 for (sx = 0; sx < wInSub; ++sx) {
112 memcpy (dest, src, subStride);
113 src += subStride;
114 dest += destStride;
115 }
116 srcRow += srcStride;
117 destRow += subStride;
118 }
119 destSRow += destStride * wInSub;
120 }
121 }
122
123 /** \brief Upload a texture image that is smaller than 8x8 pixels.
124 *
125 * \param tileInfo
126 * \param width
127 * \param height
128 * \param bpp
129 * \param src
130 * \param dest
131 */
132 static void savageUploadTiny (const savageTileInfo *tileInfo,
133 GLuint width, GLuint height, GLuint bpp,
134 GLubyte *src, GLubyte *dest) {
135 GLuint size = MAX2(width, height);
136 GLuint offset = (size <= 2 ? tileInfo->tinyOffset[size-1] : 0);
137 GLuint wInSub = width / tileInfo->subWidth;
138
139 #if 0
140 /* Fill the file with a test pattern */
141 GLuint i;
142 GLushort *sdest = (GLushort*)dest;
143 if (offset)
144 sdest += 0x20;
145 for (i = 0; i < tileInfo->subWidth*tileInfo->subHeight; ++i) {
146 GLuint x = i;
147 GLuint mask = 0;
148 GLushort val = 0;
149 switch (i & 3) {
150 case 0: mask = 1; break;
151 case 1: mask = 2; break;
152 case 2: mask = 4; break;
153 case 3: mask = 7; break;
154 }
155 if (mask & 1)
156 val |= x;
157 if (mask & 2)
158 val |= x*2 << 5;
159 if (mask & 4)
160 val |= x << (5+6);
161 *sdest++ = val;
162 }
163 #else
164 if (wInSub > 1) { /* several subtiles wide but less than a subtile high */
165 GLuint destStride = tileInfo->subWidth * tileInfo->subHeight * bpp;
166 GLuint subStride = tileInfo->subWidth * bpp;
167 GLuint srcStride = width * bpp;
168 GLubyte *srcRow = src, *destRow = dest;
169 GLuint sx, y;
170 for (y = 0; y < height; ++y) {
171 src = srcRow;
172 dest = destRow;
173 /* iterate over subtile columns */
174 for (sx = 0; sx < wInSub; ++sx) {
175 memcpy (dest, src, subStride);
176 src += subStride;
177 dest += destStride;
178 }
179 srcRow += srcStride;
180 destRow += subStride;
181 /* if the subtile width is 4 skip every other tile */
182 if ((y & 7) == 7 && tileInfo->subWidth == 4)
183 destRow += destStride;
184 }
185 } else if (size > 4) { /* not the last 3 mipmap levels */
186 GLuint y;
187 for (y = 0; y < height; ++y) {
188 memcpy (dest, src, bpp*width);
189 src += width * bpp;
190 dest += tileInfo->subWidth * bpp;
191 /* if the subtile width is 4 skip every other tile */
192 if ((y & 7) == 7 && tileInfo->subWidth == 4)
193 dest += tileInfo->subHeight * tileInfo->subWidth * bpp;
194 }
195 } else { /* the last 3 mipmap levels */
196 GLuint y;
197 dest += offset;
198 for (y = 0; y < height; ++y) {
199 memcpy (dest, src, bpp*width);
200 src += width * bpp;
201 dest += tileInfo->subWidth * bpp;
202 }
203 }
204 #endif
205 }
206
207 static GLuint savageTexImageSize (GLuint width, GLuint height, GLuint bpp) {
208 /* full subtiles */
209 if (width >= 8 && height >= 8)
210 return width * height * bpp;
211 /* special case for the last three mipmap levels: the hardware computes
212 * the offset internally */
213 else if (width <= 4 && height <= 4)
214 return 0;
215 /* partially filled sub tiles waste memory
216 * on Savage3D and Savage4 with subtile width 4 every other subtile is
217 * skipped if width < 8 so we can assume a uniform subtile width of 8 */
218 else if (width >= 8)
219 return width * 8 * bpp;
220 else if (height >= 8)
221 return 8 * height * bpp;
222 else
223 return 64 * bpp;
224 }
225
226 static void savageSetTexWrapping(savageTextureObjectPtr tex, GLenum s, GLenum t)
227 {
228 tex->texParams.sWrapMode = s;
229 tex->texParams.tWrapMode = t;
230 }
231
232 static void savageSetTexFilter(savageTextureObjectPtr t,
233 GLenum minf, GLenum magf)
234 {
235 t->texParams.minFilter = minf;
236 t->texParams.magFilter = magf;
237 }
238
239
240 /* Need a fallback ?
241 */
242 static void savageSetTexBorderColor(savageTextureObjectPtr t, GLubyte color[4])
243 {
244 /* t->Setup[SAVAGE_TEXREG_TEXBORDERCOL] = */
245 t->texParams.boarderColor = SAVAGEPACKCOLOR8888(color[0],color[1],color[2],color[3]);
246 }
247
248
249
250 static savageTextureObjectPtr
251 savageAllocTexObj( struct gl_texture_object *texObj )
252 {
253 savageTextureObjectPtr t;
254
255 t = (savageTextureObjectPtr) calloc(1,sizeof(*t));
256 texObj->DriverData = t;
257 if ( t != NULL ) {
258
259 /* Initialize non-image-dependent parts of the state:
260 */
261 t->globj = texObj;
262
263 /* FIXME Something here to set initial values for other parts of
264 * FIXME t->setup?
265 */
266
267 make_empty_list( t );
268
269 savageSetTexWrapping(t,texObj->WrapS,texObj->WrapT);
270 savageSetTexFilter(t,texObj->MinFilter,texObj->MagFilter);
271 savageSetTexBorderColor(t,texObj->_BorderChan);
272 }
273
274 return t;
275 }
276
277 /* Called by the _mesa_store_teximage[123]d() functions. */
278 static const struct gl_texture_format *
279 savageChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
280 GLenum format, GLenum type )
281 {
282 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
283 const GLboolean do32bpt = GL_FALSE;
284 const GLboolean force16bpt = GL_FALSE;
285 const GLboolean isSavage4 = (imesa->savageScreen->chipset >= S3_SAVAGE4);
286 (void) format;
287 (void) type;
288
289 switch ( internalFormat ) {
290 case 4:
291 case GL_RGBA:
292 case GL_COMPRESSED_RGBA:
293 switch ( type ) {
294 case GL_UNSIGNED_INT_10_10_10_2:
295 case GL_UNSIGNED_INT_2_10_10_10_REV:
296 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555;
297 case GL_UNSIGNED_SHORT_4_4_4_4:
298 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
299 return &_mesa_texformat_argb4444;
300 case GL_UNSIGNED_SHORT_5_5_5_1:
301 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
302 return &_mesa_texformat_argb1555;
303 default:
304 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
305 }
306
307 case 3:
308 case GL_RGB:
309 case GL_COMPRESSED_RGB:
310 switch ( type ) {
311 case GL_UNSIGNED_SHORT_4_4_4_4:
312 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
313 return &_mesa_texformat_argb4444;
314 case GL_UNSIGNED_SHORT_5_5_5_1:
315 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
316 return &_mesa_texformat_argb1555;
317 case GL_UNSIGNED_SHORT_5_6_5:
318 case GL_UNSIGNED_SHORT_5_6_5_REV:
319 return &_mesa_texformat_rgb565;
320 default:
321 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
322 }
323
324 case GL_RGBA8:
325 case GL_RGBA12:
326 case GL_RGBA16:
327 return !force16bpt ?
328 &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
329
330 case GL_RGB10_A2:
331 return !force16bpt ?
332 &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555;
333
334 case GL_RGBA4:
335 case GL_RGBA2:
336 return &_mesa_texformat_argb4444;
337
338 case GL_RGB5_A1:
339 return &_mesa_texformat_argb1555;
340
341 case GL_RGB8:
342 case GL_RGB10:
343 case GL_RGB12:
344 case GL_RGB16:
345 return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
346
347 case GL_RGB5:
348 case GL_RGB4:
349 case GL_R3_G3_B2:
350 return &_mesa_texformat_rgb565;
351
352 case GL_ALPHA:
353 case GL_COMPRESSED_ALPHA:
354 return isSavage4 ? &_mesa_texformat_a8 : (
355 do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
356 case GL_ALPHA4:
357 return isSavage4 ? &_mesa_texformat_a8 : &_mesa_texformat_argb4444;
358 case GL_ALPHA8:
359 case GL_ALPHA12:
360 case GL_ALPHA16:
361 return isSavage4 ? &_mesa_texformat_a8 : (
362 !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
363
364 case 1:
365 case GL_LUMINANCE:
366 case GL_COMPRESSED_LUMINANCE:
367 /* no alpha, but use argb1555 in 16bit case to get pure grey values */
368 return isSavage4 ? &_mesa_texformat_l8 : (
369 do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555);
370 case GL_LUMINANCE4:
371 return isSavage4 ? &_mesa_texformat_l8 : &_mesa_texformat_argb1555;
372 case GL_LUMINANCE8:
373 case GL_LUMINANCE12:
374 case GL_LUMINANCE16:
375 return isSavage4 ? &_mesa_texformat_l8 : (
376 !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555);
377
378 case 2:
379 case GL_LUMINANCE_ALPHA:
380 case GL_COMPRESSED_LUMINANCE_ALPHA:
381 /* Savage4 has a al44 texture format. But it's not supported by Mesa. */
382 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
383 case GL_LUMINANCE4_ALPHA4:
384 case GL_LUMINANCE6_ALPHA2:
385 return &_mesa_texformat_argb4444;
386 case GL_LUMINANCE8_ALPHA8:
387 case GL_LUMINANCE12_ALPHA4:
388 case GL_LUMINANCE12_ALPHA12:
389 case GL_LUMINANCE16_ALPHA16:
390 return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
391
392 case GL_INTENSITY:
393 case GL_COMPRESSED_INTENSITY:
394 return isSavage4 ? &_mesa_texformat_i8 : (
395 do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
396 case GL_INTENSITY4:
397 return isSavage4 ? &_mesa_texformat_i8 : &_mesa_texformat_argb4444;
398 case GL_INTENSITY8:
399 case GL_INTENSITY12:
400 case GL_INTENSITY16:
401 return isSavage4 ? &_mesa_texformat_i8 : (
402 !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
403 /*
404 case GL_COLOR_INDEX:
405 case GL_COLOR_INDEX1_EXT:
406 case GL_COLOR_INDEX2_EXT:
407 case GL_COLOR_INDEX4_EXT:
408 case GL_COLOR_INDEX8_EXT:
409 case GL_COLOR_INDEX12_EXT:
410 case GL_COLOR_INDEX16_EXT:
411 return &_mesa_texformat_ci8;
412 */
413 default:
414 _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__);
415 return NULL;
416 }
417 }
418
419 static void savageSetTexImages( savageContextPtr imesa,
420 const struct gl_texture_object *tObj )
421 {
422 savageTextureObjectPtr t = (savageTextureObjectPtr) tObj->DriverData;
423 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
424 GLuint offset, i, textureFormat, size;
425
426 assert(t);
427 assert(image);
428
429 switch (image->TexFormat->MesaFormat) {
430 case MESA_FORMAT_ARGB8888:
431 textureFormat = TFT_ARGB8888;
432 t->texelBytes = 4;
433 break;
434 case MESA_FORMAT_ARGB1555:
435 textureFormat = TFT_ARGB1555;
436 t->texelBytes = 2;
437 break;
438 case MESA_FORMAT_ARGB4444:
439 textureFormat = TFT_ARGB4444;
440 t->texelBytes = 2;
441 break;
442 case MESA_FORMAT_RGB565:
443 textureFormat = TFT_RGB565;
444 t->texelBytes = 2;
445 break;
446 case MESA_FORMAT_L8:
447 textureFormat = TFT_L8;
448 t->texelBytes = 1;
449 break;
450 case MESA_FORMAT_I8:
451 textureFormat = TFT_I8;
452 t->texelBytes = 1;
453 break;
454 case MESA_FORMAT_A8:
455 textureFormat = TFT_A8;
456 t->texelBytes = 1;
457 break;
458 default:
459 _mesa_problem(imesa->glCtx, "Bad texture format in %s", __FUNCTION__);
460 return;
461 }
462
463 /* Select tiling format depending on the chipset and bytes per texel */
464 if (imesa->savageScreen->chipset <= S3_SAVAGE4)
465 t->tileInfo = &tileInfo_s3d_s4[t->texelBytes];
466 else
467 t->tileInfo = &tileInfo_pro[t->texelBytes];
468
469 /* Figure out the size now (and count the levels). Upload won't be done
470 * until later.
471 */
472 t->dirty_images = 0;
473 offset = 0;
474 size = 1;
475 for ( i = 0 ; i < SAVAGE_TEX_MAXLEVELS && tObj->Image[0][i] ; i++ ) {
476 image = tObj->Image[0][i];
477 t->image[i].image = image;
478 t->image[i].offset = offset;
479 t->image[i].internalFormat = textureFormat;
480 t->dirty_images |= (1<<i);
481 size = savageTexImageSize (image->Width2, image->Height2,
482 t->texelBytes);
483 offset += size;
484 }
485
486 t->totalSize = offset;
487 /* the last three mipmap levels don't add to the offset. They are packed
488 * into 64 pixels. */
489 if (size == 0)
490 t->totalSize += 64 * t->texelBytes;
491 /* 2k-aligned */
492 t->totalSize = (t->totalSize + 2047UL) & ~2047UL;
493 t->max_level = i-1;
494 t->min_level = 0;
495 }
496
497 void savageDestroyTexObj(savageContextPtr imesa, savageTextureObjectPtr t)
498 {
499 if (!t) return;
500
501 /* This is sad - need to sync *in case* we upload a texture
502 * to this newly free memory...
503 */
504 if (t->MemBlock) {
505 mmFreeMem(t->MemBlock);
506 t->MemBlock = 0;
507
508 if (t->age > imesa->dirtyAge)
509 imesa->dirtyAge = t->age;
510 }
511
512 if (t->globj)
513 t->globj->DriverData = 0;
514
515 remove_from_list(t);
516 free(t);
517 }
518
519
520 static void savageSwapOutTexObj(savageContextPtr imesa, savageTextureObjectPtr t)
521 {
522 if (t->MemBlock) {
523 mmFreeMem(t->MemBlock);
524 t->MemBlock = 0;
525
526 if (t->age > imesa->dirtyAge)
527 imesa->dirtyAge = t->age;
528 }
529
530 t->dirty_images = ~0;
531 move_to_tail(&(imesa->SwappedOut), t);
532 }
533
534
535
536 /* Upload an image from mesa's internal copy.
537 */
538 static void savageUploadTexLevel( savageTextureObjectPtr t, int level )
539 {
540 const struct gl_texture_image *image = t->image[level].image;
541 const savageTileInfo *tileInfo = t->tileInfo;
542 GLuint width = image->Width2, height = image->Height2;
543 GLuint bpp = t->texelBytes;
544
545 /* Need triangle (rather than pixel) fallbacks to simulate this using
546 * normal textured triangles.
547 *
548 * DO THIS IN DRIVER STATE MANAGMENT, not hardware state.
549 *
550 */
551
552 if(image->Border != 0)
553 fprintf (stderr, "Not supported texture border %d.\n",
554 (int) image->Border);
555
556 if (width >= 8 && height >= tileInfo->subHeight) {
557 if (width >= tileInfo->width && height >= tileInfo->height) {
558 GLuint wInTiles = width / tileInfo->width;
559 GLuint hInTiles = height / tileInfo->height;
560 GLubyte *srcTRow = image->Data, *src;
561 GLubyte *dest = (GLubyte *)(t->BufAddr + t->image[level].offset);
562 GLuint x, y;
563 for (y = 0; y < hInTiles; ++y) {
564 src = srcTRow;
565 for (x = 0; x < wInTiles; ++x) {
566 savageUploadTile (tileInfo,
567 tileInfo->wInSub, tileInfo->hInSub, bpp,
568 src, width * bpp, dest);
569 src += tileInfo->width * bpp;
570 dest += 2048; /* tile size is always 2k */
571 }
572 srcTRow += width * tileInfo->height * bpp;
573 }
574 } else {
575 savageUploadTile (tileInfo, width / tileInfo->subWidth,
576 height / tileInfo->subHeight, bpp,
577 image->Data, width * bpp,
578 (GLubyte *)(t->BufAddr + t->image[level].offset));
579 }
580 } else {
581 GLuint minHeight, minWidth, hRepeat, vRepeat, x, y;
582 if (width > 4 || height > 4) {
583 minWidth = tileInfo->subWidth;
584 minHeight = tileInfo->subHeight;
585 } else {
586 minWidth = 4;
587 minHeight = 4;
588 }
589 hRepeat = width >= minWidth ? 1 : minWidth / width;
590 vRepeat = height >= minHeight ? 1 : minHeight / height;
591 for (y = 0; y < vRepeat; ++y)
592 for (x = 0; x < hRepeat; ++x) {
593 GLuint offset = (y * tileInfo->subWidth*height +
594 x * width) * bpp;
595 savageUploadTiny (tileInfo, width, height, bpp, image->Data,
596 (GLubyte *)(t->BufAddr +
597 t->image[level].offset + offset));
598 }
599 }
600 }
601
602
603
604 void savagePrintLocalLRU( savageContextPtr imesa , GLuint heap)
605 {
606 savageTextureObjectPtr t;
607 int sz = 1 << (imesa->savageScreen->logTextureGranularity[heap]);
608
609 foreach( t, &imesa->TexObjList[heap] ) {
610 if (!t->globj)
611 fprintf(stderr, "Placeholder %d at %x sz %x\n",
612 t->MemBlock->ofs / sz,
613 t->MemBlock->ofs,
614 t->MemBlock->size);
615 else
616 fprintf(stderr, "Texture (bound %d) at %x sz %x\n",
617 t->bound,
618 t->MemBlock->ofs,
619 t->MemBlock->size);
620
621 }
622 }
623
624 void savagePrintGlobalLRU( savageContextPtr imesa , GLuint heap)
625 {
626 int i, j;
627
628 drm_savage_tex_region_t *list = imesa->sarea->texList[heap];
629
630
631 for (i = 0, j = SAVAGE_NR_TEX_REGIONS ; i < SAVAGE_NR_TEX_REGIONS ; i++) {
632 fprintf(stderr, "list[%d] age %d next %d prev %d\n",
633 j, list[j].age, list[j].next, list[j].prev);
634 j = list[j].next;
635 if (j == SAVAGE_NR_TEX_REGIONS) break;
636 }
637
638 if (j != SAVAGE_NR_TEX_REGIONS)
639 fprintf(stderr, "Loop detected in global LRU\n");
640 for (i = 0 ; i < SAVAGE_NR_TEX_REGIONS ; i++)
641 {
642 fprintf(stderr,"list[%d] age %d next %d prev %d\n",
643 i, list[i].age, list[i].next, list[i].prev);
644 }
645 }
646
647
648 void savageResetGlobalLRU( savageContextPtr imesa, GLuint heap )
649 {
650 drm_savage_tex_region_t *list = imesa->sarea->texList[heap];
651 int sz = 1 << imesa->savageScreen->logTextureGranularity[heap];
652 int i;
653
654 /* (Re)initialize the global circular LRU list. The last element
655 * in the array (SAVAGE_NR_TEX_REGIONS) is the sentinal. Keeping it
656 * at the end of the array allows it to be addressed rationally
657 * when looking up objects at a particular location in texture
658 * memory.
659 */
660 for (i = 0 ; (i+1) * sz <= imesa->savageScreen->textureSize[heap]; i++) {
661 list[i].prev = i-1;
662 list[i].next = i+1;
663 list[i].age = 0;
664 }
665
666 i--;
667 list[0].prev = SAVAGE_NR_TEX_REGIONS;
668 list[i].prev = i-1;
669 list[i].next = SAVAGE_NR_TEX_REGIONS;
670 list[SAVAGE_NR_TEX_REGIONS].prev = i;
671 list[SAVAGE_NR_TEX_REGIONS].next = 0;
672 imesa->sarea->texAge[heap] = 0;
673 }
674
675
676 static void savageUpdateTexLRU( savageContextPtr imesa, savageTextureObjectPtr t )
677 {
678 int i;
679 int heap = t->heap;
680 int logsz = imesa->savageScreen->logTextureGranularity[heap];
681 int start = t->MemBlock->ofs >> logsz;
682 int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz;
683 drm_savage_tex_region_t *list = imesa->sarea->texList[heap];
684
685 imesa->texAge[heap] = ++imesa->sarea->texAge[heap];
686
687 /* Update our local LRU
688 */
689 move_to_head( &(imesa->TexObjList[heap]), t );
690
691 /* Update the global LRU
692 */
693 for (i = start ; i <= end ; i++) {
694
695 list[i].in_use = 1;
696 list[i].age = imesa->texAge[heap];
697
698 /* remove_from_list(i)
699 */
700 list[(unsigned)list[i].next].prev = list[i].prev;
701 list[(unsigned)list[i].prev].next = list[i].next;
702
703 /* insert_at_head(list, i)
704 */
705 list[i].prev = SAVAGE_NR_TEX_REGIONS;
706 list[i].next = list[SAVAGE_NR_TEX_REGIONS].next;
707 list[(unsigned)list[SAVAGE_NR_TEX_REGIONS].next].prev = i;
708 list[SAVAGE_NR_TEX_REGIONS].next = i;
709 }
710 }
711
712
713 /* Called for every shared texture region which has increased in age
714 * since we last held the lock.
715 *
716 * Figures out which of our textures have been ejected by other clients,
717 * and pushes a placeholder texture onto the LRU list to represent
718 * the other client's textures.
719 */
720 void savageTexturesGone( savageContextPtr imesa,
721 GLuint heap,
722 GLuint offset,
723 GLuint size,
724 GLuint in_use )
725 {
726 savageTextureObjectPtr t, tmp;
727
728 foreach_s ( t, tmp, &imesa->TexObjList[heap] ) {
729
730 if (t->MemBlock->ofs >= offset + size ||
731 t->MemBlock->ofs + t->MemBlock->size <= offset)
732 continue;
733
734 /* It overlaps - kick it off. Need to hold onto the currently bound
735 * objects, however.
736 */
737 if (t->bound)
738 savageSwapOutTexObj( imesa, t );
739 else
740 savageDestroyTexObj( imesa, t );
741 }
742
743
744 if (in_use) {
745 t = (savageTextureObjectPtr) calloc(1,sizeof(*t));
746 if (!t) return;
747
748 t->heap = heap;
749 t->MemBlock = mmAllocMem( imesa->texHeap[heap], size, 0, offset);
750 if(!t->MemBlock)
751 {
752 free(t);
753 return;
754 }
755 insert_at_head( &imesa->TexObjList[heap], t );
756 }
757 }
758
759
760
761
762
763 /* This is called with the lock held. May have to eject our own and/or
764 * other client's texture objects to make room for the upload.
765 */
766 int savageUploadTexImages( savageContextPtr imesa, savageTextureObjectPtr t )
767 {
768 int heap;
769 int i;
770 int ofs;
771
772 heap = t->heap = SAVAGE_CARD_HEAP;
773
774 /* Do we need to eject LRU texture objects?
775 */
776 if (!t->MemBlock) {
777 while (1)
778 {
779 t->MemBlock = mmAllocMem( imesa->texHeap[heap], t->totalSize, 12, 0 );
780 if (t->MemBlock)
781 break;
782 else
783 {
784 heap = t->heap = SAVAGE_AGP_HEAP;
785 t->MemBlock = mmAllocMem( imesa->texHeap[heap], t->totalSize, 12, 0 );
786
787 if (t->MemBlock)
788 break;
789 }
790
791 if (imesa->TexObjList[heap].prev->bound) {
792 fprintf(stderr, "Hit bound texture in upload\n");
793 savagePrintLocalLRU( imesa,heap );
794 return -1;
795 }
796
797 if (imesa->TexObjList[heap].prev == &(imesa->TexObjList[heap])) {
798 fprintf(stderr, "Failed to upload texture, sz %d\n", t->totalSize);
799 mmDumpMemInfo( imesa->texHeap[heap] );
800 return -1;
801 }
802
803 savageDestroyTexObj( imesa, imesa->TexObjList[heap].prev );
804 }
805
806 ofs = t->MemBlock->ofs;
807 t->texParams.hwPhysAddress = imesa->savageScreen->textureOffset[heap] + ofs;
808 t->BufAddr = (char *)((GLuint) imesa->savageScreen->texVirtual[heap] + ofs);
809 imesa->dirty |= SAVAGE_UPLOAD_CTX;
810 }
811
812 /* Let the world know we've used this memory recently.
813 */
814 savageUpdateTexLRU( imesa, t );
815
816 if (t->dirty_images) {
817 if (SAVAGE_DEBUG & DEBUG_VERBOSE_LRU)
818 fprintf(stderr, "*");
819
820 for (i = t->min_level ; i <= t->max_level ; i++)
821 if (t->dirty_images & (1<<i))
822 savageUploadTexLevel( t, i );
823 }
824
825
826 t->dirty_images = 0;
827 return 0;
828 }
829
830 static void savageTexSetUnit( savageTextureObjectPtr t, GLuint unit )
831 {
832 if (t->current_unit == unit) return;
833
834 t->current_unit = unit;
835 }
836
837
838
839
840 static void savageUpdateTex0State_s4( GLcontext *ctx )
841 {
842 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
843 struct gl_texture_object *tObj;
844 savageTextureObjectPtr t;
845 GLuint format;
846
847 /* disable */
848 if (ctx->Texture.Unit[0]._ReallyEnabled == 0) {
849 imesa->regs.s4.texDescr.ni.tex0En = GL_FALSE;
850 imesa->regs.s4.texBlendCtrl[0].ui = TBC_NoTexMap;
851 imesa->regs.s4.texCtrl[0].ui = 0x20f040;
852 imesa->regs.s4.texAddr[0].ui = 0;
853 return;
854 }
855
856 tObj = ctx->Texture.Unit[0]._Current;
857 if (ctx->Texture.Unit[0]._ReallyEnabled != TEXTURE_2D_BIT ||
858 tObj->Image[0][tObj->BaseLevel]->Border > 0) {
859 /* 1D or 3D texturing enabled, or texture border - fallback */
860 FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
861 return;
862 }
863
864 /* Do 2D texture setup */
865
866 t = tObj->DriverData;
867 if (!t) {
868 t = savageAllocTexObj( tObj );
869 if (!t)
870 return;
871 }
872
873 if (t->current_unit != 0)
874 savageTexSetUnit( t, 0 );
875
876 imesa->CurrentTexObj[0] = t;
877 t->bound |= 1;
878
879 if (t->dirty_images) {
880 savageSetTexImages(imesa, tObj);
881 savageUploadTexImages(imesa, imesa->CurrentTexObj[0]);
882 }
883
884 if (t->MemBlock)
885 savageUpdateTexLRU( imesa, t );
886
887 format = tObj->Image[0][tObj->BaseLevel]->Format;
888
889 switch (ctx->Texture.Unit[0].EnvMode) {
890 case GL_REPLACE:
891 imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
892 switch(format)
893 {
894 case GL_LUMINANCE:
895 case GL_RGB:
896 imesa->regs.s4.texBlendCtrl[0].ui = TBC_Decal;
897 break;
898
899 case GL_LUMINANCE_ALPHA:
900 case GL_RGBA:
901 case GL_INTENSITY:
902 imesa->regs.s4.texBlendCtrl[0].ui = TBC_Copy;
903 break;
904
905 case GL_ALPHA:
906 imesa->regs.s4.texBlendCtrl[0].ui = TBC_CopyAlpha;
907 break;
908 }
909 __HWEnvCombineSingleUnitScale(imesa, 0, 0,
910 &imesa->regs.s4.texBlendCtrl[0]);
911 break;
912
913 case GL_DECAL:
914 imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
915 switch (format)
916 {
917 case GL_RGB:
918 case GL_LUMINANCE:
919 imesa->regs.s4.texBlendCtrl[0].ui = TBC_Decal;
920 break;
921
922 case GL_RGBA:
923 case GL_INTENSITY:
924 case GL_LUMINANCE_ALPHA:
925 imesa->regs.s4.texBlendCtrl[0].ui = TBC_DecalAlpha;
926 break;
927
928 /*
929 GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY
930 are undefined with GL_DECAL
931 */
932
933 case GL_ALPHA:
934 imesa->regs.s4.texBlendCtrl[0].ui = TBC_CopyAlpha;
935 break;
936 }
937 __HWEnvCombineSingleUnitScale(imesa, 0, 0,
938 &imesa->regs.s4.texBlendCtrl[0]);
939 break;
940
941 case GL_MODULATE:
942 imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
943 imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha;
944 __HWEnvCombineSingleUnitScale(imesa, 0, 0,
945 &imesa->regs.s4.texBlendCtrl[0]);
946 break;
947
948 case GL_BLEND:
949
950 switch (format)
951 {
952 case GL_ALPHA:
953 imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha;
954 imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
955 break;
956
957 case GL_LUMINANCE:
958 case GL_RGB:
959 imesa->regs.s4.texBlendCtrl[0].ui = TBC_Blend0;
960 imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE;
961 imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
962 imesa->regs.s4.texDescr.ni.tex1Width =
963 imesa->regs.s4.texDescr.ni.tex0Width;
964 imesa->regs.s4.texDescr.ni.tex1Height =
965 imesa->regs.s4.texDescr.ni.tex0Height;
966 imesa->regs.s4.texDescr.ni.tex1Fmt =
967 imesa->regs.s4.texDescr.ni.tex0Fmt;
968
969 imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui;
970 imesa->regs.s4.texBlendCtrl[1].ui = TBC_Blend1;
971
972 imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE;
973 imesa->bTexEn1 = GL_TRUE;
974 break;
975
976 case GL_LUMINANCE_ALPHA:
977 case GL_RGBA:
978 imesa->regs.s4.texBlendCtrl[0].ui = TBC_BlendAlpha0;
979 imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE;
980 imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
981 imesa->regs.s4.texDescr.ni.tex1Width =
982 imesa->regs.s4.texDescr.ni.tex0Width;
983 imesa->regs.s4.texDescr.ni.tex1Height =
984 imesa->regs.s4.texDescr.ni.tex0Height;
985 imesa->regs.s4.texDescr.ni.tex1Fmt =
986 imesa->regs.s4.texDescr.ni.tex0Fmt;
987
988 imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui;
989 imesa->regs.s4.texBlendCtrl[1].ui = TBC_BlendAlpha1;
990
991 imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE;
992 imesa->bTexEn1 = GL_TRUE;
993 break;
994
995 case GL_INTENSITY:
996 imesa->regs.s4.texBlendCtrl[0].ui = TBC_BlendInt0;
997 imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE;
998 imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
999 imesa->regs.s4.texDescr.ni.tex1Width =
1000 imesa->regs.s4.texDescr.ni.tex0Width;
1001 imesa->regs.s4.texDescr.ni.tex1Height =
1002 imesa->regs.s4.texDescr.ni.tex0Height;
1003 imesa->regs.s4.texDescr.ni.tex1Fmt =
1004 imesa->regs.s4.texDescr.ni.tex0Fmt;
1005
1006 imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui;
1007 imesa->regs.s4.texBlendCtrl[1].ui = TBC_BlendInt1;
1008
1009 imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE;
1010 imesa->regs.s4.texCtrl[0].ni.alphaArg1Invert = GL_TRUE;
1011 imesa->bTexEn1 = GL_TRUE;
1012 break;
1013 }
1014 __HWEnvCombineSingleUnitScale(imesa, 0, 0,
1015 &imesa->regs.s4.texBlendCtrl[0]);
1016 break;
1017
1018 /*
1019 GL_ADD
1020 */
1021 case GL_ADD:
1022 printf("Add\n");
1023 imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
1024 imesa->regs.s4.texBlendCtrl[0].ui = TBC_AddAlpha;
1025 __HWEnvCombineSingleUnitScale(imesa, 0, 0,
1026 &imesa->regs.s4.texBlendCtrl[0]);
1027 break;
1028
1029 #if GL_ARB_texture_env_combine
1030 case GL_COMBINE_ARB:
1031 __HWParseTexEnvCombine(imesa, 0, &imesa->regs.s4.texCtrl[0],
1032 &imesa->regs.s4.texBlendCtrl[0]);
1033 break;
1034 #endif
1035
1036 default:
1037 fprintf(stderr, "unknown tex env mode");
1038 exit(1);
1039 break;
1040 }
1041
1042 imesa->regs.s4.texCtrl[0].ni.uMode = !(t->texParams.sWrapMode & 0x01);
1043 imesa->regs.s4.texCtrl[0].ni.vMode = !(t->texParams.tWrapMode & 0x01);
1044
1045 switch (t->texParams.minFilter)
1046 {
1047 case GL_NEAREST:
1048 imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Point;
1049 imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_FALSE;
1050 break;
1051
1052 case GL_LINEAR:
1053 imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Bilin;
1054 imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_FALSE;
1055 break;
1056
1057 case GL_NEAREST_MIPMAP_NEAREST:
1058 imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Point;
1059 imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_TRUE;
1060 break;
1061
1062 case GL_LINEAR_MIPMAP_NEAREST:
1063 imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Bilin;
1064 imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_TRUE;
1065 break;
1066
1067 case GL_NEAREST_MIPMAP_LINEAR:
1068 case GL_LINEAR_MIPMAP_LINEAR:
1069 imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Trilin;
1070 imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_TRUE;
1071 break;
1072 }
1073
1074 if((ctx->Texture.Unit[0].LodBias !=0.0F) &&
1075 (imesa->regs.s4.texCtrl[0].ni.dBias != 0))
1076 {
1077 union {
1078 GLfloat f;
1079 GLint i;
1080 } bias;
1081 GLuint ul;
1082
1083 bias.f = ctx->Texture.Unit[0].LodBias;
1084
1085 /* if the value is >= 15.9375 determine whether >= 16
1086 or <0
1087 */
1088 if(((bias.i) & 0x7FFFFFFF) >= 0x417F0000)
1089 {
1090 if((bias.i) & 0x80000000)
1091 {
1092 ul=0x101;
1093 }
1094 else
1095 {
1096 ul=0xff;
1097 }
1098 }
1099 else
1100 {
1101 ul=(GLuint)(bias.f*16.0);
1102 }
1103
1104 ul &= 0x1FF;
1105 imesa->regs.s4.texCtrl[0].ni.dBias = ul;
1106 }
1107
1108 imesa->regs.s4.texDescr.ni.tex0En = GL_TRUE;
1109 imesa->regs.s4.texDescr.ni.tex0Width = t->image[0].image->WidthLog2;
1110 imesa->regs.s4.texDescr.ni.tex0Height = t->image[0].image->HeightLog2;
1111 imesa->regs.s4.texDescr.ni.tex0Fmt = t->image[0].internalFormat;
1112 imesa->regs.s4.texCtrl[0].ni.dMax = t->max_level;
1113
1114 if (imesa->regs.s4.texDescr.ni.tex1En)
1115 imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
1116
1117 imesa->regs.s4.texAddr[0].ui = (GLuint) t->texParams.hwPhysAddress | 0x2;
1118 if(t->heap == SAVAGE_AGP_HEAP)
1119 imesa->regs.s4.texAddr[0].ui |= 0x1;
1120
1121 return;
1122 }
1123 static void savageUpdateTex1State_s4( GLcontext *ctx )
1124 {
1125 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
1126 struct gl_texture_object *tObj;
1127 savageTextureObjectPtr t;
1128 GLuint format;
1129
1130 /* disable */
1131 if(imesa->bTexEn1)
1132 {
1133 imesa->bTexEn1 = GL_FALSE;
1134 return;
1135 }
1136
1137 if (ctx->Texture.Unit[1]._ReallyEnabled == 0) {
1138 imesa->regs.s4.texDescr.ni.tex1En = GL_FALSE;
1139 imesa->regs.s4.texBlendCtrl[1].ui = TBC_NoTexMap1;
1140 imesa->regs.s4.texCtrl[1].ui = 0x20f040;
1141 imesa->regs.s4.texAddr[1].ui = 0;
1142 imesa->regs.s4.texDescr.ni.texBLoopEn = GL_FALSE;
1143 return;
1144 }
1145
1146 tObj = ctx->Texture.Unit[1]._Current;
1147
1148 if (ctx->Texture.Unit[1]._ReallyEnabled != TEXTURE_2D_BIT ||
1149 tObj->Image[0][tObj->BaseLevel]->Border > 0) {
1150 /* 1D or 3D texturing enabled, or texture border - fallback */
1151 FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
1152 return;
1153 }
1154
1155 /* Do 2D texture setup */
1156
1157 t = tObj->DriverData;
1158 if (!t) {
1159 t = savageAllocTexObj( tObj );
1160 if (!t)
1161 return;
1162 }
1163
1164 if (t->current_unit != 1)
1165 savageTexSetUnit( t, 1 );
1166
1167 imesa->CurrentTexObj[1] = t;
1168
1169 t->bound |= 2;
1170
1171 if (t->dirty_images) {
1172 savageSetTexImages(imesa, tObj);
1173 savageUploadTexImages(imesa, imesa->CurrentTexObj[1]);
1174 }
1175
1176 if (t->MemBlock)
1177 savageUpdateTexLRU( imesa, t );
1178
1179 format = tObj->Image[0][tObj->BaseLevel]->Format;
1180
1181 switch (ctx->Texture.Unit[1].EnvMode) {
1182 case GL_REPLACE:
1183 imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE;
1184 switch (format)
1185 {
1186 case GL_LUMINANCE:
1187 case GL_RGB:
1188 imesa->regs.s4.texBlendCtrl[1].ui = TBC_Decal;
1189 break;
1190
1191 case GL_LUMINANCE_ALPHA:
1192 case GL_INTENSITY:
1193 case GL_RGBA:
1194 imesa->regs.s4.texBlendCtrl[1].ui = TBC_Copy;
1195 break;
1196
1197 case GL_ALPHA:
1198 imesa->regs.s4.texBlendCtrl[1].ui = TBC_CopyAlpha1;
1199 break;
1200 }
1201 __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
1202 break;
1203 case GL_MODULATE:
1204 imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE;
1205 imesa->regs.s4.texBlendCtrl[1].ui = TBC_ModulAlpha1;
1206 __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
1207 break;
1208
1209 /*#if GL_EXT_texture_env_add*/
1210 case GL_ADD:
1211 imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE;
1212 imesa->regs.s4.texBlendCtrl[1].ui = TBC_AddAlpha1;
1213 __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
1214 break;
1215 /*#endif*/
1216
1217 #if GL_ARB_texture_env_combine
1218 case GL_COMBINE_ARB:
1219 __HWParseTexEnvCombine(imesa, 1, &texCtrl, &imesa->regs.s4.texBlendCtrl);
1220 break;
1221 #endif
1222
1223 case GL_DECAL:
1224 imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE;
1225
1226 switch (format)
1227 {
1228 case GL_LUMINANCE:
1229 case GL_RGB:
1230 imesa->regs.s4.texBlendCtrl[1].ui = TBC_Decal1;
1231 break;
1232 case GL_LUMINANCE_ALPHA:
1233 case GL_INTENSITY:
1234 case GL_RGBA:
1235 imesa->regs.s4.texBlendCtrl[1].ui = TBC_DecalAlpha1;
1236 break;
1237
1238 /*
1239 // GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY
1240 // are undefined with GL_DECAL
1241 */
1242 case GL_ALPHA:
1243 imesa->regs.s4.texBlendCtrl[1].ui = TBC_CopyAlpha1;
1244 break;
1245 }
1246 __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
1247 break;
1248
1249 case GL_BLEND:
1250 if (format == GL_LUMINANCE)
1251 {
1252 /*
1253 // This is a hack for GLQuake, invert.
1254 */
1255 imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_TRUE;
1256 imesa->regs.s4.texBlendCtrl[1].ui = 0;
1257 }
1258 __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
1259 break;
1260
1261 default:
1262 fprintf(stderr, "unkown tex 1 env mode\n");
1263 exit(1);
1264 break;
1265 }
1266
1267 imesa->regs.s4.texCtrl[1].ni.uMode = !(t->texParams.sWrapMode & 0x01);
1268 imesa->regs.s4.texCtrl[1].ni.vMode = !(t->texParams.tWrapMode & 0x01);
1269
1270 switch (t->texParams.minFilter)
1271 {
1272 case GL_NEAREST:
1273 imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Point;
1274 imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_FALSE;
1275 break;
1276
1277 case GL_LINEAR:
1278 imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Bilin;
1279 imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_FALSE;
1280 break;
1281
1282 case GL_NEAREST_MIPMAP_NEAREST:
1283 imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Point;
1284 imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_TRUE;
1285 break;
1286
1287 case GL_LINEAR_MIPMAP_NEAREST:
1288 imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Bilin;
1289 imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_TRUE;
1290 break;
1291
1292 case GL_NEAREST_MIPMAP_LINEAR:
1293 case GL_LINEAR_MIPMAP_LINEAR:
1294 imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Trilin;
1295 imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_TRUE;
1296 break;
1297 }
1298
1299 if((ctx->Texture.Unit[1].LodBias !=0.0F)&&
1300 (imesa->regs.s4.texCtrl[1].ni.dBias != 0))
1301 {
1302 union {
1303 GLfloat f;
1304 GLint i;
1305 } bias;
1306 GLuint ul;
1307
1308 bias.f = ctx->Texture.Unit[1].LodBias;
1309
1310 /* if the value is >= 15.9375 determine whether >= 16
1311 or <0
1312 */
1313 if(((bias.i) & 0x7FFFFFFF) >= 0x417F0000)
1314 {
1315 if((bias.i) & 0x80000000)
1316 {
1317 ul=0x101;
1318 }
1319 else
1320 {
1321 ul=0xff;
1322 }
1323 }
1324 else
1325 {
1326 ul=(GLuint)(bias.f*16.0);
1327 }
1328
1329 ul &= 0x1FF;
1330 imesa->regs.s4.texCtrl[1].ni.dBias = ul;
1331 }
1332
1333 imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE;
1334 imesa->regs.s4.texDescr.ni.tex1Width = t->image[0].image->WidthLog2;
1335 imesa->regs.s4.texDescr.ni.tex1Height = t->image[0].image->HeightLog2;
1336 imesa->regs.s4.texDescr.ni.tex1Fmt = t->image[0].internalFormat;
1337 imesa->regs.s4.texCtrl[1].ni.dMax = t->max_level;
1338 imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
1339
1340 imesa->regs.s4.texAddr[1].ui = (GLuint) t->texParams.hwPhysAddress| 2;
1341 if(t->heap == SAVAGE_AGP_HEAP)
1342 imesa->regs.s4.texAddr[1].ui |= 0x1;
1343 }
1344 static void savageUpdateTexState_s3d( GLcontext *ctx )
1345 {
1346 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
1347 struct gl_texture_object *tObj;
1348 savageTextureObjectPtr t;
1349 GLuint format;
1350
1351 /* disable */
1352 if (ctx->Texture.Unit[0]._ReallyEnabled == 0) {
1353 imesa->regs.s3d.texCtrl.ui = 0;
1354 imesa->regs.s3d.texCtrl.ni.texEn = GL_FALSE;
1355 imesa->regs.s3d.texCtrl.ni.dBias = 0x08;
1356 imesa->regs.s3d.texCtrl.ni.texXprEn = GL_TRUE;
1357 imesa->regs.s3d.texAddr.ui = 0;
1358 return;
1359 }
1360
1361 tObj = ctx->Texture.Unit[0]._Current;
1362 if (ctx->Texture.Unit[0]._ReallyEnabled != TEXTURE_2D_BIT ||
1363 tObj->Image[0][tObj->BaseLevel]->Border > 0) {
1364 /* 1D or 3D texturing enabled, or texture border - fallback */
1365 FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
1366 return;
1367 }
1368
1369 /* Do 2D texture setup */
1370 t = tObj->DriverData;
1371 if (!t) {
1372 t = savageAllocTexObj( tObj );
1373 if (!t)
1374 return;
1375 }
1376
1377 if (t->current_unit != 0)
1378 savageTexSetUnit( t, 0 );
1379
1380 imesa->CurrentTexObj[0] = t;
1381 t->bound |= 1;
1382
1383 if (t->dirty_images) {
1384 savageSetTexImages(imesa, tObj);
1385 savageUploadTexImages(imesa, imesa->CurrentTexObj[0]);
1386 }
1387
1388 if (t->MemBlock)
1389 savageUpdateTexLRU( imesa, t );
1390
1391 format = tObj->Image[0][tObj->BaseLevel]->Format;
1392
1393 /* FIXME: copied from utah-glx, probably needs some tuning */
1394 switch (ctx->Texture.Unit[0].EnvMode) {
1395 case GL_DECAL:
1396 imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_DECAL_S3D;
1397 break;
1398 case GL_REPLACE:
1399 imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_COPY_S3D;
1400 break;
1401 case GL_BLEND: /* FIXIT */
1402 case GL_MODULATE:
1403 imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_MODULATEALPHA_S3D;
1404 break;
1405 default:
1406 fprintf(stderr, "unkown tex env mode\n");
1407 /*exit(1);*/
1408 break;
1409 }
1410
1411 imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
1412 imesa->regs.s3d.drawCtrl.ni.flushPdZbufWrites = GL_TRUE;
1413
1414 /* FIXME: this is how the utah-driver works. I doubt it's the ultimate
1415 truth. */
1416 imesa->regs.s3d.texCtrl.ni.uWrapEn = 0;
1417 imesa->regs.s3d.texCtrl.ni.vWrapEn = 0;
1418 if (t->texParams.sWrapMode == GL_CLAMP)
1419 imesa->regs.s3d.texCtrl.ni.wrapMode = TAM_Clamp;
1420 else
1421 imesa->regs.s3d.texCtrl.ni.wrapMode = TAM_Wrap;
1422
1423 switch (t->texParams.minFilter) {
1424 case GL_NEAREST:
1425 imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Point;
1426 imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_TRUE;
1427 break;
1428
1429 case GL_LINEAR:
1430 imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Bilin;
1431 imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_TRUE;
1432 break;
1433
1434 case GL_NEAREST_MIPMAP_NEAREST:
1435 imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Point;
1436 imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE;
1437 break;
1438
1439 case GL_LINEAR_MIPMAP_NEAREST:
1440 imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Bilin;
1441 imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE;
1442 break;
1443
1444 case GL_NEAREST_MIPMAP_LINEAR:
1445 case GL_LINEAR_MIPMAP_LINEAR:
1446 imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Trilin;
1447 imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE;
1448 break;
1449 }
1450
1451 /* There is no way to specify a maximum mipmap level. We may have to
1452 disable mipmapping completely. */
1453 /*
1454 if (t->max_level < t->image[0].image->WidthLog2 ||
1455 t->max_level < t->image[0].image->HeightLog2) {
1456 texCtrl.ni.mipmapEnable = GL_TRUE;
1457 if (texCtrl.ni.filterMode == TFM_Trilin)
1458 texCtrl.ni.filterMode = TFM_Bilin;
1459 texCtrl.ni.filterMode = TFM_Point;
1460 }
1461 */
1462
1463 /* LOD bias makes corruption of small mipmap levels worse on Savage IX
1464 * but doesn't show the desired effect with the lodbias mesa demo. */
1465 imesa->regs.s3d.texCtrl.ni.dBias = 0;
1466
1467 imesa->regs.s3d.texCtrl.ni.texEn = GL_TRUE;
1468 imesa->regs.s3d.texDescr.ni.texWidth = t->image[0].image->WidthLog2;
1469 imesa->regs.s3d.texDescr.ni.texHeight = t->image[0].image->HeightLog2;
1470 assert (t->image[0].internalFormat <= 7);
1471 imesa->regs.s3d.texDescr.ni.texFmt = t->image[0].internalFormat;
1472
1473 imesa->regs.s3d.texAddr.ni.addr = (GLuint) t->texParams.hwPhysAddress >> 3;
1474 if(t->heap == SAVAGE_AGP_HEAP) {
1475 imesa->regs.s3d.texAddr.ni.inSysTex = 1;
1476 imesa->regs.s3d.texAddr.ni.inAGPTex = 1;
1477 } else {
1478 imesa->regs.s3d.texAddr.ni.inSysTex = 0;
1479 imesa->regs.s3d.texAddr.ni.inAGPTex = 1;
1480 }
1481 }
1482
1483
1484
1485 static void savageUpdateTextureState_s4( GLcontext *ctx )
1486 {
1487 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
1488 if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound &= ~1;
1489 if (imesa->CurrentTexObj[1]) imesa->CurrentTexObj[1]->bound &= ~2;
1490 imesa->CurrentTexObj[0] = 0;
1491 imesa->CurrentTexObj[1] = 0;
1492 FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_FALSE);
1493 savageUpdateTex0State_s4( ctx );
1494 savageUpdateTex1State_s4( ctx );
1495 imesa->dirty |= (SAVAGE_UPLOAD_CTX |
1496 SAVAGE_UPLOAD_TEX0 |
1497 SAVAGE_UPLOAD_TEX1);
1498 }
1499 static void savageUpdateTextureState_s3d( GLcontext *ctx )
1500 {
1501 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
1502 if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound &= ~1;
1503 imesa->CurrentTexObj[0] = 0;
1504 if (ctx->Texture.Unit[1]._ReallyEnabled) {
1505 FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
1506 } else {
1507 FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_FALSE);
1508 savageUpdateTexState_s3d( ctx );
1509 imesa->dirty |= (SAVAGE_UPLOAD_CTX |
1510 SAVAGE_UPLOAD_TEX0);
1511 }
1512 }
1513 void savageUpdateTextureState( GLcontext *ctx)
1514 {
1515 savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
1516 if (imesa->savageScreen->chipset >= S3_SAVAGE4)
1517 savageUpdateTextureState_s4 (ctx);
1518 else
1519 savageUpdateTextureState_s3d (ctx);
1520 }
1521
1522
1523
1524 /*****************************************
1525 * DRIVER functions
1526 *****************************************/
1527
1528 static void savageTexEnv( GLcontext *ctx, GLenum target,
1529 GLenum pname, const GLfloat *param )
1530 {
1531 savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
1532
1533 if (pname == GL_TEXTURE_ENV_MODE) {
1534
1535 imesa->new_state |= SAVAGE_NEW_TEXTURE;
1536
1537 } else if (pname == GL_TEXTURE_ENV_COLOR) {
1538
1539 struct gl_texture_unit *texUnit =
1540 &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1541 const GLfloat *fc = texUnit->EnvColor;
1542 GLuint r, g, b, a, col;
1543 CLAMPED_FLOAT_TO_UBYTE(r, fc[0]);
1544 CLAMPED_FLOAT_TO_UBYTE(g, fc[1]);
1545 CLAMPED_FLOAT_TO_UBYTE(b, fc[2]);
1546 CLAMPED_FLOAT_TO_UBYTE(a, fc[3]);
1547
1548 col = ((a << 24) |
1549 (r << 16) |
1550 (g << 8) |
1551 (b << 0));
1552
1553
1554 }
1555 }
1556
1557 static void savageTexImage2D( GLcontext *ctx, GLenum target, GLint level,
1558 GLint internalFormat,
1559 GLint width, GLint height, GLint border,
1560 GLenum format, GLenum type, const GLvoid *pixels,
1561 const struct gl_pixelstore_attrib *packing,
1562 struct gl_texture_object *texObj,
1563 struct gl_texture_image *texImage )
1564 {
1565 savageTextureObjectPtr t = (savageTextureObjectPtr) texObj->DriverData;
1566 if (t) {
1567 savageSwapOutTexObj( SAVAGE_CONTEXT(ctx), t );
1568 } else {
1569 t = savageAllocTexObj(texObj);
1570 if (!t) {
1571 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1572 return;
1573 }
1574 }
1575 _mesa_store_teximage2d( ctx, target, level, internalFormat,
1576 width, height, border, format, type,
1577 pixels, packing, texObj, texImage );
1578 t->dirty_images |= (1 << level);
1579 SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
1580 }
1581
1582 static void savageTexSubImage2D( GLcontext *ctx,
1583 GLenum target,
1584 GLint level,
1585 GLint xoffset, GLint yoffset,
1586 GLsizei width, GLsizei height,
1587 GLenum format, GLenum type,
1588 const GLvoid *pixels,
1589 const struct gl_pixelstore_attrib *packing,
1590 struct gl_texture_object *texObj,
1591 struct gl_texture_image *texImage )
1592 {
1593 savageTextureObjectPtr t = (savageTextureObjectPtr) texObj->DriverData;
1594 assert( t ); /* this _should_ be true */
1595 if (t) {
1596 savageSwapOutTexObj( SAVAGE_CONTEXT(ctx), t );
1597 } else {
1598 t = savageAllocTexObj(texObj);
1599 if (!t) {
1600 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
1601 return;
1602 }
1603 }
1604 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
1605 height, format, type, pixels, packing, texObj,
1606 texImage);
1607 t->dirty_images |= (1 << level);
1608 SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
1609 }
1610
1611 static void savageTexParameter( GLcontext *ctx, GLenum target,
1612 struct gl_texture_object *tObj,
1613 GLenum pname, const GLfloat *params )
1614 {
1615 savageTextureObjectPtr t = (savageTextureObjectPtr) tObj->DriverData;
1616 savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
1617
1618 if (!t || target != GL_TEXTURE_2D)
1619 return;
1620
1621 switch (pname) {
1622 case GL_TEXTURE_MIN_FILTER:
1623 case GL_TEXTURE_MAG_FILTER:
1624 savageSetTexFilter(t,tObj->MinFilter,tObj->MagFilter);
1625 break;
1626
1627 case GL_TEXTURE_WRAP_S:
1628 case GL_TEXTURE_WRAP_T:
1629 savageSetTexWrapping(t,tObj->WrapS,tObj->WrapT);
1630 break;
1631
1632 case GL_TEXTURE_BORDER_COLOR:
1633 savageSetTexBorderColor(t,tObj->_BorderChan);
1634 break;
1635
1636 default:
1637 return;
1638 }
1639
1640 imesa->new_state |= SAVAGE_NEW_TEXTURE;
1641 }
1642
1643 static void savageBindTexture( GLcontext *ctx, GLenum target,
1644 struct gl_texture_object *tObj )
1645 {
1646 savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
1647
1648 assert( (target != GL_TEXTURE_2D) || (tObj->DriverData != NULL) );
1649
1650 imesa->new_state |= SAVAGE_NEW_TEXTURE;
1651 }
1652
1653 static void savageDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
1654 {
1655 savageTextureObjectPtr t = (savageTextureObjectPtr)tObj->DriverData;
1656 savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
1657
1658 if (t) {
1659
1660 if (t->bound) {
1661 imesa->CurrentTexObj[t->bound-1] = 0;
1662 imesa->new_state |= SAVAGE_NEW_TEXTURE;
1663 }
1664
1665 savageDestroyTexObj(imesa,t);
1666 tObj->DriverData=0;
1667 }
1668 /* Free mipmap images and the texture object itself */
1669 _mesa_delete_texture_object(ctx, tObj);
1670 }
1671
1672
1673 static GLboolean savageIsTextureResident( GLcontext *ctx,
1674 struct gl_texture_object *t )
1675 {
1676 savageTextureObjectPtr mt;
1677
1678 /* LOCK_HARDWARE; */
1679 mt = (savageTextureObjectPtr)t->DriverData;
1680 /* UNLOCK_HARDWARE; */
1681
1682 return mt && mt->MemBlock;
1683 }
1684
1685
1686 static struct gl_texture_object *
1687 savageNewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
1688 {
1689 struct gl_texture_object *obj;
1690 obj = _mesa_new_texture_object(ctx, name, target);
1691 savageAllocTexObj( obj );
1692
1693 return obj;
1694 }
1695
1696 void savageDDInitTextureFuncs( struct dd_function_table *functions )
1697 {
1698 functions->TexEnv = savageTexEnv;
1699 functions->ChooseTextureFormat = savageChooseTextureFormat;
1700 functions->TexImage2D = savageTexImage2D;
1701 functions->TexSubImage2D = savageTexSubImage2D;
1702 functions->BindTexture = savageBindTexture;
1703 functions->NewTextureObject = savageNewTextureObject;
1704 functions->DeleteTexture = savageDeleteTexture;
1705 functions->IsTextureResident = savageIsTextureResident;
1706 functions->TexParameter = savageTexParameter;
1707 }