1 /**************************************************************************
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
31 #include "simple_list.h"
33 #include "texformat.h"
38 #include "intel_screen.h"
39 #include "intel_ioctl.h"
40 #include "intel_tex.h"
42 #include "i830_context.h"
45 static const GLint initial_offsets
[6][2] = { {0,0},
52 static const GLint step_offsets
[6][2] = { {0,2},
59 #define I830_TEX_UNIT_ENABLED(unit) (1<<unit)
61 static GLboolean
i830SetTexImages( i830ContextPtr i830
,
62 struct gl_texture_object
*tObj
)
64 GLuint total_height
, pitch
, i
, textureFormat
;
65 i830TextureObjectPtr t
= (i830TextureObjectPtr
) tObj
->DriverData
;
66 const struct gl_texture_image
*baseImage
= tObj
->Image
[0][tObj
->BaseLevel
];
67 GLint firstLevel
, lastLevel
, numLevels
;
69 switch( baseImage
->TexFormat
->MesaFormat
) {
71 t
->intel
.texelBytes
= 1;
72 textureFormat
= MAPSURF_8BIT
| MT_8BIT_L8
;
76 t
->intel
.texelBytes
= 1;
77 textureFormat
= MAPSURF_8BIT
| MT_8BIT_I8
;
81 t
->intel
.texelBytes
= 1;
82 textureFormat
= MAPSURF_8BIT
| MT_8BIT_I8
; /* Kludge -- check with conform, glean */
85 case MESA_FORMAT_AL88
:
86 t
->intel
.texelBytes
= 2;
87 textureFormat
= MAPSURF_16BIT
| MT_16BIT_AY88
;
90 case MESA_FORMAT_RGB565
:
91 t
->intel
.texelBytes
= 2;
92 textureFormat
= MAPSURF_16BIT
| MT_16BIT_RGB565
;
95 case MESA_FORMAT_ARGB1555
:
96 t
->intel
.texelBytes
= 2;
97 textureFormat
= MAPSURF_16BIT
| MT_16BIT_ARGB1555
;
100 case MESA_FORMAT_ARGB4444
:
101 t
->intel
.texelBytes
= 2;
102 textureFormat
= MAPSURF_16BIT
| MT_16BIT_ARGB4444
;
105 case MESA_FORMAT_ARGB8888
:
106 t
->intel
.texelBytes
= 4;
107 textureFormat
= MAPSURF_32BIT
| MT_32BIT_ARGB8888
;
110 case MESA_FORMAT_YCBCR_REV
:
111 t
->intel
.texelBytes
= 2;
112 textureFormat
= (MAPSURF_422
| MT_422_YCRCB_NORMAL
|
113 TM0S1_COLORSPACE_CONVERSION
);
116 case MESA_FORMAT_YCBCR
:
117 t
->intel
.texelBytes
= 2;
118 textureFormat
= (MAPSURF_422
| MT_422_YCRCB_SWAPY
| /* ??? */
119 TM0S1_COLORSPACE_CONVERSION
);
122 case MESA_FORMAT_RGB_FXT1
:
123 case MESA_FORMAT_RGBA_FXT1
:
124 t
->intel
.texelBytes
= 2;
125 textureFormat
= MAPSURF_COMPRESSED
| MT_COMPRESS_FXT1
;
128 case MESA_FORMAT_RGBA_DXT1
:
129 case MESA_FORMAT_RGB_DXT1
:
131 * DXTn pitches are Width/4 * blocksize in bytes
132 * for DXT1: blocksize=8 so Width/4*8 = Width * 2
133 * for DXT3/5: blocksize=16 so Width/4*16 = Width * 4
135 t
->intel
.texelBytes
= 2;
136 textureFormat
= (MAPSURF_COMPRESSED
| MT_COMPRESS_DXT1
);
138 case MESA_FORMAT_RGBA_DXT3
:
139 t
->intel
.texelBytes
= 4;
140 textureFormat
= (MAPSURF_COMPRESSED
| MT_COMPRESS_DXT2_3
);
142 case MESA_FORMAT_RGBA_DXT5
:
143 t
->intel
.texelBytes
= 4;
144 textureFormat
= (MAPSURF_COMPRESSED
| MT_COMPRESS_DXT4_5
);
148 fprintf(stderr
, "%s: bad image format\n", __FUNCTION__
);
152 /* Compute which mipmap levels we really want to send to the hardware.
153 * This depends on the base image size, GL_TEXTURE_MIN_LOD,
154 * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
155 * Yes, this looks overly complicated, but it's all needed.
157 driCalculateTextureFirstLastLevel( (driTextureObject
*) t
);
160 /* Figure out the amount of memory required to hold all the mipmap
161 * levels. Choose the smallest pitch to accomodate the largest
164 firstLevel
= t
->intel
.base
.firstLevel
;
165 lastLevel
= t
->intel
.base
.lastLevel
;
166 numLevels
= lastLevel
- firstLevel
+ 1;
169 /* All images must be loaded at this pitch. Count the number of
172 switch (tObj
->Target
) {
173 case GL_TEXTURE_CUBE_MAP
: {
174 const GLuint dim
= tObj
->Image
[0][firstLevel
]->Width
;
177 pitch
= dim
* t
->intel
.texelBytes
;
178 pitch
*= 2; /* double pitch for cube layouts */
179 pitch
= (pitch
+ 3) & ~3;
181 total_height
= dim
* 4;
183 for ( face
= 0 ; face
< 6 ; face
++) {
184 GLuint x
= initial_offsets
[face
][0] * dim
;
185 GLuint y
= initial_offsets
[face
][1] * dim
;
188 t
->intel
.base
.dirty_images
[face
] = ~0;
190 assert(tObj
->Image
[face
][firstLevel
]->Width
== dim
);
191 assert(tObj
->Image
[face
][firstLevel
]->Height
== dim
);
193 for (i
= 0; i
< numLevels
; i
++) {
194 t
->intel
.image
[face
][i
].image
= tObj
->Image
[face
][firstLevel
+ i
];
195 if (!t
->intel
.image
[face
][i
].image
) {
196 fprintf(stderr
, "no image %d %d\n", face
, i
);
197 break; /* can't happen */
200 t
->intel
.image
[face
][i
].offset
=
201 y
* pitch
+ x
* t
->intel
.texelBytes
;
202 t
->intel
.image
[face
][i
].internalFormat
= baseImage
->_BaseFormat
;
205 x
+= step_offsets
[face
][0] * d
;
206 y
+= step_offsets
[face
][1] * d
;
212 pitch
= tObj
->Image
[0][firstLevel
]->Width
* t
->intel
.texelBytes
;
213 pitch
= (pitch
+ 3) & ~3;
214 t
->intel
.base
.dirty_images
[0] = ~0;
216 for ( total_height
= i
= 0 ; i
< numLevels
; i
++ ) {
217 t
->intel
.image
[0][i
].image
= tObj
->Image
[0][firstLevel
+ i
];
218 if (!t
->intel
.image
[0][i
].image
)
221 t
->intel
.image
[0][i
].offset
= total_height
* pitch
;
222 t
->intel
.image
[0][i
].internalFormat
= baseImage
->_BaseFormat
;
223 if (t
->intel
.image
[0][i
].image
->IsCompressed
)
225 if (t
->intel
.image
[0][i
].image
->Height
> 4)
226 total_height
+= t
->intel
.image
[0][i
].image
->Height
/4;
231 total_height
+= MAX2(2, t
->intel
.image
[0][i
].image
->Height
);
236 t
->intel
.Pitch
= pitch
;
237 t
->intel
.base
.totalSize
= total_height
*pitch
;
238 t
->intel
.max_level
= i
-1;
239 t
->Setup
[I830_TEXREG_TM0S1
] =
240 (((tObj
->Image
[0][firstLevel
]->Height
- 1) << TM0S1_HEIGHT_SHIFT
) |
241 ((tObj
->Image
[0][firstLevel
]->Width
- 1) << TM0S1_WIDTH_SHIFT
) |
243 t
->Setup
[I830_TEXREG_TM0S2
] =
244 (((pitch
/ 4) - 1) << TM0S2_PITCH_SHIFT
) |
245 TM0S2_CUBE_FACE_ENA_MASK
;
246 t
->Setup
[I830_TEXREG_TM0S3
] &= ~TM0S3_MAX_MIP_MASK
;
247 t
->Setup
[I830_TEXREG_TM0S3
] &= ~TM0S3_MIN_MIP_MASK
;
248 t
->Setup
[I830_TEXREG_TM0S3
] |= ((numLevels
- 1)*4) << TM0S3_MIN_MIP_SHIFT
;
249 t
->intel
.dirty
= I830_UPLOAD_TEX_ALL
;
251 return intelUploadTexImages( &i830
->intel
, &t
->intel
, 0 );
255 static void i830_import_tex_unit( i830ContextPtr i830
,
256 i830TextureObjectPtr t
,
259 if(INTEL_DEBUG
&DEBUG_TEXTURE
)
260 fprintf(stderr
, "%s unit(%d)\n", __FUNCTION__
, unit
);
262 if (i830
->intel
.CurrentTexObj
[unit
])
263 i830
->intel
.CurrentTexObj
[unit
]->base
.bound
&= ~(1U << unit
);
265 i830
->intel
.CurrentTexObj
[unit
] = (intelTextureObjectPtr
)t
;
266 t
->intel
.base
.bound
|= (1 << unit
);
268 I830_STATECHANGE( i830
, I830_UPLOAD_TEX(unit
) );
270 i830
->state
.Tex
[unit
][I830_TEXREG_TM0LI
] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2
|
271 (LOAD_TEXTURE_MAP0
<< unit
) | 4);
272 i830
->state
.Tex
[unit
][I830_TEXREG_TM0S0
] = (TM0S0_USE_FENCE
|
273 t
->intel
.TextureOffset
);
275 i830
->state
.Tex
[unit
][I830_TEXREG_TM0S1
] = t
->Setup
[I830_TEXREG_TM0S1
];
276 i830
->state
.Tex
[unit
][I830_TEXREG_TM0S2
] = t
->Setup
[I830_TEXREG_TM0S2
];
278 i830
->state
.Tex
[unit
][I830_TEXREG_TM0S3
] &= TM0S3_LOD_BIAS_MASK
;
279 i830
->state
.Tex
[unit
][I830_TEXREG_TM0S3
] |= (t
->Setup
[I830_TEXREG_TM0S3
] &
280 ~TM0S3_LOD_BIAS_MASK
);
282 i830
->state
.Tex
[unit
][I830_TEXREG_TM0S4
] = t
->Setup
[I830_TEXREG_TM0S4
];
283 i830
->state
.Tex
[unit
][I830_TEXREG_MCS
] = (t
->Setup
[I830_TEXREG_MCS
] &
285 i830
->state
.Tex
[unit
][I830_TEXREG_CUBE
] = t
->Setup
[I830_TEXREG_CUBE
];
286 i830
->state
.Tex
[unit
][I830_TEXREG_MCS
] |= MAP_UNIT(unit
);
288 t
->intel
.dirty
&= ~I830_UPLOAD_TEX(unit
);
293 static GLboolean
enable_tex_common( GLcontext
*ctx
, GLuint unit
)
295 i830ContextPtr i830
= I830_CONTEXT(ctx
);
296 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
297 struct gl_texture_object
*tObj
= texUnit
->_Current
;
298 i830TextureObjectPtr t
= (i830TextureObjectPtr
)tObj
->DriverData
;
300 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
302 /* Fallback if there's a texture border */
303 if ( tObj
->Image
[0][tObj
->BaseLevel
]->Border
> 0 ) {
304 fprintf(stderr
, "Texture border\n");
308 /* Upload teximages (not pipelined)
310 if (t
->intel
.base
.dirty_images
[0]) {
311 if (!i830SetTexImages( i830
, tObj
)) {
316 /* Update state if this is a different texture object to last
319 if (i830
->intel
.CurrentTexObj
[unit
] != &t
->intel
||
320 (t
->intel
.dirty
& I830_UPLOAD_TEX(unit
))) {
321 i830_import_tex_unit( i830
, t
, unit
);
324 I830_ACTIVESTATE(i830
, I830_UPLOAD_TEX(unit
), GL_TRUE
);
329 static GLboolean
enable_tex_rect( GLcontext
*ctx
, GLuint unit
)
331 i830ContextPtr i830
= I830_CONTEXT(ctx
);
332 GLuint mcs
= i830
->state
.Tex
[unit
][I830_TEXREG_MCS
];
334 mcs
&= ~TEXCOORDS_ARE_NORMAL
;
335 mcs
|= TEXCOORDS_ARE_IN_TEXELUNITS
;
337 if ((mcs
!= i830
->state
.Tex
[unit
][I830_TEXREG_MCS
])
338 || (0 != i830
->state
.Tex
[unit
][I830_TEXREG_CUBE
])) {
339 I830_STATECHANGE(i830
, I830_UPLOAD_TEX(unit
));
340 i830
->state
.Tex
[unit
][I830_TEXREG_MCS
] = mcs
;
341 i830
->state
.Tex
[unit
][I830_TEXREG_CUBE
] = 0;
348 static GLboolean
enable_tex_2d( GLcontext
*ctx
, GLuint unit
)
350 i830ContextPtr i830
= I830_CONTEXT(ctx
);
351 GLuint mcs
= i830
->state
.Tex
[unit
][I830_TEXREG_MCS
];
353 mcs
&= ~TEXCOORDS_ARE_IN_TEXELUNITS
;
354 mcs
|= TEXCOORDS_ARE_NORMAL
;
356 if ((mcs
!= i830
->state
.Tex
[unit
][I830_TEXREG_MCS
])
357 || (0 != i830
->state
.Tex
[unit
][I830_TEXREG_CUBE
])) {
358 I830_STATECHANGE(i830
, I830_UPLOAD_TEX(unit
));
359 i830
->state
.Tex
[unit
][I830_TEXREG_MCS
] = mcs
;
360 i830
->state
.Tex
[unit
][I830_TEXREG_CUBE
] = 0;
367 static GLboolean
enable_tex_cube( GLcontext
*ctx
, GLuint unit
)
369 i830ContextPtr i830
= I830_CONTEXT(ctx
);
370 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
371 struct gl_texture_object
*tObj
= texUnit
->_Current
;
372 i830TextureObjectPtr t
= (i830TextureObjectPtr
)tObj
->DriverData
;
373 GLuint mcs
= i830
->state
.Tex
[unit
][I830_TEXREG_MCS
];
374 const GLuint cube
= CUBE_NEGX_ENABLE
| CUBE_POSX_ENABLE
375 | CUBE_NEGY_ENABLE
| CUBE_POSY_ENABLE
376 | CUBE_NEGZ_ENABLE
| CUBE_POSZ_ENABLE
;
379 mcs
&= ~TEXCOORDS_ARE_IN_TEXELUNITS
;
380 mcs
|= TEXCOORDS_ARE_NORMAL
;
382 if ((mcs
!= i830
->state
.Tex
[unit
][I830_TEXREG_MCS
])
383 || (cube
!= i830
->state
.Tex
[unit
][I830_TEXREG_CUBE
])) {
384 I830_STATECHANGE(i830
, I830_UPLOAD_TEX(unit
));
385 i830
->state
.Tex
[unit
][I830_TEXREG_MCS
] = mcs
;
386 i830
->state
.Tex
[unit
][I830_TEXREG_CUBE
] = cube
;
389 /* Upload teximages (not pipelined)
391 if ( t
->intel
.base
.dirty_images
[0] || t
->intel
.base
.dirty_images
[1] ||
392 t
->intel
.base
.dirty_images
[2] || t
->intel
.base
.dirty_images
[3] ||
393 t
->intel
.base
.dirty_images
[4] || t
->intel
.base
.dirty_images
[5] ) {
394 i830SetTexImages( i830
, tObj
);
397 /* upload (per face) */
398 for (face
= 0; face
< 6; face
++) {
399 if (t
->intel
.base
.dirty_images
[face
]) {
400 if (!intelUploadTexImages( &i830
->intel
, &t
->intel
, face
)) {
411 static GLboolean
disable_tex( GLcontext
*ctx
, GLuint unit
)
413 i830ContextPtr i830
= I830_CONTEXT(ctx
);
415 /* This is happening too often. I need to conditionally send diffuse
416 * state to the card. Perhaps a diffuse dirty flag of some kind.
417 * Will need to change this logic if more than 2 texture units are
418 * used. We need to only do this up to the last unit enabled, or unit
419 * one if nothing is enabled.
422 if ( i830
->intel
.CurrentTexObj
[unit
] != NULL
) {
423 /* The old texture is no longer bound to this texture unit.
427 i830
->intel
.CurrentTexObj
[unit
]->base
.bound
&= ~(1U << 0);
428 i830
->intel
.CurrentTexObj
[unit
] = NULL
;
434 static GLboolean
i830UpdateTexUnit( GLcontext
*ctx
, GLuint unit
)
436 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
438 if (texUnit
->_ReallyEnabled
&&
439 INTEL_CONTEXT(ctx
)->intelScreen
->tex
.size
< 2048 * 1024)
442 switch(texUnit
->_ReallyEnabled
) {
445 return (enable_tex_common( ctx
, unit
) &&
446 enable_tex_2d( ctx
, unit
));
447 case TEXTURE_RECT_BIT
:
448 return (enable_tex_common( ctx
, unit
) &&
449 enable_tex_rect( ctx
, unit
));
450 case TEXTURE_CUBE_BIT
:
451 return (enable_tex_common( ctx
, unit
) &&
452 enable_tex_cube( ctx
, unit
));
454 return disable_tex( ctx
, unit
);
461 void i830UpdateTextureState( intelContextPtr intel
)
463 i830ContextPtr i830
= I830_CONTEXT(intel
);
464 GLcontext
*ctx
= &intel
->ctx
;
467 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
469 I830_ACTIVESTATE(i830
, I830_UPLOAD_TEX_ALL
, GL_FALSE
);
471 ok
= (i830UpdateTexUnit( ctx
, 0 ) &&
472 i830UpdateTexUnit( ctx
, 1 ) &&
473 i830UpdateTexUnit( ctx
, 2 ) &&
474 i830UpdateTexUnit( ctx
, 3 ));
476 FALLBACK( intel
, I830_FALLBACK_TEXTURE
, !ok
);
479 i830EmitTextureBlend( i830
);