1 /************************************************************************** 2 * 3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 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: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 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. 25 * 26 **************************************************************************/ 27 28 #include "main/mtypes.h" 29 #include "main/enums.h" 30 #include "main/colormac.h" 31 #include "main/macros.h" 32 #include "main/samplerobj.h" 33 34 #include "intel_mipmap_tree.h" 35 #include "intel_tex.h" 36 37 #include "i830_context.h" 38 #include "i830_reg.h" 39 #include "intel_chipset.h" 40 41 42 static GLuint 43 translate_texture_format(GLuint mesa_format) 44 { 45 switch (mesa_format) { 46 case MESA_FORMAT_L8: 47 return MAPSURF_8BIT | MT_8BIT_L8; 48 case MESA_FORMAT_I8: 49 return MAPSURF_8BIT | MT_8BIT_I8; 50 case MESA_FORMAT_A8: 51 return MAPSURF_8BIT | MT_8BIT_I8; /* Kludge! */ 52 case MESA_FORMAT_AL88: 53 return MAPSURF_16BIT | MT_16BIT_AY88; 54 case MESA_FORMAT_RGB565: 55 return MAPSURF_16BIT | MT_16BIT_RGB565; 56 case MESA_FORMAT_ARGB1555: 57 return MAPSURF_16BIT | MT_16BIT_ARGB1555; 58 case MESA_FORMAT_ARGB4444: 59 return MAPSURF_16BIT | MT_16BIT_ARGB4444; 60 case MESA_FORMAT_ARGB8888: 61 return MAPSURF_32BIT | MT_32BIT_ARGB8888; 62 case MESA_FORMAT_XRGB8888: 63 return MAPSURF_32BIT | MT_32BIT_XRGB8888; 64 case MESA_FORMAT_YCBCR_REV: 65 return (MAPSURF_422 | MT_422_YCRCB_NORMAL); 66 case MESA_FORMAT_YCBCR: 67 return (MAPSURF_422 | MT_422_YCRCB_SWAPY); 68 case MESA_FORMAT_RGB_FXT1: 69 case MESA_FORMAT_RGBA_FXT1: 70 return (MAPSURF_COMPRESSED | MT_COMPRESS_FXT1); 71 case MESA_FORMAT_RGBA_DXT1: 72 case MESA_FORMAT_RGB_DXT1: 73 return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT1); 74 case MESA_FORMAT_RGBA_DXT3: 75 return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT2_3); 76 case MESA_FORMAT_RGBA_DXT5: 77 return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5); 78 default: 79 fprintf(stderr, "%s: bad image format %s\n", __FUNCTION__, 80 _mesa_get_format_name(mesa_format)); 81 abort(); 82 return 0; 83 } 84 } 85 86 87 88 89 /* The i915 (and related graphics cores) do not support GL_CLAMP. The 90 * Intel drivers for "other operating systems" implement GL_CLAMP as 91 * GL_CLAMP_TO_EDGE, so the same is done here. 92 */ 93 static GLuint 94 translate_wrap_mode(GLenum wrap) 95 { 96 switch (wrap) { 97 case GL_REPEAT: 98 return TEXCOORDMODE_WRAP; 99 case GL_CLAMP: 100 case GL_CLAMP_TO_EDGE: 101 return TEXCOORDMODE_CLAMP; /* not really correct */ 102 case GL_CLAMP_TO_BORDER: 103 return TEXCOORDMODE_CLAMP_BORDER; 104 case GL_MIRRORED_REPEAT: 105 return TEXCOORDMODE_MIRROR; 106 default: 107 return TEXCOORDMODE_WRAP; 108 } 109 } 110 111 112 /* Recalculate all state from scratch. Perhaps not the most 113 * efficient, but this has gotten complex enough that we need 114 * something which is understandable and reliable. 115 */ 116 static bool 117 i830_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) 118 { 119 struct gl_context *ctx = &intel->ctx; 120 struct i830_context *i830 = i830_context(ctx); 121 struct gl_texture_unit *tUnit = &ctx->Texture.Unit[unit]; 122 struct gl_texture_object *tObj = tUnit->_Current; 123 struct intel_texture_object *intelObj = intel_texture_object(tObj); 124 struct gl_texture_image *firstImage; 125 struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit); 126 GLuint *state = i830->state.Tex[unit], format, pitch; 127 GLint lodbias; 128 GLubyte border[4]; 129 GLuint dst_x, dst_y; 130 131 memset(state, 0, sizeof(*state)); 132 133 /*We need to refcount these. */ 134 135 if (i830->state.tex_buffer[unit] != NULL) { 136 drm_intel_bo_unreference(i830->state.tex_buffer[unit]); 137 i830->state.tex_buffer[unit] = NULL; 138 } 139 140 if (!intel_finalize_mipmap_tree(intel, unit)) 141 return false; 142 143 /* Get first image here, since intelObj->firstLevel will get set in 144 * the intel_finalize_mipmap_tree() call above. 145 */ 146 firstImage = tObj->Image[0][tObj->BaseLevel]; 147 148 intel_miptree_get_image_offset(intelObj->mt, tObj->BaseLevel, 0, 0, 149 &dst_x, &dst_y); 150 151 drm_intel_bo_reference(intelObj->mt->region->bo); 152 i830->state.tex_buffer[unit] = intelObj->mt->region->bo; 153 pitch = intelObj->mt->region->pitch * intelObj->mt->cpp; 154 155 /* XXX: This calculation is probably broken for tiled images with 156 * a non-page-aligned offset. 157 */ 158 i830->state.tex_offset[unit] = dst_x * intelObj->mt->cpp + dst_y * pitch; 159 160 format = translate_texture_format(firstImage->TexFormat); 161 162 state[I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 | 163 (LOAD_TEXTURE_MAP0 << unit) | 4); 164 165 state[I830_TEXREG_TM0S1] = 166 (((firstImage->Height - 1) << TM0S1_HEIGHT_SHIFT) | 167 ((firstImage->Width - 1) << TM0S1_WIDTH_SHIFT) | format); 168 169 if (intelObj->mt->region->tiling != I915_TILING_NONE) { 170 state[I830_TEXREG_TM0S1] |= TM0S1_TILED_SURFACE; 171 if (intelObj->mt->region->tiling == I915_TILING_Y) 172 state[I830_TEXREG_TM0S1] |= TM0S1_TILE_WALK; 173 } 174 175 state[I830_TEXREG_TM0S2] = 176 ((((pitch / 4) - 1) << TM0S2_PITCH_SHIFT) | TM0S2_CUBE_FACE_ENA_MASK); 177 178 { 179 if (tObj->Target == GL_TEXTURE_CUBE_MAP) 180 state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit) | 181 CUBE_NEGX_ENABLE | 182 CUBE_POSX_ENABLE | 183 CUBE_NEGY_ENABLE | 184 CUBE_POSY_ENABLE | 185 CUBE_NEGZ_ENABLE | CUBE_POSZ_ENABLE); 186 else 187 state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit)); 188 } 189 190 191 192 193 { 194 GLuint minFilt, mipFilt, magFilt; 195 float maxlod; 196 uint32_t minlod_fixed, maxlod_fixed; 197 198 switch (sampler->MinFilter) { 199 case GL_NEAREST: 200 minFilt = FILTER_NEAREST; 201 mipFilt = MIPFILTER_NONE; 202 break; 203 case GL_LINEAR: 204 minFilt = FILTER_LINEAR; 205 mipFilt = MIPFILTER_NONE; 206 break; 207 case GL_NEAREST_MIPMAP_NEAREST: 208 minFilt = FILTER_NEAREST; 209 mipFilt = MIPFILTER_NEAREST; 210 break; 211 case GL_LINEAR_MIPMAP_NEAREST: 212 minFilt = FILTER_LINEAR; 213 mipFilt = MIPFILTER_NEAREST; 214 break; 215 case GL_NEAREST_MIPMAP_LINEAR: 216 minFilt = FILTER_NEAREST; 217 mipFilt = MIPFILTER_LINEAR; 218 break; 219 case GL_LINEAR_MIPMAP_LINEAR: 220 minFilt = FILTER_LINEAR; 221 mipFilt = MIPFILTER_LINEAR; 222 break; 223 default: 224 return false; 225 } 226 227 if (sampler->MaxAnisotropy > 1.0) { 228 minFilt = FILTER_ANISOTROPIC; 229 magFilt = FILTER_ANISOTROPIC; 230 } 231 else { 232 switch (sampler->MagFilter) { 233 case GL_NEAREST: 234 magFilt = FILTER_NEAREST; 235 break; 236 case GL_LINEAR: 237 magFilt = FILTER_LINEAR; 238 break; 239 default: 240 return false; 241 } 242 } 243 244 lodbias = (int) ((tUnit->LodBias + sampler->LodBias) * 16.0); 245 if (lodbias < -64) 246 lodbias = -64; 247 if (lodbias > 63) 248 lodbias = 63; 249 250 state[I830_TEXREG_TM0S3] = ((lodbias << TM0S3_LOD_BIAS_SHIFT) & 251 TM0S3_LOD_BIAS_MASK); 252 #if 0 253 /* YUV conversion: 254 */ 255 if (firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR || 256 firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV) 257 state[I830_TEXREG_TM0S3] |= SS2_COLORSPACE_CONVERSION; 258 #endif 259 260 /* We get one field with fraction bits for the maximum 261 * addressable (smallest resolution) LOD. Use it to cover both 262 * MAX_LEVEL and MAX_LOD. 263 */ 264 minlod_fixed = U_FIXED(CLAMP(sampler->MinLod, 0.0, 11), 4); 265 maxlod = MIN2(sampler->MaxLod, tObj->_MaxLevel - tObj->BaseLevel); 266 if (intel->intelScreen->deviceID == PCI_CHIP_I855_GM || 267 intel->intelScreen->deviceID == PCI_CHIP_I865_G) { 268 maxlod_fixed = U_FIXED(CLAMP(maxlod, 0.0, 11.75), 2); 269 maxlod_fixed = MAX2(maxlod_fixed, (minlod_fixed + 3) >> 2); 270 state[I830_TEXREG_TM0S3] |= maxlod_fixed << TM0S3_MIN_MIP_SHIFT; 271 state[I830_TEXREG_TM0S2] |= TM0S2_LOD_PRECLAMP; 272 } else { 273 maxlod_fixed = U_FIXED(CLAMP(maxlod, 0.0, 11), 0); 274 maxlod_fixed = MAX2(maxlod_fixed, (minlod_fixed + 15) >> 4); 275 state[I830_TEXREG_TM0S3] |= maxlod_fixed << TM0S3_MIN_MIP_SHIFT_830; 276 } 277 state[I830_TEXREG_TM0S3] |= minlod_fixed << TM0S3_MAX_MIP_SHIFT; 278 state[I830_TEXREG_TM0S3] |= ((minFilt << TM0S3_MIN_FILTER_SHIFT) | 279 (mipFilt << TM0S3_MIP_FILTER_SHIFT) | 280 (magFilt << TM0S3_MAG_FILTER_SHIFT)); 281 } 282 283 { 284 GLenum ws = sampler->WrapS; 285 GLenum wt = sampler->WrapT; 286 287 288 /* 3D textures not available on i830 289 */ 290 if (tObj->Target == GL_TEXTURE_3D) 291 return false; 292 293 state[I830_TEXREG_MCS] = (_3DSTATE_MAP_COORD_SET_CMD | 294 MAP_UNIT(unit) | 295 ENABLE_TEXCOORD_PARAMS | 296 ss3 | 297 ENABLE_ADDR_V_CNTL | 298 TEXCOORD_ADDR_V_MODE(translate_wrap_mode(wt)) 299 | ENABLE_ADDR_U_CNTL | 300 TEXCOORD_ADDR_U_MODE(translate_wrap_mode 301 (ws))); 302 } 303 304 /* convert border color from float to ubyte */ 305 CLAMPED_FLOAT_TO_UBYTE(border[0], sampler->BorderColor.f[0]); 306 CLAMPED_FLOAT_TO_UBYTE(border[1], sampler->BorderColor.f[1]); 307 CLAMPED_FLOAT_TO_UBYTE(border[2], sampler->BorderColor.f[2]); 308 CLAMPED_FLOAT_TO_UBYTE(border[3], sampler->BorderColor.f[3]); 309 310 state[I830_TEXREG_TM0S4] = PACK_COLOR_8888(border[3], 311 border[0], 312 border[1], 313 border[2]); 314 315 I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(unit), true); 316 /* memcmp was already disabled, but definitely won't work as the 317 * region might now change and that wouldn't be detected: 318 */ 319 I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit)); 320 return true; 321 } 322 323 324 325 326 void 327 i830UpdateTextureState(struct intel_context *intel) 328 { 329 struct i830_context *i830 = i830_context(&intel->ctx); 330 bool ok = true; 331 GLuint i; 332 333 for (i = 0; i < I830_TEX_UNITS && ok; i++) { 334 switch (intel->ctx.Texture.Unit[i]._ReallyEnabled) { 335 case TEXTURE_1D_BIT: 336 case TEXTURE_2D_BIT: 337 case TEXTURE_CUBE_BIT: 338 ok = i830_update_tex_unit(intel, i, TEXCOORDS_ARE_NORMAL); 339 break; 340 case TEXTURE_RECT_BIT: 341 ok = i830_update_tex_unit(intel, i, TEXCOORDS_ARE_IN_TEXELUNITS); 342 break; 343 case 0:{ 344 struct i830_context *i830 = i830_context(&intel->ctx); 345 if (i830->state.active & I830_UPLOAD_TEX(i)) 346 I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(i), false); 347 348 if (i830->state.tex_buffer[i] != NULL) { 349 drm_intel_bo_unreference(i830->state.tex_buffer[i]); 350 i830->state.tex_buffer[i] = NULL; 351 } 352 break; 353 } 354 case TEXTURE_3D_BIT: 355 default: 356 ok = false; 357 break; 358 } 359 } 360 361 FALLBACK(intel, I830_FALLBACK_TEXTURE, !ok); 362 363 if (ok) 364 i830EmitTextureBlend(i830); 365 } 366