shaders_cache.c revision 213e288e78bf5b0fb0a996cc17dfd959756c2c53
1be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver/**************************************************************************
2be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *
3be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * Copyright 2009 VMware, Inc.  All Rights Reserved.
4be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *
5be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * Permission is hereby granted, free of charge, to any person obtaining a
6be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * copy of this software and associated documentation files (the
7be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * "Software"), to deal in the Software without restriction, including
8be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * without limitation the rights to use, copy, modify, merge, publish,
9be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * distribute, sub license, and/or sell copies of the Software, and to
10be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * permit persons to whom the Software is furnished to do so, subject to
11be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * the following conditions:
12be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *
13be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * The above copyright notice and this permission notice (including the
14be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * next paragraph) shall be included in all copies or substantial portions
15be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * of the Software.
16be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *
17be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver *
25be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver **************************************************************************/
26be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
27be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "shaders_cache.h"
28be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
29be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "vg_context.h"
30be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
31be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "pipe/p_context.h"
32be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "pipe/p_defines.h"
33be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "pipe/p_shader_tokens.h"
3484c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver
3536e2ee200517b36652a6e8fe1c5aa24ce249765eBen Gruver#include "tgsi/tgsi_build.h"
36be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "tgsi/tgsi_dump.h"
377c71ad420dbdfe2e36f205d335a261435181a25bBen Gruver#include "tgsi/tgsi_parse.h"
38be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "tgsi/tgsi_util.h"
39be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "tgsi/tgsi_text.h"
408daecd0246fb0d4eb29f53ab4ef99b506d395401Ben Gruver
41be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "util/u_memory.h"
42be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "util/u_math.h"
43be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "util/u_debug.h"
4425d385a441b95d56987c81f00f19297d799e1b31Ben Gruver#include "cso_cache/cso_hash.h"
45be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "cso_cache/cso_context.h"
46be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
47be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "VG/openvg.h"
487c71ad420dbdfe2e36f205d335a261435181a25bBen Gruver
49be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#include "asm_fill.h"
50be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
518daecd0246fb0d4eb29f53ab4ef99b506d395401Ben Gruver/* Essentially we construct an ubber-shader based on the state
5284c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver * of the pipeline. The stages are:
53be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 1) Paint generation (color/gradient/pattern)
54be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 2) Image composition (normal/multiply/stencil)
55be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 3) Mask
5684c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver * 4) Extended blend (multiply/screen/darken/lighten)
57be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 5) Premultiply/Unpremultiply
58be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver * 6) Color transform (to black and white)
59be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver */
6036e2ee200517b36652a6e8fe1c5aa24ce249765eBen Gruver#define SHADER_STAGES 6
61be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
62be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverstruct cached_shader {
63be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver   void *driver_shader;
6484c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver   struct pipe_shader_state state;
6584c1762a62d7fc6638432c6c56e0422aa8cc6939Ben Gruver};
66be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
67be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverstruct shaders_cache {
68be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver   struct vg_context *pipe;
698daecd0246fb0d4eb29f53ab4ef99b506d395401Ben Gruver
707c71ad420dbdfe2e36f205d335a261435181a25bBen Gruver   struct cso_hash *hash;
71be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver};
72be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
73be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
74be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruverstatic INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens)
75be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver{
76be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver   struct tgsi_token *tokens;
77be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
78be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver   tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0]));
79be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
80be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver   tgsi_text_translate(txt, tokens, num_tokens);
81be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
82be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#if DEBUG_SHADERS
83be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver   tgsi_dump(tokens, 0);
84be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver#endif
85be799799ff8bbc5d86f8cfdc850947ab4f41695fBen Gruver
86   return tokens;
87}
88
89/*
90static const char max_shader_preamble[] =
91   "FRAG\n"
92   "DCL IN[0], POSITION, LINEAR\n"
93   "DCL IN[1], GENERIC[0], PERSPECTIVE\n"
94   "DCL OUT[0], COLOR, CONSTANT\n"
95   "DCL CONST[0..9], CONSTANT\n"
96   "DCL TEMP[0..9], CONSTANT\n"
97   "DCL SAMP[0..9], CONSTANT\n";
98
99   max_shader_preamble strlen == 175
100*/
101#define MAX_PREAMBLE 175
102
103static INLINE VGint range_min(VGint min, VGint current)
104{
105   if (min < 0)
106      min = current;
107   else
108      min = MIN2(min, current);
109   return min;
110}
111
112static INLINE VGint range_max(VGint max, VGint current)
113{
114   return MAX2(max, current);
115}
116
117static void *
118combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders,
119                struct pipe_context *pipe,
120                struct pipe_shader_state *shader)
121{
122   VGboolean declare_input = VG_FALSE;
123   VGint start_const   = -1, end_const   = 0;
124   VGint start_temp    = -1, end_temp    = 0;
125   VGint start_sampler = -1, end_sampler = 0;
126   VGint i, current_shader = 0;
127   VGint num_consts, num_temps, num_samplers;
128   struct ureg_program *ureg;
129   struct ureg_src in[2];
130   struct ureg_src *sampler = NULL;
131   struct ureg_src *constant = NULL;
132   struct ureg_dst out, *temp = NULL;
133   void *p = NULL;
134
135   for (i = 0; i < num_shaders; ++i) {
136      if (shaders[i]->num_consts)
137         start_const = range_min(start_const, shaders[i]->start_const);
138      if (shaders[i]->num_temps)
139         start_temp = range_min(start_temp, shaders[i]->start_temp);
140      if (shaders[i]->num_samplers)
141         start_sampler = range_min(start_sampler, shaders[i]->start_sampler);
142
143      end_const = range_max(end_const, shaders[i]->start_const +
144                            shaders[i]->num_consts);
145      end_temp = range_max(end_temp, shaders[i]->start_temp +
146                            shaders[i]->num_temps);
147      end_sampler = range_max(end_sampler, shaders[i]->start_sampler +
148                            shaders[i]->num_samplers);
149      if (shaders[i]->needs_position)
150         declare_input = VG_TRUE;
151   }
152   /* if they're still unitialized, initialize them */
153   if (start_const < 0)
154      start_const = 0;
155   if (start_temp < 0)
156      start_temp = 0;
157   if (start_sampler < 0)
158       start_sampler = 0;
159
160   num_consts   = end_const   - start_const;
161   num_temps    = end_temp    - start_temp;
162   num_samplers = end_sampler - start_sampler;
163
164   ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
165   if (!ureg)
166       return NULL;
167
168   if (declare_input) {
169      in[0] = ureg_DECL_fs_input(ureg,
170                                 TGSI_SEMANTIC_POSITION,
171                                 0,
172                                 TGSI_INTERPOLATE_LINEAR);
173      in[1] = ureg_DECL_fs_input(ureg,
174                                 TGSI_SEMANTIC_GENERIC,
175                                 0,
176                                 TGSI_INTERPOLATE_PERSPECTIVE);
177   }
178
179   /* we always have a color output */
180   out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
181
182   if (num_consts >= 1) {
183      constant = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_const);
184      for (i = start_const; i < end_const; i++) {
185         constant[i] = ureg_DECL_constant(ureg, i);
186      }
187
188   }
189
190   if (num_temps >= 1) {
191      temp = (struct ureg_dst *) malloc(sizeof(struct ureg_dst) * end_temp);
192      for (i = start_temp; i < end_temp; i++) {
193         temp[i] = ureg_DECL_temporary(ureg);
194      }
195   }
196
197   if (num_samplers >= 1) {
198      sampler = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_sampler);
199      for (i = start_sampler; i < end_sampler; i++) {
200         sampler[i] = ureg_DECL_sampler(ureg, i);
201      }
202   }
203
204   while (current_shader < num_shaders) {
205      if ((current_shader + 1) == num_shaders) {
206         shaders[current_shader]->func(ureg,
207                                       &out,
208                                       in,
209                                       sampler,
210                                       temp,
211                                       constant);
212      } else {
213         shaders[current_shader]->func(ureg,
214                                      &temp[0],
215                                      in,
216                                      sampler,
217                                      temp,
218                                      constant);
219      }
220      current_shader++;
221   }
222
223   ureg_END(ureg);
224
225   shader->tokens = ureg_finalize(ureg);
226   if(!shader->tokens)
227      return NULL;
228
229   p = pipe->create_fs_state(pipe, shader);
230   ureg_destroy(ureg);
231
232   if (num_temps >= 1) {
233      for (i = start_temp; i < end_temp; i++) {
234         ureg_release_temporary(ureg, temp[i]);
235      }
236   }
237
238   if (temp)
239      free(temp);
240   if (constant)
241      free(constant);
242   if (sampler)
243      free(sampler);
244
245   return p;
246}
247
248static void *
249create_shader(struct pipe_context *pipe,
250              int id,
251              struct pipe_shader_state *shader)
252{
253   int idx = 0, sh;
254   const struct shader_asm_info * shaders[SHADER_STAGES];
255
256   /* first stage */
257   sh = SHADERS_GET_PAINT_SHADER(id);
258   switch (sh << SHADERS_PAINT_SHIFT) {
259   case VEGA_SOLID_FILL_SHADER:
260   case VEGA_LINEAR_GRADIENT_SHADER:
261   case VEGA_RADIAL_GRADIENT_SHADER:
262   case VEGA_PATTERN_SHADER:
263      shaders[idx] = &shaders_paint_asm[(sh >> SHADERS_PAINT_SHIFT) - 1];
264      assert(shaders[idx]->id == sh);
265      idx++;
266      break;
267   default:
268      break;
269   }
270
271   /* second stage */
272   sh = SHADERS_GET_IMAGE_SHADER(id);
273   switch (sh) {
274   case VEGA_IMAGE_NORMAL_SHADER:
275   case VEGA_IMAGE_MULTIPLY_SHADER:
276   case VEGA_IMAGE_STENCIL_SHADER:
277      shaders[idx] = &shaders_image_asm[(sh >> SHADERS_IMAGE_SHIFT) - 1];
278      assert(shaders[idx]->id == sh);
279      idx++;
280      break;
281   default:
282      break;
283   }
284
285   /* sanity check */
286   assert(idx == ((!sh || sh == VEGA_IMAGE_NORMAL_SHADER) ? 1 : 2));
287
288   /* third stage */
289   sh = SHADERS_GET_MASK_SHADER(id);
290   switch (sh) {
291   case VEGA_MASK_SHADER:
292      shaders[idx] = &shaders_mask_asm[(sh >> SHADERS_MASK_SHIFT) - 1];
293      assert(shaders[idx]->id == sh);
294      idx++;
295      break;
296   default:
297      break;
298   }
299
300   /* fourth stage */
301   sh = SHADERS_GET_BLEND_SHADER(id);
302   switch (sh) {
303   case VEGA_BLEND_MULTIPLY_SHADER:
304   case VEGA_BLEND_SCREEN_SHADER:
305   case VEGA_BLEND_DARKEN_SHADER:
306   case VEGA_BLEND_LIGHTEN_SHADER:
307      shaders[idx] = &shaders_blend_asm[(sh >> SHADERS_BLEND_SHIFT) - 1];
308      assert(shaders[idx]->id == sh);
309      idx++;
310      break;
311   default:
312      break;
313   }
314
315   /* fifth stage */
316   sh = SHADERS_GET_PREMULTIPLY_SHADER(id);
317   switch (sh) {
318   case VEGA_PREMULTIPLY_SHADER:
319   case VEGA_UNPREMULTIPLY_SHADER:
320      shaders[idx] = &shaders_premultiply_asm[
321         (sh >> SHADERS_PREMULTIPLY_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_BW_SHADER(id);
331   switch (sh) {
332   case VEGA_BW_SHADER:
333      shaders[idx] = &shaders_bw_asm[(sh >> SHADERS_BW_SHIFT) - 1];
334      assert(shaders[idx]->id == sh);
335      idx++;
336      break;
337   default:
338      break;
339   }
340
341   return combine_shaders(shaders, idx, pipe, shader);
342}
343
344/*************************************************/
345
346struct shaders_cache * shaders_cache_create(struct vg_context *vg)
347{
348   struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache);
349
350   sc->pipe = vg;
351   sc->hash = cso_hash_create();
352
353   return sc;
354}
355
356void shaders_cache_destroy(struct shaders_cache *sc)
357{
358   struct cso_hash_iter iter = cso_hash_first_node(sc->hash);
359
360   while (!cso_hash_iter_is_null(iter)) {
361      struct cached_shader *cached =
362         (struct cached_shader *)cso_hash_iter_data(iter);
363      cso_delete_fragment_shader(sc->pipe->cso_context,
364                                 cached->driver_shader);
365      iter = cso_hash_erase(sc->hash, iter);
366   }
367
368   cso_hash_delete(sc->hash);
369   FREE(sc);
370}
371
372void * shaders_cache_fill(struct shaders_cache *sc,
373                          int shader_key)
374{
375   VGint key = shader_key;
376   struct cached_shader *cached;
377   struct cso_hash_iter iter = cso_hash_find(sc->hash, key);
378
379   if (cso_hash_iter_is_null(iter)) {
380      cached = CALLOC_STRUCT(cached_shader);
381      cached->driver_shader = create_shader(sc->pipe->pipe, key, &cached->state);
382
383      cso_hash_insert(sc->hash, key, cached);
384
385      return cached->driver_shader;
386   }
387
388   cached = (struct cached_shader *)cso_hash_iter_data(iter);
389
390   assert(cached->driver_shader);
391   return cached->driver_shader;
392}
393
394struct vg_shader * shader_create_from_text(struct pipe_context *pipe,
395                                           const char *txt, int num_tokens,
396                                           int type)
397{
398   struct vg_shader *shader = (struct vg_shader *)MALLOC(
399      sizeof(struct vg_shader));
400   struct tgsi_token *tokens = tokens_from_assembly(txt, num_tokens);
401   struct pipe_shader_state state;
402
403   debug_assert(type == PIPE_SHADER_VERTEX ||
404                type == PIPE_SHADER_FRAGMENT);
405
406   state.tokens = tokens;
407   shader->type = type;
408   shader->tokens = tokens;
409
410   if (type == PIPE_SHADER_FRAGMENT)
411      shader->driver = pipe->create_fs_state(pipe, &state);
412   else
413      shader->driver = pipe->create_vs_state(pipe, &state);
414   return shader;
415}
416
417void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader)
418{
419   if (shader->type == PIPE_SHADER_FRAGMENT)
420      cso_delete_fragment_shader(ctx->cso_context, shader->driver);
421   else
422      cso_delete_vertex_shader(ctx->cso_context, shader->driver);
423   FREE(shader->tokens);
424   FREE(shader);
425}
426