1 /************************************************************************** 2 * 3 * Copyright 2007 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 /* 29 * Authors: 30 * Keith Whitwell <keith (at) tungstengraphics.com> 31 * Brian Paul 32 */ 33 34 35 #include "main/macros.h" 36 #include "main/mtypes.h" 37 #include "main/samplerobj.h" 38 #include "main/texobj.h" 39 #include "program/prog_instruction.h" 40 41 #include "st_context.h" 42 #include "st_atom.h" 43 #include "st_texture.h" 44 #include "st_format.h" 45 #include "st_cb_texture.h" 46 #include "pipe/p_context.h" 47 #include "util/u_format.h" 48 #include "util/u_inlines.h" 49 #include "cso_cache/cso_context.h" 50 51 52 /** 53 * Combine depth texture mode with "swizzle" so that depth mode swizzling 54 * takes place before texture swizzling, and return the resulting swizzle. 55 * If the format is not a depth format, return "swizzle" unchanged. 56 * 57 * \param format PIPE_FORMAT_*. 58 * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4. 59 * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA, GL_RED. 60 */ 61 static GLuint 62 apply_depthmode(enum pipe_format format, GLuint swizzle, GLenum depthmode) 63 { 64 const struct util_format_description *desc = 65 util_format_description(format); 66 unsigned char swiz[4]; 67 unsigned i; 68 69 if (desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS || 70 desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_NONE) { 71 /* Not a depth format. */ 72 return swizzle; 73 } 74 75 for (i = 0; i < 4; i++) 76 swiz[i] = GET_SWZ(swizzle, i); 77 78 switch (depthmode) { 79 case GL_LUMINANCE: 80 /* Rewrite reads from W to ONE, and reads from XYZ to XXX. */ 81 for (i = 0; i < 4; i++) 82 if (swiz[i] == SWIZZLE_W) 83 swiz[i] = SWIZZLE_ONE; 84 else if (swiz[i] < SWIZZLE_W) 85 swiz[i] = SWIZZLE_X; 86 break; 87 88 case GL_INTENSITY: 89 /* Rewrite reads from XYZW to XXXX. */ 90 for (i = 0; i < 4; i++) 91 if (swiz[i] <= SWIZZLE_W) 92 swiz[i] = SWIZZLE_X; 93 break; 94 95 case GL_ALPHA: 96 /* Rewrite reads from W to X, and reads from XYZ to 000. */ 97 for (i = 0; i < 4; i++) 98 if (swiz[i] == SWIZZLE_W) 99 swiz[i] = SWIZZLE_X; 100 else if (swiz[i] < SWIZZLE_W) 101 swiz[i] = SWIZZLE_ZERO; 102 break; 103 case GL_RED: 104 /* Rewrite reads W to 1, XYZ to X00 */ 105 for (i = 0; i < 4; i++) 106 if (swiz[i] == SWIZZLE_W) 107 swiz[i] = SWIZZLE_ONE; 108 else if (swiz[i] == SWIZZLE_Y || swiz[i] == SWIZZLE_Z) 109 swiz[i] = SWIZZLE_ZERO; 110 break; 111 } 112 113 return MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]); 114 } 115 116 117 /** 118 * Return TRUE if the swizzling described by "swizzle" and 119 * "depthmode" (for depth textures only) is different from the swizzling 120 * set in the given sampler view. 121 * 122 * \param sv A sampler view. 123 * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4. 124 * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA. 125 */ 126 static boolean 127 check_sampler_swizzle(struct pipe_sampler_view *sv, 128 GLuint swizzle, GLenum depthmode) 129 { 130 swizzle = apply_depthmode(sv->texture->format, swizzle, depthmode); 131 132 if ((sv->swizzle_r != GET_SWZ(swizzle, 0)) || 133 (sv->swizzle_g != GET_SWZ(swizzle, 1)) || 134 (sv->swizzle_b != GET_SWZ(swizzle, 2)) || 135 (sv->swizzle_a != GET_SWZ(swizzle, 3))) 136 return TRUE; 137 return FALSE; 138 } 139 140 141 static struct pipe_sampler_view * 142 st_create_texture_sampler_view_from_stobj(struct pipe_context *pipe, 143 struct st_texture_object *stObj, 144 const struct gl_sampler_object *samp, 145 enum pipe_format format) 146 { 147 struct pipe_sampler_view templ; 148 GLuint swizzle = apply_depthmode(stObj->pt->format, 149 stObj->base._Swizzle, 150 stObj->base.DepthMode); 151 152 u_sampler_view_default_template(&templ, 153 stObj->pt, 154 format); 155 templ.u.tex.first_level = stObj->base.BaseLevel; 156 157 if (swizzle != SWIZZLE_NOOP) { 158 templ.swizzle_r = GET_SWZ(swizzle, 0); 159 templ.swizzle_g = GET_SWZ(swizzle, 1); 160 templ.swizzle_b = GET_SWZ(swizzle, 2); 161 templ.swizzle_a = GET_SWZ(swizzle, 3); 162 } 163 164 return pipe->create_sampler_view(pipe, stObj->pt, &templ); 165 } 166 167 168 static struct pipe_sampler_view * 169 st_get_texture_sampler_view_from_stobj(struct st_texture_object *stObj, 170 struct pipe_context *pipe, 171 const struct gl_sampler_object *samp, 172 enum pipe_format format) 173 { 174 if (!stObj || !stObj->pt) { 175 return NULL; 176 } 177 178 if (!stObj->sampler_view) { 179 stObj->sampler_view = 180 st_create_texture_sampler_view_from_stobj(pipe, stObj, samp, format); 181 } 182 183 return stObj->sampler_view; 184 } 185 186 187 static GLboolean 188 update_single_texture(struct st_context *st, 189 struct pipe_sampler_view **sampler_view, 190 GLuint texUnit) 191 { 192 struct pipe_context *pipe = st->pipe; 193 struct gl_context *ctx = st->ctx; 194 const struct gl_sampler_object *samp; 195 struct gl_texture_object *texObj; 196 struct st_texture_object *stObj; 197 enum pipe_format st_view_format; 198 GLboolean retval; 199 200 samp = _mesa_get_samplerobj(ctx, texUnit); 201 202 texObj = ctx->Texture.Unit[texUnit]._Current; 203 204 if (!texObj) { 205 texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); 206 samp = &texObj->Sampler; 207 } 208 stObj = st_texture_object(texObj); 209 210 retval = st_finalize_texture(ctx, st->pipe, texObj); 211 if (!retval) { 212 /* out of mem */ 213 return GL_FALSE; 214 } 215 216 /* Determine the format of the texture sampler view */ 217 st_view_format = stObj->pt->format; 218 { 219 const struct st_texture_image *firstImage = 220 st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); 221 const gl_format texFormat = firstImage->base.TexFormat; 222 enum pipe_format firstImageFormat = 223 st_mesa_format_to_pipe_format(texFormat); 224 225 if ((samp->sRGBDecode == GL_SKIP_DECODE_EXT) && 226 (_mesa_get_format_color_encoding(texFormat) == GL_SRGB)) { 227 /* Don't do sRGB->RGB conversion. Interpret the texture data as 228 * linear values. 229 */ 230 const gl_format linearFormat = 231 _mesa_get_srgb_format_linear(texFormat); 232 firstImageFormat = st_mesa_format_to_pipe_format(linearFormat); 233 } 234 235 if (firstImageFormat != stObj->pt->format) 236 st_view_format = firstImageFormat; 237 } 238 239 /* if sampler view has changed dereference it */ 240 if (stObj->sampler_view) { 241 if (check_sampler_swizzle(stObj->sampler_view, 242 stObj->base._Swizzle, 243 stObj->base.DepthMode) || 244 (st_view_format != stObj->sampler_view->format) || 245 stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) { 246 pipe_sampler_view_reference(&stObj->sampler_view, NULL); 247 } 248 } 249 250 *sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe, 251 samp, 252 st_view_format); 253 return GL_TRUE; 254 } 255 256 257 258 static void 259 update_textures(struct st_context *st, 260 unsigned shader_stage, 261 const struct gl_program *prog, 262 unsigned max_units, 263 struct pipe_sampler_view **sampler_views, 264 unsigned *num_textures) 265 { 266 const GLuint old_max = *num_textures; 267 GLbitfield samplers_used = prog->SamplersUsed; 268 GLuint unit, new_count; 269 270 if (samplers_used == 0x0 && old_max == 0) 271 return; 272 273 *num_textures = 0; 274 275 /* loop over sampler units (aka tex image units) */ 276 for (unit = 0; unit < max_units; unit++, samplers_used >>= 1) { 277 struct pipe_sampler_view *sampler_view = NULL; 278 279 if (samplers_used & 1) { 280 const GLuint texUnit = prog->SamplerUnits[unit]; 281 GLboolean retval; 282 283 retval = update_single_texture(st, &sampler_view, texUnit); 284 if (retval == GL_FALSE) 285 continue; 286 287 *num_textures = unit + 1; 288 } 289 else if (samplers_used == 0 && unit >= old_max) { 290 /* if we've reset all the old views and we have no more new ones */ 291 break; 292 } 293 294 pipe_sampler_view_reference(&(sampler_views[unit]), sampler_view); 295 } 296 297 /* Ex: if old_max = 3 and *num_textures = 1, we need to pass an 298 * array of views={X, NULL, NULL} to unref the old texture views 299 * at positions [1] and [2]. 300 */ 301 new_count = MAX2(*num_textures, old_max); 302 assert(new_count <= max_units); 303 304 cso_set_sampler_views(st->cso_context, 305 shader_stage, 306 new_count, 307 sampler_views); 308 } 309 310 311 312 static void 313 update_vertex_textures(struct st_context *st) 314 { 315 const struct gl_context *ctx = st->ctx; 316 317 if (ctx->Const.MaxVertexTextureImageUnits > 0) { 318 update_textures(st, 319 PIPE_SHADER_VERTEX, 320 &ctx->VertexProgram._Current->Base, 321 ctx->Const.MaxVertexTextureImageUnits, 322 st->state.sampler_views[PIPE_SHADER_VERTEX], 323 &st->state.num_sampler_views[PIPE_SHADER_VERTEX]); 324 } 325 } 326 327 328 static void 329 update_fragment_textures(struct st_context *st) 330 { 331 const struct gl_context *ctx = st->ctx; 332 333 update_textures(st, 334 PIPE_SHADER_FRAGMENT, 335 &ctx->FragmentProgram._Current->Base, 336 ctx->Const.MaxTextureImageUnits, 337 st->state.sampler_views[PIPE_SHADER_FRAGMENT], 338 &st->state.num_sampler_views[PIPE_SHADER_FRAGMENT]); 339 } 340 341 342 static void 343 update_geometry_textures(struct st_context *st) 344 { 345 const struct gl_context *ctx = st->ctx; 346 347 if (ctx->GeometryProgram._Current) { 348 update_textures(st, 349 PIPE_SHADER_GEOMETRY, 350 &ctx->GeometryProgram._Current->Base, 351 ctx->Const.MaxTextureImageUnits, 352 st->state.sampler_views[PIPE_SHADER_GEOMETRY], 353 &st->state.num_sampler_views[PIPE_SHADER_GEOMETRY]); 354 } 355 } 356 357 358 const struct st_tracked_state st_update_fragment_texture = { 359 "st_update_texture", /* name */ 360 { /* dirty */ 361 _NEW_TEXTURE, /* mesa */ 362 ST_NEW_FRAGMENT_PROGRAM, /* st */ 363 }, 364 update_fragment_textures /* update */ 365 }; 366 367 368 const struct st_tracked_state st_update_vertex_texture = { 369 "st_update_vertex_texture", /* name */ 370 { /* dirty */ 371 _NEW_TEXTURE, /* mesa */ 372 ST_NEW_VERTEX_PROGRAM, /* st */ 373 }, 374 update_vertex_textures /* update */ 375 }; 376 377 378 const struct st_tracked_state st_update_geometry_texture = { 379 "st_update_geometry_texture", /* name */ 380 { /* dirty */ 381 _NEW_TEXTURE, /* mesa */ 382 ST_NEW_GEOMETRY_PROGRAM, /* st */ 383 }, 384 update_geometry_textures /* update */ 385 }; 386 387 388 389 static void 390 finalize_textures(struct st_context *st) 391 { 392 struct gl_context *ctx = st->ctx; 393 struct gl_fragment_program *fprog = ctx->FragmentProgram._Current; 394 const GLboolean prev_missing_textures = st->missing_textures; 395 GLuint su; 396 397 st->missing_textures = GL_FALSE; 398 399 for (su = 0; su < ctx->Const.MaxTextureCoordUnits; su++) { 400 if (fprog->Base.SamplersUsed & (1 << su)) { 401 const GLuint texUnit = fprog->Base.SamplerUnits[su]; 402 struct gl_texture_object *texObj 403 = ctx->Texture.Unit[texUnit]._Current; 404 405 if (texObj) { 406 GLboolean retval; 407 408 retval = st_finalize_texture(ctx, st->pipe, texObj); 409 if (!retval) { 410 /* out of mem */ 411 st->missing_textures = GL_TRUE; 412 continue; 413 } 414 } 415 } 416 } 417 418 if (prev_missing_textures != st->missing_textures) 419 st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; 420 } 421 422 423 const struct st_tracked_state st_finalize_textures = { 424 "st_finalize_textures", /* name */ 425 { /* dirty */ 426 _NEW_TEXTURE, /* mesa */ 427 0, /* st */ 428 }, 429 finalize_textures /* update */ 430 }; 431