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