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 "GSTextureCache.h"
2009-05-22 01:22:52 +00:00
GSTextureCache : : GSTextureCache ( GSRenderer * r )
: m_renderer ( r )
{
2009-07-06 16:35:06 +00:00
m_paltex = ! ! theApp . GetConfig ( " paltex " , 0 ) ;
2009-05-22 01:22:52 +00:00
}
GSTextureCache : : ~ GSTextureCache ( )
{
RemoveAll ( ) ;
}
void GSTextureCache : : RemoveAll ( )
{
2009-06-27 03:32:33 +00:00
m_src . RemoveAll ( ) ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
for ( int type = 0 ; type < 2 ; type + + )
2009-05-22 01:22:52 +00:00
{
2009-07-04 17:37:06 +00:00
for_each ( m_dst [ type ] . begin ( ) , m_dst [ type ] . end ( ) , delete_object ( ) ) ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
m_dst [ type ] . clear ( ) ;
2009-05-22 01:22:52 +00:00
}
}
2009-06-27 03:32:33 +00:00
GSTextureCache : : Source * GSTextureCache : : LookupSource ( const GIFRegTEX0 & TEX0 , const GIFRegTEXA & TEXA , const GSVector4i & r )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ TEX0 . PSM ] ;
const uint32 * clut = m_renderer - > m_mem . m_clut ;
Source * src = NULL ;
2009-05-22 01:22:52 +00:00
2009-07-12 13:46:05 +00:00
list < Source * > & m = m_src . m_map [ TEX0 . TBP0 > > 5 ] ;
2009-05-22 01:22:52 +00:00
2009-07-12 13:46:05 +00:00
for ( list < Source * > : : iterator i = m . begin ( ) ; i ! = m . end ( ) ; i + + )
2009-05-22 01:22:52 +00:00
{
2009-07-12 13:46:05 +00:00
Source * s = * i ;
2009-05-22 01:22:52 +00:00
2009-07-04 15:14:04 +00:00
if ( ( ( TEX0 . u32 [ 0 ] ^ s - > m_TEX0 . u32 [ 0 ] ) | ( ( TEX0 . u32 [ 1 ] ^ s - > m_TEX0 . u32 [ 1 ] ) & 3 ) ) ! = 0 ) // TBP0 TBW PSM TW TH
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
continue ;
2009-05-22 01:22:52 +00:00
}
2009-06-27 03:32:33 +00:00
if ( ( psm . trbpp = = 16 | | psm . trbpp = = 24 ) & & TEX0 . TCC & & TEXA ! = s - > m_TEXA )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
continue ;
2009-05-22 01:22:52 +00:00
}
2009-07-22 03:55:28 +00:00
if ( s - > m_palette = = NULL & & psm . pal > 0 & & ! GSVector4i : : compare64 ( clut , s - > m_clut , psm . pal * sizeof ( clut [ 0 ] ) ) )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
continue ;
2009-05-22 01:22:52 +00:00
}
2009-07-12 13:46:05 +00:00
m . splice ( m . begin ( ) , m , i ) ;
2009-06-27 03:32:33 +00:00
src = s ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
break ;
2009-05-22 01:22:52 +00:00
}
2009-06-27 03:32:33 +00:00
Target * dst = NULL ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
if ( src = = NULL )
2009-05-22 01:22:52 +00:00
{
2009-07-04 15:14:04 +00:00
uint32 bp = TEX0 . TBP0 ;
uint32 psm = TEX0 . PSM ;
2009-06-27 03:32:33 +00:00
for ( int type = 0 ; type < 2 & & dst = = NULL ; type + + )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
for ( list < Target * > : : iterator i = m_dst [ type ] . begin ( ) ; i ! = m_dst [ type ] . end ( ) ; i + + )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
Target * t = * i ;
2009-05-22 01:22:52 +00:00
2009-07-04 15:14:04 +00:00
if ( t - > m_used & & t - > m_dirty . empty ( ) & & GSUtil : : HasSharedBits ( bp , psm , t - > m_TEX0 . TBP0 , t - > m_TEX0 . PSM ) )
2009-06-27 03:32:33 +00:00
{
dst = t ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
break ;
}
2009-05-22 01:22:52 +00:00
}
}
}
2009-06-27 03:32:33 +00:00
if ( src = = NULL )
2009-05-22 01:22:52 +00:00
{
2009-07-31 23:59:06 +00:00
src = CreateSource ( TEX0 , TEXA , dst ) ;
2009-05-22 01:22:52 +00:00
2009-07-31 23:59:06 +00:00
if ( src = = NULL )
2009-05-22 01:22:52 +00:00
{
return NULL ;
}
}
2009-06-27 03:32:33 +00:00
if ( psm . pal > 0 )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
int size = psm . pal * sizeof ( clut [ 0 ] ) ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
if ( src - > m_palette )
2009-06-17 11:24:42 +00:00
{
2009-07-06 16:35:06 +00:00
if ( src - > m_initpalette | | ! GSVector4i : : update ( src - > m_clut , clut , size ) )
2009-06-27 03:32:33 +00:00
{
src - > m_palette - > Update ( GSVector4i ( 0 , 0 , psm . pal , 1 ) , src - > m_clut , size ) ;
src - > m_initpalette = false ;
}
2009-06-17 11:24:42 +00:00
}
2009-06-27 03:32:33 +00:00
}
2009-06-17 11:24:42 +00:00
2009-06-27 03:32:33 +00:00
src - > Update ( TEX0 , TEXA , r ) ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
m_src . m_used = true ;
2009-06-09 10:13:28 +00:00
2009-06-27 03:32:33 +00:00
return src ;
}
2009-06-20 20:28:36 +00:00
2009-07-31 23:59:06 +00:00
GSTextureCache : : Target * GSTextureCache : : LookupTarget ( const GIFRegTEX0 & TEX0 , int w , int h , int type , bool used )
2009-06-27 03:32:33 +00:00
{
2009-07-04 15:14:04 +00:00
uint32 bp = TEX0 . TBP0 ;
2009-06-27 03:32:33 +00:00
Target * dst = NULL ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
for ( list < Target * > : : iterator i = m_dst [ type ] . begin ( ) ; i ! = m_dst [ type ] . end ( ) ; i + + )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
Target * t = * i ;
2009-05-22 01:22:52 +00:00
2009-07-04 15:14:04 +00:00
if ( bp = = t - > m_TEX0 . TBP0 )
2009-06-27 03:32:33 +00:00
{
m_dst [ type ] . splice ( m_dst [ type ] . begin ( ) , m_dst [ type ] , i ) ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
dst = t ;
2009-05-22 01:22:52 +00:00
2009-07-31 23:59:06 +00:00
dst - > m_TEX0 = TEX0 ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
break ;
2009-05-22 01:22:52 +00:00
}
}
2009-06-27 03:32:33 +00:00
if ( dst = = NULL )
2009-05-22 01:22:52 +00:00
{
2009-07-31 23:59:06 +00:00
dst = CreateTarget ( TEX0 , w , h , type ) ;
2009-06-27 03:32:33 +00:00
2009-07-31 23:59:06 +00:00
if ( dst = = NULL )
2009-05-22 01:22:52 +00:00
{
return NULL ;
}
2009-06-27 03:32:33 +00:00
}
else
{
dst - > Update ( ) ;
2009-05-22 01:22:52 +00:00
}
2009-06-27 03:32:33 +00:00
if ( m_renderer - > CanUpscale ( ) )
2009-05-22 01:22:52 +00:00
{
2009-10-26 15:52:45 +00:00
int multiplier = m_renderer - > upscale_Multiplier ( ) ;
2009-10-21 22:57:20 +00:00
if ( multiplier > 1 ) //it's limited to a maximum of 4 on reading the config
2009-05-22 01:22:52 +00:00
{
2009-10-21 22:57:20 +00:00
dst - > m_texture - > SetScale ( GSVector2 ( ( float ) multiplier , ( float ) multiplier ) ) ;
2009-06-27 03:32:33 +00:00
}
2009-10-21 22:57:20 +00:00
else
2009-06-27 03:32:33 +00:00
{
2009-07-31 23:59:06 +00:00
2009-10-21 22:57:20 +00:00
GSVector4i fr = m_renderer - > GetFrameRect ( ) ;
int ww = ( int ) ( fr . left + dst - > m_TEX0 . TBW * 64 ) ;
int hh = ( int ) ( fr . top + m_renderer - > GetDisplayRect ( ) . height ( ) ) ;
if ( hh < = m_renderer - > GetDeviceSize ( ) . y / 2 )
{
hh * = 2 ;
}
if ( hh < 512 & & m_renderer - > m_context - > SCISSOR . SCAY1 = = 511 ) // vp2
{
hh = 512 ;
}
if ( ww > 0 & & hh > 0 )
{
dst - > m_texture - > SetScale ( GSVector2 ( ( float ) w / ww , ( float ) h / hh ) ) ;
}
2009-05-22 01:22:52 +00:00
}
}
2009-06-27 03:32:33 +00:00
if ( used )
{
dst - > m_used = true ;
}
2009-06-09 10:13:28 +00:00
2009-06-27 03:32:33 +00:00
return dst ;
2009-05-22 01:22:52 +00:00
}
2009-07-31 23:59:06 +00:00
GSTextureCache : : Target * GSTextureCache : : LookupTarget ( const GIFRegTEX0 & TEX0 , int w , int h )
{
uint32 bp = TEX0 . TBP0 ;
Target * dst = NULL ;
for ( list < Target * > : : iterator i = m_dst [ RenderTarget ] . begin ( ) ; i ! = m_dst [ RenderTarget ] . end ( ) ; i + + )
{
Target * t = * i ;
if ( bp = = t - > m_TEX0 . TBP0 )
{
dst = t ;
break ;
}
else
{
// HACK: try to find something close to the base pointer
if ( t - > m_TEX0 . TBP0 < = bp & & bp < t - > m_TEX0 . TBP0 + 0x700 & & ( ! dst | | t - > m_TEX0 . TBP0 > = dst - > m_TEX0 . TBP0 ) )
{
dst = t ;
}
}
}
if ( dst = = NULL )
{
dst = CreateTarget ( TEX0 , w , h , RenderTarget ) ;
if ( dst = = NULL )
{
return NULL ;
}
}
else
{
dst - > Update ( ) ;
}
dst - > m_used = true ;
return dst ;
}
2009-07-22 03:55:28 +00:00
void GSTextureCache : : InvalidateVideoMem ( const GSOffset * o , const GSVector4i & rect , bool target )
2009-05-22 01:22:52 +00:00
{
2009-07-22 03:55:28 +00:00
uint32 bp = o - > bp ;
uint32 bw = o - > bw ;
uint32 psm = o - > psm ;
2009-07-04 15:14:04 +00:00
GSVector2i bs = ( bp & 31 ) = = 0 ? GSLocalMemory : : m_psm [ psm ] . pgs : GSLocalMemory : : m_psm [ psm ] . bs ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
GSVector4i r = rect . ralign < GSVector4i : : Outside > ( bs ) ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
if ( ! target )
2009-05-22 01:22:52 +00:00
{
2009-07-12 13:46:05 +00:00
const list < Source * > & m = m_src . m_map [ bp > > 5 ] ;
2009-05-22 01:22:52 +00:00
2009-07-12 13:46:05 +00:00
for ( list < Source * > : : const_iterator i = m . begin ( ) ; i ! = m . end ( ) ; )
2009-05-22 01:22:52 +00:00
{
2009-07-12 13:46:05 +00:00
list < Source * > : : const_iterator j = i + + ;
2009-05-22 01:22:52 +00:00
2009-07-12 13:46:05 +00:00
Source * s = * j ;
2009-06-27 03:32:33 +00:00
2009-07-04 15:14:04 +00:00
if ( GSUtil : : HasSharedBits ( bp , psm , s - > m_TEX0 . TBP0 , s - > m_TEX0 . PSM ) )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
m_src . RemoveAt ( s ) ;
2009-05-22 01:22:52 +00:00
}
}
2009-06-27 03:32:33 +00:00
}
2009-07-04 15:14:04 +00:00
bool found = false ;
2009-06-27 03:32:33 +00:00
for ( int y = r . top ; y < r . bottom ; y + = bs . y )
{
2009-07-22 03:55:28 +00:00
uint32 base = o - > block . row [ y > > 3 ] ;
2009-06-27 03:32:33 +00:00
for ( int x = r . left ; x < r . right ; x + = bs . x )
2009-05-22 01:22:52 +00:00
{
2009-07-22 03:55:28 +00:00
uint32 page = ( base + o - > block . col [ x > > 3 ] ) > > 5 ;
2009-06-27 03:32:33 +00:00
if ( page < MAX_PAGES )
2009-05-22 01:22:52 +00:00
{
2009-07-12 13:46:05 +00:00
const list < Source * > & m = m_src . m_map [ page ] ;
2009-05-22 01:22:52 +00:00
2009-07-12 13:46:05 +00:00
for ( list < Source * > : : const_iterator i = m . begin ( ) ; i ! = m . end ( ) ; )
2009-05-22 01:22:52 +00:00
{
2009-07-12 13:46:05 +00:00
list < Source * > : : const_iterator j = i + + ;
2009-05-22 01:22:52 +00:00
2009-07-12 13:46:05 +00:00
Source * s = * j ;
2009-05-22 01:22:52 +00:00
2009-07-04 15:14:04 +00:00
if ( GSUtil : : HasSharedBits ( psm , s - > m_TEX0 . PSM ) )
2009-05-22 01:22:52 +00:00
{
2009-07-04 15:14:04 +00:00
bool b = bp = = s - > m_TEX0 . TBP0 ;
2009-06-27 03:32:33 +00:00
if ( ! s - > m_target )
{
2009-07-01 21:14:12 +00:00
s - > m_valid [ page ] = 0 ;
s - > m_complete = false ;
2009-06-27 03:32:33 +00:00
2009-07-04 15:14:04 +00:00
found = b ;
2009-06-27 03:32:33 +00:00
}
else
{
2009-07-02 00:47:50 +00:00
// TODO
2009-07-04 15:14:04 +00:00
if ( b )
2009-06-27 03:32:33 +00:00
{
m_src . RemoveAt ( s ) ;
}
}
2009-05-22 01:22:52 +00:00
}
}
}
}
}
2009-06-27 03:32:33 +00:00
if ( ! target ) return ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
for ( int type = 0 ; type < 2 ; type + + )
{
for ( list < Target * > : : iterator i = m_dst [ type ] . begin ( ) ; i ! = m_dst [ type ] . end ( ) ; )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
list < Target * > : : iterator j = i + + ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
Target * t = * j ;
2009-05-22 01:22:52 +00:00
2009-07-04 15:14:04 +00:00
if ( GSUtil : : HasSharedBits ( bp , psm , t - > m_TEX0 . TBP0 , t - > m_TEX0 . PSM ) )
2009-05-22 01:22:52 +00:00
{
2009-07-04 15:14:04 +00:00
if ( ! found & & GSUtil : : HasCompatibleBits ( psm , t - > m_TEX0 . PSM ) )
2009-05-22 01:22:52 +00:00
{
2009-07-04 15:14:04 +00:00
t - > m_dirty . push_back ( GSDirtyRect ( r , psm ) ) ;
t - > m_TEX0 . TBW = bw ;
2009-06-27 03:32:33 +00:00
}
else
{
m_dst [ type ] . erase ( j ) ;
delete t ;
2009-05-22 01:22:52 +00:00
continue ;
}
}
2009-07-04 15:14:04 +00:00
if ( GSUtil : : HasSharedBits ( psm , t - > m_TEX0 . PSM ) & & bp < t - > m_TEX0 . TBP0 )
2009-05-22 01:22:52 +00:00
{
2009-07-04 15:14:04 +00:00
uint32 rowsize = bw * 8192 ;
uint32 offset = ( uint32 ) ( ( t - > m_TEX0 . TBP0 - bp ) * 256 ) ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
if ( rowsize > 0 & & offset % rowsize = = 0 )
2009-05-22 01:22:52 +00:00
{
2009-07-04 15:14:04 +00:00
int y = GSLocalMemory : : m_psm [ psm ] . pgs . y * offset / rowsize ;
2009-06-27 03:32:33 +00:00
if ( r . bottom > y )
{
// TODO: do not add this rect above too
2009-07-04 15:14:04 +00:00
t - > m_dirty . push_back ( GSDirtyRect ( GSVector4i ( r . left , r . top - y , r . right , r . bottom - y ) , psm ) ) ;
t - > m_TEX0 . TBW = bw ;
2009-06-27 03:32:33 +00:00
continue ;
}
2009-05-22 01:22:52 +00:00
}
}
}
}
}
2009-07-22 03:55:28 +00:00
void GSTextureCache : : InvalidateLocalMem ( const GSOffset * o , const GSVector4i & r )
2009-05-22 01:22:52 +00:00
{
2009-07-22 03:55:28 +00:00
uint32 bp = o - > bp ;
uint32 psm = o - > psm ;
2009-07-04 15:14:04 +00:00
2009-06-27 03:32:33 +00:00
for ( list < Target * > : : iterator i = m_dst [ RenderTarget ] . begin ( ) ; i ! = m_dst [ RenderTarget ] . end ( ) ; )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
list < Target * > : : iterator j = i + + ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
Target * t = * j ;
2009-05-22 01:22:52 +00:00
2009-07-04 15:14:04 +00:00
if ( GSUtil : : HasSharedBits ( bp , psm , t - > m_TEX0 . TBP0 , t - > m_TEX0 . PSM ) )
2009-05-22 01:22:52 +00:00
{
2009-07-04 15:14:04 +00:00
if ( GSUtil : : HasCompatibleBits ( psm , t - > m_TEX0 . PSM ) )
2009-05-22 01:22:52 +00:00
{
2009-07-31 23:59:06 +00:00
Read ( t , r . rintersect ( t - > m_valid ) ) ;
2009-06-27 03:32:33 +00:00
2009-05-22 01:22:52 +00:00
return ;
}
2009-07-04 15:14:04 +00:00
else if ( psm = = PSM_PSMCT32 & & ( t - > m_TEX0 . PSM = = PSM_PSMCT16 | | t - > m_TEX0 . PSM = = PSM_PSMCT16S ) )
2009-05-22 01:22:52 +00:00
{
// ffx-2 riku changing to her default (shoots some reflecting glass at the end), 16-bit rt read as 32-bit
2009-07-31 23:59:06 +00:00
Read ( t , GSVector4i ( r . left , r . top , r . right , r . top + ( r . bottom - r . top ) * 2 ) . rintersect ( t - > m_valid ) ) ;
2009-06-27 03:32:33 +00:00
2009-05-22 01:22:52 +00:00
return ;
}
else
{
2009-06-27 03:32:33 +00:00
m_dst [ RenderTarget ] . erase ( j ) ;
delete t ;
2009-05-22 01:22:52 +00:00
}
}
}
/*
// no good, ffx does a lot of readback after exiting menu, at 0x02f00 this wrongly finds rt 0x02100 (0,448 - 512,480)
GSRenderTarget * rt2 = NULL ;
int ymin = INT_MAX ;
pos = m_rt . GetHeadPosition ( ) ;
while ( pos )
{
GSRenderTarget * rt = m_rt . GetNext ( pos ) ;
if ( HasSharedBits ( BITBLTBUF . SPSM , rt - > m_TEX0 . PSM ) & & BITBLTBUF . SBP > rt - > m_TEX0 . TBP0 )
{
// ffx2 pause screen background
uint32 rowsize = BITBLTBUF . SBW * 8192 ;
uint32 offset = ( uint32 ) ( ( BITBLTBUF . SBP - rt - > m_TEX0 . TBP0 ) * 256 ) ;
if ( rowsize > 0 & & offset % rowsize = = 0 )
{
2009-06-27 03:32:33 +00:00
int y = GSLocalMemory : : m_psm [ BITBLTBUF . SPSM ] . pgs . y * offset / rowsize ;
2009-05-22 01:22:52 +00:00
if ( y < ymin & & y < 512 )
{
rt2 = rt ;
ymin = y ;
}
}
}
}
if ( rt2 )
{
rt2 - > Read ( GSVector4i ( r . left , r . top + ymin , r . right , r . bottom + ymin ) ) ;
}
// TODO: ds
*/
}
2009-11-06 17:13:36 +00:00
2009-05-22 01:22:52 +00:00
void GSTextureCache : : IncAge ( )
{
2009-06-27 03:32:33 +00:00
int maxage = m_src . m_used ? 3 : 30 ;
2009-07-16 21:36:07 +00:00
for ( hash_set < Source * > : : iterator i = m_src . m_surfaces . begin ( ) ; i ! = m_src . m_surfaces . end ( ) ; )
2009-06-27 03:32:33 +00:00
{
2009-07-16 21:36:07 +00:00
hash_set < Source * > : : iterator j = i + + ;
2009-06-09 10:13:28 +00:00
2009-07-16 21:36:07 +00:00
Source * s = * j ;
2009-06-27 03:32:33 +00:00
if ( + + s - > m_age > maxage )
{
m_src . RemoveAt ( s ) ;
}
}
m_src . m_used = false ;
2009-11-06 17:13:36 +00:00
// Clearing of Rendertargets causes flickering in many scene transitions, so let's not :p
//maxage = 4; // ffx intro scene changes leave the old image untouched for a couple of frames and only then start using it
2009-06-27 03:32:33 +00:00
2009-11-06 17:13:36 +00:00
//for(int type = 0; type < 2; type++)
//{
// for(list<Target*>::iterator i = m_dst[type].begin(); i != m_dst[type].end(); )
// {
// list<Target*>::iterator j = i++;
2009-06-27 03:32:33 +00:00
2009-11-06 17:13:36 +00:00
// Target* t = *j;
2009-06-27 03:32:33 +00:00
2009-11-06 17:13:36 +00:00
// if(++t->m_age > maxage)
// {
// m_dst[type].erase(j);
2009-06-27 03:32:33 +00:00
2009-11-06 17:13:36 +00:00
// delete t;
// }
// }
//}
2009-05-22 01:22:52 +00:00
}
2009-11-09 00:32:52 +00:00
//Fixme: Several issues in here. Not handling depth stencil, pitch conversion doesnt work.
//The alternative version isn't much better though :p
# if 1
2009-07-31 23:59:06 +00:00
GSTextureCache : : Source * GSTextureCache : : CreateSource ( const GIFRegTEX0 & TEX0 , const GIFRegTEXA & TEXA , Target * dst )
2009-05-22 01:22:52 +00:00
{
2009-07-31 23:59:06 +00:00
Source * src = new Source ( m_renderer ) ;
2009-05-22 01:22:52 +00:00
2009-07-31 23:59:06 +00:00
src - > m_TEX0 = TEX0 ;
src - > m_TEXA = TEXA ;
2009-05-22 01:22:52 +00:00
2009-07-31 23:59:06 +00:00
int tw = 1 < < TEX0 . TW ;
int th = 1 < < TEX0 . TH ;
int tp = ( int ) TEX0 . TW < < 6 ;
2009-06-27 03:32:33 +00:00
2009-07-31 23:59:06 +00:00
if ( dst = = NULL )
{
if ( m_paltex & & GSLocalMemory : : m_psm [ TEX0 . PSM ] . pal > 0 )
{
2009-09-18 00:16:52 +00:00
src - > m_fmt = FMT_8 ;
2009-06-28 02:02:14 +00:00
2009-07-31 23:59:06 +00:00
src - > m_texture = m_renderer - > m_dev - > CreateTexture ( tw , th , Get8bitFormat ( ) ) ;
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
}
else
{
2009-09-18 00:16:52 +00:00
src - > m_fmt = FMT_32 ;
2009-05-22 01:22:52 +00:00
2009-07-31 23:59:06 +00:00
src - > m_texture = m_renderer - > m_dev - > CreateTexture ( tw , th ) ;
}
}
else
{
// TODO: clean up this mess
2009-05-22 01:22:52 +00:00
2009-07-31 23:59:06 +00:00
src - > m_target = true ;
2009-06-28 02:02:14 +00:00
2009-07-31 23:59:06 +00:00
if ( dst - > m_type ! = RenderTarget )
{
// TODO
2009-05-22 01:22:52 +00:00
2009-07-31 23:59:06 +00:00
delete src ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
return NULL ;
}
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
dst - > Update ( ) ;
2009-07-06 16:35:06 +00:00
2009-08-02 23:07:30 +00:00
GSTexture * tmp = NULL ;
if ( dst - > m_texture - > IsMSAA ( ) )
{
tmp = dst - > m_texture ;
dst - > m_texture = m_renderer - > m_dev - > Resolve ( dst - > m_texture ) ;
}
2009-07-31 23:59:06 +00:00
// do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows)
2009-07-06 16:35:06 +00:00
2009-08-02 23:07:30 +00:00
int w = ( int ) ( dst - > m_texture - > GetScale ( ) . x * tw ) ;
int h = ( int ) ( dst - > m_texture - > GetScale ( ) . y * th ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
GSVector2i dstsize = dst - > m_texture - > GetSize ( ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
// pitch conversion
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
if ( dst - > m_TEX0 . TBW ! = TEX0 . TBW ) // && dst->m_TEX0.PSM == TEX0.PSM
{
2009-10-22 01:52:41 +00:00
//Better not do the code below, "fixes" like every game that ever gets here..
delete src ; return NULL ;
2009-07-31 23:59:06 +00:00
// sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left)
2009-07-06 16:35:06 +00:00
2009-11-09 00:32:52 +00:00
ASSERT ( dst - > m_TEX0 . TBW > TEX0 . TBW ) ; // otherwise scale.x need to be reduced to make the larger texture fit (TODO)
2009-07-06 16:35:06 +00:00
2009-08-02 23:07:30 +00:00
src - > m_texture = m_renderer - > m_dev - > CreateRenderTarget ( dstsize . x , dstsize . y , false ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
GSVector4 size = GSVector4 ( dstsize ) . xyxy ( ) ;
2009-08-02 23:07:30 +00:00
GSVector4 scale = GSVector4 ( dst - > m_texture - > GetScale ( ) ) . xyxy ( ) ;
2009-07-06 16:35:06 +00:00
2009-10-21 12:36:32 +00:00
int blockWidth = 64 ;
int blockHeight = TEX0 . PSM = = PSM_PSMCT32 | | TEX0 . PSM = = PSM_PSMCT24 ? 32 : 64 ;
2009-07-06 16:35:06 +00:00
2009-10-21 12:36:32 +00:00
GSVector4i br ( 0 , 0 , blockWidth , blockHeight ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
int sw = ( int ) dst - > m_TEX0 . TBW < < 6 ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
int dw = ( int ) TEX0 . TBW < < 6 ;
int dh = 1 < < TEX0 . TH ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
if ( sw ! = 0 )
2009-10-21 12:36:32 +00:00
for ( int dy = 0 ; dy < dh ; dy + = blockHeight )
2009-07-31 23:59:06 +00:00
{
2009-10-21 12:36:32 +00:00
for ( int dx = 0 ; dx < dw ; dx + = blockWidth )
2009-07-31 23:59:06 +00:00
{
2009-10-21 12:36:32 +00:00
int o = dy * dw / blockHeight + dx ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
int sx = o % sw ;
int sy = o / sw ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
GSVector4 sr = GSVector4 ( GSVector4i ( sx , sy ) . xyxy ( ) + br ) * scale / size ;
GSVector4 dr = GSVector4 ( GSVector4i ( dx , dy ) . xyxy ( ) + br ) * scale ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
m_renderer - > m_dev - > StretchRect ( dst - > m_texture , sr , src - > m_texture , dr ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
// TODO: this is quite a lot of StretchRect, do it with one Draw
}
}
}
2009-10-24 18:39:36 +00:00
else if ( tw < tp )
{
// FIXME: timesplitters blurs the render target by blending itself over a couple of times
if ( tw = = 256 & & th = = 128 & & tp = = 512 & & ( TEX0 . TBP0 = = 0 | | TEX0 . TBP0 = = 0x00e00 ) )
{
delete src ;
return false ;
}
}
2009-07-31 23:59:06 +00:00
// width/height conversion
2009-07-06 16:35:06 +00:00
2009-08-02 23:07:30 +00:00
GSVector2 scale = dst - > m_texture - > GetScale ( ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
GSVector4 dr ( 0 , 0 , w , h ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
if ( w > dstsize . x )
{
scale . x = ( float ) dstsize . x / tw ;
2009-08-02 23:07:30 +00:00
dr . z = ( float ) dstsize . x * scale . x / dst - > m_texture - > GetScale ( ) . x ;
2009-07-31 23:59:06 +00:00
w = dstsize . x ;
}
if ( h > dstsize . y )
{
scale . y = ( float ) dstsize . y / th ;
2009-08-02 23:07:30 +00:00
dr . w = ( float ) dstsize . y * scale . y / dst - > m_texture - > GetScale ( ) . y ;
2009-07-31 23:59:06 +00:00
h = dstsize . y ;
}
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
GSVector4 sr ( 0 , 0 , w , h ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
GSTexture * st = src - > m_texture ? src - > m_texture : dst - > m_texture ;
2009-08-02 23:07:30 +00:00
GSTexture * dt = m_renderer - > m_dev - > CreateRenderTarget ( w , h , false ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
if ( ! src - > m_texture )
2009-07-06 16:35:06 +00:00
{
2009-07-31 23:59:06 +00:00
src - > m_texture = dt ;
}
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
if ( ( sr = = dr ) . alltrue ( ) )
{
m_renderer - > m_dev - > CopyRect ( st , dt , GSVector4i ( 0 , 0 , w , h ) ) ;
}
else
{
2009-08-02 23:07:30 +00:00
sr . z / = st - > GetWidth ( ) ;
sr . w / = st - > GetHeight ( ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
m_renderer - > m_dev - > StretchRect ( st , sr , dt , dr ) ;
}
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
if ( dt ! = src - > m_texture )
{
m_renderer - > m_dev - > Recycle ( src - > m_texture ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
src - > m_texture = dt ;
2009-07-06 16:35:06 +00:00
}
2009-08-02 23:07:30 +00:00
src - > m_texture - > SetScale ( scale ) ;
2009-07-31 23:59:06 +00:00
switch ( TEX0 . PSM )
2009-07-06 16:35:06 +00:00
{
2009-07-31 23:59:06 +00:00
default :
2009-10-14 16:42:59 +00:00
// Note: this assertion triggers in Xenosaga2 after the first intro scenes, when
// gameplay first begins (in the city).
2009-07-31 23:59:06 +00:00
ASSERT ( 0 ) ;
case PSM_PSMCT32 :
2009-09-18 00:16:52 +00:00
src - > m_fmt = FMT_32 ;
2009-07-31 23:59:06 +00:00
break ;
case PSM_PSMCT24 :
2009-09-18 00:16:52 +00:00
src - > m_fmt = FMT_24 ;
2009-07-31 23:59:06 +00:00
break ;
case PSM_PSMCT16 :
case PSM_PSMCT16S :
2009-09-18 00:16:52 +00:00
src - > m_fmt = FMT_16 ;
2009-07-31 23:59:06 +00:00
break ;
case PSM_PSMT8H :
2009-09-18 00:16:52 +00:00
src - > m_fmt = FMT_8H ;
2009-07-31 23:59:06 +00:00
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
break ;
2009-10-21 12:36:32 +00:00
case PSM_PSMT8 :
//Not sure, this wasn't handled at all.
//Xenosaga 2 and 3 use it, Tales of Legendia as well.
//It's always used for fog like effects.
src - > m_fmt = FMT_8 ;
2009-10-22 01:52:41 +00:00
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
2009-10-21 12:36:32 +00:00
break ;
2009-07-31 23:59:06 +00:00
case PSM_PSMT4HL :
2009-09-18 00:16:52 +00:00
src - > m_fmt = FMT_4HL ;
2009-07-31 23:59:06 +00:00
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
break ;
case PSM_PSMT4HH :
2009-09-18 00:16:52 +00:00
src - > m_fmt = FMT_4HH ;
2009-07-31 23:59:06 +00:00
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
break ;
2009-07-06 16:35:06 +00:00
}
2009-08-02 23:07:30 +00:00
if ( tmp ! = NULL )
{
m_renderer - > m_dev - > Recycle ( dst - > m_texture ) ;
dst - > m_texture = tmp ;
}
2009-07-06 16:35:06 +00:00
}
2009-07-31 23:59:06 +00:00
if ( src - > m_texture = = NULL )
{
ASSERT ( 0 ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
return NULL ;
}
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ TEX0 . PSM ] ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
if ( psm . pal > 0 )
2009-07-06 16:35:06 +00:00
{
2009-07-31 23:59:06 +00:00
memcpy ( src - > m_clut , ( const uint32 * ) m_renderer - > m_mem . m_clut , psm . pal * sizeof ( uint32 ) ) ;
2009-07-06 16:35:06 +00:00
}
2009-07-31 23:59:06 +00:00
m_src . Add ( src , TEX0 , m_renderer - > m_context - > offset . tex ) ;
return src ;
}
2009-11-09 00:32:52 +00:00
# else
//WIP fog / blur / depth of field handling.
GSTextureCache : : Source * GSTextureCache : : CreateSource ( const GIFRegTEX0 & TEX0 , const GIFRegTEXA & TEXA , Target * dst )
{
Source * src = new Source ( m_renderer ) ;
src - > m_TEX0 = TEX0 ;
src - > m_TEXA = TEXA ;
int tw = 1 < < TEX0 . TW ;
int th = 1 < < TEX0 . TH ;
int tp = ( int ) TEX0 . TW < < 6 ;
if ( dst = = NULL )
{
if ( m_paltex & & GSLocalMemory : : m_psm [ TEX0 . PSM ] . pal > 0 )
{
src - > m_fmt = FMT_8 ;
src - > m_texture = m_renderer - > m_dev - > CreateTexture ( tw , th , Get8bitFormat ( ) ) ;
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
}
else
{
src - > m_fmt = FMT_32 ;
src - > m_texture = m_renderer - > m_dev - > CreateTexture ( tw , th ) ;
}
}
else
{
// TODO: clean up this mess
src - > m_target = true ;
dst - > Update ( ) ;
if ( dst - > m_type ! = RenderTarget )
{
//src->m_target = false; //no idea what depth stencil needs ><
//printf("type stencil\n");
}
GSTexture * tmp = NULL ;
if ( dst - > m_texture - > IsMSAA ( ) )
{
tmp = dst - > m_texture ;
dst - > m_texture = m_renderer - > m_dev - > Resolve ( dst - > m_texture ) ;
}
// do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows)
int w = ( int ) ( dst - > m_texture - > GetScale ( ) . x * tw ) ;
int h = ( int ) ( dst - > m_texture - > GetScale ( ) . y * th ) ;
GSVector2i dstsize = dst - > m_texture - > GetSize ( ) ;
//Hacked up to figure out how fog / depth / blur effects are done. Works in Xenosaga 3.
if ( ( tw = = 1024 & & th = = 1024 ) & & dst - > m_TEX0 . TBW ! = TEX0 . TBW ) {
if ( dst - > m_type ! = RenderTarget )
{
src - > m_texture = m_renderer - > m_dev - > CreateDepthStencil ( dstsize . x , dstsize . y , false ) ;
}
else {
src - > m_texture = m_renderer - > m_dev - > CreateRenderTarget ( dstsize . x , dstsize . y , false ) ;
}
GSVector4 size = GSVector4 ( dstsize ) . xyxy ( ) * 2 ; // * 2 to force the effect overlay into the right position
GSVector4 scale = GSVector4 ( dst - > m_texture - > GetScale ( ) ) . xyxy ( ) ; //Not needed right now, but good for testing
GSVector4 br ( 0.0f , 0.0f , 1024.0f , 1024.0f ) ; // entire RT
GSVector4 sr = br * scale / size ;
GSVector4 dr = br * scale ;
m_renderer - > m_dev - > StretchRect ( dst - > m_texture , sr , src - > m_texture , dr ) ;
}
// pitch conversion
else if ( dst - > m_TEX0 . TBW ! = TEX0 . TBW ) // && dst->m_TEX0.PSM == TEX0.PSM
{
// sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left)
// ASSERT(dst->m_TEX0.TBW > TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO)
if ( dst - > m_type ! = RenderTarget )
{
src - > m_texture = m_renderer - > m_dev - > CreateDepthStencil ( dstsize . x , dstsize . y , false ) ;
}
else {
src - > m_texture = m_renderer - > m_dev - > CreateRenderTarget ( dstsize . x , dstsize . y , false ) ;
}
GSVector4 size = GSVector4 ( dstsize ) . xyxy ( ) ;
GSVector4 scale = GSVector4 ( dst - > m_texture - > GetScale ( ) ) . xyxy ( ) ;
if ( dst - > m_TEX0 . TBW < TEX0 . TBW ) // otherwise scale.x need to be reduced to make the larger texture fit
{
scale . x = ( ( float ) dst - > m_TEX0 . TBW / ( float ) TEX0 . TBW ) ;
//printf("scale.x = %f \n", scale.x);
}
int blockWidth = 64 ;
int blockHeight = TEX0 . PSM = = PSM_PSMCT32 | | TEX0 . PSM = = PSM_PSMCT24 ? 32 : 64 ;
GSVector4i br ( 0 , 0 , blockWidth , blockHeight ) ;
int sw = ( int ) dst - > m_TEX0 . TBW < < 6 ;
int dw = ( int ) TEX0 . TBW < < 6 ;
int dh = 1 < < TEX0 . TH ;
if ( sw ! = 0 )
for ( int dy = 0 ; dy < dh ; dy + = blockHeight )
{
for ( int dx = 0 ; dx < dw ; dx + = blockWidth )
{
int o = dy * dw / blockHeight + dx ;
int sx = o % sw ;
int sy = o / sw ;
//printf("sx = %d ,sy = %d ,sw = %d ,o = %d \n",sx,sy,sw,o);
GSVector4 sr = GSVector4 ( GSVector4i ( sx , sy ) . xyxy ( ) + br ) * scale / size ;
GSVector4 dr = GSVector4 ( GSVector4i ( dx , dy ) . xyxy ( ) + br ) * scale ;
m_renderer - > m_dev - > StretchRect ( dst - > m_texture , sr , src - > m_texture , dr ) ;
// TODO: this is quite a lot of StretchRect, do it with one Draw
}
}
}
else if ( tw < tp )
{
// FIXME: timesplitters blurs the render target by blending itself over a couple of times
2009-11-01 11:42:12 +00:00
2009-11-09 00:32:52 +00:00
if ( tw = = 256 & & th = = 128 & & tp = = 512 & & ( TEX0 . TBP0 = = 0 | | TEX0 . TBP0 = = 0x00e00 ) )
{
delete src ;
return false ;
}
}
2009-07-06 16:35:06 +00:00
2009-11-09 00:32:52 +00:00
// width/height conversion
GSVector2 scale = dst - > m_texture - > GetScale ( ) ;
GSVector4 dr ( 0 , 0 , w , h ) ;
//if(dst->m_type != RenderTarget) {
if ( w > dstsize . x )
{
scale . x = ( float ) dstsize . x / tw ;
dr . z = ( float ) dstsize . x * scale . x / dst - > m_texture - > GetScale ( ) . x ;
w = dstsize . x ;
}
if ( h > dstsize . y )
{
scale . y = ( float ) dstsize . y / th ;
dr . w = ( float ) dstsize . y * scale . y / dst - > m_texture - > GetScale ( ) . y ;
h = dstsize . y ;
}
//}
GSVector4 sr ( 0 , 0 , w , h ) ;
GSTexture * st = src - > m_texture ? src - > m_texture : dst - > m_texture ;
GSTexture * dt ;
if ( dst - > m_type = = RenderTarget ) dt = m_renderer - > m_dev - > CreateRenderTarget ( w , h , false ) ;
else dt = m_renderer - > m_dev - > CreateDepthStencil ( w , h , false ) ;
if ( ! src - > m_texture )
{
src - > m_texture = dt ;
}
if ( ( sr = = dr ) . alltrue ( ) )
{
m_renderer - > m_dev - > CopyRect ( st , dt , GSVector4i ( 0 , 0 , w , h ) ) ;
}
else
{
sr . z / = st - > GetWidth ( ) ;
sr . w / = st - > GetHeight ( ) ;
m_renderer - > m_dev - > StretchRect ( st , sr , dt , dr ) ;
}
if ( dt ! = src - > m_texture )
{
m_renderer - > m_dev - > Recycle ( src - > m_texture ) ;
src - > m_texture = dt ;
}
src - > m_texture - > SetScale ( scale ) ;
switch ( TEX0 . PSM )
{
default :
// Unhandled texture format
ASSERT ( 0 ) ;
case PSM_PSMCT32 :
src - > m_fmt = FMT_32 ;
break ;
case PSM_PSMCT24 :
src - > m_fmt = FMT_24 ;
break ;
case PSM_PSMCT16 :
case PSM_PSMCT16S :
src - > m_fmt = FMT_16 ;
break ;
case PSM_PSMZ32 :
src - > m_fmt = FMT_32 ;
break ;
case PSM_PSMZ24 :
src - > m_fmt = FMT_24 ;
break ;
case PSM_PSMZ16 :
src - > m_fmt = FMT_16 ;
break ;
case PSM_PSMT8H :
src - > m_fmt = FMT_8H ;
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
break ;
case PSM_PSMT8 :
//Not sure, this wasn't handled at all.
//Xenosaga 2 and 3 use it, Tales of Legendia as well.
//It's always used for fog like effects.
src - > m_fmt = FMT_8 ;
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
break ;
case PSM_PSMT4HL :
src - > m_fmt = FMT_4HL ;
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
break ;
case PSM_PSMT4HH :
src - > m_fmt = FMT_4HH ;
src - > m_palette = m_renderer - > m_dev - > CreateTexture ( 256 , 1 ) ;
break ;
}
if ( tmp ! = NULL )
{
m_renderer - > m_dev - > Recycle ( dst - > m_texture ) ;
dst - > m_texture = tmp ;
}
}
if ( src - > m_texture = = NULL )
{
ASSERT ( 0 ) ;
return NULL ;
}
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ TEX0 . PSM ] ;
if ( psm . pal > 0 )
{
memcpy ( src - > m_clut , ( const uint32 * ) m_renderer - > m_mem . m_clut , psm . pal * sizeof ( uint32 ) ) ;
}
m_src . Add ( src , TEX0 , m_renderer - > m_context - > offset . tex ) ;
return src ;
}
# endif
2009-07-31 23:59:06 +00:00
GSTextureCache : : Target * GSTextureCache : : CreateTarget ( const GIFRegTEX0 & TEX0 , int w , int h , int type )
{
Target * t = new Target ( m_renderer ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
t - > m_TEX0 = TEX0 ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
// FIXME: initial data should be unswizzled from local mem in Update() if dirty
t - > m_type = type ;
if ( type = = RenderTarget )
2009-07-06 16:35:06 +00:00
{
2009-08-02 23:07:30 +00:00
t - > m_texture = m_renderer - > m_dev - > CreateRenderTarget ( w , h , true ) ;
2009-07-31 23:59:06 +00:00
t - > m_used = true ; // FIXME
2009-07-06 16:35:06 +00:00
}
2009-07-31 23:59:06 +00:00
else if ( type = = DepthStencil )
2009-07-06 16:35:06 +00:00
{
2009-08-02 23:07:30 +00:00
t - > m_texture = m_renderer - > m_dev - > CreateDepthStencil ( w , h , true ) ;
2009-07-06 16:35:06 +00:00
}
2009-07-31 23:59:06 +00:00
if ( t - > m_texture = = NULL )
2009-07-06 16:35:06 +00:00
{
2009-07-31 23:59:06 +00:00
ASSERT ( 0 ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
return NULL ;
2009-07-06 16:35:06 +00:00
}
2009-07-31 23:59:06 +00:00
m_dst [ type ] . push_front ( t ) ;
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
return t ;
}
// GSTextureCache::Surface
2009-07-06 16:35:06 +00:00
2009-07-31 23:59:06 +00:00
GSTextureCache : : Surface : : Surface ( GSRenderer * r )
: m_renderer ( r )
, m_texture ( NULL )
, m_age ( 0 )
{
m_TEX0 . TBP0 = ( uint32 ) ~ 0 ;
}
GSTextureCache : : Surface : : ~ Surface ( )
{
m_renderer - > m_dev - > Recycle ( m_texture ) ;
}
void GSTextureCache : : Surface : : Update ( )
{
m_age = 0 ;
}
// GSTextureCache::Source
GSTextureCache : : Source : : Source ( GSRenderer * r )
: Surface ( r )
, m_palette ( NULL )
, m_initpalette ( true )
, m_fmt ( 0 )
, m_target ( false )
, m_complete ( false )
{
memset ( m_valid , 0 , sizeof ( m_valid ) ) ;
m_clut = ( uint32 * ) _aligned_malloc ( 256 * sizeof ( uint32 ) , 16 ) ;
memset ( m_clut , 0 , sizeof ( m_clut ) ) ;
m_write . rect = ( GSVector4i * ) _aligned_malloc ( 3 * sizeof ( GSVector4i ) , 16 ) ;
m_write . count = 0 ;
}
GSTextureCache : : Source : : ~ Source ( )
{
m_renderer - > m_dev - > Recycle ( m_palette ) ;
_aligned_free ( m_clut ) ;
_aligned_free ( m_write . rect ) ;
2009-07-06 16:35:06 +00:00
}
2009-06-27 03:32:33 +00:00
void GSTextureCache : : Source : : Update ( const GIFRegTEX0 & TEX0 , const GIFRegTEXA & TEXA , const GSVector4i & rect )
2009-06-12 19:09:17 +00:00
{
__super : : Update ( ) ;
2009-07-01 21:14:12 +00:00
if ( m_complete | | m_target )
2009-06-27 03:32:33 +00:00
{
return ;
}
2009-06-12 19:09:17 +00:00
2009-06-27 03:32:33 +00:00
m_TEX0 = TEX0 ;
m_TEXA = TEXA ;
2009-06-12 19:09:17 +00:00
2009-07-04 15:14:04 +00:00
GSVector2i bs = GSLocalMemory : : m_psm [ m_TEX0 . PSM ] . bs ;
2009-06-27 03:32:33 +00:00
2009-07-16 21:36:07 +00:00
int tw = std : : max < int > ( 1 < < m_TEX0 . TW , bs . x ) ;
int th = std : : max < int > ( 1 < < m_TEX0 . TH , bs . y ) ;
GSVector4i r = rect . ralign < GSVector4i : : Outside > ( bs ) ;
2009-06-27 03:32:33 +00:00
2009-07-16 21:36:07 +00:00
if ( r . eq ( GSVector4i ( 0 , 0 , tw , th ) ) )
2009-07-01 21:14:12 +00:00
{
m_complete = true ; // lame, but better than nothing
}
2009-07-22 03:55:28 +00:00
const GSOffset * o = m_renderer - > m_context - > offset . tex ;
2009-06-27 03:32:33 +00:00
2009-07-04 15:14:04 +00:00
bool repeating = m_TEX0 . IsRepeating ( ) ;
2009-06-12 19:09:17 +00:00
2009-06-28 02:02:14 +00:00
uint32 blocks = 0 ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
for ( int y = r . top ; y < r . bottom ; y + = bs . y )
2009-06-12 19:09:17 +00:00
{
2009-07-22 03:55:28 +00:00
uint32 base = o - > block . row [ y > > 3 ] ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
for ( int x = r . left ; x < r . right ; x + = bs . x )
2009-06-27 03:32:33 +00:00
{
2009-07-22 03:55:28 +00:00
uint32 block = base + o - > block . col [ x > > 3 ] ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
if ( block < MAX_BLOCKS )
2009-06-27 03:32:33 +00:00
{
2009-06-28 02:02:14 +00:00
uint32 row = block > > 5 ;
uint32 col = 1 < < ( block & 31 ) ;
2009-06-27 03:32:33 +00:00
2009-07-01 21:14:12 +00:00
if ( ( m_valid [ row ] & col ) = = 0 )
2009-06-27 03:32:33 +00:00
{
2009-07-01 21:14:12 +00:00
if ( ! repeating )
{
m_valid [ row ] | = col ;
}
2009-06-12 19:09:17 +00:00
2009-06-28 02:02:14 +00:00
Write ( GSVector4i ( x , y , x + bs . x , y + bs . y ) ) ;
2009-06-12 19:09:17 +00:00
2009-06-28 02:02:14 +00:00
blocks + + ;
2009-06-27 03:32:33 +00:00
}
}
}
}
2009-06-28 02:02:14 +00:00
if ( blocks > 0 )
{
if ( repeating )
2009-06-12 19:09:17 +00:00
{
2009-06-28 02:02:14 +00:00
for ( int y = r . top ; y < r . bottom ; y + = bs . y )
2009-06-27 03:32:33 +00:00
{
2009-07-22 03:55:28 +00:00
uint32 base = o - > block . row [ y > > 3 ] ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
for ( int x = r . left ; x < r . right ; x + = bs . x )
2009-06-27 03:32:33 +00:00
{
2009-07-22 03:55:28 +00:00
uint32 block = base + o - > block . col [ x > > 3 ] ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
if ( block < MAX_BLOCKS )
2009-06-27 03:32:33 +00:00
{
2009-06-28 02:02:14 +00:00
uint32 row = block > > 5 ;
uint32 col = 1 < < ( block & 31 ) ;
2009-06-27 03:32:33 +00:00
2009-07-01 21:14:12 +00:00
m_valid [ row ] | = col ;
2009-06-27 03:32:33 +00:00
}
}
}
2009-06-12 19:09:17 +00:00
}
2009-06-27 03:32:33 +00:00
2009-09-18 00:16:52 +00:00
m_renderer - > m_perfmon . Put ( GSPerfMon : : Unswizzle , bs . x * bs . y * blocks < < ( m_fmt = = FMT_32 ? 2 : 0 ) ) ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
Flush ( m_write . count ) ;
}
}
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
void GSTextureCache : : Source : : Write ( const GSVector4i & r )
{
m_write . rect [ m_write . count + + ] = r ;
while ( m_write . count > = 2 )
{
GSVector4i & a = m_write . rect [ m_write . count - 2 ] ;
GSVector4i & b = m_write . rect [ m_write . count - 1 ] ;
if ( ( a = = b . zyxw ( ) ) . mask ( ) = = 0xfff0 )
{
a . right = b . right ; // extend right
m_write . count - - ;
2009-06-12 19:09:17 +00:00
}
2009-06-28 02:02:14 +00:00
else if ( ( a = = b . xwzy ( ) ) . mask ( ) = = 0xff0f )
{
a . bottom = b . bottom ; // extend down
2009-06-12 19:09:17 +00:00
2009-06-28 02:02:14 +00:00
m_write . count - - ;
}
else
{
break ;
}
}
2009-06-12 19:09:17 +00:00
2009-06-28 02:02:14 +00:00
if ( m_write . count > 2 )
{
Flush ( 1 ) ;
}
2009-06-27 03:32:33 +00:00
}
2009-06-12 19:09:17 +00:00
2009-06-28 02:02:14 +00:00
void GSTextureCache : : Source : : Flush ( uint32 count )
2009-06-27 03:32:33 +00:00
{
2009-06-28 02:02:14 +00:00
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ m_TEX0 . PSM ] ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
int tw = 1 < < m_TEX0 . TW ;
int th = 1 < < m_TEX0 . TH ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
GSVector4i tr ( 0 , 0 , tw , th ) ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
int pitch = max ( tw , psm . bs . x ) * sizeof ( uint32 ) ;
2009-07-04 15:14:04 +00:00
GSLocalMemory & mem = m_renderer - > m_mem ;
2009-06-28 02:02:14 +00:00
2009-07-22 03:55:28 +00:00
const GSOffset * o = m_renderer - > m_context - > offset . tex ;
2009-06-28 02:02:14 +00:00
GSLocalMemory : : readTexture rtx = psm . rtx ;
2009-09-18 00:16:52 +00:00
if ( m_fmt = = FMT_8 )
2009-07-06 16:35:06 +00:00
{
pitch > > = 2 ;
rtx = psm . rtxP ;
}
2009-10-12 19:58:03 +00:00
uint8 * buff = m_renderer - > GetTextureBufferLock ( ) ;
2009-06-28 02:02:14 +00:00
for ( uint32 i = 0 ; i < count ; i + + )
2009-06-27 03:32:33 +00:00
{
2009-06-28 02:02:14 +00:00
GSVector4i r = m_write . rect [ i ] ;
2009-06-27 19:05:36 +00:00
2009-06-28 02:02:14 +00:00
if ( ( r > tr ) . mask ( ) & 0xff00 )
2009-06-27 19:05:36 +00:00
{
2009-07-22 03:55:28 +00:00
( mem . * rtx ) ( o , r , buff , pitch , m_TEXA ) ;
2009-06-27 03:32:33 +00:00
2009-06-28 02:02:14 +00:00
m_texture - > Update ( r . rintersect ( tr ) , buff , pitch ) ;
2009-06-27 19:05:36 +00:00
}
else
{
2009-06-28 02:02:14 +00:00
GSTexture : : GSMap m ;
if ( m_texture - > Map ( m , & r ) )
{
2009-07-22 03:55:28 +00:00
( mem . * rtx ) ( o , r , m . bits , m . pitch , m_TEXA ) ;
2009-06-28 02:02:14 +00:00
m_texture - > Unmap ( ) ;
}
else
{
2009-07-22 03:55:28 +00:00
( mem . * rtx ) ( o , r , buff , pitch , m_TEXA ) ;
2009-06-27 19:05:36 +00:00
2009-06-28 02:02:14 +00:00
m_texture - > Update ( r , buff , pitch ) ;
}
2009-06-27 19:05:36 +00:00
}
2009-06-12 19:09:17 +00:00
}
2009-06-28 02:02:14 +00:00
2009-10-12 19:58:03 +00:00
m_renderer - > ReleaseTextureBufferLock ( ) ;
2009-06-28 02:02:14 +00:00
if ( count < m_write . count )
{
memcpy ( m_write . rect [ 0 ] , & m_write . rect [ count ] , ( m_write . count - count ) * sizeof ( m_write . rect [ 0 ] ) ) ;
}
m_write . count - = count ;
2009-06-12 19:09:17 +00:00
}
2009-06-27 03:32:33 +00:00
// GSTextureCache::Target
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
GSTextureCache : : Target : : Target ( GSRenderer * r )
: Surface ( r )
, m_type ( - 1 )
2009-05-22 01:22:52 +00:00
, m_used ( false )
{
2009-07-12 13:46:05 +00:00
m_valid = GSVector4i : : zero ( ) ;
2009-05-22 01:22:52 +00:00
}
2009-06-27 03:32:33 +00:00
void GSTextureCache : : Target : : Update ( )
2009-06-12 19:09:17 +00:00
{
__super : : Update ( ) ;
2009-06-27 03:32:33 +00:00
// FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :)
2009-06-20 20:28:36 +00:00
GSVector4i r = m_dirty . GetDirtyRectAndClear ( m_TEX0 , m_texture - > GetSize ( ) ) ;
if ( r . rempty ( ) ) return ;
2009-06-27 03:32:33 +00:00
if ( m_type = = RenderTarget )
{
int w = r . width ( ) ;
int h = r . height ( ) ;
2009-06-20 20:28:36 +00:00
2009-06-27 03:32:33 +00:00
if ( GSTexture * t = m_renderer - > m_dev - > CreateTexture ( w , h ) )
{
2009-07-24 09:24:09 +00:00
const GSOffset * o = m_renderer - > m_mem . GetOffset ( m_TEX0 . TBP0 , m_TEX0 . TBW , m_TEX0 . PSM ) ;
2009-07-22 03:55:28 +00:00
2009-06-27 03:32:33 +00:00
GIFRegTEXA TEXA ;
2009-06-12 19:09:17 +00:00
2009-06-27 03:32:33 +00:00
TEXA . AEM = 1 ;
TEXA . TA0 = 0 ;
TEXA . TA1 = 0x80 ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
GSTexture : : GSMap m ;
2009-06-17 11:24:42 +00:00
2009-06-27 03:32:33 +00:00
if ( t - > Map ( m ) )
{
2009-07-22 03:55:28 +00:00
m_renderer - > m_mem . ReadTexture ( o , r , m . bits , m . pitch , TEXA ) ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
t - > Unmap ( ) ;
}
else
{
static uint8 * buff = ( uint8 * ) : : _aligned_malloc ( 1024 * 1024 * 4 , 16 ) ;
int pitch = ( ( w + 3 ) & ~ 3 ) * 4 ;
2009-05-22 01:22:52 +00:00
2009-07-22 03:55:28 +00:00
m_renderer - > m_mem . ReadTexture ( o , r , buff , pitch , TEXA ) ;
2009-06-27 03:32:33 +00:00
t - > Update ( r . rsize ( ) , buff , pitch ) ;
}
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
// m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, w * h * 4);
2009-05-22 01:22:52 +00:00
2009-08-02 23:07:30 +00:00
m_renderer - > m_dev - > StretchRect ( t , m_texture , GSVector4 ( r ) * GSVector4 ( m_texture - > GetScale ( ) ) . xyxy ( ) ) ;
2009-06-27 03:32:33 +00:00
m_renderer - > m_dev - > Recycle ( t ) ;
}
}
else if ( m_type = = DepthStencil )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
// do the most likely thing a direct write would do, clear it
2009-07-04 15:14:04 +00:00
if ( ( m_renderer - > m_game . flags & CRC : : ZWriteMustNotClear ) = = 0 )
{
m_renderer - > m_dev - > ClearDepth ( m_texture , 0 ) ;
}
2009-05-22 01:22:52 +00:00
}
2009-06-27 03:32:33 +00:00
}
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
// GSTextureCache::SourceMap
2009-05-22 01:22:52 +00:00
2009-07-22 03:55:28 +00:00
void GSTextureCache : : SourceMap : : Add ( Source * s , const GIFRegTEX0 & TEX0 , const GSOffset * o )
2009-06-27 03:32:33 +00:00
{
2009-07-16 21:36:07 +00:00
m_surfaces . insert ( s ) ;
2009-05-22 01:22:52 +00:00
2009-07-02 00:47:50 +00:00
if ( s - > m_target )
{
// TODO
2009-07-12 13:46:05 +00:00
m_map [ TEX0 . TBP0 > > 5 ] . push_front ( s ) ;
2009-07-02 00:47:50 +00:00
return ;
}
2009-06-27 03:32:33 +00:00
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ TEX0 . PSM ] ;
2009-05-22 01:22:52 +00:00
2009-07-06 16:35:06 +00:00
GSVector2i bs = ( TEX0 . TBP0 & 31 ) = = 0 ? psm . pgs : psm . bs ;
2009-07-04 15:14:04 +00:00
int tw = 1 < < TEX0 . TW ;
int th = 1 < < TEX0 . TH ;
2009-06-27 03:32:33 +00:00
for ( int y = 0 ; y < th ; y + = bs . y )
2009-05-22 01:22:52 +00:00
{
2009-07-22 03:55:28 +00:00
uint32 base = o - > block . row [ y > > 3 ] ;
2009-05-28 02:57:01 +00:00
2009-06-27 03:32:33 +00:00
for ( int x = 0 ; x < tw ; x + = bs . x )
{
2009-07-22 03:55:28 +00:00
uint32 page = ( base + o - > block . col [ x > > 3 ] ) > > 5 ;
2009-05-22 01:22:52 +00:00
2009-07-01 21:14:12 +00:00
if ( page < MAX_PAGES )
2009-06-27 03:32:33 +00:00
{
2009-07-01 21:14:12 +00:00
m_pages [ page > > 5 ] | = 1 < < ( page & 31 ) ;
2009-06-27 03:32:33 +00:00
}
}
}
2009-06-28 02:02:14 +00:00
2009-07-01 21:14:12 +00:00
for ( int i = 0 ; i < countof ( m_pages ) ; i + + )
{
2009-07-01 22:29:24 +00:00
if ( uint32 p = m_pages [ i ] )
2009-07-01 21:14:12 +00:00
{
2009-07-01 22:29:24 +00:00
m_pages [ i ] = 0 ;
2009-07-12 13:46:05 +00:00
list < Source * > * m = & m_map [ i < < 5 ] ;
2009-07-01 21:14:12 +00:00
2009-07-16 21:36:07 +00:00
unsigned long j ;
while ( _BitScanForward ( & j , p ) )
2009-07-01 21:14:12 +00:00
{
2009-07-16 21:36:07 +00:00
p ^ = 1 < < j ;
m [ j ] . push_front ( s ) ;
2009-07-01 21:14:12 +00:00
}
}
}
2009-05-22 01:22:52 +00:00
}
2009-06-27 03:32:33 +00:00
void GSTextureCache : : SourceMap : : RemoveAll ( )
2009-05-22 01:22:52 +00:00
{
2009-07-16 21:36:07 +00:00
for_each ( m_surfaces . begin ( ) , m_surfaces . end ( ) , delete_object ( ) ) ;
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
m_surfaces . clear ( ) ;
2009-05-22 01:22:52 +00:00
2009-07-01 21:14:12 +00:00
for ( uint32 i = 0 ; i < countof ( m_map ) ; i + + )
2009-05-22 01:22:52 +00:00
{
2009-06-27 03:32:33 +00:00
m_map [ i ] . clear ( ) ;
2009-05-22 01:22:52 +00:00
}
2009-06-27 03:32:33 +00:00
}
2009-05-22 01:22:52 +00:00
2009-06-27 03:32:33 +00:00
void GSTextureCache : : SourceMap : : RemoveAt ( Source * s )
{
m_surfaces . erase ( s ) ;
2009-07-12 13:46:05 +00:00
for ( uint32 start = s - > m_TEX0 . TBP0 > > 5 , end = s - > m_target ? start : countof ( m_map ) - 1 ; start < = end ; start + + )
2009-05-22 01:22:52 +00:00
{
2009-07-12 13:46:05 +00:00
list < Source * > & m = m_map [ start ] ;
2009-07-02 00:47:50 +00:00
2009-07-12 13:46:05 +00:00
for ( list < Source * > : : iterator i = m . begin ( ) ; i ! = m . end ( ) ; )
2009-07-02 00:47:50 +00:00
{
2009-07-12 13:46:05 +00:00
list < Source * > : : iterator j = i + + ;
if ( * j = = s ) { m . erase ( j ) ; break ; }
2009-07-02 00:47:50 +00:00
}
2009-05-22 01:22:52 +00:00
}
2009-06-27 03:32:33 +00:00
delete s ;
}