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