shaders_cache.c revision e360f91f152615b35857a4d008d0439a3c3285a8
12d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines/************************************************************************** 2effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * 32d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * Copyright 2009 VMware, Inc. All Rights Reserved. 4effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * 52d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * Permission is hereby granted, free of charge, to any person obtaining a 6effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * copy of this software and associated documentation files (the 72d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * "Software"), to deal in the Software without restriction, including 8effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * without limitation the rights to use, copy, modify, merge, publish, 9effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * distribute, sub license, and/or sell copies of the Software, and to 102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * permit persons to whom the Software is furnished to do so, subject to 11effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * the following conditions: 122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * 13effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * The above copyright notice and this permission notice (including the 142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * next paragraph) shall be included in all copies or substantial portions 15effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * of the Software. 162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * 17effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * 252d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines **************************************************************************/ 26effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov 272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "shaders_cache.h" 28effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov 29effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov#include "vg_context.h" 302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "pipe/p_context.h" 32effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov#include "pipe/p_defines.h" 33effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov#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) Mask 57 * 5) Extended blend (multiply/screen/darken/lighten) 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 shaders[idx] = &shaders_paint_asm[(sh >> SHADERS_PAINT_SHIFT) - 1]; 265 assert(shaders[idx]->id == sh); 266 idx++; 267 break; 268 default: 269 break; 270 } 271 272 /* second stage */ 273 sh = SHADERS_GET_IMAGE_SHADER(id); 274 switch (sh) { 275 case VEGA_IMAGE_NORMAL_SHADER: 276 case VEGA_IMAGE_MULTIPLY_SHADER: 277 case VEGA_IMAGE_STENCIL_SHADER: 278 shaders[idx] = &shaders_image_asm[(sh >> SHADERS_IMAGE_SHIFT) - 1]; 279 assert(shaders[idx]->id == sh); 280 idx++; 281 break; 282 default: 283 break; 284 } 285 286 /* sanity check */ 287 assert(idx == ((!sh || sh == VEGA_IMAGE_NORMAL_SHADER) ? 1 : 2)); 288 289 /* third stage */ 290 sh = SHADERS_GET_COLOR_TRANSFORM_SHADER(id); 291 switch (sh) { 292 case VEGA_COLOR_TRANSFORM_SHADER: 293 shaders[idx] = &shaders_color_transform_asm[ 294 (sh >> SHADERS_COLOR_TRANSFORM_SHIFT) - 1]; 295 assert(shaders[idx]->id == sh); 296 idx++; 297 break; 298 default: 299 break; 300 } 301 302 /* fourth stage */ 303 sh = SHADERS_GET_MASK_SHADER(id); 304 switch (sh) { 305 case VEGA_MASK_SHADER: 306 shaders[idx] = &shaders_mask_asm[(sh >> SHADERS_MASK_SHIFT) - 1]; 307 assert(shaders[idx]->id == sh); 308 idx++; 309 break; 310 default: 311 break; 312 } 313 314 /* fifth stage */ 315 sh = SHADERS_GET_BLEND_SHADER(id); 316 switch (sh) { 317 case VEGA_BLEND_MULTIPLY_SHADER: 318 case VEGA_BLEND_SCREEN_SHADER: 319 case VEGA_BLEND_DARKEN_SHADER: 320 case VEGA_BLEND_LIGHTEN_SHADER: 321 shaders[idx] = &shaders_blend_asm[(sh >> SHADERS_BLEND_SHIFT) - 1]; 322 assert(shaders[idx]->id == sh); 323 idx++; 324 break; 325 default: 326 break; 327 } 328 329 /* sixth stage */ 330 sh = SHADERS_GET_PREMULTIPLY_SHADER(id); 331 switch (sh) { 332 case VEGA_PREMULTIPLY_SHADER: 333 case VEGA_UNPREMULTIPLY_SHADER: 334 shaders[idx] = &shaders_premultiply_asm[ 335 (sh >> SHADERS_PREMULTIPLY_SHIFT) - 1]; 336 assert(shaders[idx]->id == sh); 337 idx++; 338 break; 339 default: 340 break; 341 } 342 343 /* seventh stage */ 344 sh = SHADERS_GET_BW_SHADER(id); 345 switch (sh) { 346 case VEGA_BW_SHADER: 347 shaders[idx] = &shaders_bw_asm[(sh >> SHADERS_BW_SHIFT) - 1]; 348 assert(shaders[idx]->id == sh); 349 idx++; 350 break; 351 default: 352 break; 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