Tizen 2.0 Release
[profile/ivi/osmesa.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_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
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
74 void shader_destroy(struct shader *shader)
75 {
76    FREE(shader);
77 }
78
79 void shader_set_color_transform(struct shader *shader, VGboolean set)
80 {
81    shader->color_transform = set;
82 }
83
84 void shader_set_masking(struct shader *shader, VGboolean set)
85 {
86    shader->masking = set;
87 }
88
89 VGboolean shader_is_masking(struct shader *shader)
90 {
91    return shader->masking;
92 }
93
94 void shader_set_paint(struct shader *shader, struct vg_paint *paint)
95 {
96    shader->paint = paint;
97 }
98
99 struct vg_paint * shader_paint(struct shader *shader)
100 {
101    return shader->paint;
102 }
103
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
130 static VGboolean blend_use_shader(struct vg_context *ctx)
131 {
132    VGboolean advanced_blending;
133
134    switch (ctx->state.vg.blend_mode) {
135    case VG_BLEND_SRC_OVER:
136       advanced_blending =
137          (!paint_is_opaque(ctx->state.vg.fill_paint) ||
138           !paint_is_opaque(ctx->state.vg.stroke_paint)) &&
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 }