shader.c revision 0ee73edeccd21034e03e9e43dd0d09fa6fbf7842
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 "shader.h"
28
29#include "vg_context.h"
30#include "shaders_cache.h"
31#include "paint.h"
32#include "mask.h"
33#include "image.h"
34#include "renderer.h"
35
36#include "pipe/p_context.h"
37#include "pipe/p_screen.h"
38#include "pipe/p_state.h"
39#include "util/u_inlines.h"
40#include "util/u_memory.h"
41#include "util/u_math.h"
42
43#define MAX_CONSTANTS 28
44
45struct shader {
46   struct vg_context *context;
47
48   VGboolean color_transform;
49   VGboolean masking;
50   struct vg_paint *paint;
51   struct vg_image *image;
52
53   struct matrix modelview;
54   struct matrix paint_matrix;
55
56   VGboolean drawing_image;
57   VGImageMode image_mode;
58
59   float constants[MAX_CONSTANTS];
60   struct pipe_resource *cbuf;
61   struct pipe_shader_state fs_state;
62   void *fs;
63};
64
65struct shader * shader_create(struct vg_context *ctx)
66{
67   struct shader *shader = 0;
68
69   shader = CALLOC_STRUCT(shader);
70   shader->context = ctx;
71
72   return shader;
73}
74
75void shader_destroy(struct shader *shader)
76{
77   FREE(shader);
78}
79
80void shader_set_color_transform(struct shader *shader, VGboolean set)
81{
82   shader->color_transform = set;
83}
84
85void shader_set_masking(struct shader *shader, VGboolean set)
86{
87   shader->masking = set;
88}
89
90VGboolean shader_is_masking(struct shader *shader)
91{
92   return shader->masking;
93}
94
95void shader_set_paint(struct shader *shader, struct vg_paint *paint)
96{
97   shader->paint = paint;
98}
99
100struct vg_paint * shader_paint(struct shader *shader)
101{
102   return shader->paint;
103}
104
105static VGint setup_constant_buffer(struct shader *shader)
106{
107   const struct vg_state *state = &shader->context->state.vg;
108   VGint param_bytes = paint_constant_buffer_size(shader->paint);
109   VGint i;
110
111   param_bytes += sizeof(VGfloat) * 8;
112   assert(param_bytes <= sizeof(shader->constants));
113
114   if (state->color_transform) {
115      for (i = 0; i < 8; i++) {
116         VGfloat val = (i < 4) ? 127.0f : 1.0f;
117         shader->constants[i] =
118            CLAMP(state->color_transform_values[i], -val, val);
119      }
120   }
121   else {
122      memset(shader->constants, 0, sizeof(VGfloat) * 8);
123   }
124
125   paint_fill_constant_buffer(shader->paint,
126         &shader->paint_matrix, shader->constants + 8);
127
128   return param_bytes;
129}
130
131static VGboolean blend_use_shader(struct vg_context *ctx)
132{
133   VGboolean advanced_blending;
134
135   switch (ctx->state.vg.blend_mode) {
136   case VG_BLEND_MULTIPLY:
137   case VG_BLEND_SCREEN:
138   case VG_BLEND_DARKEN:
139   case VG_BLEND_LIGHTEN:
140      advanced_blending = VG_TRUE;
141      break;
142   default:
143      advanced_blending = VG_FALSE;
144      break;
145   }
146
147   return advanced_blending;
148}
149
150static VGint blend_bind_samplers(struct vg_context *ctx,
151                                 struct pipe_sampler_state **samplers,
152                                 struct pipe_sampler_view **sampler_views)
153{
154   if (blend_use_shader(ctx)) {
155      samplers[2] = &ctx->blend_sampler;
156      sampler_views[2] = vg_prepare_blend_surface(ctx);
157
158      if (!samplers[0] || !sampler_views[0]) {
159         samplers[0] = samplers[2];
160         sampler_views[0] = sampler_views[2];
161      }
162      if (!samplers[1] || !sampler_views[1]) {
163         samplers[1] = samplers[0];
164         sampler_views[1] = sampler_views[0];
165      }
166
167      return 1;
168   }
169   return 0;
170}
171
172static VGint setup_samplers(struct shader *shader,
173                            struct pipe_sampler_state **samplers,
174                            struct pipe_sampler_view **sampler_views)
175{
176   struct vg_context *ctx = shader->context;
177   /* a little wonky: we use the num as a boolean that just says
178    * whether any sampler/textures have been set. the actual numbering
179    * for samplers is always the same:
180    * 0 - paint sampler/texture for gradient/pattern
181    * 1 - mask sampler/texture
182    * 2 - blend sampler/texture
183    * 3 - image sampler/texture
184    * */
185   VGint num = 0;
186
187   samplers[0] = NULL;
188   samplers[1] = NULL;
189   samplers[2] = NULL;
190   samplers[3] = NULL;
191   sampler_views[0] = NULL;
192   sampler_views[1] = NULL;
193   sampler_views[2] = NULL;
194   sampler_views[3] = NULL;
195
196   num += paint_bind_samplers(shader->paint, samplers, sampler_views);
197   num += mask_bind_samplers(samplers, sampler_views);
198   num += blend_bind_samplers(ctx, samplers, sampler_views);
199   if (shader->drawing_image && shader->image)
200      num += image_bind_samplers(shader->image, samplers, sampler_views);
201
202   return (num) ? 4 : 0;
203}
204
205static INLINE VGboolean is_format_bw(struct shader *shader)
206{
207#if 0
208   struct vg_context *ctx = shader->context;
209   struct st_framebuffer *stfb = ctx->draw_buffer;
210#endif
211
212   if (shader->drawing_image && shader->image) {
213      if (shader->image->format == VG_BW_1)
214         return VG_TRUE;
215   }
216
217   return VG_FALSE;
218}
219
220static void setup_shader_program(struct shader *shader)
221{
222   struct vg_context *ctx = shader->context;
223   VGint shader_id = 0;
224   VGBlendMode blend_mode = ctx->state.vg.blend_mode;
225   VGboolean black_white = is_format_bw(shader);
226
227   /* 1st stage: fill */
228   if (!shader->drawing_image ||
229       (shader->image_mode == VG_DRAW_IMAGE_MULTIPLY || shader->image_mode == VG_DRAW_IMAGE_STENCIL)) {
230      switch(paint_type(shader->paint)) {
231      case VG_PAINT_TYPE_COLOR:
232         shader_id |= VEGA_SOLID_FILL_SHADER;
233         break;
234      case VG_PAINT_TYPE_LINEAR_GRADIENT:
235         shader_id |= VEGA_LINEAR_GRADIENT_SHADER;
236         break;
237      case VG_PAINT_TYPE_RADIAL_GRADIENT:
238         shader_id |= VEGA_RADIAL_GRADIENT_SHADER;
239         break;
240      case VG_PAINT_TYPE_PATTERN:
241         shader_id |= VEGA_PATTERN_SHADER;
242         break;
243
244      default:
245         abort();
246      }
247
248      if (paint_is_degenerate(shader->paint))
249         shader_id = VEGA_PAINT_DEGENERATE_SHADER;
250   }
251
252   /* second stage image */
253   if (shader->drawing_image) {
254      switch(shader->image_mode) {
255      case VG_DRAW_IMAGE_NORMAL:
256         shader_id |= VEGA_IMAGE_NORMAL_SHADER;
257         break;
258      case VG_DRAW_IMAGE_MULTIPLY:
259         shader_id |= VEGA_IMAGE_MULTIPLY_SHADER;
260         break;
261      case VG_DRAW_IMAGE_STENCIL:
262         shader_id |= VEGA_IMAGE_STENCIL_SHADER;
263         break;
264      default:
265         debug_printf("Unknown image mode!");
266      }
267   }
268
269   if (shader->color_transform)
270      shader_id |= VEGA_COLOR_TRANSFORM_SHADER;
271
272   if (blend_use_shader(ctx)) {
273      if (shader->drawing_image && shader->image_mode == VG_DRAW_IMAGE_STENCIL)
274         shader_id |= VEGA_ALPHA_PER_CHANNEL_SHADER;
275      else
276         shader_id |= VEGA_ALPHA_NORMAL_SHADER;
277
278      switch(blend_mode) {
279      case VG_BLEND_SRC:
280         shader_id |= VEGA_BLEND_SRC_SHADER;
281         break;
282      case VG_BLEND_SRC_OVER:
283         shader_id |= VEGA_BLEND_SRC_OVER_SHADER;
284         break;
285      case VG_BLEND_DST_OVER:
286         shader_id |= VEGA_BLEND_DST_OVER_SHADER;
287         break;
288      case VG_BLEND_SRC_IN:
289         shader_id |= VEGA_BLEND_SRC_IN_SHADER;
290         break;
291      case VG_BLEND_DST_IN:
292         shader_id |= VEGA_BLEND_DST_IN_SHADER;
293         break;
294      case VG_BLEND_MULTIPLY:
295         shader_id |= VEGA_BLEND_MULTIPLY_SHADER;
296         break;
297      case VG_BLEND_SCREEN:
298         shader_id |= VEGA_BLEND_SCREEN_SHADER;
299         break;
300      case VG_BLEND_DARKEN:
301         shader_id |= VEGA_BLEND_DARKEN_SHADER;
302         break;
303      case VG_BLEND_LIGHTEN:
304         shader_id |= VEGA_BLEND_LIGHTEN_SHADER;
305         break;
306      case VG_BLEND_ADDITIVE:
307         shader_id |= VEGA_BLEND_ADDITIVE_SHADER;
308         break;
309      default:
310         assert(0);
311         break;
312      }
313   }
314   else {
315      /* update alpha of the source */
316      if (shader->drawing_image && shader->image_mode == VG_DRAW_IMAGE_STENCIL)
317         shader_id |= VEGA_ALPHA_PER_CHANNEL_SHADER;
318   }
319
320   if (shader->masking)
321      shader_id |= VEGA_MASK_SHADER;
322
323   if (black_white)
324      shader_id |= VEGA_BW_SHADER;
325
326   shader->fs = shaders_cache_fill(ctx->sc, shader_id);
327}
328
329
330void shader_bind(struct shader *shader)
331{
332   struct vg_context *ctx = shader->context;
333   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
334   struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
335   VGint num_samplers, param_bytes;
336
337   /* first resolve the real paint type */
338   paint_resolve_type(shader->paint);
339
340   num_samplers = setup_samplers(shader, samplers, sampler_views);
341   param_bytes = setup_constant_buffer(shader);
342   setup_shader_program(shader);
343
344   renderer_validate_for_shader(ctx->renderer,
345         (const struct pipe_sampler_state **) samplers,
346         sampler_views, num_samplers,
347         &shader->modelview,
348         shader->fs, (const void *) shader->constants, param_bytes);
349}
350
351void shader_set_image_mode(struct shader *shader, VGImageMode image_mode)
352{
353   shader->image_mode = image_mode;
354}
355
356VGImageMode shader_image_mode(struct shader *shader)
357{
358   return shader->image_mode;
359}
360
361void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image)
362{
363   shader->drawing_image = drawing_image;
364}
365
366VGboolean shader_drawing_image(struct shader *shader)
367{
368   return shader->drawing_image;
369}
370
371void shader_set_image(struct shader *shader, struct vg_image *img)
372{
373   shader->image = img;
374}
375
376/**
377 * Set the transformation to map a vertex to the surface coordinates.
378 */
379void shader_set_surface_matrix(struct shader *shader,
380                               const struct matrix *mat)
381{
382   shader->modelview = *mat;
383}
384
385/**
386 * Set the transformation to map a pixel to the paint coordinates.
387 */
388void shader_set_paint_matrix(struct shader *shader, const struct matrix *mat)
389{
390   const struct st_framebuffer *stfb = shader->context->draw_buffer;
391   const VGfloat px_center_offset = 0.5f;
392
393   memcpy(&shader->paint_matrix, mat, sizeof(*mat));
394
395   /* make it window-to-paint for the shaders */
396   matrix_translate(&shader->paint_matrix, px_center_offset,
397         stfb->height - 1.0f + px_center_offset);
398   matrix_scale(&shader->paint_matrix, 1.0f, -1.0f);
399}
400