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_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 create_preamble(char *txt
,
128 const struct shader_asm_info
*shaders
[SHADER_STAGES
],
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;
136 VGint num_consts
, num_temps
, num_samplers
;
138 for (i
= 0; i
< num_shaders
; ++i
) {
139 if (shaders
[i
]->num_consts
)
140 start_const
= range_min(start_const
, shaders
[i
]->start_const
);
141 if (shaders
[i
]->num_temps
)
142 start_temp
= range_min(start_temp
, shaders
[i
]->start_temp
);
143 if (shaders
[i
]->num_samplers
)
144 start_sampler
= range_min(start_sampler
, shaders
[i
]->start_sampler
);
146 end_const
= range_max(end_const
, shaders
[i
]->start_const
+
147 shaders
[i
]->num_consts
);
148 end_temp
= range_max(end_temp
, shaders
[i
]->start_temp
+
149 shaders
[i
]->num_temps
);
150 end_sampler
= range_max(end_sampler
, shaders
[i
]->start_sampler
+
151 shaders
[i
]->num_samplers
);
152 if (shaders
[i
]->needs_position
)
153 declare_input
= VG_TRUE
;
155 /* if they're still unitialized, initialize them */
160 if (start_sampler
< 0)
163 num_consts
= end_const
- start_const
;
164 num_temps
= end_temp
- start_temp
;
165 num_samplers
= end_sampler
- start_sampler
;
171 sprintf(txt
, "FRAG\n");
174 sprintf(txt
+ strlen(txt
), "DCL IN[0], POSITION, LINEAR\n");
175 sprintf(txt
+ strlen(txt
), "DCL IN[1], GENERIC[0], PERSPECTIVE\n");
178 /* we always have a color output */
179 sprintf(txt
+ strlen(txt
), "DCL OUT[0], COLOR, CONSTANT\n");
182 sprintf(txt
+ strlen(txt
), "DCL CONST[%d..%d], CONSTANT\n", start_const
, end_const
);
183 else if (num_consts
== 1)
184 sprintf(txt
+ strlen(txt
), "DCL CONST[%d], CONSTANT\n", start_const
);
187 sprintf(txt
+ strlen(txt
), "DCL TEMP[%d..%d], CONSTANT\n", start_temp
, end_temp
);
188 else if (num_temps
> 1)
189 sprintf(txt
+ strlen(txt
), "DCL TEMP[%d], CONSTANT\n", start_temp
);
191 if (num_samplers
> 1)
192 sprintf(txt
+ strlen(txt
), "DCL SAMP[%d..%d], CONSTANT\n", start_sampler
, end_sampler
);
193 else if (num_samplers
== 1)
194 sprintf(txt
+ strlen(txt
), "DCL SAMP[%d], CONSTANT\n", start_sampler
);
198 combine_shaders(const struct shader_asm_info
*shaders
[SHADER_STAGES
], int num_shaders
,
199 struct pipe_context
*pipe
,
200 struct pipe_shader_state
*shader
)
203 int combined_len
= MAX_PREAMBLE
;
204 int combined_tokens
= 0;
206 int current_shader
= 0;
209 for (i
= 0; i
< num_shaders
; ++i
) {
210 combined_len
+= strlen(shaders
[i
]->txt
);
211 combined_tokens
+= shaders
[i
]->num_tokens
;
213 /* add for the %s->TEMP[0] substitutions */
214 combined_len
+= num_shaders
* 7 /*TEMP[0]*/ + 4 /*"END\n"*/;
216 combined_txt
= (char*)malloc(combined_len
);
217 combined_txt
[0] = '\0';
219 create_preamble(combined_txt
, shaders
, num_shaders
);
221 while (current_shader
< num_shaders
) {
222 const char temp
[] = "TEMP[0]";
223 const char out
[] = "OUT[0]";
224 const char *subst
= temp
;
226 current_len
= strlen(combined_txt
);
228 /* if the last shader then output */
229 if (current_shader
+ 1 == num_shaders
)
232 snprintf(combined_txt
+ current_len
,
233 combined_len
- current_len
,
234 shaders
[current_shader
]->txt
,
240 current_len
= strlen(combined_txt
);
241 snprintf(combined_txt
+ current_len
,
242 combined_len
- current_len
,
245 debug_printf("Combined shader is : \n%s\n",
248 shader
->tokens
= tokens_from_assembly(
249 combined_txt
, combined_tokens
);
253 return pipe
->create_fs_state(pipe
, shader
);
257 create_shader(struct pipe_context
*pipe
,
259 struct pipe_shader_state
*shader
)
262 const struct shader_asm_info
* shaders
[SHADER_STAGES
];
264 /* the shader has to have a fill */
265 debug_assert(id
& ALL_FILLS
);
268 if (id
& VEGA_SOLID_FILL_SHADER
) {
269 debug_assert(idx
== 0);
270 shaders
[idx
] = &shaders_asm
[0];
271 debug_assert(shaders_asm
[0].id
== VEGA_SOLID_FILL_SHADER
);
274 if ((id
& VEGA_LINEAR_GRADIENT_SHADER
)) {
275 debug_assert(idx
== 0);
276 shaders
[idx
] = &shaders_asm
[1];
277 debug_assert(shaders_asm
[1].id
== VEGA_LINEAR_GRADIENT_SHADER
);
280 if ((id
& VEGA_RADIAL_GRADIENT_SHADER
)) {
281 debug_assert(idx
== 0);
282 shaders
[idx
] = &shaders_asm
[2];
283 debug_assert(shaders_asm
[2].id
== VEGA_RADIAL_GRADIENT_SHADER
);
286 if ((id
& VEGA_PATTERN_SHADER
)) {
287 debug_assert(idx
== 0);
288 debug_assert(shaders_asm
[3].id
== VEGA_PATTERN_SHADER
);
289 shaders
[idx
] = &shaders_asm
[3];
292 if ((id
& VEGA_IMAGE_NORMAL_SHADER
)) {
293 debug_assert(idx
== 0);
294 debug_assert(shaders_asm
[4].id
== VEGA_IMAGE_NORMAL_SHADER
);
295 shaders
[idx
] = &shaders_asm
[4];
300 if ((id
& VEGA_IMAGE_MULTIPLY_SHADER
)) {
301 debug_assert(shaders_asm
[5].id
== VEGA_IMAGE_MULTIPLY_SHADER
);
302 shaders
[idx
] = &shaders_asm
[5];
304 } else if ((id
& VEGA_IMAGE_STENCIL_SHADER
)) {
305 debug_assert(shaders_asm
[6].id
== VEGA_IMAGE_STENCIL_SHADER
);
306 shaders
[idx
] = &shaders_asm
[6];
311 if ((id
& VEGA_MASK_SHADER
)) {
312 debug_assert(idx
== 1);
313 debug_assert(shaders_asm
[7].id
== VEGA_MASK_SHADER
);
314 shaders
[idx
] = &shaders_asm
[7];
319 if ((id
& VEGA_BLEND_MULTIPLY_SHADER
)) {
320 debug_assert(shaders_asm
[8].id
== VEGA_BLEND_MULTIPLY_SHADER
);
321 shaders
[idx
] = &shaders_asm
[8];
323 } else if ((id
& VEGA_BLEND_SCREEN_SHADER
)) {
324 debug_assert(shaders_asm
[9].id
== VEGA_BLEND_SCREEN_SHADER
);
325 shaders
[idx
] = &shaders_asm
[9];
327 } else if ((id
& VEGA_BLEND_DARKEN_SHADER
)) {
328 debug_assert(shaders_asm
[10].id
== VEGA_BLEND_DARKEN_SHADER
);
329 shaders
[idx
] = &shaders_asm
[10];
331 } else if ((id
& VEGA_BLEND_LIGHTEN_SHADER
)) {
332 debug_assert(shaders_asm
[11].id
== VEGA_BLEND_LIGHTEN_SHADER
);
333 shaders
[idx
] = &shaders_asm
[11];
338 if ((id
& VEGA_PREMULTIPLY_SHADER
)) {
339 debug_assert(shaders_asm
[12].id
== VEGA_PREMULTIPLY_SHADER
);
340 shaders
[idx
] = &shaders_asm
[12];
342 } else if ((id
& VEGA_UNPREMULTIPLY_SHADER
)) {
343 debug_assert(shaders_asm
[13].id
== VEGA_UNPREMULTIPLY_SHADER
);
344 shaders
[idx
] = &shaders_asm
[13];
349 if ((id
& VEGA_BW_SHADER
)) {
350 debug_assert(shaders_asm
[14].id
== VEGA_BW_SHADER
);
351 shaders
[idx
] = &shaders_asm
[14];
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
);