1 /************************************************************************** 2 * 3 * Copyright 2003 VMware, Inc. 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 VMWARE 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_L_UNORM8: 47 return MAPSURF_8BIT | MT_8BIT_L8; 48 case MESA_FORMAT_I_UNORM8: 49 return MAPSURF_8BIT | MT_8BIT_I8; 50 case MESA_FORMAT_L8A8_UNORM: 51 return MAPSURF_16BIT | MT_16BIT_AY88; 52 case MESA_FORMAT_B5G6R5_UNORM: 53 return MAPSURF_16BIT | MT_16BIT_RGB565; 54 case MESA_FORMAT_B5G5R5A1_UNORM: 55 return MAPSURF_16BIT | MT_16BIT_ARGB1555; 56 case MESA_FORMAT_B4G4R4A4_UNORM: 57 return MAPSURF_16BIT | MT_16BIT_ARGB4444; 58 case MESA_FORMAT_B8G8R8A8_UNORM: 59 return MAPSURF_32BIT | MT_32BIT_ARGB8888; 60 case MESA_FORMAT_B8G8R8X8_UNORM: 61 return MAPSURF_32BIT | MT_32BIT_XRGB8888; 62 case MESA_FORMAT_YCBCR_REV: 63 return (MAPSURF_422 | MT_422_YCRCB_NORMAL); 64 case MESA_FORMAT_YCBCR: 65 return (MAPSURF_422 | MT_422_YCRCB_SWAPY); 66 case MESA_FORMAT_RGB_FXT1: 67 case MESA_FORMAT_RGBA_FXT1: 68 return (MAPSURF_COMPRESSED | MT_COMPRESS_FXT1); 69 case MESA_FORMAT_RGBA_DXT1: 70 case MESA_FORMAT_RGB_DXT1: 71 return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT1); 72 case MESA_FORMAT_RGBA_DXT3: 73 return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT2_3); 74 case MESA_FORMAT_RGBA_DXT5: 75 return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5); 76 default: 77 fprintf(stderr, "%s: bad image format %s\n", __func__, 78 _mesa_get_format_name(mesa_format)); 79 abort(); 80 return 0; 81 } 82 } 83 84 85 86 87 /* The i915 (and related graphics cores) do not support GL_CLAMP. The 88 * Intel drivers for "other operating systems" implement GL_CLAMP as 89 * GL_CLAMP_TO_EDGE, so the same is done here. 90 */ 91 static GLuint 92 translate_wrap_mode(GLenum wrap) 93 { 94 switch (wrap) { 95 case GL_REPEAT: 96 return TEXCOORDMODE_WRAP; 97 case GL_CLAMP: 98 case GL_CLAMP_TO_EDGE: 99 return TEXCOORDMODE_CLAMP; /* not really correct */ 100 case GL_CLAMP_TO_BORDER: 101 return TEXCOORDMODE_CLAMP_BORDER; 102 case GL_MIRRORED_REPEAT: 103 return TEXCOORDMODE_MIRROR; 104 default: 105 return TEXCOORDMODE_WRAP; 106 } 107 } 108 109 110 /* Recalculate all state from scratch. Perhaps not the most 111 * efficient, but this has gotten complex enough that we need 112 * something which is understandable and reliable. 113 */ 114 static bool 115 i830_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) 116 { 117 struct gl_context *ctx = &intel->ctx; 118 struct i830_context *i830 = i830_context(ctx); 119 struct gl_texture_unit *tUnit = &ctx->Texture.Unit[unit]; 120 struct gl_texture_object *tObj = tUnit->_Current; 121 struct intel_texture_object *intelObj = intel_texture_object(tObj); 122 struct gl_texture_image *firstImage; 123 struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit); 124 GLuint *state = i830->state.Tex[unit], format, pitch; 125 GLint lodbias; 126 GLubyte border[4]; 127 GLuint dst_x, dst_y; 128 129 memset(state, 0, sizeof(*state)); 130 131 /*We need to refcount these. */ 132 133 if (i830->state.tex_buffer[unit] != NULL) { 134 drm_intel_bo_unreference(i830->state.tex_buffer[unit]); 135 i830->state.tex_buffer[unit] = NULL; 136 } 137 138 if (!intel_finalize_mipmap_tree(intel, unit)) 139 return false; 140 141 /* Get first image here, since intelObj->firstLevel will get set in 142 * the intel_finalize_mipmap_tree() call above. 143 */ 144 firstImage = tObj->Image[0][tObj->BaseLevel]; 145 146 intel_miptree_get_image_offset(intelObj->mt, tObj->BaseLevel, 0, 147 &dst_x, &dst_y); 148 149 drm_intel_bo_reference(intelObj->mt->region->bo); 150 i830->state.tex_buffer[unit] = intelObj->mt->region->bo; 151 pitch = intelObj->mt->region->pitch; 152 153 /* XXX: This calculation is probably broken for tiled images with 154 * a non-page-aligned offset. 155 */ 156 i830->state.tex_offset[unit] = dst_x * intelObj->mt->cpp + dst_y * pitch; 157 158 format = translate_texture_format(firstImage->TexFormat); 159 160 state[I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 | 161 (LOAD_TEXTURE_MAP0 << unit) | 4); 162 163 state[I830_TEXREG_TM0S1] = 164 (((firstImage->Height - 1) << TM0S1_HEIGHT_SHIFT) | 165 ((firstImage->Width - 1) << TM0S1_WIDTH_SHIFT) | format); 166 167 if (intelObj->mt->region->tiling != I915_TILING_NONE) { 168 state[I830_TEXREG_TM0S1] |= TM0S1_TILED_SURFACE; 169 if (intelObj->mt->region->tiling == I915_TILING_Y) 170 state[I830_TEXREG_TM0S1] |= TM0S1_TILE_WALK; 171 } 172 173 state[I830_TEXREG_TM0S2] = 174 ((((pitch / 4) - 1) << TM0S2_PITCH_SHIFT) | TM0S2_CUBE_FACE_ENA_MASK); 175 176 { 177 if (tObj->Target == GL_TEXTURE_CUBE_MAP) 178 state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit) | 179 CUBE_NEGX_ENABLE | 180 CUBE_POSX_ENABLE | 181 CUBE_NEGY_ENABLE | 182 CUBE_POSY_ENABLE | 183 CUBE_NEGZ_ENABLE | CUBE_POSZ_ENABLE); 184 else 185 state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit)); 186 } 187 188 189 190 191 { 192 GLuint minFilt, mipFilt, magFilt; 193 float maxlod; 194 uint32_t minlod_fixed, maxlod_fixed; 195 196 switch (sampler->MinFilter) { 197 case GL_NEAREST: 198 minFilt = FILTER_NEAREST; 199 mipFilt = MIPFILTER_NONE; 200 break; 201 case GL_LINEAR: 202 minFilt = FILTER_LINEAR; 203 mipFilt = MIPFILTER_NONE; 204 break; 205 case GL_NEAREST_MIPMAP_NEAREST: 206 minFilt = FILTER_NEAREST; 207 mipFilt = MIPFILTER_NEAREST; 208 break; 209 case GL_LINEAR_MIPMAP_NEAREST: 210 minFilt = FILTER_LINEAR; 211 mipFilt = MIPFILTER_NEAREST; 212 break; 213 case GL_NEAREST_MIPMAP_LINEAR: 214 minFilt = FILTER_NEAREST; 215 mipFilt = MIPFILTER_LINEAR; 216 break; 217 case GL_LINEAR_MIPMAP_LINEAR: 218 minFilt = FILTER_LINEAR; 219 mipFilt = MIPFILTER_LINEAR; 220 break; 221 default: 222 return false; 223 } 224 225 if (sampler->MaxAnisotropy > 1.0) { 226 minFilt = FILTER_ANISOTROPIC; 227 magFilt = FILTER_ANISOTROPIC; 228 /* no trilinear + anisotropic */ 229 mipFilt = MIPFILTER_NEAREST; 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 if (intel->ctx.Texture.Unit[i]._Current) { 335 switch (intel->ctx.Texture.Unit[i]._Current->Target) { 336 case GL_TEXTURE_1D: 337 case GL_TEXTURE_2D: 338 case GL_TEXTURE_CUBE_MAP: 339 ok = i830_update_tex_unit(intel, i, TEXCOORDS_ARE_NORMAL); 340 break; 341 case GL_TEXTURE_RECTANGLE: 342 ok = i830_update_tex_unit(intel, i, TEXCOORDS_ARE_IN_TEXELUNITS); 343 break; 344 case GL_TEXTURE_3D: 345 default: 346 ok = false; 347 break; 348 } 349 } else { 350 struct i830_context *i830 = i830_context(&intel->ctx); 351 if (i830->state.active & I830_UPLOAD_TEX(i)) 352 I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(i), false); 353 354 if (i830->state.tex_buffer[i] != NULL) { 355 drm_intel_bo_unreference(i830->state.tex_buffer[i]); 356 i830->state.tex_buffer[i] = NULL; 357 } 358 } 359 } 360 361 FALLBACK(intel, I830_FALLBACK_TEXTURE, !ok); 362 363 if (ok) 364 i830EmitTextureBlend(i830); 365 } 366