home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mesa5.zip / mesa5src.zip / tnl / t_array_api.cpp < prev    next >
C/C++ Source or Header  |  2002-10-24  |  12KB  |  403 lines

  1. /* $Id: t_array_api.c,v 1.28 2002/10/24 23:57:25 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  4.1
  6.  *
  7.  * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  8.  *
  9.  * Permission is hereby granted, free of charge, to any person obtaining a
  10.  * copy of this software and associated documentation files (the "Software"),
  11.  * to deal in the Software without restriction, including without limitation
  12.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13.  * and/or sell copies of the Software, and to permit persons to whom the
  14.  * Software is furnished to do so, subject to the following conditions:
  15.  *
  16.  * The above copyright notice and this permission notice shall be included
  17.  * in all copies or substantial portions of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  22.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  23.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  24.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  */
  26.  
  27. /**
  28.  * \file vpexec.c
  29.  * \brief Vertex array API functions (glDrawArrays, etc)
  30.  * \author Keith Whitwell
  31.  */
  32.  
  33. #include "glheader.h"
  34. #include "api_validate.h"
  35. #include "context.h"
  36. #include "imports.h"
  37. #include "macros.h"
  38. #include "mmath.h"
  39. #include "mtypes.h"
  40. #include "state.h"
  41.  
  42. #include "array_cache/acache.h"
  43.  
  44. #include "t_array_api.h"
  45. #include "t_array_import.h"
  46. #include "t_imm_api.h"
  47. #include "t_imm_exec.h"
  48. #include "t_context.h"
  49. #include "t_pipeline.h"
  50.  
  51. static void fallback_drawarrays( GLcontext *ctx, GLenum mode, GLint start,
  52.                  GLsizei count )
  53. {
  54.    if (_tnl_hard_begin( ctx, mode )) {
  55.       GLint i;
  56.       for (i = start; i < count; i++) 
  57.      glArrayElement( i );
  58.       glEnd();
  59.    }
  60. }
  61.  
  62.  
  63. static void fallback_drawelements( GLcontext *ctx, GLenum mode, GLsizei count,
  64.                    const GLuint *indices)
  65. {
  66.    if (_tnl_hard_begin(ctx, mode)) {
  67.       GLint i;
  68.       for (i = 0 ; i < count ; i++)
  69.      glArrayElement( indices[i] );
  70.       glEnd();
  71.    }
  72. }
  73.  
  74.  
  75. static void _tnl_draw_range_elements( GLcontext *ctx, GLenum mode,
  76.                       GLuint start, GLuint end,
  77.                       GLsizei count, const GLuint *indices )
  78.  
  79. {
  80.    TNLcontext *tnl = TNL_CONTEXT(ctx);
  81.    FLUSH_CURRENT( ctx, 0 );
  82.    
  83.    /*  _mesa_debug(ctx, "%s\n", __FUNCTION__); */
  84.    if (tnl->pipeline.build_state_changes)
  85.       _tnl_validate_pipeline( ctx );
  86.  
  87.    _tnl_vb_bind_arrays( ctx, start, end );
  88.  
  89.    tnl->vb.FirstPrimitive = 0;
  90.    tnl->vb.Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
  91.    tnl->vb.PrimitiveLength[0] = count;
  92.    tnl->vb.Elts = (GLuint *)indices;
  93.  
  94.    if (ctx->Array.LockCount)
  95.       tnl->Driver.RunPipeline( ctx );
  96.    else {
  97.       /* Note that arrays may have changed before/after execution.
  98.        */
  99.       tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
  100.       tnl->Driver.RunPipeline( ctx );
  101.       tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
  102.    }
  103. }
  104.  
  105.  
  106.  
  107. /**
  108.  * Called via the GL API dispatcher.
  109.  */
  110. void
  111. _tnl_DrawArrays(GLenum mode, GLint start, GLsizei count)
  112. {
  113.    GET_CURRENT_CONTEXT(ctx);
  114.    TNLcontext *tnl = TNL_CONTEXT(ctx);
  115.    struct vertex_buffer *VB = &tnl->vb;
  116.    GLuint thresh = (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) ? 30 : 10;
  117.    
  118.    if (MESA_VERBOSE & VERBOSE_API)
  119.       _mesa_debug(NULL, "_tnl_DrawArrays %d %d\n", start, count); 
  120.    
  121.    /* Check arguments, etc.
  122.     */
  123.    if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
  124.       return;
  125.  
  126.    if (tnl->pipeline.build_state_changes)
  127.       _tnl_validate_pipeline( ctx );
  128.  
  129.    if (ctx->CompileFlag) {
  130.       fallback_drawarrays( ctx, mode, start, start + count );
  131.    }    
  132.    else if (!ctx->Array.LockCount && (GLuint) count < thresh) {
  133.       /* Small primitives: attempt to share a vb (at the expense of
  134.        * using the immediate interface).
  135.       */
  136.       fallback_drawarrays( ctx, mode, start, start + count );
  137.    } 
  138.    else if (ctx->Array.LockCount && 
  139.         count < (GLint) ctx->Const.MaxArrayLockSize) {
  140.       
  141.       /* Locked primitives which can fit in a single vertex buffer:
  142.        */
  143.       FLUSH_CURRENT( ctx, 0 );
  144.  
  145.       if (start < (GLint) ctx->Array.LockFirst)
  146.      start = ctx->Array.LockFirst;
  147.       if (start + count > (GLint) ctx->Array.LockCount)
  148.      count = ctx->Array.LockCount - start;
  149.       
  150.       /* Locked drawarrays.  Reuse any previously transformed data.
  151.        */
  152.       _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
  153.       VB->FirstPrimitive = start;
  154.       VB->Primitive[start] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
  155.       VB->PrimitiveLength[start] = count;
  156.       tnl->Driver.RunPipeline( ctx );
  157.    } 
  158.    else {
  159.       int bufsz = 256;        /* Use a small buffer for cache goodness */
  160.       int j, nr;
  161.       int minimum, modulo, skip;
  162.  
  163.       /* Large primitives requiring decomposition to multiple vertex
  164.        * buffers:
  165.        */
  166.       switch (mode) {
  167.       case GL_POINTS:
  168.      minimum = 0;
  169.      modulo = 1;
  170.      skip = 0;
  171.       case GL_LINES:
  172.      minimum = 1;
  173.      modulo = 2;
  174.      skip = 1;
  175.       case GL_LINE_STRIP:
  176.      minimum = 1;
  177.      modulo = 1;
  178.      skip = 0;
  179.      break;
  180.       case GL_TRIANGLES:
  181.      minimum = 2;
  182.      modulo = 3;
  183.      skip = 2;
  184.      break;
  185.       case GL_TRIANGLE_STRIP:
  186.      minimum = 2;
  187.      modulo = 1;
  188.      skip = 0;
  189.      break;
  190.       case GL_QUADS:
  191.      minimum = 3;
  192.      modulo = 4;
  193.      skip = 3;
  194.      break;
  195.       case GL_QUAD_STRIP:
  196.      minimum = 3;
  197.      modulo = 2;
  198.      skip = 0;
  199.      break;
  200.       case GL_LINE_LOOP:
  201.       case GL_TRIANGLE_FAN:
  202.       case GL_POLYGON:
  203.       default:
  204.      /* Primitives requiring a copied vertex (fan-like primitives)
  205.       * must use the slow path if they cannot fit in a single
  206.       * vertex buffer.  
  207.       */
  208.      if (count < (GLint) ctx->Const.MaxArrayLockSize) {
  209.         bufsz = ctx->Const.MaxArrayLockSize;
  210.         minimum = 0;
  211.         modulo = 1;
  212.         skip = 0;
  213.      }
  214.      else {
  215.         fallback_drawarrays( ctx, mode, start, start + count );
  216.         return;
  217.      }
  218.       }
  219.  
  220.       FLUSH_CURRENT( ctx, 0 );
  221.  
  222.       bufsz -= bufsz % modulo;
  223.       bufsz -= minimum;
  224.       count += start;
  225.  
  226.       for (j = start + minimum ; j < count ; j += nr + skip ) {
  227.  
  228.      nr = MIN2( bufsz, count - j );
  229.  
  230.      _tnl_vb_bind_arrays( ctx, j - minimum, j + nr );
  231.  
  232.      VB->FirstPrimitive = 0;
  233.      VB->Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
  234.      VB->PrimitiveLength[0] = nr + minimum;
  235.      tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
  236.      tnl->Driver.RunPipeline( ctx );
  237.      tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
  238.       }
  239.    }
  240. }
  241.  
  242.  
  243. /**
  244.  * Called via the GL API dispatcher.
  245.  */
  246. void
  247. _tnl_DrawRangeElements(GLenum mode,
  248.                GLuint start, GLuint end,
  249.                GLsizei count, GLenum type, const GLvoid *indices)
  250. {
  251.    GET_CURRENT_CONTEXT(ctx);
  252.    GLuint *ui_indices;
  253.  
  254.    if (MESA_VERBOSE & VERBOSE_API)
  255.       _mesa_debug(NULL, "_tnl_DrawRangeElements %d %d %d\n", start, end, count); 
  256.  
  257.    /* Check arguments, etc.
  258.     */
  259.    if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
  260.                                           type, indices ))
  261.       return;
  262.  
  263.    ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
  264.                            count, type, indices );
  265.  
  266.  
  267.    if (ctx->CompileFlag) {
  268.       /* Can't do anything when compiling:
  269.        */
  270.       fallback_drawelements( ctx, mode, count, ui_indices );
  271.    }
  272.    else if (ctx->Array.LockCount) {
  273.       /* Are the arrays already locked?  If so we currently have to look
  274.        * at the whole locked range.
  275.        */
  276.       if (start >= ctx->Array.LockFirst && end <= ctx->Array.LockCount)
  277.      _tnl_draw_range_elements( ctx, mode,
  278.                    ctx->Array.LockFirst,
  279.                    ctx->Array.LockCount,
  280.                    count, ui_indices );
  281.       else {
  282.      /* The spec says referencing elements outside the locked
  283.       * range is undefined.  I'm going to make it a noop this time
  284.       * round, maybe come up with something beter before 3.6.
  285.       *
  286.       * May be able to get away with just setting LockCount==0,
  287.       * though this raises the problems of dependent state.  May
  288.       * have to call glUnlockArrays() directly?
  289.       *
  290.       * Or scan the list and replace bad indices?
  291.       */
  292.      _mesa_problem( ctx,
  293.              "DrawRangeElements references "
  294.              "elements outside locked range.");
  295.       }
  296.    }
  297.    else if (end + 1 - start < ctx->Const.MaxArrayLockSize) {
  298.       /* The arrays aren't locked but we can still fit them inside a
  299.        * single vertexbuffer.
  300.        */
  301.       _tnl_draw_range_elements( ctx, mode, start, end + 1, count, ui_indices );
  302.    } else {
  303.       /* Range is too big to optimize:
  304.        */
  305.       fallback_drawelements( ctx, mode, count, ui_indices );
  306.    }
  307. }
  308.  
  309.  
  310.  
  311. /**
  312.  * Called via the GL API dispatcher.
  313.  */
  314. void
  315. _tnl_DrawElements(GLenum mode, GLsizei count, GLenum type,
  316.           const GLvoid *indices)
  317. {
  318.    GET_CURRENT_CONTEXT(ctx);
  319.    GLuint *ui_indices;
  320.  
  321.    if (MESA_VERBOSE & VERBOSE_API)
  322.       _mesa_debug(NULL, "_tnl_DrawElements %d\n", count); 
  323.  
  324.    /* Check arguments, etc.
  325.     */
  326.    if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
  327.       return;
  328.  
  329.    ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
  330.                            count, type, indices );
  331.  
  332.    if (ctx->CompileFlag) {
  333.       /* Can't do anything when compiling:
  334.        */
  335.       fallback_drawelements( ctx, mode, count, ui_indices );
  336.    }
  337.    else if (ctx->Array.LockCount) {
  338.       _tnl_draw_range_elements( ctx, mode,
  339.                 ctx->Array.LockFirst,
  340.                 ctx->Array.LockCount,
  341.                 count, ui_indices );
  342.    }
  343.    else {
  344.       /* Scan the index list and see if we can use the locked path anyway.
  345.        */
  346.       GLuint max_elt = 0;
  347.       GLint i;
  348.  
  349.       for (i = 0 ; i < count ; i++)
  350.      if (ui_indices[i] > max_elt)
  351.             max_elt = ui_indices[i];
  352.  
  353.       if (max_elt < ctx->Const.MaxArrayLockSize && /* can we use it? */
  354.       max_elt < (GLuint) count)                /* do we want to use it? */
  355.      _tnl_draw_range_elements( ctx, mode, 0, max_elt+1, count, ui_indices );
  356.       else
  357.      fallback_drawelements( ctx, mode, count, ui_indices );
  358.    }
  359. }
  360.  
  361.  
  362. /**
  363.  * Initialize context's vertex array fields.  Called during T 'n L context
  364.  * creation.
  365.  */
  366. void _tnl_array_init( GLcontext *ctx )
  367. {
  368.    TNLcontext *tnl = TNL_CONTEXT(ctx);
  369.    struct vertex_arrays *tmp = &tnl->array_inputs;
  370.    GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->vtxfmt);
  371.    GLuint i;
  372.  
  373.    vfmt->DrawArrays = _tnl_DrawArrays;
  374.    vfmt->DrawElements = _tnl_DrawElements;
  375.    vfmt->DrawRangeElements = _tnl_DrawRangeElements;
  376.  
  377.    /* Setup vector pointers that will be used to bind arrays to VB's.
  378.     */
  379.    _mesa_vector4f_init( &tmp->Obj, 0, 0 );
  380.    _mesa_vector4f_init( &tmp->Normal, 0, 0 );   
  381.    _mesa_vector4f_init( &tmp->FogCoord, 0, 0 );
  382.    _mesa_vector1ui_init( &tmp->Index, 0, 0 );
  383.    _mesa_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
  384.  
  385.    for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
  386.       _mesa_vector4f_init( &tmp->TexCoord[i], 0, 0);
  387.  
  388.    tnl->tmp_primitive = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
  389.    tnl->tmp_primitive_length = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
  390. }
  391.  
  392.  
  393. /**
  394.  * Destroy the context's vertex array stuff.
  395.  * Called during T 'n L context destruction.
  396.  */
  397. void _tnl_array_destroy( GLcontext *ctx )
  398. {
  399.    TNLcontext *tnl = TNL_CONTEXT(ctx);
  400.    if (tnl->tmp_primitive_length) FREE(tnl->tmp_primitive_length);
  401.    if (tnl->tmp_primitive) FREE(tnl->tmp_primitive);
  402. }
  403.