Home | History | Annotate | Download | only in llvmpipe
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 VMware, Inc.
      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 VMWARE 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 #include "util/u_framebuffer.h"
     29 #include "util/u_math.h"
     30 #include "util/u_memory.h"
     31 #include "util/u_inlines.h"
     32 #include "util/simple_list.h"
     33 #include "util/u_format.h"
     34 #include "lp_scene.h"
     35 #include "lp_fence.h"
     36 #include "lp_debug.h"
     37 
     38 
     39 #define RESOURCE_REF_SZ 32
     40 
     41 /** List of resource references */
     42 struct resource_ref {
     43    struct pipe_resource *resource[RESOURCE_REF_SZ];
     44    int count;
     45    struct resource_ref *next;
     46 };
     47 
     48 
     49 /**
     50  * Create a new scene object.
     51  * \param queue  the queue to put newly rendered/emptied scenes into
     52  */
     53 struct lp_scene *
     54 lp_scene_create( struct pipe_context *pipe )
     55 {
     56    struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
     57    if (!scene)
     58       return NULL;
     59 
     60    scene->pipe = pipe;
     61 
     62    scene->data.head =
     63       CALLOC_STRUCT(data_block);
     64 
     65    pipe_mutex_init(scene->mutex);
     66 
     67 #ifdef DEBUG
     68    /* Do some scene limit sanity checks here */
     69    {
     70       size_t maxBins = TILES_X * TILES_Y;
     71       size_t maxCommandBytes = sizeof(struct cmd_block) * maxBins;
     72       size_t maxCommandPlusData = maxCommandBytes + DATA_BLOCK_SIZE;
     73       /* We'll need at least one command block per bin.  Make sure that's
     74        * less than the max allowed scene size.
     75        */
     76       assert(maxCommandBytes < LP_SCENE_MAX_SIZE);
     77       /* We'll also need space for at least one other data block */
     78       assert(maxCommandPlusData <= LP_SCENE_MAX_SIZE);
     79    }
     80 #endif
     81 
     82    return scene;
     83 }
     84 
     85 
     86 /**
     87  * Free all data associated with the given scene, and the scene itself.
     88  */
     89 void
     90 lp_scene_destroy(struct lp_scene *scene)
     91 {
     92    lp_fence_reference(&scene->fence, NULL);
     93    pipe_mutex_destroy(scene->mutex);
     94    assert(scene->data.head->next == NULL);
     95    FREE(scene->data.head);
     96    FREE(scene);
     97 }
     98 
     99 
    100 /**
    101  * Check if the scene's bins are all empty.
    102  * For debugging purposes.
    103  */
    104 boolean
    105 lp_scene_is_empty(struct lp_scene *scene )
    106 {
    107    unsigned x, y;
    108 
    109    for (y = 0; y < TILES_Y; y++) {
    110       for (x = 0; x < TILES_X; x++) {
    111          const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
    112          if (bin->head) {
    113             return FALSE;
    114          }
    115       }
    116    }
    117    return TRUE;
    118 }
    119 
    120 
    121 /* Returns true if there has ever been a failed allocation attempt in
    122  * this scene.  Used in triangle emit to avoid having to check success
    123  * at each bin.
    124  */
    125 boolean
    126 lp_scene_is_oom(struct lp_scene *scene)
    127 {
    128    return scene->alloc_failed;
    129 }
    130 
    131 
    132 /* Remove all commands from a bin.  Tries to reuse some of the memory
    133  * allocated to the bin, however.
    134  */
    135 void
    136 lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
    137 {
    138    struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
    139 
    140    bin->last_state = NULL;
    141    bin->head = bin->tail;
    142    if (bin->tail) {
    143       bin->tail->next = NULL;
    144       bin->tail->count = 0;
    145    }
    146 }
    147 
    148 
    149 void
    150 lp_scene_begin_rasterization(struct lp_scene *scene)
    151 {
    152    const struct pipe_framebuffer_state *fb = &scene->fb;
    153    int i;
    154 
    155    //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
    156 
    157    for (i = 0; i < scene->fb.nr_cbufs; i++) {
    158       struct pipe_surface *cbuf = scene->fb.cbufs[i];
    159 
    160       if (!cbuf) {
    161          scene->cbufs[i].stride = 0;
    162          scene->cbufs[i].layer_stride = 0;
    163          scene->cbufs[i].map = NULL;
    164          continue;
    165       }
    166 
    167       if (llvmpipe_resource_is_texture(cbuf->texture)) {
    168          scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture,
    169                                                            cbuf->u.tex.level);
    170          scene->cbufs[i].layer_stride = llvmpipe_layer_stride(cbuf->texture,
    171                                                               cbuf->u.tex.level);
    172 
    173          scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture,
    174                                                      cbuf->u.tex.level,
    175                                                      cbuf->u.tex.first_layer,
    176                                                      LP_TEX_USAGE_READ_WRITE);
    177          scene->cbufs[i].format_bytes = util_format_get_blocksize(cbuf->format);
    178       }
    179       else {
    180          struct llvmpipe_resource *lpr = llvmpipe_resource(cbuf->texture);
    181          unsigned pixstride = util_format_get_blocksize(cbuf->format);
    182          scene->cbufs[i].stride = cbuf->texture->width0;
    183          scene->cbufs[i].layer_stride = 0;
    184          scene->cbufs[i].map = lpr->data;
    185          scene->cbufs[i].map += cbuf->u.buf.first_element * pixstride;
    186          scene->cbufs[i].format_bytes = util_format_get_blocksize(cbuf->format);
    187       }
    188    }
    189 
    190    if (fb->zsbuf) {
    191       struct pipe_surface *zsbuf = scene->fb.zsbuf;
    192       scene->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->u.tex.level);
    193       scene->zsbuf.layer_stride = llvmpipe_layer_stride(zsbuf->texture, zsbuf->u.tex.level);
    194 
    195       scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture,
    196                                                zsbuf->u.tex.level,
    197                                                zsbuf->u.tex.first_layer,
    198                                                LP_TEX_USAGE_READ_WRITE);
    199       scene->zsbuf.format_bytes = util_format_get_blocksize(zsbuf->format);
    200    }
    201 }
    202 
    203 
    204 
    205 
    206 /**
    207  * Free all the temporary data in a scene.
    208  */
    209 void
    210 lp_scene_end_rasterization(struct lp_scene *scene )
    211 {
    212    int i, j;
    213 
    214    /* Unmap color buffers */
    215    for (i = 0; i < scene->fb.nr_cbufs; i++) {
    216       if (scene->cbufs[i].map) {
    217          struct pipe_surface *cbuf = scene->fb.cbufs[i];
    218          if (llvmpipe_resource_is_texture(cbuf->texture)) {
    219             llvmpipe_resource_unmap(cbuf->texture,
    220                                     cbuf->u.tex.level,
    221                                     cbuf->u.tex.first_layer);
    222          }
    223          scene->cbufs[i].map = NULL;
    224       }
    225    }
    226 
    227    /* Unmap z/stencil buffer */
    228    if (scene->zsbuf.map) {
    229       struct pipe_surface *zsbuf = scene->fb.zsbuf;
    230       llvmpipe_resource_unmap(zsbuf->texture,
    231                               zsbuf->u.tex.level,
    232                               zsbuf->u.tex.first_layer);
    233       scene->zsbuf.map = NULL;
    234    }
    235 
    236    /* Reset all command lists:
    237     */
    238    for (i = 0; i < scene->tiles_x; i++) {
    239       for (j = 0; j < scene->tiles_y; j++) {
    240          struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
    241          bin->head = NULL;
    242          bin->tail = NULL;
    243          bin->last_state = NULL;
    244       }
    245    }
    246 
    247    /* If there are any bins which weren't cleared by the loop above,
    248     * they will be caught (on debug builds at least) by this assert:
    249     */
    250    assert(lp_scene_is_empty(scene));
    251 
    252    /* Decrement texture ref counts
    253     */
    254    {
    255       struct resource_ref *ref;
    256       int i, j = 0;
    257 
    258       for (ref = scene->resources; ref; ref = ref->next) {
    259          for (i = 0; i < ref->count; i++) {
    260             if (LP_DEBUG & DEBUG_SETUP)
    261                debug_printf("resource %d: %p %dx%d sz %d\n",
    262                             j,
    263                             (void *) ref->resource[i],
    264                             ref->resource[i]->width0,
    265                             ref->resource[i]->height0,
    266                             llvmpipe_resource_size(ref->resource[i]));
    267             j++;
    268             pipe_resource_reference(&ref->resource[i], NULL);
    269          }
    270       }
    271 
    272       if (LP_DEBUG & DEBUG_SETUP)
    273          debug_printf("scene %d resources, sz %d\n",
    274                       j, scene->resource_reference_size);
    275    }
    276 
    277    /* Free all scene data blocks:
    278     */
    279    {
    280       struct data_block_list *list = &scene->data;
    281       struct data_block *block, *tmp;
    282 
    283       for (block = list->head->next; block; block = tmp) {
    284          tmp = block->next;
    285 	 FREE(block);
    286       }
    287 
    288       list->head->next = NULL;
    289       list->head->used = 0;
    290    }
    291 
    292    lp_fence_reference(&scene->fence, NULL);
    293 
    294    scene->resources = NULL;
    295    scene->scene_size = 0;
    296    scene->resource_reference_size = 0;
    297 
    298    scene->alloc_failed = FALSE;
    299 
    300    util_unreference_framebuffer_state( &scene->fb );
    301 }
    302 
    303 
    304 
    305 
    306 
    307 
    308 struct cmd_block *
    309 lp_scene_new_cmd_block( struct lp_scene *scene,
    310                         struct cmd_bin *bin )
    311 {
    312    struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
    313    if (block) {
    314       if (bin->tail) {
    315          bin->tail->next = block;
    316          bin->tail = block;
    317       }
    318       else {
    319          bin->head = block;
    320          bin->tail = block;
    321       }
    322       //memset(block, 0, sizeof *block);
    323       block->next = NULL;
    324       block->count = 0;
    325    }
    326    return block;
    327 }
    328 
    329 
    330 struct data_block *
    331 lp_scene_new_data_block( struct lp_scene *scene )
    332 {
    333    if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {
    334       if (0) debug_printf("%s: failed\n", __FUNCTION__);
    335       scene->alloc_failed = TRUE;
    336       return NULL;
    337    }
    338    else {
    339       struct data_block *block = MALLOC_STRUCT(data_block);
    340       if (!block)
    341          return NULL;
    342 
    343       scene->scene_size += sizeof *block;
    344 
    345       block->used = 0;
    346       block->next = scene->data.head;
    347       scene->data.head = block;
    348 
    349       return block;
    350    }
    351 }
    352 
    353 
    354 /**
    355  * Return number of bytes used for all bin data within a scene.
    356  * This does not include resources (textures) referenced by the scene.
    357  */
    358 static unsigned
    359 lp_scene_data_size( const struct lp_scene *scene )
    360 {
    361    unsigned size = 0;
    362    const struct data_block *block;
    363    for (block = scene->data.head; block; block = block->next) {
    364       size += block->used;
    365    }
    366    return size;
    367 }
    368 
    369 
    370 
    371 /**
    372  * Add a reference to a resource by the scene.
    373  */
    374 boolean
    375 lp_scene_add_resource_reference(struct lp_scene *scene,
    376                                 struct pipe_resource *resource,
    377                                 boolean initializing_scene)
    378 {
    379    struct resource_ref *ref, **last = &scene->resources;
    380    int i;
    381 
    382    /* Look at existing resource blocks:
    383     */
    384    for (ref = scene->resources; ref; ref = ref->next) {
    385       last = &ref->next;
    386 
    387       /* Search for this resource:
    388        */
    389       for (i = 0; i < ref->count; i++)
    390          if (ref->resource[i] == resource)
    391             return TRUE;
    392 
    393       if (ref->count < RESOURCE_REF_SZ) {
    394          /* If the block is half-empty, then append the reference here.
    395           */
    396          break;
    397       }
    398    }
    399 
    400    /* Create a new block if no half-empty block was found.
    401     */
    402    if (!ref) {
    403       assert(*last == NULL);
    404       *last = lp_scene_alloc(scene, sizeof *ref);
    405       if (*last == NULL)
    406           return FALSE;
    407 
    408       ref = *last;
    409       memset(ref, 0, sizeof *ref);
    410    }
    411 
    412    /* Append the reference to the reference block.
    413     */
    414    pipe_resource_reference(&ref->resource[ref->count++], resource);
    415    scene->resource_reference_size += llvmpipe_resource_size(resource);
    416 
    417    /* Heuristic to advise scene flushes.  This isn't helpful in the
    418     * initial setup of the scene, but after that point flush on the
    419     * next resource added which exceeds 64MB in referenced texture
    420     * data.
    421     */
    422    if (!initializing_scene &&
    423        scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE)
    424       return FALSE;
    425 
    426    return TRUE;
    427 }
    428 
    429 
    430 /**
    431  * Does this scene have a reference to the given resource?
    432  */
    433 boolean
    434 lp_scene_is_resource_referenced(const struct lp_scene *scene,
    435                                 const struct pipe_resource *resource)
    436 {
    437    const struct resource_ref *ref;
    438    int i;
    439 
    440    for (ref = scene->resources; ref; ref = ref->next) {
    441       for (i = 0; i < ref->count; i++)
    442          if (ref->resource[i] == resource)
    443             return TRUE;
    444    }
    445 
    446    return FALSE;
    447 }
    448 
    449 
    450 
    451 
    452 /** advance curr_x,y to the next bin */
    453 static boolean
    454 next_bin(struct lp_scene *scene)
    455 {
    456    scene->curr_x++;
    457    if (scene->curr_x >= scene->tiles_x) {
    458       scene->curr_x = 0;
    459       scene->curr_y++;
    460    }
    461    if (scene->curr_y >= scene->tiles_y) {
    462       /* no more bins */
    463       return FALSE;
    464    }
    465    return TRUE;
    466 }
    467 
    468 
    469 void
    470 lp_scene_bin_iter_begin( struct lp_scene *scene )
    471 {
    472    scene->curr_x = scene->curr_y = -1;
    473 }
    474 
    475 
    476 /**
    477  * Return pointer to next bin to be rendered.
    478  * The lp_scene::curr_x and ::curr_y fields will be advanced.
    479  * Multiple rendering threads will call this function to get a chunk
    480  * of work (a bin) to work on.
    481  */
    482 struct cmd_bin *
    483 lp_scene_bin_iter_next( struct lp_scene *scene , int *x, int *y)
    484 {
    485    struct cmd_bin *bin = NULL;
    486 
    487    pipe_mutex_lock(scene->mutex);
    488 
    489    if (scene->curr_x < 0) {
    490       /* first bin */
    491       scene->curr_x = 0;
    492       scene->curr_y = 0;
    493    }
    494    else if (!next_bin(scene)) {
    495       /* no more bins left */
    496       goto end;
    497    }
    498 
    499    bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
    500    *x = scene->curr_x;
    501    *y = scene->curr_y;
    502 
    503 end:
    504    /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
    505    pipe_mutex_unlock(scene->mutex);
    506    return bin;
    507 }
    508 
    509 
    510 void lp_scene_begin_binning( struct lp_scene *scene,
    511                              struct pipe_framebuffer_state *fb, boolean discard )
    512 {
    513    int i;
    514    unsigned max_layer = ~0;
    515 
    516    assert(lp_scene_is_empty(scene));
    517 
    518    scene->discard = discard;
    519    util_copy_framebuffer_state(&scene->fb, fb);
    520 
    521    scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
    522    scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;
    523    assert(scene->tiles_x <= TILES_X);
    524    assert(scene->tiles_y <= TILES_Y);
    525 
    526    /*
    527     * Determine how many layers the fb has (used for clamping layer value).
    528     * OpenGL (but not d3d10) permits different amount of layers per rt, however
    529     * results are undefined if layer exceeds the amount of layers of ANY
    530     * attachment hence don't need separate per cbuf and zsbuf max.
    531     */
    532    for (i = 0; i < scene->fb.nr_cbufs; i++) {
    533       struct pipe_surface *cbuf = scene->fb.cbufs[i];
    534       if (cbuf) {
    535          if (llvmpipe_resource_is_texture(cbuf->texture)) {
    536             max_layer = MIN2(max_layer,
    537                              cbuf->u.tex.last_layer - cbuf->u.tex.first_layer);
    538          }
    539          else {
    540             max_layer = 0;
    541          }
    542       }
    543    }
    544    if (fb->zsbuf) {
    545       struct pipe_surface *zsbuf = scene->fb.zsbuf;
    546       max_layer = MIN2(max_layer, zsbuf->u.tex.last_layer - zsbuf->u.tex.first_layer);
    547    }
    548    scene->fb_max_layer = max_layer;
    549 }
    550 
    551 
    552 void lp_scene_end_binning( struct lp_scene *scene )
    553 {
    554    if (LP_DEBUG & DEBUG_SCENE) {
    555       debug_printf("rasterize scene:\n");
    556       debug_printf("  scene_size: %u\n",
    557                    scene->scene_size);
    558       debug_printf("  data size: %u\n",
    559                    lp_scene_data_size(scene));
    560 
    561       if (0)
    562          lp_debug_bins( scene );
    563    }
    564 }
    565