shaders_cache.c revision 2d8e70fcd57b23786e3f4196f35440ed1861a98b
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
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#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/*
99static 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
112static 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
121static INLINE VGint range_max(VGint max, VGint current)
122{
123   return MAX2(max, current);
124}
125
126static void *
127combine_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
257static void *
258create_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
361struct 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
371void 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
387void * 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
409struct 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
432void 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}
441