api_filters.c revision f8e0dd246b26281d31d4f37799985e27368ba2f4
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 35#include "pipe/p_context.h" 36#include "pipe/p_state.h" 37#include "util/u_inlines.h" 38#include "pipe/p_screen.h" 39 40#include "util/u_format.h" 41#include "util/u_sampler.h" 42#include "util/u_string.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_sampler_view *extra_texture_view; 57}; 58 59static INLINE struct pipe_resource *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_resource *tex = 0; 66 struct pipe_resource templ; 67 68 memset(&templ, 0, sizeof(templ)); 69 templ.target = PIPE_TEXTURE_1D; 70 templ.format = PIPE_FORMAT_B8G8R8A8_UNORM; 71 templ.last_level = 0; 72 templ.width0 = color_data_len; 73 templ.height0 = 1; 74 templ.depth0 = 1; 75 templ.bind = PIPE_BIND_SAMPLER_VIEW; 76 77 tex = screen->resource_create(screen, &templ); 78 79 { /* upload color_data */ 80 struct pipe_transfer *transfer = 81 pipe_get_transfer(pipe, tex, 82 0, 0, 0, 83 PIPE_TRANSFER_READ_WRITE , 84 0, 0, tex->width0, tex->height0); 85 void *map = pipe->transfer_map(pipe, transfer); 86 memcpy(map, color_data, sizeof(VGint)*color_data_len); 87 pipe->transfer_unmap(pipe, transfer); 88 pipe->transfer_destroy(pipe, transfer); 89 } 90 91 return tex; 92} 93 94static INLINE struct pipe_sampler_view *create_texture_1d_view(struct vg_context *ctx, 95 const VGuint *color_data, 96 const VGint color_data_len) 97{ 98 struct pipe_context *pipe = ctx->pipe; 99 struct pipe_resource *texture; 100 struct pipe_sampler_view view_templ; 101 struct pipe_sampler_view *view; 102 103 texture = create_texture_1d(ctx, color_data, color_data_len); 104 105 if (!texture) 106 return NULL; 107 108 u_sampler_view_default_template(&view_templ, texture, texture->format); 109 view = pipe->create_sampler_view(pipe, texture, &view_templ); 110 /* want the texture to go away if the view is freed */ 111 pipe_resource_reference(&texture, NULL); 112 113 return view; 114} 115 116static struct vg_shader * setup_color_matrix(struct vg_context *ctx, void *user_data) 117{ 118 struct vg_shader *shader = 119 shader_create_from_text(ctx->pipe, color_matrix_asm, 200, 120 PIPE_SHADER_FRAGMENT); 121 return shader; 122} 123 124static struct vg_shader * setup_convolution(struct vg_context *ctx, void *user_data) 125{ 126 char buffer[1024]; 127 VGint num_consts = (VGint)(long)(user_data); 128 struct vg_shader *shader; 129 130 util_snprintf(buffer, 1023, convolution_asm, num_consts, num_consts / 2 + 1); 131 132 shader = shader_create_from_text(ctx->pipe, buffer, 200, 133 PIPE_SHADER_FRAGMENT); 134 135 return shader; 136} 137 138static struct vg_shader * setup_lookup(struct vg_context *ctx, void *user_data) 139{ 140 struct vg_shader *shader = 141 shader_create_from_text(ctx->pipe, lookup_asm, 142 200, PIPE_SHADER_FRAGMENT); 143 144 return shader; 145} 146 147 148static struct vg_shader * setup_lookup_single(struct vg_context *ctx, void *user_data) 149{ 150 char buffer[1024]; 151 VGImageChannel channel = (VGImageChannel)(user_data); 152 struct vg_shader *shader; 153 154 switch(channel) { 155 case VG_RED: 156 util_snprintf(buffer, 1023, lookup_single_asm, "xxxx"); 157 break; 158 case VG_GREEN: 159 util_snprintf(buffer, 1023, lookup_single_asm, "yyyy"); 160 break; 161 case VG_BLUE: 162 util_snprintf(buffer, 1023, lookup_single_asm, "zzzz"); 163 break; 164 case VG_ALPHA: 165 util_snprintf(buffer, 1023, lookup_single_asm, "wwww"); 166 break; 167 default: 168 debug_assert(!"Unknown color channel"); 169 } 170 171 shader = shader_create_from_text(ctx->pipe, buffer, 200, 172 PIPE_SHADER_FRAGMENT); 173 174 return shader; 175} 176 177static void execute_filter(struct vg_context *ctx, 178 struct filter_info *info) 179{ 180 struct vg_shader *shader; 181 const struct pipe_sampler_state *samplers[2]; 182 struct pipe_sampler_view *views[2]; 183 struct pipe_sampler_state sampler; 184 uint tex_wrap; 185 186 memset(&sampler, 0, sizeof(sampler)); 187 sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; 188 sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; 189 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 190 sampler.normalized_coords = 1; 191 192 switch (info->tiling_mode) { 193 case VG_TILE_FILL: 194 tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_BORDER; 195 /* copy border color */ 196 memcpy(sampler.border_color, ctx->state.vg.tile_fill_color, 197 sizeof(sampler.border_color)); 198 break; 199 case VG_TILE_PAD: 200 tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_EDGE;; 201 break; 202 case VG_TILE_REPEAT: 203 tex_wrap = PIPE_TEX_WRAP_REPEAT;; 204 break; 205 case VG_TILE_REFLECT: 206 tex_wrap = PIPE_TEX_WRAP_MIRROR_REPEAT; 207 break; 208 default: 209 debug_assert(!"Unknown tiling mode"); 210 break; 211 } 212 213 sampler.wrap_s = tex_wrap; 214 sampler.wrap_t = tex_wrap; 215 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 216 217 samplers[0] = samplers[1] = &sampler; 218 views[0] = info->src->sampler_view; 219 views[1] = info->extra_texture_view; 220 221 shader = info->setup_shader(ctx, info->user_data); 222 223 if (renderer_filter_begin(ctx->renderer, 224 info->dst->sampler_view->texture, VG_TRUE, 225 ctx->state.vg.filter_channel_mask, 226 samplers, views, (info->extra_texture_view) ? 2 : 1, 227 shader->driver, info->const_buffer, info->const_buffer_len)) { 228 renderer_filter(ctx->renderer, 229 info->dst->x, info->dst->y, info->dst->width, info->dst->height, 230 info->src->x, info->src->y, info->src->width, info->src->height); 231 renderer_filter_end(ctx->renderer); 232 } 233 234 vg_shader_destroy(ctx, shader); 235} 236 237void vegaColorMatrix(VGImage dst, VGImage src, 238 const VGfloat * matrix) 239{ 240 struct vg_context *ctx = vg_current_context(); 241 struct vg_image *d, *s; 242 struct filter_info info; 243 244 if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { 245 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 246 return; 247 } 248 if (!matrix || !is_aligned(matrix)) { 249 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 250 return; 251 } 252 253 d = (struct vg_image*)dst; 254 s = (struct vg_image*)src; 255 256 if (vg_image_overlaps(d, s)) { 257 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 258 return; 259 } 260 261 info.dst = d; 262 info.src = s; 263 info.setup_shader = &setup_color_matrix; 264 info.user_data = NULL; 265 info.const_buffer = matrix; 266 info.const_buffer_len = 20 * sizeof(VGfloat); 267 info.tiling_mode = VG_TILE_PAD; 268 info.extra_texture_view = NULL; 269 execute_filter(ctx, &info); 270} 271 272static VGfloat texture_offset(VGfloat width, VGint kernelSize, VGint current, VGint shift) 273{ 274 VGfloat diff = current - shift; 275 276 return diff / width; 277} 278 279void vegaConvolve(VGImage dst, VGImage src, 280 VGint kernelWidth, VGint kernelHeight, 281 VGint shiftX, VGint shiftY, 282 const VGshort * kernel, 283 VGfloat scale, 284 VGfloat bias, 285 VGTilingMode tilingMode) 286{ 287 struct vg_context *ctx = vg_current_context(); 288 VGfloat *buffer; 289 VGint buffer_len; 290 VGint i, j; 291 VGint idx = 0; 292 struct vg_image *d, *s; 293 VGint kernel_size = kernelWidth * kernelHeight; 294 struct filter_info info; 295 const VGint max_kernel_size = vgGeti(VG_MAX_KERNEL_SIZE); 296 297 if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { 298 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 299 return; 300 } 301 302 if (kernelWidth <= 0 || kernelHeight <= 0 || 303 kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) { 304 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 305 return; 306 } 307 308 if (!kernel || !is_aligned_to(kernel, 2)) { 309 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 310 return; 311 } 312 313 if (tilingMode < VG_TILE_FILL || 314 tilingMode > VG_TILE_REFLECT) { 315 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 316 return; 317 } 318 319 d = (struct vg_image*)dst; 320 s = (struct vg_image*)src; 321 322 if (vg_image_overlaps(d, s)) { 323 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 324 return; 325 } 326 327 vg_validate_state(ctx); 328 329 buffer_len = 8 + 2 * 4 * kernel_size; 330 buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat)); 331 332 buffer[0] = 0.f; 333 buffer[1] = 1.f; 334 buffer[2] = 2.f; /*unused*/ 335 buffer[3] = 4.f; /*unused*/ 336 337 buffer[4] = kernelWidth * kernelHeight; 338 buffer[5] = scale; 339 buffer[6] = bias; 340 buffer[7] = 0.f; 341 342 idx = 8; 343 for (j = 0; j < kernelHeight; ++j) { 344 for (i = 0; i < kernelWidth; ++i) { 345 VGint index = j * kernelWidth + i; 346 VGfloat x, y; 347 348 x = texture_offset(s->width, kernelWidth, i, shiftX); 349 y = texture_offset(s->height, kernelHeight, j, shiftY); 350 351 buffer[idx + index*4 + 0] = x; 352 buffer[idx + index*4 + 1] = y; 353 buffer[idx + index*4 + 2] = 0.f; 354 buffer[idx + index*4 + 3] = 0.f; 355 } 356 } 357 idx += kernel_size * 4; 358 359 for (j = 0; j < kernelHeight; ++j) { 360 for (i = 0; i < kernelWidth; ++i) { 361 /* transpose the kernel */ 362 VGint index = j * kernelWidth + i; 363 VGint kindex = (kernelWidth - i - 1) * kernelHeight + (kernelHeight - j - 1); 364 buffer[idx + index*4 + 0] = kernel[kindex]; 365 buffer[idx + index*4 + 1] = kernel[kindex]; 366 buffer[idx + index*4 + 2] = kernel[kindex]; 367 buffer[idx + index*4 + 3] = kernel[kindex]; 368 } 369 } 370 371 info.dst = d; 372 info.src = s; 373 info.setup_shader = &setup_convolution; 374 info.user_data = (void*)(long)(buffer_len/4); 375 info.const_buffer = buffer; 376 info.const_buffer_len = buffer_len * sizeof(VGfloat); 377 info.tiling_mode = tilingMode; 378 info.extra_texture_view = NULL; 379 execute_filter(ctx, &info); 380 381 free(buffer); 382} 383 384void vegaSeparableConvolve(VGImage dst, VGImage src, 385 VGint kernelWidth, 386 VGint kernelHeight, 387 VGint shiftX, VGint shiftY, 388 const VGshort * kernelX, 389 const VGshort * kernelY, 390 VGfloat scale, 391 VGfloat bias, 392 VGTilingMode tilingMode) 393{ 394 struct vg_context *ctx = vg_current_context(); 395 VGshort *kernel; 396 VGint i, j, idx = 0; 397 const VGint max_kernel_size = vgGeti(VG_MAX_SEPARABLE_KERNEL_SIZE); 398 399 if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { 400 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 401 return; 402 } 403 404 if (kernelWidth <= 0 || kernelHeight <= 0 || 405 kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) { 406 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 407 return; 408 } 409 410 if (!kernelX || !kernelY || 411 !is_aligned_to(kernelX, 2) || !is_aligned_to(kernelY, 2)) { 412 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 413 return; 414 } 415 if (tilingMode < VG_TILE_FILL || 416 tilingMode > VG_TILE_REFLECT) { 417 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 418 return; 419 } 420 kernel = malloc(sizeof(VGshort)*kernelWidth*kernelHeight); 421 for (i = 0; i < kernelWidth; ++i) { 422 for (j = 0; j < kernelHeight; ++j) { 423 kernel[idx] = kernelX[i] * kernelY[j]; 424 ++idx; 425 } 426 } 427 vgConvolve(dst, src, kernelWidth, kernelHeight, shiftX, shiftY, 428 kernel, scale, bias, tilingMode); 429 free(kernel); 430} 431 432static INLINE VGfloat compute_gaussian_componenet(VGfloat x, VGfloat y, 433 VGfloat stdDeviationX, 434 VGfloat stdDeviationY) 435{ 436 VGfloat mult = 1 / ( 2 * M_PI * stdDeviationX * stdDeviationY); 437 VGfloat e = exp( - ( pow(x, 2)/(2*pow(stdDeviationX, 2)) + 438 pow(y, 2)/(2*pow(stdDeviationY, 2)) ) ); 439 return mult * e; 440} 441 442static INLINE VGint compute_kernel_size(VGfloat deviation) 443{ 444 VGint size = ceil(2.146 * deviation); 445 if (size > 11) 446 return 11; 447 return size; 448} 449 450static void compute_gaussian_kernel(VGfloat *kernel, 451 VGint width, VGint height, 452 VGfloat stdDeviationX, 453 VGfloat stdDeviationY) 454{ 455 VGint i, j; 456 VGfloat scale = 0.0f; 457 458 for (j = 0; j < height; ++j) { 459 for (i = 0; i < width; ++i) { 460 VGint idx = (height - j -1) * width + (width - i -1); 461 kernel[idx] = compute_gaussian_componenet(i-(ceil(width/2))-1, 462 j-ceil(height/2)-1, 463 stdDeviationX, stdDeviationY); 464 scale += kernel[idx]; 465 } 466 } 467 468 for (j = 0; j < height; ++j) { 469 for (i = 0; i < width; ++i) { 470 VGint idx = j * width + i; 471 kernel[idx] /= scale; 472 } 473 } 474} 475 476void vegaGaussianBlur(VGImage dst, VGImage src, 477 VGfloat stdDeviationX, 478 VGfloat stdDeviationY, 479 VGTilingMode tilingMode) 480{ 481 struct vg_context *ctx = vg_current_context(); 482 struct vg_image *d, *s; 483 VGfloat *buffer, *kernel; 484 VGint kernel_width, kernel_height, kernel_size; 485 VGint buffer_len; 486 VGint idx, i, j; 487 struct filter_info info; 488 489 if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { 490 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 491 return; 492 } 493 if (stdDeviationX <= 0 || stdDeviationY <= 0) { 494 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 495 return; 496 } 497 498 if (tilingMode < VG_TILE_FILL || 499 tilingMode > VG_TILE_REFLECT) { 500 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 501 return; 502 } 503 504 d = (struct vg_image*)dst; 505 s = (struct vg_image*)src; 506 507 if (vg_image_overlaps(d, s)) { 508 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 509 return; 510 } 511 512 kernel_width = compute_kernel_size(stdDeviationX); 513 kernel_height = compute_kernel_size(stdDeviationY); 514 kernel_size = kernel_width * kernel_height; 515 kernel = malloc(sizeof(VGfloat)*kernel_size); 516 compute_gaussian_kernel(kernel, kernel_width, kernel_height, 517 stdDeviationX, stdDeviationY); 518 519 buffer_len = 8 + 2 * 4 * kernel_size; 520 buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat)); 521 522 buffer[0] = 0.f; 523 buffer[1] = 1.f; 524 buffer[2] = 2.f; /*unused*/ 525 buffer[3] = 4.f; /*unused*/ 526 527 buffer[4] = kernel_width * kernel_height; 528 buffer[5] = 1.f;/*scale*/ 529 buffer[6] = 0.f;/*bias*/ 530 buffer[7] = 0.f; 531 532 idx = 8; 533 for (j = 0; j < kernel_height; ++j) { 534 for (i = 0; i < kernel_width; ++i) { 535 VGint index = j * kernel_width + i; 536 VGfloat x, y; 537 538 x = texture_offset(s->width, kernel_width, i, kernel_width/2); 539 y = texture_offset(s->height, kernel_height, j, kernel_height/2); 540 541 buffer[idx + index*4 + 0] = x; 542 buffer[idx + index*4 + 1] = y; 543 buffer[idx + index*4 + 2] = 0.f; 544 buffer[idx + index*4 + 3] = 0.f; 545 } 546 } 547 idx += kernel_size * 4; 548 549 for (j = 0; j < kernel_height; ++j) { 550 for (i = 0; i < kernel_width; ++i) { 551 /* transpose the kernel */ 552 VGint index = j * kernel_width + i; 553 VGint kindex = (kernel_width - i - 1) * kernel_height + (kernel_height - j - 1); 554 buffer[idx + index*4 + 0] = kernel[kindex]; 555 buffer[idx + index*4 + 1] = kernel[kindex]; 556 buffer[idx + index*4 + 2] = kernel[kindex]; 557 buffer[idx + index*4 + 3] = kernel[kindex]; 558 } 559 } 560 561 info.dst = d; 562 info.src = s; 563 info.setup_shader = &setup_convolution; 564 info.user_data = (void*)(long)(buffer_len/4); 565 info.const_buffer = buffer; 566 info.const_buffer_len = buffer_len * sizeof(VGfloat); 567 info.tiling_mode = tilingMode; 568 info.extra_texture_view = NULL; 569 execute_filter(ctx, &info); 570 571 free(buffer); 572 free(kernel); 573} 574 575void vegaLookup(VGImage dst, VGImage src, 576 const VGubyte * redLUT, 577 const VGubyte * greenLUT, 578 const VGubyte * blueLUT, 579 const VGubyte * alphaLUT, 580 VGboolean outputLinear, 581 VGboolean outputPremultiplied) 582{ 583 struct vg_context *ctx = vg_current_context(); 584 struct vg_image *d, *s; 585 VGuint color_data[256]; 586 VGint i; 587 struct pipe_sampler_view *lut_texture_view; 588 VGfloat buffer[4]; 589 struct filter_info info; 590 591 if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { 592 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 593 return; 594 } 595 596 if (!redLUT || !greenLUT || !blueLUT || !alphaLUT) { 597 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 598 return; 599 } 600 601 d = (struct vg_image*)dst; 602 s = (struct vg_image*)src; 603 604 if (vg_image_overlaps(d, s)) { 605 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 606 return; 607 } 608 609 for (i = 0; i < 256; ++i) { 610 color_data[i] = blueLUT[i] << 24 | greenLUT[i] << 16 | 611 redLUT[i] << 8 | alphaLUT[i]; 612 } 613 lut_texture_view = create_texture_1d_view(ctx, color_data, 255); 614 615 buffer[0] = 0.f; 616 buffer[1] = 0.f; 617 buffer[2] = 1.f; 618 buffer[3] = 1.f; 619 620 info.dst = d; 621 info.src = s; 622 info.setup_shader = &setup_lookup; 623 info.user_data = NULL; 624 info.const_buffer = buffer; 625 info.const_buffer_len = 4 * sizeof(VGfloat); 626 info.tiling_mode = VG_TILE_PAD; 627 info.extra_texture_view = lut_texture_view; 628 629 execute_filter(ctx, &info); 630 631 pipe_sampler_view_reference(&lut_texture_view, NULL); 632} 633 634void vegaLookupSingle(VGImage dst, VGImage src, 635 const VGuint * lookupTable, 636 VGImageChannel sourceChannel, 637 VGboolean outputLinear, 638 VGboolean outputPremultiplied) 639{ 640 struct vg_context *ctx = vg_current_context(); 641 struct vg_image *d, *s; 642 struct pipe_sampler_view *lut_texture_view; 643 VGfloat buffer[4]; 644 struct filter_info info; 645 VGuint color_data[256]; 646 VGint i; 647 648 if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { 649 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 650 return; 651 } 652 653 if (!lookupTable || !is_aligned(lookupTable)) { 654 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 655 return; 656 } 657 658 if (sourceChannel != VG_RED && sourceChannel != VG_GREEN && 659 sourceChannel != VG_BLUE && sourceChannel != VG_ALPHA) { 660 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 661 return; 662 } 663 664 d = (struct vg_image*)dst; 665 s = (struct vg_image*)src; 666 667 if (vg_image_overlaps(d, s)) { 668 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 669 return; 670 } 671 672 vg_validate_state(ctx); 673 674 for (i = 0; i < 256; ++i) { 675 VGuint rgba = lookupTable[i]; 676 VGubyte blue, green, red, alpha; 677 red = (rgba & 0xff000000)>>24; 678 green = (rgba & 0x00ff0000)>>16; 679 blue = (rgba & 0x0000ff00)>> 8; 680 alpha = (rgba & 0x000000ff)>> 0; 681 color_data[i] = blue << 24 | green << 16 | 682 red << 8 | alpha; 683 } 684 lut_texture_view = create_texture_1d_view(ctx, color_data, 256); 685 686 buffer[0] = 0.f; 687 buffer[1] = 0.f; 688 buffer[2] = 1.f; 689 buffer[3] = 1.f; 690 691 info.dst = d; 692 info.src = s; 693 info.setup_shader = &setup_lookup_single; 694 info.user_data = (void*)sourceChannel; 695 info.const_buffer = buffer; 696 info.const_buffer_len = 4 * sizeof(VGfloat); 697 info.tiling_mode = VG_TILE_PAD; 698 info.extra_texture_view = lut_texture_view; 699 700 execute_filter(ctx, &info); 701 702 pipe_sampler_view_reference(&lut_texture_view, NULL); 703} 704