shaders_cache.c revision 93a7e6d94e09a25bdbe31eedb0759e390ccb6a86
1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 **************************************************************************/ 26 27#include "shaders_cache.h" 28 29#include "vg_context.h" 30 31#include "pipe/p_context.h" 32#include "pipe/p_defines.h" 33#include "pipe/p_shader_tokens.h" 34 35#include "tgsi/tgsi_build.h" 36#include "tgsi/tgsi_dump.h" 37#include "tgsi/tgsi_parse.h" 38#include "tgsi/tgsi_util.h" 39#include "tgsi/tgsi_text.h" 40 41#include "util/u_memory.h" 42#include "util/u_math.h" 43#include "util/u_debug.h" 44#include "cso_cache/cso_hash.h" 45#include "cso_cache/cso_context.h" 46 47#include "VG/openvg.h" 48 49#include "asm_fill.h" 50 51/* Essentially we construct an ubber-shader based on the state 52 * of the pipeline. The stages are: 53 * 1) Fill (mandatory, solid color/gradient/pattern/image draw) 54 * 2) Image composition (image mode multiply and stencil) 55 * 3) Mask 56 * 4) Extended blend (multiply/screen/darken/lighten) 57 * 5) Premultiply/Unpremultiply 58 * 6) Color transform (to black and white) 59 */ 60#define SHADER_STAGES 6 61 62struct cached_shader { 63 void *driver_shader; 64 struct pipe_shader_state state; 65}; 66 67struct shaders_cache { 68 struct vg_context *pipe; 69 70 struct cso_hash *hash; 71}; 72 73 74static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens) 75{ 76 struct tgsi_token *tokens; 77 78 tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0])); 79 80 tgsi_text_translate(txt, tokens, num_tokens); 81 82#if DEBUG_SHADERS 83 tgsi_dump(tokens, 0); 84#endif 85 86 return tokens; 87} 88 89#define ALL_FILLS (VEGA_SOLID_FILL_SHADER | \ 90 VEGA_LINEAR_GRADIENT_SHADER | \ 91 VEGA_RADIAL_GRADIENT_SHADER | \ 92 VEGA_PATTERN_SHADER | \ 93 VEGA_IMAGE_NORMAL_SHADER) 94 95 96/* 97static const char max_shader_preamble[] = 98 "FRAG\n" 99 "DCL IN[0], POSITION, LINEAR\n" 100 "DCL IN[1], GENERIC[0], PERSPECTIVE\n" 101 "DCL OUT[0], COLOR, CONSTANT\n" 102 "DCL CONST[0..9], CONSTANT\n" 103 "DCL TEMP[0..9], CONSTANT\n" 104 "DCL SAMP[0..9], CONSTANT\n"; 105 106 max_shader_preamble strlen == 175 107*/ 108#define MAX_PREAMBLE 175 109 110static INLINE VGint range_min(VGint min, VGint current) 111{ 112 if (min < 0) 113 min = current; 114 else 115 min = MIN2(min, current); 116 return min; 117} 118 119static INLINE VGint range_max(VGint max, VGint current) 120{ 121 return MAX2(max, current); 122} 123 124static void * 125combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders, 126 struct pipe_context *pipe, 127 struct pipe_shader_state *shader) 128{ 129 VGboolean declare_input = VG_FALSE; 130 VGint start_const = -1, end_const = 0; 131 VGint start_temp = -1, end_temp = 0; 132 VGint start_sampler = -1, end_sampler = 0; 133 VGint i, current_shader = 0; 134 VGint num_consts, num_temps, num_samplers; 135 struct ureg_program *ureg; 136 struct ureg_src in[2]; 137 struct ureg_src *sampler = NULL; 138 struct ureg_src *constant = NULL; 139 struct ureg_dst out, *temp = NULL; 140 void *p = NULL; 141 142 for (i = 0; i < num_shaders; ++i) { 143 if (shaders[i]->num_consts) 144 start_const = range_min(start_const, shaders[i]->start_const); 145 if (shaders[i]->num_temps) 146 start_temp = range_min(start_temp, shaders[i]->start_temp); 147 if (shaders[i]->num_samplers) 148 start_sampler = range_min(start_sampler, shaders[i]->start_sampler); 149 150 end_const = range_max(end_const, shaders[i]->start_const + 151 shaders[i]->num_consts); 152 end_temp = range_max(end_temp, shaders[i]->start_temp + 153 shaders[i]->num_temps); 154 end_sampler = range_max(end_sampler, shaders[i]->start_sampler + 155 shaders[i]->num_samplers); 156 if (shaders[i]->needs_position) 157 declare_input = VG_TRUE; 158 } 159 /* if they're still unitialized, initialize them */ 160 if (start_const < 0) 161 start_const = 0; 162 if (start_temp < 0) 163 start_temp = 0; 164 if (start_sampler < 0) 165 start_sampler = 0; 166 167 num_consts = end_const - start_const; 168 num_temps = end_temp - start_temp; 169 num_samplers = end_sampler - start_sampler; 170 171 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); 172 if (!ureg) 173 return NULL; 174 175 if (declare_input) { 176 in[0] = ureg_DECL_fs_input(ureg, 177 TGSI_SEMANTIC_POSITION, 178 0, 179 TGSI_INTERPOLATE_LINEAR); 180 in[1] = ureg_DECL_fs_input(ureg, 181 TGSI_SEMANTIC_GENERIC, 182 0, 183 TGSI_INTERPOLATE_PERSPECTIVE); 184 } 185 186 /* we always have a color output */ 187 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); 188 189 if (num_consts >= 1) { 190 constant = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_const); 191 for (i = start_const; i < end_const; i++) { 192 constant[i] = ureg_DECL_constant(ureg, i); 193 } 194 195 } 196 197 if (num_temps >= 1) { 198 temp = (struct ureg_dst *) malloc(sizeof(struct ureg_dst) * end_temp); 199 for (i = start_temp; i < end_temp; i++) { 200 temp[i] = ureg_DECL_temporary(ureg); 201 } 202 } 203 204 if (num_samplers >= 1) { 205 sampler = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_sampler); 206 for (i = start_sampler; i < end_sampler; i++) { 207 sampler[i] = ureg_DECL_sampler(ureg, i); 208 } 209 } 210 211 while (current_shader < num_shaders) { 212 if ((current_shader + 1) == num_shaders) { 213 shaders[current_shader]->func(ureg, 214 &out, 215 in, 216 sampler, 217 temp, 218 constant); 219 } else { 220 shaders[current_shader]->func(ureg, 221 &temp[0], 222 in, 223 sampler, 224 temp, 225 constant); 226 } 227 current_shader++; 228 } 229 230 ureg_END(ureg); 231 232 shader->tokens = ureg_finalize(ureg); 233 if(!shader->tokens) 234 return NULL; 235 236 p = pipe->create_fs_state(pipe, shader); 237 ureg_destroy(ureg); 238 239 if (num_temps >= 1) { 240 for (i = start_temp; i < end_temp; i++) { 241 ureg_release_temporary(ureg, temp[i]); 242 } 243 } 244 245 if (temp) 246 free(temp); 247 if (constant) 248 free(constant); 249 if (sampler) 250 free(sampler); 251 252 return p; 253} 254 255static void * 256create_shader(struct pipe_context *pipe, 257 int id, 258 struct pipe_shader_state *shader) 259{ 260 int idx = 0; 261 const struct shader_asm_info * shaders[SHADER_STAGES]; 262 263 /* the shader has to have a fill */ 264 debug_assert(id & ALL_FILLS); 265 266 /* first stage */ 267 if (id & VEGA_SOLID_FILL_SHADER) { 268 debug_assert(idx == 0); 269 shaders[idx] = &shaders_asm[0]; 270 debug_assert(shaders_asm[0].id == VEGA_SOLID_FILL_SHADER); 271 ++idx; 272 } 273 if ((id & VEGA_LINEAR_GRADIENT_SHADER)) { 274 debug_assert(idx == 0); 275 shaders[idx] = &shaders_asm[1]; 276 debug_assert(shaders_asm[1].id == VEGA_LINEAR_GRADIENT_SHADER); 277 ++idx; 278 } 279 if ((id & VEGA_RADIAL_GRADIENT_SHADER)) { 280 debug_assert(idx == 0); 281 shaders[idx] = &shaders_asm[2]; 282 debug_assert(shaders_asm[2].id == VEGA_RADIAL_GRADIENT_SHADER); 283 ++idx; 284 } 285 if ((id & VEGA_PATTERN_SHADER)) { 286 debug_assert(idx == 0); 287 debug_assert(shaders_asm[3].id == VEGA_PATTERN_SHADER); 288 shaders[idx] = &shaders_asm[3]; 289 ++idx; 290 } 291 if ((id & VEGA_IMAGE_NORMAL_SHADER)) { 292 debug_assert(idx == 0); 293 debug_assert(shaders_asm[4].id == VEGA_IMAGE_NORMAL_SHADER); 294 shaders[idx] = &shaders_asm[4]; 295 ++idx; 296 } 297 298 /* second stage */ 299 if ((id & VEGA_IMAGE_MULTIPLY_SHADER)) { 300 debug_assert(shaders_asm[5].id == VEGA_IMAGE_MULTIPLY_SHADER); 301 shaders[idx] = &shaders_asm[5]; 302 ++idx; 303 } else if ((id & VEGA_IMAGE_STENCIL_SHADER)) { 304 debug_assert(shaders_asm[6].id == VEGA_IMAGE_STENCIL_SHADER); 305 shaders[idx] = &shaders_asm[6]; 306 ++idx; 307 } 308 309 /* third stage */ 310 if ((id & VEGA_MASK_SHADER)) { 311 debug_assert(idx == 1); 312 debug_assert(shaders_asm[7].id == VEGA_MASK_SHADER); 313 shaders[idx] = &shaders_asm[7]; 314 ++idx; 315 } 316 317 /* fourth stage */ 318 if ((id & VEGA_BLEND_MULTIPLY_SHADER)) { 319 debug_assert(shaders_asm[8].id == VEGA_BLEND_MULTIPLY_SHADER); 320 shaders[idx] = &shaders_asm[8]; 321 ++idx; 322 } else if ((id & VEGA_BLEND_SCREEN_SHADER)) { 323 debug_assert(shaders_asm[9].id == VEGA_BLEND_SCREEN_SHADER); 324 shaders[idx] = &shaders_asm[9]; 325 ++idx; 326 } else if ((id & VEGA_BLEND_DARKEN_SHADER)) { 327 debug_assert(shaders_asm[10].id == VEGA_BLEND_DARKEN_SHADER); 328 shaders[idx] = &shaders_asm[10]; 329 ++idx; 330 } else if ((id & VEGA_BLEND_LIGHTEN_SHADER)) { 331 debug_assert(shaders_asm[11].id == VEGA_BLEND_LIGHTEN_SHADER); 332 shaders[idx] = &shaders_asm[11]; 333 ++idx; 334 } 335 336 /* fifth stage */ 337 if ((id & VEGA_PREMULTIPLY_SHADER)) { 338 debug_assert(shaders_asm[12].id == VEGA_PREMULTIPLY_SHADER); 339 shaders[idx] = &shaders_asm[12]; 340 ++idx; 341 } else if ((id & VEGA_UNPREMULTIPLY_SHADER)) { 342 debug_assert(shaders_asm[13].id == VEGA_UNPREMULTIPLY_SHADER); 343 shaders[idx] = &shaders_asm[13]; 344 ++idx; 345 } 346 347 /* sixth stage */ 348 if ((id & VEGA_BW_SHADER)) { 349 debug_assert(shaders_asm[14].id == VEGA_BW_SHADER); 350 shaders[idx] = &shaders_asm[14]; 351 ++idx; 352 } 353 354 return combine_shaders(shaders, idx, pipe, shader); 355} 356 357/*************************************************/ 358 359struct shaders_cache * shaders_cache_create(struct vg_context *vg) 360{ 361 struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache); 362 363 sc->pipe = vg; 364 sc->hash = cso_hash_create(); 365 366 return sc; 367} 368 369void shaders_cache_destroy(struct shaders_cache *sc) 370{ 371 struct cso_hash_iter iter = cso_hash_first_node(sc->hash); 372 373 while (!cso_hash_iter_is_null(iter)) { 374 struct cached_shader *cached = 375 (struct cached_shader *)cso_hash_iter_data(iter); 376 cso_delete_fragment_shader(sc->pipe->cso_context, 377 cached->driver_shader); 378 iter = cso_hash_erase(sc->hash, iter); 379 } 380 381 cso_hash_delete(sc->hash); 382 FREE(sc); 383} 384 385void * shaders_cache_fill(struct shaders_cache *sc, 386 int shader_key) 387{ 388 VGint key = shader_key; 389 struct cached_shader *cached; 390 struct cso_hash_iter iter = cso_hash_find(sc->hash, key); 391 392 if (cso_hash_iter_is_null(iter)) { 393 cached = CALLOC_STRUCT(cached_shader); 394 cached->driver_shader = create_shader(sc->pipe->pipe, key, &cached->state); 395 396 cso_hash_insert(sc->hash, key, cached); 397 398 return cached->driver_shader; 399 } 400 401 cached = (struct cached_shader *)cso_hash_iter_data(iter); 402 403 assert(cached->driver_shader); 404 return cached->driver_shader; 405} 406 407struct vg_shader * shader_create_from_text(struct pipe_context *pipe, 408 const char *txt, int num_tokens, 409 int type) 410{ 411 struct vg_shader *shader = (struct vg_shader *)MALLOC( 412 sizeof(struct vg_shader)); 413 struct tgsi_token *tokens = tokens_from_assembly(txt, num_tokens); 414 struct pipe_shader_state state; 415 416 debug_assert(type == PIPE_SHADER_VERTEX || 417 type == PIPE_SHADER_FRAGMENT); 418 419 state.tokens = tokens; 420 shader->type = type; 421 shader->tokens = tokens; 422 423 if (type == PIPE_SHADER_FRAGMENT) 424 shader->driver = pipe->create_fs_state(pipe, &state); 425 else 426 shader->driver = pipe->create_vs_state(pipe, &state); 427 return shader; 428} 429 430void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader) 431{ 432 if (shader->type == PIPE_SHADER_FRAGMENT) 433 cso_delete_fragment_shader(ctx->cso_context, shader->driver); 434 else 435 cso_delete_vertex_shader(ctx->cso_context, shader->driver); 436 FREE(shader->tokens); 437 FREE(shader); 438} 439