Home | History | Annotate | Download | only in vega
      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