2009-02-09 21:15:56 +00:00
/*
* Copyright ( C ) 2007 - 2009 Gabest
* http : //www.gabest.org
*
* This Program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This Program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with GNU Make ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
* http : //www.gnu.org/copyleft/gpl.html
*
*/
# include "StdAfx.h"
# include "GSTextureCacheSW.h"
GSTextureCacheSW : : GSTextureCacheSW ( GSState * state )
: m_state ( state )
{
2009-07-01 22:29:24 +00:00
memset ( m_pages , 0 , sizeof ( m_pages ) ) ;
2009-02-09 21:15:56 +00:00
}
GSTextureCacheSW : : ~ GSTextureCacheSW ( )
{
RemoveAll ( ) ;
}
2009-05-20 15:35:31 +00:00
const GSTextureCacheSW : : GSTexture * GSTextureCacheSW : : Lookup ( const GIFRegTEX0 & TEX0 , const GIFRegTEXA & TEXA , const GSVector4i & r )
2009-02-09 21:15:56 +00:00
{
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ TEX0 . PSM ] ;
GSTexture * t = NULL ;
2009-06-27 03:32:33 +00:00
const hash_map < GSTexture * , bool > & map = m_map [ TEX0 . TBP0 > > 5 ] ;
2009-05-11 08:18:00 +00:00
for ( hash_map < GSTexture * , bool > : : const_iterator i = map . begin ( ) ; i ! = map . end ( ) ; i + + )
2009-02-09 21:15:56 +00:00
{
2009-06-27 03:32:33 +00:00
GSTexture * t2 = i - > first ;
2009-05-11 08:18:00 +00:00
2009-06-09 10:13:28 +00:00
if ( ( ( t2 - > m_TEX0 . u32 [ 0 ] ^ TEX0 . u32 [ 0 ] ) | ( ( t2 - > m_TEX0 . u32 [ 1 ] ^ TEX0 . u32 [ 1 ] ) & 3 ) ) ! = 0 ) // TBP0 TBW PSM TW TH
2009-02-09 21:15:56 +00:00
{
continue ;
}
2009-06-17 11:24:42 +00:00
if ( ( psm . trbpp = = 16 | | psm . trbpp = = 24 ) & & TEX0 . TCC & & TEXA ! = t2 - > m_TEXA )
2009-02-09 21:15:56 +00:00
{
continue ;
}
t = t2 ;
t - > m_age = 0 ;
break ;
}
if ( t = = NULL )
{
t = new GSTexture ( m_state ) ;
2009-05-11 08:18:00 +00:00
m_textures [ t ] = true ;
2009-02-09 21:15:56 +00:00
int tw = 1 < < TEX0 . TW ;
int th = 1 < < TEX0 . TH ;
2009-05-14 16:41:52 +00:00
uint32 bp = TEX0 . TBP0 ;
uint32 bw = TEX0 . TBW ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
GSVector2i s = ( bp & 31 ) = = 0 ? psm . pgs : psm . bs ;
2009-05-07 06:32:10 +00:00
2009-05-14 16:41:52 +00:00
for ( int y = 0 ; y < th ; y + = s . y )
2009-02-09 21:15:56 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 base = psm . bn ( 0 , y , bp , bw ) ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
for ( int x = 0 ; x < tw ; x + = s . x )
2009-02-09 21:15:56 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 page = ( base + psm . blockOffset [ x > > 3 ] ) > > 5 ;
2009-02-09 21:15:56 +00:00
2009-06-27 03:32:33 +00:00
if ( page < MAX_PAGES )
2009-05-07 06:32:10 +00:00
{
2009-07-01 22:29:24 +00:00
m_pages [ page > > 5 ] | = 1 < < ( page & 31 ) ;
}
}
}
for ( int i = 0 ; i < countof ( m_pages ) ; i + + )
{
if ( uint32 p = m_pages [ i ] )
{
m_pages [ i ] = 0 ;
hash_map < GSTexture * , bool > * m = & m_map [ i < < 5 ] ;
for ( int j = 0 ; j < 32 ; j + + )
{
if ( p & ( 1 < < j ) )
{
m [ j ] [ t ] = true ;
}
2009-05-07 06:32:10 +00:00
}
2009-02-09 21:15:56 +00:00
}
}
}
if ( ! t - > Update ( TEX0 , TEXA , r ) )
{
2009-05-07 06:32:10 +00:00
printf ( " !@#$% \n " ) ; // memory allocation may fail if the game is too hungry
2009-05-11 08:18:00 +00:00
m_textures . erase ( t ) ;
2009-02-09 21:15:56 +00:00
2009-05-07 06:32:10 +00:00
for ( int i = 0 ; i < MAX_PAGES ; i + + )
{
2009-05-11 08:18:00 +00:00
m_map [ i ] . erase ( t ) ;
2009-05-07 06:32:10 +00:00
}
2009-02-09 21:15:56 +00:00
2009-05-07 06:32:10 +00:00
delete t ;
2009-02-09 21:15:56 +00:00
return NULL ;
}
return t ;
}
void GSTextureCacheSW : : RemoveAll ( )
{
2009-05-11 08:18:00 +00:00
for ( hash_map < GSTexture * , bool > : : iterator i = m_textures . begin ( ) ; i ! = m_textures . end ( ) ; i + + )
2009-02-09 21:15:56 +00:00
{
2009-05-11 08:18:00 +00:00
delete i - > first ;
2009-02-09 21:15:56 +00:00
}
2009-05-11 08:18:00 +00:00
m_textures . clear ( ) ;
2009-02-09 21:15:56 +00:00
for ( int i = 0 ; i < MAX_PAGES ; i + + )
{
2009-05-11 08:18:00 +00:00
m_map [ i ] . clear ( ) ;
2009-02-09 21:15:56 +00:00
}
}
void GSTextureCacheSW : : IncAge ( )
{
2009-05-11 08:18:00 +00:00
for ( hash_map < GSTexture * , bool > : : iterator i = m_textures . begin ( ) ; i ! = m_textures . end ( ) ; )
2009-02-09 21:15:56 +00:00
{
2009-05-11 08:18:00 +00:00
hash_map < GSTexture * , bool > : : iterator j = i + + ;
2009-02-09 21:15:56 +00:00
2009-05-11 08:18:00 +00:00
GSTexture * t = j - > first ;
2009-02-09 21:15:56 +00:00
2009-05-07 06:32:10 +00:00
if ( + + t - > m_age > 30 )
2009-02-09 21:15:56 +00:00
{
2009-05-11 08:18:00 +00:00
m_textures . erase ( j ) ;
2009-02-09 21:15:56 +00:00
2009-05-07 06:32:10 +00:00
for ( int i = 0 ; i < MAX_PAGES ; i + + )
{
2009-05-11 08:18:00 +00:00
m_map [ i ] . erase ( t ) ;
2009-05-07 06:32:10 +00:00
}
2009-02-09 21:15:56 +00:00
delete t ;
}
}
}
2009-05-14 16:41:52 +00:00
void GSTextureCacheSW : : InvalidateVideoMem ( const GIFRegBITBLTBUF & BITBLTBUF , const GSVector4i & rect )
2009-02-09 21:15:56 +00:00
{
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ BITBLTBUF . DPSM ] ;
2009-05-14 16:41:52 +00:00
uint32 bp = BITBLTBUF . DBP ;
uint32 bw = BITBLTBUF . DBW ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
GSVector2i s = ( bp & 31 ) = = 0 ? psm . pgs : psm . bs ;
2009-05-07 06:32:10 +00:00
2009-05-20 15:35:31 +00:00
GSVector4i r = rect . ralign < GSVector4i : : Outside > ( s ) ;
2009-05-07 06:32:10 +00:00
2009-05-14 16:41:52 +00:00
for ( int y = r . top ; y < r . bottom ; y + = s . y )
2009-02-09 21:15:56 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 base = psm . bn ( 0 , y , bp , bw ) ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
for ( int x = r . left ; x < r . right ; x + = s . x )
2009-02-09 21:15:56 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 page = ( base + psm . blockOffset [ x > > 3 ] ) > > 5 ;
2009-02-09 21:15:56 +00:00
2009-06-27 03:32:33 +00:00
if ( page < MAX_PAGES )
2009-02-09 21:15:56 +00:00
{
2009-06-27 03:32:33 +00:00
const hash_map < GSTexture * , bool > & map = m_map [ page ] ;
2009-02-09 21:15:56 +00:00
2009-06-27 03:32:33 +00:00
for ( hash_map < GSTexture * , bool > : : const_iterator i = map . begin ( ) ; i ! = map . end ( ) ; i + + )
{
GSTexture * t = i - > first ;
2009-02-09 21:15:56 +00:00
2009-06-27 03:32:33 +00:00
if ( GSUtil : : HasSharedBits ( BITBLTBUF . DPSM , t - > m_TEX0 . PSM ) )
{
t - > m_valid [ page ] = 0 ;
t - > m_complete = false ;
}
}
2009-02-09 21:15:56 +00:00
}
}
}
}
//
GSTextureCacheSW : : GSTexture : : GSTexture ( GSState * state )
: m_state ( state )
, m_buff ( NULL )
, m_tw ( 0 )
, m_age ( 0 )
2009-05-07 06:32:10 +00:00
, m_complete ( false )
2009-02-09 21:15:56 +00:00
{
memset ( m_valid , 0 , sizeof ( m_valid ) ) ;
}
GSTextureCacheSW : : GSTexture : : ~ GSTexture ( )
{
if ( m_buff )
{
_aligned_free ( m_buff ) ;
}
}
2009-05-20 15:35:31 +00:00
bool GSTextureCacheSW : : GSTexture : : Update ( const GIFRegTEX0 & TEX0 , const GIFRegTEXA & TEXA , const GSVector4i & rect )
2009-02-09 21:15:56 +00:00
{
2009-05-07 06:32:10 +00:00
if ( m_complete )
2009-02-09 21:15:56 +00:00
{
return true ;
}
m_TEX0 = TEX0 ;
m_TEXA = TEXA ;
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ TEX0 . PSM ] ;
2009-05-14 16:41:52 +00:00
GSVector2i s = psm . bs ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
int tw = max ( 1 < < TEX0 . TW , s . x ) ;
int th = max ( 1 < < TEX0 . TH , s . y ) ;
2009-02-09 21:15:56 +00:00
if ( m_buff = = NULL )
{
2009-05-14 16:41:52 +00:00
m_buff = _aligned_malloc ( tw * th * sizeof ( uint32 ) , 16 ) ;
2009-02-09 21:15:56 +00:00
if ( m_buff = = NULL )
{
return false ;
}
m_tw = max ( psm . pal > 0 ? 5 : 3 , TEX0 . TW ) ; // makes one row 32 bytes at least, matches the smallest block size that is allocated above for m_buff
}
2009-05-20 15:35:31 +00:00
GSVector4i r = rect . ralign < GSVector4i : : Outside > ( s ) ;
2009-02-09 21:15:56 +00:00
2009-07-01 21:14:12 +00:00
if ( r . eq ( GSVector4i ( 0 , 0 , tw , th ) ) )
2009-05-07 06:32:10 +00:00
{
m_complete = true ; // lame, but better than nothing
}
2009-02-09 21:15:56 +00:00
2009-06-27 03:32:33 +00:00
GSLocalMemory & mem = m_state - > m_mem ;
uint32 bp = TEX0 . TBP0 ;
uint32 bw = TEX0 . TBW ;
2009-05-07 06:32:10 +00:00
GSLocalMemory : : readTextureBlock rtxb = psm . rtxbP ;
2009-06-27 03:32:33 +00:00
2009-02-09 21:15:56 +00:00
int bytes = psm . pal > 0 ? 1 : 4 ;
2009-05-14 16:41:52 +00:00
uint32 pitch = ( 1 < < m_tw ) * bytes ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
uint8 * dst = ( uint8 * ) m_buff + pitch * r . top ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
uint32 blocks = 0 ;
2009-02-09 21:15:56 +00:00
2009-05-09 08:37:02 +00:00
if ( tw < = ( bw < < 6 ) )
2009-05-07 06:32:10 +00:00
{
2009-05-14 16:41:52 +00:00
for ( int y = r . top , o = pitch * s . y ; y < r . bottom ; y + = s . y , dst + = o )
2009-02-09 21:15:56 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 base = psm . bn ( 0 , y , bp , bw ) ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
for ( int x = r . left ; x < r . right ; x + = s . x )
2009-02-09 21:15:56 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 block = base + psm . blockOffset [ x > > 3 ] ;
2009-02-09 21:15:56 +00:00
2009-05-09 08:37:02 +00:00
if ( block < MAX_BLOCKS )
{
2009-05-14 16:41:52 +00:00
uint32 row = block > > 5 ;
uint32 col = 1 < < ( block & 31 ) ;
2009-02-09 21:15:56 +00:00
2009-05-09 08:37:02 +00:00
if ( ( m_valid [ row ] & col ) = = 0 )
{
m_valid [ row ] | = col ;
2009-02-09 21:15:56 +00:00
2009-05-09 08:37:02 +00:00
( mem . * rtxb ) ( block , & dst [ x * bytes ] , pitch , TEXA ) ;
2009-02-09 21:15:56 +00:00
2009-05-09 08:37:02 +00:00
blocks + + ;
}
}
}
2009-05-07 06:32:10 +00:00
}
}
2009-05-09 08:37:02 +00:00
else
2009-05-07 06:32:10 +00:00
{
2009-05-09 08:37:02 +00:00
// unfortunatelly a block may be part of the same texture multiple times at different places (tw 1024 > tbw 640, between 640 -> 1024 it is repeated from the next row),
// so just can't set the block's bit to valid in one pass, even if 99.9% of the games don't address the repeated part at the right side
// TODO: still bogus if those repeated parts aren't fetched together
2009-05-07 06:32:10 +00:00
2009-05-14 16:41:52 +00:00
for ( int y = r . top , o = pitch * s . y ; y < r . bottom ; y + = s . y , dst + = o )
2009-05-07 06:32:10 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 base = psm . bn ( 0 , y , bp , bw ) ;
2009-05-07 06:32:10 +00:00
2009-05-14 16:41:52 +00:00
for ( int x = r . left ; x < r . right ; x + = s . x )
2009-05-07 06:32:10 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 block = base + psm . blockOffset [ x > > 3 ] ;
2009-05-09 08:37:02 +00:00
if ( block < MAX_BLOCKS )
{
2009-05-14 16:41:52 +00:00
uint32 row = block > > 5 ;
uint32 col = 1 < < ( block & 31 ) ;
2009-05-09 08:37:02 +00:00
if ( ( m_valid [ row ] & col ) = = 0 )
{
( mem . * rtxb ) ( block , & dst [ x * bytes ] , pitch , TEXA ) ;
blocks + + ;
}
}
2009-05-07 06:32:10 +00:00
}
2009-05-09 08:37:02 +00:00
}
2009-05-07 06:32:10 +00:00
2009-05-14 16:41:52 +00:00
for ( int y = r . top ; y < r . bottom ; y + = s . y )
2009-05-09 08:37:02 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 base = psm . bn ( 0 , y , bp , bw ) ;
2009-05-09 08:37:02 +00:00
2009-05-14 16:41:52 +00:00
for ( int x = r . left ; x < r . right ; x + = s . x )
2009-05-09 08:37:02 +00:00
{
2009-05-14 16:41:52 +00:00
uint32 block = base + psm . blockOffset [ x > > 3 ] ;
2009-05-09 08:37:02 +00:00
if ( block < MAX_BLOCKS )
{
2009-05-14 16:41:52 +00:00
uint32 row = block > > 5 ;
uint32 col = 1 < < ( block & 31 ) ;
2009-05-07 06:32:10 +00:00
2009-05-09 08:37:02 +00:00
m_valid [ row ] | = col ;
}
}
2009-02-09 21:15:56 +00:00
}
}
2009-05-14 16:41:52 +00:00
m_state - > m_perfmon . Put ( GSPerfMon : : Unswizzle , s . x * s . y * bytes * blocks ) ;
2009-05-09 08:37:02 +00:00
2009-02-09 21:15:56 +00:00
return true ;
2009-05-07 06:32:10 +00:00
}