Subversion Repositories Kolibri OS

Rev

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

  1.  
  2. /*
  3.  * Mesa 3-D graphics library
  4.  * Version:  6.5
  5.  *
  6.  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
  7.  *
  8.  * Permission is hereby granted, free of charge, to any person obtaining a
  9.  * copy of this software and associated documentation files (the "Software"),
  10.  * to deal in the Software without restriction, including without limitation
  11.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12.  * and/or sell copies of the Software, and to permit persons to whom the
  13.  * Software is furnished to do so, subject to the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice shall be included
  16.  * in all copies or substantial portions 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 MERCHANTABILITY,
  20.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  21.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  22.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23.  * CONNECTION WITH THE SOFTWARE OR THE USE OR 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/image.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 _mesa_index_buffer ib;
  66.    GLuint i;
  67.  
  68.    if (!split->dstprim_nr)
  69.       return;
  70.  
  71.    if (split->ib) {
  72.       ib = *split->ib;
  73.  
  74.       ib.count = split->max_index - split->min_index + 1;
  75.       ib.ptr = (const void *)((const char *)ib.ptr +
  76.                               split->min_index * _mesa_sizeof_type(ib.type));
  77.  
  78.       /* Rebase the primitives to save index buffer entries. */
  79.       for (i = 0; i < split->dstprim_nr; i++)
  80.          split->dstprim[i].start -= split->min_index;
  81.    }
  82.  
  83.    assert(split->max_index >= split->min_index);
  84.  
  85.    split->draw(split->ctx,
  86.                split->array,
  87.                split->dstprim,
  88.                split->dstprim_nr,
  89.                split->ib ? &ib : NULL,
  90.                !split->ib,
  91.                split->min_index,
  92.                split->max_index);
  93.  
  94.    split->dstprim_nr = 0;
  95.    split->min_index = ~0;
  96.    split->max_index = 0;
  97. }
  98.  
  99.  
  100. static struct _mesa_prim *next_outprim( struct split_context *split )
  101. {
  102.    if (split->dstprim_nr == MAX_PRIM-1) {
  103.       flush_vertex(split);
  104.    }
  105.  
  106.    {
  107.       struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
  108.       memset(prim, 0, sizeof(*prim));
  109.       return prim;
  110.    }
  111. }
  112.  
  113. static void update_index_bounds(struct split_context *split,
  114.                                 const struct _mesa_prim *prim)
  115. {
  116.    split->min_index = MIN2(split->min_index, prim->start);
  117.    split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
  118. }
  119.  
  120. /* Return the maximum amount of vertices that can be emitted for a
  121.  * primitive starting at 'prim->start', depending on the previous
  122.  * index bounds.
  123.  */
  124. static GLuint get_max_vertices(struct split_context *split,
  125.                                const struct _mesa_prim *prim)
  126. {
  127.    if ((prim->start > split->min_index &&
  128.         prim->start - split->min_index >= split->limit) ||
  129.        (prim->start < split->max_index &&
  130.         split->max_index - prim->start >= split->limit))
  131.       /* "prim" starts too far away from the old range. */
  132.       return 0;
  133.  
  134.    return MIN2(split->min_index, prim->start) + split->limit - prim->start;
  135. }
  136.  
  137. /* Break large primitives into smaller ones.  If not possible, convert
  138.  * the primitive to indexed and pass to split_elts().
  139.  */
  140. static void split_prims( struct split_context *split)
  141. {
  142.    GLuint i;
  143.  
  144.    for (i = 0; i < split->nr_prims; i++) {
  145.       const struct _mesa_prim *prim = &split->prim[i];
  146.       GLuint first, incr;
  147.       GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
  148.       GLuint available = get_max_vertices(split, prim);
  149.       GLuint count = prim->count - (prim->count - first) % incr;
  150.  
  151.       if (prim->count < first)
  152.          continue;
  153.  
  154.       if ((available < count && !split_inplace) ||
  155.           (available < first && split_inplace)) {
  156.          flush_vertex(split);
  157.          available = get_max_vertices(split, prim);
  158.       }
  159.      
  160.       if (available >= count) {
  161.          struct _mesa_prim *outprim = next_outprim(split);
  162.  
  163.          *outprim = *prim;
  164.          update_index_bounds(split, outprim);
  165.       }
  166.       else if (split_inplace) {
  167.          GLuint j, nr;
  168.  
  169.          for (j = 0 ; j < count ; ) {
  170.             GLuint remaining = count - j;
  171.             struct _mesa_prim *outprim = next_outprim(split);
  172.  
  173.             nr = MIN2( available, remaining );
  174.             nr -= (nr - first) % incr;
  175.            
  176.             outprim->mode = prim->mode;
  177.             outprim->begin = (j == 0 && prim->begin);
  178.             outprim->end = (nr == remaining && prim->end);
  179.             outprim->start = prim->start + j;
  180.             outprim->count = nr;
  181.  
  182.             update_index_bounds(split, outprim);
  183.  
  184.             if (nr == remaining) {
  185.                /* Finished.
  186.                 */
  187.                j += nr;
  188.             }
  189.             else {
  190.                /* Wrapped the primitive:
  191.                 */
  192.                j += nr - (first - incr);
  193.                flush_vertex(split);
  194.                available = get_max_vertices(split, prim);
  195.             }
  196.          }
  197.       }
  198.       else if (split->ib == NULL) {
  199.          /* XXX: could at least send the first max_verts off from the
  200.           * inplace buffers.
  201.           */
  202.  
  203.          /* else convert to indexed primitive and pass to split_elts,
  204.           * which will do the necessary copying and turn it back into a
  205.           * vertex primitive for rendering...
  206.           */
  207.          struct _mesa_index_buffer ib;
  208.          struct _mesa_prim tmpprim;
  209.          GLuint *elts = malloc(count * sizeof(GLuint));
  210.          GLuint j;
  211.          
  212.          for (j = 0; j < count; j++)
  213.             elts[j] = prim->start + j;
  214.  
  215.          ib.count = count;
  216.          ib.type = GL_UNSIGNED_INT;
  217.          ib.obj = split->ctx->Shared->NullBufferObj;
  218.          ib.ptr = elts;
  219.            
  220.          tmpprim = *prim;
  221.          tmpprim.indexed = 1;
  222.          tmpprim.start = 0;
  223.          tmpprim.count = count;
  224.  
  225.          flush_vertex(split);
  226.  
  227.          vbo_split_copy(split->ctx,
  228.                         split->array,
  229.                         &tmpprim, 1,
  230.                         &ib,
  231.                         split->draw,
  232.                         split->limits);
  233.            
  234.          free(elts);
  235.       }
  236.       else {
  237.          flush_vertex(split);
  238.  
  239.          vbo_split_copy(split->ctx,
  240.                         split->array,
  241.                         prim, 1,
  242.                         split->ib,
  243.                         split->draw,
  244.                         split->limits);
  245.       }
  246.    }
  247.  
  248.    flush_vertex(split);
  249. }
  250.  
  251.  
  252. void vbo_split_inplace( struct gl_context *ctx,
  253.                         const struct gl_client_array *arrays[],
  254.                         const struct _mesa_prim *prim,
  255.                         GLuint nr_prims,
  256.                         const struct _mesa_index_buffer *ib,
  257.                         GLuint min_index,
  258.                         GLuint max_index,
  259.                         vbo_draw_func draw,
  260.                         const struct split_limits *limits )
  261. {
  262.    struct split_context split;
  263.  
  264.    memset(&split, 0, sizeof(split));
  265.  
  266.    split.ctx = ctx;
  267.    split.array = arrays;
  268.    split.prim = prim;
  269.    split.nr_prims = nr_prims;
  270.    split.ib = ib;
  271.  
  272.    /* Empty interval, makes calculations simpler. */
  273.    split.min_index = ~0;
  274.    split.max_index = 0;
  275.  
  276.    split.draw = draw;
  277.    split.limits = limits;
  278.    split.limit = ib ? limits->max_indices : limits->max_verts;
  279.  
  280.    split_prims( &split );
  281. }
  282.  
  283.  
  284.