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)
57 * 5) Extended blend (multiply/screen/darken/lighten)
58 * 6) Premultiply/Unpremultiply
59 * 7) Color transform (to black and white)
61 #define SHADER_STAGES 7
63 struct cached_shader
{
65 struct pipe_shader_state state
;
68 struct shaders_cache
{
69 struct vg_context
*pipe
;
71 struct cso_hash
*hash
;
75 static INLINE
struct tgsi_token
*tokens_from_assembly(const char *txt
, int num_tokens
)
77 struct tgsi_token
*tokens
;
79 tokens
= (struct tgsi_token
*) MALLOC(num_tokens
* sizeof(tokens
[0]));
81 tgsi_text_translate(txt
, tokens
, num_tokens
);
91 static const char max_shader_preamble[] =
93 "DCL IN[0], POSITION, LINEAR\n"
94 "DCL IN[1], GENERIC[0], PERSPECTIVE\n"
95 "DCL OUT[0], COLOR, CONSTANT\n"
96 "DCL CONST[0..9], CONSTANT\n"
97 "DCL TEMP[0..9], CONSTANT\n"
98 "DCL SAMP[0..9], CONSTANT\n";
100 max_shader_preamble strlen == 175
102 #define MAX_PREAMBLE 175
104 static INLINE VGint
range_min(VGint min
, VGint current
)
109 min
= MIN2(min
, current
);
113 static INLINE VGint
range_max(VGint max
, VGint current
)
115 return MAX2(max
, current
);
119 combine_shaders(const struct shader_asm_info
*shaders
[SHADER_STAGES
], int num_shaders
,
120 struct pipe_context
*pipe
,
121 struct pipe_shader_state
*shader
)
123 VGboolean declare_input
= VG_FALSE
;
124 VGint start_const
= -1, end_const
= 0;
125 VGint start_temp
= -1, end_temp
= 0;
126 VGint start_sampler
= -1, end_sampler
= 0;
127 VGint i
, current_shader
= 0;
128 VGint num_consts
, num_temps
, num_samplers
;
129 struct ureg_program
*ureg
;
130 struct ureg_src in
[2];
131 struct ureg_src
*sampler
= NULL
;
132 struct ureg_src
*constant
= NULL
;
133 struct ureg_dst out
, *temp
= NULL
;
136 for (i
= 0; i
< num_shaders
; ++i
) {
137 if (shaders
[i
]->num_consts
)
138 start_const
= range_min(start_const
, shaders
[i
]->start_const
);
139 if (shaders
[i
]->num_temps
)
140 start_temp
= range_min(start_temp
, shaders
[i
]->start_temp
);
141 if (shaders
[i
]->num_samplers
)
142 start_sampler
= range_min(start_sampler
, shaders
[i
]->start_sampler
);
144 end_const
= range_max(end_const
, shaders
[i
]->start_const
+
145 shaders
[i
]->num_consts
);
146 end_temp
= range_max(end_temp
, shaders
[i
]->start_temp
+
147 shaders
[i
]->num_temps
);
148 end_sampler
= range_max(end_sampler
, shaders
[i
]->start_sampler
+
149 shaders
[i
]->num_samplers
);
150 if (shaders
[i
]->needs_position
)
151 declare_input
= VG_TRUE
;
153 /* if they're still unitialized, initialize them */
158 if (start_sampler
< 0)
161 num_consts
= end_const
- start_const
;
162 num_temps
= end_temp
- start_temp
;
163 num_samplers
= end_sampler
- start_sampler
;
165 ureg
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
170 in
[0] = ureg_DECL_fs_input(ureg
,
171 TGSI_SEMANTIC_POSITION
,
173 TGSI_INTERPOLATE_LINEAR
);
174 in
[1] = ureg_DECL_fs_input(ureg
,
175 TGSI_SEMANTIC_GENERIC
,
177 TGSI_INTERPOLATE_PERSPECTIVE
);
180 /* we always have a color output */
181 out
= ureg_DECL_output(ureg
, TGSI_SEMANTIC_COLOR
, 0);
183 if (num_consts
>= 1) {
184 constant
= (struct ureg_src
*) malloc(sizeof(struct ureg_src
) * end_const
);
185 for (i
= start_const
; i
< end_const
; i
++) {
186 constant
[i
] = ureg_DECL_constant(ureg
, i
);
191 if (num_temps
>= 1) {
192 temp
= (struct ureg_dst
*) malloc(sizeof(struct ureg_dst
) * end_temp
);
193 for (i
= start_temp
; i
< end_temp
; i
++) {
194 temp
[i
] = ureg_DECL_temporary(ureg
);
198 if (num_samplers
>= 1) {
199 sampler
= (struct ureg_src
*) malloc(sizeof(struct ureg_src
) * end_sampler
);
200 for (i
= start_sampler
; i
< end_sampler
; i
++) {
201 sampler
[i
] = ureg_DECL_sampler(ureg
, i
);
205 while (current_shader
< num_shaders
) {
206 if ((current_shader
+ 1) == num_shaders
) {
207 shaders
[current_shader
]->func(ureg
,
214 shaders
[current_shader
]->func(ureg
,
226 shader
->tokens
= ureg_finalize(ureg
);
230 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
]);
250 create_shader(struct pipe_context
*pipe
,
252 struct pipe_shader_state
*shader
)
255 const struct shader_asm_info
* shaders
[SHADER_STAGES
];
258 sh
= SHADERS_GET_PAINT_SHADER(id
);
259 switch (sh
<< SHADERS_PAINT_SHIFT
) {
260 case VEGA_SOLID_FILL_SHADER
:
261 case VEGA_LINEAR_GRADIENT_SHADER
:
262 case VEGA_RADIAL_GRADIENT_SHADER
:
263 case VEGA_PATTERN_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_MASK_SHADER(id
);
305 case VEGA_MASK_SHADER
:
306 shaders
[idx
] = &shaders_mask_asm
[(sh
>> SHADERS_MASK_SHIFT
) - 1];
307 assert(shaders
[idx
]->id
== sh
);
315 sh
= SHADERS_GET_BLEND_SHADER(id
);
317 case VEGA_BLEND_MULTIPLY_SHADER
:
318 case VEGA_BLEND_SCREEN_SHADER
:
319 case VEGA_BLEND_DARKEN_SHADER
:
320 case VEGA_BLEND_LIGHTEN_SHADER
:
321 shaders
[idx
] = &shaders_blend_asm
[(sh
>> SHADERS_BLEND_SHIFT
) - 1];
322 assert(shaders
[idx
]->id
== sh
);
330 sh
= SHADERS_GET_PREMULTIPLY_SHADER(id
);
332 case VEGA_PREMULTIPLY_SHADER
:
333 case VEGA_UNPREMULTIPLY_SHADER
:
334 shaders
[idx
] = &shaders_premultiply_asm
[
335 (sh
>> SHADERS_PREMULTIPLY_SHIFT
) - 1];
336 assert(shaders
[idx
]->id
== sh
);
344 sh
= SHADERS_GET_BW_SHADER(id
);
347 shaders
[idx
] = &shaders_bw_asm
[(sh
>> SHADERS_BW_SHIFT
) - 1];
348 assert(shaders
[idx
]->id
== sh
);
355 return combine_shaders(shaders
, idx
, pipe
, shader
);
358 /*************************************************/
360 struct shaders_cache
* shaders_cache_create(struct vg_context
*vg
)
362 struct shaders_cache
*sc
= CALLOC_STRUCT(shaders_cache
);
365 sc
->hash
= cso_hash_create();
370 void shaders_cache_destroy(struct shaders_cache
*sc
)
372 struct cso_hash_iter iter
= cso_hash_first_node(sc
->hash
);
374 while (!cso_hash_iter_is_null(iter
)) {
375 struct cached_shader
*cached
=
376 (struct cached_shader
*)cso_hash_iter_data(iter
);
377 cso_delete_fragment_shader(sc
->pipe
->cso_context
,
378 cached
->driver_shader
);
379 iter
= cso_hash_erase(sc
->hash
, iter
);
382 cso_hash_delete(sc
->hash
);
386 void * shaders_cache_fill(struct shaders_cache
*sc
,
389 VGint key
= shader_key
;
390 struct cached_shader
*cached
;
391 struct cso_hash_iter iter
= cso_hash_find(sc
->hash
, key
);
393 if (cso_hash_iter_is_null(iter
)) {
394 cached
= CALLOC_STRUCT(cached_shader
);
395 cached
->driver_shader
= create_shader(sc
->pipe
->pipe
, key
, &cached
->state
);
397 cso_hash_insert(sc
->hash
, key
, cached
);
399 return cached
->driver_shader
;
402 cached
= (struct cached_shader
*)cso_hash_iter_data(iter
);
404 assert(cached
->driver_shader
);
405 return cached
->driver_shader
;
408 struct vg_shader
* shader_create_from_text(struct pipe_context
*pipe
,
409 const char *txt
, int num_tokens
,
412 struct vg_shader
*shader
= (struct vg_shader
*)MALLOC(
413 sizeof(struct vg_shader
));
414 struct tgsi_token
*tokens
= tokens_from_assembly(txt
, num_tokens
);
415 struct pipe_shader_state state
;
417 debug_assert(type
== PIPE_SHADER_VERTEX
||
418 type
== PIPE_SHADER_FRAGMENT
);
420 state
.tokens
= tokens
;
422 shader
->tokens
= tokens
;
424 if (type
== PIPE_SHADER_FRAGMENT
)
425 shader
->driver
= pipe
->create_fs_state(pipe
, &state
);
427 shader
->driver
= pipe
->create_vs_state(pipe
, &state
);
431 void vg_shader_destroy(struct vg_context
*ctx
, struct vg_shader
*shader
)
433 if (shader
->type
== PIPE_SHADER_FRAGMENT
)
434 cso_delete_fragment_shader(ctx
->cso_context
, shader
->driver
);
436 cso_delete_vertex_shader(ctx
->cso_context
, shader
->driver
);
437 FREE(shader
->tokens
);