shaders_cache.c revision 2d8e70fcd57b23786e3f4196f35440ed1861a98b
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 "util/u_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 * 127combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders, 128 struct pipe_context *pipe, 129 struct pipe_shader_state *shader) 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, current_shader = 0; 136 VGint num_consts, num_temps, num_samplers; 137 struct ureg_program *ureg; 138 struct ureg_src in[2]; 139 struct ureg_src *sampler = NULL; 140 struct ureg_src *constant = NULL; 141 struct ureg_dst out, *temp = NULL; 142 void *p = NULL; 143 144 for (i = 0; i < num_shaders; ++i) { 145 if (shaders[i]->num_consts) 146 start_const = range_min(start_const, shaders[i]->start_const); 147 if (shaders[i]->num_temps) 148 start_temp = range_min(start_temp, shaders[i]->start_temp); 149 if (shaders[i]->num_samplers) 150 start_sampler = range_min(start_sampler, shaders[i]->start_sampler); 151 152 end_const = range_max(end_const, shaders[i]->start_const + 153 shaders[i]->num_consts); 154 end_temp = range_max(end_temp, shaders[i]->start_temp + 155 shaders[i]->num_temps); 156 end_sampler = range_max(end_sampler, shaders[i]->start_sampler + 157 shaders[i]->num_samplers); 158 if (shaders[i]->needs_position) 159 declare_input = VG_TRUE; 160 } 161 /* if they're still unitialized, initialize them */ 162 if (start_const < 0) 163 start_const = 0; 164 if (start_temp < 0) 165 start_temp = 0; 166 if (start_sampler < 0) 167 start_sampler = 0; 168 169 num_consts = end_const - start_const; 170 num_temps = end_temp - start_temp; 171 num_samplers = end_sampler - start_sampler; 172 173 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); 174 if (!ureg) 175 return NULL; 176 177 if (declare_input) { 178 in[0] = ureg_DECL_fs_input(ureg, 179 TGSI_SEMANTIC_POSITION, 180 0, 181 TGSI_INTERPOLATE_LINEAR); 182 in[1] = ureg_DECL_fs_input(ureg, 183 TGSI_SEMANTIC_GENERIC, 184 0, 185 TGSI_INTERPOLATE_PERSPECTIVE); 186 } 187 188 /* we always have a color output */ 189 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); 190 191 if (num_consts >= 1) { 192 constant = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_const); 193 for (i = start_const; i < end_const; i++) { 194 constant[i] = ureg_DECL_constant(ureg, i); 195 } 196 197 } 198 199 if (num_temps >= 1) { 200 temp = (struct ureg_dst *) malloc(sizeof(struct ureg_dst) * end_temp); 201 for (i = start_temp; i < end_temp; i++) { 202 temp[i] = ureg_DECL_temporary(ureg); 203 } 204 } 205 206 if (num_samplers >= 1) { 207 sampler = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_sampler); 208 for (i = start_sampler; i < end_sampler; i++) { 209 sampler[i] = ureg_DECL_sampler(ureg, i); 210 } 211 } 212 213 while (current_shader < num_shaders) { 214 if ((current_shader + 1) == num_shaders) { 215 shaders[current_shader]->func(ureg, 216 &out, 217 in, 218 sampler, 219 temp, 220 constant); 221 } else { 222 shaders[current_shader]->func(ureg, 223 &temp[0], 224 in, 225 sampler, 226 temp, 227 constant); 228 } 229 current_shader++; 230 } 231 232 ureg_END(ureg); 233 234 shader->tokens = ureg_finalize(ureg); 235 if(!shader->tokens) 236 return NULL; 237 238 p = pipe->create_fs_state(pipe, shader); 239 ureg_destroy(ureg); 240 241 if (num_temps >= 1) { 242 for (i = start_temp; i < end_temp; i++) { 243 ureg_release_temporary(ureg, temp[i]); 244 } 245 } 246 247 if (temp) 248 free(temp); 249 if (constant) 250 free(constant); 251 if (sampler) 252 free(sampler); 253 254 return p; 255} 256 257static void * 258create_shader(struct pipe_context *pipe, 259 int id, 260 struct pipe_shader_state *shader) 261{ 262 int idx = 0; 263 const struct shader_asm_info * shaders[SHADER_STAGES]; 264 265 /* the shader has to have a fill */ 266 debug_assert(id & ALL_FILLS); 267 268 /* first stage */ 269 if (id & VEGA_SOLID_FILL_SHADER) { 270 debug_assert(idx == 0); 271 shaders[idx] = &shaders_asm[0]; 272 debug_assert(shaders_asm[0].id == VEGA_SOLID_FILL_SHADER); 273 ++idx; 274 } 275 if ((id & VEGA_LINEAR_GRADIENT_SHADER)) { 276 debug_assert(idx == 0); 277 shaders[idx] = &shaders_asm[1]; 278 debug_assert(shaders_asm[1].id == VEGA_LINEAR_GRADIENT_SHADER); 279 ++idx; 280 } 281 if ((id & VEGA_RADIAL_GRADIENT_SHADER)) { 282 debug_assert(idx == 0); 283 shaders[idx] = &shaders_asm[2]; 284 debug_assert(shaders_asm[2].id == VEGA_RADIAL_GRADIENT_SHADER); 285 ++idx; 286 } 287 if ((id & VEGA_PATTERN_SHADER)) { 288 debug_assert(idx == 0); 289 debug_assert(shaders_asm[3].id == VEGA_PATTERN_SHADER); 290 shaders[idx] = &shaders_asm[3]; 291 ++idx; 292 } 293 if ((id & VEGA_IMAGE_NORMAL_SHADER)) { 294 debug_assert(idx == 0); 295 debug_assert(shaders_asm[4].id == VEGA_IMAGE_NORMAL_SHADER); 296 shaders[idx] = &shaders_asm[4]; 297 ++idx; 298 } 299 300 /* second stage */ 301 if ((id & VEGA_IMAGE_MULTIPLY_SHADER)) { 302 debug_assert(shaders_asm[5].id == VEGA_IMAGE_MULTIPLY_SHADER); 303 shaders[idx] = &shaders_asm[5]; 304 ++idx; 305 } else if ((id & VEGA_IMAGE_STENCIL_SHADER)) { 306 debug_assert(shaders_asm[6].id == VEGA_IMAGE_STENCIL_SHADER); 307 shaders[idx] = &shaders_asm[6]; 308 ++idx; 309 } 310 311 /* third stage */ 312 if ((id & VEGA_MASK_SHADER)) { 313 debug_assert(idx == 1); 314 debug_assert(shaders_asm[7].id == VEGA_MASK_SHADER); 315 shaders[idx] = &shaders_asm[7]; 316 ++idx; 317 } 318 319 /* fourth stage */ 320 if ((id & VEGA_BLEND_MULTIPLY_SHADER)) { 321 debug_assert(shaders_asm[8].id == VEGA_BLEND_MULTIPLY_SHADER); 322 shaders[idx] = &shaders_asm[8]; 323 ++idx; 324 } else if ((id & VEGA_BLEND_SCREEN_SHADER)) { 325 debug_assert(shaders_asm[9].id == VEGA_BLEND_SCREEN_SHADER); 326 shaders[idx] = &shaders_asm[9]; 327 ++idx; 328 } else if ((id & VEGA_BLEND_DARKEN_SHADER)) { 329 debug_assert(shaders_asm[10].id == VEGA_BLEND_DARKEN_SHADER); 330 shaders[idx] = &shaders_asm[10]; 331 ++idx; 332 } else if ((id & VEGA_BLEND_LIGHTEN_SHADER)) { 333 debug_assert(shaders_asm[11].id == VEGA_BLEND_LIGHTEN_SHADER); 334 shaders[idx] = &shaders_asm[11]; 335 ++idx; 336 } 337 338 /* fifth stage */ 339 if ((id & VEGA_PREMULTIPLY_SHADER)) { 340 debug_assert(shaders_asm[12].id == VEGA_PREMULTIPLY_SHADER); 341 shaders[idx] = &shaders_asm[12]; 342 ++idx; 343 } else if ((id & VEGA_UNPREMULTIPLY_SHADER)) { 344 debug_assert(shaders_asm[13].id == VEGA_UNPREMULTIPLY_SHADER); 345 shaders[idx] = &shaders_asm[13]; 346 ++idx; 347 } 348 349 /* sixth stage */ 350 if ((id & VEGA_BW_SHADER)) { 351 debug_assert(shaders_asm[14].id == VEGA_BW_SHADER); 352 shaders[idx] = &shaders_asm[14]; 353 ++idx; 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