1 /************************************************************************** 2 * 3 * Copyright 2007 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 /* 29 * Authors: 30 * Keith Whitwell <keithw (at) vmware.com> 31 * Brian Paul 32 */ 33 34 35 #include "main/macros.h" 36 #include "main/mtypes.h" 37 #include "main/glformats.h" 38 #include "main/samplerobj.h" 39 #include "main/teximage.h" 40 #include "main/texobj.h" 41 42 #include "st_context.h" 43 #include "st_cb_texture.h" 44 #include "st_format.h" 45 #include "st_atom.h" 46 #include "st_texture.h" 47 #include "pipe/p_context.h" 48 #include "pipe/p_defines.h" 49 50 #include "cso_cache/cso_context.h" 51 52 #include "util/u_format.h" 53 54 55 /** 56 * Convert GLenum texcoord wrap tokens to pipe tokens. 57 */ 58 static GLuint 59 gl_wrap_xlate(GLenum wrap) 60 { 61 switch (wrap) { 62 case GL_REPEAT: 63 return PIPE_TEX_WRAP_REPEAT; 64 case GL_CLAMP: 65 return PIPE_TEX_WRAP_CLAMP; 66 case GL_CLAMP_TO_EDGE: 67 return PIPE_TEX_WRAP_CLAMP_TO_EDGE; 68 case GL_CLAMP_TO_BORDER: 69 return PIPE_TEX_WRAP_CLAMP_TO_BORDER; 70 case GL_MIRRORED_REPEAT: 71 return PIPE_TEX_WRAP_MIRROR_REPEAT; 72 case GL_MIRROR_CLAMP_EXT: 73 return PIPE_TEX_WRAP_MIRROR_CLAMP; 74 case GL_MIRROR_CLAMP_TO_EDGE_EXT: 75 return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; 76 case GL_MIRROR_CLAMP_TO_BORDER_EXT: 77 return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER; 78 default: 79 assert(0); 80 return 0; 81 } 82 } 83 84 85 static GLuint 86 gl_filter_to_mip_filter(GLenum filter) 87 { 88 switch (filter) { 89 case GL_NEAREST: 90 case GL_LINEAR: 91 return PIPE_TEX_MIPFILTER_NONE; 92 93 case GL_NEAREST_MIPMAP_NEAREST: 94 case GL_LINEAR_MIPMAP_NEAREST: 95 return PIPE_TEX_MIPFILTER_NEAREST; 96 97 case GL_NEAREST_MIPMAP_LINEAR: 98 case GL_LINEAR_MIPMAP_LINEAR: 99 return PIPE_TEX_MIPFILTER_LINEAR; 100 101 default: 102 assert(0); 103 return PIPE_TEX_MIPFILTER_NONE; 104 } 105 } 106 107 108 static GLuint 109 gl_filter_to_img_filter(GLenum filter) 110 { 111 switch (filter) { 112 case GL_NEAREST: 113 case GL_NEAREST_MIPMAP_NEAREST: 114 case GL_NEAREST_MIPMAP_LINEAR: 115 return PIPE_TEX_FILTER_NEAREST; 116 117 case GL_LINEAR: 118 case GL_LINEAR_MIPMAP_NEAREST: 119 case GL_LINEAR_MIPMAP_LINEAR: 120 return PIPE_TEX_FILTER_LINEAR; 121 122 default: 123 assert(0); 124 return PIPE_TEX_FILTER_NEAREST; 125 } 126 } 127 128 129 static void 130 convert_sampler(struct st_context *st, 131 struct pipe_sampler_state *sampler, 132 GLuint texUnit) 133 { 134 const struct gl_texture_object *texobj; 135 struct gl_context *ctx = st->ctx; 136 const struct gl_sampler_object *msamp; 137 GLenum texBaseFormat; 138 139 texobj = ctx->Texture.Unit[texUnit]._Current; 140 if (!texobj) { 141 texobj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); 142 msamp = &texobj->Sampler; 143 } else { 144 msamp = _mesa_get_samplerobj(ctx, texUnit); 145 } 146 147 texBaseFormat = _mesa_texture_base_format(texobj); 148 149 memset(sampler, 0, sizeof(*sampler)); 150 sampler->wrap_s = gl_wrap_xlate(msamp->WrapS); 151 sampler->wrap_t = gl_wrap_xlate(msamp->WrapT); 152 sampler->wrap_r = gl_wrap_xlate(msamp->WrapR); 153 154 sampler->min_img_filter = gl_filter_to_img_filter(msamp->MinFilter); 155 sampler->min_mip_filter = gl_filter_to_mip_filter(msamp->MinFilter); 156 sampler->mag_img_filter = gl_filter_to_img_filter(msamp->MagFilter); 157 158 if (texobj->Target != GL_TEXTURE_RECTANGLE_ARB) 159 sampler->normalized_coords = 1; 160 161 sampler->lod_bias = ctx->Texture.Unit[texUnit].LodBias + msamp->LodBias; 162 /* Reduce the number of states by allowing only the values that AMD GCN 163 * can represent. Apps use lod_bias for smooth transitions to bigger mipmap 164 * levels. 165 */ 166 sampler->lod_bias = CLAMP(sampler->lod_bias, -16, 16); 167 sampler->lod_bias = floorf(sampler->lod_bias * 256) / 256; 168 169 sampler->min_lod = MAX2(msamp->MinLod, 0.0f); 170 sampler->max_lod = msamp->MaxLod; 171 if (sampler->max_lod < sampler->min_lod) { 172 /* The GL spec doesn't seem to specify what to do in this case. 173 * Swap the values. 174 */ 175 float tmp = sampler->max_lod; 176 sampler->max_lod = sampler->min_lod; 177 sampler->min_lod = tmp; 178 assert(sampler->min_lod <= sampler->max_lod); 179 } 180 181 /* For non-black borders... */ 182 if (msamp->BorderColor.ui[0] || 183 msamp->BorderColor.ui[1] || 184 msamp->BorderColor.ui[2] || 185 msamp->BorderColor.ui[3]) { 186 const struct st_texture_object *stobj = st_texture_object_const(texobj); 187 const GLboolean is_integer = texobj->_IsIntegerFormat; 188 const struct pipe_sampler_view *sv = NULL; 189 union pipe_color_union border_color; 190 GLuint i; 191 192 /* Just search for the first used view. We can do this because the 193 swizzle is per-texture, not per context. */ 194 /* XXX: clean that up to not use the sampler view at all */ 195 for (i = 0; i < stobj->num_sampler_views; ++i) { 196 if (stobj->sampler_views[i]) { 197 sv = stobj->sampler_views[i]; 198 break; 199 } 200 } 201 202 if (st->apply_texture_swizzle_to_border_color && sv) { 203 const unsigned char swz[4] = 204 { 205 sv->swizzle_r, 206 sv->swizzle_g, 207 sv->swizzle_b, 208 sv->swizzle_a, 209 }; 210 211 st_translate_color(&msamp->BorderColor, 212 &border_color, 213 texBaseFormat, is_integer); 214 215 util_format_apply_color_swizzle(&sampler->border_color, 216 &border_color, swz, is_integer); 217 } else { 218 st_translate_color(&msamp->BorderColor, 219 &sampler->border_color, 220 texBaseFormat, is_integer); 221 } 222 } 223 224 sampler->max_anisotropy = (msamp->MaxAnisotropy == 1.0 ? 225 0 : (GLuint) msamp->MaxAnisotropy); 226 227 /* If sampling a depth texture and using shadow comparison */ 228 if ((texBaseFormat == GL_DEPTH_COMPONENT || 229 (texBaseFormat == GL_DEPTH_STENCIL && !texobj->StencilSampling)) && 230 msamp->CompareMode == GL_COMPARE_R_TO_TEXTURE) { 231 sampler->compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE; 232 sampler->compare_func = st_compare_func_to_pipe(msamp->CompareFunc); 233 } 234 235 sampler->seamless_cube_map = 236 ctx->Texture.CubeMapSeamless || msamp->CubeMapSeamless; 237 } 238 239 240 /** 241 * Update the gallium driver's sampler state for fragment, vertex or 242 * geometry shader stage. 243 */ 244 static void 245 update_shader_samplers(struct st_context *st, 246 enum pipe_shader_type shader_stage, 247 const struct gl_program *prog, 248 unsigned max_units, 249 struct pipe_sampler_state *samplers, 250 unsigned *num_samplers) 251 { 252 GLbitfield samplers_used = prog->SamplersUsed; 253 GLbitfield free_slots = ~prog->SamplersUsed; 254 GLbitfield external_samplers_used = prog->ExternalSamplersUsed; 255 GLuint unit; 256 const GLuint old_max = *num_samplers; 257 const struct pipe_sampler_state *states[PIPE_MAX_SAMPLERS]; 258 259 if (*num_samplers == 0 && samplers_used == 0x0) 260 return; 261 262 *num_samplers = 0; 263 264 /* loop over sampler units (aka tex image units) */ 265 for (unit = 0; unit < max_units; unit++, samplers_used >>= 1) { 266 struct pipe_sampler_state *sampler = samplers + unit; 267 268 if (samplers_used & 1) { 269 const GLuint texUnit = prog->SamplerUnits[unit]; 270 271 convert_sampler(st, sampler, texUnit); 272 states[unit] = sampler; 273 *num_samplers = unit + 1; 274 } 275 else if (samplers_used != 0 || unit < old_max) { 276 states[unit] = NULL; 277 } 278 else { 279 /* if we've reset all the old samplers and we have no more new ones */ 280 break; 281 } 282 } 283 284 /* For any external samplers with multiplaner YUV, stuff the additional 285 * sampler states we need at the end. 286 * 287 * Just re-use the existing sampler-state from the primary slot. 288 */ 289 while (unlikely(external_samplers_used)) { 290 GLuint unit = u_bit_scan(&external_samplers_used); 291 GLuint extra = 0; 292 struct st_texture_object *stObj = 293 st_get_texture_object(st->ctx, prog, unit); 294 struct pipe_sampler_state *sampler = samplers + unit; 295 296 if (!stObj) 297 continue; 298 299 switch (st_get_view_format(stObj)) { 300 case PIPE_FORMAT_NV12: 301 /* we need one additional sampler: */ 302 extra = u_bit_scan(&free_slots); 303 states[extra] = sampler; 304 break; 305 case PIPE_FORMAT_IYUV: 306 /* we need two additional samplers: */ 307 extra = u_bit_scan(&free_slots); 308 states[extra] = sampler; 309 extra = u_bit_scan(&free_slots); 310 states[extra] = sampler; 311 break; 312 default: 313 break; 314 } 315 316 *num_samplers = MAX2(*num_samplers, extra + 1); 317 } 318 319 cso_set_samplers(st->cso_context, shader_stage, *num_samplers, states); 320 } 321 322 323 static void 324 update_samplers(struct st_context *st) 325 { 326 const struct gl_context *ctx = st->ctx; 327 328 update_shader_samplers(st, 329 PIPE_SHADER_FRAGMENT, 330 ctx->FragmentProgram._Current, 331 ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits, 332 st->state.samplers[PIPE_SHADER_FRAGMENT], 333 &st->state.num_samplers[PIPE_SHADER_FRAGMENT]); 334 335 update_shader_samplers(st, 336 PIPE_SHADER_VERTEX, 337 ctx->VertexProgram._Current, 338 ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits, 339 st->state.samplers[PIPE_SHADER_VERTEX], 340 &st->state.num_samplers[PIPE_SHADER_VERTEX]); 341 342 if (ctx->GeometryProgram._Current) { 343 update_shader_samplers(st, 344 PIPE_SHADER_GEOMETRY, 345 ctx->GeometryProgram._Current, 346 ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxTextureImageUnits, 347 st->state.samplers[PIPE_SHADER_GEOMETRY], 348 &st->state.num_samplers[PIPE_SHADER_GEOMETRY]); 349 } 350 if (ctx->TessCtrlProgram._Current) { 351 update_shader_samplers(st, 352 PIPE_SHADER_TESS_CTRL, 353 ctx->TessCtrlProgram._Current, 354 ctx->Const.Program[MESA_SHADER_TESS_CTRL].MaxTextureImageUnits, 355 st->state.samplers[PIPE_SHADER_TESS_CTRL], 356 &st->state.num_samplers[PIPE_SHADER_TESS_CTRL]); 357 } 358 if (ctx->TessEvalProgram._Current) { 359 update_shader_samplers(st, 360 PIPE_SHADER_TESS_EVAL, 361 ctx->TessEvalProgram._Current, 362 ctx->Const.Program[MESA_SHADER_TESS_EVAL].MaxTextureImageUnits, 363 st->state.samplers[PIPE_SHADER_TESS_EVAL], 364 &st->state.num_samplers[PIPE_SHADER_TESS_EVAL]); 365 } 366 if (ctx->ComputeProgram._Current) { 367 update_shader_samplers(st, 368 PIPE_SHADER_COMPUTE, 369 ctx->ComputeProgram._Current, 370 ctx->Const.Program[MESA_SHADER_COMPUTE].MaxTextureImageUnits, 371 st->state.samplers[PIPE_SHADER_COMPUTE], 372 &st->state.num_samplers[PIPE_SHADER_COMPUTE]); 373 } 374 } 375 376 377 const struct st_tracked_state st_update_sampler = { 378 update_samplers /* update */ 379 }; 380