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) Per-channel alpha generation
57 * 5) Extended blend (multiply/screen/darken/lighten)
58 * 6) Mask
59 * 7) Premultiply/Unpremultiply
60 * 8) Color transform (to black and white)
61 */
62#define SHADER_STAGES 8
63
64struct cached_shader {
65   void *driver_shader;
66   struct pipe_shader_state state;
67};
68
69struct shaders_cache {
70   struct vg_context *pipe;
71
72   struct cso_hash *hash;
73};
74
75
76static 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/*
92static const char max_shader_preamble[] =
93   "FRAG\n"
94   "DCL IN[0], POSITION, LINEAR\n"
95   "DCL IN[1], GENERIC[0], PERSPECTIVE\n"
96   "DCL OUT[0], COLOR, CONSTANT\n"
97   "DCL CONST[0..9], CONSTANT\n"
98   "DCL TEMP[0..9], CONSTANT\n"
99   "DCL SAMP[0..9], CONSTANT\n";
100
101   max_shader_preamble strlen == 175
102*/
103#define MAX_PREAMBLE 175
104
105static INLINE VGint range_min(VGint min, VGint current)
106{
107   if (min < 0)
108      min = current;
109   else
110      min = MIN2(min, current);
111   return min;
112}
113
114static INLINE VGint range_max(VGint max, VGint current)
115{
116   return MAX2(max, current);
117}
118
119static void *
120combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders,
121                struct pipe_context *pipe,
122                struct pipe_shader_state *shader)
123{
124   VGboolean declare_input = VG_FALSE;
125   VGint start_const   = -1, end_const   = 0;
126   VGint start_temp    = -1, end_temp    = 0;
127   VGint start_sampler = -1, end_sampler = 0;
128   VGint i, current_shader = 0;
129   VGint num_consts, num_temps, num_samplers;
130   struct ureg_program *ureg;
131   struct ureg_src in[2];
132   struct ureg_src *sampler = NULL;
133   struct ureg_src *constant = NULL;
134   struct ureg_dst out, *temp = NULL;
135   void *p = NULL;
136
137   for (i = 0; i < num_shaders; ++i) {
138      if (shaders[i]->num_consts)
139         start_const = range_min(start_const, shaders[i]->start_const);
140      if (shaders[i]->num_temps)
141         start_temp = range_min(start_temp, shaders[i]->start_temp);
142      if (shaders[i]->num_samplers)
143         start_sampler = range_min(start_sampler, shaders[i]->start_sampler);
144
145      end_const = range_max(end_const, shaders[i]->start_const +
146                            shaders[i]->num_consts);
147      end_temp = range_max(end_temp, shaders[i]->start_temp +
148                            shaders[i]->num_temps);
149      end_sampler = range_max(end_sampler, shaders[i]->start_sampler +
150                            shaders[i]->num_samplers);
151      if (shaders[i]->needs_position)
152         declare_input = VG_TRUE;
153   }
154   /* if they're still unitialized, initialize them */
155   if (start_const < 0)
156      start_const = 0;
157   if (start_temp < 0)
158      start_temp = 0;
159   if (start_sampler < 0)
160       start_sampler = 0;
161
162   num_consts   = end_const   - start_const;
163   num_temps    = end_temp    - start_temp;
164   num_samplers = end_sampler - start_sampler;
165
166   ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
167   if (!ureg)
168       return NULL;
169
170   if (declare_input) {
171      in[0] = ureg_DECL_fs_input(ureg,
172                                 TGSI_SEMANTIC_POSITION,
173                                 0,
174                                 TGSI_INTERPOLATE_LINEAR);
175      in[1] = ureg_DECL_fs_input(ureg,
176                                 TGSI_SEMANTIC_GENERIC,
177                                 0,
178                                 TGSI_INTERPOLATE_PERSPECTIVE);
179   }
180
181   /* we always have a color output */
182   out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
183
184   if (num_consts >= 1) {
185      constant = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_const);
186      for (i = start_const; i < end_const; i++) {
187         constant[i] = ureg_DECL_constant(ureg, i);
188      }
189
190   }
191
192   if (num_temps >= 1) {
193      temp = (struct ureg_dst *) malloc(sizeof(struct ureg_dst) * end_temp);
194      for (i = start_temp; i < end_temp; i++) {
195         temp[i] = ureg_DECL_temporary(ureg);
196      }
197   }
198
199   if (num_samplers >= 1) {
200      sampler = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_sampler);
201      for (i = start_sampler; i < end_sampler; i++) {
202         sampler[i] = ureg_DECL_sampler(ureg, i);
203      }
204   }
205
206   while (current_shader < num_shaders) {
207      if ((current_shader + 1) == num_shaders) {
208         shaders[current_shader]->func(ureg,
209                                       &out,
210                                       in,
211                                       sampler,
212                                       temp,
213                                       constant);
214      } else {
215         shaders[current_shader]->func(ureg,
216                                      &temp[0],
217                                      in,
218                                      sampler,
219                                      temp,
220                                      constant);
221      }
222      current_shader++;
223   }
224
225   ureg_END(ureg);
226
227   shader->tokens = ureg_finalize(ureg);
228   if(!shader->tokens)
229      return NULL;
230
231   p = pipe->create_fs_state(pipe, shader);
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   ureg_destroy(ureg);
240
241   if (temp)
242      free(temp);
243   if (constant)
244      free(constant);
245   if (sampler)
246      free(sampler);
247
248   return p;
249}
250
251static void *
252create_shader(struct pipe_context *pipe,
253              int id,
254              struct pipe_shader_state *shader)
255{
256   int idx = 0, sh;
257   const struct shader_asm_info * shaders[SHADER_STAGES];
258
259   /* first stage */
260   sh = SHADERS_GET_PAINT_SHADER(id);
261   switch (sh << SHADERS_PAINT_SHIFT) {
262   case VEGA_SOLID_FILL_SHADER:
263   case VEGA_LINEAR_GRADIENT_SHADER:
264   case VEGA_RADIAL_GRADIENT_SHADER:
265   case VEGA_PATTERN_SHADER:
266   case VEGA_PAINT_DEGENERATE_SHADER:
267      shaders[idx] = &shaders_paint_asm[(sh >> SHADERS_PAINT_SHIFT) - 1];
268      assert(shaders[idx]->id == sh);
269      idx++;
270      break;
271   default:
272      break;
273   }
274
275   /* second stage */
276   sh = SHADERS_GET_IMAGE_SHADER(id);
277   switch (sh) {
278   case VEGA_IMAGE_NORMAL_SHADER:
279   case VEGA_IMAGE_MULTIPLY_SHADER:
280   case VEGA_IMAGE_STENCIL_SHADER:
281      shaders[idx] = &shaders_image_asm[(sh >> SHADERS_IMAGE_SHIFT) - 1];
282      assert(shaders[idx]->id == sh);
283      idx++;
284      break;
285   default:
286      break;
287   }
288
289   /* sanity check */
290   assert(idx == ((!sh || sh == VEGA_IMAGE_NORMAL_SHADER) ? 1 : 2));
291
292   /* third stage */
293   sh = SHADERS_GET_COLOR_TRANSFORM_SHADER(id);
294   switch (sh) {
295   case VEGA_COLOR_TRANSFORM_SHADER:
296      shaders[idx] = &shaders_color_transform_asm[
297         (sh >> SHADERS_COLOR_TRANSFORM_SHIFT) - 1];
298      assert(shaders[idx]->id == sh);
299      idx++;
300      break;
301   default:
302      break;
303   }
304
305   /* fourth stage */
306   sh = SHADERS_GET_ALPHA_SHADER(id);
307   switch (sh) {
308   case VEGA_ALPHA_NORMAL_SHADER:
309   case VEGA_ALPHA_PER_CHANNEL_SHADER:
310      shaders[idx] = &shaders_alpha_asm[
311         (sh >> SHADERS_ALPHA_SHIFT) - 1];
312      assert(shaders[idx]->id == sh);
313      idx++;
314      break;
315   default:
316      break;
317   }
318
319   /* fifth stage */
320   sh = SHADERS_GET_BLEND_SHADER(id);
321   switch (sh) {
322   case VEGA_BLEND_SRC_SHADER:
323   case VEGA_BLEND_SRC_OVER_SHADER:
324   case VEGA_BLEND_DST_OVER_SHADER:
325   case VEGA_BLEND_SRC_IN_SHADER:
326   case VEGA_BLEND_DST_IN_SHADER:
327   case VEGA_BLEND_MULTIPLY_SHADER:
328   case VEGA_BLEND_SCREEN_SHADER:
329   case VEGA_BLEND_DARKEN_SHADER:
330   case VEGA_BLEND_LIGHTEN_SHADER:
331   case VEGA_BLEND_ADDITIVE_SHADER:
332      shaders[idx] = &shaders_blend_asm[(sh >> SHADERS_BLEND_SHIFT) - 1];
333      assert(shaders[idx]->id == sh);
334      idx++;
335      break;
336   default:
337      break;
338   }
339
340   /* sixth stage */
341   sh = SHADERS_GET_MASK_SHADER(id);
342   switch (sh) {
343   case VEGA_MASK_SHADER:
344      shaders[idx] = &shaders_mask_asm[(sh >> SHADERS_MASK_SHIFT) - 1];
345      assert(shaders[idx]->id == sh);
346      idx++;
347      break;
348   default:
349      break;
350   }
351
352   /* seventh stage */
353   sh = SHADERS_GET_PREMULTIPLY_SHADER(id);
354   switch (sh) {
355   case VEGA_PREMULTIPLY_SHADER:
356   case VEGA_UNPREMULTIPLY_SHADER:
357      shaders[idx] = &shaders_premultiply_asm[
358         (sh >> SHADERS_PREMULTIPLY_SHIFT) - 1];
359      assert(shaders[idx]->id == sh);
360      idx++;
361      break;
362   default:
363      break;
364   }
365
366   /* eighth stage */
367   sh = SHADERS_GET_BW_SHADER(id);
368   switch (sh) {
369   case VEGA_BW_SHADER:
370      shaders[idx] = &shaders_bw_asm[(sh >> SHADERS_BW_SHIFT) - 1];
371      assert(shaders[idx]->id == sh);
372      idx++;
373      break;
374   default:
375      break;
376   }
377
378   return combine_shaders(shaders, idx, pipe, shader);
379}
380
381/*************************************************/
382
383struct shaders_cache * shaders_cache_create(struct vg_context *vg)
384{
385   struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache);
386
387   sc->pipe = vg;
388   sc->hash = cso_hash_create();
389
390   return sc;
391}
392
393void shaders_cache_destroy(struct shaders_cache *sc)
394{
395   struct cso_hash_iter iter = cso_hash_first_node(sc->hash);
396
397   while (!cso_hash_iter_is_null(iter)) {
398      struct cached_shader *cached =
399         (struct cached_shader *)cso_hash_iter_data(iter);
400      cso_delete_fragment_shader(sc->pipe->cso_context,
401                                 cached->driver_shader);
402      iter = cso_hash_erase(sc->hash, iter);
403   }
404
405   cso_hash_delete(sc->hash);
406   FREE(sc);
407}
408
409void * shaders_cache_fill(struct shaders_cache *sc,
410                          int shader_key)
411{
412   VGint key = shader_key;
413   struct cached_shader *cached;
414   struct cso_hash_iter iter = cso_hash_find(sc->hash, key);
415
416   if (cso_hash_iter_is_null(iter)) {
417      cached = CALLOC_STRUCT(cached_shader);
418      cached->driver_shader = create_shader(sc->pipe->pipe, key, &cached->state);
419
420      cso_hash_insert(sc->hash, key, cached);
421
422      return cached->driver_shader;
423   }
424
425   cached = (struct cached_shader *)cso_hash_iter_data(iter);
426
427   assert(cached->driver_shader);
428   return cached->driver_shader;
429}
430
431struct vg_shader * shader_create_from_text(struct pipe_context *pipe,
432                                           const char *txt, int num_tokens,
433                                           int type)
434{
435   struct vg_shader *shader = (struct vg_shader *)MALLOC(
436      sizeof(struct vg_shader));
437   struct tgsi_token *tokens = tokens_from_assembly(txt, num_tokens);
438   struct pipe_shader_state state;
439
440   debug_assert(type == PIPE_SHADER_VERTEX ||
441                type == PIPE_SHADER_FRAGMENT);
442
443   state.tokens = tokens;
444   memset(&state.stream_output, 0, sizeof(state.stream_output));
445   shader->type = type;
446   shader->tokens = tokens;
447
448   if (type == PIPE_SHADER_FRAGMENT)
449      shader->driver = pipe->create_fs_state(pipe, &state);
450   else
451      shader->driver = pipe->create_vs_state(pipe, &state);
452   return shader;
453}
454
455void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader)
456{
457   if (shader->type == PIPE_SHADER_FRAGMENT)
458      cso_delete_fragment_shader(ctx->cso_context, shader->driver);
459   else
460      cso_delete_vertex_shader(ctx->cso_context, shader->driver);
461   FREE(shader->tokens);
462   FREE(shader);
463}
464