00001
00002
00003
00004
00005 #include "ps2s/gsmem.h"
00006
00007 #include "GL/ps2gl.h"
00008
00009 #include "ps2gl/debug.h"
00010 #include "ps2gl/texture.h"
00011 #include "ps2gl/glcontext.h"
00012 #include "ps2gl/dlist.h"
00013 #include "ps2gl/immgmanager.h"
00014 #include "ps2gl/dlgmanager.h"
00015 #include "ps2gl/metrics.h"
00016
00017
00018
00019
00020
00021 CTexManager::CTexManager( CGLContext &context )
00022 : GLContext(context), IsTexEnabled(false), InsideDListDef(false),
00023 Cursor(0), LastTexSent(NULL),
00024 CurClut(NULL),
00025 TexMode(GS::TexMode::kModulate)
00026 {
00027
00028 for ( int i = 0; i < NumTexNames; i++ )
00029 TexNames[i] = NULL;
00030
00031
00032 DefaultTex = new CMMTexture( GS::kContext1 );
00033 CurTexture = DefaultTex;
00034 }
00035
00036 CTexManager::~CTexManager()
00037 {
00038 delete DefaultTex;
00039 if ( CurClut ) delete CurClut;
00040
00041 for ( int i = 0; i < NumTexNames; i++ ) {
00042 if (TexNames[i]) delete TexNames[i];
00043 }
00044 }
00045
00046 class CSetTexEnabledCmd : public CDListCmd {
00047 bool IsEnabled;
00048 public:
00049 CSetTexEnabledCmd( bool enabled ) : IsEnabled(enabled) {}
00050 CDListCmd* Play() {
00051 pGLContext->GetTexManager().SetTexEnabled(IsEnabled);
00052 return CDListCmd::GetNextCmd(this);
00053 }
00054 };
00055
00056 void
00057 CTexManager::SetTexEnabled( bool yesNo )
00058 {
00059 if (! InsideDListDef) {
00060 if ( IsTexEnabled != yesNo ) {
00061 GLContext.TexEnabledChanged();
00062 GLContext.GetImmGeomManager().GetVsmManager().TexEnabledChanged(yesNo);
00063 IsTexEnabled = yesNo;
00064 }
00065 }
00066 else {
00067 CDList &dlist = GLContext.GetDListManager().GetOpenDList();
00068 dlist += CSetTexEnabledCmd( yesNo );
00069 GLContext.TexEnabledChanged();
00070 }
00071 }
00072
00073 class CSetTexModeCmd : public CDListCmd {
00074 GS::tTexMode Mode;
00075 public:
00076 CSetTexModeCmd( GS::tTexMode mode ) : Mode(mode) {}
00077 CDListCmd* Play() {
00078 pGLContext->GetTexManager().SetTexMode(Mode);
00079 return CDListCmd::GetNextCmd(this);
00080 }
00081 };
00082
00083 void
00084 CTexManager::SetTexMode( GS::tTexMode mode )
00085 {
00086 if ( ! InsideDListDef )
00087 TexMode = mode;
00088 else {
00089 CDList &dlist = GLContext.GetDListManager().GetOpenDList();
00090 dlist += CSetTexModeCmd( mode );
00091 }
00092 }
00093
00094 void
00095 CTexManager::GenTextures( GLsizei numNewTexNames, GLuint *newTexNames )
00096 {
00097 for ( int curTexName = 0; curTexName < numNewTexNames; curTexName++ ) {
00098
00099 int i;
00100 for ( i = 0; i < NumTexNames; i++ ) {
00101
00102 if ( Cursor != 0 && TexNames[Cursor] == NULL ) break;
00103
00104 IncCursor();
00105 }
00106
00107 if ( i == NumTexNames ) {
00108 mError("No free texture names. Time to write a less braindead tex manager.");
00109
00110
00111 while(i < NumTexNames) {
00112 newTexNames[i] = 0;
00113 ++i;
00114 }
00115 } else {
00116 newTexNames[curTexName] = Cursor;
00117 IncCursor();
00118 }
00119 }
00120 }
00121
00122 void
00123 CTexManager::UseCurTexture( CVifSCDmaPacket &renderPacket )
00124 {
00125 if ( IsTexEnabled ) {
00126 GS::tPSM psm = CurTexture->GetPSM();
00127
00128 if ( psm == GS::kPsm8 || psm == GS::kPsm8h ) {
00129 mErrorIf( CurClut == NULL,
00130 "Trying to use an indexed-color texture with no color table given!" );
00131 CurClut->Load( renderPacket );
00132 }
00133
00134 CurTexture->SetTexMode( TexMode );
00135 if ( CurTexture->GetPSM() == GS::kPsm8
00136 || CurTexture->GetPSM() == GS::kPsm8h )
00137 CurTexture->SetClut( *CurClut );
00138 CurTexture->Use( renderPacket );
00139 }
00140 }
00141
00142 class CBindTextureCmd : public CDListCmd {
00143 unsigned int TexName;
00144 public:
00145 CBindTextureCmd( unsigned int name ) : TexName(name) {}
00146 CDListCmd* Play() {
00147 pGLContext->GetTexManager().BindTexture(TexName);
00148 return CDListCmd::GetNextCmd(this);
00149 }
00150 };
00151
00152 void
00153 CTexManager::BindTexture( GLuint texNameToBind )
00154 {
00155 GLContext.TextureChanged();
00156
00157 if ( ! InsideDListDef ) {
00158 if ( texNameToBind == 0 ) {
00159
00160 CurTexture = DefaultTex;
00161 }
00162 else {
00163 if ( TexNames[texNameToBind] == NULL )
00164 TexNames[texNameToBind] = new CMMTexture( GS::kContext1 );
00165 CurTexture = TexNames[texNameToBind];
00166 }
00167
00168 pglAddToMetric(kMetricsBindTexture);
00169 }
00170 else {
00171 CDList &dlist = GLContext.GetDListManager().GetOpenDList();
00172 dlist += CBindTextureCmd( texNameToBind );
00173 }
00174 }
00175
00176 void
00177 CTexManager::DeleteTextures( GLsizei numToDelete, const GLuint *texNames )
00178 {
00179 for ( int i = 0; i < numToDelete; i++ ) {
00180 mErrorIf( TexNames[texNames[i]] == NULL,
00181 "Trying to delete a texture that doesn't exist!" );
00182 GLuint texName = texNames[i];
00183 if ( CurTexture == TexNames[texName] )
00184 CurTexture = DefaultTex;
00185 delete TexNames[texName];
00186 TexNames[texName] = NULL;
00187 }
00188 }
00189
00190 class CSetCurTexParamCmd : public CDListCmd {
00191 GLenum PName;
00192 int Param;
00193 public:
00194 CSetCurTexParamCmd( GLenum pname, int param ) : PName(pname), Param(param) {}
00195 CDListCmd* Play() {
00196 pGLContext->GetTexManager().SetCurTexParam(PName, Param);
00197 return CDListCmd::GetNextCmd(this);
00198 }
00199 };
00200
00201 void
00202 CTexManager::SetCurTexParam( GLenum pname, GLint param )
00203 {
00204 if ( ! InsideDListDef ) {
00205 CMMTexture &tex = *CurTexture;
00206
00207 switch( pname ) {
00208 case GL_TEXTURE_MIN_FILTER:
00209 tex.SetMinMode( (GS::tMinMode)(param & 0xf) );
00210 break;
00211 case GL_TEXTURE_MAG_FILTER:
00212 tex.SetMagMode( (GS::tMagMode)(param & 0xf) );
00213 break;
00214 case GL_TEXTURE_MIN_LOD:
00215 case GL_TEXTURE_MAX_LOD:
00216 case GL_TEXTURE_BASE_LEVEL:
00217 case GL_TEXTURE_MAX_LEVEL:
00218 case GL_TEXTURE_PRIORITY:
00219 case GL_TEXTURE_BORDER_COLOR:
00220 mNotImplemented( );
00221 break;
00222 case GL_TEXTURE_WRAP_S:
00223 tex.SetWrapModeS( (GS::tTexWrapMode)(param & 0xf) );
00224 break;
00225 case GL_TEXTURE_WRAP_T:
00226 tex.SetWrapModeT( (GS::tTexWrapMode)(param & 0xf) );
00227 break;
00228 case GL_TEXTURE_WRAP_R:
00229 mNotImplemented( "Sorry, only 2d textures." );
00230 break;
00231 }
00232 }
00233 else {
00234 CDList &dlist = GLContext.GetDListManager().GetOpenDList();
00235 dlist += CSetCurTexParamCmd(pname, param);
00236 }
00237 }
00238
00239 class CSetCurTexImageCmd : public CDListCmd {
00240 tU128 *Image;
00241 unsigned int Width, Height;
00242 GS::tPSM Psm;
00243 public:
00244 CSetCurTexImageCmd( tU128 *image, unsigned int w, unsigned int h,
00245 GS::tPSM psm )
00246 : Image(image), Width(w), Height(h), Psm(psm) {}
00247 CDListCmd* Play() {
00248 pGLContext->GetTexManager().SetCurTexImage( Image, Width, Height, Psm );
00249 return CDListCmd::GetNextCmd(this);
00250 }
00251 };
00252
00253 void
00254 CTexManager::SetCurTexImage( tU128* imagePtr, tU32 w, tU32 h,
00255 GS::tPSM psm )
00256 {
00257 GLContext.TextureChanged();
00258
00259 if ( ! InsideDListDef ) {
00260 CurTexture->SetImage( imagePtr, w, h, psm );
00261 }
00262 else {
00263 CDList &dlist = GLContext.GetDListManager().GetOpenDList();
00264 dlist += CSetCurTexImageCmd( imagePtr, w, h, psm );
00265 }
00266 }
00267
00268 class CSetCurClutCmd : public CDListCmd {
00269 const void *Clut;
00270 int NumEntries;
00271 public:
00272 CSetCurClutCmd( const void *clut, int numEntries )
00273 : Clut(clut), NumEntries(numEntries) {}
00274 CDListCmd* Play() {
00275 pGLContext->GetTexManager().SetCurClut(Clut, NumEntries);
00276 return CDListCmd::GetNextCmd(this);
00277 }
00278 };
00279
00280 void
00281 CTexManager::SetCurClut( const void *clut, int numEntries )
00282 {
00283 GLContext.TextureChanged();
00284
00285 if ( ! InsideDListDef ) {
00286 if ( CurClut ) delete CurClut;
00287 CurClut = new CMMClut( clut );
00288 }
00289 else {
00290 CDList &dlist = GLContext.GetDListManager().GetOpenDList();
00291 dlist += CSetCurClutCmd( clut, numEntries );
00292 }
00293 }
00294
00295 class CSetGsTextureCmd : public CDListCmd {
00296 GS::CMemArea &Texture;
00297 public:
00298 CSetGsTextureCmd(GS::CMemArea &tex) : Texture(tex) {}
00299 CDListCmd* Play() {
00300 pGLContext->GetTexManager().SetGsTexture(Texture);
00301 return CDListCmd::GetNextCmd(this);
00302 }
00303 };
00304
00305 void
00306 CTexManager::SetGsTexture( GS::CMemArea &area )
00307 {
00308 GLContext.TextureChanged();
00309
00310 if ( ! InsideDListDef )
00311 CurTexture->SetImage( area );
00312 else {
00313 CDList &dlist = GLContext.GetDListManager().GetOpenDList();
00314 dlist += CSetGsTextureCmd(area);
00315 }
00316 }
00317
00318
00319
00320
00321
00322 CMMTexture::CMMTexture( GS::tContext context )
00323 : CTexture( context ), pImageMem(NULL), XferImage(false)
00324 {
00325 }
00326
00327 CMMTexture::~CMMTexture()
00328 {
00329 delete pImageMem;
00330 }
00331
00335 void
00336 CMMTexture::SetImage( tU128* imagePtr, tU32 w, tU32 h, GS::tPSM psm )
00337 {
00338 if ( pImageMem ) {
00339
00340 delete pImageMem;
00341 CTexture::Reset();
00342 }
00343
00344 CTexture::SetImage( imagePtr, w, h, psm, NULL );
00345
00346
00347 tU32 bufWidth = gsrTex0.TBW * 64;
00348 pImageMem = new GS::CMemArea( bufWidth, h, psm, GS::kAlignBlock );
00349
00350 XferImage = true;
00351 }
00352
00357 void
00358 CMMTexture::SetImage( const GS::CMemArea &area )
00359 {
00360 CTexEnv::SetPSM( area.GetPixFormat() );
00361 CTexEnv::SetDimensions( area.GetWidth(), area.GetHeight() );
00362 SetImageGsAddr( area.GetWordAddr() );
00363
00364 XferImage = false;
00365 }
00366
00367 void
00368 CMMTexture::Load( bool waitForEnd = true )
00369 {
00370 mErrorIf( pImageMem == NULL,
00371 "Trying to load a texture that hasn't been defined!" );
00372
00373 if ( ! pImageMem->IsAllocated() ) {
00374 pImageMem->Alloc();
00375 SetImageGsAddr( pImageMem->GetWordAddr() );
00376 FlushCache(0);
00377
00378
00379 SendImage( waitForEnd, Packet::kDontFlushCache );
00380
00381 pglAddToMetric(kMetricsTextureUploadCount);
00382 }
00383 }
00384
00385
00386
00387 void
00388 CMMTexture::Load( CSCDmaPacket& packet )
00389 {
00390 mErrorIf( pImageMem == NULL,
00391 "Trying to load a texture that hasn't been defined!" );
00392 if ( ! pImageMem->IsAllocated() ) {
00393 pImageMem->Alloc();
00394 SetImageGsAddr( pImageMem->GetWordAddr() );
00395 SendImage( packet );
00396
00397 pglAddToMetric(kMetricsTextureUploadCount);
00398 }
00399 }
00400 void
00401 CMMTexture::Load( CVifSCDmaPacket& packet )
00402 {
00403 mErrorIf( pImageMem == NULL,
00404 "Trying to load a texture that hasn't been defined!" );
00405 if ( ! pImageMem->IsAllocated() ) {
00406 pImageMem->Alloc();
00407 SetImageGsAddr( pImageMem->GetWordAddr() );
00408 SendImage( packet );
00409
00410 pglAddToMetric(kMetricsTextureUploadCount);
00411 }
00412 }
00413
00414
00415
00416 void
00417 CMMTexture::Use( bool waitForEnd = false )
00418 {
00419 if ( XferImage ) Load();
00420 SendSettings( waitForEnd, Packet::kDontFlushCache );
00421 }
00422 void
00423 CMMTexture::Use( CSCDmaPacket& packet )
00424 {
00425 if ( XferImage ) Load( packet );
00426 SendSettings( packet );
00427 }
00428 void
00429 CMMTexture::Use( CVifSCDmaPacket& packet )
00430 {
00431 if ( XferImage ) Load( packet );
00432 SendSettings( packet );
00433 }
00434
00435 void
00436 CMMTexture::Free( void )
00437 {
00438 pImageMem->Free();
00439 }
00440
00441
00442
00443
00444
00445 void
00446 CMMClut::Load( CVifSCDmaPacket &packet )
00447 {
00448 if ( ! GsMem.IsAllocated() ) {
00449 GsMem.Alloc();
00450 SetGsAddr( GsMem.GetWordAddr() );
00451 Send(packet);
00452
00453 pglAddToMetric(kMetricsClutUploadCount);
00454 }
00455 }
00456
00457
00458
00459
00460
00461 void glGenTextures( GLsizei numNewTexNames, GLuint *newTexNames )
00462 {
00463 CTexManager &texManager = pGLContext->GetTexManager();
00464 texManager.GenTextures( numNewTexNames, newTexNames );
00465 }
00466
00467 void glBindTexture( GLenum target, GLuint texName )
00468 {
00469 mErrorIf( target != GL_TEXTURE_2D, "There are only 2D textures in ps2gl" );
00470
00471 CTexManager &texManager = pGLContext->GetTexManager();
00472 texManager.BindTexture( texName );
00473 }
00474
00475 void glDeleteTextures( GLsizei numToDelete, const GLuint *texNames )
00476 {
00477 CTexManager &texManager = pGLContext->GetTexManager();
00478 texManager.DeleteTextures( numToDelete, texNames );
00479 }
00480
00481 void glTexImage2D( GLenum target,
00482 GLint level,
00483 GLint internalFormat,
00484 GLsizei width,
00485 GLsizei height,
00486 GLint border,
00487 GLenum format,
00488 GLenum type,
00489 const GLvoid *pixels )
00490 {
00491 if ( target == GL_PROXY_TEXTURE_2D ) {
00492 mNotImplemented( );
00493 return;
00494 }
00495 if ( level > 0 ) {
00496 mNotImplemented("mipmapping");
00497 return;
00498 }
00499 if ( border > 0 ) {
00500 mNotImplemented("texture borders");
00501 return;
00502 }
00503 if ( (unsigned int)pixels & 0xf ) {
00504 mNotImplemented( "texture data needs to be aligned to at least 16 bytes, "
00505 "preferably 9 quads" );
00506 }
00507
00508 GS::tPSM psm = GS::kInvalidPsm;
00509 switch (format) {
00510 case GL_RGBA:
00511 if ( type == GL_UNSIGNED_BYTE ||
00512 type == GL_UNSIGNED_INT_8_8_8_8 )
00513 psm = GS::kPsm32;
00514 else if ( type == GL_UNSIGNED_SHORT_5_5_5_1 )
00515 psm = GS::kPsm16;
00516 else {
00517 mNotImplemented( "RGBA textures should have a type of GL_UNSIGNED_BYTE, "
00518 "GL_UNSIGNED_INT_8_8_8_8, or GL_UNSIGNED_SHORT_5_5_5_1" );
00519 }
00520 break;
00521 case GL_RGB:
00522 if ( type == GL_UNSIGNED_BYTE )
00523 psm = GS::kPsm24;
00524 else {
00525 mNotImplemented( "RGB textures should have a type of GL_UNSIGNED_BYTE" );
00526 }
00527 break;
00528 case GL_COLOR_INDEX:
00529 if ( type == GL_UNSIGNED_BYTE )
00530 psm = GS::kPsm8;
00531 else {
00532 mNotImplemented( "indexed textures should have a type of GL_UNSIGNED_BYTE" );
00533 }
00534 break;
00535 }
00536
00537 if ( psm != GS::kInvalidPsm ) {
00538 CTexManager& tm = pGLContext->GetTexManager();
00539 tm.SetCurTexImage( (tU128*)pixels, width, height, psm );
00540 }
00541 }
00542
00543 void glColorTable( GLenum target, GLenum internalFormat,
00544 GLsizei width, GLenum format, GLenum type,
00545 const GLvoid *table )
00546 {
00547 mWarnIf( target != GL_COLOR_TABLE,
00548 "glColorTable only supports GL_COLOR_TABLE" );
00549
00550 mErrorIf( width != 16 && width != 256,
00551 "A color table must contain either 16 or 256 entries" );
00552 mErrorIf( format != GL_RGB && format != GL_RGBA,
00553 "The pixel format of color tables must be either GL_RGB or GL_RGBA" );
00554 mWarnIf( type != GL_UNSIGNED_INT && type != GL_UNSIGNED_INT_8_8_8_8,
00555 "The type of color table data must be either GL_UNSIGNED_INT or"
00556 "GL_UNSIGNED_INT_8_8_8_8" );
00557 mErrorIf( (unsigned int)table & (16-1),
00558 "Color tables in ps2gl need to be 16-byte aligned in memory.." );
00559
00560 CTexManager& tm = pGLContext->GetTexManager();
00561 tm.SetCurClut( table, width );
00562 }
00563
00564 void glTexParameteri( GLenum target, GLenum pname, GLint param )
00565 {
00566 if ( target != GL_TEXTURE_2D ) {
00567 mNotImplemented( "Sorry, only 2d textures." );
00568 return;
00569 }
00570
00571 pGLContext->GetTexManager().SetCurTexParam( pname, param );
00572 }
00573
00574 void glTexParameterf( GLenum target, GLenum pname, GLfloat param )
00575 {
00576 glTexParameteri( target, pname, (GLint)param );
00577 }
00578
00579 void glTexParameteriv( GLenum target, GLenum pname, GLint *param )
00580 {
00581 glTexParameteri( target, pname, *param );
00582 }
00583
00584 void glTexParameterfv( GLenum target, GLenum pname, GLfloat *param )
00585 {
00586 glTexParameteri( target, pname, (GLint)*param );
00587 }
00588
00589 void glTexEnvi( GLenum target, GLenum pname, GLint param )
00590 {
00591 CTexManager &tm = pGLContext->GetTexManager();
00592
00593 switch( param ) {
00594 case GL_MODULATE:
00595 tm.SetTexMode( (GS::tTexMode)(param & 0xf) );
00596 break;
00597 case GL_DECAL:
00598 mWarn( "GL_DECAL functions exactly as GL_REPLACE right now." );
00599 case GL_REPLACE:
00600 tm.SetTexMode( (GS::tTexMode)(param & 0xf) );
00601 break;
00602 case GL_BLEND:
00603 mNotImplemented( );
00604 break;
00605 }
00606 }
00607
00608 void glTexEnvf( GLenum target, GLenum pname, GLfloat param )
00609 {
00610 glTexEnvi( target, pname, (GLint)param );
00611 }
00612
00613 void glTexEnvfv( GLenum target, GLenum pname, GLfloat *param )
00614 {
00615 glTexEnvi( target, pname, (GLint)*param );
00616 }
00617
00618 void glTexEnviv( GLenum target, GLenum pname, GLint *param )
00619 {
00620 glTexEnvi( target, pname, *param );
00621 }
00622
00623
00624
00625
00626
00637 void pglTextureFromGsMemArea( pgl_area_handle_t tex_area_handle )
00638 {
00639 CTexManager &texManager = pGLContext->GetTexManager();
00640 GS::CMemArea *texArea = reinterpret_cast<GS::CMemArea*>(tex_area_handle);
00641 texManager.SetGsTexture( *texArea );
00642 }
00643