Home | History | Annotate | Download | only in vbo
      1 /*
      2  * Copyright 2007 VMware, Inc.
      3  * All Rights Reserved.
      4  *
      5  * Copyright  2012 Intel Corporation
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the next
     15  * paragraph) shall be included in all copies or substantial portions of the
     16  * Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     24  * IN THE SOFTWARE.
     25  *
     26  * Authors:
     27  *    Jordan Justen <jordan.l.justen (at) intel.com>
     28  *
     29  */
     30 
     31 #include "main/imports.h"
     32 #include "main/bufferobj.h"
     33 #include "main/macros.h"
     34 #include "main/varray.h"
     35 
     36 #include "vbo.h"
     37 #include "vbo_context.h"
     38 
     39 #define UPDATE_MIN2(a, b) (a) = MIN2((a), (b))
     40 #define UPDATE_MAX2(a, b) (a) = MAX2((a), (b))
     41 
     42 /*
     43  * Notes on primitive restart:
     44  * The code below is used when the driver does not fully support primitive
     45  * restart (for example, if it only does restart index of ~0).
     46  *
     47  * We map the index buffer, find the restart indexes, unmap
     48  * the index buffer then draw the sub-primitives delineated by the restarts.
     49  *
     50  * A couple possible optimizations:
     51  * 1. Save the list of sub-primitive (start, count) values in a list attached
     52  *    to the index buffer for re-use in subsequent draws.  The list would be
     53  *    invalidated when the contents of the buffer changed.
     54  * 2. If drawing triangle strips or quad strips, create a new index buffer
     55  *    that uses duplicated vertices to render the disjoint strips as one
     56  *    long strip.  We'd have to be careful to avoid using too much memory
     57  *    for this.
     58  *
     59  * Finally, some apps might perform better if they don't use primitive restart
     60  * at all rather than this fallback path.  Set MESA_EXTENSION_OVERRIDE to
     61  * "-GL_NV_primitive_restart" to test that.
     62  */
     63 
     64 
     65 struct sub_primitive
     66 {
     67    GLuint start;
     68    GLuint count;
     69    GLuint min_index;
     70    GLuint max_index;
     71 };
     72 
     73 
     74 /**
     75  * Scan the elements array to find restart indexes.  Return an array
     76  * of struct sub_primitive to indicate how to draw the sub-primitives
     77  * are delineated by the restart index.
     78  */
     79 static struct sub_primitive *
     80 find_sub_primitives(const void *elements, unsigned element_size,
     81                     unsigned start, unsigned end, unsigned restart_index,
     82                     unsigned *num_sub_prims)
     83 {
     84    const unsigned max_prims = end - start;
     85    struct sub_primitive *sub_prims;
     86    unsigned i, cur_start, cur_count;
     87    GLuint scan_index;
     88    unsigned scan_num;
     89 
     90    sub_prims =
     91       malloc(max_prims * sizeof(struct sub_primitive));
     92 
     93    if (!sub_prims) {
     94       *num_sub_prims = 0;
     95       return NULL;
     96    }
     97 
     98    cur_start = start;
     99    cur_count = 0;
    100    scan_num = 0;
    101 
    102 #define IB_INDEX_READ(TYPE, INDEX) (((const GL##TYPE *) elements)[INDEX])
    103 
    104 #define SCAN_ELEMENTS(TYPE) \
    105    sub_prims[scan_num].min_index = (GL##TYPE) 0xffffffff; \
    106    sub_prims[scan_num].max_index = 0; \
    107    for (i = start; i < end; i++) { \
    108       scan_index = IB_INDEX_READ(TYPE, i); \
    109       if (scan_index == restart_index) { \
    110          if (cur_count > 0) { \
    111             assert(scan_num < max_prims); \
    112             sub_prims[scan_num].start = cur_start; \
    113             sub_prims[scan_num].count = cur_count; \
    114             scan_num++; \
    115             sub_prims[scan_num].min_index = (GL##TYPE) 0xffffffff; \
    116             sub_prims[scan_num].max_index = 0; \
    117          } \
    118          cur_start = i + 1; \
    119          cur_count = 0; \
    120       } \
    121       else { \
    122          UPDATE_MIN2(sub_prims[scan_num].min_index, scan_index); \
    123          UPDATE_MAX2(sub_prims[scan_num].max_index, scan_index); \
    124          cur_count++; \
    125       } \
    126    } \
    127    if (cur_count > 0) { \
    128       assert(scan_num < max_prims); \
    129       sub_prims[scan_num].start = cur_start; \
    130       sub_prims[scan_num].count = cur_count; \
    131       scan_num++; \
    132    }
    133 
    134    switch (element_size) {
    135    case 1:
    136       SCAN_ELEMENTS(ubyte);
    137       break;
    138    case 2:
    139       SCAN_ELEMENTS(ushort);
    140       break;
    141    case 4:
    142       SCAN_ELEMENTS(uint);
    143       break;
    144    default:
    145       assert(0 && "bad index_size in find_sub_primitives()");
    146    }
    147 
    148 #undef SCAN_ELEMENTS
    149 
    150    *num_sub_prims = scan_num;
    151 
    152    return sub_prims;
    153 }
    154 
    155 
    156 /**
    157  * Handle primitive restart in software.
    158  *
    159  * This function breaks up calls into the driver so primitive restart
    160  * support is not required in the driver.
    161  */
    162 void
    163 vbo_sw_primitive_restart(struct gl_context *ctx,
    164                          const struct _mesa_prim *prims,
    165                          GLuint nr_prims,
    166                          const struct _mesa_index_buffer *ib,
    167                          struct gl_buffer_object *indirect)
    168 {
    169    GLuint prim_num;
    170    struct _mesa_prim new_prim;
    171    struct _mesa_index_buffer new_ib;
    172    struct sub_primitive *sub_prims;
    173    struct sub_primitive *sub_prim;
    174    GLuint num_sub_prims;
    175    GLuint sub_prim_num;
    176    GLuint end_index;
    177    GLuint sub_end_index;
    178    GLuint restart_index = _mesa_primitive_restart_index(ctx, ib->index_size);
    179    struct _mesa_prim temp_prim;
    180    struct vbo_context *vbo = vbo_context(ctx);
    181    vbo_draw_func draw_prims_func = vbo->draw_prims;
    182    GLboolean map_ib = ib->obj->Name && !ib->obj->Mappings[MAP_INTERNAL].Pointer;
    183    void *ptr;
    184 
    185    /* If there is an indirect buffer, map it and extract the draw params */
    186    if (indirect && prims[0].is_indirect) {
    187       const uint32_t *indirect_params;
    188       if (!ctx->Driver.MapBufferRange(ctx, 0, indirect->Size, GL_MAP_READ_BIT,
    189                                       indirect, MAP_INTERNAL)) {
    190 
    191          /* something went wrong with mapping, give up */
    192          _mesa_error(ctx, GL_OUT_OF_MEMORY,
    193                      "failed to map indirect buffer for sw primitive restart");
    194          return;
    195       }
    196 
    197       assert(nr_prims == 1);
    198       new_prim = prims[0];
    199       indirect_params = (const uint32_t *)
    200                         ADD_POINTERS(indirect->Mappings[MAP_INTERNAL].Pointer,
    201                                      new_prim.indirect_offset);
    202 
    203       new_prim.is_indirect = 0;
    204       new_prim.count = indirect_params[0];
    205       new_prim.num_instances = indirect_params[1];
    206       new_prim.start = indirect_params[2];
    207       new_prim.basevertex = indirect_params[3];
    208       new_prim.base_instance = indirect_params[4];
    209 
    210       new_ib = *ib;
    211       new_ib.count = new_prim.count;
    212 
    213       prims = &new_prim;
    214       ib = &new_ib;
    215 
    216       ctx->Driver.UnmapBuffer(ctx, indirect, MAP_INTERNAL);
    217    }
    218 
    219    /* Find the sub-primitives. These are regions in the index buffer which
    220     * are split based on the primitive restart index value.
    221     */
    222    if (map_ib) {
    223       ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT,
    224                                  ib->obj, MAP_INTERNAL);
    225    }
    226 
    227    ptr = ADD_POINTERS(ib->obj->Mappings[MAP_INTERNAL].Pointer, ib->ptr);
    228 
    229    sub_prims = find_sub_primitives(ptr, ib->index_size,
    230                                    0, ib->count, restart_index,
    231                                    &num_sub_prims);
    232 
    233    if (map_ib) {
    234       ctx->Driver.UnmapBuffer(ctx, ib->obj, MAP_INTERNAL);
    235    }
    236 
    237    /* Loop over the primitives, and use the located sub-primitives to draw
    238     * each primitive with a break to implement each primitive restart.
    239     */
    240    for (prim_num = 0; prim_num < nr_prims; prim_num++) {
    241       end_index = prims[prim_num].start + prims[prim_num].count;
    242       memcpy(&temp_prim, &prims[prim_num], sizeof (temp_prim));
    243       /* Loop over the sub-primitives drawing sub-ranges of the primitive. */
    244       for (sub_prim_num = 0; sub_prim_num < num_sub_prims; sub_prim_num++) {
    245          sub_prim = &sub_prims[sub_prim_num];
    246          sub_end_index = sub_prim->start + sub_prim->count;
    247          if (prims[prim_num].start <= sub_prim->start) {
    248             temp_prim.start = MAX2(prims[prim_num].start, sub_prim->start);
    249             temp_prim.count = MIN2(sub_end_index, end_index) - temp_prim.start;
    250             if ((temp_prim.start == sub_prim->start) &&
    251                 (temp_prim.count == sub_prim->count)) {
    252                draw_prims_func(ctx, &temp_prim, 1, ib,
    253                                GL_TRUE, sub_prim->min_index, sub_prim->max_index,
    254                                NULL, 0, NULL);
    255             } else {
    256                draw_prims_func(ctx, &temp_prim, 1, ib,
    257                                GL_FALSE, -1, -1,
    258                                NULL, 0, NULL);
    259             }
    260          }
    261          if (sub_end_index >= end_index) {
    262             break;
    263          }
    264       }
    265    }
    266 
    267    free(sub_prims);
    268 }
    269 
    270