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
= 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
= 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
= 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
]);
249 create_shader(struct pipe_context
*pipe
,
251 struct pipe_shader_state
*shader
)
254 const struct shader_asm_info
* shaders
[SHADER_STAGES
];
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 case VEGA_PAINT_DEGENERATE_SHADER
:
264 shaders
[idx
] = &shaders_paint_asm
[(sh
>> SHADERS_PAINT_SHIFT
) - 1];
265 assert(shaders
[idx
]->id
== sh
);
273 sh
= SHADERS_GET_IMAGE_SHADER(id
);
275 case VEGA_IMAGE_NORMAL_SHADER
:
276 case VEGA_IMAGE_MULTIPLY_SHADER
:
277 case VEGA_IMAGE_STENCIL_SHADER
:
278 shaders
[idx
] = &shaders_image_asm
[(sh
>> SHADERS_IMAGE_SHIFT
) - 1];
279 assert(shaders
[idx
]->id
== sh
);
287 assert(idx
== ((!sh
|| sh
== VEGA_IMAGE_NORMAL_SHADER
) ? 1 : 2));
290 sh
= SHADERS_GET_COLOR_TRANSFORM_SHADER(id
);
292 case VEGA_COLOR_TRANSFORM_SHADER
:
293 shaders
[idx
] = &shaders_color_transform_asm
[
294 (sh
>> SHADERS_COLOR_TRANSFORM_SHIFT
) - 1];
295 assert(shaders
[idx
]->id
== sh
);
303 sh
= SHADERS_GET_ALPHA_SHADER(id
);
305 case VEGA_ALPHA_NORMAL_SHADER
:
306 case VEGA_ALPHA_PER_CHANNEL_SHADER
:
307 shaders
[idx
] = &shaders_alpha_asm
[
308 (sh
>> SHADERS_ALPHA_SHIFT
) - 1];
309 assert(shaders
[idx
]->id
== sh
);
317 sh
= SHADERS_GET_BLEND_SHADER(id
);
319 case VEGA_BLEND_SRC_SHADER
:
320 case VEGA_BLEND_SRC_OVER_SHADER
:
321 case VEGA_BLEND_DST_OVER_SHADER
:
322 case VEGA_BLEND_SRC_IN_SHADER
:
323 case VEGA_BLEND_DST_IN_SHADER
:
324 case VEGA_BLEND_MULTIPLY_SHADER
:
325 case VEGA_BLEND_SCREEN_SHADER
:
326 case VEGA_BLEND_DARKEN_SHADER
:
327 case VEGA_BLEND_LIGHTEN_SHADER
:
328 case VEGA_BLEND_ADDITIVE_SHADER
:
329 shaders
[idx
] = &shaders_blend_asm
[(sh
>> SHADERS_BLEND_SHIFT
) - 1];
330 assert(shaders
[idx
]->id
== sh
);
338 sh
= SHADERS_GET_MASK_SHADER(id
);
340 case VEGA_MASK_SHADER
:
341 shaders
[idx
] = &shaders_mask_asm
[(sh
>> SHADERS_MASK_SHIFT
) - 1];
342 assert(shaders
[idx
]->id
== sh
);
350 sh
= SHADERS_GET_PREMULTIPLY_SHADER(id
);
352 case VEGA_PREMULTIPLY_SHADER
:
353 case VEGA_UNPREMULTIPLY_SHADER
:
354 shaders
[idx
] = &shaders_premultiply_asm
[
355 (sh
>> SHADERS_PREMULTIPLY_SHIFT
) - 1];
356 assert(shaders
[idx
]->id
== sh
);
364 sh
= SHADERS_GET_BW_SHADER(id
);
367 shaders
[idx
] = &shaders_bw_asm
[(sh
>> SHADERS_BW_SHIFT
) - 1];
368 assert(shaders
[idx
]->id
== sh
);
375 return combine_shaders(shaders
, idx
, pipe
, shader
);
378 /*************************************************/
380 struct shaders_cache
* shaders_cache_create(struct vg_context
*vg
)
382 struct shaders_cache
*sc
= CALLOC_STRUCT(shaders_cache
);
385 sc
->hash
= cso_hash_create();
390 void shaders_cache_destroy(struct shaders_cache
*sc
)
392 struct cso_hash_iter iter
= cso_hash_first_node(sc
->hash
);
394 while (!cso_hash_iter_is_null(iter
)) {
395 struct cached_shader
*cached
=
396 (struct cached_shader
*)cso_hash_iter_data(iter
);
397 cso_delete_fragment_shader(sc
->pipe
->cso_context
,
398 cached
->driver_shader
);
399 iter
= cso_hash_erase(sc
->hash
, iter
);
402 cso_hash_delete(sc
->hash
);
406 void * shaders_cache_fill(struct shaders_cache
*sc
,
409 VGint key
= shader_key
;
410 struct cached_shader
*cached
;
411 struct cso_hash_iter iter
= cso_hash_find(sc
->hash
, key
);
413 if (cso_hash_iter_is_null(iter
)) {
414 cached
= CALLOC_STRUCT(cached_shader
);
415 cached
->driver_shader
= create_shader(sc
->pipe
->pipe
, key
, &cached
->state
);
417 cso_hash_insert(sc
->hash
, key
, cached
);
419 return cached
->driver_shader
;
422 cached
= (struct cached_shader
*)cso_hash_iter_data(iter
);
424 assert(cached
->driver_shader
);
425 return cached
->driver_shader
;
428 struct vg_shader
* shader_create_from_text(struct pipe_context
*pipe
,
429 const char *txt
, int num_tokens
,
432 struct vg_shader
*shader
= (struct vg_shader
*)MALLOC(
433 sizeof(struct vg_shader
));
434 struct tgsi_token
*tokens
= tokens_from_assembly(txt
, num_tokens
);
435 struct pipe_shader_state state
;
437 debug_assert(type
== PIPE_SHADER_VERTEX
||
438 type
== PIPE_SHADER_FRAGMENT
);
440 state
.tokens
= tokens
;
441 memset(&state
.stream_output
, 0, sizeof(state
.stream_output
));
443 shader
->tokens
= tokens
;
445 if (type
== PIPE_SHADER_FRAGMENT
)
446 shader
->driver
= pipe
->create_fs_state(pipe
, &state
);
448 shader
->driver
= pipe
->create_vs_state(pipe
, &state
);
452 void vg_shader_destroy(struct vg_context
*ctx
, struct vg_shader
*shader
)
454 if (shader
->type
== PIPE_SHADER_FRAGMENT
)
455 cso_delete_fragment_shader(ctx
->cso_context
, shader
->driver
);
457 cso_delete_vertex_shader(ctx
->cso_context
, shader
->driver
);
458 FREE(shader
->tokens
);