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