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) Fill (mandatory, solid color/gradient/pattern/image draw)
54 * 2) Image composition (image mode multiply and stencil)
56 * 4) Extended blend (multiply/screen/darken/lighten)
57 * 5) Premultiply/Unpremultiply
58 * 6) Color transform (to black and white)
60 #define SHADER_STAGES 6
62 struct cached_shader
{
64 struct pipe_shader_state state
;
67 struct shaders_cache
{
68 struct vg_context
*pipe
;
70 struct cso_hash
*hash
;
74 static INLINE
struct tgsi_token
*tokens_from_assembly(const char *txt
, int num_tokens
)
76 struct tgsi_token
*tokens
;
78 tokens
= (struct tgsi_token
*) MALLOC(num_tokens
* sizeof(tokens
[0]));
80 tgsi_text_translate(txt
, tokens
, num_tokens
);
89 #define ALL_FILLS (VEGA_SOLID_FILL_SHADER | \
90 VEGA_LINEAR_GRADIENT_SHADER | \
91 VEGA_RADIAL_GRADIENT_SHADER | \
92 VEGA_PATTERN_SHADER | \
93 VEGA_IMAGE_NORMAL_SHADER)
97 static const char max_shader_preamble[] =
99 "DCL IN[0], POSITION, LINEAR\n"
100 "DCL IN[1], GENERIC[0], PERSPECTIVE\n"
101 "DCL OUT[0], COLOR, CONSTANT\n"
102 "DCL CONST[0..9], CONSTANT\n"
103 "DCL TEMP[0..9], CONSTANT\n"
104 "DCL SAMP[0..9], CONSTANT\n";
106 max_shader_preamble strlen == 175
108 #define MAX_PREAMBLE 175
110 static INLINE VGint
range_min(VGint min
, VGint current
)
115 min
= MIN2(min
, current
);
119 static INLINE VGint
range_max(VGint max
, VGint current
)
121 return MAX2(max
, current
);
125 combine_shaders(const struct shader_asm_info
*shaders
[SHADER_STAGES
], int num_shaders
,
126 struct pipe_context
*pipe
,
127 struct pipe_shader_state
*shader
)
129 VGboolean declare_input
= VG_FALSE
;
130 VGint start_const
= -1, end_const
= 0;
131 VGint start_temp
= -1, end_temp
= 0;
132 VGint start_sampler
= -1, end_sampler
= 0;
133 VGint i
, current_shader
= 0;
134 VGint num_consts
, num_temps
, num_samplers
;
135 struct ureg_program
*ureg
;
136 struct ureg_src in
[2];
137 struct ureg_src
*sampler
= NULL
;
138 struct ureg_src
*constant
= NULL
;
139 struct ureg_dst out
, *temp
= NULL
;
142 for (i
= 0; i
< num_shaders
; ++i
) {
143 if (shaders
[i
]->num_consts
)
144 start_const
= range_min(start_const
, shaders
[i
]->start_const
);
145 if (shaders
[i
]->num_temps
)
146 start_temp
= range_min(start_temp
, shaders
[i
]->start_temp
);
147 if (shaders
[i
]->num_samplers
)
148 start_sampler
= range_min(start_sampler
, shaders
[i
]->start_sampler
);
150 end_const
= range_max(end_const
, shaders
[i
]->start_const
+
151 shaders
[i
]->num_consts
);
152 end_temp
= range_max(end_temp
, shaders
[i
]->start_temp
+
153 shaders
[i
]->num_temps
);
154 end_sampler
= range_max(end_sampler
, shaders
[i
]->start_sampler
+
155 shaders
[i
]->num_samplers
);
156 if (shaders
[i
]->needs_position
)
157 declare_input
= VG_TRUE
;
159 /* if they're still unitialized, initialize them */
164 if (start_sampler
< 0)
167 num_consts
= end_const
- start_const
;
168 num_temps
= end_temp
- start_temp
;
169 num_samplers
= end_sampler
- start_sampler
;
171 ureg
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
176 in
[0] = ureg_DECL_fs_input(ureg
,
177 TGSI_SEMANTIC_POSITION
,
179 TGSI_INTERPOLATE_LINEAR
);
180 in
[1] = ureg_DECL_fs_input(ureg
,
181 TGSI_SEMANTIC_GENERIC
,
183 TGSI_INTERPOLATE_PERSPECTIVE
);
186 /* we always have a color output */
187 out
= ureg_DECL_output(ureg
, TGSI_SEMANTIC_COLOR
, 0);
189 if (num_consts
>= 1) {
190 constant
= (struct ureg_src
*) malloc(sizeof(struct ureg_src
) * end_const
);
191 for (i
= start_const
; i
< end_const
; i
++) {
192 constant
[i
] = ureg_DECL_constant(ureg
, i
);
197 if (num_temps
>= 1) {
198 temp
= (struct ureg_dst
*) malloc(sizeof(struct ureg_dst
) * end_temp
);
199 for (i
= start_temp
; i
< end_temp
; i
++) {
200 temp
[i
] = ureg_DECL_temporary(ureg
);
204 if (num_samplers
>= 1) {
205 sampler
= (struct ureg_src
*) malloc(sizeof(struct ureg_src
) * end_sampler
);
206 for (i
= start_sampler
; i
< end_sampler
; i
++) {
207 sampler
[i
] = ureg_DECL_sampler(ureg
, i
);
211 while (current_shader
< num_shaders
) {
212 if ((current_shader
+ 1) == num_shaders
) {
213 shaders
[current_shader
]->func(ureg
,
220 shaders
[current_shader
]->func(ureg
,
232 shader
->tokens
= ureg_finalize(ureg
);
236 p
= pipe
->create_fs_state(pipe
, shader
);
239 if (num_temps
>= 1) {
240 for (i
= start_temp
; i
< end_temp
; i
++) {
241 ureg_release_temporary(ureg
, temp
[i
]);
256 create_shader(struct pipe_context
*pipe
,
258 struct pipe_shader_state
*shader
)
261 const struct shader_asm_info
* shaders
[SHADER_STAGES
];
263 /* the shader has to have a fill */
264 debug_assert(id
& ALL_FILLS
);
267 if (id
& VEGA_SOLID_FILL_SHADER
) {
268 debug_assert(idx
== 0);
269 shaders
[idx
] = &shaders_asm
[0];
270 debug_assert(shaders_asm
[0].id
== VEGA_SOLID_FILL_SHADER
);
273 if ((id
& VEGA_LINEAR_GRADIENT_SHADER
)) {
274 debug_assert(idx
== 0);
275 shaders
[idx
] = &shaders_asm
[1];
276 debug_assert(shaders_asm
[1].id
== VEGA_LINEAR_GRADIENT_SHADER
);
279 if ((id
& VEGA_RADIAL_GRADIENT_SHADER
)) {
280 debug_assert(idx
== 0);
281 shaders
[idx
] = &shaders_asm
[2];
282 debug_assert(shaders_asm
[2].id
== VEGA_RADIAL_GRADIENT_SHADER
);
285 if ((id
& VEGA_PATTERN_SHADER
)) {
286 debug_assert(idx
== 0);
287 debug_assert(shaders_asm
[3].id
== VEGA_PATTERN_SHADER
);
288 shaders
[idx
] = &shaders_asm
[3];
291 if ((id
& VEGA_IMAGE_NORMAL_SHADER
)) {
292 debug_assert(idx
== 0);
293 debug_assert(shaders_asm
[4].id
== VEGA_IMAGE_NORMAL_SHADER
);
294 shaders
[idx
] = &shaders_asm
[4];
299 if ((id
& VEGA_IMAGE_MULTIPLY_SHADER
)) {
300 debug_assert(shaders_asm
[5].id
== VEGA_IMAGE_MULTIPLY_SHADER
);
301 shaders
[idx
] = &shaders_asm
[5];
303 } else if ((id
& VEGA_IMAGE_STENCIL_SHADER
)) {
304 debug_assert(shaders_asm
[6].id
== VEGA_IMAGE_STENCIL_SHADER
);
305 shaders
[idx
] = &shaders_asm
[6];
310 if ((id
& VEGA_MASK_SHADER
)) {
311 debug_assert(idx
== 1);
312 debug_assert(shaders_asm
[7].id
== VEGA_MASK_SHADER
);
313 shaders
[idx
] = &shaders_asm
[7];
318 if ((id
& VEGA_BLEND_MULTIPLY_SHADER
)) {
319 debug_assert(shaders_asm
[8].id
== VEGA_BLEND_MULTIPLY_SHADER
);
320 shaders
[idx
] = &shaders_asm
[8];
322 } else if ((id
& VEGA_BLEND_SCREEN_SHADER
)) {
323 debug_assert(shaders_asm
[9].id
== VEGA_BLEND_SCREEN_SHADER
);
324 shaders
[idx
] = &shaders_asm
[9];
326 } else if ((id
& VEGA_BLEND_DARKEN_SHADER
)) {
327 debug_assert(shaders_asm
[10].id
== VEGA_BLEND_DARKEN_SHADER
);
328 shaders
[idx
] = &shaders_asm
[10];
330 } else if ((id
& VEGA_BLEND_LIGHTEN_SHADER
)) {
331 debug_assert(shaders_asm
[11].id
== VEGA_BLEND_LIGHTEN_SHADER
);
332 shaders
[idx
] = &shaders_asm
[11];
337 if ((id
& VEGA_PREMULTIPLY_SHADER
)) {
338 debug_assert(shaders_asm
[12].id
== VEGA_PREMULTIPLY_SHADER
);
339 shaders
[idx
] = &shaders_asm
[12];
341 } else if ((id
& VEGA_UNPREMULTIPLY_SHADER
)) {
342 debug_assert(shaders_asm
[13].id
== VEGA_UNPREMULTIPLY_SHADER
);
343 shaders
[idx
] = &shaders_asm
[13];
348 if ((id
& VEGA_BW_SHADER
)) {
349 debug_assert(shaders_asm
[14].id
== VEGA_BW_SHADER
);
350 shaders
[idx
] = &shaders_asm
[14];
354 return combine_shaders(shaders
, idx
, pipe
, shader
);
357 /*************************************************/
359 struct shaders_cache
* shaders_cache_create(struct vg_context
*vg
)
361 struct shaders_cache
*sc
= CALLOC_STRUCT(shaders_cache
);
364 sc
->hash
= cso_hash_create();
369 void shaders_cache_destroy(struct shaders_cache
*sc
)
371 struct cso_hash_iter iter
= cso_hash_first_node(sc
->hash
);
373 while (!cso_hash_iter_is_null(iter
)) {
374 struct cached_shader
*cached
=
375 (struct cached_shader
*)cso_hash_iter_data(iter
);
376 cso_delete_fragment_shader(sc
->pipe
->cso_context
,
377 cached
->driver_shader
);
378 iter
= cso_hash_erase(sc
->hash
, iter
);
381 cso_hash_delete(sc
->hash
);
385 void * shaders_cache_fill(struct shaders_cache
*sc
,
388 VGint key
= shader_key
;
389 struct cached_shader
*cached
;
390 struct cso_hash_iter iter
= cso_hash_find(sc
->hash
, key
);
392 if (cso_hash_iter_is_null(iter
)) {
393 cached
= CALLOC_STRUCT(cached_shader
);
394 cached
->driver_shader
= create_shader(sc
->pipe
->pipe
, key
, &cached
->state
);
396 cso_hash_insert(sc
->hash
, key
, cached
);
398 return cached
->driver_shader
;
401 cached
= (struct cached_shader
*)cso_hash_iter_data(iter
);
403 assert(cached
->driver_shader
);
404 return cached
->driver_shader
;
407 struct vg_shader
* shader_create_from_text(struct pipe_context
*pipe
,
408 const char *txt
, int num_tokens
,
411 struct vg_shader
*shader
= (struct vg_shader
*)MALLOC(
412 sizeof(struct vg_shader
));
413 struct tgsi_token
*tokens
= tokens_from_assembly(txt
, num_tokens
);
414 struct pipe_shader_state state
;
416 debug_assert(type
== PIPE_SHADER_VERTEX
||
417 type
== PIPE_SHADER_FRAGMENT
);
419 state
.tokens
= tokens
;
421 shader
->tokens
= tokens
;
423 if (type
== PIPE_SHADER_FRAGMENT
)
424 shader
->driver
= pipe
->create_fs_state(pipe
, &state
);
426 shader
->driver
= pipe
->create_vs_state(pipe
, &state
);
430 void vg_shader_destroy(struct vg_context
*ctx
, struct vg_shader
*shader
)
432 if (shader
->type
== PIPE_SHADER_FRAGMENT
)
433 cso_delete_fragment_shader(ctx
->cso_context
, shader
->driver
);
435 cso_delete_vertex_shader(ctx
->cso_context
, shader
->driver
);
436 FREE(shader
->tokens
);