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