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