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

linear_renderer.cpp

Go to the documentation of this file.
00001 /*        Copyright (C) 2000,2001,2002  Sony Computer Entertainment America
00002           
00003           This file is subject to the terms and conditions of the GNU Lesser
00004           General Public License Version 2.1. See the file "COPYING" in the
00005           main directory of this archive for more details.                             */
00006 
00007 #include "ps2s/packet.h"
00008 #include "ps2s/math.h"
00009 #include "ps2s/cpu_matrix.h"
00010 
00011 #include "ps2gl/linear_renderer.h"
00012 #include "ps2gl/glcontext.h"
00013 #include "ps2gl/metrics.h"
00014 #include "ps2gl/immgmanager.h"
00015 #include "ps2gl/lighting.h"
00016 #include "ps2gl/material.h"
00017 #include "ps2gl/matrix.h"
00018 #include "ps2gl/texture.h"
00019 #include "ps2gl/drawcontext.h"
00020 
00021 #include "vu1_mem_linear.h"
00022 
00023 void
00024 CLinearRenderer::DrawLinearArrays( CGeometryBlock &block )
00025 {
00026    int wordsPerVert = block.GetWordsPerVertex();
00027    int wordsPerNormal = (block.GetNormalsAreValid()) ? block.GetWordsPerNormal() : 0;
00028    int wordsPerTex = (block.GetTexCoordsAreValid()) ? block.GetWordsPerTexCoord() : 0;
00029    int wordsPerColor = (block.GetColorsAreValid()) ? block.GetWordsPerColor() : 0;
00030 
00031    CVifSCDmaPacket &packet = pGLContext->GetVif1Packet();
00032    InitXferBlock( packet, wordsPerVert, wordsPerNormal, wordsPerTex, wordsPerColor );
00033    
00034    // get max number of vertices per vu1 buffer
00035 
00036    // let's assume separate unpacks for vertices, normals, tex uvs..
00037    int maxUnpackVerts = 256;
00038    // max number of vertex data in vu1 memory
00039    int vu1QuadsPerVert = InputQuadsPerVert;
00040    int inputBufSize = InputGeomBufSize;
00041    int maxVu1VertsPerBuffer = inputBufSize / vu1QuadsPerVert;
00042    // max vertices per buffer
00043    int maxVertsPerBuffer = Math::Min( maxUnpackVerts, maxVu1VertsPerBuffer );
00044    maxVertsPerBuffer -= 3;
00045    // make sure we don't end in the middle of a polygon
00046    maxVertsPerBuffer -= maxVertsPerBuffer % block.GetNumVertsPerPrim();
00047 
00048    // draw
00049 
00050    DrawBlock( packet, block, maxVertsPerBuffer );
00051 }
00052 
00053 void
00054 CLinearRenderer::InitContext( GLenum primType, tU32 rcChanges, bool userRcChanged )
00055 {
00056    CGLContext &glContext = *pGLContext;
00057    CVifSCDmaPacket &packet = glContext.GetVif1Packet();
00058 
00059    packet.Cnt();
00060    {
00061       AddVu1RendererContext( packet, primType, kContextStart );
00062 
00063       packet.Mscal(0);
00064       packet.Flushe();
00065 
00066       packet.Base( kDoubleBufBase );
00067       packet.Offset( kDoubleBufOffset );
00068    }
00069    packet.CloseTag();
00070 
00071    CacheRendererState();
00072 }
00073 
00074 int
00075 CLinearRenderer::GetPacketQwordSize( const CGeometryBlock &geometry )
00076 {
00077    // FIXME:  this is a pitiful hack for allocating enough memory
00078    return Math::Max(geometry.GetTotalVertices() / 70, 1) * 1000;
00079 }
00080 
00081 CRendererProps
00082 CLinearRenderer::GetRenderContextDeps()
00083 {
00084    CRendererProps deps;
00085    deps = (tU64)0;
00086    deps.Lighting = 1;
00087    deps.Texture = 1;
00088    deps.PerVtxMaterial = 1;
00089    
00090    return deps;
00091 }
00092 
00093 bool
00094 CLinearRenderer::GetCachePackets( const CGeometryBlock &geometry )
00095 {
00096    return !( pGLContext->GetImmLighting().GetLightingEnabled()
00097              && ! geometry.GetNormalsAreValid() );
00098 }
00099 
00100 void
00101 CLinearRenderer::DrawBlock( CVifSCDmaPacket &packet,
00102                             CGeometryBlock &block, int maxVertsPerBuffer )
00103 {
00104    mErrorIf( block.GetWordsPerVertex() == 2, "2 word vertices not supported" );
00105 
00106    // interleave the vertices, normals, tex coords, and colors using
00107    // "skipping write" vif mode on each block of data
00108    // (clobbered in XferBufferHeader())
00109    packet.Cnt();
00110    {
00111       packet.Stcycl(1, InputQuadsPerVert);
00112       packet.Pad128();
00113    }
00114    packet.CloseTag();
00115 
00116    // return;
00117 
00118    //
00119    // loop over the strips in this geometry block
00120    //
00121 
00122    int numVertsToRestart = block.GetNumVertsToRestartStrip();
00123    bool stripsCanBeMerged = block.GetStripsCanBeMerged();
00124 
00125    int numVertsXferred = 0;
00126    int numStripsInBuffer = 0;
00127    unsigned short stripOffsets[16];
00128    bool haveContinued = false;
00129    const void *normals, *vertices, *texCoords, *colors;
00130    normals = vertices = texCoords = colors = NULL;
00131    int vu1BufferOffset = 0, stripIndex = 0, vertsInBlock = 0;
00132    // keep number of verts transferred in each full buffer in sync with
00133    // FindNumBuffers() below
00134    int adjMaxVertsPerBuffer =
00135       maxVertsPerBuffer - (Math::IsOdd(maxVertsPerBuffer - numVertsToRestart));
00136    for ( int curStrip = 0; curStrip < block.GetNumStrips(); curStrip++ ) {
00137 
00138       // find the number of vu1 buffers this strip will take
00139       int numVertsFirstBuffer, numVertsLastBuffer, numBuffers;
00140       FindNumBuffers( block.GetStripLength(curStrip),
00141                       numVertsToRestart, numVertsXferred, maxVertsPerBuffer,
00142                       numVertsFirstBuffer, numVertsLastBuffer, numBuffers );
00143 
00144       //
00145       // loop over the buffers this strip will fill (usually one)
00146       //
00147 
00148       int numVertsThisBuffer;
00149       int indexIntoStrip = 0;
00150       int vu1QuadsPerVert = InputQuadsPerVert;
00151       for ( int curBuffer = 0;
00152             curBuffer < numBuffers;
00153             curBuffer++, indexIntoStrip += numVertsThisBuffer - numVertsToRestart ) {
00154 
00155          // how many verts in this vu1 buffer?
00156          if ( curBuffer == 0 )
00157             numVertsThisBuffer = numVertsFirstBuffer;
00158          else if ( curBuffer == numBuffers - 1 )
00159             numVertsThisBuffer = numVertsLastBuffer;
00160          else
00161             numVertsThisBuffer = adjMaxVertsPerBuffer;
00162 
00163          // xfer the list of primitives
00164 
00165          if ( ! haveContinued ) {
00166             vertices = (block.GetVerticesAreValid()) ? block.GetVertices(curStrip) : NULL;
00167             normals = (block.GetNormalsAreValid()) ? block.GetNormals(curStrip) : NULL;
00168             texCoords = (block.GetTexCoordsAreValid()) ? block.GetTexCoords(curStrip) : NULL;
00169             colors = (block.GetColorsAreValid()) ? block.GetColors(curStrip) : NULL;
00170             vu1BufferOffset = InputGeomOffset + numVertsXferred * vu1QuadsPerVert;
00171             stripIndex = indexIntoStrip;
00172             vertsInBlock = 0;
00173          }
00174 
00175          // we only want to transfer the geometry data if:
00176          //   - the next strip is not adjacent in memory to this one (indicated by
00177          //     CGeometryBlock::StripIsContinued) and so cannot be combined into
00178          //     one transfer
00179          //   - this strip spills over into the next buffer (so it must be split
00180          //     into more than one transfer)
00181          if ( ! block.StripIsContinued(curStrip)
00182               || curBuffer < numBuffers - 1 ) {
00183             XferBlock( packet,
00184                        vertices, normals, texCoords, colors,
00185                        vu1BufferOffset,
00186                        stripIndex, vertsInBlock + numVertsThisBuffer );
00187             haveContinued = false;
00188          }
00189          else {
00190             vertsInBlock += numVertsThisBuffer;
00191             haveContinued = true;
00192          }
00193 
00194          stripOffsets[numStripsInBuffer++] = numVertsXferred;
00195          mErrorIf( numStripsInBuffer > 16, "Too many strips in buffer.. this shouldn't happen" );
00196          numVertsXferred += numVertsThisBuffer;
00197 
00198          // if there are more buffers in this strip, render this buffer
00199          if ( curBuffer < numBuffers - 1 ) {
00200             FinishBuffer( packet, numVertsToRestart, numVertsXferred, vu1QuadsPerVert,
00201                           numStripsInBuffer, stripOffsets );
00202             numStripsInBuffer = 0;
00203             numVertsXferred = 0;
00204          }
00205 
00206       } // end buffer loop
00207 
00208       // finish this buffer if:
00209       //   - strips of this prim type cannot be merged into a single buffer/giftag
00210       //   - there is too little free space left
00211       //   - we have filled the max number of strips per buffer
00212       //   - or this is the last strip
00213 
00214       // test against 'numVertsToRestart + 1' because FindNumBuffers() might
00215       // clip off one vert for backface culling
00216       // (maybe this should be 'adjMaxVertsPerBuffer'?)
00217       if ( ! stripsCanBeMerged
00218            || ( (maxVertsPerBuffer - numVertsXferred) <= numVertsToRestart + 1 )
00219            || numStripsInBuffer == 16
00220            || (curStrip == block.GetNumStrips() - 1) ) {
00221          if ( haveContinued ) {
00222             XferBlock( packet,
00223                        vertices, normals, texCoords, colors,
00224                        vu1BufferOffset,
00225                        stripIndex, vertsInBlock );
00226             haveContinued = false;
00227          }
00228 
00229          FinishBuffer( packet, numVertsToRestart, numVertsXferred, vu1QuadsPerVert,
00230                        numStripsInBuffer, stripOffsets );
00231          numStripsInBuffer = 0;
00232          numVertsXferred = 0;
00233       }
00234 
00235    } // end strip loop
00236 }
00237 
00238 void
00239 CLinearRenderer::FinishBuffer( CVifSCDmaPacket &packet, int numVertsToBreakStrip,
00240                                int numVertsInBuffer, int vu1QuadsPerVert,
00241                                int numStripsInBuffer, unsigned short *stripOffsets )
00242 {
00243    packet.Cnt();
00244    {
00245       // going to start a new buffer, so finish this one
00246       // header (giftag, etc..)
00247       XferBufferHeader( packet, numVertsToBreakStrip,
00248                         numVertsInBuffer,
00249                         numStripsInBuffer, stripOffsets );
00250 
00251       packet.Mscnt();
00252       packet.Pad128();
00253    }
00254    packet.CloseTag();
00255 }
00256 
00257 void
00258 CLinearRenderer::FindNumBuffers( int numToAdd, int numVertsToRestart,
00259                                  int numVertsAlreadyInFirstBuffer, int maxVertsPerBuffer,
00260                                  int &numVertsFirstBuffer, int &numVertsLastBuffer,
00261                                  int &numBuffers )
00262 {
00263    // find number of buffers (chunks that will fit into vu1 mem buffers/unpack)
00264 
00265    // deal with the first buffer
00266    int numLeftToAdd;
00267    int freeVertsFirstBuffer = maxVertsPerBuffer - numVertsAlreadyInFirstBuffer;
00268    if ( numToAdd <= freeVertsFirstBuffer ) {
00269       numVertsFirstBuffer = numToAdd;
00270       numLeftToAdd = 0;
00271    }
00272    else {
00273       // we only want even numbers of vertices in tri strips that are spilled
00274       // across buffer boundaries so that the sense of the backfacing calculation
00275       // remains correct in the next buffer
00276       numVertsFirstBuffer = freeVertsFirstBuffer - (int)Math::IsOdd(freeVertsFirstBuffer);
00277       numLeftToAdd = numToAdd - (numVertsFirstBuffer - numVertsToRestart);
00278    }
00279    // if this doesn't make sense, try drawing it..
00280    int adjVertsPerBuffer = maxVertsPerBuffer - numVertsToRestart;
00281    adjVertsPerBuffer -= (int)Math::IsOdd(adjVertsPerBuffer);
00282    numBuffers = 1 + numLeftToAdd / adjVertsPerBuffer; // 1 is first buffer
00283    if ( numLeftToAdd % adjVertsPerBuffer > numVertsToRestart ) numBuffers++;
00284 
00285    numVertsLastBuffer =
00286       (numBuffers > 1)
00287       ? numToAdd - ((numVertsFirstBuffer - numVertsToRestart)
00288                     + (numBuffers-2) * adjVertsPerBuffer)
00289       : numToAdd;
00290 }
00291 
00292 void
00293 CLinearRenderer::XferBufferHeader( CVifSCDmaPacket& packet,
00294                                    int numVertsToBreakStrip,
00295                                    int numVerts,
00296                                    int numStripsInBuffer, unsigned short *stripOffsets )
00297 {
00298    int vu1OutQuadsPerVert = OutputQuadsPerVert;
00299 
00300    // xfer header info for strip
00301    packet.Stcycl(4,4);
00302    packet.OpenUnpack( Vifs::UnpackModes::v4_32, 0, Packet::kDoubleBuff );
00303    {
00304       // num vertices
00305       packet += numVerts;
00306       packet += 0; packet += (tU64)0;
00307 
00308       // adc bits for the beginning of strips.. 16 24-bit values of following format:
00309       //   bits 0-9     : offset into output geometry (not including giftag)
00310       //   bit 10       : stop bit
00311       //   bit 11       : ADC bit of second vertex starting at offset
00312       // these are converted to floats to do a right shift with a fp add on vu1
00313       unsigned int adcBits = 0;
00314       if ( numVertsToBreakStrip == 0 )
00315          numStripsInBuffer = 0;
00316       else if ( numVertsToBreakStrip == 2 )
00317          adcBits = 0x800;
00318          
00319       float adc;
00320       unsigned int stopBit = 0x400;
00321       for ( int i = 0; i < 16; i++ ) {
00322          if ( i < numStripsInBuffer )
00323             adc = (float)(adcBits |
00324                           (unsigned int)stripOffsets[i] * vu1OutQuadsPerVert );
00325          else if ( i == numStripsInBuffer )
00326             adc = (float)stopBit;
00327          else
00328             adc = (float)0;
00329          packet += adc;
00330       }
00331    }
00332    packet.CloseUnpack();
00333 
00334    // restore the write cycle
00335    packet.Stcycl(1, InputQuadsPerVert);
00336 }
00337 
00338 

ps2gl version cvs