shaders_cache.c revision 5285de7c0fc067dc036a5b421140a696ce2cabbf
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_inlines.h" 34#include "pipe/p_screen.h" 35#include "pipe/p_shader_tokens.h" 36 37#include "tgsi/tgsi_build.h" 38#include "tgsi/tgsi_dump.h" 39#include "tgsi/tgsi_parse.h" 40#include "tgsi/tgsi_util.h" 41#include "tgsi/tgsi_text.h" 42 43#include "util/u_memory.h" 44#include "util/u_math.h" 45#include "util/u_debug.h" 46#include "cso_cache/cso_hash.h" 47#include "cso_cache/cso_context.h" 48 49#include "VG/openvg.h" 50 51#include "asm_fill.h" 52 53/* Essentially we construct an ubber-shader based on the state 54 * of the pipeline. The stages are: 55 * 1) Fill (mandatory, solid color/gradient/pattern/image draw) 56 * 2) Image composition (image mode multiply and stencil) 57 * 3) Mask 58 * 4) Extended blend (multiply/screen/darken/lighten) 59 * 5) Premultiply/Unpremultiply 60 * 6) Color transform (to black and white) 61 */ 62#define SHADER_STAGES 6 63 64struct cached_shader { 65 void *driver_shader; 66 struct pipe_shader_state state; 67}; 68 69struct shaders_cache { 70 struct vg_context *pipe; 71 72 struct cso_hash *hash; 73}; 74 75 76static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens) 77{ 78 struct tgsi_token *tokens; 79 80 tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0])); 81 82 tgsi_text_translate(txt, tokens, num_tokens); 83 84#if DEBUG_SHADERS 85 tgsi_dump(tokens, 0); 86#endif 87 88 return tokens; 89} 90 91#define ALL_FILLS (VEGA_SOLID_FILL_SHADER | \ 92 VEGA_LINEAR_GRADIENT_SHADER | \ 93 VEGA_RADIAL_GRADIENT_SHADER | \ 94 VEGA_PATTERN_SHADER | \ 95 VEGA_IMAGE_NORMAL_SHADER) 96 97 98/* 99static const char max_shader_preamble[] = 100 "FRAG\n" 101 "DCL IN[0], POSITION, LINEAR\n" 102 "DCL IN[1], GENERIC[0], PERSPECTIVE\n" 103 "DCL OUT[0], COLOR, CONSTANT\n" 104 "DCL CONST[0..9], CONSTANT\n" 105 "DCL TEMP[0..9], CONSTANT\n" 106 "DCL SAMP[0..9], CONSTANT\n"; 107 108 max_shader_preamble strlen == 175 109*/ 110#define MAX_PREAMBLE 175 111 112static INLINE VGint range_min(VGint min, VGint current) 113{ 114 if (min < 0) 115 min = current; 116 else 117 min = MIN2(min, current); 118 return min; 119} 120 121static INLINE VGint range_max(VGint max, VGint current) 122{ 123 return MAX2(max, current); 124} 125 126static void 127create_preamble(char *txt, 128 const struct shader_asm_info *shaders[SHADER_STAGES], 129 int num_shaders) 130{ 131 VGboolean declare_input = VG_FALSE; 132 VGint start_const = -1, end_const = 0; 133 VGint start_temp = -1, end_temp = 0; 134 VGint start_sampler = -1, end_sampler = 0; 135 VGint i; 136 VGint num_consts, num_temps, num_samplers; 137 138 for (i = 0; i < num_shaders; ++i) { 139 if (shaders[i]->num_consts) 140 start_const = range_min(start_const, shaders[i]->start_const); 141 if (shaders[i]->num_temps) 142 start_temp = range_min(start_temp, shaders[i]->start_temp); 143 if (shaders[i]->num_samplers) 144 start_sampler = range_min(start_sampler, shaders[i]->start_sampler); 145 146 end_const = range_max(end_const, shaders[i]->start_const + 147 shaders[i]->num_consts); 148 end_temp = range_max(end_temp, shaders[i]->start_temp + 149 shaders[i]->num_temps); 150 end_sampler = range_max(end_sampler, shaders[i]->start_sampler + 151 shaders[i]->num_samplers); 152 if (shaders[i]->needs_position) 153 declare_input = VG_TRUE; 154 } 155 /* if they're still unitialized, initialize them */ 156 if (start_const < 0) 157 start_const = 0; 158 if (start_temp < 0) 159 start_temp = 0; 160 if (start_sampler < 0) 161 start_sampler = 0; 162 163 num_consts = end_const - start_const; 164 num_temps = end_temp - start_temp; 165 num_samplers = end_sampler - start_sampler; 166 /* end exclusive */ 167 --end_const; 168 --end_temp; 169 --end_sampler; 170 171 sprintf(txt, "FRAG\n"); 172 173 if (declare_input) { 174 sprintf(txt + strlen(txt), "DCL IN[0], POSITION, LINEAR\n"); 175 sprintf(txt + strlen(txt), "DCL IN[1], GENERIC[0], PERSPECTIVE\n"); 176 } 177 178 /* we always have a color output */ 179 sprintf(txt + strlen(txt), "DCL OUT[0], COLOR, CONSTANT\n"); 180 181 if (num_consts > 1) 182 sprintf(txt + strlen(txt), "DCL CONST[%d..%d], CONSTANT\n", start_const, end_const); 183 else if (num_consts == 1) 184 sprintf(txt + strlen(txt), "DCL CONST[%d], CONSTANT\n", start_const); 185 186 if (num_temps > 1) 187 sprintf(txt + strlen(txt), "DCL TEMP[%d..%d], CONSTANT\n", start_temp, end_temp); 188 else if (num_temps > 1) 189 sprintf(txt + strlen(txt), "DCL TEMP[%d], CONSTANT\n", start_temp); 190 191 if (num_samplers > 1) 192 sprintf(txt + strlen(txt), "DCL SAMP[%d..%d], CONSTANT\n", start_sampler, end_sampler); 193 else if (num_samplers == 1) 194 sprintf(txt + strlen(txt), "DCL SAMP[%d], CONSTANT\n", start_sampler); 195} 196 197static void * 198combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders, 199 struct pipe_context *pipe, 200 struct pipe_shader_state *shader) 201{ 202 char *combined_txt; 203 int combined_len = MAX_PREAMBLE; 204 int combined_tokens = 0; 205 int i = 0; 206 int current_shader = 0; 207 int current_len; 208 209 for (i = 0; i < num_shaders; ++i) { 210 combined_len += strlen(shaders[i]->txt); 211 combined_tokens += shaders[i]->num_tokens; 212 } 213 /* add for the %s->TEMP[0] substitutions */ 214 combined_len += num_shaders * 7 /*TEMP[0]*/ + 4 /*"END\n"*/; 215 216 combined_txt = (char*)malloc(combined_len); 217 combined_txt[0] = '\0'; 218 219 create_preamble(combined_txt, shaders, num_shaders); 220 221 while (current_shader < num_shaders) { 222 const char temp[] = "TEMP[0]"; 223 const char out[] = "OUT[0]"; 224 const char *subst = temp; 225 226 current_len = strlen(combined_txt); 227 228 /* if the last shader then output */ 229 if (current_shader + 1 == num_shaders) 230 subst = out; 231 232 snprintf(combined_txt + current_len, 233 combined_len - current_len, 234 shaders[current_shader]->txt, 235 subst); 236 ++current_shader; 237 } 238 239 240 current_len = strlen(combined_txt); 241 snprintf(combined_txt + current_len, 242 combined_len - current_len, 243 "END\n"); 244 245 debug_printf("Combined shader is : \n%s\n", 246 combined_txt); 247 248 shader->tokens = tokens_from_assembly( 249 combined_txt, combined_tokens); 250 251 free(combined_txt); 252 253 return pipe->create_fs_state(pipe, shader); 254} 255 256static void * 257create_shader(struct pipe_context *pipe, 258 int id, 259 struct pipe_shader_state *shader) 260{ 261 int idx = 0; 262 const struct shader_asm_info * shaders[SHADER_STAGES]; 263 264 /* the shader has to have a fill */ 265 debug_assert(id & ALL_FILLS); 266 267 /* first stage */ 268 if (id & VEGA_SOLID_FILL_SHADER) { 269 debug_assert(idx == 0); 270 shaders[idx] = &shaders_asm[0]; 271 debug_assert(shaders_asm[0].id == VEGA_SOLID_FILL_SHADER); 272 ++idx; 273 } 274 if ((id & VEGA_LINEAR_GRADIENT_SHADER)) { 275 debug_assert(idx == 0); 276 shaders[idx] = &shaders_asm[1]; 277 debug_assert(shaders_asm[1].id == VEGA_LINEAR_GRADIENT_SHADER); 278 ++idx; 279 } 280 if ((id & VEGA_RADIAL_GRADIENT_SHADER)) { 281 debug_assert(idx == 0); 282 shaders[idx] = &shaders_asm[2]; 283 debug_assert(shaders_asm[2].id == VEGA_RADIAL_GRADIENT_SHADER); 284 ++idx; 285 } 286 if ((id & VEGA_PATTERN_SHADER)) { 287 debug_assert(idx == 0); 288 debug_assert(shaders_asm[3].id == VEGA_PATTERN_SHADER); 289 shaders[idx] = &shaders_asm[3]; 290 ++idx; 291 } 292 if ((id & VEGA_IMAGE_NORMAL_SHADER)) { 293 debug_assert(idx == 0); 294 debug_assert(shaders_asm[4].id == VEGA_IMAGE_NORMAL_SHADER); 295 shaders[idx] = &shaders_asm[4]; 296 ++idx; 297 } 298 299 /* second stage */ 300 if ((id & VEGA_IMAGE_MULTIPLY_SHADER)) { 301 debug_assert(shaders_asm[5].id == VEGA_IMAGE_MULTIPLY_SHADER); 302 shaders[idx] = &shaders_asm[5]; 303 ++idx; 304 } else if ((id & VEGA_IMAGE_STENCIL_SHADER)) { 305 debug_assert(shaders_asm[6].id == VEGA_IMAGE_STENCIL_SHADER); 306 shaders[idx] = &shaders_asm[6]; 307 ++idx; 308 } 309 310 /* third stage */ 311 if ((id & VEGA_MASK_SHADER)) { 312 debug_assert(idx == 1); 313 debug_assert(shaders_asm[7].id == VEGA_MASK_SHADER); 314 shaders[idx] = &shaders_asm[7]; 315 ++idx; 316 } 317 318 /* fourth stage */ 319 if ((id & VEGA_BLEND_MULTIPLY_SHADER)) { 320 debug_assert(shaders_asm[8].id == VEGA_BLEND_MULTIPLY_SHADER); 321 shaders[idx] = &shaders_asm[8]; 322 ++idx; 323 } else if ((id & VEGA_BLEND_SCREEN_SHADER)) { 324 debug_assert(shaders_asm[9].id == VEGA_BLEND_SCREEN_SHADER); 325 shaders[idx] = &shaders_asm[9]; 326 ++idx; 327 } else if ((id & VEGA_BLEND_DARKEN_SHADER)) { 328 debug_assert(shaders_asm[10].id == VEGA_BLEND_DARKEN_SHADER); 329 shaders[idx] = &shaders_asm[10]; 330 ++idx; 331 } else if ((id & VEGA_BLEND_LIGHTEN_SHADER)) { 332 debug_assert(shaders_asm[11].id == VEGA_BLEND_LIGHTEN_SHADER); 333 shaders[idx] = &shaders_asm[11]; 334 ++idx; 335 } 336 337 /* fifth stage */ 338 if ((id & VEGA_PREMULTIPLY_SHADER)) { 339 debug_assert(shaders_asm[12].id == VEGA_PREMULTIPLY_SHADER); 340 shaders[idx] = &shaders_asm[12]; 341 ++idx; 342 } else if ((id & VEGA_UNPREMULTIPLY_SHADER)) { 343 debug_assert(shaders_asm[13].id == VEGA_UNPREMULTIPLY_SHADER); 344 shaders[idx] = &shaders_asm[13]; 345 ++idx; 346 } 347 348 /* sixth stage */ 349 if ((id & VEGA_BW_SHADER)) { 350 debug_assert(shaders_asm[14].id == VEGA_BW_SHADER); 351 shaders[idx] = &shaders_asm[14]; 352 ++idx; 353 } 354 355 return combine_shaders(shaders, idx, pipe, shader); 356} 357 358/*************************************************/ 359 360struct shaders_cache * shaders_cache_create(struct vg_context *vg) 361{ 362 struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache); 363 364 sc->pipe = vg; 365 sc->hash = cso_hash_create(); 366 367 return sc; 368} 369 370void shaders_cache_destroy(struct shaders_cache *sc) 371{ 372 struct cso_hash_iter iter = cso_hash_first_node(sc->hash); 373 374 while (!cso_hash_iter_is_null(iter)) { 375 struct cached_shader *cached = 376 (struct cached_shader *)cso_hash_iter_data(iter); 377 cso_delete_fragment_shader(sc->pipe->cso_context, 378 cached->driver_shader); 379 iter = cso_hash_erase(sc->hash, iter); 380 } 381 382 cso_hash_delete(sc->hash); 383 free(sc); 384} 385 386void * shaders_cache_fill(struct shaders_cache *sc, 387 int shader_key) 388{ 389 VGint key = shader_key; 390 struct cached_shader *cached; 391 struct cso_hash_iter iter = cso_hash_find(sc->hash, key); 392 393 if (cso_hash_iter_is_null(iter)) { 394 cached = CALLOC_STRUCT(cached_shader); 395 cached->driver_shader = create_shader(sc->pipe->pipe, key, &cached->state); 396 397 cso_hash_insert(sc->hash, key, cached); 398 399 return cached->driver_shader; 400 } 401 402 cached = (struct cached_shader *)cso_hash_iter_data(iter); 403 404 assert(cached->driver_shader); 405 return cached->driver_shader; 406} 407 408struct vg_shader * shader_create_from_text(struct pipe_context *pipe, 409 const char *txt, int num_tokens, 410 int type) 411{ 412 struct vg_shader *shader = (struct vg_shader *)malloc( 413 sizeof(struct vg_shader)); 414 struct tgsi_token *tokens = tokens_from_assembly(txt, num_tokens); 415 struct pipe_shader_state state; 416 417 debug_assert(type == PIPE_SHADER_VERTEX || 418 type == PIPE_SHADER_FRAGMENT); 419 420 state.tokens = tokens; 421 shader->type = type; 422 shader->tokens = tokens; 423 424 if (type == PIPE_SHADER_FRAGMENT) 425 shader->driver = pipe->create_fs_state(pipe, &state); 426 else 427 shader->driver = pipe->create_vs_state(pipe, &state); 428 return shader; 429} 430 431void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader) 432{ 433 if (shader->type == PIPE_SHADER_FRAGMENT) 434 cso_delete_fragment_shader(ctx->cso_context, shader->driver); 435 else 436 cso_delete_vertex_shader(ctx->cso_context, shader->driver); 437 free(shader->tokens); 438 free(shader); 439} 440