Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

vsmmanager.cpp

Go to the documentation of this file.
00001 /*           Copyright (C) 2001 Sony Computer Entertainment America
00002                               All Rights Reserved
00003                                SCEA Confidential                                */
00004 
00005 #include "ps2s/packet.h"
00006 #include "ps2s/cpu_matrix.h"
00007 #include "ps2s/math.h"
00008 #include "ps2s/timer.h"
00009 
00010 #include "ps2gl/vsmmanager.h"
00011 #include "ps2gl/immgmanager.h"
00012 #include "ps2gl/lighting.h"
00013 #include "ps2gl/glcontext.h"
00014 #include "ps2gl/material.h"
00015 #include "ps2gl/matrix.h"
00016 #include "ps2gl/texture.h"
00017 #include "ps2gl/metrics.h"
00018 #include "ps2gl/drawcontext.h"
00019 
00020 #include "vu1common.h"
00021 #include "vu1renderers.h"
00022 
00023 using namespace Vu1RendererProps;
00024 
00025 /********************************************
00026  * class CVsmManager
00027  */
00028 
00029 // static data
00030 
00031 const tVu1Renderer CVsmManager::Vu1Renderers[] =
00032 {
00033    {
00034       (void*)vsmSCEI,
00035       {
00036          PrimType:      kPtsLinesStripsFans,
00037          Lighting:      1,
00038          LightTypes:    k3DirLights,
00039          Texture:       1,
00040          Specular:      0,
00041          PerVtxMaterial: kNone,
00042          CullFace:      0,
00043          TwoSidedLighting: 0
00044       }
00045       , 3, 3
00046    },
00047 
00048    {
00049       (void*)vsmGeneralNoSpec,
00050       {
00051          PrimType:      kPtsLinesStripsFans,
00052          Lighting:      1,
00053          LightTypes:    k3DirLights | k8DirLights | k1PtLight | k2PtLights | k8PtLights,
00054          Texture:       1,
00055          Specular:      0,
00056          PerVtxMaterial: kNone,
00057          CullFace:      1,
00058          TwoSidedLighting: 0
00059       },
00060       3, 3
00061    },
00062    {
00063       (void*)vsmGeneralNoSpecTri,
00064       {
00065          PrimType:      kTriangles,
00066          Lighting:      1,
00067          LightTypes:    k3DirLights | k8DirLights | k1PtLight | k2PtLights | k8PtLights,
00068          Texture:       1,
00069          Specular:      0,
00070          PerVtxMaterial: kNone,
00071          CullFace:      1,
00072          TwoSidedLighting: 0
00073       },
00074       3, 3
00075    },
00076    {
00077       (void*)vsmGeneralNoSpecQuad,
00078       {
00079          PrimType:      kQuads,
00080          Lighting:      1,
00081          LightTypes:    k3DirLights | k8DirLights | k1PtLight | k2PtLights | k8PtLights,
00082          Texture:       1,
00083          Specular:      0,
00084          PerVtxMaterial: kNone,
00085          CullFace:      1,
00086          TwoSidedLighting: 0
00087       },
00088       3, 3
00089    },
00090 
00091 
00092 
00093    {
00094       (void*)vsmGeneral,
00095       {
00096          PrimType:      kPtsLinesStripsFans,
00097          Lighting:      1,
00098          LightTypes:    k3DirLights | k8DirLights | k1PtLight | k2PtLights | k8PtLights,
00099          Texture:       1,
00100          Specular:      1,
00101          PerVtxMaterial: kNone,
00102          CullFace:      1,
00103          TwoSidedLighting: 0
00104       },
00105       3, 3
00106    },
00107    {
00108       (void*)vsmGeneralQuad,
00109       {
00110          PrimType:      kQuads,
00111          Lighting:      1,
00112          LightTypes:    k3DirLights | k8DirLights | k1PtLight | k2PtLights | k8PtLights,
00113          Texture:       1,
00114          Specular:      1,
00115          PerVtxMaterial: kNone,
00116          CullFace:      1,
00117          TwoSidedLighting: 0
00118       },
00119       3, 3
00120    },
00121    {
00122       (void*)vsmGeneralTri,
00123       {
00124          PrimType:      kTriangles,
00125          Lighting:      1,
00126          LightTypes:    k3DirLights | k8DirLights | k1PtLight | k2PtLights | k8PtLights,
00127          Texture:       1,
00128          Specular:      1,
00129          PerVtxMaterial: kNone,
00130          CullFace:      1,
00131          TwoSidedLighting: 0
00132       },
00133       3, 3
00134    },
00135 
00136 
00137 
00138 
00139    {
00140       (void*)vsmGeneralPVDiff,
00141       {
00142          PrimType:      kPtsLinesStripsFans | kTriangles | kQuads,
00143          Lighting:      1,
00144          LightTypes:    k3DirLights | k8DirLights | k1PtLight | k2PtLights | k8PtLights,
00145          Texture:       1,
00146          Specular:      1,
00147          PerVtxMaterial: kDiffuse,
00148          CullFace:      1,
00149          TwoSidedLighting: 0
00150       },
00151       4, 3
00152    },
00153    {
00154       (void*)vsmGeneralPVDiffTri,
00155       {
00156          PrimType:      kTriangles,
00157          Lighting:      1,
00158          LightTypes:    k3DirLights | k8DirLights | k1PtLight | k2PtLights | k8PtLights,
00159          Texture:       1,
00160          Specular:      1,
00161          PerVtxMaterial: kDiffuse,
00162          CullFace:      1,
00163          TwoSidedLighting: 0
00164       },
00165       4, 3
00166    },
00167    {
00168       (void*)vsmGeneralPVDiffQuad,
00169       {
00170          PrimType:      kQuads,
00171          Lighting:      1,
00172          LightTypes:    k3DirLights | k8DirLights | k1PtLight | k2PtLights | k8PtLights,
00173          Texture:       1,
00174          Specular:      1,
00175          PerVtxMaterial: kDiffuse,
00176          CullFace:      1,
00177          TwoSidedLighting: 0
00178       },
00179       4, 3
00180    },
00181 };
00182 
00183 const int CVsmManager::NumVu1Renderers = sizeof(CVsmManager::Vu1Renderers) / sizeof(tVu1Renderer);
00184 
00185 
00186 CVsmManager::CVsmManager( CGLContext &context)
00187    : GLContext(context),
00188      VsmReqsHaveChanged(false), CurrentVu1Renderer(NULL)
00189 {
00190    VsmRequirements.PrimType     = 0;
00191    VsmRequirements.Lighting     = 0;
00192    VsmRequirements.LightTypes   = 0;
00193    VsmRequirements.Texture      = 0;
00194    VsmRequirements.Specular     = 0;
00195    VsmRequirements.PerVtxMaterial = kNone;
00196    VsmRequirements.CullFace     = 0;
00197    VsmRequirements.TwoSidedLighting = 0;
00198 }
00199 
00200 // state updates
00201 
00202 void
00203 CVsmManager::NumLightsChanged( tLightType type, int num )
00204 {
00205    CVu1RendererProps newState = VsmRequirements;
00206 
00207    switch (type) {
00208       case kDirectional:
00209          if (0 < num && num <= 3) newState.LightTypes = k3DirLights; // in namespace??
00210          else newState.LightTypes = k8DirLights;
00211 
00212          if ( VsmRequirements != newState ) {
00213             VsmRequirements = newState;
00214             VsmReqsHaveChanged = true;
00215          }
00216          break;
00217 
00218       case kPoint:
00219          if (num == 1) newState.LightTypes = k1PtLight;
00220          else if (num == 2) newState.LightTypes = k2PtLights;
00221          else newState.LightTypes = k8PtLights;
00222 
00223          if ( VsmRequirements != newState ) {
00224             VsmRequirements = newState;
00225             VsmReqsHaveChanged = true;
00226          }
00227          break;
00228 
00229       case kSpot:
00230          break;
00231    }
00232 }
00233 
00234 void
00235 CVsmManager::PrimChanged( unsigned char prim )
00236 {
00237    CVu1RendererProps newState = VsmRequirements;
00238 
00239    if (prim <= GL_LINE_STRIP)
00240       newState.PrimType = kPtsLinesStripsFans;
00241    else if (prim == GL_TRIANGLE_STRIP
00242             || prim == GL_TRIANGLE_FAN
00243             || prim == GL_POLYGON)
00244       newState.PrimType = kPtsLinesStripsFans;
00245    else if (prim == GL_QUAD_STRIP)
00246       newState.PrimType = kPtsLinesStripsFans;
00247    else if (prim == GL_TRIANGLES)
00248       newState.PrimType = kTriangles;
00249    else if (prim == GL_QUADS)
00250       newState.PrimType = kQuads;
00251    else {
00252       mError("shouldn't get here");
00253    }
00254 
00255    if ( VsmRequirements != newState ) {
00256       VsmRequirements = newState;
00257       VsmReqsHaveChanged = true;
00258    }
00259 }
00260 
00261 void
00262 CVsmManager::TexEnabledChanged( bool enabled )
00263 {
00264    CVu1RendererProps newState = VsmRequirements;
00265 
00266    if ( enabled ) newState.Texture = 1;
00267    else newState.Texture = 0;
00268 
00269    if ( VsmRequirements != newState ) {
00270       VsmRequirements = newState;
00271       VsmReqsHaveChanged = true;
00272    }
00273 }
00274 
00275 void
00276 CVsmManager::LightingEnabledChanged( bool enabled )
00277 {
00278    CVu1RendererProps newState = VsmRequirements;
00279 
00280    if (enabled) newState.Lighting = 1;
00281    else newState.Lighting = 0;
00282 
00283    if (VsmRequirements != newState) {
00284       VsmRequirements = newState;
00285       VsmReqsHaveChanged = true;
00286    }
00287 }
00288 
00289 void
00290 CVsmManager::SpecularEnabledChanged( bool enabled )
00291 {
00292    CVu1RendererProps newState = VsmRequirements;
00293 
00294    if (enabled) newState.Specular = 1;
00295    else newState.Specular = 0;
00296    
00297    if (VsmRequirements != newState) {
00298       VsmRequirements = newState;
00299       VsmReqsHaveChanged = true;
00300    }
00301 }
00302 
00303 void
00304 CVsmManager::PerVtxMaterialChanged( Vu1RendererProps::tPerVtxMaterial matType )
00305 {
00306    if ( VsmRequirements.PerVtxMaterial != (unsigned int)matType ) {
00307       VsmRequirements.PerVtxMaterial = matType;
00308       VsmReqsHaveChanged = true;
00309    }
00310 }
00311 
00312 void
00313 CVsmManager::CullFaceEnabledChanged( bool enabled )
00314 {
00315    if ( VsmRequirements.CullFace != enabled ) {
00316       VsmRequirements.CullFace = enabled;
00317       VsmReqsHaveChanged = true;
00318    }
00319 }
00320 
00321 bool
00322 CVsmManager::SyncVu1Renderer()
00323 {
00324    bool rendererChanged = false;
00325 
00326    if ( VsmReqsHaveChanged ) {
00327       int i;
00328       for ( i = 0; i < NumVu1Renderers; i++ )
00329          if ( VsmRequirements == (VsmRequirements & Vu1Renderers[i].provides) )
00330             break;
00331 
00332       mErrorIf( i == NumVu1Renderers,
00333                 "Couldn't find a suitable vu1 renderer.. requirements = 0x%08x",
00334                 (unsigned int)VsmRequirements );
00335       if (CurrentVu1Renderer != &Vu1Renderers[i]) {
00336          CurrentVu1Renderer = &Vu1Renderers[i];
00337          /*
00338          printf("vu1 renderer requirements are 0x%08x, renderer = 0x%08x\n",
00339                 (unsigned int)VsmRequirements, (unsigned int)CurrentVu1Renderer->provides);
00340          */
00341          rendererChanged = true;
00342       }
00343    }
00344 
00345    return rendererChanged;
00346 }
00347 
00348 void
00349 CVsmManager::XferVu1Renderer( CVifSCDmaPacket &packet )
00350 {
00351    mAssert( CurrentVu1Renderer != NULL );
00352    mErrorIf( *(unsigned short*)CurrentVu1Renderer->packet > 1024,
00353              "This vu1 renderer won't fit into vu1 code memory: 0x%08x",
00354              (unsigned int)CurrentVu1Renderer->provides );
00355 
00356    packet.Call( CurrentVu1Renderer->packet );
00357    packet.Pad128();
00358    packet.CloseTag();
00359 
00360    pglAddToMetric(kMetricsRendererUpload);
00361 }
00362 
00363 void
00364 CVsmManager::TransferSetupInfo( CVifSCDmaPacket &packet,
00365                                CImmGeomManager &gmanager, GLenum primType )
00366 {
00367    // The "global" vu1 parameters depend on the following info:
00368    // which lights are enabled/disabled, each enabled light's settings,
00369    // global ambient, current material, vertex xform, giftag
00370 
00371    packet.Cnt();
00372    {
00373       packet.Stcycl(1,1);
00374       packet.Flush();
00375       packet.Pad96();
00376       packet.OpenUnpack( Vifs::UnpackModes::v4_32, kInitInfoStart, Packet::kSingleBuff );
00377       {
00378          // find light pointers
00379          CImmLighting &lighting = GLContext.GetImmLighting();
00380          tLightPtrs lightPtrs[8];
00381          tLightPtrs *nextDir, *nextPt, *nextSpot;
00382          nextDir = nextPt = nextSpot = &lightPtrs[0];
00383          int numDirs, numPts, numSpots;
00384          numDirs = numPts = numSpots = 0;
00385          for ( int i = 0; i < 8; i++ ) {
00386             CImmLight& light = lighting.GetImmLight(i);
00387             if ( light.IsEnabled() ) {
00388                if ( light.IsDirectional() ) {
00389                   nextDir->dir = kLight0Base + i * kLightStructSize;
00390                   nextDir++;
00391                   numDirs++;
00392                }
00393                else if ( light.IsPoint() ) {
00394                   nextPt->point = kLight0Base + i * kLightStructSize;
00395                   nextPt++;
00396                   numPts++;
00397                }
00398                else if ( light.IsSpot() ) {
00399                   nextSpot->spot = kLight0Base + i * kLightStructSize;
00400                   nextSpot++;
00401                   numSpots++;
00402                }
00403             }
00404          }       
00405 
00406          bool doLighting = GLContext.GetImmLighting().GetLightingEnabled();
00407 
00408          // transpose of object to world space xfrm (for light directions)
00409          cpu_mat_44 objToWorldXfrmTrans = GLContext.GetModelViewStack().GetTop();
00410          // clear any translations.. should be doing a 3x3 transpose..
00411          objToWorldXfrmTrans.set_col3( cpu_vec_xyzw(0, 0, 0, 1) );
00412          objToWorldXfrmTrans = objToWorldXfrmTrans.transpose();
00413          // do we need to rescale normals?
00414          cpu_mat_44 normalRescale;
00415          normalRescale.set_identity();
00416          float normalScale = 1.0f;
00417          CImmDrawContext &drawContext = GLContext.GetImmDrawContext();
00418          if ( drawContext.GetRescaleNormals() ) {
00419             cpu_vec_xyzw fake_normal( 1, 0, 0, 0 );
00420             fake_normal = objToWorldXfrmTrans * fake_normal;
00421             normalScale = 1.0f / fake_normal.length();
00422             normalRescale.set_scale( cpu_vec_xyz(normalScale, normalScale, normalScale) );
00423          }
00424          objToWorldXfrmTrans = normalRescale * objToWorldXfrmTrans;
00425 
00426          // num lights
00427          if ( doLighting ) {
00428             packet += numDirs;
00429             packet += numPts;
00430             packet += numSpots;
00431          }
00432          else {
00433             packet += (tU64)0;
00434             packet += 0;
00435          }
00436 
00437          // backface culling multiplier -- this is 1.0f or -1.0f, the 6th bit
00438          // also turns on/off culling
00439          float bfc_mult = (float)drawContext.GetCullFaceDir();
00440          unsigned int bfc_word;
00441          asm( " ## nop ## " : "=r" (bfc_word) : "0" (bfc_mult) );
00442          bool do_culling = drawContext.GetDoCullFace() && (primType > GL_LINE_STRIP);
00443          packet += bfc_word | (unsigned int)do_culling << 5;
00444 
00445          // light pointers
00446          packet.Add( &lightPtrs[0], 8 );
00447          
00448          // when texturing in modulate mode, 100% of a channel occurs at
00449          // 0.5 on the gs, so we want a color component value of 1.0 to map to
00450          // 128, else 255
00451          float maxColorValue = 255.0f;
00452          if ( GLContext.GetTexManager().GetTexEnabled() )
00453             maxColorValue = 128.0f;
00454 
00455          // add light info
00456          for ( int i = 0; i < 8; i++ ) {
00457             CImmLight& light = lighting.GetImmLight(i);
00458             packet += light.GetAmbient() * maxColorValue;
00459             packet += light.GetDiffuse() * maxColorValue;
00460             packet += light.GetSpecular() * maxColorValue;
00461 
00462             if ( light.IsDirectional() )
00463                packet += light.GetPosition();
00464             else {
00465                packet += light.GetPosition();
00466             }
00467 
00468             packet += light.GetSpotDir();
00469 
00470             // attenuation coeffs for positional light sources
00471             // because we're doing lighting calculations in object space,
00472             // we need to adjust the attenuation of positional light sources
00473             // and all lighting directions to take into account scaling
00474             packet += light.GetConstantAtten();
00475             packet += light.GetLinearAtten() * 1.0f/normalScale;
00476             packet += light.GetQuadAtten() * 1.0f/normalScale;
00477             packet += 0; // padding
00478 
00479          }
00480 
00481          // a zero for turning off lighting (sortof..)
00482          tU128 zeroQuad;
00483          asm ( "pxor %0, %0, %0" : "=r" (zeroQuad) );
00484 
00485          // global ambient
00486          if ( doLighting )
00487             packet += lighting.GetGlobalAmbient() * maxColorValue;
00488          else
00489             packet += zeroQuad;
00490 
00491          // cur material
00492          CImmMaterial& material = GLContext.GetMaterialManager().GetImmMaterial();
00493          if ( doLighting )
00494             packet += material.GetEmission() * maxColorValue;
00495          else
00496             packet += GLContext.GetMaterialManager().GetCurColor() * maxColorValue;
00497          packet += material.GetAmbient();
00498          packet += material.GetDiffuse();
00499          packet += material.GetSpecular();
00500 
00501          // vertex xform
00502          packet += drawContext.GetVertexXform();
00503 
00504          // fixed vertToEye vector for non-local specular
00505          cpu_vec_xyzw vertToEye( 0.0f, 0.0f, 1.0f, 0.0f );
00506          packet += objToWorldXfrmTrans * vertToEye;
00507 
00508          // transpose of object to world space transform
00509          packet += objToWorldXfrmTrans;
00510 
00511          // world to object space xfrm (for light positions)
00512          cpu_mat_44 worldToObjXfrm = GLContext.GetModelViewStack().GetInvTop();
00513          packet += worldToObjXfrm;
00514 
00515          // giftag - this is down at the bottom to make sure that when switching
00516          // primitives the last buffer will have a chance to copy the giftag before
00517          // it is overwritten with the new one
00518          SyncGifTag( gmanager, primType );
00519          packet += GifTag;
00520       }
00521       packet.CloseUnpack();
00522 
00523       packet.Mscal(0);
00524       packet.Flushe();
00525 
00526       packet.Base( kDoubleBufBase );
00527       packet.Offset( kDoubleBufOffset );
00528    }
00529    packet.CloseTag();
00530 
00531    ColorMaterialEnabled = GLContext.GetMaterialManager().GetColorMaterialEnabled();
00532    TexEnabled = GLContext.GetTexManager().GetTexEnabled();
00533 }
00534 
00535 void
00536 CVsmManager::SyncGifTag( CImmGeomManager &gmanager, GLenum primType )
00537 {
00538    primType &= 0x7;  // convert from GL #define to gs prim number
00539    CImmDrawContext &drawContext = GLContext.GetImmDrawContext();
00540    bool smoothShading = drawContext.GetDoSmoothShading();
00541    bool useTexture = GLContext.GetTexManager().GetTexEnabled();
00542    bool alpha = drawContext.GetBlendEnabled();
00543    unsigned int nreg = CurrentVu1Renderer->outputQuadsPerVert;
00544 
00545    sceGsPrim prim = { PRIM: primType, IIP: smoothShading, TME: useTexture,
00546                       FGE: 0, ABE: alpha, AA1: 0, FST: 0, CTXT: 0, FIX: 0 };
00547    sceGifTag giftag = { NLOOP: 0, EOP: 1, pad16: 0, id: 0, PRE: 1,
00548                         PRIM: *(tU64*)&prim, FLG: 0, NREG: nreg, REGS0: 2, REGS1: 1,
00549                         REGS2: 4 };
00550    GifTag = giftag;
00551 }
00552 
00553 void
00554 CVsmManager::XferVectors( CVifSCDmaPacket &packet, unsigned int *dataStart,
00555                          int startOffset, int numVectors, int wordsPerVec,
00556                          Vifs::tMask unpackMask, tU32 unpackMode,
00557                          int vu1MemOffset )
00558 {
00559    // find number of words to prepend with a cnt
00560 
00561    unsigned int *vecDataStart = dataStart + startOffset * wordsPerVec;
00562    unsigned int *vecDataEnd = vecDataStart + numVectors * wordsPerVec;
00563 
00564    mAssert( numVectors > 0 );
00565    mErrorIf( (unsigned int)vecDataStart & 4-1,
00566              "XferVectors only works with word-aligned data" );
00567 
00568    int numWordsToPrepend = 0;
00569    unsigned int *refXferStart = vecDataStart;
00570    while ( (unsigned int)refXferStart & (16-1) ) {
00571       numWordsToPrepend++;
00572       refXferStart++;
00573       if ( refXferStart == vecDataEnd ) break;
00574    }
00575    int numWordsToAppend = 0;
00576    unsigned int *refXferEnd = vecDataEnd;
00577    while ( ((unsigned int)refXferEnd & (16-1)) && refXferEnd > refXferStart ) {
00578       numWordsToAppend++;
00579       refXferEnd--;
00580    }
00581    int numQuadsInRefXfer = ((unsigned int)refXferEnd - (unsigned int)refXferStart) / 16;
00582 
00583    packet.Cnt();
00584    {
00585       // set mask to expand vectors appropriately
00586       packet.Stmask( unpackMask );
00587 
00588       // prepend
00589       if ( numWordsToPrepend > 1 ) {
00590          // either 2 or 3 words to prepend
00591          packet.Nop().Nop();
00592          if ( numWordsToPrepend == 2 )
00593             packet.Nop();
00594          
00595          packet.OpenUnpack( unpackMode,
00596                             vu1MemOffset,
00597                             Packet::kDoubleBuff,
00598                             Packet::kMasked );
00599          packet.CloseUnpack( numVectors );
00600 
00601          if ( numWordsToPrepend == 3 )
00602             packet += *vecDataStart;
00603       }
00604 
00605       packet.Pad128();
00606    }
00607    packet.CloseTag();
00608 
00609    // xfer qword block of vectors
00610    packet.Ref( Core::MakePtrNormal(refXferStart), numQuadsInRefXfer );
00611    {
00612       // either 0 words to prepend or 1 word left to prepend
00613       if ( numWordsToPrepend == 0 )
00614          packet.Nop();
00615       if ( numWordsToPrepend <= 1 ) {
00616          packet.OpenUnpack( unpackMode,
00617                             vu1MemOffset,
00618                             Packet::kDoubleBuff,
00619                             Packet::kMasked );
00620          packet.CloseUnpack( numVectors );
00621       }
00622       if ( numWordsToPrepend == 1 )
00623          packet += *vecDataStart;
00624       else if ( numWordsToPrepend == 2 )
00625          packet.Add( vecDataStart, 2 );
00626       else if ( numWordsToPrepend == 3 )
00627          packet.Add( &vecDataStart[1], 2 );
00628    }
00629 
00630    // xfer any remaining vectors
00631    if ( numWordsToAppend > 0 ) {
00632       packet.Cnt();
00633       {
00634          packet.Add( refXferEnd, numWordsToAppend );
00635          packet.Pad128();
00636       }
00637       packet.CloseTag();
00638    }
00639 }
00640 
00641 void
00642 CVsmManager::XferBufferHeader( CVifSCDmaPacket& packet, GLenum primType,
00643                               int numVerts,
00644                               int numStripsInBuffer, unsigned short *stripOffsets )
00645 {
00646    int vu1InQuadsPerVert = CurrentVu1Renderer->inputQuadsPerVert;
00647    int vu1OutQuadsPerVert = CurrentVu1Renderer->outputQuadsPerVert;
00648 
00649    packet.Cnt();
00650    {
00651       // xfer header info for strip
00652       packet.Stcycl(4,4);
00653       packet.OpenUnpack( Vifs::UnpackModes::v4_32, 0, Packet::kDoubleBuff );
00654       {
00655          // num vertices
00656          packet += numVerts;
00657          packet += 0; packet += (tU64)0;
00658 
00659          // input strides
00660          if ( primType == GL_QUADS ) {
00661             packet += 1 * vu1InQuadsPerVert;
00662             packet += 2 * vu1InQuadsPerVert; 
00663             packet += -1 * vu1InQuadsPerVert;
00664             packet += 2 * vu1InQuadsPerVert;
00665          }
00666          else {
00667             packet += 1 * vu1InQuadsPerVert;
00668             packet += 1 * vu1InQuadsPerVert;
00669             packet += 1 * vu1InQuadsPerVert;
00670             packet += 1 * vu1InQuadsPerVert;
00671          }
00672 
00673          // ADC bits (only set to draw disjoint quads)
00674          if ( primType == GL_QUADS ) {
00675             packet += 0x8000; packet += 0x8000; packet += 0; packet += 0;
00676          }
00677          else {
00678             packet += 0; packet += 0; packet += 0; packet += 0;
00679          }
00680 
00681          // adc bits for the beginning of strips.. 16 24-bit values of following format:
00682          //   bits 0-9  : offset into output geometry (not including giftag)
00683          //   bit 10    : stop bit
00684          //   bit 11    : ADC bit of second vertex starting at offset
00685          // these are converted to floats to do a right shift with a fp add on vu1
00686          unsigned int adcBits = 0;
00687          if ( primType == GL_TRIANGLE_STRIP || primType == GL_QUAD_STRIP )
00688             adcBits = 0x800;
00689          float adc;
00690          unsigned int stopBit = 0x400;
00691          for ( int i = 0; i < 16; i++ ) {
00692             if ( i < numStripsInBuffer )
00693                adc = (float)(adcBits |
00694                              (unsigned int)stripOffsets[i] * vu1OutQuadsPerVert );
00695             else if ( i == numStripsInBuffer )
00696                adc = (float)stopBit;
00697             else
00698                adc = (float)0;
00699             packet += adc;
00700          }
00701       }
00702       packet.CloseUnpack();
00703    }
00704    packet.CloseTag();
00705 }
00706 
00707 void
00708 CVsmManager::GetUnpackAttribs( int numWords, unsigned int &mode, Vifs::tMask &mask )
00709 {
00710 
00711    if ( numWords == 3 ) {
00712       Vifs::tMask vec3Mask = { 0, 0, 0, 1,
00713                                0, 0, 0, 1,
00714                                0, 0, 0, 1,
00715                                0, 0, 0, 1 };
00716       mode = Vifs::UnpackModes::v3_32;
00717       mask = vec3Mask;
00718    }
00719    else if ( numWords == 4 ) {
00720       Vifs::tMask vec4Mask = { 0, 0, 0, 0,
00721                                0, 0, 0, 0,
00722                                0, 0, 0, 0,
00723                                0, 0, 0, 0 };
00724       mode = Vifs::UnpackModes::v4_32;
00725       mask = vec4Mask;
00726    }
00727    else if ( numWords == 2 ) {
00728       Vifs::tMask vec2Mask = { 0, 0, 1, 1,
00729                                0, 0, 1, 1,
00730                                0, 0, 1, 1,
00731                                0, 0, 1, 1 };
00732       mode = Vifs::UnpackModes::v2_32;
00733       mask = vec2Mask;
00734    }
00735    else {
00736       mError("shouldn't get here (you're probably calling glDrawArrays"
00737          "without setting one of the pointers)");
00738    }
00739 }
00740 
00741 void
00742 CVsmManager::DrawArrays( CVifSCDmaPacket &packet, CImmGeomManager &gmanager,
00743                         CGeometryBlock &block )
00744 {
00745    mErrorIf( block.GetWordsPerVertex() == 2, "2 word vertices not supported" );
00746 
00747    //
00748    // set up the row register to expand vectors with fewer than 4 elements
00749    //
00750 
00751    packet.Cnt();
00752    {
00753       static const float row[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
00754       packet.Strow( row );
00755 
00756       packet.Pad128();
00757    }
00758    packet.CloseTag();
00759 
00760    //
00761    // get unpack modes/masks
00762    //
00763 
00764    WordsPerVertex = block.GetWordsPerVertex();
00765    GetUnpackAttribs( WordsPerVertex, VertexUnpackMode, VertexUnpackMask );
00766 
00767    WordsPerNormal = 0;
00768    if ( block.GetNormalsAreValid() )
00769       WordsPerNormal = block.GetWordsPerNormal();
00770    else
00771       WordsPerNormal = 3;
00772    GetUnpackAttribs( WordsPerNormal, NormalUnpackMode, NormalUnpackMask );
00773 
00774    WordsPerTexCoord = 0;
00775    if ( block.GetTexCoordsAreValid() )
00776       WordsPerTexCoord = block.GetWordsPerTexCoord();
00777    else
00778       WordsPerTexCoord = 2;
00779    GetUnpackAttribs( WordsPerTexCoord, TexCoordUnpackMode, TexCoordUnpackMask );
00780 
00781    WordsPerColor = 0;
00782    if ( block.GetColorsAreValid() )
00783       WordsPerColor = block.GetWordsPerColor();
00784    else
00785       WordsPerColor = 3;
00786    GetUnpackAttribs( WordsPerColor, ColorUnpackMode, ColorUnpackMask );
00787 
00788    //
00789    // get max number of vertices per vu1 buffer
00790    //
00791 
00792    // let's assume separate unpacks for vertices, normals, tex uvs..
00793    int maxUnpackVerts = 256;
00794    // max number of vertex data in vu1 memory
00795    int vu1QuadsPerVert = CurrentVu1Renderer->inputQuadsPerVert;
00796    int inputBufSize = kInputBufSize - kInputStart;
00797    int maxVu1VertsPerBuffer = inputBufSize / vu1QuadsPerVert;
00798    // max vertices per buffer
00799    int maxVertsPerBuffer = Math::Min( maxUnpackVerts, maxVu1VertsPerBuffer );
00800    maxVertsPerBuffer -= 10;
00801    // make sure we don't end in the middle of a polygon
00802    maxVertsPerBuffer -= maxVertsPerBuffer % block.GetNumVertsPerPrim();
00803 
00804    //
00805    // draw
00806    //
00807 
00808    DrawStrip( packet, gmanager, block, maxVertsPerBuffer );
00809 }
00810 
00811 void
00812 CVsmManager::DrawStrip( CVifSCDmaPacket &packet, CImmGeomManager &gmanager,
00813                        CGeometryBlock &block, int maxVertsPerBuffer )
00814 {
00815    //
00816    // loop over the strips in this geometry block
00817    //
00818 
00819    int numVertsToRestart = block.GetNumVertsToRestartStrip();
00820    int numVertsXferred = 0;
00821    bool writeModeIsValid = false;
00822    int numStripsInBuffer = 0;
00823    unsigned short stripOffsets[16];
00824    bool haveContinued = false;
00825    void *normals, *vertices, *texCoords, *colors;
00826    normals = vertices = texCoords = colors = NULL;
00827    int vu1BufferOffset = 0, stripIndex = 0, vertsInBlock = 0;
00828    for ( int curStrip = 0; curStrip < block.GetNumStrips(); curStrip++ ) {
00829 
00830       // find the number of vu1 buffers this strip will take
00831       int numVertsFirstBuffer, numVertsLastBuffer, numBuffers;
00832       FindNumBuffers( block.GetStripLength(curStrip),
00833                       numVertsToRestart, numVertsXferred, maxVertsPerBuffer,
00834                       numVertsFirstBuffer, numVertsLastBuffer, numBuffers );
00835 
00836       //
00837       // loop over the buffers this strip will fill (usually one)
00838       //
00839 
00840       int numVertsThisBuffer;
00841       int indexIntoStrip = 0;
00842       int vu1QuadsPerVert = CurrentVu1Renderer->inputQuadsPerVert;
00843       for ( int curBuffer = 0;
00844             curBuffer < numBuffers;
00845             curBuffer++, indexIntoStrip += numVertsThisBuffer - numVertsToRestart ) {
00846 
00847          // how many verts in this vu1 buffer?
00848          if ( curBuffer == 0 )
00849             numVertsThisBuffer = numVertsFirstBuffer;
00850          else if ( curBuffer == numBuffers - 1 )
00851             numVertsThisBuffer = numVertsLastBuffer;
00852          else
00853             numVertsThisBuffer = maxVertsPerBuffer;
00854 
00855          // xfer the list of primitives
00856 
00857          if ( ! writeModeIsValid ) {
00858             // interleave the vertices, normals, tex coords, and colors using
00859             // "skipping write" vif mode on each block of data
00860             // (clobbered in XferBufferHeader())
00861             packet.Cnt();
00862             {
00863                packet.Stcycl(1, vu1QuadsPerVert);
00864                packet.Pad128();
00865             }
00866             packet.CloseTag();
00867          }
00868 
00869          if ( ! haveContinued ) {
00870             vertices = (block.GetVerticesAreValid()) ? block.GetVertices(curStrip) : NULL;
00871             normals = (block.GetNormalsAreValid()) ? block.GetNormals(curStrip) : NULL;
00872             texCoords = (block.GetTexCoordsAreValid()) ? block.GetTexCoords(curStrip) : NULL;
00873             colors = (block.GetColorsAreValid()) ? block.GetColors(curStrip) : NULL;
00874             vu1BufferOffset = kInputStart + numVertsXferred * vu1QuadsPerVert;
00875             stripIndex = indexIntoStrip;
00876             vertsInBlock = 0;
00877          }
00878 
00879          // we only want to transfer the geometry data if:
00880          //   - the next strip is not adjacent in memory to this one (indicated by
00881          //     CGeometryBlock::StripIsContinued)
00882          //   - this strip spills over into the next buffer
00883          if ( ! block.StripIsContinued(curStrip)
00884               || curBuffer < numBuffers - 1 ) {
00885             XferBlock( packet, gmanager, block.GetPrimType(),
00886                        vertices, normals, texCoords, colors,
00887                        vu1BufferOffset,
00888                        stripIndex, vertsInBlock + numVertsThisBuffer );
00889             haveContinued = false;
00890          }
00891          else {
00892             vertsInBlock += numVertsThisBuffer;
00893             haveContinued = true;
00894          }
00895 
00896          stripOffsets[numStripsInBuffer++] = numVertsXferred;
00897          mErrorIf( numStripsInBuffer > 16, "Too many strips in buffer.. this shouldn't happen" );
00898          numVertsXferred += numVertsThisBuffer;
00899 
00900          // if there are more buffers in this strip, render this buffer
00901          if ( curBuffer < numBuffers - 1 ) {
00902             FinishBuffer( packet, block, numVertsXferred, vu1QuadsPerVert,
00903                           numStripsInBuffer, stripOffsets );
00904             writeModeIsValid = false;
00905             numStripsInBuffer = 0;
00906             numVertsXferred = 0;
00907          }
00908 
00909       } // end buffer loop
00910 
00911       // finish this buffer and start a new one if:
00912       //   - there is too little free space left
00913       //   - we have filled the max number of strips per buffer
00914       //   - or this is the last strip
00915 
00916       // test against 'numVertsToRestart + 1' because FindNumBuffers() might
00917       // clip off one vert for backface culling
00918       if ( ( (maxVertsPerBuffer - numVertsXferred) <= numVertsToRestart + 1 )
00919            || numStripsInBuffer == 16
00920            || (curStrip == block.GetNumStrips() - 1) ) {
00921          if ( haveContinued ) {
00922             XferBlock( packet, gmanager, block.GetPrimType(),
00923                        vertices, normals, texCoords, colors,
00924                        vu1BufferOffset,
00925                        stripIndex, vertsInBlock );
00926             haveContinued = false;
00927          }
00928 
00929          FinishBuffer( packet, block, numVertsXferred, vu1QuadsPerVert,
00930                           numStripsInBuffer, stripOffsets );
00931          writeModeIsValid = false;
00932          numStripsInBuffer = 0;
00933          numVertsXferred = 0;
00934       }
00935 
00936    } // end strip loop
00937 }
00938 
00939 void
00940 CVsmManager::FinishBuffer( CVifSCDmaPacket &packet, CGeometryBlock &block,
00941                           int numVertsInBuffer, int vu1QuadsPerVert,
00942                           int numStripsInBuffer, unsigned short *stripOffsets )
00943 {
00944    // going to start a new buffer, so finish this one
00945    // header (giftag, etc..)
00946    XferBufferHeader( packet, block.GetPrimType(),
00947                      numVertsInBuffer,
00948                      numStripsInBuffer, stripOffsets );
00949 
00950    // render the buffer
00951    packet.Cnt(); {
00952       packet.Mscnt();
00953       packet.Nop();
00954    }
00955    packet.CloseTag();
00956 }
00957 
00958 void
00959 CVsmManager::FindNumBuffers( int numToAdd, int numVertsToRestart,
00960                             int numVertsAlreadyInFirstBuffer, int maxVertsPerBuffer,
00961                             int &numVertsFirstBuffer, int &numVertsLastBuffer,
00962                             int &numBuffers )
00963 {
00964    // find number of buffers (chunks that will fit into vu1 mem buffers/unpack)
00965 
00966    // deal with the first buffer
00967    int numLeftToAdd;
00968    int freeVertsFirstBuffer = maxVertsPerBuffer - numVertsAlreadyInFirstBuffer;
00969    if ( numToAdd <= freeVertsFirstBuffer ) {
00970       numVertsFirstBuffer = numToAdd;
00971       numLeftToAdd = 0;
00972    }
00973    else {
00974       // we only want even numbers of vertices in tri strips that are spilled
00975       // across buffer boundaries so that the sense of the backfacing calculation
00976       // remains correct in the next buffer
00977       numVertsFirstBuffer = freeVertsFirstBuffer - (int)Math::IsOdd(freeVertsFirstBuffer);
00978       numLeftToAdd = numToAdd - (numVertsFirstBuffer - numVertsToRestart);
00979    }
00980    // if this doesn't make sense, try drawing it..
00981    int adjVertsPerBuffer = maxVertsPerBuffer - numVertsToRestart;
00982    adjVertsPerBuffer -= (int)Math::IsOdd(adjVertsPerBuffer);
00983    numBuffers = 1 + numLeftToAdd / adjVertsPerBuffer; // 1 is first buffer
00984    if ( numLeftToAdd % adjVertsPerBuffer > numVertsToRestart ) numBuffers++;
00985 
00986    numVertsLastBuffer =
00987       (numBuffers > 1)
00988       ? numToAdd - ((numVertsFirstBuffer - numVertsToRestart)
00989                     + (numBuffers-2) * adjVertsPerBuffer)
00990       : numToAdd;
00991 }
00992 
00993 
00994 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00995 // You MUST set the vif1 write mode correctly before calling XferBlock!!
00996 // e.g., Stcycl(1, vu1QuadsPerVert)
00997 void
00998 CVsmManager::XferBlock( CVifSCDmaPacket &packet, CImmGeomManager &gmanager, GLenum primType,
00999                        void *vertices, void *normals, void *texCoords, void *colors,
01000                        int vu1Offset, int firstElement, int numToAdd )
01001 {
01002    //
01003    // vertices
01004    //
01005 
01006    mErrorIf( vertices == NULL, "Tried to render an array with no vertices!" );
01007    XferVectors( packet, (unsigned int *)vertices,
01008                 firstElement, numToAdd,
01009                 WordsPerVertex, VertexUnpackMask, VertexUnpackMode,
01010                 vu1Offset );
01011 
01012    //
01013    // normals
01014    //
01015 
01016    int firstNormal = firstElement;
01017    if ( normals == NULL ) {
01018       // no normals given, so use the current normal..
01019       // I hate to actually write every normal into the packet,
01020       // but I can't use the vif to expand the data because I
01021       // need it to interleave the vertices, normals, etc..
01022       CDmaPacket &normalBuf = gmanager.GetNormalBuf();
01023       normals = (void*)normalBuf.GetNextPtr();
01024       firstNormal = 0;
01025 
01026       cpu_vec_xyz curNormal = gmanager.GetCurNormal();
01027       for ( int i = 0; i < numToAdd; i++ )
01028          normalBuf += curNormal;
01029    }
01030 
01031    XferVectors( packet, (unsigned int*)normals,
01032                 firstNormal, numToAdd,
01033                 WordsPerNormal, NormalUnpackMask, NormalUnpackMode,
01034                 vu1Offset + 1 );
01035 
01036    //
01037    // tex coords
01038    //
01039 
01040    int firstTexCoord = firstElement;
01041    if ( TexEnabled && texCoords == NULL ) {
01042       // no tex coords given, so use the current value..
01043       // see note above for normals
01044       CDmaPacket &texCoordBuf = gmanager.GetTexCoordBuf();
01045       texCoords = (void*)texCoordBuf.GetNextPtr();
01046       firstTexCoord = 0;
01047 
01048       const float* curTexCoord = gmanager.GetCurTexCoord();
01049       for ( int i = 0; i < numToAdd; i++ ) {
01050          texCoordBuf    += curTexCoord[0];
01051          texCoordBuf    += curTexCoord[1];
01052       }
01053    }
01054    if ( TexEnabled )
01055       XferVectors( packet, (unsigned int*)texCoords,
01056                    firstTexCoord, numToAdd,
01057                    WordsPerTexCoord, TexCoordUnpackMask, TexCoordUnpackMode,
01058                    vu1Offset + 2 );
01059 
01060    //
01061    // colors
01062    //
01063 
01064    int firstColor = firstElement;
01065    if ( colors != NULL && ColorMaterialEnabled ) {
01066       XferVectors( packet, (unsigned int*)colors,
01067                    firstColor, numToAdd,
01068                    WordsPerColor, ColorUnpackMask, ColorUnpackMode,
01069                    vu1Offset + 3 );
01070    }
01071 
01072 }
01073 

ps2gl version 0.2