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

base_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 <stdlib.h>
00012 
00013 #include "ps2gl/base_renderer.h"
00014 #include "ps2gl/glcontext.h"
00015 #include "ps2gl/metrics.h"
00016 #include "ps2gl/immgmanager.h"
00017 #include "ps2gl/lighting.h"
00018 #include "ps2gl/material.h"
00019 #include "ps2gl/matrix.h"
00020 #include "ps2gl/texture.h"
00021 #include "ps2gl/drawcontext.h"
00022 
00023 #include "vu1_context.h"
00024 
00025 void
00026 CBaseRenderer::GetUnpackAttribs( int numWords, unsigned int &mode, Vifs::tMask &mask )
00027 {
00028 
00029    if ( numWords == 3 ) {
00030       Vifs::tMask vec3Mask = { 0, 0, 0, 1,
00031                                0, 0, 0, 1,
00032                                0, 0, 0, 1,
00033                                0, 0, 0, 1 };
00034       mode = Vifs::UnpackModes::v3_32;
00035       mask = vec3Mask;
00036    }
00037    else if ( numWords == 4 ) {
00038       Vifs::tMask vec4Mask = { 0, 0, 0, 0,
00039                                0, 0, 0, 0,
00040                                0, 0, 0, 0,
00041                                0, 0, 0, 0 };
00042       mode = Vifs::UnpackModes::v4_32;
00043       mask = vec4Mask;
00044    }
00045    else if ( numWords == 2 ) {
00046       Vifs::tMask vec2Mask = { 0, 0, 1, 1,
00047                                0, 0, 1, 1,
00048                                0, 0, 1, 1,
00049                                0, 0, 1, 1 };
00050       mode = Vifs::UnpackModes::v2_32;
00051       mask = vec2Mask;
00052    }
00053    else {
00054       mError("shouldn't get here (you're probably calling glDrawArrays"
00055          "without setting one of the pointers)");
00056    }
00057 }
00058 
00064 void
00065 CBaseRenderer::InitXferBlock( CVifSCDmaPacket &packet,
00066                               int wordsPerVertex, int wordsPerNormal,
00067                               int wordsPerTex, int wordsPerColor )
00068 {
00069    CImmGeomManager &gmanager = pGLContext->GetImmGeomManager();
00070 
00071    NormalBuf = & gmanager.GetNormalBuf();
00072    TexCoordBuf = & gmanager.GetTexCoordBuf();
00073 
00074    CurNormal = gmanager.GetCurNormal();
00075    const float* texCoord = gmanager.GetCurTexCoord();
00076    CurTexCoord[0] = texCoord[0];
00077    CurTexCoord[1] = texCoord[1];
00078 
00079    // get unpack modes/masks
00080 
00081    WordsPerVertex = wordsPerVertex;
00082    GetUnpackAttribs( WordsPerVertex, VertexUnpackMode, VertexUnpackMask );
00083 
00084    WordsPerNormal = (wordsPerNormal > 0) ? wordsPerNormal : 3;
00085    GetUnpackAttribs( WordsPerNormal, NormalUnpackMode, NormalUnpackMask );
00086 
00087    WordsPerTexCoord = (wordsPerTex > 0) ? wordsPerTex : 2;
00088    GetUnpackAttribs( WordsPerTexCoord, TexCoordUnpackMode, TexCoordUnpackMask );
00089 
00090    WordsPerColor = (wordsPerColor > 0) ? wordsPerColor : 3;
00091    GetUnpackAttribs( WordsPerColor, ColorUnpackMode, ColorUnpackMask );
00092 
00093    // set up the row register to expand vectors with fewer than 4 elements
00094 
00095    packet.Cnt();
00096    {
00097      // w is 256 to remind me that this is not used as the vertex w but
00098      // is necessary to clear any adc bits set for strips, otherwise they
00099      // accumulate..
00100       static const float row[4] = { 0.0f, 0.0f, 1.0f, 256.0f };
00101       packet.Strow( row );
00102 
00103       packet.Pad128();
00104    }
00105    packet.CloseTag();
00106 }
00107 
00108 
00120 void
00121 CBaseRenderer::XferBlock( CVifSCDmaPacket &packet,
00122                           const void *vertices, const void *normals,
00123                           const void *texCoords, const void *colors,
00124                           int vu1Offset, int firstElement, int numToAdd )
00125 {
00126    //
00127    // vertices
00128    //
00129 
00130    if ( XferVertices ) {
00131       mErrorIf( vertices == NULL, "Tried to render an array with no vertices!" );
00132       XferVectors( packet, (unsigned int *)vertices,
00133                    firstElement, numToAdd,
00134                    WordsPerVertex, VertexUnpackMask, VertexUnpackMode,
00135                    vu1Offset );
00136    }
00137 
00138    //
00139    // normals
00140    //
00141 
00142    int firstNormal = firstElement;
00143    if ( XferNormals && normals == NULL ) {
00144       // no normals given, so use the current normal..
00145       // I hate to actually write every normal into the packet,
00146       // but I can't use the vif to expand the data because I
00147       // need it to interleave the vertices, normals, etc..
00148       CDmaPacket &normalBuf = *NormalBuf;
00149       normals = (void*)normalBuf.GetNextPtr();
00150       firstNormal = 0;
00151 
00152       for ( int i = 0; i < numToAdd; i++ )
00153          normalBuf += CurNormal;
00154    }
00155 
00156    if ( XferNormals )
00157       XferVectors( packet, (unsigned int*)normals,
00158                    firstNormal, numToAdd,
00159                    WordsPerNormal, NormalUnpackMask, NormalUnpackMode,
00160                    vu1Offset + 1 );
00161 
00162    //
00163    // tex coords
00164    //
00165 
00166    int firstTexCoord = firstElement;
00167    if ( XferTexCoords && texCoords == NULL ) {
00168       // no tex coords given, so use the current value..
00169       // see note above for normals
00170       CDmaPacket &texCoordBuf = *TexCoordBuf;
00171       texCoords = (void*)texCoordBuf.GetNextPtr();
00172       firstTexCoord = 0;
00173 
00174       for ( int i = 0; i < numToAdd; i++ ) {
00175          texCoordBuf += CurTexCoord[0];
00176          texCoordBuf += CurTexCoord[1];
00177       }
00178    }
00179    if ( XferTexCoords )
00180       XferVectors( packet, (unsigned int*)texCoords,
00181                    firstTexCoord, numToAdd,
00182                    WordsPerTexCoord, TexCoordUnpackMask, TexCoordUnpackMode,
00183                    vu1Offset + 2 );
00184 
00185    //
00186    // colors
00187    //
00188 
00189    int firstColor = firstElement;
00190    if ( colors != NULL && XferColors ) {
00191       XferVectors( packet, (unsigned int*)colors,
00192                    firstColor, numToAdd,
00193                    WordsPerColor, ColorUnpackMask, ColorUnpackMode,
00194                    vu1Offset + 3 );
00195    }
00196 
00197 }
00198 
00199 #define kContextStart 0 // for the kLightBase stuff below
00200 
00201 void
00202 CBaseRenderer::AddVu1RendererContext( CVifSCDmaPacket &packet, GLenum primType, int vu1Offset )
00203 {
00204    CGLContext &glContext = *pGLContext;
00205 
00206    packet.Stcycl(1,1);
00207    packet.Flush();
00208    packet.Pad96();
00209    packet.OpenUnpack( Vifs::UnpackModes::v4_32, vu1Offset, Packet::kSingleBuff );
00210    {
00211       // find light pointers
00212       CImmLighting &lighting = glContext.GetImmLighting();
00213       tLightPtrs lightPtrs[8];
00214       tLightPtrs *nextDir, *nextPt, *nextSpot;
00215       nextDir = nextPt = nextSpot = &lightPtrs[0];
00216       int numDirs, numPts, numSpots;
00217       numDirs = numPts = numSpots = 0;
00218       for ( int i = 0; i < 8; i++ ) {
00219          CImmLight& light = lighting.GetImmLight(i);
00220          if ( light.IsEnabled() ) {
00221             int lightBase = kLight0Base + vu1Offset;
00222             if ( light.IsDirectional() ) {
00223                nextDir->dir = lightBase + i * kLightStructSize;
00224                nextDir++;
00225                numDirs++;
00226             }
00227             else if ( light.IsPoint() ) {
00228                nextPt->point = lightBase + i * kLightStructSize;
00229                nextPt++;
00230                numPts++;
00231             }
00232             else if ( light.IsSpot() ) {
00233                nextSpot->spot = lightBase + i * kLightStructSize;
00234                nextSpot++;
00235                numSpots++;
00236             }
00237          }
00238       }  
00239 
00240       bool doLighting = glContext.GetImmLighting().GetLightingEnabled();
00241 
00242       // transpose of object to world space xfrm (for light directions)
00243       cpu_mat_44 objToWorldXfrmTrans = glContext.GetModelViewStack().GetTop();
00244       // clear any translations.. should be doing a 3x3 transpose..
00245       objToWorldXfrmTrans.set_col3( cpu_vec_xyzw(0, 0, 0, 1) );
00246       objToWorldXfrmTrans = objToWorldXfrmTrans.transpose();
00247       // do we need to rescale normals?
00248       cpu_mat_44 normalRescale;
00249       normalRescale.set_identity();
00250       float normalScale = 1.0f;
00251       CImmDrawContext &drawContext = glContext.GetImmDrawContext();
00252       if ( drawContext.GetRescaleNormals() ) {
00253          cpu_vec_xyzw fake_normal( 1, 0, 0, 0 );
00254          fake_normal = objToWorldXfrmTrans * fake_normal;
00255          normalScale = 1.0f / fake_normal.length();
00256          normalRescale.set_scale( cpu_vec_xyz(normalScale, normalScale, normalScale) );
00257       }
00258       objToWorldXfrmTrans = normalRescale * objToWorldXfrmTrans;
00259 
00260       // num lights
00261       if ( doLighting ) {
00262          packet += numDirs;
00263          packet += numPts;
00264          packet += numSpots;
00265       }
00266       else {
00267          packet += (tU64)0;
00268          packet += 0;
00269       }
00270 
00271       // backface culling multiplier -- this is 1.0f or -1.0f, the 6th bit
00272       // also turns on/off culling
00273       float bfc_mult = (float)drawContext.GetCullFaceDir();
00274       unsigned int bfc_word;
00275       asm( " ## nop ## " : "=r" (bfc_word) : "0" (bfc_mult) );
00276       bool do_culling = drawContext.GetDoCullFace() && (primType > GL_LINE_STRIP);
00277       packet += bfc_word | (unsigned int)do_culling << 5;
00278 
00279       // light pointers
00280       packet.Add( &lightPtrs[0], 8 );
00281          
00282       float maxColorValue = GetMaxColorValue( glContext.GetTexManager().GetTexEnabled() );
00283 
00284       // add light info
00285       for ( int i = 0; i < 8; i++ ) {
00286          CImmLight& light = lighting.GetImmLight(i);
00287          packet += light.GetAmbient() * maxColorValue;
00288          packet += light.GetDiffuse() * maxColorValue;
00289          packet += light.GetSpecular() * maxColorValue;
00290 
00291          if ( light.IsDirectional() )
00292             packet += light.GetPosition();
00293          else {
00294             packet += light.GetPosition();
00295          }
00296 
00297          packet += light.GetSpotDir();
00298 
00299          // attenuation coeffs for positional light sources
00300          // because we're doing lighting calculations in object space,
00301          // we need to adjust the attenuation of positional light sources
00302          // and all lighting directions to take into account scaling
00303          packet += light.GetConstantAtten();
00304          packet += light.GetLinearAtten() * 1.0f/normalScale;
00305          packet += light.GetQuadAtten() * 1.0f/normalScale;
00306          packet += 0; // padding
00307 
00308       }
00309 
00310       // global ambient
00311       cpu_vec_4 globalAmb;
00312       if ( doLighting )
00313          globalAmb = lighting.GetGlobalAmbient() * maxColorValue;
00314       else
00315          globalAmb = cpu_vec_4(0, 0, 0, 0);
00316       packet.Add( (tU32*)&globalAmb, 3 );
00317 
00318       // stick in the offset to convert clip space depth value to GS
00319       float depthClipToGs = (float)((1 << drawContext.GetDepthBits()) - 1)/2.0f;
00320       packet += depthClipToGs;
00321 
00322       // cur material
00323 
00324       CImmMaterial& material = glContext.GetMaterialManager().GetImmMaterial();
00325 
00326       // add emissive component
00327       cpu_vec_4 emission;
00328       if ( doLighting )
00329          emission = material.GetEmission() * maxColorValue;
00330       else
00331          emission = glContext.GetMaterialManager().GetCurColor() * maxColorValue;
00332       packet += emission;
00333 
00334       // ambient
00335       packet += material.GetAmbient();
00336 
00337       // diffuse
00338       cpu_vec_4 matDiffuse = material.GetDiffuse();
00339       // the alpha value is set to the alpha of the diffuse in the renderers;
00340       // this should be the current color alpha if lighting is disabled
00341       if ( ! doLighting )
00342          matDiffuse[3] = glContext.GetMaterialManager().GetCurColor()[3];
00343       packet += matDiffuse;
00344 
00345       // specular
00346       packet += material.GetSpecular();
00347 
00348       // vertex xform
00349       packet += drawContext.GetVertexXform();
00350 
00351       // fixed vertToEye vector for non-local specular
00352       cpu_vec_xyzw vertToEye( 0.0f, 0.0f, 1.0f, 0.0f );
00353       packet += objToWorldXfrmTrans * vertToEye;
00354 
00355       // transpose of object to world space transform
00356       packet += objToWorldXfrmTrans;
00357 
00358       // world to object space xfrm (for light positions)
00359       cpu_mat_44 worldToObjXfrm = glContext.GetModelViewStack().GetInvTop();
00360       packet += worldToObjXfrm;
00361 
00362       // giftag - this is down at the bottom to make sure that when switching
00363       // primitives the last buffer will have a chance to copy the giftag before
00364       // it is overwritten with the new one
00365       GLenum newPrimType = drawContext.GetPolygonMode();
00366       if (newPrimType == GL_FILL) newPrimType = primType;
00367       newPrimType &= 0xff;
00368       tGifTag giftag = BuildGiftag( newPrimType );
00369       packet += giftag;
00370 
00371       // add info used by clipping code
00372       // first the dimensions of the framebuffer
00373       float xClip = (float)2048.0f/(drawContext.GetFBWidth() * 0.5f * 2.0f);
00374       packet += Math::Max( xClip, 1.0f );
00375       float yClip = (float)2048.0f/(drawContext.GetFBHeight() * 0.5f * 2.0f);
00376       packet += Math::Max( yClip, 1.0f );
00377       float depthClip = 2048.0f / depthClipToGs;
00378       // FIXME: maybe these 2048's should be 2047.5s...
00379       depthClip *= 1.003f; // round up a bit for fp error (????)
00380       packet += depthClip;
00381       // enable/disable clipping
00382       packet += (drawContext.GetDoClipping()) ? 1 : 0;
00383    }
00384    packet.CloseUnpack();
00385 }
00386 
00387 tGifTag
00388 CBaseRenderer::BuildGiftag( GLenum primType )
00389 {
00390    CGLContext &glContext = *pGLContext;
00391 
00392    primType &= 0x7;  // convert from GL #define to gs prim number
00393    CImmDrawContext &drawContext = glContext.GetImmDrawContext();
00394    bool smoothShading = drawContext.GetDoSmoothShading();
00395    bool useTexture = glContext.GetTexManager().GetTexEnabled();
00396    bool alpha = drawContext.GetBlendEnabled();
00397    unsigned int nreg = OutputQuadsPerVert;
00398 
00399    GS::tPrim prim = { PRIM: primType, IIP: smoothShading, TME: useTexture,
00400                       FGE: 0, ABE: alpha, AA1: 0, FST: 0, CTXT: 0, FIX: 0 };
00401    tGifTag giftag = { NLOOP: 0, EOP: 1, pad0: 0, id: 0, PRE: 1,
00402                         PRIM: *(tU64*)&prim, FLG: 0, NREG: nreg, REGS0: 2, REGS1: 1,
00403                         REGS2: 4 };
00404    return giftag;
00405 }
00406 
00407 void
00408 CBaseRenderer::CacheRendererState()
00409 {
00410    XferNormals = pGLContext->GetImmLighting().GetLightingEnabled();
00411    XferTexCoords = pGLContext->GetTexManager().GetTexEnabled();
00412    XferColors = pGLContext->GetMaterialManager().GetColorMaterialEnabled();
00413 }
00414 
00415 void
00416 CBaseRenderer::Load()
00417 {
00418    mErrorIf( *(unsigned short*)MicrocodePacket > 1024,
00419              "This vu1 renderer won't fit into vu1 code memory: 0x%08x",
00420              (unsigned int)Capabilities );
00421    CVifSCDmaPacket &packet = pGLContext->GetVif1Packet();
00422 
00423    packet.Call( MicrocodePacket );
00424    packet.Pad128();
00425    packet.CloseTag();
00426 
00427    pglAddToMetric(kMetricsRendererUpload);
00428 }
00429 
00430 void
00431 CBaseRenderer::XferVectors( CVifSCDmaPacket &packet, unsigned int *dataStart,
00432                          int startOffset, int numVectors, int wordsPerVec,
00433                          Vifs::tMask unpackMask, tU32 unpackMode,
00434                          int vu1MemOffset )
00435 {
00436    // find number of words to prepend with a cnt
00437 
00438    unsigned int *vecDataStart = dataStart + startOffset * wordsPerVec;
00439    unsigned int *vecDataEnd = vecDataStart + numVectors * wordsPerVec;
00440 
00441    mAssert( numVectors > 0 );
00442    mErrorIf( (unsigned int)vecDataStart & 4-1,
00443              "XferVectors only works with word-aligned data" );
00444 
00445    int numWordsToPrepend = 0;
00446    unsigned int *refXferStart = vecDataStart;
00447    while ( (unsigned int)refXferStart & (16-1) ) {
00448       numWordsToPrepend++;
00449       refXferStart++;
00450       if ( refXferStart == vecDataEnd ) break;
00451    }
00452    int numWordsToAppend = 0;
00453    unsigned int *refXferEnd = vecDataEnd;
00454    while ( ((unsigned int)refXferEnd & (16-1)) && refXferEnd > refXferStart ) {
00455       numWordsToAppend++;
00456       refXferEnd--;
00457    }
00458    int numQuadsInRefXfer = ((unsigned int)refXferEnd - (unsigned int)refXferStart) / 16;
00459 
00460    packet.Cnt();
00461    {
00462       // set mask to expand vectors appropriately
00463       packet.Stmask( unpackMask );
00464 
00465       // prepend
00466       if ( numWordsToPrepend > 1 ) {
00467          // either 2 or 3 words to prepend
00468          packet.Nop().Nop();
00469          if ( numWordsToPrepend == 2 )
00470             packet.Nop();
00471          
00472          packet.OpenUnpack( unpackMode,
00473                             vu1MemOffset,
00474                             VifDoubleBuffered,
00475                             Packet::kMasked );
00476          packet.CloseUnpack( numVectors );
00477 
00478          if ( numWordsToPrepend == 3 )
00479             packet += *vecDataStart;
00480       }
00481 
00482       packet.Pad128();
00483    }
00484    packet.CloseTag();
00485 
00486    // xfer qword block of vectors
00487    packet.Ref( Core::MakePtrNormal(refXferStart), numQuadsInRefXfer );
00488    {
00489       // either 0 words to prepend or 1 word left to prepend
00490       if ( numWordsToPrepend == 0 )
00491          packet.Nop();
00492       if ( numWordsToPrepend <= 1 ) {
00493          packet.OpenUnpack( unpackMode,
00494                             vu1MemOffset,
00495                             VifDoubleBuffered,
00496                             Packet::kMasked );
00497          packet.CloseUnpack( numVectors );
00498       }
00499       if ( numWordsToPrepend == 1 )
00500          packet += *vecDataStart;
00501       else if ( numWordsToPrepend == 2 )
00502          packet.Add( vecDataStart, 2 );
00503       else if ( numWordsToPrepend == 3 )
00504          packet.Add( &vecDataStart[1], 2 );
00505    }
00506 
00507    // xfer any remaining vectors
00508    if ( numWordsToAppend > 0 ) {
00509       packet.Cnt();
00510       {
00511          packet.Add( refXferEnd, numWordsToAppend );
00512          packet.Pad128();
00513       }
00514       packet.CloseTag();
00515    }
00516 }
00517 

ps2gl version cvs