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