a643f38624fd709da57c3fcaa18a949a8e841885
[profile/ivi/mesa.git] / src / gallium / state_trackers / vega / api_filters.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 "VG/openvg.h"
28
29 #include "vg_context.h"
30 #include "image.h"
31 #include "renderer.h"
32 #include "shaders_cache.h"
33 #include "st_inlines.h"
34
35 #include "pipe/p_context.h"
36 #include "pipe/p_state.h"
37 #include "util/u_inlines.h"
38 #include "pipe/p_screen.h"
39 #include "pipe/p_shader_tokens.h"
40
41 #include "util/u_format.h"
42 #include "util/u_memory.h"
43 #include "util/u_sampler.h"
44
45
46 #include "asm_filters.h"
47
48
49 struct filter_info {
50    struct vg_image *dst;
51    struct vg_image *src;
52    struct vg_shader * (*setup_shader)(struct vg_context *, void *);
53    void *user_data;
54    const void *const_buffer;
55    VGint const_buffer_len;
56    VGTilingMode tiling_mode;
57    struct pipe_sampler_view *extra_texture_view;
58 };
59
60 static INLINE struct pipe_texture *create_texture_1d(struct vg_context *ctx,
61                                                      const VGuint *color_data,
62                                                      const VGint color_data_len)
63 {
64    struct pipe_context *pipe = ctx->pipe;
65    struct pipe_screen *screen = pipe->screen;
66    struct pipe_texture *tex = 0;
67    struct pipe_texture templ;
68
69    memset(&templ, 0, sizeof(templ));
70    templ.target = PIPE_TEXTURE_1D;
71    templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
72    templ.last_level = 0;
73    templ.width0 = color_data_len;
74    templ.height0 = 1;
75    templ.depth0 = 1;
76    templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
77
78    tex = screen->texture_create(screen, &templ);
79
80    { /* upload color_data */
81       struct pipe_transfer *transfer =
82          pipe->get_tex_transfer(pipe, tex,
83                                 0, 0, 0,
84                                 PIPE_TRANSFER_READ_WRITE ,
85                                 0, 0, tex->width0, tex->height0);
86       void *map = pipe->transfer_map(pipe, transfer);
87       memcpy(map, color_data, sizeof(VGint)*color_data_len);
88       pipe->transfer_unmap(pipe, transfer);
89       pipe->tex_transfer_destroy(pipe, transfer);
90    }
91
92    return tex;
93 }
94
95 static INLINE struct pipe_sampler_view *create_texture_1d_view(struct vg_context *ctx,
96                                                                const VGuint *color_data,
97                                                                const VGint color_data_len)
98 {
99    struct pipe_context *pipe = ctx->pipe;
100    struct pipe_texture *texture;
101    struct pipe_sampler_view view_templ;
102    struct pipe_sampler_view *view;
103
104    texture = create_texture_1d(ctx, color_data, color_data_len);
105
106    if (!texture)
107       return NULL;
108
109    u_sampler_view_default_template(&view_templ, texture, texture->format);
110    view = pipe->create_sampler_view(pipe, texture, &view_templ);
111    /* want the texture to go away if the view is freed */
112    pipe_texture_reference(&texture, NULL);
113
114    return view;
115 }
116
117 static INLINE struct pipe_surface * setup_framebuffer(struct vg_image *dst)
118 {
119    struct vg_context *ctx = vg_current_context();
120    struct pipe_context *pipe = ctx->pipe;
121    struct pipe_framebuffer_state fb;
122    struct pipe_surface *dst_surf = pipe->screen->get_tex_surface(
123       pipe->screen, dst->sampler_view->texture, 0, 0, 0,
124       PIPE_BUFFER_USAGE_GPU_WRITE);
125
126    /* drawing dest */
127    memset(&fb, 0, sizeof(fb));
128    fb.width  = dst->x + dst_surf->width;
129    fb.height = dst->y + dst_surf->height;
130    fb.nr_cbufs = 1;
131    fb.cbufs[0] = dst_surf;
132    {
133       VGint i;
134       for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
135          fb.cbufs[i] = 0;
136    }
137    cso_set_framebuffer(ctx->cso_context, &fb);
138
139    return dst_surf;
140 }
141
142 static void setup_viewport(struct vg_image *dst)
143 {
144    struct vg_context *ctx = vg_current_context();
145    vg_set_viewport(ctx, VEGA_Y0_TOP);
146 }
147
148 static void setup_blend()
149 {
150    struct vg_context *ctx = vg_current_context();
151    struct pipe_blend_state blend;
152    memset(&blend, 0, sizeof(blend));
153    blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
154    blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
155    blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
156    blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
157    if (ctx->state.vg.filter_channel_mask & VG_RED)
158       blend.rt[0].colormask |= PIPE_MASK_R;
159    if (ctx->state.vg.filter_channel_mask & VG_GREEN)
160       blend.rt[0].colormask |= PIPE_MASK_G;
161    if (ctx->state.vg.filter_channel_mask & VG_BLUE)
162       blend.rt[0].colormask |= PIPE_MASK_B;
163    if (ctx->state.vg.filter_channel_mask & VG_ALPHA)
164       blend.rt[0].colormask |= PIPE_MASK_A;
165    blend.rt[0].blend_enable = 0;
166    cso_set_blend(ctx->cso_context, &blend);
167 }
168
169 static void setup_constant_buffer(struct vg_context *ctx, const void *buffer,
170                                   VGint param_bytes)
171 {
172    struct pipe_context *pipe = ctx->pipe;
173    struct pipe_buffer **cbuf = &ctx->filter.buffer;
174
175    /* We always need to get a new buffer, to keep the drivers simple and
176     * avoid gratuitous rendering synchronization. */
177    pipe_buffer_reference(cbuf, NULL);
178
179    *cbuf = pipe_buffer_create(pipe->screen, 16,
180                               PIPE_BUFFER_USAGE_CONSTANT,
181                               param_bytes);
182
183    if (*cbuf) {
184       st_no_flush_pipe_buffer_write(ctx, *cbuf,
185                                     0, param_bytes, buffer);
186    }
187
188    ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf);
189 }
190
191 static void setup_samplers(struct vg_context *ctx, struct filter_info *info)
192 {
193    struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
194    struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
195    struct pipe_sampler_state sampler[3];
196    int num_samplers = 0;
197    int num_textures = 0;
198
199    samplers[0] = NULL;
200    samplers[1] = NULL;
201    samplers[2] = NULL;
202    samplers[3] = NULL;
203    sampler_views[0] = NULL;
204    sampler_views[1] = NULL;
205    sampler_views[2] = NULL;
206    sampler_views[3] = NULL;
207
208    memset(&sampler[0], 0, sizeof(struct pipe_sampler_state));
209    sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
210    sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
211    sampler[0].wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
212    sampler[0].min_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
213    sampler[0].mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
214    sampler[0].normalized_coords = 1;
215
216    switch(info->tiling_mode) {
217    case VG_TILE_FILL:
218       sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
219       sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
220       memcpy(sampler[0].border_color,
221              ctx->state.vg.tile_fill_color,
222              sizeof(VGfloat) * 4);
223       break;
224    case VG_TILE_PAD:
225       sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
226       sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
227       break;
228    case VG_TILE_REPEAT:
229       sampler[0].wrap_s = PIPE_TEX_WRAP_REPEAT;
230       sampler[0].wrap_t = PIPE_TEX_WRAP_REPEAT;
231       break;
232    case VG_TILE_REFLECT:
233       sampler[0].wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
234       sampler[0].wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT;
235       break;
236    default:
237       debug_assert(!"Unknown tiling mode");
238    }
239
240    samplers[0] = &sampler[0];
241    sampler_views[0] = info->src->sampler_view;
242    ++num_samplers;
243    ++num_textures;
244
245    if (info->extra_texture_view) {
246       memcpy(&sampler[1], &sampler[0], sizeof(struct pipe_sampler_state));
247       samplers[1] = &sampler[1];
248       sampler_views[1] = info->extra_texture_view;
249       ++num_samplers;
250       ++num_textures;
251    }
252
253
254    cso_set_samplers(ctx->cso_context, num_samplers, (const struct pipe_sampler_state **)samplers);
255    cso_set_fragment_sampler_views(ctx->cso_context, num_textures, sampler_views);
256 }
257
258 static struct vg_shader * setup_color_matrix(struct vg_context *ctx, void *user_data)
259 {
260    struct vg_shader *shader =
261       shader_create_from_text(ctx->pipe, color_matrix_asm, 200,
262          PIPE_SHADER_FRAGMENT);
263    cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
264    return shader;
265 }
266
267 static struct vg_shader * setup_convolution(struct vg_context *ctx, void *user_data)
268 {
269    char buffer[1024];
270    VGint num_consts = (VGint)(long)(user_data);
271    struct vg_shader *shader;
272
273    snprintf(buffer, 1023, convolution_asm, num_consts, num_consts / 2 + 1);
274
275    shader = shader_create_from_text(ctx->pipe, buffer, 200,
276                                     PIPE_SHADER_FRAGMENT);
277
278    cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
279    return shader;
280 }
281
282 static struct vg_shader * setup_lookup(struct vg_context *ctx, void *user_data)
283 {
284    struct vg_shader *shader =
285       shader_create_from_text(ctx->pipe, lookup_asm,
286                               200, PIPE_SHADER_FRAGMENT);
287
288    cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
289    return shader;
290 }
291
292
293 static struct vg_shader * setup_lookup_single(struct vg_context *ctx, void *user_data)
294 {
295    char buffer[1024];
296    VGImageChannel channel = (VGImageChannel)(user_data);
297    struct vg_shader *shader;
298
299    switch(channel) {
300    case VG_RED:
301       snprintf(buffer, 1023, lookup_single_asm, "xxxx");
302       break;
303    case VG_GREEN:
304       snprintf(buffer, 1023, lookup_single_asm, "yyyy");
305       break;
306    case VG_BLUE:
307       snprintf(buffer, 1023, lookup_single_asm, "zzzz");
308       break;
309    case VG_ALPHA:
310       snprintf(buffer, 1023, lookup_single_asm, "wwww");
311       break;
312    default:
313       debug_assert(!"Unknown color channel");
314    }
315
316    shader = shader_create_from_text(ctx->pipe, buffer, 200,
317                                     PIPE_SHADER_FRAGMENT);
318
319    cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
320    return shader;
321 }
322
323 static void execute_filter(struct vg_context *ctx,
324                            struct filter_info *info)
325 {
326    struct pipe_surface *dst_surf;
327    struct vg_shader *shader;
328
329    cso_save_framebuffer(ctx->cso_context);
330    cso_save_fragment_shader(ctx->cso_context);
331    cso_save_viewport(ctx->cso_context);
332    cso_save_blend(ctx->cso_context);
333    cso_save_samplers(ctx->cso_context);
334    cso_save_fragment_sampler_views(ctx->cso_context);
335
336    dst_surf = setup_framebuffer(info->dst);
337    setup_viewport(info->dst);
338    setup_blend();
339    setup_constant_buffer(ctx, info->const_buffer, info->const_buffer_len);
340    shader = info->setup_shader(ctx, info->user_data);
341    setup_samplers(ctx, info);
342
343    renderer_draw_texture(ctx->renderer,
344                          info->src->sampler_view->texture,
345                          info->dst->x, info->dst->y,
346                          info->dst->x + info->dst->width,
347                          info->dst->y + info->dst->height,
348                          info->dst->x, info->dst->y,
349                          info->dst->x + info->dst->width,
350                          info->dst->y + info->dst->height);
351
352    cso_restore_framebuffer(ctx->cso_context);
353    cso_restore_fragment_shader(ctx->cso_context);
354    cso_restore_viewport(ctx->cso_context);
355    cso_restore_blend(ctx->cso_context);
356    cso_restore_samplers(ctx->cso_context);
357    cso_restore_fragment_sampler_views(ctx->cso_context);
358
359    vg_shader_destroy(ctx, shader);
360
361    pipe_surface_reference(&dst_surf, NULL);
362 }
363
364 void vgColorMatrix(VGImage dst, VGImage src,
365                    const VGfloat * matrix)
366 {
367    struct vg_context *ctx = vg_current_context();
368    struct vg_image *d, *s;
369    struct filter_info info;
370
371    if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
372       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
373       return;
374    }
375    if (!matrix || !is_aligned(matrix)) {
376       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
377       return;
378    }
379
380    d = (struct vg_image*)dst;
381    s = (struct vg_image*)src;
382
383    if (vg_image_overlaps(d, s)) {
384       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
385       return;
386    }
387
388    info.dst = d;
389    info.src = s;
390    info.setup_shader = &setup_color_matrix;
391    info.user_data = NULL;
392    info.const_buffer = matrix;
393    info.const_buffer_len = 20 * sizeof(VGfloat);
394    info.tiling_mode = VG_TILE_PAD;
395    info.extra_texture_view = NULL;
396    execute_filter(ctx, &info);
397 }
398
399 static VGfloat texture_offset(VGfloat width, VGint kernelSize, VGint current, VGint shift)
400 {
401    VGfloat diff = current - shift;
402
403    return diff / width;
404 }
405
406 void vgConvolve(VGImage dst, VGImage src,
407                 VGint kernelWidth, VGint kernelHeight,
408                 VGint shiftX, VGint shiftY,
409                 const VGshort * kernel,
410                 VGfloat scale,
411                 VGfloat bias,
412                 VGTilingMode tilingMode)
413 {
414    struct vg_context *ctx = vg_current_context();
415    VGfloat *buffer;
416    VGint buffer_len;
417    VGint i, j;
418    VGint idx = 0;
419    struct vg_image *d, *s;
420    VGint kernel_size = kernelWidth * kernelHeight;
421    struct filter_info info;
422    const VGint max_kernel_size = vgGeti(VG_MAX_KERNEL_SIZE);
423
424    if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
425       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
426       return;
427    }
428
429    if (kernelWidth <= 0 || kernelHeight <= 0 ||
430       kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) {
431       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
432       return;
433    }
434
435    if (!kernel || !is_aligned_to(kernel, 2)) {
436       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
437       return;
438    }
439
440    if (tilingMode < VG_TILE_FILL ||
441        tilingMode > VG_TILE_REFLECT) {
442       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
443       return;
444    }
445
446    d = (struct vg_image*)dst;
447    s = (struct vg_image*)src;
448
449    if (vg_image_overlaps(d, s)) {
450       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
451       return;
452    }
453
454    vg_validate_state(ctx);
455
456    buffer_len = 8 + 2 * 4 * kernel_size;
457    buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat));
458
459    buffer[0] = 0.f;
460    buffer[1] = 1.f;
461    buffer[2] = 2.f; /*unused*/
462    buffer[3] = 4.f; /*unused*/
463
464    buffer[4] = kernelWidth * kernelHeight;
465    buffer[5] = scale;
466    buffer[6] = bias;
467    buffer[7] = 0.f;
468
469    idx = 8;
470    for (j = 0; j < kernelHeight; ++j) {
471       for (i = 0; i < kernelWidth; ++i) {
472          VGint index = j * kernelWidth + i;
473          VGfloat x, y;
474
475          x = texture_offset(s->width, kernelWidth, i, shiftX);
476          y = texture_offset(s->height, kernelHeight, j, shiftY);
477
478          buffer[idx + index*4 + 0] = x;
479          buffer[idx + index*4 + 1] = y;
480          buffer[idx + index*4 + 2] = 0.f;
481          buffer[idx + index*4 + 3] = 0.f;
482       }
483    }
484    idx += kernel_size * 4;
485
486    for (j = 0; j < kernelHeight; ++j) {
487       for (i = 0; i < kernelWidth; ++i) {
488          /* transpose the kernel */
489          VGint index = j * kernelWidth + i;
490          VGint kindex = (kernelWidth - i - 1) * kernelHeight + (kernelHeight - j - 1);
491          buffer[idx + index*4 + 0] = kernel[kindex];
492          buffer[idx + index*4 + 1] = kernel[kindex];
493          buffer[idx + index*4 + 2] = kernel[kindex];
494          buffer[idx + index*4 + 3] = kernel[kindex];
495       }
496    }
497
498    info.dst = d;
499    info.src = s;
500    info.setup_shader = &setup_convolution;
501    info.user_data = (void*)(long)(buffer_len/4);
502    info.const_buffer = buffer;
503    info.const_buffer_len = buffer_len * sizeof(VGfloat);
504    info.tiling_mode = tilingMode;
505    info.extra_texture_view = NULL;
506    execute_filter(ctx, &info);
507
508    free(buffer);
509 }
510
511 void vgSeparableConvolve(VGImage dst, VGImage src,
512                          VGint kernelWidth,
513                          VGint kernelHeight,
514                          VGint shiftX, VGint shiftY,
515                          const VGshort * kernelX,
516                          const VGshort * kernelY,
517                          VGfloat scale,
518                          VGfloat bias,
519                          VGTilingMode tilingMode)
520 {
521    struct vg_context *ctx = vg_current_context();
522    VGshort *kernel;
523    VGint i, j, idx = 0;
524    const VGint max_kernel_size = vgGeti(VG_MAX_SEPARABLE_KERNEL_SIZE);
525
526    if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
527       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
528       return;
529    }
530
531    if (kernelWidth <= 0 || kernelHeight <= 0 ||
532        kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) {
533       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
534       return;
535    }
536
537    if (!kernelX || !kernelY ||
538        !is_aligned_to(kernelX, 2) || !is_aligned_to(kernelY, 2)) {
539       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
540       return;
541    }
542    if (tilingMode < VG_TILE_FILL ||
543        tilingMode > VG_TILE_REFLECT) {
544       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
545       return;
546    }
547    kernel = malloc(sizeof(VGshort)*kernelWidth*kernelHeight);
548    for (i = 0; i < kernelWidth; ++i) {
549       for (j = 0; j < kernelHeight; ++j) {
550          kernel[idx] = kernelX[i] * kernelY[j];
551          ++idx;
552       }
553    }
554    vgConvolve(dst, src, kernelWidth, kernelHeight, shiftX, shiftY,
555               kernel, scale, bias, tilingMode);
556    free(kernel);
557 }
558
559 static INLINE VGfloat compute_gaussian_componenet(VGfloat x, VGfloat y,
560                                                   VGfloat stdDeviationX,
561                                                   VGfloat stdDeviationY)
562 {
563    VGfloat mult = 1 / ( 2 * M_PI * stdDeviationX * stdDeviationY);
564    VGfloat e = exp( - ( pow(x, 2)/(2*pow(stdDeviationX, 2)) +
565                         pow(y, 2)/(2*pow(stdDeviationY, 2)) ) );
566    return mult * e;
567 }
568
569 static INLINE VGint compute_kernel_size(VGfloat deviation)
570 {
571    VGint size = ceil(2.146 * deviation);
572    if (size > 11)
573       return 11;
574    return size;
575 }
576
577 static void compute_gaussian_kernel(VGfloat *kernel,
578                                     VGint width, VGint height,
579                                     VGfloat stdDeviationX,
580                                     VGfloat stdDeviationY)
581 {
582    VGint i, j;
583    VGfloat scale = 0.0f;
584
585    for (j = 0; j < height; ++j) {
586       for (i = 0; i < width; ++i) {
587          VGint idx =  (height - j -1) * width + (width - i -1);
588          kernel[idx] = compute_gaussian_componenet(i-(ceil(width/2))-1,
589                                                    j-ceil(height/2)-1,
590                                                    stdDeviationX, stdDeviationY);
591          scale += kernel[idx];
592       }
593    }
594
595    for (j = 0; j < height; ++j) {
596       for (i = 0; i < width; ++i) {
597          VGint idx = j * width + i;
598          kernel[idx] /= scale;
599       }
600    }
601 }
602
603 void vgGaussianBlur(VGImage dst, VGImage src,
604                     VGfloat stdDeviationX,
605                     VGfloat stdDeviationY,
606                     VGTilingMode tilingMode)
607 {
608    struct vg_context *ctx = vg_current_context();
609    struct vg_image *d, *s;
610    VGfloat *buffer, *kernel;
611    VGint kernel_width, kernel_height, kernel_size;
612    VGint buffer_len;
613    VGint idx, i, j;
614    struct filter_info info;
615
616    if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
617       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
618       return;
619    }
620    if (stdDeviationX <= 0 || stdDeviationY <= 0) {
621       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
622       return;
623    }
624
625    if (tilingMode < VG_TILE_FILL ||
626        tilingMode > VG_TILE_REFLECT) {
627       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
628       return;
629    }
630
631    d = (struct vg_image*)dst;
632    s = (struct vg_image*)src;
633
634    if (vg_image_overlaps(d, s)) {
635       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
636       return;
637    }
638
639    kernel_width = compute_kernel_size(stdDeviationX);
640    kernel_height = compute_kernel_size(stdDeviationY);
641    kernel_size = kernel_width * kernel_height;
642    kernel = malloc(sizeof(VGfloat)*kernel_size);
643    compute_gaussian_kernel(kernel, kernel_width, kernel_height,
644                            stdDeviationX, stdDeviationY);
645
646    buffer_len = 8 + 2 * 4 * kernel_size;
647    buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat));
648
649    buffer[0] = 0.f;
650    buffer[1] = 1.f;
651    buffer[2] = 2.f; /*unused*/
652    buffer[3] = 4.f; /*unused*/
653
654    buffer[4] = kernel_width * kernel_height;
655    buffer[5] = 1.f;/*scale*/
656    buffer[6] = 0.f;/*bias*/
657    buffer[7] = 0.f;
658
659    idx = 8;
660    for (j = 0; j < kernel_height; ++j) {
661       for (i = 0; i < kernel_width; ++i) {
662          VGint index = j * kernel_width + i;
663          VGfloat x, y;
664
665          x = texture_offset(s->width, kernel_width, i, kernel_width/2);
666          y = texture_offset(s->height, kernel_height, j, kernel_height/2);
667
668          buffer[idx + index*4 + 0] = x;
669          buffer[idx + index*4 + 1] = y;
670          buffer[idx + index*4 + 2] = 0.f;
671          buffer[idx + index*4 + 3] = 0.f;
672       }
673    }
674    idx += kernel_size * 4;
675
676    for (j = 0; j < kernel_height; ++j) {
677       for (i = 0; i < kernel_width; ++i) {
678          /* transpose the kernel */
679          VGint index = j * kernel_width + i;
680          VGint kindex = (kernel_width - i - 1) * kernel_height + (kernel_height - j - 1);
681          buffer[idx + index*4 + 0] = kernel[kindex];
682          buffer[idx + index*4 + 1] = kernel[kindex];
683          buffer[idx + index*4 + 2] = kernel[kindex];
684          buffer[idx + index*4 + 3] = kernel[kindex];
685       }
686    }
687
688    info.dst = d;
689    info.src = s;
690    info.setup_shader = &setup_convolution;
691    info.user_data = (void*)(long)(buffer_len/4);
692    info.const_buffer = buffer;
693    info.const_buffer_len = buffer_len * sizeof(VGfloat);
694    info.tiling_mode = tilingMode;
695    info.extra_texture_view = NULL;
696    execute_filter(ctx, &info);
697
698    free(buffer);
699    free(kernel);
700 }
701
702 void vgLookup(VGImage dst, VGImage src,
703               const VGubyte * redLUT,
704               const VGubyte * greenLUT,
705               const VGubyte * blueLUT,
706               const VGubyte * alphaLUT,
707               VGboolean outputLinear,
708               VGboolean outputPremultiplied)
709 {
710    struct vg_context *ctx = vg_current_context();
711    struct vg_image *d, *s;
712    VGuint color_data[256];
713    VGint i;
714    struct pipe_sampler_view *lut_texture_view;
715    VGfloat buffer[4];
716    struct filter_info info;
717
718    if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
719       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
720       return;
721    }
722
723    if (!redLUT || !greenLUT || !blueLUT || !alphaLUT) {
724       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
725       return;
726    }
727
728    d = (struct vg_image*)dst;
729    s = (struct vg_image*)src;
730
731    if (vg_image_overlaps(d, s)) {
732       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
733       return;
734    }
735
736    for (i = 0; i < 256; ++i) {
737       color_data[i] = blueLUT[i] << 24 | greenLUT[i] << 16 |
738                       redLUT[i]  <<  8 | alphaLUT[i];
739    }
740    lut_texture_view = create_texture_1d_view(ctx, color_data, 255);
741
742    buffer[0] = 0.f;
743    buffer[1] = 0.f;
744    buffer[2] = 1.f;
745    buffer[3] = 1.f;
746
747    info.dst = d;
748    info.src = s;
749    info.setup_shader = &setup_lookup;
750    info.user_data = NULL;
751    info.const_buffer = buffer;
752    info.const_buffer_len = 4 * sizeof(VGfloat);
753    info.tiling_mode = VG_TILE_PAD;
754    info.extra_texture_view = lut_texture_view;
755
756    execute_filter(ctx, &info);
757
758    pipe_sampler_view_reference(&lut_texture_view, NULL);
759 }
760
761 void vgLookupSingle(VGImage dst, VGImage src,
762                     const VGuint * lookupTable,
763                     VGImageChannel sourceChannel,
764                     VGboolean outputLinear,
765                     VGboolean outputPremultiplied)
766 {
767    struct vg_context *ctx = vg_current_context();
768    struct vg_image *d, *s;
769    struct pipe_sampler_view *lut_texture_view;
770    VGfloat buffer[4];
771    struct filter_info info;
772    VGuint color_data[256];
773    VGint i;
774
775    if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) {
776       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
777       return;
778    }
779
780    if (!lookupTable || !is_aligned(lookupTable)) {
781       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
782       return;
783    }
784
785    if (sourceChannel != VG_RED && sourceChannel != VG_GREEN &&
786        sourceChannel != VG_BLUE && sourceChannel != VG_ALPHA) {
787       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
788       return;
789    }
790
791    d = (struct vg_image*)dst;
792    s = (struct vg_image*)src;
793
794    if (vg_image_overlaps(d, s)) {
795       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
796       return;
797    }
798
799    for (i = 0; i < 256; ++i) {
800       VGuint rgba = lookupTable[i];
801       VGubyte blue, green, red, alpha;
802       red   = (rgba & 0xff000000)>>24;
803       green = (rgba & 0x00ff0000)>>16;
804       blue  = (rgba & 0x0000ff00)>> 8;
805       alpha = (rgba & 0x000000ff)>> 0;
806       color_data[i] = blue << 24 | green << 16 |
807                       red  <<  8 | alpha;
808    }
809    lut_texture_view = create_texture_1d_view(ctx, color_data, 256);
810
811    buffer[0] = 0.f;
812    buffer[1] = 0.f;
813    buffer[2] = 1.f;
814    buffer[3] = 1.f;
815
816    info.dst = d;
817    info.src = s;
818    info.setup_shader = &setup_lookup_single;
819    info.user_data = (void*)sourceChannel;
820    info.const_buffer = buffer;
821    info.const_buffer_len = 4 * sizeof(VGfloat);
822    info.tiling_mode = VG_TILE_PAD;
823    info.extra_texture_view = lut_texture_view;
824
825    execute_filter(ctx, &info);
826
827    pipe_sampler_view_reference(&lut_texture_view, NULL);
828 }