Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
  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@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 support primitive
  45.  * restart itself. (ctx->Const.PrimitiveRestartInSoftware == GL_TRUE)
  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. {
  168.    GLuint prim_num;
  169.    struct sub_primitive *sub_prims;
  170.    struct sub_primitive *sub_prim;
  171.    GLuint num_sub_prims;
  172.    GLuint sub_prim_num;
  173.    GLuint end_index;
  174.    GLuint sub_end_index;
  175.    GLuint restart_index = _mesa_primitive_restart_index(ctx, ib->type);
  176.    struct _mesa_prim temp_prim;
  177.    struct vbo_context *vbo = vbo_context(ctx);
  178.    vbo_draw_func draw_prims_func = vbo->draw_prims;
  179.    GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer;
  180.    void *ptr;
  181.  
  182.    /* Find the sub-primitives. These are regions in the index buffer which
  183.     * are split based on the primitive restart index value.
  184.     */
  185.    if (map_ib) {
  186.       ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT,
  187.                                  ib->obj);
  188.    }
  189.  
  190.    ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
  191.  
  192.    sub_prims = find_sub_primitives(ptr, vbo_sizeof_ib_type(ib->type),
  193.                                    0, ib->count, restart_index,
  194.                                    &num_sub_prims);
  195.  
  196.    if (map_ib) {
  197.       ctx->Driver.UnmapBuffer(ctx, ib->obj);
  198.    }
  199.  
  200.    /* Loop over the primitives, and use the located sub-primitives to draw
  201.     * each primitive with a break to implement each primitive restart.
  202.     */
  203.    for (prim_num = 0; prim_num < nr_prims; prim_num++) {
  204.       end_index = prims[prim_num].start + prims[prim_num].count;
  205.       memcpy(&temp_prim, &prims[prim_num], sizeof (temp_prim));
  206.       /* Loop over the sub-primitives drawing sub-ranges of the primitive. */
  207.       for (sub_prim_num = 0; sub_prim_num < num_sub_prims; sub_prim_num++) {
  208.          sub_prim = &sub_prims[sub_prim_num];
  209.          sub_end_index = sub_prim->start + sub_prim->count;
  210.          if (prims[prim_num].start <= sub_prim->start) {
  211.             temp_prim.start = MAX2(prims[prim_num].start, sub_prim->start);
  212.             temp_prim.count = MIN2(sub_end_index, end_index) - temp_prim.start;
  213.             if ((temp_prim.start == sub_prim->start) &&
  214.                 (temp_prim.count == sub_prim->count)) {
  215.                draw_prims_func(ctx, &temp_prim, 1, ib,
  216.                                GL_TRUE, sub_prim->min_index, sub_prim->max_index,
  217.                                NULL);
  218.             } else {
  219.                draw_prims_func(ctx, &temp_prim, 1, ib,
  220.                                GL_FALSE, -1, -1,
  221.                                NULL);
  222.             }
  223.          }
  224.          if (sub_end_index >= end_index) {
  225.             break;
  226.          }
  227.       }
  228.    }
  229.  
  230.    free(sub_prims);
  231. }
  232.  
  233.