Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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@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->type);
  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, vbo_sizeof_ib_type(ib->type),
  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, NULL);
  255.             } else {
  256.                draw_prims_func(ctx, &temp_prim, 1, ib,
  257.                                GL_FALSE, -1, -1,
  258.                                NULL, NULL);
  259.             }
  260.          }
  261.          if (sub_end_index >= end_index) {
  262.             break;
  263.          }
  264.       }
  265.    }
  266.  
  267.    free(sub_prims);
  268. }
  269.  
  270.