Subversion Repositories Kolibri OS

Rev

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

  1.  
  2. /*
  3.  * Mesa 3-D graphics library
  4.  *
  5.  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
  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 shall be included
  15.  * in all copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23.  * OTHER DEALINGS IN THE SOFTWARE.
  24.  *
  25.  * Authors:
  26.  *    Keith Whitwell <keith@tungstengraphics.com>
  27.  */
  28.  
  29.  
  30. #include "main/mtypes.h"
  31. #include "main/macros.h"
  32. #include "main/enums.h"
  33. #include "main/glformats.h"
  34. #include "vbo_split.h"
  35.  
  36.  
  37. #define MAX_PRIM 32
  38.  
  39. /* Used for splitting without copying. No attempt is made to handle
  40.  * too large indexed vertex buffers: In general you need to copy to do
  41.  * that.
  42.  */
  43. struct split_context {
  44.    struct gl_context *ctx;
  45.    const struct gl_client_array **array;
  46.    const struct _mesa_prim *prim;
  47.    GLuint nr_prims;
  48.    const struct _mesa_index_buffer *ib;
  49.    GLuint min_index;
  50.    GLuint max_index;
  51.    vbo_draw_func draw;
  52.  
  53.    const struct split_limits *limits;
  54.    GLuint limit;
  55.  
  56.    struct _mesa_prim dstprim[MAX_PRIM];
  57.    GLuint dstprim_nr;
  58. };
  59.  
  60.  
  61.  
  62.  
  63. static void flush_vertex( struct split_context *split )
  64. {
  65.    struct gl_context *ctx = split->ctx;
  66.    const struct gl_client_array **saved_arrays = ctx->Array._DrawArrays;
  67.    struct _mesa_index_buffer ib;
  68.    GLuint i;
  69.  
  70.    if (!split->dstprim_nr)
  71.       return;
  72.  
  73.    if (split->ib) {
  74.       ib = *split->ib;
  75.  
  76.       ib.count = split->max_index - split->min_index + 1;
  77.       ib.ptr = (const void *)((const char *)ib.ptr +
  78.                               split->min_index * _mesa_sizeof_type(ib.type));
  79.  
  80.       /* Rebase the primitives to save index buffer entries. */
  81.       for (i = 0; i < split->dstprim_nr; i++)
  82.          split->dstprim[i].start -= split->min_index;
  83.    }
  84.  
  85.    assert(split->max_index >= split->min_index);
  86.  
  87.    ctx->Array._DrawArrays = split->array;
  88.    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
  89.  
  90.    split->draw(ctx,
  91.                split->dstprim,
  92.                split->dstprim_nr,
  93.                split->ib ? &ib : NULL,
  94.                !split->ib,
  95.                split->min_index,
  96.                split->max_index,
  97.                NULL);
  98.  
  99.    ctx->Array._DrawArrays = saved_arrays;
  100.    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
  101.  
  102.    split->dstprim_nr = 0;
  103.    split->min_index = ~0;
  104.    split->max_index = 0;
  105. }
  106.  
  107.  
  108. static struct _mesa_prim *next_outprim( struct split_context *split )
  109. {
  110.    if (split->dstprim_nr == MAX_PRIM-1) {
  111.       flush_vertex(split);
  112.    }
  113.  
  114.    {
  115.       struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
  116.       memset(prim, 0, sizeof(*prim));
  117.       return prim;
  118.    }
  119. }
  120.  
  121. static void update_index_bounds(struct split_context *split,
  122.                                 const struct _mesa_prim *prim)
  123. {
  124.    split->min_index = MIN2(split->min_index, prim->start);
  125.    split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
  126. }
  127.  
  128. /* Return the maximum amount of vertices that can be emitted for a
  129.  * primitive starting at 'prim->start', depending on the previous
  130.  * index bounds.
  131.  */
  132. static GLuint get_max_vertices(struct split_context *split,
  133.                                const struct _mesa_prim *prim)
  134. {
  135.    if ((prim->start > split->min_index &&
  136.         prim->start - split->min_index >= split->limit) ||
  137.        (prim->start < split->max_index &&
  138.         split->max_index - prim->start >= split->limit))
  139.       /* "prim" starts too far away from the old range. */
  140.       return 0;
  141.  
  142.    return MIN2(split->min_index, prim->start) + split->limit - prim->start;
  143. }
  144.  
  145. /* Break large primitives into smaller ones.  If not possible, convert
  146.  * the primitive to indexed and pass to split_elts().
  147.  */
  148. static void split_prims( struct split_context *split)
  149. {
  150.    GLuint i;
  151.  
  152.    for (i = 0; i < split->nr_prims; i++) {
  153.       const struct _mesa_prim *prim = &split->prim[i];
  154.       GLuint first, incr;
  155.       GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
  156.       GLuint available = get_max_vertices(split, prim);
  157.       GLuint count = prim->count - (prim->count - first) % incr;
  158.  
  159.       if (prim->count < first)
  160.          continue;
  161.  
  162.       if ((available < count && !split_inplace) ||
  163.           (available < first && split_inplace)) {
  164.          flush_vertex(split);
  165.          available = get_max_vertices(split, prim);
  166.       }
  167.      
  168.       if (available >= count) {
  169.          struct _mesa_prim *outprim = next_outprim(split);
  170.  
  171.          *outprim = *prim;
  172.          update_index_bounds(split, outprim);
  173.       }
  174.       else if (split_inplace) {
  175.          GLuint j, nr;
  176.  
  177.          for (j = 0 ; j < count ; ) {
  178.             GLuint remaining = count - j;
  179.             struct _mesa_prim *outprim = next_outprim(split);
  180.  
  181.             nr = MIN2( available, remaining );
  182.             nr -= (nr - first) % incr;
  183.  
  184.             outprim->mode = prim->mode;
  185.             outprim->begin = (j == 0 && prim->begin);
  186.             outprim->end = (nr == remaining && prim->end);
  187.             outprim->start = prim->start + j;
  188.             outprim->count = nr;
  189.             outprim->num_instances = prim->num_instances;
  190.             outprim->base_instance = prim->base_instance;
  191.  
  192.             update_index_bounds(split, outprim);
  193.  
  194.             if (nr == remaining) {
  195.                /* Finished.
  196.                 */
  197.                j += nr;
  198.             }
  199.             else {
  200.                /* Wrapped the primitive:
  201.                 */
  202.                j += nr - (first - incr);
  203.                flush_vertex(split);
  204.                available = get_max_vertices(split, prim);
  205.             }
  206.          }
  207.       }
  208.       else if (split->ib == NULL) {
  209.          /* XXX: could at least send the first max_verts off from the
  210.           * inplace buffers.
  211.           */
  212.  
  213.          /* else convert to indexed primitive and pass to split_elts,
  214.           * which will do the necessary copying and turn it back into a
  215.           * vertex primitive for rendering...
  216.           */
  217.          struct _mesa_index_buffer ib;
  218.          struct _mesa_prim tmpprim;
  219.          GLuint *elts = malloc(count * sizeof(GLuint));
  220.          GLuint j;
  221.          
  222.          for (j = 0; j < count; j++)
  223.             elts[j] = prim->start + j;
  224.  
  225.          ib.count = count;
  226.          ib.type = GL_UNSIGNED_INT;
  227.          ib.obj = split->ctx->Shared->NullBufferObj;
  228.          ib.ptr = elts;
  229.  
  230.          tmpprim = *prim;
  231.          tmpprim.indexed = 1;
  232.          tmpprim.start = 0;
  233.          tmpprim.count = count;
  234.          tmpprim.num_instances = 1;
  235.          tmpprim.base_instance = 0;
  236.  
  237.          flush_vertex(split);
  238.  
  239.          vbo_split_copy(split->ctx,
  240.                         split->array,
  241.                         &tmpprim, 1,
  242.                         &ib,
  243.                         split->draw,
  244.                         split->limits);
  245.            
  246.          free(elts);
  247.       }
  248.       else {
  249.          flush_vertex(split);
  250.  
  251.          vbo_split_copy(split->ctx,
  252.                         split->array,
  253.                         prim, 1,
  254.                         split->ib,
  255.                         split->draw,
  256.                         split->limits);
  257.       }
  258.    }
  259.  
  260.    flush_vertex(split);
  261. }
  262.  
  263.  
  264. void vbo_split_inplace( struct gl_context *ctx,
  265.                         const struct gl_client_array *arrays[],
  266.                         const struct _mesa_prim *prim,
  267.                         GLuint nr_prims,
  268.                         const struct _mesa_index_buffer *ib,
  269.                         GLuint min_index,
  270.                         GLuint max_index,
  271.                         vbo_draw_func draw,
  272.                         const struct split_limits *limits )
  273. {
  274.    struct split_context split;
  275.  
  276.    memset(&split, 0, sizeof(split));
  277.  
  278.    split.ctx = ctx;
  279.    split.array = arrays;
  280.    split.prim = prim;
  281.    split.nr_prims = nr_prims;
  282.    split.ib = ib;
  283.  
  284.    /* Empty interval, makes calculations simpler. */
  285.    split.min_index = ~0;
  286.    split.max_index = 0;
  287.  
  288.    split.draw = draw;
  289.    split.limits = limits;
  290.    split.limit = ib ? limits->max_indices : limits->max_verts;
  291.  
  292.    split_prims( &split );
  293. }
  294.  
  295.  
  296.