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