api_filters.c revision e5f0384ad06359aa1b9dc1b4bc6f475f7a119af2
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 49struct 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 60static 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 95static 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 117static 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 142static 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 148static 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 169static 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 191static 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 258static 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 267static 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 282static 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 293static 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 323static 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 364void 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 399static VGfloat texture_offset(VGfloat width, VGint kernelSize, VGint current, VGint shift) 400{ 401 VGfloat diff = current - shift; 402 403 return diff / width; 404} 405 406void 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 511void 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 559static 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 569static 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 577static 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 603void 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 702void 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 761void 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} 829