Merge remote branch 'origin/7.8'
[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_resource *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_resource *tex = 0;
67 struct pipe_resource 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.bind = PIPE_BIND_SAMPLER_VIEW;
77
78 tex = screen->resource_create(screen, &templ);
79
80 { /* upload color_data */
81 struct pipe_transfer *transfer =
82 pipe_get_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->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_resource *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_resource_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_BIND_RENDER_TARGET);
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_resource **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_resource_reference(cbuf, NULL);
178
179 *cbuf = pipe_buffer_create(pipe->screen,
180 PIPE_BIND_CONSTANT_BUFFER,
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 }