shaders_cache.c revision e360f91f152615b35857a4d008d0439a3c3285a8
12d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines/**************************************************************************
2effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov *
32d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * Copyright 2009 VMware, Inc.  All Rights Reserved.
4effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov *
52d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * Permission is hereby granted, free of charge, to any person obtaining a
6effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * copy of this software and associated documentation files (the
72d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * "Software"), to deal in the Software without restriction, including
8effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * without limitation the rights to use, copy, modify, merge, publish,
9effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * distribute, sub license, and/or sell copies of the Software, and to
102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * permit persons to whom the Software is furnished to do so, subject to
11effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * the following conditions:
122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines *
13effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * The above copyright notice and this permission notice (including the
142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * next paragraph) shall be included in all copies or substantial portions
15effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * of the Software.
162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines *
17effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov *
252d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines **************************************************************************/
26effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov
272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "shaders_cache.h"
28effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov
29effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov#include "vg_context.h"
302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "pipe/p_context.h"
32effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov#include "pipe/p_defines.h"
33effdc7e483708cfa4dc597c21f246c5dbc09daa0Evgeniy Stepanov#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
63struct cached_shader {
64   void *driver_shader;
65   struct pipe_shader_state state;
66};
67
68struct shaders_cache {
69   struct vg_context *pipe;
70
71   struct cso_hash *hash;
72};
73
74
75static 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/*
91static 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
104static 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
113static INLINE VGint range_max(VGint max, VGint current)
114{
115   return MAX2(max, current);
116}
117
118static void *
119combine_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
249static void *
250create_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
360struct 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
370void 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
386void * 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
408struct 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
431void 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}
440