Subversion Repositories Kolibri OS

Rev

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 <keithw@vmware.com>
  27.  */
  28.  
  29. /* Helper for drivers which find themselves rendering a range of
  30.  * indices starting somewhere above zero.  Typically the application
  31.  * is issuing multiple DrawArrays() or DrawElements() to draw
  32.  * successive primitives layed out linearly in the vertex arrays.
  33.  * Unless the vertex arrays are all in a VBO, the OpenGL semantics
  34.  * imply that we need to re-upload the vertex data on each draw call.
  35.  * In that case, we want to avoid starting the upload at zero, as it
  36.  * will mean every draw call uploads an increasing amount of not-used
  37.  * vertex data.  Worse - in the software tnl module, all those
  38.  * vertices will be transformed and lit.
  39.  *
  40.  * If we just upload the new data, however, the indices will be
  41.  * incorrect as we tend to upload each set of vertex data to a new
  42.  * region.  
  43.  *
  44.  * This file provides a helper to adjust the arrays, primitives and
  45.  * indices of a draw call so that it can be re-issued with a min_index
  46.  * of zero.
  47.  */
  48.  
  49. #include <stdio.h>
  50. #include "main/glheader.h"
  51. #include "main/imports.h"
  52. #include "main/mtypes.h"
  53.  
  54. #include "vbo.h"
  55.  
  56.  
  57. #define REBASE(TYPE)                                            \
  58. static void *rebase_##TYPE( const void *ptr,                    \
  59.                           GLuint count,                         \
  60.                           TYPE min_index )                      \
  61. {                                                               \
  62.    GLuint i;                                                    \
  63.    const TYPE *in = (TYPE *)ptr;                                \
  64.    TYPE *tmp_indices = malloc(count * sizeof(TYPE));            \
  65.                                                                 \
  66.    if (tmp_indices == NULL) {                                   \
  67.       _mesa_error_no_memory(__func__);                          \
  68.       return NULL;                                              \
  69.    }                                                            \
  70.                                                                 \
  71.    for (i = 0; i < count; i++)                                  \
  72.       tmp_indices[i] = in[i] - min_index;                       \
  73.                                                                 \
  74.    return (void *)tmp_indices;                                  \
  75. }
  76.  
  77.  
  78. REBASE(GLuint)
  79. REBASE(GLushort)
  80. REBASE(GLubyte)
  81.  
  82. GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] )
  83. {
  84.    GLuint i;
  85.    
  86.    for (i = 0; i < VERT_ATTRIB_MAX; i++)
  87.       if (arrays[i]->StrideB &&
  88.           arrays[i]->BufferObj->Name == 0)
  89.          return GL_FALSE;
  90.  
  91.    return GL_TRUE;
  92. }
  93.  
  94. GLboolean vbo_any_varyings_in_vbos( const struct gl_client_array *arrays[] )
  95. {
  96.    GLuint i;
  97.  
  98.    for (i = 0; i < VERT_ATTRIB_MAX; i++)
  99.       if (arrays[i]->BufferObj->Name != 0)
  100.          return GL_TRUE;
  101.  
  102.    return GL_FALSE;
  103. }
  104.  
  105. /* Adjust primitives, indices and vertex definitions so that min_index
  106.  * becomes zero. There are lots of reasons for wanting to do this, eg:
  107.  *
  108.  * Software tnl:
  109.  *    - any time min_index != 0, otherwise unused vertices lower than
  110.  *      min_index will be transformed.
  111.  *
  112.  * Hardware tnl:
  113.  *    - if ib != NULL and min_index != 0, otherwise vertices lower than
  114.  *      min_index will be uploaded.  Requires adjusting index values.
  115.  *
  116.  *    - if ib == NULL and min_index != 0, just for convenience so this doesn't
  117.  *      have to be handled within the driver.
  118.  *
  119.  * Hardware tnl with VBO support:
  120.  *    - as above, but only when vertices are not (all?) in VBO's.
  121.  *    - can't save time by trying to upload half a vbo - typically it is
  122.  *      all or nothing.
  123.  */
  124. void vbo_rebase_prims( struct gl_context *ctx,
  125.                        const struct gl_client_array *arrays[],
  126.                        const struct _mesa_prim *prim,
  127.                        GLuint nr_prims,
  128.                        const struct _mesa_index_buffer *ib,
  129.                        GLuint min_index,
  130.                        GLuint max_index,
  131.                        vbo_draw_func draw )
  132. {
  133.    struct gl_client_array tmp_arrays[VERT_ATTRIB_MAX];
  134.    const struct gl_client_array *tmp_array_pointers[VERT_ATTRIB_MAX];
  135.  
  136.    struct _mesa_index_buffer tmp_ib;
  137.    struct _mesa_prim *tmp_prims = NULL;
  138.    const struct gl_client_array **saved_arrays = ctx->Array._DrawArrays;
  139.    void *tmp_indices = NULL;
  140.    GLuint i;
  141.  
  142.    assert(min_index != 0);
  143.  
  144.    if (0)
  145.       printf("%s %d..%d\n", __func__, min_index, max_index);
  146.  
  147.  
  148.    /* XXX this path is disabled for now.
  149.     * There's rendering corruption in some apps when it's enabled.
  150.     */
  151.    if (0 && ib && ctx->Extensions.ARB_draw_elements_base_vertex) {
  152.       /* If we can just tell the hardware or the TNL to interpret our
  153.        * indices with a different base, do so.
  154.        */
  155.       tmp_prims = malloc(sizeof(*prim) * nr_prims);
  156.  
  157.       if (tmp_prims == NULL) {
  158.          _mesa_error_no_memory(__func__);
  159.          return;
  160.       }
  161.  
  162.       for (i = 0; i < nr_prims; i++) {
  163.          tmp_prims[i] = prim[i];
  164.          tmp_prims[i].basevertex -= min_index;
  165.       }
  166.  
  167.       prim = tmp_prims;
  168.    } else if (ib) {
  169.       /* Unfortunately need to adjust each index individually.
  170.        */
  171.       GLboolean map_ib = ib->obj->Name &&
  172.                          !ib->obj->Mappings[MAP_INTERNAL].Pointer;
  173.       void *ptr;
  174.  
  175.       if (map_ib)
  176.          ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT,
  177.                                     ib->obj, MAP_INTERNAL);
  178.  
  179.  
  180.       ptr = ADD_POINTERS(ib->obj->Mappings[MAP_INTERNAL].Pointer, ib->ptr);
  181.  
  182.       /* Some users might prefer it if we translated elements to
  183.        * GLuints here.  Others wouldn't...
  184.        */
  185.       switch (ib->type) {
  186.       case GL_UNSIGNED_INT:
  187.          tmp_indices = rebase_GLuint( ptr, ib->count, min_index );
  188.          break;
  189.       case GL_UNSIGNED_SHORT:
  190.          tmp_indices = rebase_GLushort( ptr, ib->count, min_index );
  191.          break;
  192.       case GL_UNSIGNED_BYTE:
  193.          tmp_indices = rebase_GLubyte( ptr, ib->count, min_index );
  194.          break;
  195.       }      
  196.  
  197.       if (map_ib)
  198.          ctx->Driver.UnmapBuffer(ctx, ib->obj, MAP_INTERNAL);
  199.  
  200.       if (tmp_indices == NULL) {
  201.          return;
  202.       }
  203.  
  204.       tmp_ib.obj = ctx->Shared->NullBufferObj;
  205.       tmp_ib.ptr = tmp_indices;
  206.       tmp_ib.count = ib->count;
  207.       tmp_ib.type = ib->type;
  208.  
  209.       ib = &tmp_ib;
  210.    }
  211.    else {
  212.       /* Otherwise the primitives need adjustment.
  213.        */
  214.       tmp_prims = malloc(sizeof(*prim) * nr_prims);
  215.  
  216.       if (tmp_prims == NULL) {
  217.          _mesa_error_no_memory(__func__);
  218.          return;
  219.       }
  220.  
  221.       for (i = 0; i < nr_prims; i++) {
  222.          /* If this fails, it could indicate an application error:
  223.           */
  224.          assert(prim[i].start >= min_index);
  225.  
  226.          tmp_prims[i] = prim[i];
  227.          tmp_prims[i].start -= min_index;
  228.       }
  229.  
  230.       prim = tmp_prims;
  231.    }
  232.  
  233.    /* Just need to adjust the pointer values on each incoming array.
  234.     * This works for VBO and non-vbo rendering and shouldn't pesimize
  235.     * VBO-based upload schemes.  However this may still not be a fast
  236.     * path for hardware tnl for VBO based rendering as most machines
  237.     * will be happier if you just specify a starting vertex value in
  238.     * each primitive.
  239.     *
  240.     * For drivers with hardware tnl, you only want to do this if you
  241.     * are forced to, eg non-VBO indexed rendering with start != 0.
  242.     */
  243.    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
  244.       tmp_arrays[i] = *arrays[i];
  245.       tmp_arrays[i].Ptr += min_index * tmp_arrays[i].StrideB;
  246.       tmp_array_pointers[i] = &tmp_arrays[i];
  247.    }
  248.    
  249.    /* Re-issue the draw call.
  250.     */
  251.    ctx->Array._DrawArrays = tmp_array_pointers;
  252.    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
  253.  
  254.    draw( ctx,
  255.          prim,
  256.          nr_prims,
  257.          ib,
  258.          GL_TRUE,
  259.          0,
  260.          max_index - min_index,
  261.          NULL, NULL );
  262.  
  263.    ctx->Array._DrawArrays = saved_arrays;
  264.    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
  265.    
  266.    free(tmp_indices);
  267.    
  268.    free(tmp_prims);
  269. }
  270.  
  271.  
  272.  
  273.