00001
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
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
00094
00095 packet.Cnt();
00096 {
00097
00098
00099
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
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
00140
00141
00142 int firstNormal = firstElement;
00143 if ( XferNormals && normals == NULL ) {
00144
00145
00146
00147
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
00164
00165
00166 int firstTexCoord = firstElement;
00167 if ( XferTexCoords && texCoords == NULL ) {
00168
00169
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
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
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
00243 cpu_mat_44 objToWorldXfrmTrans = glContext.GetModelViewStack().GetTop();
00244
00245 objToWorldXfrmTrans.set_col3( cpu_vec_xyzw(0, 0, 0, 1) );
00246 objToWorldXfrmTrans = objToWorldXfrmTrans.transpose();
00247
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
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
00272
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
00280 packet.Add( &lightPtrs[0], 8 );
00281
00282 float maxColorValue = GetMaxColorValue( glContext.GetTexManager().GetTexEnabled() );
00283
00284
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
00300
00301
00302
00303 packet += light.GetConstantAtten();
00304 packet += light.GetLinearAtten() * 1.0f/normalScale;
00305 packet += light.GetQuadAtten() * 1.0f/normalScale;
00306 packet += 0;
00307
00308 }
00309
00310
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
00319 float depthClipToGs = (float)((1 << drawContext.GetDepthBits()) - 1)/2.0f;
00320 packet += depthClipToGs;
00321
00322
00323
00324 CImmMaterial& material = glContext.GetMaterialManager().GetImmMaterial();
00325
00326
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
00335 packet += material.GetAmbient();
00336
00337
00338 cpu_vec_4 matDiffuse = material.GetDiffuse();
00339
00340
00341 if ( ! doLighting )
00342 matDiffuse[3] = glContext.GetMaterialManager().GetCurColor()[3];
00343 packet += matDiffuse;
00344
00345
00346 packet += material.GetSpecular();
00347
00348
00349 packet += drawContext.GetVertexXform();
00350
00351
00352 cpu_vec_xyzw vertToEye( 0.0f, 0.0f, 1.0f, 0.0f );
00353 packet += objToWorldXfrmTrans * vertToEye;
00354
00355
00356 packet += objToWorldXfrmTrans;
00357
00358
00359 cpu_mat_44 worldToObjXfrm = glContext.GetModelViewStack().GetInvTop();
00360 packet += worldToObjXfrm;
00361
00362
00363
00364
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
00372
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
00379 depthClip *= 1.003f;
00380 packet += depthClip;
00381
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;
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
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
00463 packet.Stmask( unpackMask );
00464
00465
00466 if ( numWordsToPrepend > 1 ) {
00467
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
00487 packet.Ref( Core::MakePtrNormal(refXferStart), numQuadsInRefXfer );
00488 {
00489
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
00508 if ( numWordsToAppend > 0 ) {
00509 packet.Cnt();
00510 {
00511 packet.Add( refXferEnd, numWordsToAppend );
00512 packet.Pad128();
00513 }
00514 packet.CloseTag();
00515 }
00516 }
00517