shader.c revision f914cd1796845164109c837a111c39ba64852ad4
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
35#include "pipe/p_context.h"
36#include "pipe/p_screen.h"
37#include "pipe/p_state.h"
38#include "util/u_inlines.h"
39#include "util/u_memory.h"
40
41#define MAX_CONSTANTS 20
42
43struct shader {
44   struct vg_context *context;
45
46   VGboolean masking;
47   struct vg_paint *paint;
48   struct vg_image *image;
49
50   VGboolean drawing_image;
51   VGImageMode image_mode;
52
53   float constants[MAX_CONSTANTS];
54   struct pipe_resource *cbuf;
55   struct pipe_shader_state fs_state;
56   void *fs;
57};
58
59struct shader * shader_create(struct vg_context *ctx)
60{
61   struct shader *shader = 0;
62
63   shader = CALLOC_STRUCT(shader);
64   shader->context = ctx;
65
66   return shader;
67}
68
69void shader_destroy(struct shader *shader)
70{
71   FREE(shader);
72}
73
74void shader_set_masking(struct shader *shader, VGboolean set)
75{
76   shader->masking = set;
77}
78
79VGboolean shader_is_masking(struct shader *shader)
80{
81   return shader->masking;
82}
83
84void shader_set_paint(struct shader *shader, struct vg_paint *paint)
85{
86   shader->paint = paint;
87}
88
89struct vg_paint * shader_paint(struct shader *shader)
90{
91   return shader->paint;
92}
93
94
95static void setup_constant_buffer(struct shader *shader)
96{
97   struct vg_context *ctx = shader->context;
98   struct pipe_context *pipe = shader->context->pipe;
99   struct pipe_resource **cbuf = &shader->cbuf;
100   VGint param_bytes = paint_constant_buffer_size(shader->paint);
101   float temp_buf[MAX_CONSTANTS];
102
103   assert(param_bytes <= sizeof(temp_buf));
104   paint_fill_constant_buffer(shader->paint, temp_buf);
105
106   if (*cbuf == NULL ||
107       memcmp(temp_buf, shader->constants, param_bytes) != 0)
108   {
109      pipe_resource_reference(cbuf, NULL);
110
111      memcpy(shader->constants, temp_buf, param_bytes);
112      *cbuf = pipe_user_buffer_create(pipe->screen,
113                                      &shader->constants,
114                                      sizeof(shader->constants),
115				      PIPE_BIND_VERTEX_BUFFER);
116   }
117
118   ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf);
119}
120
121static VGint blend_bind_samplers(struct vg_context *ctx,
122                                 struct pipe_sampler_state **samplers,
123                                 struct pipe_sampler_view **sampler_views)
124{
125   VGBlendMode bmode = ctx->state.vg.blend_mode;
126
127   if (bmode == VG_BLEND_MULTIPLY ||
128       bmode == VG_BLEND_SCREEN ||
129       bmode == VG_BLEND_DARKEN ||
130       bmode == VG_BLEND_LIGHTEN) {
131      struct st_framebuffer *stfb = ctx->draw_buffer;
132
133      vg_prepare_blend_surface(ctx);
134
135      samplers[2] = &ctx->blend_sampler;
136      sampler_views[2] = stfb->blend_texture_view;
137
138      if (!samplers[0] || !sampler_views[0]) {
139         samplers[0] = samplers[2];
140         sampler_views[0] = sampler_views[2];
141      }
142      if (!samplers[1] || !sampler_views[1]) {
143         samplers[1] = samplers[0];
144         sampler_views[1] = sampler_views[0];
145      }
146
147      return 1;
148   }
149   return 0;
150}
151
152static void setup_samplers(struct shader *shader)
153{
154   struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
155   struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
156   struct vg_context *ctx = shader->context;
157   /* a little wonky: we use the num as a boolean that just says
158    * whether any sampler/textures have been set. the actual numbering
159    * for samplers is always the same:
160    * 0 - paint sampler/texture for gradient/pattern
161    * 1 - mask sampler/texture
162    * 2 - blend sampler/texture
163    * 3 - image sampler/texture
164    * */
165   VGint num = 0;
166
167   samplers[0] = NULL;
168   samplers[1] = NULL;
169   samplers[2] = NULL;
170   samplers[3] = NULL;
171   sampler_views[0] = NULL;
172   sampler_views[1] = NULL;
173   sampler_views[2] = NULL;
174   sampler_views[3] = NULL;
175
176   num += paint_bind_samplers(shader->paint, samplers, sampler_views);
177   num += mask_bind_samplers(samplers, sampler_views);
178   num += blend_bind_samplers(ctx, samplers, sampler_views);
179   if (shader->drawing_image && shader->image)
180      num += image_bind_samplers(shader->image, samplers, sampler_views);
181
182   if (num) {
183      cso_set_samplers(ctx->cso_context, 4, (const struct pipe_sampler_state **)samplers);
184      cso_set_fragment_sampler_views(ctx->cso_context, 4, sampler_views);
185   }
186}
187
188static INLINE VGboolean is_format_bw(struct shader *shader)
189{
190#if 0
191   struct vg_context *ctx = shader->context;
192   struct st_framebuffer *stfb = ctx->draw_buffer;
193#endif
194
195   if (shader->drawing_image && shader->image) {
196      if (shader->image->format == VG_BW_1)
197         return VG_TRUE;
198   }
199
200   return VG_FALSE;
201}
202
203static void setup_shader_program(struct shader *shader)
204{
205   struct vg_context *ctx = shader->context;
206   VGint shader_id = 0;
207   VGBlendMode blend_mode = ctx->state.vg.blend_mode;
208   VGboolean black_white = is_format_bw(shader);
209
210   /* 1st stage: fill */
211   if (!shader->drawing_image ||
212       (shader->image_mode == VG_DRAW_IMAGE_MULTIPLY || shader->image_mode == VG_DRAW_IMAGE_STENCIL)) {
213      switch(paint_type(shader->paint)) {
214      case VG_PAINT_TYPE_COLOR:
215         shader_id |= VEGA_SOLID_FILL_SHADER;
216         break;
217      case VG_PAINT_TYPE_LINEAR_GRADIENT:
218         shader_id |= VEGA_LINEAR_GRADIENT_SHADER;
219         break;
220      case VG_PAINT_TYPE_RADIAL_GRADIENT:
221         shader_id |= VEGA_RADIAL_GRADIENT_SHADER;
222         break;
223      case VG_PAINT_TYPE_PATTERN:
224         shader_id |= VEGA_PATTERN_SHADER;
225         break;
226
227      default:
228         abort();
229      }
230   }
231
232   /* second stage image */
233   if (shader->drawing_image) {
234      switch(shader->image_mode) {
235      case VG_DRAW_IMAGE_NORMAL:
236         shader_id |= VEGA_IMAGE_NORMAL_SHADER;
237         break;
238      case VG_DRAW_IMAGE_MULTIPLY:
239         shader_id |= VEGA_IMAGE_MULTIPLY_SHADER;
240         break;
241      case VG_DRAW_IMAGE_STENCIL:
242         shader_id |= VEGA_IMAGE_STENCIL_SHADER;
243         break;
244      default:
245         debug_printf("Unknown image mode!");
246      }
247   }
248
249   if (shader->masking)
250      shader_id |= VEGA_MASK_SHADER;
251
252   switch(blend_mode) {
253   case VG_BLEND_MULTIPLY:
254      shader_id |= VEGA_BLEND_MULTIPLY_SHADER;
255      break;
256   case VG_BLEND_SCREEN:
257      shader_id |= VEGA_BLEND_SCREEN_SHADER;
258      break;
259   case VG_BLEND_DARKEN:
260      shader_id |= VEGA_BLEND_DARKEN_SHADER;
261      break;
262   case VG_BLEND_LIGHTEN:
263      shader_id |= VEGA_BLEND_LIGHTEN_SHADER;
264      break;
265   default:
266      /* handled by pipe_blend_state */
267      break;
268   }
269
270   if (black_white)
271      shader_id |= VEGA_BW_SHADER;
272
273   shader->fs = shaders_cache_fill(ctx->sc, shader_id);
274   cso_set_fragment_shader_handle(ctx->cso_context, shader->fs);
275}
276
277
278void shader_bind(struct shader *shader)
279{
280   /* first resolve the real paint type */
281   paint_resolve_type(shader->paint);
282
283   setup_constant_buffer(shader);
284   setup_samplers(shader);
285   setup_shader_program(shader);
286}
287
288void shader_set_image_mode(struct shader *shader, VGImageMode image_mode)
289{
290   shader->image_mode = image_mode;
291}
292
293VGImageMode shader_image_mode(struct shader *shader)
294{
295   return shader->image_mode;
296}
297
298void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image)
299{
300   shader->drawing_image = drawing_image;
301}
302
303VGboolean shader_drawing_image(struct shader *shader)
304{
305   return shader->drawing_image;
306}
307
308void shader_set_image(struct shader *shader, struct vg_image *img)
309{
310   shader->image = img;
311}
312