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