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 /* Authors: 29 * Brian Paul 30 */ 31 32 #include "util/u_memory.h" 33 #include "util/u_inlines.h" 34 35 #include "draw/draw_context.h" 36 37 #include "sp_context.h" 38 #include "sp_state.h" 39 #include "sp_texture.h" 40 #include "sp_tex_sample.h" 41 #include "sp_tex_tile_cache.h" 42 43 44 struct sp_sampler { 45 struct pipe_sampler_state base; 46 struct sp_sampler_variant *variants; 47 struct sp_sampler_variant *current; 48 }; 49 50 static struct sp_sampler *sp_sampler( struct pipe_sampler_state *sampler ) 51 { 52 return (struct sp_sampler *)sampler; 53 } 54 55 56 static void * 57 softpipe_create_sampler_state(struct pipe_context *pipe, 58 const struct pipe_sampler_state *sampler) 59 { 60 struct sp_sampler *sp_sampler = CALLOC_STRUCT(sp_sampler); 61 62 sp_sampler->base = *sampler; 63 sp_sampler->variants = NULL; 64 65 return (void *)sp_sampler; 66 } 67 68 69 /** 70 * Bind a range [start, start+num-1] of samplers for a shader stage. 71 */ 72 static void 73 softpipe_bind_sampler_states(struct pipe_context *pipe, 74 unsigned shader, 75 unsigned start, 76 unsigned num, 77 void **samplers) 78 { 79 struct softpipe_context *softpipe = softpipe_context(pipe); 80 unsigned i; 81 82 assert(shader < PIPE_SHADER_TYPES); 83 assert(start + num <= Elements(softpipe->samplers[shader])); 84 85 /* Check for no-op */ 86 if (start + num <= softpipe->num_samplers[shader] && 87 !memcmp(softpipe->samplers[shader] + start, samplers, 88 num * sizeof(void *))) { 89 return; 90 } 91 92 draw_flush(softpipe->draw); 93 94 /* set the new samplers */ 95 for (i = 0; i < num; i++) { 96 softpipe->samplers[shader][start + i] = samplers[i]; 97 } 98 99 /* find highest non-null samplers[] entry */ 100 { 101 unsigned j = MAX2(softpipe->num_samplers[shader], start + num); 102 while (j > 0 && softpipe->samplers[shader][j - 1] == NULL) 103 j--; 104 softpipe->num_samplers[shader] = j; 105 } 106 107 if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) { 108 draw_set_samplers(softpipe->draw, 109 shader, 110 softpipe->samplers[shader], 111 softpipe->num_samplers[shader]); 112 } 113 114 softpipe->dirty |= SP_NEW_SAMPLER; 115 } 116 117 118 119 static void 120 softpipe_bind_fragment_sampler_states(struct pipe_context *pipe, 121 unsigned num, void **samplers) 122 { 123 softpipe_bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, num, samplers); 124 } 125 126 127 static void 128 softpipe_bind_vertex_sampler_states(struct pipe_context *pipe, 129 unsigned num, 130 void **samplers) 131 { 132 softpipe_bind_sampler_states(pipe, PIPE_SHADER_VERTEX, 0, num, samplers); 133 } 134 135 136 static void 137 softpipe_bind_geometry_sampler_states(struct pipe_context *pipe, 138 unsigned num, 139 void **samplers) 140 { 141 softpipe_bind_sampler_states(pipe, PIPE_SHADER_GEOMETRY, 0, num, samplers); 142 } 143 144 145 static struct pipe_sampler_view * 146 softpipe_create_sampler_view(struct pipe_context *pipe, 147 struct pipe_resource *resource, 148 const struct pipe_sampler_view *templ) 149 { 150 struct pipe_sampler_view *view = CALLOC_STRUCT(pipe_sampler_view); 151 152 if (view) { 153 *view = *templ; 154 view->reference.count = 1; 155 view->texture = NULL; 156 pipe_resource_reference(&view->texture, resource); 157 view->context = pipe; 158 } 159 160 return view; 161 } 162 163 164 static void 165 softpipe_sampler_view_destroy(struct pipe_context *pipe, 166 struct pipe_sampler_view *view) 167 { 168 pipe_resource_reference(&view->texture, NULL); 169 FREE(view); 170 } 171 172 173 static void 174 softpipe_set_sampler_views(struct pipe_context *pipe, 175 unsigned shader, 176 unsigned start, 177 unsigned num, 178 struct pipe_sampler_view **views) 179 { 180 struct softpipe_context *softpipe = softpipe_context(pipe); 181 uint i; 182 183 assert(shader < PIPE_SHADER_TYPES); 184 assert(start + num <= Elements(softpipe->sampler_views[shader])); 185 186 /* Check for no-op */ 187 if (start + num <= softpipe->num_sampler_views[shader] && 188 !memcmp(softpipe->sampler_views[shader] + start, views, 189 num * sizeof(struct pipe_sampler_view *))) { 190 return; 191 } 192 193 draw_flush(softpipe->draw); 194 195 /* set the new sampler views */ 196 for (i = 0; i < num; i++) { 197 pipe_sampler_view_reference(&softpipe->sampler_views[shader][start + i], 198 views[i]); 199 sp_tex_tile_cache_set_sampler_view(softpipe->tex_cache[shader][start + i], 200 views[i]); 201 } 202 203 /* find highest non-null sampler_views[] entry */ 204 { 205 unsigned j = MAX2(softpipe->num_sampler_views[shader], start + num); 206 while (j > 0 && softpipe->sampler_views[shader][j - 1] == NULL) 207 j--; 208 softpipe->num_sampler_views[shader] = j; 209 } 210 211 if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) { 212 draw_set_sampler_views(softpipe->draw, 213 shader, 214 softpipe->sampler_views[shader], 215 softpipe->num_sampler_views[shader]); 216 } 217 218 softpipe->dirty |= SP_NEW_TEXTURE; 219 } 220 221 222 static void 223 softpipe_set_fragment_sampler_views(struct pipe_context *pipe, 224 unsigned num, 225 struct pipe_sampler_view **views) 226 { 227 softpipe_set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, num, views); 228 } 229 230 231 static void 232 softpipe_set_vertex_sampler_views(struct pipe_context *pipe, 233 unsigned num, 234 struct pipe_sampler_view **views) 235 { 236 softpipe_set_sampler_views(pipe, PIPE_SHADER_VERTEX, 0, num, views); 237 } 238 239 240 static void 241 softpipe_set_geometry_sampler_views(struct pipe_context *pipe, 242 unsigned num, 243 struct pipe_sampler_view **views) 244 { 245 softpipe_set_sampler_views(pipe, PIPE_SHADER_GEOMETRY, 0, num, views); 246 } 247 248 249 /** 250 * Find/create an sp_sampler_variant object for sampling the given texture, 251 * sampler and tex unit. 252 * 253 * Note that the tex unit is significant. We can't re-use a sampler 254 * variant for multiple texture units because the sampler variant contains 255 * the texture object pointer. If the texture object pointer were stored 256 * somewhere outside the sampler variant, we could re-use samplers for 257 * multiple texture units. 258 */ 259 static struct sp_sampler_variant * 260 get_sampler_variant( unsigned unit, 261 struct sp_sampler *sampler, 262 struct pipe_sampler_view *view, 263 unsigned processor ) 264 { 265 struct softpipe_resource *sp_texture = softpipe_resource(view->texture); 266 struct sp_sampler_variant *v = NULL; 267 union sp_sampler_key key; 268 269 /* if this fails, widen the key.unit field and update this assertion */ 270 assert(PIPE_MAX_SAMPLERS <= 16); 271 272 key.bits.target = sp_texture->base.target; 273 key.bits.is_pot = sp_texture->pot; 274 key.bits.processor = processor; 275 key.bits.unit = unit; 276 key.bits.swizzle_r = view->swizzle_r; 277 key.bits.swizzle_g = view->swizzle_g; 278 key.bits.swizzle_b = view->swizzle_b; 279 key.bits.swizzle_a = view->swizzle_a; 280 key.bits.pad = 0; 281 282 if (sampler->current && 283 key.value == sampler->current->key.value) { 284 v = sampler->current; 285 } 286 287 if (v == NULL) { 288 for (v = sampler->variants; v; v = v->next) 289 if (v->key.value == key.value) 290 break; 291 292 if (v == NULL) { 293 v = sp_create_sampler_variant( &sampler->base, key ); 294 v->next = sampler->variants; 295 sampler->variants = v; 296 } 297 } 298 299 sampler->current = v; 300 return v; 301 } 302 303 304 /** 305 * Reset the sampler variants for a shader stage (vert, frag, geom). 306 */ 307 static void 308 reset_sampler_variants(struct softpipe_context *softpipe, 309 unsigned shader, 310 unsigned tgsi_shader, 311 int max_sampler) 312 { 313 int i; 314 315 for (i = 0; i <= max_sampler; i++) { 316 if (softpipe->samplers[shader][i]) { 317 softpipe->tgsi.samplers_list[shader][i] = 318 get_sampler_variant(i, 319 sp_sampler(softpipe->samplers[shader][i]), 320 softpipe->sampler_views[shader][i], 321 tgsi_shader); 322 323 sp_sampler_variant_bind_view(softpipe->tgsi.samplers_list[shader][i], 324 softpipe->tex_cache[shader][i], 325 softpipe->sampler_views[shader][i]); 326 } 327 } 328 } 329 330 331 void 332 softpipe_reset_sampler_variants(struct softpipe_context *softpipe) 333 { 334 /* It's a bit hard to build these samplers ahead of time -- don't 335 * really know which samplers are going to be used for vertex and 336 * fragment programs. 337 */ 338 339 /* XXX note: PIPE_SHADER_x != TGSI_PROCESSOR_x (fix that someday) */ 340 reset_sampler_variants(softpipe, 341 PIPE_SHADER_VERTEX, 342 TGSI_PROCESSOR_VERTEX, 343 softpipe->vs->max_sampler); 344 345 reset_sampler_variants(softpipe, 346 PIPE_SHADER_FRAGMENT, 347 TGSI_PROCESSOR_FRAGMENT, 348 softpipe->fs_variant->info.file_max[TGSI_FILE_SAMPLER]); 349 350 if (softpipe->gs) { 351 reset_sampler_variants(softpipe, 352 PIPE_SHADER_GEOMETRY, 353 TGSI_PROCESSOR_GEOMETRY, 354 softpipe->gs->max_sampler); 355 } 356 } 357 358 359 static void 360 softpipe_delete_sampler_state(struct pipe_context *pipe, 361 void *sampler) 362 { 363 struct sp_sampler *sp_sampler = (struct sp_sampler *)sampler; 364 struct sp_sampler_variant *v, *tmp; 365 366 for (v = sp_sampler->variants; v; v = tmp) { 367 tmp = v->next; 368 sp_sampler_variant_destroy(v); 369 } 370 371 FREE( sampler ); 372 } 373 374 375 void 376 softpipe_init_sampler_funcs(struct pipe_context *pipe) 377 { 378 pipe->create_sampler_state = softpipe_create_sampler_state; 379 pipe->bind_fragment_sampler_states = softpipe_bind_fragment_sampler_states; 380 pipe->bind_vertex_sampler_states = softpipe_bind_vertex_sampler_states; 381 pipe->bind_geometry_sampler_states = softpipe_bind_geometry_sampler_states; 382 pipe->delete_sampler_state = softpipe_delete_sampler_state; 383 384 pipe->set_fragment_sampler_views = softpipe_set_fragment_sampler_views; 385 pipe->set_vertex_sampler_views = softpipe_set_vertex_sampler_views; 386 pipe->set_geometry_sampler_views = softpipe_set_geometry_sampler_views; 387 388 pipe->create_sampler_view = softpipe_create_sampler_view; 389 pipe->sampler_view_destroy = softpipe_sampler_view_destroy; 390 } 391 392