Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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. #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.    unsigned max_layer = ~0;
  155.  
  156.    //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__);
  157.  
  158.    for (i = 0; i < scene->fb.nr_cbufs; i++) {
  159.       struct pipe_surface *cbuf = scene->fb.cbufs[i];
  160.       if (llvmpipe_resource_is_texture(cbuf->texture)) {
  161.          scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture,
  162.                                                            cbuf->u.tex.level);
  163.          scene->cbufs[i].layer_stride = llvmpipe_layer_stride(cbuf->texture,
  164.                                                               cbuf->u.tex.level);
  165.          max_layer = MIN2(max_layer, cbuf->u.tex.last_layer - cbuf->u.tex.first_layer);
  166.  
  167.          scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture,
  168.                                                      cbuf->u.tex.level,
  169.                                                      cbuf->u.tex.first_layer,
  170.                                                      LP_TEX_USAGE_READ_WRITE);
  171.       }
  172.       else {
  173.          struct llvmpipe_resource *lpr = llvmpipe_resource(cbuf->texture);
  174.          unsigned pixstride = util_format_get_blocksize(cbuf->format);
  175.          scene->cbufs[i].stride = cbuf->texture->width0;
  176.          max_layer = 0;
  177.  
  178.          scene->cbufs[i].map = lpr->data;
  179.          scene->cbufs[i].map += cbuf->u.buf.first_element * pixstride;
  180.       }
  181.    }
  182.  
  183.    if (fb->zsbuf) {
  184.       struct pipe_surface *zsbuf = scene->fb.zsbuf;
  185.       scene->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->u.tex.level);
  186.       scene->zsbuf.layer_stride = llvmpipe_layer_stride(zsbuf->texture, zsbuf->u.tex.level);
  187.       max_layer = MIN2(max_layer, zsbuf->u.tex.last_layer - zsbuf->u.tex.first_layer);
  188.  
  189.       scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture,
  190.                                                zsbuf->u.tex.level,
  191.                                                zsbuf->u.tex.first_layer,
  192.                                                LP_TEX_USAGE_READ_WRITE);
  193.    }
  194.  
  195.    scene->fb_max_layer = max_layer;
  196. }
  197.  
  198.  
  199.  
  200.  
  201. /**
  202.  * Free all the temporary data in a scene.
  203.  */
  204. void
  205. lp_scene_end_rasterization(struct lp_scene *scene )
  206. {
  207.    int i, j;
  208.  
  209.    /* Unmap color buffers */
  210.    for (i = 0; i < scene->fb.nr_cbufs; i++) {
  211.       if (scene->cbufs[i].map) {
  212.          struct pipe_surface *cbuf = scene->fb.cbufs[i];
  213.          if (llvmpipe_resource_is_texture(cbuf->texture)) {
  214.             llvmpipe_resource_unmap(cbuf->texture,
  215.                                     cbuf->u.tex.level,
  216.                                     cbuf->u.tex.first_layer);
  217.          }
  218.          scene->cbufs[i].map = NULL;
  219.       }
  220.    }
  221.  
  222.    /* Unmap z/stencil buffer */
  223.    if (scene->zsbuf.map) {
  224.       struct pipe_surface *zsbuf = scene->fb.zsbuf;
  225.       llvmpipe_resource_unmap(zsbuf->texture,
  226.                               zsbuf->u.tex.level,
  227.                               zsbuf->u.tex.first_layer);
  228.       scene->zsbuf.map = NULL;
  229.    }
  230.  
  231.    /* Reset all command lists:
  232.     */
  233.    for (i = 0; i < scene->tiles_x; i++) {
  234.       for (j = 0; j < scene->tiles_y; j++) {
  235.          struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
  236.          bin->head = NULL;
  237.          bin->tail = NULL;
  238.          bin->last_state = NULL;
  239.       }
  240.    }
  241.  
  242.    /* If there are any bins which weren't cleared by the loop above,
  243.     * they will be caught (on debug builds at least) by this assert:
  244.     */
  245.    assert(lp_scene_is_empty(scene));
  246.  
  247.    /* Decrement texture ref counts
  248.     */
  249.    {
  250.       struct resource_ref *ref;
  251.       int i, j = 0;
  252.  
  253.       for (ref = scene->resources; ref; ref = ref->next) {
  254.          for (i = 0; i < ref->count; i++) {
  255.             if (LP_DEBUG & DEBUG_SETUP)
  256.                debug_printf("resource %d: %p %dx%d sz %d\n",
  257.                             j,
  258.                             (void *) ref->resource[i],
  259.                             ref->resource[i]->width0,
  260.                             ref->resource[i]->height0,
  261.                             llvmpipe_resource_size(ref->resource[i]));
  262.             j++;
  263.             pipe_resource_reference(&ref->resource[i], NULL);
  264.          }
  265.       }
  266.  
  267.       if (LP_DEBUG & DEBUG_SETUP)
  268.          debug_printf("scene %d resources, sz %d\n",
  269.                       j, scene->resource_reference_size);
  270.    }
  271.  
  272.    /* Free all scene data blocks:
  273.     */
  274.    {
  275.       struct data_block_list *list = &scene->data;
  276.       struct data_block *block, *tmp;
  277.  
  278.       for (block = list->head->next; block; block = tmp) {
  279.          tmp = block->next;
  280.          FREE(block);
  281.       }
  282.  
  283.       list->head->next = NULL;
  284.       list->head->used = 0;
  285.    }
  286.  
  287.    lp_fence_reference(&scene->fence, NULL);
  288.  
  289.    scene->resources = NULL;
  290.    scene->scene_size = 0;
  291.    scene->resource_reference_size = 0;
  292.  
  293.    scene->has_depthstencil_clear = FALSE;
  294.    scene->alloc_failed = FALSE;
  295.  
  296.    util_unreference_framebuffer_state( &scene->fb );
  297. }
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304. struct cmd_block *
  305. lp_scene_new_cmd_block( struct lp_scene *scene,
  306.                         struct cmd_bin *bin )
  307. {
  308.    struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block));
  309.    if (block) {
  310.       if (bin->tail) {
  311.          bin->tail->next = block;
  312.          bin->tail = block;
  313.       }
  314.       else {
  315.          bin->head = block;
  316.          bin->tail = block;
  317.       }
  318.       //memset(block, 0, sizeof *block);
  319.       block->next = NULL;
  320.       block->count = 0;
  321.    }
  322.    return block;
  323. }
  324.  
  325.  
  326. struct data_block *
  327. lp_scene_new_data_block( struct lp_scene *scene )
  328. {
  329.    if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) {
  330.       if (0) debug_printf("%s: failed\n", __FUNCTION__);
  331.       scene->alloc_failed = TRUE;
  332.       return NULL;
  333.    }
  334.    else {
  335.       struct data_block *block = MALLOC_STRUCT(data_block);
  336.       if (block == NULL)
  337.          return NULL;
  338.      
  339.       scene->scene_size += sizeof *block;
  340.  
  341.       block->used = 0;
  342.       block->next = scene->data.head;
  343.       scene->data.head = block;
  344.  
  345.       return block;
  346.    }
  347. }
  348.  
  349.  
  350. /**
  351.  * Return number of bytes used for all bin data within a scene.
  352.  * This does not include resources (textures) referenced by the scene.
  353.  */
  354. static unsigned
  355. lp_scene_data_size( const struct lp_scene *scene )
  356. {
  357.    unsigned size = 0;
  358.    const struct data_block *block;
  359.    for (block = scene->data.head; block; block = block->next) {
  360.       size += block->used;
  361.    }
  362.    return size;
  363. }
  364.  
  365.  
  366.  
  367. /**
  368.  * Add a reference to a resource by the scene.
  369.  */
  370. boolean
  371. lp_scene_add_resource_reference(struct lp_scene *scene,
  372.                                 struct pipe_resource *resource,
  373.                                 boolean initializing_scene)
  374. {
  375.    struct resource_ref *ref, **last = &scene->resources;
  376.    int i;
  377.  
  378.    /* Look at existing resource blocks:
  379.     */
  380.    for (ref = scene->resources; ref; ref = ref->next) {
  381.       last = &ref->next;
  382.  
  383.       /* Search for this resource:
  384.        */
  385.       for (i = 0; i < ref->count; i++)
  386.          if (ref->resource[i] == resource)
  387.             return TRUE;
  388.  
  389.       if (ref->count < RESOURCE_REF_SZ) {
  390.          /* If the block is half-empty, then append the reference here.
  391.           */
  392.          break;
  393.       }
  394.    }
  395.  
  396.    /* Create a new block if no half-empty block was found.
  397.     */
  398.    if (!ref) {
  399.       assert(*last == NULL);
  400.       *last = lp_scene_alloc(scene, sizeof *ref);
  401.       if (*last == NULL)
  402.           return FALSE;
  403.  
  404.       ref = *last;
  405.       memset(ref, 0, sizeof *ref);
  406.    }
  407.  
  408.    /* Append the reference to the reference block.
  409.     */
  410.    pipe_resource_reference(&ref->resource[ref->count++], resource);
  411.    scene->resource_reference_size += llvmpipe_resource_size(resource);
  412.  
  413.    /* Heuristic to advise scene flushes.  This isn't helpful in the
  414.     * initial setup of the scene, but after that point flush on the
  415.     * next resource added which exceeds 64MB in referenced texture
  416.     * data.
  417.     */
  418.    if (!initializing_scene &&
  419.        scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE)
  420.       return FALSE;
  421.  
  422.    return TRUE;
  423. }
  424.  
  425.  
  426. /**
  427.  * Does this scene have a reference to the given resource?
  428.  */
  429. boolean
  430. lp_scene_is_resource_referenced(const struct lp_scene *scene,
  431.                                 const struct pipe_resource *resource)
  432. {
  433.    const struct resource_ref *ref;
  434.    int i;
  435.  
  436.    for (ref = scene->resources; ref; ref = ref->next) {
  437.       for (i = 0; i < ref->count; i++)
  438.          if (ref->resource[i] == resource)
  439.             return TRUE;
  440.    }
  441.  
  442.    return FALSE;
  443. }
  444.  
  445.  
  446.  
  447.  
  448. /** advance curr_x,y to the next bin */
  449. static boolean
  450. next_bin(struct lp_scene *scene)
  451. {
  452.    scene->curr_x++;
  453.    if (scene->curr_x >= scene->tiles_x) {
  454.       scene->curr_x = 0;
  455.       scene->curr_y++;
  456.    }
  457.    if (scene->curr_y >= scene->tiles_y) {
  458.       /* no more bins */
  459.       return FALSE;
  460.    }
  461.    return TRUE;
  462. }
  463.  
  464.  
  465. void
  466. lp_scene_bin_iter_begin( struct lp_scene *scene )
  467. {
  468.    scene->curr_x = scene->curr_y = -1;
  469. }
  470.  
  471.  
  472. /**
  473.  * Return pointer to next bin to be rendered.
  474.  * The lp_scene::curr_x and ::curr_y fields will be advanced.
  475.  * Multiple rendering threads will call this function to get a chunk
  476.  * of work (a bin) to work on.
  477.  */
  478. struct cmd_bin *
  479. lp_scene_bin_iter_next( struct lp_scene *scene , int *x, int *y)
  480. {
  481.    struct cmd_bin *bin = NULL;
  482.  
  483.    pipe_mutex_lock(scene->mutex);
  484.  
  485.    if (scene->curr_x < 0) {
  486.       /* first bin */
  487.       scene->curr_x = 0;
  488.       scene->curr_y = 0;
  489.    }
  490.    else if (!next_bin(scene)) {
  491.       /* no more bins left */
  492.       goto end;
  493.    }
  494.  
  495.    bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
  496.    *x = scene->curr_x;
  497.    *y = scene->curr_y;
  498.  
  499. end:
  500.    /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
  501.    pipe_mutex_unlock(scene->mutex);
  502.    return bin;
  503. }
  504.  
  505.  
  506. void lp_scene_begin_binning( struct lp_scene *scene,
  507.                              struct pipe_framebuffer_state *fb, boolean discard )
  508. {
  509.    assert(lp_scene_is_empty(scene));
  510.  
  511.    scene->discard = discard;
  512.    util_copy_framebuffer_state(&scene->fb, fb);
  513.  
  514.    scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
  515.    scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE;
  516.  
  517.    assert(scene->tiles_x <= TILES_X);
  518.    assert(scene->tiles_y <= TILES_Y);
  519. }
  520.  
  521.  
  522. void lp_scene_end_binning( struct lp_scene *scene )
  523. {
  524.    if (LP_DEBUG & DEBUG_SCENE) {
  525.       debug_printf("rasterize scene:\n");
  526.       debug_printf("  scene_size: %u\n",
  527.                    scene->scene_size);
  528.       debug_printf("  data size: %u\n",
  529.                    lp_scene_data_size(scene));
  530.  
  531.       if (0)
  532.          lp_debug_bins( scene );
  533.    }
  534. }
  535.