Savage3D-based chips seem so use a constant tile stride of 2048 for
[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 }