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/u_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    return scene;
     68 }
     69 
     70 
     71 /**
     72  * Free all data associated with the given scene, and the scene itself.
     73  */
     74 void
     75 lp_scene_destroy(struct lp_scene *scene)
     76 {
     77    lp_fence_reference(&scene->fence, NULL);
     78    pipe_mutex_destroy(scene->mutex);
     79    assert(scene->data.head->next == NULL);
     80    FREE(scene->data.head);
     81    FREE(scene);
     82 }
     83 
     84 
     85 /**
     86  * Check if the scene's bins are all empty.
     87  * For debugging purposes.
     88  */
     89 boolean
     90 lp_scene_is_empty(struct lp_scene *scene )
     91 {
     92    unsigned x, y;
     93 
     94    for (y = 0; y < TILES_Y; y++) {
     95       for (x = 0; x < TILES_X; x++) {
     96          const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
     97          if (bin->head) {
     98             return FALSE;
     99          }
    100       }
    101    }
    102    return TRUE;
    103 }
    104 
    105 
    106 /* Returns true if there has ever been a failed allocation attempt in
    107  * this scene.  Used in triangle emit to avoid having to check success
    108  * at each bin.
    109  */
    110 boolean
    111 lp_scene_is_oom(struct lp_scene *scene)
    112 {
    113    return scene->alloc_failed;
    114 }
    115 
    116 
    117 /* Remove all commands from a bin.  Tries to reuse some of the memory
    118  * allocated to the bin, however.
    119  */
    120 void
    121 lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
    122 {
    123    struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
    124 
    125    bin->last_state = NULL;
    126    bin->head = bin->tail;
    127    if (bin->tail) {
    128       bin->tail->next = NULL;
    129       bin->tail->count = 0;
    130    }
    131 }
    132 
    133 
    134 void
    135 lp_scene_begin_rasterization(struct lp_scene *scene)
    136 {
    137    const struct pipe_framebuffer_state *fb = &scene->fb;
    138    int i;
    139 
    140    //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
    141 
    142    for (i = 0; i < scene->fb.nr_cbufs; i++) {
    143       struct pipe_surface *cbuf = scene->fb.cbufs[i];
    144       assert(cbuf->u.tex.first_layer == cbuf->u.tex.last_layer);
    145       scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture,
    146                                                         cbuf->u.tex.level);
    147 
    148       scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture,
    149                                                   cbuf->u.tex.level,
    150                                                   cbuf->u.tex.first_layer,
    151                                                   LP_TEX_USAGE_READ_WRITE,
    152                                                   LP_TEX_LAYOUT_LINEAR);
    153    }
    154 
    155    if (fb->zsbuf) {
    156       struct pipe_surface *zsbuf = scene->fb.zsbuf;
    157       assert(zsbuf->u.tex.first_layer == zsbuf->u.tex.last_layer);
    158       scene->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->u.tex.level);
    159       scene->zsbuf.blocksize =
    160          util_format_get_blocksize(zsbuf->texture->format);
    161 
    162       scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture,
    163                                                zsbuf->u.tex.level,
    164                                                zsbuf->u.tex.first_layer,
    165                                                LP_TEX_USAGE_READ_WRITE,
    166                                                LP_TEX_LAYOUT_NONE);
    167    }
    168 }
    169 
    170 
    171 
    172 
    173 /**
    174  * Free all the temporary data in a scene.
    175  */
    176 void
    177 lp_scene_end_rasterization(struct lp_scene *scene )
    178 {
    179    int i, j;
    180 
    181    /* Unmap color buffers */
    182    for (i = 0; i < scene->fb.nr_cbufs; i++) {
    183       if (scene->cbufs[i].map) {
    184          struct pipe_surface *cbuf = scene->fb.cbufs[i];
    185          llvmpipe_resource_unmap(cbuf->texture,
    186                                  cbuf->u.tex.level,
    187                                  cbuf->u.tex.first_layer);
    188          scene->cbufs[i].map = NULL;
    189       }
    190    }
    191 
    192    /* Unmap z/stencil buffer */
    193    if (scene->zsbuf.map) {
    194       struct pipe_surface *zsbuf = scene->fb.zsbuf;
    195       llvmpipe_resource_unmap(zsbuf->texture,
    196                               zsbuf->u.tex.level,
    197                               zsbuf->u.tex.first_layer);
    198       scene->zsbuf.map = NULL;
    199    }
    200 
    201    /* Reset all command lists:
    202     */
    203    for (i = 0; i < scene->tiles_x; i++) {
    204       for (j = 0; j < scene->tiles_y; j++) {
    205          struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
    206          bin->head = NULL;
    207          bin->tail = NULL;
    208          bin->last_state = NULL;
    209       }
    210    }
    211 
    212    /* If there are any bins which weren't cleared by the loop above,
    213     * they will be caught (on debug builds at least) by this assert:
    214     */
    215    assert(lp_scene_is_empty(scene));
    216 
    217    /* Decrement texture ref counts
    218     */
    219    {
    220       struct resource_ref *ref;
    221       int i, j = 0;
    222 
    223       for (ref = scene->resources; ref; ref = ref->next) {
    224          for (i = 0; i < ref->count; i++) {
    225             if (LP_DEBUG & DEBUG_SETUP)
    226                debug_printf("resource %d: %p %dx%d sz %d\n",
    227                             j,
    228                             (void *) ref->resource[i],
    229                             ref->resource[i]->width0,
    230                             ref->resource[i]->height0,
    231                             llvmpipe_resource_size(ref->resource[i]));
    232             j++;
    233             pipe_resource_reference(&ref->resource[i], NULL);
    234          }
    235       }
    236 
    237       if (LP_DEBUG & DEBUG_SETUP)
    238          debug_printf("scene %d resources, sz %d\n",
    239                       j, scene->resource_reference_size);
    240    }
    241 
    242    /* Free all scene data blocks:
    243     */
    244    {
    245       struct data_block_list *list = &scene->data;
    246       struct data_block *block, *tmp;
    247 
    248       for (block = list->head->next; block; block = tmp) {
    249          tmp = block->next;
    250 	 FREE(block);
    251       }
    252 
    253       list->head->next = NULL;
    254       list->head->used = 0;
    255    }
    256 
    257    lp_fence_reference(&scene->fence, NULL);
    258 
    259    scene->resources = NULL;
    260    scene->scene_size = 0;
    261    scene->resource_reference_size = 0;
    262 
    263    scene->has_depthstencil_clear = FALSE;
    264    scene->alloc_failed = FALSE;
    265 
    266    util_unreference_framebuffer_state( &scene->fb );
    267 }
    268 
    269 
    270 
    271 
    272 
    273 
    274 struct cmd_block *
    275 lp_scene_new_cmd_block( struct lp_scene *scene,
    276                         struct cmd_bin *bin )
    277 {
    278    struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
    279    if (block) {
    280       if (bin->tail) {
    281          bin->tail->next = block;
    282          bin->tail = block;
    283       }
    284       else {
    285          bin->head = block;
    286          bin->tail = block;
    287       }
    288       //memset(block, 0, sizeof *block);
    289       block->next = NULL;
    290       block->count = 0;
    291    }
    292    return block;
    293 }
    294 
    295 
    296 struct data_block *
    297 lp_scene_new_data_block( struct lp_scene *scene )
    298 {
    299    if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {
    300       if (0) debug_printf("%s: failed\n", __FUNCTION__);
    301       scene->alloc_failed = TRUE;
    302       return NULL;
    303    }
    304    else {
    305       struct data_block *block = MALLOC_STRUCT(data_block);
    306       if (block == NULL)
    307          return NULL;
    308 
    309       scene->scene_size += sizeof *block;
    310 
    311       block->used = 0;
    312       block->next = scene->data.head;
    313       scene->data.head = block;
    314 
    315       return block;
    316    }
    317 }
    318 
    319 
    320 /**
    321  * Return number of bytes used for all bin data within a scene.
    322  * This does not include resources (textures) referenced by the scene.
    323  */
    324 static unsigned
    325 lp_scene_data_size( const struct lp_scene *scene )
    326 {
    327    unsigned size = 0;
    328    const struct data_block *block;
    329    for (block = scene->data.head; block; block = block->next) {
    330       size += block->used;
    331    }
    332    return size;
    333 }
    334 
    335 
    336 
    337 /**
    338  * Add a reference to a resource by the scene.
    339  */
    340 boolean
    341 lp_scene_add_resource_reference(struct lp_scene *scene,
    342                                 struct pipe_resource *resource,
    343                                 boolean initializing_scene)
    344 {
    345    struct resource_ref *ref, **last = &scene->resources;
    346    int i;
    347 
    348    /* Look at existing resource blocks:
    349     */
    350    for (ref = scene->resources; ref; ref = ref->next) {
    351       last = &ref->next;
    352 
    353       /* Search for this resource:
    354        */
    355       for (i = 0; i < ref->count; i++)
    356          if (ref->resource[i] == resource)
    357             return TRUE;
    358 
    359       if (ref->count < RESOURCE_REF_SZ) {
    360          /* If the block is half-empty, then append the reference here.
    361           */
    362          break;
    363       }
    364    }
    365 
    366    /* Create a new block if no half-empty block was found.
    367     */
    368    if (!ref) {
    369       assert(*last == NULL);
    370       *last = lp_scene_alloc(scene, sizeof *ref);
    371       if (*last == NULL)
    372           return FALSE;
    373 
    374       ref = *last;
    375       memset(ref, 0, sizeof *ref);
    376    }
    377 
    378    /* Append the reference to the reference block.
    379     */
    380    pipe_resource_reference(&ref->resource[ref->count++], resource);
    381    scene->resource_reference_size += llvmpipe_resource_size(resource);
    382 
    383    /* Heuristic to advise scene flushes.  This isn't helpful in the
    384     * initial setup of the scene, but after that point flush on the
    385     * next resource added which exceeds 64MB in referenced texture
    386     * data.
    387     */
    388    if (!initializing_scene &&
    389        scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE)
    390       return FALSE;
    391 
    392    return TRUE;
    393 }
    394 
    395 
    396 /**
    397  * Does this scene have a reference to the given resource?
    398  */
    399 boolean
    400 lp_scene_is_resource_referenced(const struct lp_scene *scene,
    401                                 const struct pipe_resource *resource)
    402 {
    403    const struct resource_ref *ref;
    404    int i;
    405 
    406    for (ref = scene->resources; ref; ref = ref->next) {
    407       for (i = 0; i < ref->count; i++)
    408          if (ref->resource[i] == resource)
    409             return TRUE;
    410    }
    411 
    412    return FALSE;
    413 }
    414 
    415 
    416 
    417 
    418 /** advance curr_x,y to the next bin */
    419 static boolean
    420 next_bin(struct lp_scene *scene)
    421 {
    422    scene->curr_x++;
    423    if (scene->curr_x >= scene->tiles_x) {
    424       scene->curr_x = 0;
    425       scene->curr_y++;
    426    }
    427    if (scene->curr_y >= scene->tiles_y) {
    428       /* no more bins */
    429       return FALSE;
    430    }
    431    return TRUE;
    432 }
    433 
    434 
    435 void
    436 lp_scene_bin_iter_begin( struct lp_scene *scene )
    437 {
    438    scene->curr_x = scene->curr_y = -1;
    439 }
    440 
    441 
    442 /**
    443  * Return pointer to next bin to be rendered.
    444  * The lp_scene::curr_x and ::curr_y fields will be advanced.
    445  * Multiple rendering threads will call this function to get a chunk
    446  * of work (a bin) to work on.
    447  */
    448 struct cmd_bin *
    449 lp_scene_bin_iter_next( struct lp_scene *scene )
    450 {
    451    struct cmd_bin *bin = NULL;
    452 
    453    pipe_mutex_lock(scene->mutex);
    454 
    455    if (scene->curr_x < 0) {
    456       /* first bin */
    457       scene->curr_x = 0;
    458       scene->curr_y = 0;
    459    }
    460    else if (!next_bin(scene)) {
    461       /* no more bins left */
    462       goto end;
    463    }
    464 
    465    bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
    466 
    467 end:
    468    /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
    469    pipe_mutex_unlock(scene->mutex);
    470    return bin;
    471 }
    472 
    473 
    474 void lp_scene_begin_binning( struct lp_scene *scene,
    475                              struct pipe_framebuffer_state *fb )
    476 {
    477    assert(lp_scene_is_empty(scene));
    478 
    479    util_copy_framebuffer_state(&scene->fb, fb);
    480 
    481    scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
    482    scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;
    483 
    484    assert(scene->tiles_x <= TILES_X);
    485    assert(scene->tiles_y <= TILES_Y);
    486 }
    487 
    488 
    489 void lp_scene_end_binning( struct lp_scene *scene )
    490 {
    491    if (LP_DEBUG & DEBUG_SCENE) {
    492       debug_printf("rasterize scene:\n");
    493       debug_printf("  scene_size: %u\n",
    494                    scene->scene_size);
    495       debug_printf("  data size: %u\n",
    496                    lp_scene_data_size(scene));
    497 
    498       if (0)
    499          lp_debug_bins( scene );
    500    }
    501 }
    502