Home | History | Annotate | Download | only in softpipe
      1 /**************************************************************************
      2  *
      3  * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27  /*
     28   * Authors:
     29   *   Keith Whitwell <keith (at) tungstengraphics.com>
     30   *   Michel Dnzer <michel (at) tungstengraphics.com>
     31   */
     32 
     33 #include "pipe/p_defines.h"
     34 #include "util/u_inlines.h"
     35 
     36 #include "util/u_format.h"
     37 #include "util/u_math.h"
     38 #include "util/u_memory.h"
     39 #include "util/u_transfer.h"
     40 
     41 #include "sp_context.h"
     42 #include "sp_flush.h"
     43 #include "sp_texture.h"
     44 #include "sp_screen.h"
     45 
     46 #include "state_tracker/sw_winsys.h"
     47 
     48 
     49 /**
     50  * Conventional allocation path for non-display textures:
     51  * Use a simple, maximally packed layout.
     52  */
     53 static boolean
     54 softpipe_resource_layout(struct pipe_screen *screen,
     55                          struct softpipe_resource *spr)
     56 {
     57    struct pipe_resource *pt = &spr->base;
     58    unsigned level;
     59    unsigned width = pt->width0;
     60    unsigned height = pt->height0;
     61    unsigned depth = pt->depth0;
     62    unsigned buffer_size = 0;
     63 
     64    for (level = 0; level <= pt->last_level; level++) {
     65       unsigned slices;
     66 
     67       if (pt->target == PIPE_TEXTURE_CUBE)
     68          slices = 6;
     69       else if (pt->target == PIPE_TEXTURE_3D)
     70          slices = depth;
     71       else
     72          slices = pt->array_size;
     73 
     74       spr->stride[level] = util_format_get_stride(pt->format, width);
     75 
     76       spr->level_offset[level] = buffer_size;
     77 
     78       buffer_size += (util_format_get_nblocksy(pt->format, height) *
     79                       slices * spr->stride[level]);
     80 
     81       width  = u_minify(width, 1);
     82       height = u_minify(height, 1);
     83       depth = u_minify(depth, 1);
     84    }
     85 
     86    spr->data = align_malloc(buffer_size, 16);
     87 
     88    return spr->data != NULL;
     89 }
     90 
     91 
     92 /**
     93  * Texture layout for simple color buffers.
     94  */
     95 static boolean
     96 softpipe_displaytarget_layout(struct pipe_screen *screen,
     97                               struct softpipe_resource *spr)
     98 {
     99    struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
    100 
    101    /* Round up the surface size to a multiple of the tile size?
    102     */
    103    spr->dt = winsys->displaytarget_create(winsys,
    104                                           spr->base.bind,
    105                                           spr->base.format,
    106                                           spr->base.width0,
    107                                           spr->base.height0,
    108                                           16,
    109                                           &spr->stride[0] );
    110 
    111    return spr->dt != NULL;
    112 }
    113 
    114 
    115 /**
    116  * Create new pipe_resource given the template information.
    117  */
    118 static struct pipe_resource *
    119 softpipe_resource_create(struct pipe_screen *screen,
    120                          const struct pipe_resource *templat)
    121 {
    122    struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
    123    if (!spr)
    124       return NULL;
    125 
    126    assert(templat->format != PIPE_FORMAT_NONE);
    127 
    128    spr->base = *templat;
    129    pipe_reference_init(&spr->base.reference, 1);
    130    spr->base.screen = screen;
    131 
    132    spr->pot = (util_is_power_of_two(templat->width0) &&
    133                util_is_power_of_two(templat->height0) &&
    134                util_is_power_of_two(templat->depth0));
    135 
    136    if (spr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
    137 			 PIPE_BIND_SCANOUT |
    138 			 PIPE_BIND_SHARED)) {
    139       if (!softpipe_displaytarget_layout(screen, spr))
    140          goto fail;
    141    }
    142    else {
    143       if (!softpipe_resource_layout(screen, spr))
    144          goto fail;
    145    }
    146 
    147    return &spr->base;
    148 
    149  fail:
    150    FREE(spr);
    151    return NULL;
    152 }
    153 
    154 
    155 static void
    156 softpipe_resource_destroy(struct pipe_screen *pscreen,
    157 			  struct pipe_resource *pt)
    158 {
    159    struct softpipe_screen *screen = softpipe_screen(pscreen);
    160    struct softpipe_resource *spr = softpipe_resource(pt);
    161 
    162    if (spr->dt) {
    163       /* display target */
    164       struct sw_winsys *winsys = screen->winsys;
    165       winsys->displaytarget_destroy(winsys, spr->dt);
    166    }
    167    else if (!spr->userBuffer) {
    168       /* regular texture */
    169       align_free(spr->data);
    170    }
    171 
    172    FREE(spr);
    173 }
    174 
    175 
    176 static struct pipe_resource *
    177 softpipe_resource_from_handle(struct pipe_screen *screen,
    178                               const struct pipe_resource *templat,
    179                               struct winsys_handle *whandle)
    180 {
    181    struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
    182    struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource);
    183    if (!spr)
    184       return NULL;
    185 
    186    spr->base = *templat;
    187    pipe_reference_init(&spr->base.reference, 1);
    188    spr->base.screen = screen;
    189 
    190    spr->pot = (util_is_power_of_two(templat->width0) &&
    191                util_is_power_of_two(templat->height0) &&
    192                util_is_power_of_two(templat->depth0));
    193 
    194    spr->dt = winsys->displaytarget_from_handle(winsys,
    195                                                templat,
    196                                                whandle,
    197                                                &spr->stride[0]);
    198    if (!spr->dt)
    199       goto fail;
    200 
    201    return &spr->base;
    202 
    203  fail:
    204    FREE(spr);
    205    return NULL;
    206 }
    207 
    208 
    209 static boolean
    210 softpipe_resource_get_handle(struct pipe_screen *screen,
    211                              struct pipe_resource *pt,
    212                              struct winsys_handle *whandle)
    213 {
    214    struct sw_winsys *winsys = softpipe_screen(screen)->winsys;
    215    struct softpipe_resource *spr = softpipe_resource(pt);
    216 
    217    assert(spr->dt);
    218    if (!spr->dt)
    219       return FALSE;
    220 
    221    return winsys->displaytarget_get_handle(winsys, spr->dt, whandle);
    222 }
    223 
    224 
    225 /**
    226  * Helper function to compute offset (in bytes) for a particular
    227  * texture level/face/slice from the start of the buffer.
    228  */
    229 static unsigned
    230 sp_get_tex_image_offset(const struct softpipe_resource *spr,
    231                         unsigned level, unsigned layer)
    232 {
    233    const unsigned hgt = u_minify(spr->base.height0, level);
    234    const unsigned nblocksy = util_format_get_nblocksy(spr->base.format, hgt);
    235    unsigned offset = spr->level_offset[level];
    236 
    237    if (spr->base.target == PIPE_TEXTURE_CUBE ||
    238        spr->base.target == PIPE_TEXTURE_3D ||
    239        spr->base.target == PIPE_TEXTURE_2D_ARRAY) {
    240       offset += layer * nblocksy * spr->stride[level];
    241    }
    242    else if (spr->base.target == PIPE_TEXTURE_1D_ARRAY) {
    243       offset += layer * spr->stride[level];
    244    }
    245    else {
    246       assert(layer == 0);
    247    }
    248 
    249    return offset;
    250 }
    251 
    252 
    253 /**
    254  * Get a pipe_surface "view" into a texture resource.
    255  */
    256 static struct pipe_surface *
    257 softpipe_create_surface(struct pipe_context *pipe,
    258                         struct pipe_resource *pt,
    259                         const struct pipe_surface *surf_tmpl)
    260 {
    261    struct pipe_surface *ps;
    262    unsigned level = surf_tmpl->u.tex.level;
    263 
    264    assert(level <= pt->last_level);
    265    assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
    266 
    267    ps = CALLOC_STRUCT(pipe_surface);
    268    if (ps) {
    269       pipe_reference_init(&ps->reference, 1);
    270       pipe_resource_reference(&ps->texture, pt);
    271       ps->context = pipe;
    272       ps->format = surf_tmpl->format;
    273       ps->width = u_minify(pt->width0, level);
    274       ps->height = u_minify(pt->height0, level);
    275       ps->usage = surf_tmpl->usage;
    276 
    277       ps->u.tex.level = level;
    278       ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
    279       ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
    280    }
    281    return ps;
    282 }
    283 
    284 
    285 /**
    286  * Free a pipe_surface which was created with softpipe_create_surface().
    287  */
    288 static void
    289 softpipe_surface_destroy(struct pipe_context *pipe,
    290                          struct pipe_surface *surf)
    291 {
    292    /* Effectively do the texture_update work here - if texture images
    293     * needed post-processing to put them into hardware layout, this is
    294     * where it would happen.  For softpipe, nothing to do.
    295     */
    296    assert(surf->texture);
    297    pipe_resource_reference(&surf->texture, NULL);
    298    FREE(surf);
    299 }
    300 
    301 
    302 /**
    303  * Geta pipe_transfer object which is used for moving data in/out of
    304  * a resource object.
    305  * \param pipe  rendering context
    306  * \param resource  the resource to transfer in/out of
    307  * \param level  which mipmap level
    308  * \param usage  bitmask of PIPE_TRANSFER_x flags
    309  * \param box  the 1D/2D/3D region of interest
    310  */
    311 static struct pipe_transfer *
    312 softpipe_get_transfer(struct pipe_context *pipe,
    313                       struct pipe_resource *resource,
    314                       unsigned level,
    315                       unsigned usage,
    316                       const struct pipe_box *box)
    317 {
    318    struct softpipe_resource *spr = softpipe_resource(resource);
    319    struct softpipe_transfer *spt;
    320 
    321    assert(resource);
    322    assert(level <= resource->last_level);
    323 
    324    /* make sure the requested region is in the image bounds */
    325    assert(box->x + box->width <= u_minify(resource->width0, level));
    326    if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
    327       assert(box->y + box->height <= resource->array_size);
    328    }
    329    else {
    330       assert(box->y + box->height <= u_minify(resource->height0, level));
    331       if (resource->target == PIPE_TEXTURE_2D_ARRAY) {
    332          assert(box->z + box->depth <= resource->array_size);
    333       }
    334       else if (resource->target == PIPE_TEXTURE_CUBE) {
    335          assert(box->z < 6);
    336       }
    337       else {
    338          assert(box->z + box->depth <= (u_minify(resource->depth0, level)));
    339       }
    340    }
    341 
    342    /*
    343     * Transfers, like other pipe operations, must happen in order, so flush the
    344     * context if necessary.
    345     */
    346    if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
    347       boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
    348       boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
    349       if (!softpipe_flush_resource(pipe, resource,
    350                                    level, box->depth > 1 ? -1 : box->z,
    351                                    0, /* flush_flags */
    352                                    read_only,
    353                                    TRUE, /* cpu_access */
    354                                    do_not_block)) {
    355          /*
    356           * It would have blocked, but state tracker requested no to.
    357           */
    358          assert(do_not_block);
    359          return NULL;
    360       }
    361    }
    362 
    363    spt = CALLOC_STRUCT(softpipe_transfer);
    364    if (spt) {
    365       struct pipe_transfer *pt = &spt->base;
    366       enum pipe_format format = resource->format;
    367       const unsigned hgt = u_minify(spr->base.height0, level);
    368       const unsigned nblocksy = util_format_get_nblocksy(format, hgt);
    369 
    370       pipe_resource_reference(&pt->resource, resource);
    371       pt->level = level;
    372       pt->usage = usage;
    373       pt->box = *box;
    374       pt->stride = spr->stride[level];
    375       pt->layer_stride = pt->stride * nblocksy;
    376 
    377       spt->offset = sp_get_tex_image_offset(spr, level, box->z);
    378 
    379       spt->offset +=
    380          box->y / util_format_get_blockheight(format) * spt->base.stride +
    381          box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
    382 
    383       return pt;
    384    }
    385    return NULL;
    386 }
    387 
    388 
    389 /**
    390  * Free a pipe_transfer object which was created with
    391  * softpipe_get_transfer().
    392  */
    393 static void
    394 softpipe_transfer_destroy(struct pipe_context *pipe,
    395                           struct pipe_transfer *transfer)
    396 {
    397    pipe_resource_reference(&transfer->resource, NULL);
    398    FREE(transfer);
    399 }
    400 
    401 
    402 /**
    403  * Create memory mapping for given pipe_transfer object.
    404  */
    405 static void *
    406 softpipe_transfer_map(struct pipe_context *pipe,
    407                       struct pipe_transfer *transfer)
    408 {
    409    struct softpipe_transfer *spt = softpipe_transfer(transfer);
    410    struct softpipe_resource *spr = softpipe_resource(transfer->resource);
    411    struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
    412    uint8_t *map;
    413 
    414    /* resources backed by display target treated specially:
    415     */
    416    if (spr->dt) {
    417       map = winsys->displaytarget_map(winsys, spr->dt, transfer->usage);
    418    }
    419    else {
    420       map = spr->data;
    421    }
    422 
    423    if (map == NULL)
    424       return NULL;
    425    else
    426       return map + spt->offset;
    427 }
    428 
    429 
    430 /**
    431  * Unmap memory mapping for given pipe_transfer object.
    432  */
    433 static void
    434 softpipe_transfer_unmap(struct pipe_context *pipe,
    435                         struct pipe_transfer *transfer)
    436 {
    437    struct softpipe_resource *spr;
    438 
    439    assert(transfer->resource);
    440    spr = softpipe_resource(transfer->resource);
    441 
    442    if (spr->dt) {
    443       /* display target */
    444       struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys;
    445       winsys->displaytarget_unmap(winsys, spr->dt);
    446    }
    447 
    448    if (transfer->usage & PIPE_TRANSFER_WRITE) {
    449       /* Mark the texture as dirty to expire the tile caches. */
    450       spr->timestamp++;
    451    }
    452 }
    453 
    454 /**
    455  * Create buffer which wraps user-space data.
    456  */
    457 struct pipe_resource *
    458 softpipe_user_buffer_create(struct pipe_screen *screen,
    459                             void *ptr,
    460                             unsigned bytes,
    461 			    unsigned bind_flags)
    462 {
    463    struct softpipe_resource *spr;
    464 
    465    spr = CALLOC_STRUCT(softpipe_resource);
    466    if (!spr)
    467       return NULL;
    468 
    469    pipe_reference_init(&spr->base.reference, 1);
    470    spr->base.screen = screen;
    471    spr->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
    472    spr->base.bind = bind_flags;
    473    spr->base.usage = PIPE_USAGE_IMMUTABLE;
    474    spr->base.flags = 0;
    475    spr->base.width0 = bytes;
    476    spr->base.height0 = 1;
    477    spr->base.depth0 = 1;
    478    spr->base.array_size = 1;
    479    spr->userBuffer = TRUE;
    480    spr->data = ptr;
    481 
    482    return &spr->base;
    483 }
    484 
    485 
    486 void
    487 softpipe_init_texture_funcs(struct pipe_context *pipe)
    488 {
    489    pipe->get_transfer = softpipe_get_transfer;
    490    pipe->transfer_destroy = softpipe_transfer_destroy;
    491    pipe->transfer_map = softpipe_transfer_map;
    492    pipe->transfer_unmap = softpipe_transfer_unmap;
    493 
    494    pipe->transfer_flush_region = u_default_transfer_flush_region;
    495    pipe->transfer_inline_write = u_default_transfer_inline_write;
    496 
    497    pipe->create_surface = softpipe_create_surface;
    498    pipe->surface_destroy = softpipe_surface_destroy;
    499 }
    500 
    501 
    502 void
    503 softpipe_init_screen_texture_funcs(struct pipe_screen *screen)
    504 {
    505    screen->resource_create = softpipe_resource_create;
    506    screen->resource_destroy = softpipe_resource_destroy;
    507    screen->resource_from_handle = softpipe_resource_from_handle;
    508    screen->resource_get_handle = softpipe_resource_get_handle;
    509 }
    510