Merge branch '7.8'
[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 "util/u_inlines.h"
34 #include "pipe/p_screen.h"
35 #include "pipe/p_shader_tokens.h"
36
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"
42
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"
48
49 #include "VG/openvg.h"
50
51 #include "asm_fill.h"
52
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)
57 * 3) Mask
58 * 4) Extended blend (multiply/screen/darken/lighten)
59 * 5) Premultiply/Unpremultiply
60 * 6) Color transform (to black and white)
61 */
62 #define SHADER_STAGES 6
63
64 struct cached_shader {
65 void *driver_shader;
66 struct pipe_shader_state state;
67 };
68
69 struct shaders_cache {
70 struct vg_context *pipe;
71
72 struct cso_hash *hash;
73 };
74
75
76 static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens)
77 {
78 struct tgsi_token *tokens;
79
80 tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0]));
81
82 tgsi_text_translate(txt, tokens, num_tokens);
83
84 #if DEBUG_SHADERS
85 tgsi_dump(tokens, 0);
86 #endif
87
88 return tokens;
89 }
90
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)
96
97
98 /*
99 static const char max_shader_preamble[] =
100 "FRAG\n"
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";
107
108 max_shader_preamble strlen == 175
109 */
110 #define MAX_PREAMBLE 175
111
112 static INLINE VGint range_min(VGint min, VGint current)
113 {
114 if (min < 0)
115 min = current;
116 else
117 min = MIN2(min, current);
118 return min;
119 }
120
121 static INLINE VGint range_max(VGint max, VGint current)
122 {
123 return MAX2(max, current);
124 }
125
126 static void *
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)
130 {
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;
142 void *p = NULL;
143
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);
151
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;
160 }
161 /* if they're still unitialized, initialize them */
162 if (start_const < 0)
163 start_const = 0;
164 if (start_temp < 0)
165 start_temp = 0;
166 if (start_sampler < 0)
167 start_sampler = 0;
168
169 num_consts = end_const - start_const;
170 num_temps = end_temp - start_temp;
171 num_samplers = end_sampler - start_sampler;
172
173 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
174 if (!ureg)
175 return NULL;
176
177 if (declare_input) {
178 in[0] = ureg_DECL_fs_input(ureg,
179 TGSI_SEMANTIC_POSITION,
180 0,
181 TGSI_INTERPOLATE_LINEAR);
182 in[1] = ureg_DECL_fs_input(ureg,
183 TGSI_SEMANTIC_GENERIC,
184 0,
185 TGSI_INTERPOLATE_PERSPECTIVE);
186 }
187
188 /* we always have a color output */
189 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
190
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);
195 }
196
197 }
198
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);
203 }
204 }
205
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);
210 }
211 }
212
213 while (current_shader < num_shaders) {
214 if ((current_shader + 1) == num_shaders) {
215 shaders[current_shader]->func(ureg,
216 &out,
217 in,
218 sampler,
219 temp,
220 constant);
221 } else {
222 shaders[current_shader]->func(ureg,
223 &temp[0],
224 in,
225 sampler,
226 temp,
227 constant);
228 }
229 current_shader++;
230 }
231
232 ureg_END(ureg);
233
234 shader->tokens = ureg_finalize(ureg);
235 if(!shader->tokens)
236 return NULL;
237
238 p = pipe->create_fs_state(pipe, shader);
239 ureg_destroy(ureg);
240
241 if (num_temps >= 1) {
242 for (i = start_temp; i < end_temp; i++) {
243 ureg_release_temporary(ureg, temp[i]);
244 }
245 }
246
247 if (temp)
248 free(temp);
249 if (constant)
250 free(constant);
251 if (sampler)
252 free(sampler);
253
254 return p;
255 }
256
257 static void *
258 create_shader(struct pipe_context *pipe,
259 int id,
260 struct pipe_shader_state *shader)
261 {
262 int idx = 0;
263 const struct shader_asm_info * shaders[SHADER_STAGES];
264
265 /* the shader has to have a fill */
266 debug_assert(id & ALL_FILLS);
267
268 /* first stage */
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);
273 ++idx;
274 }
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);
279 ++idx;
280 }
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);
285 ++idx;
286 }
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];
291 ++idx;
292 }
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];
297 ++idx;
298 }
299
300 /* second stage */
301 if ((id & VEGA_IMAGE_MULTIPLY_SHADER)) {
302 debug_assert(shaders_asm[5].id == VEGA_IMAGE_MULTIPLY_SHADER);
303 shaders[idx] = &shaders_asm[5];
304 ++idx;
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];
308 ++idx;
309 }
310
311 /* third stage */
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];
316 ++idx;
317 }
318
319 /* fourth stage */
320 if ((id & VEGA_BLEND_MULTIPLY_SHADER)) {
321 debug_assert(shaders_asm[8].id == VEGA_BLEND_MULTIPLY_SHADER);
322 shaders[idx] = &shaders_asm[8];
323 ++idx;
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];
327 ++idx;
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];
331 ++idx;
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];
335 ++idx;
336 }
337
338 /* fifth stage */
339 if ((id & VEGA_PREMULTIPLY_SHADER)) {
340 debug_assert(shaders_asm[12].id == VEGA_PREMULTIPLY_SHADER);
341 shaders[idx] = &shaders_asm[12];
342 ++idx;
343 } else if ((id & VEGA_UNPREMULTIPLY_SHADER)) {
344 debug_assert(shaders_asm[13].id == VEGA_UNPREMULTIPLY_SHADER);
345 shaders[idx] = &shaders_asm[13];
346 ++idx;
347 }
348
349 /* sixth stage */
350 if ((id & VEGA_BW_SHADER)) {
351 debug_assert(shaders_asm[14].id == VEGA_BW_SHADER);
352 shaders[idx] = &shaders_asm[14];
353 ++idx;
354 }
355
356 return combine_shaders(shaders, idx, pipe, shader);
357 }
358
359 /*************************************************/
360
361 struct shaders_cache * shaders_cache_create(struct vg_context *vg)
362 {
363 struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache);
364
365 sc->pipe = vg;
366 sc->hash = cso_hash_create();
367
368 return sc;
369 }
370
371 void shaders_cache_destroy(struct shaders_cache *sc)
372 {
373 struct cso_hash_iter iter = cso_hash_first_node(sc->hash);
374
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);
381 }
382
383 cso_hash_delete(sc->hash);
384 free(sc);
385 }
386
387 void * shaders_cache_fill(struct shaders_cache *sc,
388 int shader_key)
389 {
390 VGint key = shader_key;
391 struct cached_shader *cached;
392 struct cso_hash_iter iter = cso_hash_find(sc->hash, key);
393
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);
397
398 cso_hash_insert(sc->hash, key, cached);
399
400 return cached->driver_shader;
401 }
402
403 cached = (struct cached_shader *)cso_hash_iter_data(iter);
404
405 assert(cached->driver_shader);
406 return cached->driver_shader;
407 }
408
409 struct vg_shader * shader_create_from_text(struct pipe_context *pipe,
410 const char *txt, int num_tokens,
411 int type)
412 {
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;
417
418 debug_assert(type == PIPE_SHADER_VERTEX ||
419 type == PIPE_SHADER_FRAGMENT);
420
421 state.tokens = tokens;
422 shader->type = type;
423 shader->tokens = tokens;
424
425 if (type == PIPE_SHADER_FRAGMENT)
426 shader->driver = pipe->create_fs_state(pipe, &state);
427 else
428 shader->driver = pipe->create_vs_state(pipe, &state);
429 return shader;
430 }
431
432 void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader)
433 {
434 if (shader->type == PIPE_SHADER_FRAGMENT)
435 cso_delete_fragment_shader(ctx->cso_context, shader->driver);
436 else
437 cso_delete_vertex_shader(ctx->cso_context, shader->driver);
438 free(shader->tokens);
439 free(shader);
440 }