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