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