api_filters.c revision e5b5d84e8a87a5603a84f8c4625592a278bcf9af
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 51struct 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 62static 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 97static 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 119static 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 144static 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 150static 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 171static 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 193static 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 260static 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 269static 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 284static 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 295static 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 325static 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 366void 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 401static VGfloat texture_offset(VGfloat width, VGint kernelSize, VGint current, VGint shift) 402{ 403 VGfloat diff = current - shift; 404 405 return diff / width; 406} 407 408void 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 513void 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 561static 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 571static 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 579static 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 605void 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 704void 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 763void 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} 831