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