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 "image.h"
     28 
     29 #include "VG/openvg.h"
     30 
     31 #include "vg_context.h"
     32 #include "vg_translate.h"
     33 #include "api_consts.h"
     34 #include "api.h"
     35 #include "handle.h"
     36 
     37 #include "pipe/p_context.h"
     38 #include "pipe/p_screen.h"
     39 #include "util/u_inlines.h"
     40 #include "util/u_tile.h"
     41 #include "util/u_math.h"
     42 
     43 static INLINE VGboolean supported_image_format(VGImageFormat format)
     44 {
     45    switch(format) {
     46    case VG_sRGBX_8888:
     47    case VG_sRGBA_8888:
     48    case VG_sRGBA_8888_PRE:
     49    case VG_sRGB_565:
     50    case VG_sRGBA_5551:
     51    case VG_sRGBA_4444:
     52    case VG_sL_8:
     53    case VG_lRGBX_8888:
     54    case VG_lRGBA_8888:
     55    case VG_lRGBA_8888_PRE:
     56    case VG_lL_8:
     57    case VG_A_8:
     58    case VG_BW_1:
     59 #ifdef OPENVG_VERSION_1_1
     60    case VG_A_1:
     61    case VG_A_4:
     62 #endif
     63    case VG_sXRGB_8888:
     64    case VG_sARGB_8888:
     65    case VG_sARGB_8888_PRE:
     66    case VG_sARGB_1555:
     67    case VG_sARGB_4444:
     68    case VG_lXRGB_8888:
     69    case VG_lARGB_8888:
     70    case VG_lARGB_8888_PRE:
     71    case VG_sBGRX_8888:
     72    case VG_sBGRA_8888:
     73    case VG_sBGRA_8888_PRE:
     74    case VG_sBGR_565:
     75    case VG_sBGRA_5551:
     76    case VG_sBGRA_4444:
     77    case VG_lBGRX_8888:
     78    case VG_lBGRA_8888:
     79    case VG_lBGRA_8888_PRE:
     80    case VG_sXBGR_8888:
     81    case VG_sABGR_8888:
     82    case VG_sABGR_8888_PRE:
     83    case VG_sABGR_1555:
     84    case VG_sABGR_4444:
     85    case VG_lXBGR_8888:
     86    case VG_lABGR_8888:
     87    case VG_lABGR_8888_PRE:
     88       return VG_TRUE;
     89    default:
     90       return VG_FALSE;
     91    }
     92    return VG_FALSE;
     93 }
     94 
     95 VGImage vegaCreateImage(VGImageFormat format,
     96                         VGint width, VGint height,
     97                         VGbitfield allowedQuality)
     98 {
     99    struct vg_context *ctx = vg_current_context();
    100 
    101    if (!supported_image_format(format)) {
    102       vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
    103       return VG_INVALID_HANDLE;
    104    }
    105    if (width <= 0 || height <= 0) {
    106       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    107       return VG_INVALID_HANDLE;
    108    }
    109    if (width > vegaGeti(VG_MAX_IMAGE_WIDTH) ||
    110        height > vegaGeti(VG_MAX_IMAGE_HEIGHT)) {
    111       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    112       return VG_INVALID_HANDLE;
    113    }
    114    if (width * height > vegaGeti(VG_MAX_IMAGE_PIXELS)) {
    115       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    116       return VG_INVALID_HANDLE;
    117    }
    118 
    119    if (!(allowedQuality & ((VG_IMAGE_QUALITY_NONANTIALIASED |
    120                            VG_IMAGE_QUALITY_FASTER |
    121                            VG_IMAGE_QUALITY_BETTER)))) {
    122       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    123       return VG_INVALID_HANDLE;
    124    }
    125 
    126    return image_to_handle(image_create(format, width, height));
    127 }
    128 
    129 void vegaDestroyImage(VGImage image)
    130 {
    131    struct vg_context *ctx = vg_current_context();
    132    struct vg_image *img = handle_to_image(image);
    133 
    134    if (image == VG_INVALID_HANDLE) {
    135       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    136       return;
    137    }
    138    if (!vg_object_is_valid(image, VG_OBJECT_IMAGE)) {
    139       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    140       return;
    141    }
    142    image_destroy(img);
    143 }
    144 
    145 void vegaClearImage(VGImage image,
    146                     VGint x, VGint y,
    147                     VGint width, VGint height)
    148 {
    149    struct vg_context *ctx = vg_current_context();
    150    struct vg_image *img;
    151 
    152    if (image == VG_INVALID_HANDLE) {
    153       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    154       return;
    155    }
    156    if (width <= 0 || height <= 0) {
    157       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    158       return;
    159    }
    160 
    161    img = handle_to_image(image);
    162 
    163    if (x + width < 0 || y + height < 0)
    164       return;
    165 
    166    image_clear(img, x, y, width, height);
    167 
    168 }
    169 
    170 void vegaImageSubData(VGImage image,
    171                       const void * data,
    172                       VGint dataStride,
    173                       VGImageFormat dataFormat,
    174                       VGint x, VGint y,
    175                       VGint width, VGint height)
    176 {
    177    struct vg_context *ctx = vg_current_context();
    178    struct vg_image *img;
    179 
    180    if (image == VG_INVALID_HANDLE) {
    181       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    182       return;
    183    }
    184    if (!supported_image_format(dataFormat)) {
    185       vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
    186       return;
    187    }
    188    if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
    189       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    190       return;
    191    }
    192 
    193    img = handle_to_image(image);
    194    image_sub_data(img, data, dataStride, dataFormat,
    195                   x, y, width, height);
    196 }
    197 
    198 void vegaGetImageSubData(VGImage image,
    199                          void * data,
    200                          VGint dataStride,
    201                          VGImageFormat dataFormat,
    202                          VGint x, VGint y,
    203                          VGint width, VGint height)
    204 {
    205    struct vg_context *ctx = vg_current_context();
    206    struct vg_image *img;
    207 
    208    if (image == VG_INVALID_HANDLE) {
    209       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    210       return;
    211    }
    212    if (!supported_image_format(dataFormat)) {
    213       vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
    214       return;
    215    }
    216    if (width <= 0 || height <= 0 || !data || !is_aligned(data)) {
    217       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    218       return;
    219    }
    220    img = handle_to_image(image);
    221    image_get_sub_data(img, data, dataStride, dataFormat,
    222                       x, y, width, height);
    223 }
    224 
    225 VGImage vegaChildImage(VGImage parent,
    226                        VGint x, VGint y,
    227                        VGint width, VGint height)
    228 {
    229    struct vg_context *ctx = vg_current_context();
    230    struct vg_image *p;
    231 
    232    if (parent == VG_INVALID_HANDLE ||
    233        !vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, parent) ||
    234        !vg_object_is_valid(parent, VG_OBJECT_IMAGE)) {
    235       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    236       return VG_INVALID_HANDLE;
    237    }
    238    if (width <= 0 || height <= 0 || x < 0 || y < 0) {
    239       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    240       return VG_INVALID_HANDLE;
    241    }
    242    p = handle_to_image(parent);
    243    if (x > p->width  || y > p->height) {
    244       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    245       return VG_INVALID_HANDLE;
    246    }
    247    if (x + width > p->width  || y + height > p->height) {
    248       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    249       return VG_INVALID_HANDLE;
    250    }
    251 
    252    return image_to_handle(image_child_image(p, x, y, width, height));
    253 }
    254 
    255 VGImage vegaGetParent(VGImage image)
    256 {
    257    struct vg_context *ctx = vg_current_context();
    258    struct vg_image *img;
    259 
    260    if (image == VG_INVALID_HANDLE) {
    261       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    262       return VG_INVALID_HANDLE;
    263    }
    264 
    265    img = handle_to_image(image);
    266    if (img->parent)
    267       return image_to_handle(img->parent);
    268    else
    269       return image;
    270 }
    271 
    272 void vegaCopyImage(VGImage dst, VGint dx, VGint dy,
    273                    VGImage src, VGint sx, VGint sy,
    274                    VGint width, VGint height,
    275                    VGboolean dither)
    276 {
    277    struct vg_context *ctx = vg_current_context();
    278 
    279    if (src == VG_INVALID_HANDLE || dst == VG_INVALID_HANDLE) {
    280       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    281       return;
    282    }
    283 
    284    if (width <= 0 || height <= 0) {
    285       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    286       return;
    287    }
    288    vg_validate_state(ctx);
    289    image_copy(handle_to_image(dst), dx, dy,
    290               handle_to_image(src), sx, sy,
    291               width, height, dither);
    292 }
    293 
    294 void vegaDrawImage(VGImage image)
    295 {
    296    struct vg_context *ctx = vg_current_context();
    297 
    298    if (!ctx)
    299       return;
    300 
    301    if (image == VG_INVALID_HANDLE) {
    302       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    303       return;
    304    }
    305 
    306    vg_validate_state(ctx);
    307    image_draw(handle_to_image(image),
    308          &ctx->state.vg.image_user_to_surface_matrix);
    309 }
    310 
    311 void vegaSetPixels(VGint dx, VGint dy,
    312                    VGImage src, VGint sx, VGint sy,
    313                    VGint width, VGint height)
    314 {
    315    struct vg_context *ctx = vg_current_context();
    316 
    317    vg_validate_state(ctx);
    318 
    319    if (src == VG_INVALID_HANDLE) {
    320       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    321       return;
    322    }
    323    if (width <= 0 || height <= 0) {
    324       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    325       return;
    326    }
    327    image_set_pixels(dx, dy, handle_to_image(src), sx, sy, width,
    328                     height);
    329 }
    330 
    331 void vegaGetPixels(VGImage dst, VGint dx, VGint dy,
    332                    VGint sx, VGint sy,
    333                    VGint width, VGint height)
    334 {
    335    struct vg_context *ctx = vg_current_context();
    336    struct vg_image *img;
    337 
    338    if (dst == VG_INVALID_HANDLE) {
    339       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    340       return;
    341    }
    342    if (width <= 0 || height <= 0) {
    343       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    344       return;
    345    }
    346 
    347    img = handle_to_image(dst);
    348 
    349    image_get_pixels(img, dx, dy,
    350                     sx, sy, width, height);
    351 }
    352 
    353 void vegaWritePixels(const void * data, VGint dataStride,
    354                      VGImageFormat dataFormat,
    355                      VGint dx, VGint dy,
    356                      VGint width, VGint height)
    357 {
    358    struct vg_context *ctx = vg_current_context();
    359 
    360    if (!supported_image_format(dataFormat)) {
    361       vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
    362       return;
    363    }
    364    if (!data || !is_aligned(data)) {
    365       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    366       return;
    367    }
    368    if (width <= 0 || height <= 0) {
    369       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    370       return;
    371    }
    372 
    373    vg_validate_state(ctx);
    374    {
    375       struct vg_image *img = image_create(dataFormat, width, height);
    376       image_sub_data(img, data, dataStride, dataFormat, 0, 0,
    377                      width, height);
    378 #if 0
    379       struct matrix *matrix = &ctx->state.vg.image_user_to_surface_matrix;
    380       matrix_translate(matrix, dx, dy);
    381       image_draw(img);
    382       matrix_translate(matrix, -dx, -dy);
    383 #else
    384       /* this looks like a better approach */
    385       image_set_pixels(dx, dy, img, 0, 0, width, height);
    386 #endif
    387       image_destroy(img);
    388    }
    389 }
    390 
    391 void vegaReadPixels(void * data, VGint dataStride,
    392                     VGImageFormat dataFormat,
    393                     VGint sx, VGint sy,
    394                     VGint width, VGint height)
    395 {
    396    struct vg_context *ctx = vg_current_context();
    397    struct pipe_context *pipe = ctx->pipe;
    398 
    399    struct st_framebuffer *stfb = ctx->draw_buffer;
    400    struct st_renderbuffer *strb = stfb->strb;
    401 
    402    VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4];
    403    VGfloat *df = (VGfloat*)temp;
    404    VGint i;
    405    VGubyte *dst = (VGubyte *)data;
    406    VGint xoffset = 0, yoffset = 0;
    407 
    408    if (!supported_image_format(dataFormat)) {
    409       vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
    410       return;
    411    }
    412    if (!data || !is_aligned(data)) {
    413       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    414       return;
    415    }
    416    if (width <= 0 || height <= 0) {
    417       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    418       return;
    419    }
    420 
    421    if (sx < 0) {
    422       xoffset = -sx;
    423       xoffset *= _vega_size_for_format(dataFormat);
    424       width += sx;
    425       sx = 0;
    426    }
    427    if (sy < 0) {
    428       yoffset = -sy;
    429       yoffset *= dataStride;
    430       height += sy;
    431       sy = 0;
    432    }
    433 
    434    if (sx + width > stfb->width || sy + height > stfb->height) {
    435       width = stfb->width - sx;
    436       height = stfb->height - sy;
    437       /* nothing to read */
    438       if (width <= 0 || height <= 0)
    439          return;
    440    }
    441 
    442    {
    443       VGint y = (stfb->height - sy) - 1, yStep = -1;
    444       struct pipe_transfer *transfer;
    445 
    446       transfer = pipe_get_transfer(pipe, strb->texture,  0, 0,
    447                                    PIPE_TRANSFER_READ,
    448                                    0, 0, sx + width, stfb->height - sy);
    449 
    450       /* Do a row at a time to flip image data vertically */
    451       for (i = 0; i < height; i++) {
    452 #if 0
    453          debug_printf("%d-%d  == %d\n", sy, height, y);
    454 #endif
    455          pipe_get_tile_rgba(pipe, transfer, sx, y, width, 1, df);
    456          y += yStep;
    457          _vega_pack_rgba_span_float(ctx, width, temp, dataFormat,
    458                                     dst + yoffset + xoffset);
    459          dst += dataStride;
    460       }
    461 
    462       pipe->transfer_destroy(pipe, transfer);
    463    }
    464 }
    465 
    466 void vegaCopyPixels(VGint dx, VGint dy,
    467                     VGint sx, VGint sy,
    468                     VGint width, VGint height)
    469 {
    470    struct vg_context *ctx = vg_current_context();
    471    struct st_framebuffer *stfb = ctx->draw_buffer;
    472    struct st_renderbuffer *strb = stfb->strb;
    473 
    474    if (width <= 0 || height <= 0) {
    475       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    476       return;
    477    }
    478 
    479    /* do nothing if we copy from outside the fb */
    480    if (dx >= (VGint)stfb->width || dy >= (VGint)stfb->height ||
    481        sx >= (VGint)stfb->width || sy >= (VGint)stfb->height)
    482       return;
    483 
    484    vg_validate_state(ctx);
    485    /* make sure rendering has completed */
    486    vegaFinish();
    487 
    488    vg_copy_surface(ctx, strb->surface, dx, dy,
    489                    strb->surface, sx, sy, width, height);
    490 }
    491