st/vega: Add color transformation support.
[mesa.git] / src / gallium / state_trackers / vega / shaders_cache.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
4 *
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:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
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.
24 *
25 **************************************************************************/
26
27 #include "shaders_cache.h"
28
29 #include "vg_context.h"
30
31 #include "pipe/p_context.h"
32 #include "pipe/p_defines.h"
33 #include "pipe/p_shader_tokens.h"
34
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"
40
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"
46
47 #include "VG/openvg.h"
48
49 #include "asm_fill.h"
50
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)
55 * 3) Color transform
56 * 4) Mask
57 * 5) Extended blend (multiply/screen/darken/lighten)
58 * 6) Premultiply/Unpremultiply
59 * 7) Color transform (to black and white)
60 */
61 #define SHADER_STAGES 7
62
63 struct cached_shader {
64 void *driver_shader;
65 struct pipe_shader_state state;
66 };
67
68 struct shaders_cache {
69 struct vg_context *pipe;
70
71 struct cso_hash *hash;
72 };
73
74
75 static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens)
76 {
77 struct tgsi_token *tokens;
78
79 tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0]));
80
81 tgsi_text_translate(txt, tokens, num_tokens);
82
83 #if DEBUG_SHADERS
84 tgsi_dump(tokens, 0);
85 #endif
86
87 return tokens;
88 }
89
90 /*
91 static const char max_shader_preamble[] =
92 "FRAG\n"
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";
99
100 max_shader_preamble strlen == 175
101 */
102 #define MAX_PREAMBLE 175
103
104 static INLINE VGint range_min(VGint min, VGint current)
105 {
106 if (min < 0)
107 min = current;
108 else
109 min = MIN2(min, current);
110 return min;
111 }
112
113 static INLINE VGint range_max(VGint max, VGint current)
114 {
115 return MAX2(max, current);
116 }
117
118 static void *
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)
122 {
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;
134 void *p = NULL;
135
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);
143
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;
152 }
153 /* if they're still unitialized, initialize them */
154 if (start_const < 0)
155 start_const = 0;
156 if (start_temp < 0)
157 start_temp = 0;
158 if (start_sampler < 0)
159 start_sampler = 0;
160
161 num_consts = end_const - start_const;
162 num_temps = end_temp - start_temp;
163 num_samplers = end_sampler - start_sampler;
164
165 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
166 if (!ureg)
167 return NULL;
168
169 if (declare_input) {
170 in[0] = ureg_DECL_fs_input(ureg,
171 TGSI_SEMANTIC_POSITION,
172 0,
173 TGSI_INTERPOLATE_LINEAR);
174 in[1] = ureg_DECL_fs_input(ureg,
175 TGSI_SEMANTIC_GENERIC,
176 0,
177 TGSI_INTERPOLATE_PERSPECTIVE);
178 }
179
180 /* we always have a color output */
181 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
182
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);
187 }
188
189 }
190
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);
195 }
196 }
197
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);
202 }
203 }
204
205 while (current_shader < num_shaders) {
206 if ((current_shader + 1) == num_shaders) {
207 shaders[current_shader]->func(ureg,
208 &out,
209 in,
210 sampler,
211 temp,
212 constant);
213 } else {
214 shaders[current_shader]->func(ureg,
215 &temp[0],
216 in,
217 sampler,
218 temp,
219 constant);
220 }
221 current_shader++;
222 }
223
224 ureg_END(ureg);
225
226 shader->tokens = ureg_finalize(ureg);
227 if(!shader->tokens)
228 return NULL;
229
230 p = pipe->create_fs_state(pipe, shader);
231 ureg_destroy(ureg);
232
233 if (num_temps >= 1) {
234 for (i = start_temp; i < end_temp; i++) {
235 ureg_release_temporary(ureg, temp[i]);
236 }
237 }
238
239 if (temp)
240 free(temp);
241 if (constant)
242 free(constant);
243 if (sampler)
244 free(sampler);
245
246 return p;
247 }
248
249 static void *
250 create_shader(struct pipe_context *pipe,
251 int id,
252 struct pipe_shader_state *shader)
253 {
254 int idx = 0, sh;
255 const struct shader_asm_info * shaders[SHADER_STAGES];
256
257 /* first stage */
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);
266 idx++;
267 break;
268 default:
269 break;
270 }
271
272 /* second stage */
273 sh = SHADERS_GET_IMAGE_SHADER(id);
274 switch (sh) {
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);
280 idx++;
281 break;
282 default:
283 break;
284 }
285
286 /* sanity check */
287 assert(idx == ((!sh || sh == VEGA_IMAGE_NORMAL_SHADER) ? 1 : 2));
288
289 /* third stage */
290 sh = SHADERS_GET_COLOR_TRANSFORM_SHADER(id);
291 switch (sh) {
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);
296 idx++;
297 break;
298 default:
299 break;
300 }
301
302 /* fourth stage */
303 sh = SHADERS_GET_MASK_SHADER(id);
304 switch (sh) {
305 case VEGA_MASK_SHADER:
306 shaders[idx] = &shaders_mask_asm[(sh >> SHADERS_MASK_SHIFT) - 1];
307 assert(shaders[idx]->id == sh);
308 idx++;
309 break;
310 default:
311 break;
312 }
313
314 /* fifth stage */
315 sh = SHADERS_GET_BLEND_SHADER(id);
316 switch (sh) {
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);
323 idx++;
324 break;
325 default:
326 break;
327 }
328
329 /* sixth stage */
330 sh = SHADERS_GET_PREMULTIPLY_SHADER(id);
331 switch (sh) {
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);
337 idx++;
338 break;
339 default:
340 break;
341 }
342
343 /* seventh stage */
344 sh = SHADERS_GET_BW_SHADER(id);
345 switch (sh) {
346 case VEGA_BW_SHADER:
347 shaders[idx] = &shaders_bw_asm[(sh >> SHADERS_BW_SHIFT) - 1];
348 assert(shaders[idx]->id == sh);
349 idx++;
350 break;
351 default:
352 break;
353 }
354
355 return combine_shaders(shaders, idx, pipe, shader);
356 }
357
358 /*************************************************/
359
360 struct shaders_cache * shaders_cache_create(struct vg_context *vg)
361 {
362 struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache);
363
364 sc->pipe = vg;
365 sc->hash = cso_hash_create();
366
367 return sc;
368 }
369
370 void shaders_cache_destroy(struct shaders_cache *sc)
371 {
372 struct cso_hash_iter iter = cso_hash_first_node(sc->hash);
373
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);
380 }
381
382 cso_hash_delete(sc->hash);
383 FREE(sc);
384 }
385
386 void * shaders_cache_fill(struct shaders_cache *sc,
387 int shader_key)
388 {
389 VGint key = shader_key;
390 struct cached_shader *cached;
391 struct cso_hash_iter iter = cso_hash_find(sc->hash, key);
392
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);
396
397 cso_hash_insert(sc->hash, key, cached);
398
399 return cached->driver_shader;
400 }
401
402 cached = (struct cached_shader *)cso_hash_iter_data(iter);
403
404 assert(cached->driver_shader);
405 return cached->driver_shader;
406 }
407
408 struct vg_shader * shader_create_from_text(struct pipe_context *pipe,
409 const char *txt, int num_tokens,
410 int type)
411 {
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;
416
417 debug_assert(type == PIPE_SHADER_VERTEX ||
418 type == PIPE_SHADER_FRAGMENT);
419
420 state.tokens = tokens;
421 shader->type = type;
422 shader->tokens = tokens;
423
424 if (type == PIPE_SHADER_FRAGMENT)
425 shader->driver = pipe->create_fs_state(pipe, &state);
426 else
427 shader->driver = pipe->create_vs_state(pipe, &state);
428 return shader;
429 }
430
431 void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader)
432 {
433 if (shader->type == PIPE_SHADER_FRAGMENT)
434 cso_delete_fragment_shader(ctx->cso_context, shader->driver);
435 else
436 cso_delete_vertex_shader(ctx->cso_context, shader->driver);
437 FREE(shader->tokens);
438 FREE(shader);
439 }