Squashed commit of the following:
[profile/ivi/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
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
43 struct 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
59 struct 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
69 void shader_destroy(struct shader *shader)
70 {
71    free(shader);
72 }
73
74 void shader_set_masking(struct shader *shader, VGboolean set)
75 {
76    shader->masking = set;
77 }
78
79 VGboolean shader_is_masking(struct shader *shader)
80 {
81    return shader->masking;
82 }
83
84 void shader_set_paint(struct shader *shader, struct vg_paint *paint)
85 {
86    shader->paint = paint;
87 }
88
89 struct vg_paint * shader_paint(struct shader *shader)
90 {
91    return shader->paint;
92 }
93
94
95 static 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
121 static 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
152 static 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
188 static 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
203 static 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
278 void 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
288 void shader_set_image_mode(struct shader *shader, VGImageMode image_mode)
289 {
290    shader->image_mode = image_mode;
291 }
292
293 VGImageMode shader_image_mode(struct shader *shader)
294 {
295    return shader->image_mode;
296 }
297
298 void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image)
299 {
300    shader->drawing_image = drawing_image;
301 }
302
303 VGboolean shader_drawing_image(struct shader *shader)
304 {
305    return shader->drawing_image;
306 }
307
308 void shader_set_image(struct shader *shader, struct vg_image *img)
309 {
310    shader->image = img;
311 }