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. /* Split indexed primitives with per-vertex copying.
  30.  */
  31.  
  32. #include "main/glheader.h"
  33. #include "main/bufferobj.h"
  34. #include "main/imports.h"
  35. #include "main/image.h"
  36. #include "main/macros.h"
  37. #include "main/mtypes.h"
  38.  
  39. #include "vbo_split.h"
  40. #include "vbo.h"
  41.  
  42.  
  43. #define ELT_TABLE_SIZE 16
  44.  
  45. /**
  46.  * Used for vertex-level splitting of indexed buffers.  Note that
  47.  * non-indexed primitives may be converted to indexed in some cases
  48.  * (eg loops, fans) in order to use this splitting path.
  49.  */
  50. struct copy_context {
  51.  
  52.    struct gl_context *ctx;
  53.    const struct gl_client_array **array;
  54.    const struct _mesa_prim *prim;
  55.    GLuint nr_prims;
  56.    const struct _mesa_index_buffer *ib;
  57.    vbo_draw_func draw;
  58.  
  59.    const struct split_limits *limits;
  60.  
  61.    struct {
  62.       GLuint attr;
  63.       GLuint size;
  64.       const struct gl_client_array *array;
  65.       const GLubyte *src_ptr;
  66.  
  67.       struct gl_client_array dstarray;
  68.  
  69.    } varying[VERT_ATTRIB_MAX];
  70.    GLuint nr_varying;
  71.  
  72.    const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX];
  73.    struct _mesa_index_buffer dstib;
  74.  
  75.    GLuint *translated_elt_buf;
  76.    const GLuint *srcelt;
  77.  
  78.    /** A baby hash table to avoid re-emitting (some) duplicate
  79.     * vertices when splitting indexed primitives.
  80.     */
  81.    struct {
  82.       GLuint in;
  83.       GLuint out;
  84.    } vert_cache[ELT_TABLE_SIZE];
  85.  
  86.    GLuint vertex_size;
  87.    GLubyte *dstbuf;
  88.    GLubyte *dstptr;     /**< dstptr == dstbuf + dstelt_max * vertsize */
  89.    GLuint dstbuf_size;  /**< in vertices */
  90.    GLuint dstbuf_nr;    /**< count of emitted vertices, also the largest value
  91.                          * in dstelt.  Our MaxIndex.
  92.                          */
  93.  
  94.    GLuint *dstelt;
  95.    GLuint dstelt_nr;
  96.    GLuint dstelt_size;
  97.  
  98. #define MAX_PRIM 32
  99.    struct _mesa_prim dstprim[MAX_PRIM];
  100.    GLuint dstprim_nr;
  101.  
  102. };
  103.  
  104.  
  105. static GLuint attr_size( const struct gl_client_array *array )
  106. {
  107.    return array->Size * _mesa_sizeof_type(array->Type);
  108. }
  109.  
  110.  
  111. /**
  112.  * Starts returning true slightly before the buffer fills, to ensure
  113.  * that there is sufficient room for any remaining vertices to finish
  114.  * off the prim:
  115.  */
  116. static GLboolean
  117. check_flush( struct copy_context *copy )
  118. {
  119.    GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
  120.  
  121.    if (GL_TRIANGLE_STRIP == mode &&
  122.        copy->dstelt_nr & 1) { /* see bug9962 */
  123.        return GL_FALSE;
  124.    }
  125.  
  126.    if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
  127.       return GL_TRUE;
  128.  
  129.    if (copy->dstelt_nr + 4 > copy->dstelt_size)
  130.       return GL_TRUE;
  131.  
  132.    return GL_FALSE;
  133. }
  134.  
  135.  
  136. /**
  137.  * Dump the parameters/info for a vbo->draw() call.
  138.  */
  139. static void
  140. dump_draw_info(struct gl_context *ctx,
  141.                const struct gl_client_array **arrays,
  142.                const struct _mesa_prim *prims,
  143.                GLuint nr_prims,
  144.                const struct _mesa_index_buffer *ib,
  145.                GLuint min_index,
  146.                GLuint max_index)
  147. {
  148.    GLuint i, j;
  149.  
  150.    printf("VBO Draw:\n");
  151.    for (i = 0; i < nr_prims; i++) {
  152.       printf("Prim %u of %u\n", i, nr_prims);
  153.       printf("  Prim mode 0x%x\n", prims[i].mode);
  154.       printf("  IB: %p\n", (void*) ib);
  155.       for (j = 0; j < VERT_ATTRIB_MAX; j++) {
  156.          printf("    array %d at %p:\n", j, (void*) arrays[j]);
  157.          printf("      enabled %d, ptr %p, size %d, type 0x%x, stride %d\n",
  158.                 arrays[j]->Enabled, arrays[j]->Ptr,
  159.                 arrays[j]->Size, arrays[j]->Type, arrays[j]->StrideB);
  160.          if (0) {
  161.             GLint k = prims[i].start + prims[i].count - 1;
  162.             GLfloat *last = (GLfloat *) (arrays[j]->Ptr + arrays[j]->Stride * k);
  163.             printf("        last: %f %f %f\n",
  164.                    last[0], last[1], last[2]);
  165.          }
  166.       }
  167.    }
  168. }
  169.  
  170.  
  171. static void
  172. flush( struct copy_context *copy )
  173. {
  174.    GLuint i;
  175.  
  176.    /* Set some counters:
  177.     */
  178.    copy->dstib.count = copy->dstelt_nr;
  179.  
  180. #if 0
  181.    dump_draw_info(copy->ctx,
  182.                   copy->dstarray_ptr,
  183.                   copy->dstprim,
  184.                   copy->dstprim_nr,
  185.                   &copy->dstib,
  186.                   0,
  187.                   copy->dstbuf_nr);
  188. #else
  189.    (void) dump_draw_info;
  190. #endif
  191.  
  192.    copy->draw( copy->ctx,
  193.                copy->dstarray_ptr,
  194.                copy->dstprim,
  195.                copy->dstprim_nr,
  196.                &copy->dstib,
  197.                GL_TRUE,
  198.                0,
  199.                copy->dstbuf_nr - 1 );
  200.  
  201.    /* Reset all pointers:
  202.     */
  203.    copy->dstprim_nr = 0;
  204.    copy->dstelt_nr = 0;
  205.    copy->dstbuf_nr = 0;
  206.    copy->dstptr = copy->dstbuf;
  207.  
  208.    /* Clear the vertex cache:
  209.     */
  210.    for (i = 0; i < ELT_TABLE_SIZE; i++)
  211.       copy->vert_cache[i].in = ~0;
  212. }
  213.  
  214.  
  215. /**
  216.  * Called at begin of each primitive during replay.
  217.  */
  218. static void
  219. begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
  220. {
  221.    struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
  222.  
  223.    prim->mode = mode;
  224.    prim->begin = begin_flag;
  225. }
  226.  
  227.  
  228. /**
  229.  * Use a hashtable to attempt to identify recently-emitted vertices
  230.  * and avoid re-emitting them.
  231.  */
  232. static GLuint
  233. elt(struct copy_context *copy, GLuint elt_idx)
  234. {
  235.    GLuint elt = copy->srcelt[elt_idx];
  236.    GLuint slot = elt & (ELT_TABLE_SIZE-1);
  237.  
  238. /*    printf("elt %d\n", elt); */
  239.  
  240.    /* Look up the incoming element in the vertex cache.  Re-emit if
  241.     * necessary.  
  242.     */
  243.    if (copy->vert_cache[slot].in != elt) {
  244.       GLubyte *csr = copy->dstptr;
  245.       GLuint i;
  246.  
  247. /*       printf("  --> emit to dstelt %d\n", copy->dstbuf_nr); */
  248.  
  249.       for (i = 0; i < copy->nr_varying; i++) {
  250.          const struct gl_client_array *srcarray = copy->varying[i].array;
  251.          const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
  252.  
  253.          memcpy(csr, srcptr, copy->varying[i].size);
  254.          csr += copy->varying[i].size;
  255.  
  256. #ifdef NAN_CHECK
  257.          if (srcarray->Type == GL_FLOAT) {
  258.             GLuint k;
  259.             GLfloat *f = (GLfloat *) srcptr;
  260.             for (k = 0; k < srcarray->Size; k++) {
  261.                assert(!IS_INF_OR_NAN(f[k]));
  262.                assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
  263.             }
  264.          }
  265. #endif
  266.  
  267.          if (0)
  268.          {
  269.             const GLuint *f = (const GLuint *)srcptr;
  270.             GLuint j;
  271.             printf("  varying %d: ", i);
  272.             for(j = 0; j < copy->varying[i].size / 4; j++)
  273.                printf("%x ", f[j]);
  274.             printf("\n");
  275.          }
  276.       }
  277.  
  278.       copy->vert_cache[slot].in = elt;
  279.       copy->vert_cache[slot].out = copy->dstbuf_nr++;
  280.       copy->dstptr += copy->vertex_size;
  281.  
  282.       assert(csr == copy->dstptr);
  283.       assert(copy->dstptr == (copy->dstbuf +
  284.                               copy->dstbuf_nr * copy->vertex_size));
  285.    }
  286. /*    else */
  287. /*       printf("  --> reuse vertex\n"); */
  288.    
  289. /*    printf("  --> emit %d\n", copy->vert_cache[slot].out); */
  290.    copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
  291.    return check_flush(copy);
  292. }
  293.  
  294.  
  295. /**
  296.  * Called at end of each primitive during replay.
  297.  */
  298. static void
  299. end( struct copy_context *copy, GLboolean end_flag )
  300. {
  301.    struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
  302.  
  303. /*    printf("end (%d)\n", end_flag); */
  304.  
  305.    prim->end = end_flag;
  306.    prim->count = copy->dstelt_nr - prim->start;
  307.  
  308.    if (++copy->dstprim_nr == MAX_PRIM ||
  309.        check_flush(copy))
  310.       flush(copy);
  311. }
  312.  
  313.  
  314. static void
  315. replay_elts( struct copy_context *copy )
  316. {
  317.    GLuint i, j, k;
  318.    GLboolean split;
  319.  
  320.    for (i = 0; i < copy->nr_prims; i++) {
  321.       const struct _mesa_prim *prim = &copy->prim[i];
  322.       const GLuint start = prim->start;
  323.       GLuint first, incr;
  324.  
  325.       switch (prim->mode) {
  326.          
  327.       case GL_LINE_LOOP:
  328.          /* Convert to linestrip and emit the final vertex explicitly,
  329.           * but only in the resultant strip that requires it.
  330.           */
  331.          j = 0;
  332.          while (j != prim->count) {
  333.             begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
  334.  
  335.             for (split = GL_FALSE; j != prim->count && !split; j++)
  336.                split = elt(copy, start + j);
  337.  
  338.             if (j == prim->count) {
  339.                /* Done, emit final line.  Split doesn't matter as
  340.                 * it is always raised a bit early so we can emit
  341.                 * the last verts if necessary!
  342.                 */
  343.                if (prim->end)
  344.                   (void)elt(copy, start + 0);
  345.  
  346.                end(copy, prim->end);
  347.             }
  348.             else {
  349.                /* Wrap
  350.                 */
  351.                assert(split);
  352.                end(copy, 0);
  353.                j--;
  354.             }
  355.          }
  356.          break;
  357.  
  358.       case GL_TRIANGLE_FAN:
  359.       case GL_POLYGON:
  360.          j = 2;
  361.          while (j != prim->count) {
  362.             begin(copy, prim->mode, prim->begin && j == 0);
  363.  
  364.             split = elt(copy, start+0);
  365.             assert(!split);
  366.  
  367.             split = elt(copy, start+j-1);
  368.             assert(!split);
  369.  
  370.             for (; j != prim->count && !split; j++)
  371.                split = elt(copy, start+j);
  372.  
  373.             end(copy, prim->end && j == prim->count);
  374.  
  375.             if (j != prim->count) {
  376.                /* Wrapped the primitive, need to repeat some vertices:
  377.                 */
  378.                j -= 1;
  379.             }
  380.          }
  381.          break;
  382.  
  383.       default:
  384.          (void)split_prim_inplace(prim->mode, &first, &incr);
  385.          
  386.          j = 0;
  387.          while (j != prim->count) {
  388.  
  389.             begin(copy, prim->mode, prim->begin && j == 0);
  390.  
  391.             split = 0;
  392.             for (k = 0; k < first; k++, j++)
  393.                split |= elt(copy, start+j);
  394.  
  395.             assert(!split);
  396.  
  397.             for (; j != prim->count && !split; )
  398.                for (k = 0; k < incr; k++, j++)
  399.                   split |= elt(copy, start+j);
  400.  
  401.             end(copy, prim->end && j == prim->count);
  402.  
  403.             if (j != prim->count) {
  404.                /* Wrapped the primitive, need to repeat some vertices:
  405.                 */
  406.                assert(j > first - incr);
  407.                j -= (first - incr);
  408.             }
  409.          }
  410.          break;
  411.       }
  412.    }
  413.  
  414.    if (copy->dstprim_nr)
  415.       flush(copy);
  416. }
  417.  
  418.  
  419. static void
  420. replay_init( struct copy_context *copy )
  421. {
  422.    struct gl_context *ctx = copy->ctx;
  423.    GLuint i;
  424.    GLuint offset;
  425.    const GLvoid *srcptr;
  426.  
  427.    /* Make a list of varying attributes and their vbo's.  Also
  428.     * calculate vertex size.
  429.     */
  430.    copy->vertex_size = 0;
  431.    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
  432.       struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
  433.  
  434.       if (copy->array[i]->StrideB == 0) {
  435.          copy->dstarray_ptr[i] = copy->array[i];
  436.       }
  437.       else {
  438.          GLuint j = copy->nr_varying++;
  439.          
  440.          copy->varying[j].attr = i;
  441.          copy->varying[j].array = copy->array[i];
  442.          copy->varying[j].size = attr_size(copy->array[i]);
  443.          copy->vertex_size += attr_size(copy->array[i]);
  444.      
  445.          if (_mesa_is_bufferobj(vbo) && !_mesa_bufferobj_mapped(vbo))
  446.             ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY, vbo);
  447.  
  448.          copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
  449.                                                  copy->array[i]->Ptr);
  450.  
  451.          copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
  452.       }
  453.    }
  454.  
  455.    /* There must always be an index buffer.  Currently require the
  456.     * caller convert non-indexed prims to indexed.  Could alternately
  457.     * do it internally.
  458.     */
  459.    if (_mesa_is_bufferobj(copy->ib->obj) &&
  460.        !_mesa_bufferobj_mapped(copy->ib->obj))
  461.       ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY,
  462.                             copy->ib->obj);
  463.  
  464.    srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Pointer,
  465.                                            copy->ib->ptr);
  466.  
  467.    switch (copy->ib->type) {
  468.    case GL_UNSIGNED_BYTE:
  469.       copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
  470.       copy->srcelt = copy->translated_elt_buf;
  471.  
  472.       for (i = 0; i < copy->ib->count; i++)
  473.          copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
  474.       break;
  475.  
  476.    case GL_UNSIGNED_SHORT:
  477.       copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
  478.       copy->srcelt = copy->translated_elt_buf;
  479.  
  480.       for (i = 0; i < copy->ib->count; i++)
  481.          copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
  482.       break;
  483.  
  484.    case GL_UNSIGNED_INT:
  485.       copy->translated_elt_buf = NULL;
  486.       copy->srcelt = (const GLuint *)srcptr;
  487.       break;
  488.    }
  489.  
  490.    /* Figure out the maximum allowed vertex buffer size:
  491.     */
  492.    if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
  493.       copy->dstbuf_size = copy->limits->max_verts;
  494.    }
  495.    else {
  496.       copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
  497.    }
  498.  
  499.    /* Allocate an output vertex buffer:
  500.     *
  501.     * XXX:  This should be a VBO!
  502.     */
  503.    copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);  
  504.    copy->dstptr = copy->dstbuf;
  505.  
  506.    /* Setup new vertex arrays to point into the output buffer:
  507.     */
  508.    for (offset = 0, i = 0; i < copy->nr_varying; i++) {
  509.       const struct gl_client_array *src = copy->varying[i].array;
  510.       struct gl_client_array *dst = &copy->varying[i].dstarray;
  511.  
  512.       dst->Size = src->Size;
  513.       dst->Type = src->Type;
  514.       dst->Format = GL_RGBA;
  515.       dst->Stride = copy->vertex_size;
  516.       dst->StrideB = copy->vertex_size;
  517.       dst->Ptr = copy->dstbuf + offset;
  518.       dst->Enabled = GL_TRUE;
  519.       dst->Normalized = src->Normalized;
  520.       dst->BufferObj = ctx->Shared->NullBufferObj;
  521.       dst->_MaxElement = copy->dstbuf_size; /* may be less! */
  522.  
  523.       offset += copy->varying[i].size;
  524.    }
  525.  
  526.    /* Allocate an output element list:
  527.     */
  528.    copy->dstelt_size = MIN2(65536,
  529.                             copy->ib->count * 2 + 3);
  530.    copy->dstelt_size = MIN2(copy->dstelt_size,
  531.                             copy->limits->max_indices);
  532.    copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
  533.    copy->dstelt_nr = 0;
  534.  
  535.    /* Setup the new index buffer to point to the allocated element
  536.     * list:
  537.     */
  538.    copy->dstib.count = 0;       /* duplicates dstelt_nr */
  539.    copy->dstib.type = GL_UNSIGNED_INT;
  540.    copy->dstib.obj = ctx->Shared->NullBufferObj;
  541.    copy->dstib.ptr = copy->dstelt;
  542. }
  543.  
  544.  
  545. /**
  546.  * Free up everything allocated during split/replay.
  547.  */
  548. static void
  549. replay_finish( struct copy_context *copy )
  550. {
  551.    struct gl_context *ctx = copy->ctx;
  552.    GLuint i;
  553.  
  554.    /* Free our vertex and index buffers:
  555.     */
  556.    free(copy->translated_elt_buf);
  557.    free(copy->dstbuf);
  558.    free(copy->dstelt);
  559.  
  560.    /* Unmap VBO's
  561.     */
  562.    for (i = 0; i < copy->nr_varying; i++) {
  563.       struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
  564.       if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo))
  565.          ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, vbo);
  566.    }
  567.  
  568.    /* Unmap index buffer:
  569.     */
  570.    if (_mesa_is_bufferobj(copy->ib->obj) &&
  571.        _mesa_bufferobj_mapped(copy->ib->obj)) {
  572.       ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, copy->ib->obj);
  573.    }
  574. }
  575.  
  576.  
  577. /**
  578.  * Split VBO into smaller pieces, draw the pieces.
  579.  */
  580. void vbo_split_copy( struct gl_context *ctx,
  581.                      const struct gl_client_array *arrays[],
  582.                      const struct _mesa_prim *prim,
  583.                      GLuint nr_prims,
  584.                      const struct _mesa_index_buffer *ib,
  585.                      vbo_draw_func draw,
  586.                      const struct split_limits *limits )
  587. {
  588.    struct copy_context copy;
  589.    GLuint i, this_nr_prims;
  590.  
  591.    for (i = 0; i < nr_prims;) {
  592.       /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
  593.        * will rebase the elements to the basevertex, and we'll only
  594.        * emit strings of prims with the same basevertex in one draw call.
  595.        */
  596.       for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
  597.            this_nr_prims++) {
  598.          if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
  599.             break;
  600.       }
  601.  
  602.       memset(&copy, 0, sizeof(copy));
  603.  
  604.       /* Require indexed primitives:
  605.        */
  606.       assert(ib);
  607.  
  608.       copy.ctx = ctx;
  609.       copy.array = arrays;
  610.       copy.prim = &prim[i];
  611.       copy.nr_prims = this_nr_prims;
  612.       copy.ib = ib;
  613.       copy.draw = draw;
  614.       copy.limits = limits;
  615.  
  616.       /* Clear the vertex cache:
  617.        */
  618.       for (i = 0; i < ELT_TABLE_SIZE; i++)
  619.          copy.vert_cache[i].in = ~0;
  620.  
  621.       replay_init(&copy);
  622.       replay_elts(&copy);
  623.       replay_finish(&copy);
  624.    }
  625. }
  626.