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