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