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
64 struct cached_shader {
65 void *driver_shader;
66 struct pipe_shader_state state;
67 };
68
69 struct shaders_cache {
70 struct vg_context *pipe;
71
72 struct cso_hash *hash;
73 };
74
75
tokens_from_assembly(const char * txt,int num_tokens)76 static 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 /*
92 static 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
range_min(VGint min,VGint current)105 static 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
range_max(VGint max,VGint current)114 static INLINE VGint range_max(VGint max, VGint current)
115 {
116 return MAX2(max, current);
117 }
118
119 static void *
combine_shaders(const struct shader_asm_info * shaders[SHADER_STAGES],int num_shaders,struct pipe_context * pipe,struct pipe_shader_state * shader)120 combine_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
251 static void *
create_shader(struct pipe_context * pipe,int id,struct pipe_shader_state * shader)252 create_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
shaders_cache_create(struct vg_context * vg)383 struct 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
shaders_cache_destroy(struct shaders_cache * sc)393 void 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
shaders_cache_fill(struct shaders_cache * sc,int shader_key)409 void * 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
shader_create_from_text(struct pipe_context * pipe,const char * txt,int num_tokens,int type)431 struct 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
vg_shader_destroy(struct vg_context * ctx,struct vg_shader * shader)455 void 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