shaders_cache.c revision 213e288e78bf5b0fb0a996cc17dfd959756c2c53
1be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver/************************************************************************** 2be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 3be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * Copyright 2009 VMware, Inc. All Rights Reserved. 4be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 5be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * Permission is hereby granted, free of charge, to any person obtaining a 6be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * copy of this software and associated documentation files (the 7be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * "Software"), to deal in the Software without restriction, including 8be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * without limitation the rights to use, copy, modify, merge, publish, 9be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * distribute, sub license, and/or sell copies of the Software, and to 10be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * permit persons to whom the Software is furnished to do so, subject to 11be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * the following conditions: 12be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 13be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * The above copyright notice and this permission notice (including the 14be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * next paragraph) shall be included in all copies or substantial portions 15be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * of the Software. 16be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 17be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 21be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 25be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver **************************************************************************/ 26be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 27be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "shaders_cache.h" 28be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 29be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "vg_context.h" 30be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 31be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "pipe/p_context.h" 32be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "pipe/p_defines.h" 33be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "pipe/p_shader_tokens.h" 3484c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver 3536e2ee200517b36652a6e8fe1c5aa24ce249765eBen Gruver#include "tgsi/tgsi_build.h" 36be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "tgsi/tgsi_dump.h" 377c71ad420dbdfe2e36f205d335a261435181a25bBen Gruver#include "tgsi/tgsi_parse.h" 38be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "tgsi/tgsi_util.h" 39be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "tgsi/tgsi_text.h" 408daecd0246fb0d4eb29f53ab4ef99b506d395401Ben Gruver 41be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "util/u_memory.h" 42be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "util/u_math.h" 43be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "util/u_debug.h" 4425d385a441b95d56987c81f00f19297d799e1b31Ben Gruver#include "cso_cache/cso_hash.h" 45be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "cso_cache/cso_context.h" 46be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 47be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "VG/openvg.h" 487c71ad420dbdfe2e36f205d335a261435181a25bBen Gruver 49be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "asm_fill.h" 50be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 518daecd0246fb0d4eb29f53ab4ef99b506d395401Ben Gruver/* Essentially we construct an ubber-shader based on the state 5284c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver * of the pipeline. The stages are: 53be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 1) Paint generation (color/gradient/pattern) 54be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 2) Image composition (normal/multiply/stencil) 55be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 3) Mask 5684c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver * 4) Extended blend (multiply/screen/darken/lighten) 57be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 5) Premultiply/Unpremultiply 58be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 6) Color transform (to black and white) 59be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver */ 6036e2ee200517b36652a6e8fe1c5aa24ce249765eBen Gruver#define SHADER_STAGES 6 61be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 62be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverstruct cached_shader { 63be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver void *driver_shader; 6484c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver struct pipe_shader_state state; 6584c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver}; 66be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 67be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverstruct shaders_cache { 68be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver struct vg_context *pipe; 698daecd0246fb0d4eb29f53ab4ef99b506d395401Ben Gruver 707c71ad420dbdfe2e36f205d335a261435181a25bBen Gruver struct cso_hash *hash; 71be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver}; 72be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 73be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 74be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverstatic INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens) 75be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver{ 76be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver struct tgsi_token *tokens; 77be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 78be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0])); 79be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 80be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver tgsi_text_translate(txt, tokens, num_tokens); 81be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 82be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#if DEBUG_SHADERS 83be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver tgsi_dump(tokens, 0); 84be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#endif 85be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver 86 return tokens; 87} 88 89/* 90static const char max_shader_preamble[] = 91 "FRAG\n" 92 "DCL IN[0], POSITION, LINEAR\n" 93 "DCL IN[1], GENERIC[0], PERSPECTIVE\n" 94 "DCL OUT[0], COLOR, CONSTANT\n" 95 "DCL CONST[0..9], CONSTANT\n" 96 "DCL TEMP[0..9], CONSTANT\n" 97 "DCL SAMP[0..9], CONSTANT\n"; 98 99 max_shader_preamble strlen == 175 100*/ 101#define MAX_PREAMBLE 175 102 103static INLINE VGint range_min(VGint min, VGint current) 104{ 105 if (min < 0) 106 min = current; 107 else 108 min = MIN2(min, current); 109 return min; 110} 111 112static INLINE VGint range_max(VGint max, VGint current) 113{ 114 return MAX2(max, current); 115} 116 117static void * 118combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders, 119 struct pipe_context *pipe, 120 struct pipe_shader_state *shader) 121{ 122 VGboolean declare_input = VG_FALSE; 123 VGint start_const = -1, end_const = 0; 124 VGint start_temp = -1, end_temp = 0; 125 VGint start_sampler = -1, end_sampler = 0; 126 VGint i, current_shader = 0; 127 VGint num_consts, num_temps, num_samplers; 128 struct ureg_program *ureg; 129 struct ureg_src in[2]; 130 struct ureg_src *sampler = NULL; 131 struct ureg_src *constant = NULL; 132 struct ureg_dst out, *temp = NULL; 133 void *p = NULL; 134 135 for (i = 0; i < num_shaders; ++i) { 136 if (shaders[i]->num_consts) 137 start_const = range_min(start_const, shaders[i]->start_const); 138 if (shaders[i]->num_temps) 139 start_temp = range_min(start_temp, shaders[i]->start_temp); 140 if (shaders[i]->num_samplers) 141 start_sampler = range_min(start_sampler, shaders[i]->start_sampler); 142 143 end_const = range_max(end_const, shaders[i]->start_const + 144 shaders[i]->num_consts); 145 end_temp = range_max(end_temp, shaders[i]->start_temp + 146 shaders[i]->num_temps); 147 end_sampler = range_max(end_sampler, shaders[i]->start_sampler + 148 shaders[i]->num_samplers); 149 if (shaders[i]->needs_position) 150 declare_input = VG_TRUE; 151 } 152 /* if they're still unitialized, initialize them */ 153 if (start_const < 0) 154 start_const = 0; 155 if (start_temp < 0) 156 start_temp = 0; 157 if (start_sampler < 0) 158 start_sampler = 0; 159 160 num_consts = end_const - start_const; 161 num_temps = end_temp - start_temp; 162 num_samplers = end_sampler - start_sampler; 163 164 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); 165 if (!ureg) 166 return NULL; 167 168 if (declare_input) { 169 in[0] = ureg_DECL_fs_input(ureg, 170 TGSI_SEMANTIC_POSITION, 171 0, 172 TGSI_INTERPOLATE_LINEAR); 173 in[1] = ureg_DECL_fs_input(ureg, 174 TGSI_SEMANTIC_GENERIC, 175 0, 176 TGSI_INTERPOLATE_PERSPECTIVE); 177 } 178 179 /* we always have a color output */ 180 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); 181 182 if (num_consts >= 1) { 183 constant = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_const); 184 for (i = start_const; i < end_const; i++) { 185 constant[i] = ureg_DECL_constant(ureg, i); 186 } 187 188 } 189 190 if (num_temps >= 1) { 191 temp = (struct ureg_dst *) malloc(sizeof(struct ureg_dst) * end_temp); 192 for (i = start_temp; i < end_temp; i++) { 193 temp[i] = ureg_DECL_temporary(ureg); 194 } 195 } 196 197 if (num_samplers >= 1) { 198 sampler = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_sampler); 199 for (i = start_sampler; i < end_sampler; i++) { 200 sampler[i] = ureg_DECL_sampler(ureg, i); 201 } 202 } 203 204 while (current_shader < num_shaders) { 205 if ((current_shader + 1) == num_shaders) { 206 shaders[current_shader]->func(ureg, 207 &out, 208 in, 209 sampler, 210 temp, 211 constant); 212 } else { 213 shaders[current_shader]->func(ureg, 214 &temp[0], 215 in, 216 sampler, 217 temp, 218 constant); 219 } 220 current_shader++; 221 } 222 223 ureg_END(ureg); 224 225 shader->tokens = ureg_finalize(ureg); 226 if(!shader->tokens) 227 return NULL; 228 229 p = pipe->create_fs_state(pipe, shader); 230 ureg_destroy(ureg); 231 232 if (num_temps >= 1) { 233 for (i = start_temp; i < end_temp; i++) { 234 ureg_release_temporary(ureg, temp[i]); 235 } 236 } 237 238 if (temp) 239 free(temp); 240 if (constant) 241 free(constant); 242 if (sampler) 243 free(sampler); 244 245 return p; 246} 247 248static void * 249create_shader(struct pipe_context *pipe, 250 int id, 251 struct pipe_shader_state *shader) 252{ 253 int idx = 0, sh; 254 const struct shader_asm_info * shaders[SHADER_STAGES]; 255 256 /* first stage */ 257 sh = SHADERS_GET_PAINT_SHADER(id); 258 switch (sh << SHADERS_PAINT_SHIFT) { 259 case VEGA_SOLID_FILL_SHADER: 260 case VEGA_LINEAR_GRADIENT_SHADER: 261 case VEGA_RADIAL_GRADIENT_SHADER: 262 case VEGA_PATTERN_SHADER: 263 shaders[idx] = &shaders_paint_asm[(sh >> SHADERS_PAINT_SHIFT) - 1]; 264 assert(shaders[idx]->id == sh); 265 idx++; 266 break; 267 default: 268 break; 269 } 270 271 /* second stage */ 272 sh = SHADERS_GET_IMAGE_SHADER(id); 273 switch (sh) { 274 case VEGA_IMAGE_NORMAL_SHADER: 275 case VEGA_IMAGE_MULTIPLY_SHADER: 276 case VEGA_IMAGE_STENCIL_SHADER: 277 shaders[idx] = &shaders_image_asm[(sh >> SHADERS_IMAGE_SHIFT) - 1]; 278 assert(shaders[idx]->id == sh); 279 idx++; 280 break; 281 default: 282 break; 283 } 284 285 /* sanity check */ 286 assert(idx == ((!sh || sh == VEGA_IMAGE_NORMAL_SHADER) ? 1 : 2)); 287 288 /* third stage */ 289 sh = SHADERS_GET_MASK_SHADER(id); 290 switch (sh) { 291 case VEGA_MASK_SHADER: 292 shaders[idx] = &shaders_mask_asm[(sh >> SHADERS_MASK_SHIFT) - 1]; 293 assert(shaders[idx]->id == sh); 294 idx++; 295 break; 296 default: 297 break; 298 } 299 300 /* fourth stage */ 301 sh = SHADERS_GET_BLEND_SHADER(id); 302 switch (sh) { 303 case VEGA_BLEND_MULTIPLY_SHADER: 304 case VEGA_BLEND_SCREEN_SHADER: 305 case VEGA_BLEND_DARKEN_SHADER: 306 case VEGA_BLEND_LIGHTEN_SHADER: 307 shaders[idx] = &shaders_blend_asm[(sh >> SHADERS_BLEND_SHIFT) - 1]; 308 assert(shaders[idx]->id == sh); 309 idx++; 310 break; 311 default: 312 break; 313 } 314 315 /* fifth stage */ 316 sh = SHADERS_GET_PREMULTIPLY_SHADER(id); 317 switch (sh) { 318 case VEGA_PREMULTIPLY_SHADER: 319 case VEGA_UNPREMULTIPLY_SHADER: 320 shaders[idx] = &shaders_premultiply_asm[ 321 (sh >> SHADERS_PREMULTIPLY_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_BW_SHADER(id); 331 switch (sh) { 332 case VEGA_BW_SHADER: 333 shaders[idx] = &shaders_bw_asm[(sh >> SHADERS_BW_SHIFT) - 1]; 334 assert(shaders[idx]->id == sh); 335 idx++; 336 break; 337 default: 338 break; 339 } 340 341 return combine_shaders(shaders, idx, pipe, shader); 342} 343 344/*************************************************/ 345 346struct shaders_cache * shaders_cache_create(struct vg_context *vg) 347{ 348 struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache); 349 350 sc->pipe = vg; 351 sc->hash = cso_hash_create(); 352 353 return sc; 354} 355 356void shaders_cache_destroy(struct shaders_cache *sc) 357{ 358 struct cso_hash_iter iter = cso_hash_first_node(sc->hash); 359 360 while (!cso_hash_iter_is_null(iter)) { 361 struct cached_shader *cached = 362 (struct cached_shader *)cso_hash_iter_data(iter); 363 cso_delete_fragment_shader(sc->pipe->cso_context, 364 cached->driver_shader); 365 iter = cso_hash_erase(sc->hash, iter); 366 } 367 368 cso_hash_delete(sc->hash); 369 FREE(sc); 370} 371 372void * shaders_cache_fill(struct shaders_cache *sc, 373 int shader_key) 374{ 375 VGint key = shader_key; 376 struct cached_shader *cached; 377 struct cso_hash_iter iter = cso_hash_find(sc->hash, key); 378 379 if (cso_hash_iter_is_null(iter)) { 380 cached = CALLOC_STRUCT(cached_shader); 381 cached->driver_shader = create_shader(sc->pipe->pipe, key, &cached->state); 382 383 cso_hash_insert(sc->hash, key, cached); 384 385 return cached->driver_shader; 386 } 387 388 cached = (struct cached_shader *)cso_hash_iter_data(iter); 389 390 assert(cached->driver_shader); 391 return cached->driver_shader; 392} 393 394struct vg_shader * shader_create_from_text(struct pipe_context *pipe, 395 const char *txt, int num_tokens, 396 int type) 397{ 398 struct vg_shader *shader = (struct vg_shader *)MALLOC( 399 sizeof(struct vg_shader)); 400 struct tgsi_token *tokens = tokens_from_assembly(txt, num_tokens); 401 struct pipe_shader_state state; 402 403 debug_assert(type == PIPE_SHADER_VERTEX || 404 type == PIPE_SHADER_FRAGMENT); 405 406 state.tokens = tokens; 407 shader->type = type; 408 shader->tokens = tokens; 409 410 if (type == PIPE_SHADER_FRAGMENT) 411 shader->driver = pipe->create_fs_state(pipe, &state); 412 else 413 shader->driver = pipe->create_vs_state(pipe, &state); 414 return shader; 415} 416 417void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader) 418{ 419 if (shader->type == PIPE_SHADER_FRAGMENT) 420 cso_delete_fragment_shader(ctx->cso_context, shader->driver); 421 else 422 cso_delete_vertex_shader(ctx->cso_context, shader->driver); 423 FREE(shader->tokens); 424 FREE(shader); 425} 426