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 "util/u_inlines.h"
34 #include "pipe/p_screen.h"
35 #include "pipe/p_shader_tokens.h"
37 #include "tgsi/tgsi_build.h"
38 #include "tgsi/tgsi_dump.h"
39 #include "tgsi/tgsi_parse.h"
40 #include "tgsi/tgsi_util.h"
41 #include "tgsi/tgsi_text.h"
43 #include "util/u_memory.h"
44 #include "util/u_math.h"
45 #include "util/u_debug.h"
46 #include "cso_cache/cso_hash.h"
47 #include "cso_cache/cso_context.h"
49 #include "VG/openvg.h"
53 /* Essentially we construct an ubber-shader based on the state
54 * of the pipeline. The stages are:
55 * 1) Fill (mandatory, solid color/gradient/pattern/image draw)
56 * 2) Image composition (image mode multiply and stencil)
58 * 4) Extended blend (multiply/screen/darken/lighten)
59 * 5) Premultiply/Unpremultiply
60 * 6) Color transform (to black and white)
62 #define SHADER_STAGES 6
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
);
91 #define ALL_FILLS (VEGA_SOLID_FILL_SHADER | \
92 VEGA_LINEAR_GRADIENT_SHADER | \
93 VEGA_RADIAL_GRADIENT_SHADER | \
94 VEGA_PATTERN_SHADER | \
95 VEGA_IMAGE_NORMAL_SHADER)
99 static const char max_shader_preamble[] =
101 "DCL IN[0], POSITION, LINEAR\n"
102 "DCL IN[1], GENERIC[0], PERSPECTIVE\n"
103 "DCL OUT[0], COLOR, CONSTANT\n"
104 "DCL CONST[0..9], CONSTANT\n"
105 "DCL TEMP[0..9], CONSTANT\n"
106 "DCL SAMP[0..9], CONSTANT\n";
108 max_shader_preamble strlen == 175
110 #define MAX_PREAMBLE 175
112 static INLINE VGint
range_min(VGint min
, VGint current
)
117 min
= MIN2(min
, current
);
121 static INLINE VGint
range_max(VGint max
, VGint current
)
123 return MAX2(max
, current
);
127 combine_shaders(const struct shader_asm_info
*shaders
[SHADER_STAGES
], int num_shaders
,
128 struct pipe_context
*pipe
,
129 struct pipe_shader_state
*shader
)
131 VGboolean declare_input
= VG_FALSE
;
132 VGint start_const
= -1, end_const
= 0;
133 VGint start_temp
= -1, end_temp
= 0;
134 VGint start_sampler
= -1, end_sampler
= 0;
135 VGint i
, current_shader
= 0;
136 VGint num_consts
, num_temps
, num_samplers
;
137 struct ureg_program
*ureg
;
138 struct ureg_src in
[2];
139 struct ureg_src
*sampler
= NULL
;
140 struct ureg_src
*constant
= NULL
;
141 struct ureg_dst out
, *temp
= NULL
;
144 for (i
= 0; i
< num_shaders
; ++i
) {
145 if (shaders
[i
]->num_consts
)
146 start_const
= range_min(start_const
, shaders
[i
]->start_const
);
147 if (shaders
[i
]->num_temps
)
148 start_temp
= range_min(start_temp
, shaders
[i
]->start_temp
);
149 if (shaders
[i
]->num_samplers
)
150 start_sampler
= range_min(start_sampler
, shaders
[i
]->start_sampler
);
152 end_const
= range_max(end_const
, shaders
[i
]->start_const
+
153 shaders
[i
]->num_consts
);
154 end_temp
= range_max(end_temp
, shaders
[i
]->start_temp
+
155 shaders
[i
]->num_temps
);
156 end_sampler
= range_max(end_sampler
, shaders
[i
]->start_sampler
+
157 shaders
[i
]->num_samplers
);
158 if (shaders
[i
]->needs_position
)
159 declare_input
= VG_TRUE
;
161 /* if they're still unitialized, initialize them */
166 if (start_sampler
< 0)
169 num_consts
= end_const
- start_const
;
170 num_temps
= end_temp
- start_temp
;
171 num_samplers
= end_sampler
- start_sampler
;
173 ureg
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
178 in
[0] = ureg_DECL_fs_input(ureg
,
179 TGSI_SEMANTIC_POSITION
,
181 TGSI_INTERPOLATE_LINEAR
);
182 in
[1] = ureg_DECL_fs_input(ureg
,
183 TGSI_SEMANTIC_GENERIC
,
185 TGSI_INTERPOLATE_PERSPECTIVE
);
188 /* we always have a color output */
189 out
= ureg_DECL_output(ureg
, TGSI_SEMANTIC_COLOR
, 0);
191 if (num_consts
>= 1) {
192 constant
= (struct ureg_src
*) malloc(sizeof(struct ureg_src
) * end_const
);
193 for (i
= start_const
; i
< end_const
; i
++) {
194 constant
[i
] = ureg_DECL_constant(ureg
, i
);
199 if (num_temps
>= 1) {
200 temp
= (struct ureg_dst
*) malloc(sizeof(struct ureg_dst
) * end_temp
);
201 for (i
= start_temp
; i
< end_temp
; i
++) {
202 temp
[i
] = ureg_DECL_temporary(ureg
);
206 if (num_samplers
>= 1) {
207 sampler
= (struct ureg_src
*) malloc(sizeof(struct ureg_src
) * end_sampler
);
208 for (i
= start_sampler
; i
< end_sampler
; i
++) {
209 sampler
[i
] = ureg_DECL_sampler(ureg
, i
);
213 while (current_shader
< num_shaders
) {
214 if ((current_shader
+ 1) == num_shaders
) {
215 shaders
[current_shader
]->func(ureg
,
222 shaders
[current_shader
]->func(ureg
,
234 shader
->tokens
= ureg_finalize(ureg
);
238 p
= pipe
->create_fs_state(pipe
, shader
);
241 if (num_temps
>= 1) {
242 for (i
= start_temp
; i
< end_temp
; i
++) {
243 ureg_release_temporary(ureg
, temp
[i
]);
258 create_shader(struct pipe_context
*pipe
,
260 struct pipe_shader_state
*shader
)
263 const struct shader_asm_info
* shaders
[SHADER_STAGES
];
265 /* the shader has to have a fill */
266 debug_assert(id
& ALL_FILLS
);
269 if (id
& VEGA_SOLID_FILL_SHADER
) {
270 debug_assert(idx
== 0);
271 shaders
[idx
] = &shaders_asm
[0];
272 debug_assert(shaders_asm
[0].id
== VEGA_SOLID_FILL_SHADER
);
275 if ((id
& VEGA_LINEAR_GRADIENT_SHADER
)) {
276 debug_assert(idx
== 0);
277 shaders
[idx
] = &shaders_asm
[1];
278 debug_assert(shaders_asm
[1].id
== VEGA_LINEAR_GRADIENT_SHADER
);
281 if ((id
& VEGA_RADIAL_GRADIENT_SHADER
)) {
282 debug_assert(idx
== 0);
283 shaders
[idx
] = &shaders_asm
[2];
284 debug_assert(shaders_asm
[2].id
== VEGA_RADIAL_GRADIENT_SHADER
);
287 if ((id
& VEGA_PATTERN_SHADER
)) {
288 debug_assert(idx
== 0);
289 debug_assert(shaders_asm
[3].id
== VEGA_PATTERN_SHADER
);
290 shaders
[idx
] = &shaders_asm
[3];
293 if ((id
& VEGA_IMAGE_NORMAL_SHADER
)) {
294 debug_assert(idx
== 0);
295 debug_assert(shaders_asm
[4].id
== VEGA_IMAGE_NORMAL_SHADER
);
296 shaders
[idx
] = &shaders_asm
[4];
301 if ((id
& VEGA_IMAGE_MULTIPLY_SHADER
)) {
302 debug_assert(shaders_asm
[5].id
== VEGA_IMAGE_MULTIPLY_SHADER
);
303 shaders
[idx
] = &shaders_asm
[5];
305 } else if ((id
& VEGA_IMAGE_STENCIL_SHADER
)) {
306 debug_assert(shaders_asm
[6].id
== VEGA_IMAGE_STENCIL_SHADER
);
307 shaders
[idx
] = &shaders_asm
[6];
312 if ((id
& VEGA_MASK_SHADER
)) {
313 debug_assert(idx
== 1);
314 debug_assert(shaders_asm
[7].id
== VEGA_MASK_SHADER
);
315 shaders
[idx
] = &shaders_asm
[7];
320 if ((id
& VEGA_BLEND_MULTIPLY_SHADER
)) {
321 debug_assert(shaders_asm
[8].id
== VEGA_BLEND_MULTIPLY_SHADER
);
322 shaders
[idx
] = &shaders_asm
[8];
324 } else if ((id
& VEGA_BLEND_SCREEN_SHADER
)) {
325 debug_assert(shaders_asm
[9].id
== VEGA_BLEND_SCREEN_SHADER
);
326 shaders
[idx
] = &shaders_asm
[9];
328 } else if ((id
& VEGA_BLEND_DARKEN_SHADER
)) {
329 debug_assert(shaders_asm
[10].id
== VEGA_BLEND_DARKEN_SHADER
);
330 shaders
[idx
] = &shaders_asm
[10];
332 } else if ((id
& VEGA_BLEND_LIGHTEN_SHADER
)) {
333 debug_assert(shaders_asm
[11].id
== VEGA_BLEND_LIGHTEN_SHADER
);
334 shaders
[idx
] = &shaders_asm
[11];
339 if ((id
& VEGA_PREMULTIPLY_SHADER
)) {
340 debug_assert(shaders_asm
[12].id
== VEGA_PREMULTIPLY_SHADER
);
341 shaders
[idx
] = &shaders_asm
[12];
343 } else if ((id
& VEGA_UNPREMULTIPLY_SHADER
)) {
344 debug_assert(shaders_asm
[13].id
== VEGA_UNPREMULTIPLY_SHADER
);
345 shaders
[idx
] = &shaders_asm
[13];
350 if ((id
& VEGA_BW_SHADER
)) {
351 debug_assert(shaders_asm
[14].id
== VEGA_BW_SHADER
);
352 shaders
[idx
] = &shaders_asm
[14];
356 return combine_shaders(shaders
, idx
, pipe
, shader
);
359 /*************************************************/
361 struct shaders_cache
* shaders_cache_create(struct vg_context
*vg
)
363 struct shaders_cache
*sc
= CALLOC_STRUCT(shaders_cache
);
366 sc
->hash
= cso_hash_create();
371 void shaders_cache_destroy(struct shaders_cache
*sc
)
373 struct cso_hash_iter iter
= cso_hash_first_node(sc
->hash
);
375 while (!cso_hash_iter_is_null(iter
)) {
376 struct cached_shader
*cached
=
377 (struct cached_shader
*)cso_hash_iter_data(iter
);
378 cso_delete_fragment_shader(sc
->pipe
->cso_context
,
379 cached
->driver_shader
);
380 iter
= cso_hash_erase(sc
->hash
, iter
);
383 cso_hash_delete(sc
->hash
);
387 void * shaders_cache_fill(struct shaders_cache
*sc
,
390 VGint key
= shader_key
;
391 struct cached_shader
*cached
;
392 struct cso_hash_iter iter
= cso_hash_find(sc
->hash
, key
);
394 if (cso_hash_iter_is_null(iter
)) {
395 cached
= CALLOC_STRUCT(cached_shader
);
396 cached
->driver_shader
= create_shader(sc
->pipe
->pipe
, key
, &cached
->state
);
398 cso_hash_insert(sc
->hash
, key
, cached
);
400 return cached
->driver_shader
;
403 cached
= (struct cached_shader
*)cso_hash_iter_data(iter
);
405 assert(cached
->driver_shader
);
406 return cached
->driver_shader
;
409 struct vg_shader
* shader_create_from_text(struct pipe_context
*pipe
,
410 const char *txt
, int num_tokens
,
413 struct vg_shader
*shader
= (struct vg_shader
*)malloc(
414 sizeof(struct vg_shader
));
415 struct tgsi_token
*tokens
= tokens_from_assembly(txt
, num_tokens
);
416 struct pipe_shader_state state
;
418 debug_assert(type
== PIPE_SHADER_VERTEX
||
419 type
== PIPE_SHADER_FRAGMENT
);
421 state
.tokens
= tokens
;
423 shader
->tokens
= tokens
;
425 if (type
== PIPE_SHADER_FRAGMENT
)
426 shader
->driver
= pipe
->create_fs_state(pipe
, &state
);
428 shader
->driver
= pipe
->create_vs_state(pipe
, &state
);
432 void vg_shader_destroy(struct vg_context
*ctx
, struct vg_shader
*shader
)
434 if (shader
->type
== PIPE_SHADER_FRAGMENT
)
435 cso_delete_fragment_shader(ctx
->cso_context
, shader
->driver
);
437 cso_delete_vertex_shader(ctx
->cso_context
, shader
->driver
);
438 free(shader
->tokens
);