2010-04-25 00:31:27 +00:00
/*
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 .
2010-04-25 00:31:27 +00:00
*
2009-02-09 21:15:56 +00:00
* 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 .
2010-04-25 00:31:27 +00:00
*
2009-02-09 21:15:56 +00:00
* You should have received a copy of the GNU General Public License
* along with GNU Make ; see the file COPYING . If not , write to
2012-09-09 18:16:11 +00:00
* the Free Software Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA USA .
2009-02-09 21:15:56 +00:00
* http : //www.gnu.org/copyleft/gpl.html
*
*/
2011-02-19 03:36:30 +00:00
# include "stdafx.h"
2009-02-09 21:15:56 +00:00
# include "GSTextureCacheSW.h"
GSTextureCacheSW : : GSTextureCacheSW ( GSState * state )
: m_state ( state )
{
}
GSTextureCacheSW : : ~ GSTextureCacheSW ( )
{
RemoveAll ( ) ;
}
2011-12-18 08:13:20 +00:00
GSTextureCacheSW : : Texture * GSTextureCacheSW : : Lookup ( const GIFRegTEX0 & TEX0 , const GIFRegTEXA & TEXA , uint32 tw0 )
2009-02-09 21:15:56 +00:00
{
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ TEX0 . PSM ] ;
2011-03-17 02:55:20 +00:00
Texture * t = NULL ;
2009-02-09 21:15:56 +00:00
2011-03-17 02:55:20 +00:00
list < Texture * > & m = m_map [ TEX0 . TBP0 > > 5 ] ;
2009-06-27 03:32:33 +00:00
2016-08-12 21:11:26 +00:00
for ( list < Texture * > : : iterator i = m . begin ( ) ; i ! = m . end ( ) ; + + i )
2009-02-09 21:15:56 +00:00
{
2011-03-17 02:55:20 +00:00
Texture * t2 = * i ;
2009-05-11 08:18:00 +00:00
2009-07-04 15:14:04 +00:00
if ( ( ( TEX0 . u32 [ 0 ] ^ t2 - > m_TEX0 . u32 [ 0 ] ) | ( ( TEX0 . u32 [ 1 ] ^ t2 - > m_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 ;
}
2011-03-17 02:55:20 +00:00
if ( tw0 ! = 0 & & t2 - > m_tw ! = tw0 )
{
continue ;
}
2009-07-12 13:46:05 +00:00
m . splice ( m . begin ( ) , m , i ) ;
2009-02-09 21:15:56 +00:00
t = t2 ;
t - > m_age = 0 ;
break ;
}
if ( t = = NULL )
{
2011-12-23 15:53:53 +00:00
t = new Texture ( m_state , tw0 , TEX0 , TEXA ) ;
2009-02-09 21:15:56 +00:00
2011-03-12 22:10:58 +00:00
m_textures . insert ( t ) ;
2009-02-09 21:15:56 +00:00
2012-01-05 02:40:24 +00:00
for ( const uint32 * p = t - > m_pages . n ; * p ! = GSOffset : : EOP ; p + + )
2009-07-01 22:29:24 +00:00
{
2012-01-05 02:40:24 +00:00
m_map [ * p ] . push_front ( t ) ;
2009-02-09 21:15:56 +00:00
}
}
return t ;
}
2012-01-05 02:40:24 +00:00
void GSTextureCacheSW : : InvalidatePages ( const uint32 * pages , uint32 psm )
2009-07-22 03:55:28 +00:00
{
2012-01-05 02:40:24 +00:00
for ( const uint32 * p = pages ; * p ! = GSOffset : : EOP ; p + + )
2009-07-22 03:55:28 +00:00
{
2011-12-23 15:53:53 +00:00
uint32 page = * p ;
const list < Texture * > & map = m_map [ page ] ;
2009-07-22 03:55:28 +00:00
2016-08-12 21:11:26 +00:00
for ( list < Texture * > : : const_iterator i = map . begin ( ) ; i ! = map . end ( ) ; + + i )
2009-07-22 03:55:28 +00:00
{
2011-12-23 15:53:53 +00:00
Texture * t = * i ;
2009-07-22 03:55:28 +00:00
2012-01-13 18:10:05 +00:00
if ( GSUtil : : HasSharedBits ( psm , t - > m_sharedbits ) )
2009-07-22 03:55:28 +00:00
{
2011-12-31 15:41:07 +00:00
uint32 * RESTRICT valid = t - > m_valid ;
2011-12-23 15:53:53 +00:00
if ( t - > m_repeating )
2009-07-22 03:55:28 +00:00
{
2011-12-31 15:41:07 +00:00
vector < GSVector2i > & l = t - > m_p2t [ page ] ;
2016-08-12 21:11:26 +00:00
for ( vector < GSVector2i > : : iterator j = l . begin ( ) ; j ! = l . end ( ) ; + + j )
2011-12-23 15:53:53 +00:00
{
2011-12-31 15:41:07 +00:00
valid [ j - > x ] & = j - > y ;
2009-07-22 03:55:28 +00:00
}
}
2011-12-23 15:53:53 +00:00
else
{
2011-12-31 15:41:07 +00:00
valid [ page ] = 0 ;
2011-12-23 15:53:53 +00:00
}
t - > m_complete = false ;
2009-07-22 03:55:28 +00:00
}
}
}
}
2009-02-09 21:15:56 +00:00
void GSTextureCacheSW : : RemoveAll ( )
{
2009-07-16 21:36:07 +00:00
for_each ( m_textures . begin ( ) , m_textures . end ( ) , delete_object ( ) ) ;
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 ( )
{
2011-03-17 02:55:20 +00:00
for ( hash_set < Texture * > : : iterator i = m_textures . begin ( ) ; i ! = m_textures . end ( ) ; )
2009-02-09 21:15:56 +00:00
{
2011-03-17 02:55:20 +00:00
hash_set < Texture * > : : iterator j = i + + ;
2009-02-09 21:15:56 +00:00
2011-03-17 02:55:20 +00:00
Texture * t = * j ;
2009-02-09 21:15:56 +00:00
2012-02-12 17:56:06 +00:00
if ( + + t - > m_age > 10 )
2009-02-09 21:15:56 +00:00
{
2012-02-12 17:56:06 +00:00
m_textures . erase ( j ) ;
for ( const uint32 * p = t - > m_pages . n ; * p ! = GSOffset : : EOP ; p + + )
{
list < Texture * > & m = m_map [ * p ] ;
for ( list < Texture * > : : iterator i = m . begin ( ) ; i ! = m . end ( ) ; )
{
list < Texture * > : : iterator j = i + + ;
if ( * j = = t ) { m . erase ( j ) ; break ; }
}
}
delete t ;
2009-02-09 21:15:56 +00:00
}
}
}
//
2011-12-23 15:53:53 +00:00
GSTextureCacheSW : : Texture : : Texture ( GSState * state , uint32 tw0 , const GIFRegTEX0 & TEX0 , const GIFRegTEXA & TEXA )
2009-02-09 21:15:56 +00:00
: m_state ( state )
, m_buff ( NULL )
2011-03-17 02:55:20 +00:00
, m_tw ( tw0 )
2009-02-09 21:15:56 +00:00
, m_age ( 0 )
2009-05-07 06:32:10 +00:00
, m_complete ( false )
2011-04-26 00:56:54 +00:00
, m_p2t ( NULL )
2009-02-09 21:15:56 +00:00
{
2011-04-25 18:18:21 +00:00
m_TEX0 = TEX0 ;
m_TEXA = TEXA ;
2012-01-21 04:44:04 +00:00
if ( m_tw = = 0 )
{
m_tw = std : : max < int > ( m_TEX0 . TW , GSLocalMemory : : m_psm [ m_TEX0 . PSM ] . pal = = 0 ? 3 : 5 ) ; // makes one row 32 bytes at least, matches the smallest block size that is allocated for m_buff
}
2009-02-09 21:15:56 +00:00
memset ( m_valid , 0 , sizeof ( m_valid ) ) ;
2011-12-23 15:53:53 +00:00
memset ( m_pages . bm , 0 , sizeof ( m_pages . bm ) ) ;
2011-12-18 08:13:20 +00:00
2012-01-13 18:10:05 +00:00
m_sharedbits = GSUtil : : HasSharedBitsPtr ( m_TEX0 . PSM ) ;
2011-12-23 15:53:53 +00:00
m_offset = m_state - > m_mem . GetOffset ( TEX0 . TBP0 , TEX0 . TBW , TEX0 . PSM ) ;
2011-12-18 08:13:20 +00:00
2011-12-28 14:10:20 +00:00
m_pages . n = m_offset - > GetPages ( GSVector4i ( 0 , 0 , 1 < < TEX0 . TW , 1 < < TEX0 . TH ) ) ;
2011-12-18 08:13:20 +00:00
2012-01-05 02:40:24 +00:00
for ( const uint32 * p = m_pages . n ; * p ! = GSOffset : : EOP ; p + + )
2011-12-18 08:13:20 +00:00
{
2012-01-05 02:40:24 +00:00
uint32 page = * p ;
2011-12-18 08:13:20 +00:00
2011-12-23 15:53:53 +00:00
m_pages . bm [ page > > 5 ] | = 1 < < ( page & 31 ) ;
2011-12-18 08:13:20 +00:00
}
2011-04-25 18:18:21 +00:00
m_repeating = m_TEX0 . IsRepeating ( ) ; // repeating mode always works, it is just slightly slower
2011-04-26 00:56:54 +00:00
if ( m_repeating )
{
m_p2t = m_state - > m_mem . GetPage2TileMap ( m_TEX0 ) ;
}
2009-02-09 21:15:56 +00:00
}
2011-03-17 02:55:20 +00:00
GSTextureCacheSW : : Texture : : ~ Texture ( )
2009-02-09 21:15:56 +00:00
{
2012-01-05 02:40:24 +00:00
delete [ ] m_pages . n ;
2011-12-28 20:21:32 +00:00
2009-02-09 21:15:56 +00:00
if ( m_buff )
{
_aligned_free ( m_buff ) ;
}
}
2011-04-25 18:18:21 +00:00
bool GSTextureCacheSW : : Texture : : Update ( 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 ;
}
2011-04-25 18:18:21 +00:00
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ m_TEX0 . PSM ] ;
2009-02-09 21:15:56 +00:00
2009-07-04 15:14:04 +00:00
GSVector2i bs = psm . bs ;
2011-03-12 22:10:58 +00:00
int shift = psm . pal = = 0 ? 2 : 0 ;
2011-04-25 18:18:21 +00:00
int tw = std : : max < int > ( 1 < < m_TEX0 . TW , bs . x ) ;
int th = std : : max < int > ( 1 < < m_TEX0 . TH , bs . y ) ;
2009-07-04 15:14:04 +00:00
2011-03-12 22:10:58 +00:00
GSVector4i r = rect ;
r = r . ralign < Align_Outside > ( bs ) ;
2009-02-09 21:15:56 +00:00
2009-07-04 15:14:04 +00:00
if ( r . eq ( GSVector4i ( 0 , 0 , tw , th ) ) )
{
m_complete = true ; // lame, but better than nothing
}
2009-02-09 21:15:56 +00:00
if ( m_buff = = NULL )
{
2011-03-17 02:55:20 +00:00
uint32 pitch = ( 1 < < m_tw ) < < shift ;
m_buff = _aligned_malloc ( pitch * th * 4 , 32 ) ;
2011-03-12 22:10:58 +00:00
2011-03-17 02:55:20 +00:00
if ( m_buff = = NULL )
{
return false ;
}
2009-02-09 21:15:56 +00:00
}
2009-07-04 15:14:04 +00:00
GSLocalMemory & mem = m_state - > m_mem ;
2009-02-09 21:15:56 +00:00
2015-05-15 18:40:09 +00:00
const GSOffset * RESTRICT off = m_offset ;
2009-07-02 16:05:03 +00:00
uint32 blocks = 0 ;
2011-03-12 22:10:58 +00:00
GSLocalMemory : : readTextureBlock rtxbP = psm . rtxbP ;
2009-02-09 21:15:56 +00:00
2009-07-02 16:05:03 +00:00
uint32 pitch = ( 1 < < m_tw ) < < shift ;
2009-02-09 21:15:56 +00:00
2011-04-25 18:18:21 +00:00
uint8 * dst = ( uint8 * ) m_buff + pitch * r . top ;
2009-07-02 16:05:03 +00:00
2012-01-08 17:10:00 +00:00
int block_pitch = pitch * bs . y ;
r = r . srl32 ( 3 ) ;
bs . x > > = 3 ;
bs . y > > = 3 ;
shift + = 3 ;
2011-04-25 18:18:21 +00:00
if ( m_repeating )
{
2012-01-08 17:10:00 +00:00
for ( int y = r . top ; y < r . bottom ; y + = bs . y , dst + = block_pitch )
2009-02-09 21:15:56 +00:00
{
2015-05-15 18:40:09 +00:00
uint32 base = off - > block . row [ y ] ;
2009-02-09 21:15:56 +00:00
2011-04-25 18:18:21 +00:00
for ( int x = r . left , i = ( y < < 7 ) + x ; x < r . right ; x + = bs . x , i + = bs . x )
2009-02-09 21:15:56 +00:00
{
2016-10-25 20:49:05 +00:00
uint32 block = ( base + off - > block . col [ x ] ) % MAX_BLOCKS ;
2009-02-09 21:15:56 +00:00
2016-10-25 20:49:05 +00:00
uint32 row = i > > 5 ;
uint32 col = 1 < < ( i & 31 ) ;
2011-04-25 01:44:00 +00:00
2016-10-25 20:49:05 +00:00
if ( ( m_valid [ row ] & col ) = = 0 )
{
m_valid [ row ] | = col ;
2009-02-09 21:15:56 +00:00
2016-10-25 20:49:05 +00:00
( mem . * rtxbP ) ( block , & dst [ x < < shift ] , pitch , m_TEXA ) ;
2009-02-09 21:15:56 +00:00
2016-10-25 20:49:05 +00:00
blocks + + ;
2009-05-09 08:37:02 +00:00
}
}
2009-05-07 06:32:10 +00:00
}
}
2011-04-25 01:44:00 +00:00
else
2009-07-02 16:05:03 +00:00
{
2012-01-08 17:10:00 +00:00
for ( int y = r . top ; y < r . bottom ; y + = bs . y , dst + = block_pitch )
2009-05-07 06:32:10 +00:00
{
2015-05-15 18:40:09 +00:00
uint32 base = off - > block . row [ y ] ;
2011-04-25 01:44:00 +00:00
for ( int x = r . left ; x < r . right ; x + = bs . x )
2009-05-07 06:32:10 +00:00
{
2016-10-25 20:49:05 +00:00
uint32 block = ( base + off - > block . col [ x ] ) % MAX_BLOCKS ;
2009-05-09 08:37:02 +00:00
2016-10-25 20:49:05 +00:00
uint32 row = block > > 5 ;
uint32 col = 1 < < ( block & 31 ) ;
2009-05-09 08:37:02 +00:00
2016-10-25 20:49:05 +00:00
if ( ( m_valid [ row ] & col ) = = 0 )
{
m_valid [ row ] | = col ;
2011-04-25 01:44:00 +00:00
2016-10-25 20:49:05 +00:00
( mem . * rtxbP ) ( block , & dst [ x < < shift ] , pitch , m_TEXA ) ;
2011-04-25 01:44:00 +00:00
2016-10-25 20:49:05 +00:00
blocks + + ;
2009-05-09 08:37:02 +00:00
}
2009-05-07 06:32:10 +00:00
}
2009-05-09 08:37:02 +00:00
}
2011-04-25 01:44:00 +00:00
}
2009-05-07 06:32:10 +00:00
2011-04-25 01:44:00 +00:00
if ( blocks > 0 )
{
2009-07-04 15:14:04 +00:00
m_state - > m_perfmon . Put ( GSPerfMon : : Unswizzle , bs . x * bs . y * blocks < < shift ) ;
2009-02-09 21:15:56 +00:00
}
return true ;
2009-05-07 06:32:10 +00:00
}
2011-03-17 02:55:20 +00:00
# include "GSTextureSW.h"
bool GSTextureCacheSW : : Texture : : Save ( const string & fn , bool dds ) const
{
const uint32 * RESTRICT clut = m_state - > m_mem . m_clut ;
int w = 1 < < m_TEX0 . TW ;
int h = 1 < < m_TEX0 . TH ;
GSTextureSW t ( 0 , w , h ) ;
GSTexture : : GSMap m ;
if ( t . Map ( m , NULL ) )
{
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ m_TEX0 . PSM ] ;
const uint8 * RESTRICT src = ( uint8 * ) m_buff ;
int pitch = 1 < < ( m_tw + ( psm . pal = = 0 ? 2 : 0 ) ) ;
for ( int j = 0 ; j < h ; j + + , src + = pitch , m . bits + = m . pitch )
{
if ( psm . pal = = 0 )
{
memcpy ( m . bits , src , sizeof ( uint32 ) * w ) ;
}
else
{
for ( int i = 0 ; i < w ; i + + )
{
2012-02-14 08:03:27 +00:00
( ( uint32 * ) m . bits ) [ i ] = clut [ src [ i ] ] ;
2011-03-17 02:55:20 +00:00
}
}
}
t . Unmap ( ) ;
2016-09-07 20:10:50 +00:00
return t . Save ( fn ) ;
2011-03-17 02:55:20 +00:00
}
return false ;
2016-10-25 20:49:05 +00:00
}