1 /**************************************************************************
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
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:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
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.
25 **************************************************************************/
27 #include "shaders_cache.h"
29 #include "vg_context.h"
31 #include "pipe/p_context.h"
32 #include "pipe/p_defines.h"
33 #include "pipe/p_shader_tokens.h"
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"
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"
47 #include "VG/openvg.h"
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)
56 * 4) Per-channel alpha generation
57 * 5) Extended blend (multiply/screen/darken/lighten)
59 * 7) Premultiply/Unpremultiply
60 * 8) Color transform (to black and white)
62 #define SHADER_STAGES 8
64 struct cached_shader
{
66 struct pipe_shader_state state
;
69 struct shaders_cache
{
70 struct vg_context
*pipe
;
72 struct cso_hash
*hash
;
76 static INLINE
struct tgsi_token
*tokens_from_assembly(const char *txt
, int num_tokens
)
78 struct tgsi_token
*tokens
;
80 tokens
= (struct tgsi_token
*) MALLOC(num_tokens
* sizeof(tokens
[0]));
82 tgsi_text_translate(txt
, tokens
, num_tokens
);
92 static const char max_shader_preamble[] =
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";
101 max_shader_preamble strlen == 175
103 #define MAX_PREAMBLE 175
105 static INLINE VGint
range_min(VGint min
, VGint current
)
110 min
= MIN2(min
, current
);
114 static INLINE VGint
range_max(VGint max
, VGint current
)
116 return MAX2(max
, current
);
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
)
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
;
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
);
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
;
154 /* if they're still unitialized, initialize them */
159 if (start_sampler
< 0)
162 num_consts
= end_const
- start_const
;
163 num_temps
= end_temp
- start_temp
;
164 num_samplers
= end_sampler
- start_sampler
;
166 ureg
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
171 in
[0] = ureg_DECL_fs_input(ureg
,
172 TGSI_SEMANTIC_POSITION
,
174 TGSI_INTERPOLATE_LINEAR
);
175 in
[1] = ureg_DECL_fs_input(ureg
,
176 TGSI_SEMANTIC_GENERIC
,
178 TGSI_INTERPOLATE_PERSPECTIVE
);
181 /* we always have a color output */
182 out
= ureg_DECL_output(ureg
, TGSI_SEMANTIC_COLOR
, 0);
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
);
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
);
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
);
206 while (current_shader
< num_shaders
) {
207 if ((current_shader
+ 1) == num_shaders
) {
208 shaders
[current_shader
]->func(ureg
,
215 shaders
[current_shader
]->func(ureg
,
227 shader
->tokens
= ureg_finalize(ureg
);
231 p
= pipe
->create_fs_state(pipe
, shader
);
233 if (num_temps
>= 1) {
234 for (i
= start_temp
; i
< end_temp
; i
++) {
235 ureg_release_temporary(ureg
, temp
[i
]);
252 create_shader(struct pipe_context
*pipe
,
254 struct pipe_shader_state
*shader
)
257 const struct shader_asm_info
* shaders
[SHADER_STAGES
];
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
);
276 sh
= SHADERS_GET_IMAGE_SHADER(id
);
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
);
290 assert(idx
== ((!sh
|| sh
== VEGA_IMAGE_NORMAL_SHADER
) ? 1 : 2));
293 sh
= SHADERS_GET_COLOR_TRANSFORM_SHADER(id
);
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
);
306 sh
= SHADERS_GET_ALPHA_SHADER(id
);
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
);
320 sh
= SHADERS_GET_BLEND_SHADER(id
);
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
);
341 sh
= SHADERS_GET_MASK_SHADER(id
);
343 case VEGA_MASK_SHADER
:
344 shaders
[idx
] = &shaders_mask_asm
[(sh
>> SHADERS_MASK_SHIFT
) - 1];
345 assert(shaders
[idx
]->id
== sh
);
353 sh
= SHADERS_GET_PREMULTIPLY_SHADER(id
);
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
);
367 sh
= SHADERS_GET_BW_SHADER(id
);
370 shaders
[idx
] = &shaders_bw_asm
[(sh
>> SHADERS_BW_SHIFT
) - 1];
371 assert(shaders
[idx
]->id
== sh
);
378 return combine_shaders(shaders
, idx
, pipe
, shader
);
381 /*************************************************/
383 struct shaders_cache
* shaders_cache_create(struct vg_context
*vg
)
385 struct shaders_cache
*sc
= CALLOC_STRUCT(shaders_cache
);
388 sc
->hash
= cso_hash_create();
393 void shaders_cache_destroy(struct shaders_cache
*sc
)
395 struct cso_hash_iter iter
= cso_hash_first_node(sc
->hash
);
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
);
405 cso_hash_delete(sc
->hash
);
409 void * shaders_cache_fill(struct shaders_cache
*sc
,
412 VGint key
= shader_key
;
413 struct cached_shader
*cached
;
414 struct cso_hash_iter iter
= cso_hash_find(sc
->hash
, key
);
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
);
420 cso_hash_insert(sc
->hash
, key
, cached
);
422 return cached
->driver_shader
;
425 cached
= (struct cached_shader
*)cso_hash_iter_data(iter
);
427 assert(cached
->driver_shader
);
428 return cached
->driver_shader
;
431 struct vg_shader
* shader_create_from_text(struct pipe_context
*pipe
,
432 const char *txt
, int num_tokens
,
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
;
440 debug_assert(type
== PIPE_SHADER_VERTEX
||
441 type
== PIPE_SHADER_FRAGMENT
);
443 state
.tokens
= tokens
;
445 shader
->tokens
= tokens
;
447 if (type
== PIPE_SHADER_FRAGMENT
)
448 shader
->driver
= pipe
->create_fs_state(pipe
, &state
);
450 shader
->driver
= pipe
->create_vs_state(pipe
, &state
);
454 void vg_shader_destroy(struct vg_context
*ctx
, struct vg_shader
*shader
)
456 if (shader
->type
== PIPE_SHADER_FRAGMENT
)
457 cso_delete_fragment_shader(ctx
->cso_context
, shader
->driver
);
459 cso_delete_vertex_shader(ctx
->cso_context
, shader
->driver
);
460 FREE(shader
->tokens
);