Browse Source

micro-optimize inner vertex loop

cxgeorge 24 years ago
parent
commit
4c90448b95
2 changed files with 139 additions and 86 deletions
  1. 127 75
      panda/src/dxgsg/dxGraphicsStateGuardian.cxx
  2. 12 11
      panda/src/dxgsg/dxGraphicsStateGuardian.h

+ 127 - 75
panda/src/dxgsg/dxGraphicsStateGuardian.cxx

@@ -99,10 +99,14 @@ const int VERT_BUFFER_SIZE = (32*6*1024L);
 TypeHandle DXGraphicsStateGuardian::_type_handle;
 TypeHandle DXGraphicsStateGuardian::_type_handle;
 
 
 // bit masks used for drawing primitives
 // bit masks used for drawing primitives
-#define PER_TEXCOORD 0x8
-#define PER_COLOR    0x4
-#define PER_NORMAL   0x2
-#define PER_COORD    0x1
+// bitmask type: normal=0x1,color=0x2,texcoord=0x4
+typedef enum { NothingSet=0,NormalOnly,ColorOnly,Normal_Color,TexCoordOnly,
+               Normal_TexCoord,Color_TexCoord,Normal_Color_TexCoord
+} DrawLoopFlags;
+
+#define PER_NORMAL   NormalOnly
+#define PER_COLOR    ColorOnly
+#define PER_TEXCOORD TexCoordOnly
 
 
 // technically DX7's front-end has no limit on the number of lights, but it's simpler for
 // technically DX7's front-end has no limit on the number of lights, but it's simpler for
 // this implementation to set a small GL-like limit to make the light array traversals short
 // this implementation to set a small GL-like limit to make the light array traversals short
@@ -1809,6 +1813,16 @@ draw_prim_setup(const Geom *geom) {
     }}
     }}
 
 
 ////////
 ////////
+    
+   // this stuff should eventually replace the iterators below
+   geom->get_coords(_coords,_vindexes);
+   if(_vindexes!=NULL) {
+      _pCurCoordIndex = &_vindexes[0];
+   } else {
+      _pCurCoord = &_coords[0];
+   }
+
+   ///////////////
 
 
    vi = geom->make_vertex_iterator();
    vi = geom->make_vertex_iterator();
    _curFVFflags = D3DFVF_XYZ;
    _curFVFflags = D3DFVF_XYZ;
@@ -1846,10 +1860,21 @@ draw_prim_setup(const Geom *geom) {
             p_normal = geom->get_next_normal(ni);    // set overall normal if there is one
             p_normal = geom->get_next_normal(ni);    // set overall normal if there is one
    }
    }
 
 
-   if (geom->get_binding(G_TEXCOORD) != G_OFF) {
-        ti = geom->make_texcoord_iterator();
-        _curFVFflags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
-        vertex_size += sizeof(float) * 2;
+
+   GeomBindType TexCoordBinding;
+   geom->get_texcoords(_texcoords,TexCoordBinding,_texcoord_indexes);
+   if (TexCoordBinding != G_OFF) {
+
+       // used by faster path
+       if(_texcoord_indexes!=NULL) {
+           _pCurTexCoordIndex = &_texcoord_indexes[0];
+       } else {
+           _pCurTexCoord = &_texcoords[0];
+       }
+
+       ti = geom->make_texcoord_iterator();
+       _curFVFflags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
+       vertex_size += sizeof(float) * 2;
    }
    }
 
 
     // If we have per-vertex colors or normals, we need smooth shading.
     // If we have per-vertex colors or normals, we need smooth shading.
@@ -1903,36 +1928,34 @@ wants_colors() const {
 //               for component normals and color
 //               for component normals and color
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
 void DXGraphicsStateGuardian::
-draw_prim_inner_loop(int nVerts, const Geom *geom, DWORD perFlags) {
-
+draw_prim_inner_loop(int nVerts, const Geom *geom, ushort perFlags) {
     Vertexf NextVert;
     Vertexf NextVert;
-    perFlags &= ~PER_COORD;  // should always be set anyway
 
 
     for(;nVerts > 0;nVerts--) {
     for(;nVerts > 0;nVerts--) {
-
          // coord info will always be _perVertex
          // coord info will always be _perVertex
         GET_NEXT_VERTEX(NextVert);     // need to optimize these 
         GET_NEXT_VERTEX(NextVert);     // need to optimize these 
         add_to_FVFBuf((void *)&NextVert, sizeof(D3DVECTOR));
         add_to_FVFBuf((void *)&NextVert, sizeof(D3DVECTOR));
 
 
-        if(perFlags==0xC) {
-            // break out the common case first
+        if(perFlags==(ushort)TexCoordOnly) {
+            // break out the common case (for animated chars) 1st
             GET_NEXT_TEXCOORD();
             GET_NEXT_TEXCOORD();
-            GET_NEXT_COLOR();
         } else {
         } else {
-            switch (perFlags) {
-                case 0x4:
+            switch (DrawLoopFlags(perFlags)) {
+                case Color_TexCoord:
+                    GET_NEXT_TEXCOORD();
+                case ColorOnly:
                     GET_NEXT_COLOR();
                     GET_NEXT_COLOR();
                     break;
                     break;
-                case 0x6:
+                case Normal_Color:
                     GET_NEXT_COLOR();
                     GET_NEXT_COLOR();
-                case 0x2:
+                case NormalOnly:
                     GET_NEXT_NORMAL();
                     GET_NEXT_NORMAL();
                     break;
                     break;
-                case 0xE:
+                case Normal_Color_TexCoord:
                     GET_NEXT_COLOR();
                     GET_NEXT_COLOR();
-                case 0xA:
+                case Normal_TexCoord:
                     GET_NEXT_NORMAL();
                     GET_NEXT_NORMAL();
-                case 0x8:
+                // case TexCoordOnly:
                     GET_NEXT_TEXCOORD();
                     GET_NEXT_TEXCOORD();
                     break;
                     break;
             }
             }
@@ -1947,6 +1970,54 @@ draw_prim_inner_loop(int nVerts, const Geom *geom, DWORD perFlags) {
     }
     }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian::draw_prim_inner_loop_coordtexonly
+//       Access: Private
+//  Description: FastPath loop used by animated character data
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian::
+draw_prim_inner_loop_coordtexonly(int nVerts, const Geom *geom) {
+    // inc'ing local ptrs avoids 'this' ptr derefs for member fields
+    Vertexf *pCurVert = _pCurCoord;
+    ushort *pCurVertIndex = _pCurCoordIndex;
+    TexCoordf *pCurTexCoord = _pCurTexCoord;
+    ushort *pCurTexCoordIndex = _pCurTexCoordIndex;
+    char *LocalFvfBufPtr=_pCurFvfBufPtr;
+    DWORD cur_color = _curD3Dcolor;
+    bool bDoIndexedTexCoords = (_texcoord_indexes != NULL);
+    bool bDoIndexedCoords = (_vindexes != NULL);
+
+    for(;nVerts > 0;nVerts--) {
+        if(bDoIndexedCoords) {
+           memcpy(LocalFvfBufPtr,(void*)&_coords[*pCurVertIndex],sizeof(D3DVECTOR));
+           pCurVertIndex++;           
+        } else {
+           memcpy(LocalFvfBufPtr,(void*)pCurVert,sizeof(D3DVECTOR));
+           pCurVert++;
+        }
+
+        LocalFvfBufPtr+=sizeof(D3DVECTOR);
+
+        *((DWORD *)LocalFvfBufPtr) = cur_color;
+        LocalFvfBufPtr += sizeof(DWORD);
+
+        if(bDoIndexedTexCoords) {
+           memcpy(LocalFvfBufPtr,(void*)&_texcoords[*pCurTexCoordIndex],sizeof(TexCoordf));
+           pCurTexCoordIndex++;
+        } else {
+           memcpy(LocalFvfBufPtr,(void*)pCurTexCoord,sizeof(TexCoordf));
+           pCurTexCoord++;
+        }
+        LocalFvfBufPtr+=sizeof(TexCoordf);
+    }
+
+    _pCurFvfBufPtr=LocalFvfBufPtr;
+    _pCurCoord = pCurVert;
+    _pCurCoordIndex = pCurVertIndex;
+    _pCurTexCoord = pCurTexCoord;
+    _pCurTexCoordIndex = pCurTexCoordIndex;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian::draw_point
 //     Function: DXGraphicsStateGuardian::draw_point
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -2016,9 +2087,8 @@ draw_point(GeomPoint *geom, GeomContext *gc) {
     // values (may only be possible to handle certain cases without reverting to old pipeline)
     // values (may only be possible to handle certain cases without reverting to old pipeline)
     if (GeomVrtFmt!=FlatVerts) {
     if (GeomVrtFmt!=FlatVerts) {
 
 
-        _perVertex = PER_COORD;
+        _perVertex = 0x0; 
         _perPrim = 0;
         _perPrim = 0;
-        if (geom->get_binding(G_COORD) == G_PER_VERTEX)  _perVertex |= PER_COORD;
         if (geom->get_binding(G_NORMAL) == G_PER_VERTEX) _perVertex |= PER_NORMAL;
         if (geom->get_binding(G_NORMAL) == G_PER_VERTEX) _perVertex |= PER_NORMAL;
         if (geom->get_binding(G_COLOR) == G_PER_VERTEX) _perVertex |= PER_COLOR;
         if (geom->get_binding(G_COLOR) == G_PER_VERTEX) _perVertex |= PER_COLOR;
 
 
@@ -2123,9 +2193,9 @@ draw_line(GeomLine* geom, GeomContext *gc) {
     }
     }
 
 
     assert(geom->get_binding(G_COORD) == G_PER_VERTEX);
     assert(geom->get_binding(G_COORD) == G_PER_VERTEX);
-    _perVertex = PER_COORD;
+    _perVertex = 0x0;
+    _perPrim = _perComp = 0x0;
 
 
-    _perPrim = _perComp = 0;
     switch(geom->get_binding(G_NORMAL)) {
     switch(geom->get_binding(G_NORMAL)) {
         case G_PER_VERTEX:
         case G_PER_VERTEX:
             _perVertex |=  PER_NORMAL;
             _perVertex |=  PER_NORMAL;
@@ -2226,7 +2296,7 @@ draw_linestrip_base(Geom* geom, GeomContext *gc, bool bConnectEnds) {
     }
     }
 
 
     assert(geom->get_binding(G_COORD) == G_PER_VERTEX);
     assert(geom->get_binding(G_COORD) == G_PER_VERTEX);
-    _perVertex = PER_COORD;
+    _perVertex = 0x0;
 
 
     _perPrim = _perComp = 0;
     _perPrim = _perComp = 0;
     switch(geom->get_binding(G_NORMAL)) {
     switch(geom->get_binding(G_NORMAL)) {
@@ -2252,6 +2322,7 @@ draw_linestrip_base(Geom* geom, GeomContext *gc, bool bConnectEnds) {
     }
     }
 
 
     size_t vertex_size = draw_prim_setup(geom);
     size_t vertex_size = draw_prim_setup(geom);
+    ushort perFlags = _perVertex | _perComp;
 
 
     for (int i = 0; i < nPrims; i++) {
     for (int i = 0; i < nPrims; i++) {
         if (_perPrim & PER_COLOR) {
         if (_perPrim & PER_COLOR) {
@@ -2260,19 +2331,17 @@ draw_linestrip_base(Geom* geom, GeomContext *gc, bool bConnectEnds) {
 
 
         int nVerts;
         int nVerts;
 
 
-        if(plen==NULL) {
-            nVerts=4;  // we've been called by draw_quad, which has no lengths array
-        } else {
+        if(plen!=NULL) {
             nVerts= *(plen++);
             nVerts= *(plen++);
             nassertv(nVerts >= 2);
             nassertv(nVerts >= 2);
+        } else {
+            nVerts=4;  // we've been called by draw_quad, which has no lengths array
         }
         }
 
 
         nassertv(_pCurFvfBufPtr == NULL);   // make sure the storage pointer is clean.
         nassertv(_pCurFvfBufPtr == NULL);   // make sure the storage pointer is clean.
         nassertv(nVerts * vertex_size < VERT_BUFFER_SIZE);
         nassertv(nVerts * vertex_size < VERT_BUFFER_SIZE);
         _pCurFvfBufPtr = _pFvfBufBasePtr;   // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
         _pCurFvfBufPtr = _pFvfBufBasePtr;   // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
 
 
-        DWORD perFlags = _perVertex | _perComp;
-
         draw_prim_inner_loop(nVerts, geom, perFlags);
         draw_prim_inner_loop(nVerts, geom, perFlags);
 
 
         if(bConnectEnds) {
         if(bConnectEnds) {
@@ -2830,15 +2899,21 @@ draw_tri(GeomTri *geom, GeomContext *gc) {
     if (GeomVrtFmt!=FlatVerts) {
     if (GeomVrtFmt!=FlatVerts) {
         // this is the old geom setup, it reformats every vtx into an output array passed to d3d
         // this is the old geom setup, it reformats every vtx into an output array passed to d3d
 
 
-        _perVertex = PER_COORD;
+        _perVertex = 0x0;
+        _perPrim = 0x0;
 
 
-        if (NormalBinding == G_PER_VERTEX)   _perVertex |= PER_NORMAL;
-        if (ColorBinding == G_PER_VERTEX)    _perVertex |= PER_COLOR;
-        if (TexCoordBinding == G_PER_VERTEX) _perVertex |= PER_TEXCOORD;
+        if(NormalBinding == G_PER_VERTEX)   
+          _perVertex |= PER_NORMAL;
+         else if(NormalBinding == G_PER_PRIM) 
+                 _perPrim |= PER_NORMAL;
 
 
-        _perPrim = 0;
-        if (NormalBinding == G_PER_PRIM) _perPrim |= PER_NORMAL;
-        if (ColorBinding == G_PER_PRIM)  _perPrim |= PER_COLOR;
+        if(ColorBinding == G_PER_PRIM)  
+           _perPrim |= PER_COLOR;
+          else if(ColorBinding == G_PER_VERTEX)    
+                 _perVertex |= PER_COLOR;
+
+        if (TexCoordBinding == G_PER_VERTEX) 
+           _perVertex |= PER_TEXCOORD;
 
 
         size_t vertex_size = draw_prim_setup(geom);
         size_t vertex_size = draw_prim_setup(geom);
 
 
@@ -2856,7 +2931,10 @@ draw_tri(GeomTri *geom, GeomContext *gc) {
             if (_perPrim & PER_NORMAL)
             if (_perPrim & PER_NORMAL)
                 p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
                 p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
 
 
-            draw_prim_inner_loop(3, geom, _perVertex);
+
+            if(_perVertex==TexCoordOnly)
+               draw_prim_inner_loop_coordtexonly(3, geom);   
+             else draw_prim_inner_loop(3, geom, _perVertex);
         }
         }
 
 
         DWORD nVerts=nPrims*3;
         DWORD nVerts=nPrims*3;
@@ -3181,10 +3259,12 @@ draw_multitri(Geom *geom, D3DPRIMITIVETYPE trilisttype) {
     if (GeomVrtFmt!=FlatVerts) {
     if (GeomVrtFmt!=FlatVerts) {
 
 
         // this is the old geom setup, it reformats every vtx into an output array passed to d3d
         // this is the old geom setup, it reformats every vtx into an output array passed to d3d
-        _perVertex = PER_COORD;
+        _perVertex = 0x0;
         _perPrim = _perComp = 0;
         _perPrim = _perComp = 0;
 
 
         switch (NormalBinding) {
         switch (NormalBinding) {
+            case G_OFF:
+                break;
             case G_PER_VERTEX:
             case G_PER_VERTEX:
                 _perVertex |= PER_NORMAL;
                 _perVertex |= PER_NORMAL;
                 break;
                 break;
@@ -3197,15 +3277,15 @@ draw_multitri(Geom *geom, D3DPRIMITIVETYPE trilisttype) {
         }
         }
 
 
         switch (ColorBinding) {
         switch (ColorBinding) {
-            case G_PER_VERTEX:
-                _perVertex |= PER_COLOR;
-                break;
             case G_PER_PRIM:
             case G_PER_PRIM:
                 _perPrim |= PER_COLOR;
                 _perPrim |= PER_COLOR;
                 break;
                 break;
             case G_PER_COMPONENT:
             case G_PER_COMPONENT:
                 _perComp |= PER_COLOR;
                 _perComp |= PER_COLOR;
                 break;
                 break;
+            case G_PER_VERTEX:
+                _perVertex |= PER_COLOR;
+                break;
         }
         }
 
 
         if (TexCoordBinding == G_PER_VERTEX)
         if (TexCoordBinding == G_PER_VERTEX)
@@ -3240,7 +3320,9 @@ draw_multitri(Geom *geom, D3DPRIMITIVETYPE trilisttype) {
             _pCurFvfBufPtr = _pFvfBufBasePtr;            // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
             _pCurFvfBufPtr = _pFvfBufBasePtr;            // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
 
 
             if(_perComp==0x0) {
             if(_perComp==0x0) {
-                    draw_prim_inner_loop(nVerts, geom, _perVertex);
+                 if(_perVertex==TexCoordOnly)
+                    draw_prim_inner_loop_coordtexonly(nVerts, geom);   
+                   else draw_prim_inner_loop(nVerts, geom, _perVertex);
             } else {
             } else {
                     if(trilisttype==D3DPT_TRIANGLESTRIP) {
                     if(trilisttype==D3DPT_TRIANGLESTRIP) {
                        // in flat shade mode, D3D strips color using the 1st vertex. 
                        // in flat shade mode, D3D strips color using the 1st vertex. 
@@ -3960,36 +4042,6 @@ apply_texture(TextureContext *tc) {
 
 
         D3DTEXTUREMINFILTER minfilter = PandaToD3DMinType[(DWORD)ft];
         D3DTEXTUREMINFILTER minfilter = PandaToD3DMinType[(DWORD)ft];
         D3DTEXTUREMIPFILTER mipfilter = PandaToD3DMipType[(DWORD)ft];
         D3DTEXTUREMIPFILTER mipfilter = PandaToD3DMipType[(DWORD)ft];
-/*
-        switch (ft) {
-            case Texture::FT_nearest:
-                minfilter = D3DTFN_POINT;
-                mipfilter = D3DTFP_NONE;
-                break;
-            case Texture::FT_linear:
-                minfilter = D3DTFN_LINEAR;
-                mipfilter = D3DTFP_NONE;
-                break;
-            case Texture::FT_nearest_mipmap_nearest:
-                minfilter = D3DTFN_POINT;
-                mipfilter = D3DTFP_POINT;
-                break;
-            case Texture::FT_linear_mipmap_nearest:
-                minfilter = D3DTFN_LINEAR;
-                mipfilter = D3DTFP_POINT;
-                break;
-            case Texture::FT_nearest_mipmap_linear:
-                minfilter = D3DTFN_POINT;
-                mipfilter = D3DTFP_LINEAR;
-                break;
-            case Texture::FT_linear_mipmap_linear:
-                minfilter = D3DTFN_LINEAR;
-                mipfilter = D3DTFP_LINEAR;
-                break;
-            default:
-                dxgsg_cat.error() << "Unknown tex filter type for tex: " << tex->get_name() << "  filter: "<<(DWORD)ft<<"\n";
-        }
-*/
 
 
         #ifndef NDEBUG
         #ifndef NDEBUG
             extern char *PandaFilterNameStrs[];
             extern char *PandaFilterNameStrs[];

+ 12 - 11
panda/src/dxgsg/dxGraphicsStateGuardian.h

@@ -310,23 +310,19 @@ protected:
   INLINE void enable_dither(bool val);
   INLINE void enable_dither(bool val);
   INLINE void enable_stencil_test(bool val);
   INLINE void enable_stencil_test(bool val);
   bool enable_light(int light, bool val);
   bool enable_light(int light, bool val);
-
-  void draw_prim_inner_loop(int nVerts, const Geom *geom, DWORD perFlags);
-  size_t draw_prim_setup(const Geom *geom) ;
+  void report_texmgr_stats();
   void draw_multitri(Geom *geom, D3DPRIMITIVETYPE tri_id);
   void draw_multitri(Geom *geom, D3DPRIMITIVETYPE tri_id);
 
 
-  void report_texmgr_stats();
+  void draw_prim_inner_loop(int nVerts, const Geom *geom, ushort perFlags);
+  void draw_prim_inner_loop_coordtexonly(int nVerts, const Geom *geom);
+  size_t draw_prim_setup(const Geom *geom) ;
 
 
   //   for drawing primitives
   //   for drawing primitives
-  //  Colorf    p_color;  bypassed by _curD3Dcolor;
-  //  Vertexf   p_vertex;
   Normalf   p_normal;  // still used to hold G_OVERALL, G_PER_PRIM values
   Normalf   p_normal;  // still used to hold G_OVERALL, G_PER_PRIM values
   TexCoordf p_texcoord;
   TexCoordf p_texcoord;
   D3DCOLOR  _curD3Dcolor;
   D3DCOLOR  _curD3Dcolor;
   DWORD     _curFVFflags;
   DWORD     _curFVFflags;
-  short     _perPrim;
-  short     _perVertex;
-  short     _perComp;
+  DWORD     _perPrim,_perVertex,_perComp;   //  these hold DrawLoopFlags bitmask values
 
 
   bool  _issued_color_enabled;      // WBD ADDED
   bool  _issued_color_enabled;      // WBD ADDED
   bool  _enable_all_color;
   bool  _enable_all_color;
@@ -352,11 +348,16 @@ protected:
   PTA_ushort _vindexes;
   PTA_ushort _vindexes;
   ushort *_pCurCoordIndex;  
   ushort *_pCurCoordIndex;  
 
 
+  PTA_TexCoordf _texcoords;
+  TexCoordf *_pCurTexCoord;
+  PTA_ushort _texcoord_indexes;
+  ushort *_pCurTexCoordIndex;  
 
 
+/*  not used yet
   PTA_Normalf _norms;
   PTA_Normalf _norms;
   PTA_Colorf _colors;
   PTA_Colorf _colors;
-  PTA_TexCoordf _texcoords;
-  PTA_ushort _cindexes,_nindexes,_tindexes;
+  PTA_ushort _cindexes,_nindexes;
+*/  
 
 
   Colorf _lmodel_ambient;
   Colorf _lmodel_ambient;
   float _material_ambient;
   float _material_ambient;