shaders_cache.c revision a19eaaa6c1956add5343295af7e9f682efa08d74
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) Paint generation (color/gradient/pattern) 54 * 2) Image composition (normal/multiply/stencil) 55 * 3) Color transform 56 * 4) Extended blend (multiply/screen/darken/lighten) 57 * 5) Mask 58 * 6) Premultiply/Unpremultiply 59 * 7) Color transform (to black and white) 60 */ 61#define SHADER_STAGES 7 62 63struct cached_shader { 64 void *driver_shader; 65 struct pipe_shader_state state; 66}; 67 68struct shaders_cache { 69 struct vg_context *pipe; 70 71 struct cso_hash *hash; 72}; 73 74 75static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens) 76{ 77 struct tgsi_token *tokens; 78 79 tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0])); 80 81 tgsi_text_translate(txt, tokens, num_tokens); 82 83#if DEBUG_SHADERS 84 tgsi_dump(tokens, 0); 85#endif 86 87 return tokens; 88} 89 90/* 91static const char max_shader_preamble[] = 92 "FRAG\n" 93 "DCL IN[0], POSITION, LINEAR\n" 94 "DCL IN[1], GENERIC[0], PERSPECTIVE\n" 95 "DCL OUT[0], COLOR, CONSTANT\n" 96 "DCL CONST[0..9], CONSTANT\n" 97 "DCL TEMP[0..9], CONSTANT\n" 98 "DCL SAMP[0..9], CONSTANT\n"; 99 100 max_shader_preamble strlen == 175 101*/ 102#define MAX_PREAMBLE 175 103 104static INLINE VGint range_min(VGint min, VGint current) 105{ 106 if (min < 0) 107 min = current; 108 else 109 min = MIN2(min, current); 110 return min; 111} 112 113static INLINE VGint range_max(VGint max, VGint current) 114{ 115 return MAX2(max, current); 116} 117 118static void * 119combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders, 120 struct pipe_context *pipe, 121 struct pipe_shader_state *shader) 122{ 123 VGboolean declare_input = VG_FALSE; 124 VGint start_const = -1, end_const = 0; 125 VGint start_temp = -1, end_temp = 0; 126 VGint start_sampler = -1, end_sampler = 0; 127 VGint i, current_shader = 0; 128 VGint num_consts, num_temps, num_samplers; 129 struct ureg_program *ureg; 130 struct ureg_src in[2]; 131 struct ureg_src *sampler = NULL; 132 struct ureg_src *constant = NULL; 133 struct ureg_dst out, *temp = NULL; 134 void *p = NULL; 135 136 for (i = 0; i < num_shaders; ++i) { 137 if (shaders[i]->num_consts) 138 start_const = range_min(start_const, shaders[i]->start_const); 139 if (shaders[i]->num_temps) 140 start_temp = range_min(start_temp, shaders[i]->start_temp); 141 if (shaders[i]->num_samplers) 142 start_sampler = range_min(start_sampler, shaders[i]->start_sampler); 143 144 end_const = range_max(end_const, shaders[i]->start_const + 145 shaders[i]->num_consts); 146 end_temp = range_max(end_temp, shaders[i]->start_temp + 147 shaders[i]->num_temps); 148 end_sampler = range_max(end_sampler, shaders[i]->start_sampler + 149 shaders[i]->num_samplers); 150 if (shaders[i]->needs_position) 151 declare_input = VG_TRUE; 152 } 153 /* if they're still unitialized, initialize them */ 154 if (start_const < 0) 155 start_const = 0; 156 if (start_temp < 0) 157 start_temp = 0; 158 if (start_sampler < 0) 159 start_sampler = 0; 160 161 num_consts = end_const - start_const; 162 num_temps = end_temp - start_temp; 163 num_samplers = end_sampler - start_sampler; 164 165 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); 166 if (!ureg) 167 return NULL; 168 169 if (declare_input) { 170 in[0] = ureg_DECL_fs_input(ureg, 171 TGSI_SEMANTIC_POSITION, 172 0, 173 TGSI_INTERPOLATE_LINEAR); 174 in[1] = ureg_DECL_fs_input(ureg, 175 TGSI_SEMANTIC_GENERIC, 176 0, 177 TGSI_INTERPOLATE_PERSPECTIVE); 178 } 179 180 /* we always have a color output */ 181 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); 182 183 if (num_consts >= 1) { 184 constant = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_const); 185 for (i = start_const; i < end_const; i++) { 186 constant[i] = ureg_DECL_constant(ureg, i); 187 } 188 189 } 190 191 if (num_temps >= 1) { 192 temp = (struct ureg_dst *) malloc(sizeof(struct ureg_dst) * end_temp); 193 for (i = start_temp; i < end_temp; i++) { 194 temp[i] = ureg_DECL_temporary(ureg); 195 } 196 } 197 198 if (num_samplers >= 1) { 199 sampler = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_sampler); 200 for (i = start_sampler; i < end_sampler; i++) { 201 sampler[i] = ureg_DECL_sampler(ureg, i); 202 } 203 } 204 205 while (current_shader < num_shaders) { 206 if ((current_shader + 1) == num_shaders) { 207 shaders[current_shader]->func(ureg, 208 &out, 209 in, 210 sampler, 211 temp, 212 constant); 213 } else { 214 shaders[current_shader]->func(ureg, 215 &temp[0], 216 in, 217 sampler, 218 temp, 219 constant); 220 } 221 current_shader++; 222 } 223 224 ureg_END(ureg); 225 226 shader->tokens = ureg_finalize(ureg); 227 if(!shader->tokens) 228 return NULL; 229 230 p = pipe->create_fs_state(pipe, shader); 231 ureg_destroy(ureg); 232 233 if (num_temps >= 1) { 234 for (i = start_temp; i < end_temp; i++) { 235 ureg_release_temporary(ureg, temp[i]); 236 } 237 } 238 239 if (temp) 240 free(temp); 241 if (constant) 242 free(constant); 243 if (sampler) 244 free(sampler); 245 246 return p; 247} 248 249static void * 250create_shader(struct pipe_context *pipe, 251 int id, 252 struct pipe_shader_state *shader) 253{ 254 int idx = 0, sh; 255 const struct shader_asm_info * shaders[SHADER_STAGES]; 256 257 /* first stage */ 258 sh = SHADERS_GET_PAINT_SHADER(id); 259 switch (sh << SHADERS_PAINT_SHIFT) { 260 case VEGA_SOLID_FILL_SHADER: 261 case VEGA_LINEAR_GRADIENT_SHADER: 262 case VEGA_RADIAL_GRADIENT_SHADER: 263 case VEGA_PATTERN_SHADER: 264 case VEGA_PAINT_DEGENERATE_SHADER: 265 shaders[idx] = &shaders_paint_asm[(sh >> SHADERS_PAINT_SHIFT) - 1]; 266 assert(shaders[idx]->id == sh); 267 idx++; 268 break; 269 default: 270 break; 271 } 272 273 /* second stage */ 274 sh = SHADERS_GET_IMAGE_SHADER(id); 275 switch (sh) { 276 case VEGA_IMAGE_NORMAL_SHADER: 277 case VEGA_IMAGE_MULTIPLY_SHADER: 278 case VEGA_IMAGE_STENCIL_SHADER: 279 shaders[idx] = &shaders_image_asm[(sh >> SHADERS_IMAGE_SHIFT) - 1]; 280 assert(shaders[idx]->id == sh); 281 idx++; 282 break; 283 default: 284 break; 285 } 286 287 /* sanity check */ 288 assert(idx == ((!sh || sh == VEGA_IMAGE_NORMAL_SHADER) ? 1 : 2)); 289 290 /* third stage */ 291 sh = SHADERS_GET_COLOR_TRANSFORM_SHADER(id); 292 switch (sh) { 293 case VEGA_COLOR_TRANSFORM_SHADER: 294 shaders[idx] = &shaders_color_transform_asm[ 295 (sh >> SHADERS_COLOR_TRANSFORM_SHIFT) - 1]; 296 assert(shaders[idx]->id == sh); 297 idx++; 298 break; 299 default: 300 break; 301 } 302 303 /* fourth stage */ 304 sh = SHADERS_GET_BLEND_SHADER(id); 305 switch (sh) { 306 case VEGA_BLEND_MULTIPLY_SHADER: 307 case VEGA_BLEND_SCREEN_SHADER: 308 case VEGA_BLEND_DARKEN_SHADER: 309 case VEGA_BLEND_LIGHTEN_SHADER: 310 shaders[idx] = &shaders_blend_asm[(sh >> SHADERS_BLEND_SHIFT) - 1]; 311 assert(shaders[idx]->id == sh); 312 idx++; 313 break; 314 default: 315 break; 316 } 317 318 /* fifth stage */ 319 sh = SHADERS_GET_MASK_SHADER(id); 320 switch (sh) { 321 case VEGA_MASK_SHADER: 322 shaders[idx] = &shaders_mask_asm[(sh >> SHADERS_MASK_SHIFT) - 1]; 323 assert(shaders[idx]->id == sh); 324 idx++; 325 break; 326 default: 327 break; 328 } 329 330 /* sixth stage */ 331 sh = SHADERS_GET_PREMULTIPLY_SHADER(id); 332 switch (sh) { 333 case VEGA_PREMULTIPLY_SHADER: 334 case VEGA_UNPREMULTIPLY_SHADER: 335 shaders[idx] = &shaders_premultiply_asm[ 336 (sh >> SHADERS_PREMULTIPLY_SHIFT) - 1]; 337 assert(shaders[idx]->id == sh); 338 idx++; 339 break; 340 default: 341 break; 342 } 343 344 /* seventh stage */ 345 sh = SHADERS_GET_BW_SHADER(id); 346 switch (sh) { 347 case VEGA_BW_SHADER: 348 shaders[idx] = &shaders_bw_asm[(sh >> SHADERS_BW_SHIFT) - 1]; 349 assert(shaders[idx]->id == sh); 350 idx++; 351 break; 352 default: 353 break; 354 } 355 356 return combine_shaders(shaders, idx, pipe, shader); 357} 358 359/*************************************************/ 360 361struct shaders_cache * shaders_cache_create(struct vg_context *vg) 362{ 363 struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache); 364 365 sc->pipe = vg; 366 sc->hash = cso_hash_create(); 367 368 return sc; 369} 370 371void shaders_cache_destroy(struct shaders_cache *sc) 372{ 373 struct cso_hash_iter iter = cso_hash_first_node(sc->hash); 374 375 while (!cso_hash_iter_is_null(iter)) { 376 struct cached_shader *cached = 377 (struct cached_shader *)cso_hash_iter_data(iter); 378 cso_delete_fragment_shader(sc->pipe->cso_context, 379 cached->driver_shader); 380 iter = cso_hash_erase(sc->hash, iter); 381 } 382 383 cso_hash_delete(sc->hash); 384 FREE(sc); 385} 386 387void * shaders_cache_fill(struct shaders_cache *sc, 388 int shader_key) 389{ 390 VGint key = shader_key; 391 struct cached_shader *cached; 392 struct cso_hash_iter iter = cso_hash_find(sc->hash, key); 393 394 if (cso_hash_iter_is_null(iter)) { 395 cached = CALLOC_STRUCT(cached_shader); 396 cached->driver_shader = create_shader(sc->pipe->pipe, key, &cached->state); 397 398 cso_hash_insert(sc->hash, key, cached); 399 400 return cached->driver_shader; 401 } 402 403 cached = (struct cached_shader *)cso_hash_iter_data(iter); 404 405 assert(cached->driver_shader); 406 return cached->driver_shader; 407} 408 409struct vg_shader * shader_create_from_text(struct pipe_context *pipe, 410 const char *txt, int num_tokens, 411 int type) 412{ 413 struct vg_shader *shader = (struct vg_shader *)MALLOC( 414 sizeof(struct vg_shader)); 415 struct tgsi_token *tokens = tokens_from_assembly(txt, num_tokens); 416 struct pipe_shader_state state; 417 418 debug_assert(type == PIPE_SHADER_VERTEX || 419 type == PIPE_SHADER_FRAGMENT); 420 421 state.tokens = tokens; 422 shader->type = type; 423 shader->tokens = tokens; 424 425 if (type == PIPE_SHADER_FRAGMENT) 426 shader->driver = pipe->create_fs_state(pipe, &state); 427 else 428 shader->driver = pipe->create_vs_state(pipe, &state); 429 return shader; 430} 431 432void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader) 433{ 434 if (shader->type == PIPE_SHADER_FRAGMENT) 435 cso_delete_fragment_shader(ctx->cso_context, shader->driver); 436 else 437 cso_delete_vertex_shader(ctx->cso_context, shader->driver); 438 FREE(shader->tokens); 439 FREE(shader); 440} 441