Home | History | Annotate | Download | only in util
      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 /**
     28  * @file
     29  * Surface utility functions.
     30  *
     31  * @author Brian Paul
     32  */
     33 
     34 
     35 #include "pipe/p_defines.h"
     36 #include "pipe/p_screen.h"
     37 #include "pipe/p_state.h"
     38 
     39 #include "util/u_format.h"
     40 #include "util/u_inlines.h"
     41 #include "util/u_rect.h"
     42 #include "util/u_surface.h"
     43 #include "util/u_pack_color.h"
     44 
     45 
     46 /**
     47  * Initialize a pipe_surface object.  'view' is considered to have
     48  * uninitialized contents.
     49  */
     50 void
     51 u_surface_default_template(struct pipe_surface *surf,
     52                            const struct pipe_resource *texture)
     53 {
     54    memset(surf, 0, sizeof(*surf));
     55 
     56    surf->format = texture->format;
     57 }
     58 
     59 
     60 /**
     61  * Copy 2D rect from one place to another.
     62  * Position and sizes are in pixels.
     63  * src_stride may be negative to do vertical flip of pixels from source.
     64  */
     65 void
     66 util_copy_rect(ubyte * dst,
     67                enum pipe_format format,
     68                unsigned dst_stride,
     69                unsigned dst_x,
     70                unsigned dst_y,
     71                unsigned width,
     72                unsigned height,
     73                const ubyte * src,
     74                int src_stride,
     75                unsigned src_x,
     76                unsigned src_y)
     77 {
     78    unsigned i;
     79    int src_stride_pos = src_stride < 0 ? -src_stride : src_stride;
     80    int blocksize = util_format_get_blocksize(format);
     81    int blockwidth = util_format_get_blockwidth(format);
     82    int blockheight = util_format_get_blockheight(format);
     83 
     84    assert(blocksize > 0);
     85    assert(blockwidth > 0);
     86    assert(blockheight > 0);
     87 
     88    dst_x /= blockwidth;
     89    dst_y /= blockheight;
     90    width = (width + blockwidth - 1)/blockwidth;
     91    height = (height + blockheight - 1)/blockheight;
     92    src_x /= blockwidth;
     93    src_y /= blockheight;
     94 
     95    dst += dst_x * blocksize;
     96    src += src_x * blocksize;
     97    dst += dst_y * dst_stride;
     98    src += src_y * src_stride_pos;
     99    width *= blocksize;
    100 
    101    if (width == dst_stride && (int)width == src_stride)
    102       memcpy(dst, src, height * width);
    103    else {
    104       for (i = 0; i < height; i++) {
    105          memcpy(dst, src, width);
    106          dst += dst_stride;
    107          src += src_stride;
    108       }
    109    }
    110 }
    111 
    112 
    113 /**
    114  * Copy 3D box from one place to another.
    115  * Position and sizes are in pixels.
    116  */
    117 void
    118 util_copy_box(ubyte * dst,
    119               enum pipe_format format,
    120               unsigned dst_stride, unsigned dst_slice_stride,
    121               unsigned dst_x, unsigned dst_y, unsigned dst_z,
    122               unsigned width, unsigned height, unsigned depth,
    123               const ubyte * src,
    124               int src_stride, unsigned src_slice_stride,
    125               unsigned src_x, unsigned src_y, unsigned src_z)
    126 {
    127    unsigned z;
    128    dst += dst_z * dst_slice_stride;
    129    src += src_z * src_slice_stride;
    130    for (z = 0; z < depth; ++z) {
    131       util_copy_rect(dst,
    132                      format,
    133                      dst_stride,
    134                      dst_x, dst_y,
    135                      width, height,
    136                      src,
    137                      src_stride,
    138                      src_x, src_y);
    139 
    140       dst += dst_slice_stride;
    141       src += src_slice_stride;
    142    }
    143 }
    144 
    145 
    146 void
    147 util_fill_rect(ubyte * dst,
    148                enum pipe_format format,
    149                unsigned dst_stride,
    150                unsigned dst_x,
    151                unsigned dst_y,
    152                unsigned width,
    153                unsigned height,
    154                union util_color *uc)
    155 {
    156    const struct util_format_description *desc = util_format_description(format);
    157    unsigned i, j;
    158    unsigned width_size;
    159    int blocksize = desc->block.bits / 8;
    160    int blockwidth = desc->block.width;
    161    int blockheight = desc->block.height;
    162 
    163    assert(blocksize > 0);
    164    assert(blockwidth > 0);
    165    assert(blockheight > 0);
    166 
    167    dst_x /= blockwidth;
    168    dst_y /= blockheight;
    169    width = (width + blockwidth - 1)/blockwidth;
    170    height = (height + blockheight - 1)/blockheight;
    171 
    172    dst += dst_x * blocksize;
    173    dst += dst_y * dst_stride;
    174    width_size = width * blocksize;
    175 
    176    switch (blocksize) {
    177    case 1:
    178       if(dst_stride == width_size)
    179          memset(dst, uc->ub, height * width_size);
    180       else {
    181          for (i = 0; i < height; i++) {
    182             memset(dst, uc->ub, width_size);
    183             dst += dst_stride;
    184          }
    185       }
    186       break;
    187    case 2:
    188       for (i = 0; i < height; i++) {
    189          uint16_t *row = (uint16_t *)dst;
    190          for (j = 0; j < width; j++)
    191             *row++ = uc->us;
    192          dst += dst_stride;
    193       }
    194       break;
    195    case 4:
    196       for (i = 0; i < height; i++) {
    197          uint32_t *row = (uint32_t *)dst;
    198          for (j = 0; j < width; j++)
    199             *row++ = uc->ui[0];
    200          dst += dst_stride;
    201       }
    202       break;
    203    default:
    204       for (i = 0; i < height; i++) {
    205          ubyte *row = dst;
    206          for (j = 0; j < width; j++) {
    207             memcpy(row, uc, blocksize);
    208             row += blocksize;
    209          }
    210          dst += dst_stride;
    211       }
    212       break;
    213    }
    214 }
    215 
    216 
    217 void
    218 util_fill_box(ubyte * dst,
    219               enum pipe_format format,
    220               unsigned stride,
    221               unsigned layer_stride,
    222               unsigned x,
    223               unsigned y,
    224               unsigned z,
    225               unsigned width,
    226               unsigned height,
    227               unsigned depth,
    228               union util_color *uc)
    229 {
    230    unsigned layer;
    231    dst += z * layer_stride;
    232    for (layer = z; layer < depth; layer++) {
    233       util_fill_rect(dst, format,
    234                      stride,
    235                      x, y, width, height, uc);
    236       dst += layer_stride;
    237    }
    238 }
    239 
    240 
    241 /**
    242  * Fallback function for pipe->resource_copy_region().
    243  * Note: (X,Y)=(0,0) is always the upper-left corner.
    244  */
    245 void
    246 util_resource_copy_region(struct pipe_context *pipe,
    247                           struct pipe_resource *dst,
    248                           unsigned dst_level,
    249                           unsigned dst_x, unsigned dst_y, unsigned dst_z,
    250                           struct pipe_resource *src,
    251                           unsigned src_level,
    252                           const struct pipe_box *src_box)
    253 {
    254    struct pipe_transfer *src_trans, *dst_trans;
    255    uint8_t *dst_map;
    256    const uint8_t *src_map;
    257    enum pipe_format src_format, dst_format;
    258    struct pipe_box dst_box;
    259 
    260    assert(src && dst);
    261    if (!src || !dst)
    262       return;
    263 
    264    assert((src->target == PIPE_BUFFER && dst->target == PIPE_BUFFER) ||
    265           (src->target != PIPE_BUFFER && dst->target != PIPE_BUFFER));
    266 
    267    src_format = src->format;
    268    dst_format = dst->format;
    269 
    270    assert(util_format_get_blocksize(dst_format) == util_format_get_blocksize(src_format));
    271    assert(util_format_get_blockwidth(dst_format) == util_format_get_blockwidth(src_format));
    272    assert(util_format_get_blockheight(dst_format) == util_format_get_blockheight(src_format));
    273 
    274    src_map = pipe->transfer_map(pipe,
    275                                 src,
    276                                 src_level,
    277                                 PIPE_TRANSFER_READ,
    278                                 src_box, &src_trans);
    279    assert(src_map);
    280    if (!src_map) {
    281       goto no_src_map;
    282    }
    283 
    284    dst_box.x = dst_x;
    285    dst_box.y = dst_y;
    286    dst_box.z = dst_z;
    287    dst_box.width  = src_box->width;
    288    dst_box.height = src_box->height;
    289    dst_box.depth  = src_box->depth;
    290 
    291    dst_map = pipe->transfer_map(pipe,
    292                                 dst,
    293                                 dst_level,
    294                                 PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
    295                                 &dst_box, &dst_trans);
    296    assert(dst_map);
    297    if (!dst_map) {
    298       goto no_dst_map;
    299    }
    300 
    301    if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
    302       assert(src_box->height == 1);
    303       assert(src_box->depth == 1);
    304       memcpy(dst_map, src_map, src_box->width);
    305    } else {
    306       util_copy_box(dst_map,
    307                     dst_format,
    308                     dst_trans->stride, dst_trans->layer_stride,
    309                     0, 0, 0,
    310                     src_box->width, src_box->height, src_box->depth,
    311                     src_map,
    312                     src_trans->stride, src_trans->layer_stride,
    313                     0, 0, 0);
    314    }
    315 
    316    pipe->transfer_unmap(pipe, dst_trans);
    317 no_dst_map:
    318    pipe->transfer_unmap(pipe, src_trans);
    319 no_src_map:
    320    ;
    321 }
    322 
    323 
    324 
    325 #define UBYTE_TO_USHORT(B) ((B) | ((B) << 8))
    326 
    327 
    328 /* Return if the box is totally inside the resource.
    329  */
    330 static boolean
    331 is_box_inside_resource(const struct pipe_resource *res,
    332                        const struct pipe_box *box,
    333                        unsigned level)
    334 {
    335    unsigned width = 1, height = 1, depth = 1;
    336 
    337    switch (res->target) {
    338    case PIPE_BUFFER:
    339       width = res->width0;
    340       height = 1;
    341       depth = 1;
    342       break;
    343    case PIPE_TEXTURE_1D:
    344       width = u_minify(res->width0, level);
    345       height = 1;
    346       depth = 1;
    347       break;
    348    case PIPE_TEXTURE_2D:
    349    case PIPE_TEXTURE_RECT:
    350       width = u_minify(res->width0, level);
    351       height = u_minify(res->height0, level);
    352       depth = 1;
    353       break;
    354    case PIPE_TEXTURE_3D:
    355       width = u_minify(res->width0, level);
    356       height = u_minify(res->height0, level);
    357       depth = u_minify(res->depth0, level);
    358       break;
    359    case PIPE_TEXTURE_CUBE:
    360       width = u_minify(res->width0, level);
    361       height = u_minify(res->height0, level);
    362       depth = 6;
    363       break;
    364    case PIPE_TEXTURE_1D_ARRAY:
    365       width = u_minify(res->width0, level);
    366       height = 1;
    367       depth = res->array_size;
    368       break;
    369    case PIPE_TEXTURE_2D_ARRAY:
    370       width = u_minify(res->width0, level);
    371       height = u_minify(res->height0, level);
    372       depth = res->array_size;
    373       break;
    374    case PIPE_TEXTURE_CUBE_ARRAY:
    375       width = u_minify(res->width0, level);
    376       height = u_minify(res->height0, level);
    377       depth = res->array_size;
    378       assert(res->array_size % 6 == 0);
    379       break;
    380    case PIPE_MAX_TEXTURE_TYPES:;
    381    }
    382 
    383    return box->x >= 0 &&
    384           box->x + box->width <= (int) width &&
    385           box->y >= 0 &&
    386           box->y + box->height <= (int) height &&
    387           box->z >= 0 &&
    388           box->z + box->depth <= (int) depth;
    389 }
    390 
    391 static unsigned
    392 get_sample_count(const struct pipe_resource *res)
    393 {
    394    return res->nr_samples ? res->nr_samples : 1;
    395 }
    396 
    397 /**
    398  * Try to do a blit using resource_copy_region. The function calls
    399  * resource_copy_region if the blit description is compatible with it.
    400  *
    401  * It returns TRUE if the blit was done using resource_copy_region.
    402  *
    403  * It returns FALSE otherwise and the caller must fall back to a more generic
    404  * codepath for the blit operation. (e.g. by using u_blitter)
    405  */
    406 boolean
    407 util_try_blit_via_copy_region(struct pipe_context *ctx,
    408                               const struct pipe_blit_info *blit)
    409 {
    410    unsigned mask = util_format_get_mask(blit->dst.format);
    411 
    412    /* No format conversions. */
    413    if (blit->src.resource->format != blit->src.format ||
    414        blit->dst.resource->format != blit->dst.format ||
    415        !util_is_format_compatible(
    416           util_format_description(blit->src.resource->format),
    417           util_format_description(blit->dst.resource->format))) {
    418       return FALSE;
    419    }
    420 
    421    /* No masks, no filtering, no scissor. */
    422    if ((blit->mask & mask) != mask ||
    423        blit->filter != PIPE_TEX_FILTER_NEAREST ||
    424        blit->scissor_enable) {
    425       return FALSE;
    426    }
    427 
    428    /* No flipping. */
    429    if (blit->src.box.width < 0 ||
    430        blit->src.box.height < 0 ||
    431        blit->src.box.depth < 0) {
    432       return FALSE;
    433    }
    434 
    435    /* No scaling. */
    436    if (blit->src.box.width != blit->dst.box.width ||
    437        blit->src.box.height != blit->dst.box.height ||
    438        blit->src.box.depth != blit->dst.box.depth) {
    439       return FALSE;
    440    }
    441 
    442    /* No out-of-bounds access. */
    443    if (!is_box_inside_resource(blit->src.resource, &blit->src.box,
    444                                blit->src.level) ||
    445        !is_box_inside_resource(blit->dst.resource, &blit->dst.box,
    446                                blit->dst.level)) {
    447       return FALSE;
    448    }
    449 
    450    /* Sample counts must match. */
    451    if (get_sample_count(blit->src.resource) !=
    452        get_sample_count(blit->dst.resource)) {
    453       return FALSE;
    454    }
    455 
    456    ctx->resource_copy_region(ctx, blit->dst.resource, blit->dst.level,
    457                              blit->dst.box.x, blit->dst.box.y, blit->dst.box.z,
    458                              blit->src.resource, blit->src.level,
    459                              &blit->src.box);
    460    return TRUE;
    461 }
    462