2010-10-19 22:24:27 +00:00
# include "MemoryUtil.h"
# include "VideoConfig.h"
# include "Statistics.h"
# include "HiresTextures.h"
2010-11-18 02:21:26 +00:00
# include "RenderBase.h"
2010-10-19 22:24:27 +00:00
# include "FileUtil.h"
# include "TextureCacheBase.h"
2010-12-05 14:15:36 +00:00
# include "Debugger.h"
2011-01-31 01:28:32 +00:00
# include "ConfigManager.h"
# include "HW/Memmap.h"
2010-10-19 22:24:27 +00:00
// ugly
extern int frameCount ;
enum
{
2011-02-04 22:51:17 +00:00
TEMP_SIZE = ( 2048 * 2048 * 4 ) ,
2010-10-19 22:24:27 +00:00
TEXTURE_KILL_THRESHOLD = 200 ,
} ;
TextureCache * g_texture_cache ;
2011-02-25 20:35:05 +00:00
GC_ALIGNED16 ( u8 * TextureCache : : temp ) = NULL ;
2011-02-05 10:08:06 +00:00
2010-10-19 22:24:27 +00:00
TextureCache : : TexCache TextureCache : : textures ;
2011-02-08 03:47:59 +00:00
bool TextureCache : : DeferredInvalidate ;
2010-10-19 22:24:27 +00:00
TextureCache : : TCacheEntryBase : : ~ TCacheEntryBase ( )
{
if ( 0 = = addr )
return ;
if ( ! isRenderTarget & & ! g_ActiveConfig . bSafeTextureCache )
{
2011-01-31 01:28:32 +00:00
u32 * const ptr = ( u32 * ) Memory : : GetPointer ( addr ) ;
2010-10-19 22:24:27 +00:00
if ( ptr & & * ptr = = hash )
* ptr = oldpixel ;
}
}
TextureCache : : TextureCache ( )
{
2011-02-05 10:08:06 +00:00
if ( ! temp )
2011-02-25 20:35:05 +00:00
temp = ( u8 * ) AllocateAlignedMemory ( TEMP_SIZE , 16 ) ;
2010-10-19 22:24:27 +00:00
TexDecoder_SetTexFmtOverlayOptions ( g_ActiveConfig . bTexFmtOverlayEnable , g_ActiveConfig . bTexFmtOverlayCenter ) ;
2011-02-05 10:08:06 +00:00
if ( g_ActiveConfig . bHiresTextures & & ! g_ActiveConfig . bDumpTextures )
HiresTextures : : Init ( SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strUniqueID . c_str ( ) ) ;
SetHash64Function ( g_ActiveConfig . bHiresTextures | | g_ActiveConfig . bDumpTextures ) ;
2010-10-19 22:24:27 +00:00
}
void TextureCache : : Invalidate ( bool shutdown )
{
TexCache : : iterator
iter = textures . begin ( ) ,
tcend = textures . end ( ) ;
for ( ; iter ! = tcend ; + + iter )
{
if ( shutdown )
iter - > second - > addr = 0 ;
delete iter - > second ;
}
textures . clear ( ) ;
2011-02-05 10:08:06 +00:00
if ( g_ActiveConfig . bHiresTextures & & ! g_ActiveConfig . bDumpTextures )
HiresTextures : : Init ( SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strUniqueID . c_str ( ) ) ;
SetHash64Function ( g_ActiveConfig . bHiresTextures | | g_ActiveConfig . bDumpTextures ) ;
2011-02-08 03:47:59 +00:00
DeferredInvalidate = false ;
}
void TextureCache : : InvalidateDefer ( )
{
DeferredInvalidate = true ;
2010-10-19 22:24:27 +00:00
}
TextureCache : : ~ TextureCache ( )
{
Invalidate ( true ) ;
2011-02-05 10:08:06 +00:00
if ( temp )
{
2011-02-25 20:35:05 +00:00
FreeAlignedMemory ( temp ) ;
2011-02-05 10:08:06 +00:00
temp = NULL ;
}
2010-10-19 22:24:27 +00:00
}
void TextureCache : : Cleanup ( )
{
2011-12-26 17:45:22 +00:00
TexCache : : iterator iter = textures . begin ( ) ;
TexCache : : iterator tcend = textures . end ( ) ;
2010-10-19 22:24:27 +00:00
while ( iter ! = tcend )
{
2011-12-26 17:33:05 +00:00
if ( frameCount > TEXTURE_KILL_THRESHOLD + iter - > second - > frameCount ) // TODO: Deleting EFB copies might not be a good idea here...
2010-10-19 22:24:27 +00:00
{
delete iter - > second ;
textures . erase ( iter + + ) ;
}
else
+ + iter ;
}
}
void TextureCache : : InvalidateRange ( u32 start_address , u32 size )
{
TexCache : : iterator
iter = textures . begin ( ) ,
tcend = textures . end ( ) ;
while ( iter ! = tcend )
{
const int rangePosition = iter - > second - > IntersectsMemoryRange ( start_address , size ) ;
if ( 0 = = rangePosition )
{
delete iter - > second ;
textures . erase ( iter + + ) ;
}
else
+ + iter ;
}
}
void TextureCache : : MakeRangeDynamic ( u32 start_address , u32 size )
{
TexCache : : iterator
2010-11-06 04:46:44 +00:00
iter = textures . lower_bound ( start_address ) ,
tcend = textures . upper_bound ( start_address + size ) ;
if ( iter ! = textures . begin ( ) )
iter - - ;
2010-10-19 22:24:27 +00:00
for ( ; iter ! = tcend ; + + iter )
{
const int rangePosition = iter - > second - > IntersectsMemoryRange ( start_address , size ) ;
if ( 0 = = rangePosition )
{
2011-12-26 17:05:01 +00:00
iter - > second - > SetHashes ( TEXHASH_INVALID ) ;
2010-10-19 22:24:27 +00:00
}
}
}
2010-11-06 04:46:44 +00:00
bool TextureCache : : Find ( u32 start_address , u64 hash )
{
2010-11-07 04:28:33 +00:00
TexCache : : iterator iter = textures . lower_bound ( start_address ) ;
2010-11-06 04:46:44 +00:00
if ( iter - > second - > hash = = hash )
return true ;
return false ;
}
2010-10-19 22:24:27 +00:00
int TextureCache : : TCacheEntryBase : : IntersectsMemoryRange ( u32 range_address , u32 range_size ) const
{
if ( addr + size_in_bytes < range_address )
return - 1 ;
if ( addr > = range_address + range_size )
return 1 ;
return 0 ;
}
void TextureCache : : ClearRenderTargets ( )
{
TexCache : : iterator
iter = textures . begin ( ) ,
tcend = textures . end ( ) ;
for ( ; iter ! = tcend ; + + iter )
2010-11-21 14:47:28 +00:00
iter - > second - > isRenderTarget = false ;
2010-10-19 22:24:27 +00:00
}
TextureCache : : TCacheEntryBase * TextureCache : : Load ( unsigned int stage ,
u32 address , unsigned int width , unsigned int height , int texformat ,
unsigned int tlutaddr , int tlutfmt , bool UseNativeMips , unsigned int maxlevel )
{
// necessary?
if ( 0 = = address )
return NULL ;
2011-01-31 01:28:32 +00:00
u8 * ptr = Memory : : GetPointer ( address ) ;
2010-10-19 22:24:27 +00:00
// TexelSizeInNibbles(format)*width*height/16;
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels ( texformat ) - 1 ;
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels ( texformat ) - 1 ;
unsigned int expandedWidth = ( width + bsw ) & ( ~ bsw ) ;
unsigned int expandedHeight = ( height + bsh ) & ( ~ bsh ) ;
2010-10-20 00:12:41 +00:00
const unsigned int nativeW = width ;
const unsigned int nativeH = height ;
bool isPow2 ;
2010-10-19 22:24:27 +00:00
2011-12-26 17:05:01 +00:00
u64 hash_value = TEXHASH_INVALID ;
u64 texHash = TEXHASH_INVALID ;
2011-12-26 20:11:31 +00:00
u64 tlut_hash = TEXHASH_INVALID ;
2010-10-19 22:24:27 +00:00
u32 texID = address ;
u32 full_format = texformat ;
const u32 texture_size = TexDecoder_GetTextureSizeInBytes ( expandedWidth , expandedHeight , texformat ) ;
bool texture_is_dynamic = false ;
2010-10-20 00:12:41 +00:00
unsigned int texLevels ;
PC_TexFormat pcfmt = PC_TEX_FMT_NONE ;
2010-10-19 22:24:27 +00:00
2011-02-05 10:08:06 +00:00
const bool isPaletteTexture = ( texformat = = GX_TF_C4 | | texformat = = GX_TF_C8 | | texformat = = GX_TF_C14X2 ) ;
2010-10-19 22:24:27 +00:00
2011-02-05 10:08:06 +00:00
if ( isPaletteTexture )
2010-10-19 22:24:27 +00:00
full_format = texformat | ( tlutfmt < < 16 ) ;
2011-12-26 20:11:31 +00:00
if ( isPaletteTexture & & ( g_ActiveConfig . bSafeTextureCache | | g_ActiveConfig . bHiresTextures | | g_ActiveConfig . bDumpTextures ) )
2010-10-19 22:24:27 +00:00
{
2011-12-26 20:11:31 +00:00
const u32 palette_size = TexDecoder_GetPaletteSize ( texformat ) ;
tlut_hash = GetHash64 ( & texMem [ tlutaddr ] , palette_size , g_ActiveConfig . iSafeTextureCache_ColorSamples ) ;
// NOTE: For non-paletted textures, texID is equal to the texture address.
// A paletted texture, however, may have multiple texIDs assigned though depending on the currently used tlut.
// This (changing texID depending on the tlut_hash) is a trick to get around
// an issue with Metroid Prime's fonts (it has multiple sets of fonts on each other
// stored in a single texture and uses the palette to make different characters
// visible or invisible. Thus, unless we want to recreate the textures for every drawn character,
// we must make sure that a paletted texture gets assigned multiple IDs for each tlut used.
//
// TODO: Because texID isn't always the same as the address now, CopyRenderTargetToTexture might be broken now
if ( g_ActiveConfig . bSafeTextureCache )
texID ^ = ( ( u32 ) tlut_hash ) ^ ( u32 ) ( tlut_hash > > 32 ) ;
}
2010-10-24 15:16:31 +00:00
2010-10-19 22:24:27 +00:00
2011-12-26 20:11:31 +00:00
TCacheEntryBase * entry = textures [ texID ] ;
if ( entry )
{
// hires texture loading and texture dumping require accurate hashes
if ( g_ActiveConfig . bSafeTextureCache | | g_ActiveConfig . bHiresTextures | | g_ActiveConfig . bDumpTextures )
{
texHash = GetHash64 ( ptr , texture_size , g_ActiveConfig . iSafeTextureCache_ColorSamples ) ;
2010-10-19 22:24:27 +00:00
2011-12-26 20:11:31 +00:00
if ( isPaletteTexture )
texHash ^ = tlut_hash ;
2010-10-19 22:24:27 +00:00
if ( g_ActiveConfig . bSafeTextureCache )
2011-12-26 20:11:31 +00:00
hash_value = texHash ;
2010-10-19 22:24:27 +00:00
}
2011-12-26 18:45:13 +00:00
// 1. Adjust reference hash:
// safe texcache: reference hash was calculated above for normal textures. 0 for virtual EFB copies.
// unsafe texcache: 0 for virtual EFB copies. Safe hash for dynamic EFB copies. First pixel for normal textures.
2011-12-26 17:45:22 +00:00
if ( g_ActiveConfig . bSafeTextureCache )
2010-10-19 22:24:27 +00:00
{
2011-12-26 17:45:22 +00:00
if ( g_ActiveConfig . bCopyEFBToTexture & & ( entry - > isRenderTarget | | entry - > isDynamic ) )
hash_value = TEXHASH_INVALID ;
}
else
{
if ( ! ( entry - > isRenderTarget | | entry - > isDynamic ) )
hash_value = * ( u32 * ) ptr ;
else if ( g_ActiveConfig . bCopyEFBToTexture )
hash_value = TEXHASH_INVALID ;
else
2010-10-19 22:24:27 +00:00
{
2010-10-20 00:12:41 +00:00
hash_value = GetHash64 ( ptr , texture_size , g_ActiveConfig . iSafeTextureCache_ColorSamples ) ;
2010-10-19 22:24:27 +00:00
2011-02-05 10:08:06 +00:00
if ( isPaletteTexture )
2011-12-26 20:11:31 +00:00
hash_value ^ = tlut_hash ; // TODO: Ugly, this is using Safe Texture Cache parameters in nonsafe TC
2010-10-19 22:24:27 +00:00
}
}
2011-12-26 18:45:13 +00:00
// 2. a) For EFB copies, only the hash and the texture address need to match
if ( ( entry - > isRenderTarget | | entry - > isDynamic ) & & hash_value = = entry - > hash & & address = = entry - > addr )
2010-10-19 22:24:27 +00:00
{
2011-12-26 18:45:13 +00:00
// TODO: Print a warning if the format changes! In this case, we could reinterpret the internal texture object data to the new pixel format (similiar to what is already being done in Renderer::ReinterpretPixelFormat())
2010-10-19 22:24:27 +00:00
entry - > isDynamic = false ;
goto return_entry ;
}
2011-12-26 18:45:13 +00:00
// 2. b) For normal textures, all texture parameters need to match
if ( address = = entry - > addr & & hash_value = = entry - > hash & & full_format = = entry - > format & &
entry - > num_mipmaps = = maxlevel & & entry - > native_width = = nativeW & & entry - > native_height = = nativeH )
{
goto return_entry ;
}
// 3. If we reach this line, we'll have to upload the new texture data to VRAM.
// If we're lucky, the texture parameters didn't change and we can reuse the internal texture object instead of destroying and recreating it.
texture_is_dynamic = ( entry - > isRenderTarget | | entry - > isDynamic ) & & ! g_ActiveConfig . bCopyEFBToTexture ;
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
// TODO: Actually, it should be enough if the internal texture format matches...
if ( ! entry - > isRenderTarget & &
( ( ! entry - > isDynamic & & width = = entry - > native_width & & height = = entry - > native_height & & full_format = = entry - > format & & entry - > num_mipmaps = = maxlevel )
| | ( entry - > isDynamic & & entry - > native_width = = width & & entry - > native_height = = height ) ) )
{
// reuse the texture
}
2010-10-19 22:24:27 +00:00
else
{
2011-12-26 18:45:13 +00:00
// delete the texture and make a new one
delete entry ;
entry = NULL ;
2010-10-19 22:24:27 +00:00
}
}
2011-12-26 18:17:04 +00:00
2010-10-19 22:24:27 +00:00
if ( g_ActiveConfig . bHiresTextures )
{
// Load Custom textures
char texPathTemp [ MAX_PATH ] ;
unsigned int newWidth = width ;
2010-10-20 00:12:41 +00:00
unsigned int newHeight = height ;
2010-10-19 22:24:27 +00:00
2011-02-05 16:06:05 +00:00
sprintf ( texPathTemp , " %s_%08x_%i " , SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strUniqueID . c_str ( ) , ( u32 ) ( texHash & 0x00000000FFFFFFFFLL ) , texformat ) ;
2010-10-19 22:24:27 +00:00
pcfmt = HiresTextures : : GetHiresTex ( texPathTemp , & newWidth , & newHeight , texformat , temp ) ;
if ( pcfmt ! = PC_TEX_FMT_NONE )
{
expandedWidth = width = newWidth ;
expandedHeight = height = newHeight ;
}
}
if ( pcfmt = = PC_TEX_FMT_NONE )
pcfmt = TexDecoder_Decode ( temp , ptr , expandedWidth ,
2011-12-26 18:17:04 +00:00
expandedHeight , texformat , tlutaddr , tlutfmt , g_ActiveConfig . backend_info . bUseRGBATextures ) ;
2010-10-19 22:24:27 +00:00
2011-12-26 18:17:04 +00:00
UseNativeMips = UseNativeMips & & ( width = = nativeW & & height = = nativeH ) ; // Only load native mips if their dimensions fit to our virtual texture dimensions
2010-10-20 00:12:41 +00:00
isPow2 = ! ( ( width & ( width - 1 ) ) | | ( height & ( height - 1 ) ) ) ;
texLevels = ( isPow2 & & UseNativeMips & & maxlevel ) ?
2010-10-19 22:24:27 +00:00
GetPow2 ( std : : max ( width , height ) ) : ! isPow2 ;
if ( ( texLevels > ( maxlevel + 1 ) ) & & maxlevel )
texLevels = maxlevel + 1 ;
// create the entry/texture
2010-10-24 15:16:31 +00:00
if ( NULL = = entry ) {
2010-10-19 22:24:27 +00:00
textures [ texID ] = entry = g_texture_cache - > CreateTexture ( width , height , expandedWidth , texLevels , pcfmt ) ;
2010-10-24 15:16:31 +00:00
// Sometimes, we can get around recreating a texture if only the number of mip levels gets changes
// e.g. if our texture cache entry got too many mipmap levels we can limit the number of used levels by setting the appropriate render states
// Thus, we don't update this member for every Load, but just whenever the texture gets recreated
2011-12-26 17:05:01 +00:00
entry - > num_mipmaps = maxlevel ; // TODO: Does this actually work? We can't really adjust mipmap settings per-stage...
2010-12-05 14:15:36 +00:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_NEW_TEXTURE , true ) ;
2010-10-24 15:16:31 +00:00
}
2010-10-19 22:24:27 +00:00
2011-12-26 17:05:01 +00:00
entry - > SetGeneralParameters ( address , texture_size , full_format , entry - > num_mipmaps ) ;
entry - > SetDimensions ( nativeW , nativeH , width , height ) ;
entry - > SetEFBCopyParameters ( false , texture_is_dynamic ) ;
2010-10-24 15:16:31 +00:00
entry - > oldpixel = * ( u32 * ) ptr ;
2010-10-19 22:24:27 +00:00
2010-10-24 15:16:31 +00:00
if ( g_ActiveConfig . bSafeTextureCache | | entry - > isDynamic )
entry - > hash = hash_value ;
else
entry - > hash = * ( u32 * ) ptr = ( u32 ) ( ( ( double ) rand ( ) / RAND_MAX ) * 0xFFFFFFFF ) ;
2010-10-19 22:24:27 +00:00
// load texture
2010-11-24 19:13:19 +00:00
entry - > Load ( width , height , expandedWidth , 0 , ( texLevels = = 0 ) ) ;
2010-10-19 22:24:27 +00:00
// load mips
if ( texLevels > 1 & & pcfmt ! = PC_TEX_FMT_NONE )
{
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles ( texformat ) ;
unsigned int level = 1 ;
unsigned int mipWidth = ( width + 1 ) > > 1 ;
unsigned int mipHeight = ( height + 1 ) > > 1 ;
ptr + = texture_size ;
while ( ( mipHeight | | mipWidth ) & & ( level < texLevels ) )
{
const unsigned int currentWidth = ( mipWidth > 0 ) ? mipWidth : 1 ;
const unsigned int currentHeight = ( mipHeight > 0 ) ? mipHeight : 1 ;
expandedWidth = ( currentWidth + bsw ) & ( ~ bsw ) ;
expandedHeight = ( currentHeight + bsh ) & ( ~ bsh ) ;
2010-11-21 14:47:28 +00:00
TexDecoder_Decode ( temp , ptr , expandedWidth , expandedHeight , texformat , tlutaddr , tlutfmt , g_ActiveConfig . backend_info . bUseRGBATextures ) ;
2011-12-26 19:05:32 +00:00
entry - > Load ( currentWidth , currentHeight , expandedWidth , level , false ) ;
2010-10-19 22:24:27 +00:00
ptr + = ( ( std : : max ( mipWidth , bsw ) * std : : max ( mipHeight , bsh ) * bsdepth ) > > 1 ) ;
mipWidth > > = 1 ;
mipHeight > > = 1 ;
+ + level ;
}
}
// TODO: won't this cause loaded hires textures to be dumped as well?
2010-10-20 00:12:41 +00:00
// dump texture to file
2010-10-19 22:24:27 +00:00
if ( g_ActiveConfig . bDumpTextures )
{
char szTemp [ MAX_PATH ] ;
2011-02-28 20:40:15 +00:00
std : : string szDir = File : : GetUserPath ( D_DUMPTEXTURES_IDX ) +
SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strUniqueID ;
2010-10-19 22:24:27 +00:00
// make sure that the directory exists
2011-03-01 03:06:14 +00:00
if ( false = = File : : Exists ( szDir ) | | false = = File : : IsDirectory ( szDir ) )
2011-02-28 20:40:15 +00:00
File : : CreateDir ( szDir . c_str ( ) ) ;
2010-10-19 22:24:27 +00:00
2011-02-28 20:40:15 +00:00
sprintf ( szTemp , " %s/%s_%08x_%i.png " , szDir . c_str ( ) ,
SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strUniqueID . c_str ( ) ,
( u32 ) ( texHash & 0x00000000FFFFFFFFLL ) , texformat ) ;
2010-10-19 22:24:27 +00:00
if ( false = = File : : Exists ( szTemp ) )
entry - > Save ( szTemp ) ;
}
INCSTAT ( stats . numTexturesCreated ) ;
SETSTAT ( stats . numTexturesAlive , textures . size ( ) ) ;
return_entry :
entry - > frameCount = frameCount ;
entry - > Bind ( stage ) ;
2010-12-05 14:15:36 +00:00
GFX_DEBUGGER_PAUSE_AT ( NEXT_TEXTURE_CHANGE , true ) ;
2010-10-19 22:24:27 +00:00
return entry ;
}
2011-02-26 23:41:02 +00:00
void TextureCache : : CopyRenderTargetToTexture ( u32 dstAddr , unsigned int dstFormat , unsigned int srcFormat ,
const EFBRectangle & srcRect , bool isIntensity , bool scaleByHalf )
2010-10-19 22:24:27 +00:00
{
2011-01-07 19:23:57 +00:00
float colmat [ 28 ] = { 0 } ;
2010-10-19 22:24:27 +00:00
float * const fConstAdd = colmat + 16 ;
2011-01-07 19:23:57 +00:00
float * const ColorMask = colmat + 20 ;
2011-12-10 15:08:26 +00:00
ColorMask [ 0 ] = ColorMask [ 1 ] = ColorMask [ 2 ] = ColorMask [ 3 ] = 255.0f ;
2011-01-07 19:23:57 +00:00
ColorMask [ 4 ] = ColorMask [ 5 ] = ColorMask [ 6 ] = ColorMask [ 7 ] = 1.0f / 255.0f ;
2010-10-19 22:24:27 +00:00
unsigned int cbufid = - 1 ;
2011-02-26 23:41:02 +00:00
if ( srcFormat = = PIXELFMT_Z24 )
2010-10-19 22:24:27 +00:00
{
2011-02-26 23:41:02 +00:00
switch ( dstFormat )
2010-10-19 22:24:27 +00:00
{
2011-12-10 15:08:26 +00:00
case 0 : // Z4
2011-01-07 19:23:57 +00:00
colmat [ 3 ] = colmat [ 7 ] = colmat [ 11 ] = colmat [ 15 ] = 1.0f ;
cbufid = 0 ;
break ;
case 1 : // Z8
case 8 : // Z8
colmat [ 0 ] = colmat [ 4 ] = colmat [ 8 ] = colmat [ 12 ] = 1.0f ;
cbufid = 1 ;
break ;
2011-12-10 15:08:26 +00:00
case 3 : // Z16
2011-01-07 19:23:57 +00:00
colmat [ 1 ] = colmat [ 5 ] = colmat [ 9 ] = colmat [ 12 ] = 1.0f ;
2011-01-29 21:13:56 +00:00
cbufid = 24 ;
2011-01-07 19:23:57 +00:00
break ;
case 11 : // Z16 (reverse order)
colmat [ 0 ] = colmat [ 4 ] = colmat [ 8 ] = colmat [ 13 ] = 1.0f ;
cbufid = 2 ;
break ;
case 6 : // Z24X8
colmat [ 0 ] = colmat [ 5 ] = colmat [ 10 ] = 1.0f ;
cbufid = 3 ;
break ;
case 9 : // Z8M
colmat [ 1 ] = colmat [ 5 ] = colmat [ 9 ] = colmat [ 13 ] = 1.0f ;
cbufid = 4 ;
break ;
case 10 : // Z8L
colmat [ 2 ] = colmat [ 6 ] = colmat [ 10 ] = colmat [ 14 ] = 1.0f ;
cbufid = 5 ;
break ;
2011-12-26 17:05:01 +00:00
case 12 : // Z16L - copy lower 16 depth bits
// expected to be used as an IA8 texture (upper 8 bits stored as intensity, lower 8 bits stored as alpha)
// Used e.g. in Zelda: Skyward Sword
2011-12-10 15:08:26 +00:00
colmat [ 1 ] = colmat [ 5 ] = colmat [ 9 ] = colmat [ 14 ] = 1.0f ;
2011-01-07 19:23:57 +00:00
cbufid = 6 ;
break ;
default :
2011-02-26 23:41:02 +00:00
ERROR_LOG ( VIDEO , " Unknown copy zbuf format: 0x%x " , dstFormat ) ;
2011-01-07 19:23:57 +00:00
colmat [ 2 ] = colmat [ 5 ] = colmat [ 8 ] = 1.0f ;
cbufid = 7 ;
break ;
2010-10-19 22:24:27 +00:00
}
}
2011-02-26 23:41:02 +00:00
else if ( isIntensity )
2010-10-19 22:24:27 +00:00
{
fConstAdd [ 0 ] = fConstAdd [ 1 ] = fConstAdd [ 2 ] = 16.0f / 255.0f ;
2011-02-26 23:41:02 +00:00
switch ( dstFormat )
2010-10-19 22:24:27 +00:00
{
case 0 : // I4
case 1 : // I8
case 2 : // IA4
case 3 : // IA8
2010-12-18 18:23:22 +00:00
case 8 : // I8
2010-10-19 22:24:27 +00:00
// TODO - verify these coefficients
colmat [ 0 ] = 0.257f ; colmat [ 1 ] = 0.504f ; colmat [ 2 ] = 0.098f ;
colmat [ 4 ] = 0.257f ; colmat [ 5 ] = 0.504f ; colmat [ 6 ] = 0.098f ;
colmat [ 8 ] = 0.257f ; colmat [ 9 ] = 0.504f ; colmat [ 10 ] = 0.098f ;
2011-02-26 23:41:02 +00:00
if ( dstFormat < 2 | | dstFormat = = 8 )
2010-10-19 22:24:27 +00:00
{
colmat [ 12 ] = 0.257f ; colmat [ 13 ] = 0.504f ; colmat [ 14 ] = 0.098f ;
2011-01-07 19:23:57 +00:00
fConstAdd [ 3 ] = 16.0f / 255.0f ;
2011-02-26 23:41:02 +00:00
if ( dstFormat = = 0 )
2011-01-07 19:23:57 +00:00
{
ColorMask [ 0 ] = ColorMask [ 1 ] = ColorMask [ 2 ] = 15.0f ;
ColorMask [ 4 ] = ColorMask [ 5 ] = ColorMask [ 6 ] = 1.0f / 15.0f ;
cbufid = 8 ;
}
else
{
cbufid = 9 ;
}
2010-10-19 22:24:27 +00:00
}
else // alpha
{
colmat [ 15 ] = 1 ;
2011-02-26 23:41:02 +00:00
if ( dstFormat = = 2 )
2011-01-07 19:23:57 +00:00
{
ColorMask [ 0 ] = ColorMask [ 1 ] = ColorMask [ 2 ] = ColorMask [ 3 ] = 15.0f ;
ColorMask [ 4 ] = ColorMask [ 5 ] = ColorMask [ 6 ] = ColorMask [ 7 ] = 1.0f / 15.0f ;
cbufid = 10 ;
}
else
{
cbufid = 11 ;
}
2010-10-19 22:24:27 +00:00
}
break ;
default :
2011-02-26 23:41:02 +00:00
ERROR_LOG ( VIDEO , " Unknown copy intensity format: 0x%x " , dstFormat ) ;
2011-01-07 19:23:57 +00:00
colmat [ 0 ] = colmat [ 5 ] = colmat [ 10 ] = colmat [ 15 ] = 1.0f ;
cbufid = 23 ;
2010-10-19 22:24:27 +00:00
break ;
}
}
else
{
2011-02-26 23:41:02 +00:00
switch ( dstFormat )
2010-10-19 22:24:27 +00:00
{
case 0 : // R4
2011-01-07 19:23:57 +00:00
colmat [ 0 ] = colmat [ 4 ] = colmat [ 8 ] = colmat [ 12 ] = 1 ;
ColorMask [ 0 ] = 15.0f ;
ColorMask [ 4 ] = 1.0f / 15.0f ;
cbufid = 12 ;
break ;
2010-12-18 18:23:22 +00:00
case 1 : // R8
2010-10-19 22:24:27 +00:00
case 8 : // R8
colmat [ 0 ] = colmat [ 4 ] = colmat [ 8 ] = colmat [ 12 ] = 1 ;
2011-01-07 19:23:57 +00:00
cbufid = 13 ;
2010-10-19 22:24:27 +00:00
break ;
case 2 : // RA4
2011-01-07 19:23:57 +00:00
colmat [ 0 ] = colmat [ 4 ] = colmat [ 8 ] = colmat [ 15 ] = 1.0f ;
ColorMask [ 0 ] = ColorMask [ 3 ] = 15.0f ;
ColorMask [ 4 ] = ColorMask [ 7 ] = 1.0f / 15.0f ;
cbufid = 14 ;
break ;
2010-10-19 22:24:27 +00:00
case 3 : // RA8
2011-01-07 19:23:57 +00:00
colmat [ 0 ] = colmat [ 4 ] = colmat [ 8 ] = colmat [ 15 ] = 1.0f ;
cbufid = 15 ;
2010-10-19 22:24:27 +00:00
break ;
case 7 : // A8
2011-01-07 19:23:57 +00:00
colmat [ 3 ] = colmat [ 7 ] = colmat [ 11 ] = colmat [ 15 ] = 1.0f ;
cbufid = 16 ;
2010-10-19 22:24:27 +00:00
break ;
case 9 : // G8
2011-01-07 19:23:57 +00:00
colmat [ 1 ] = colmat [ 5 ] = colmat [ 9 ] = colmat [ 13 ] = 1.0f ;
cbufid = 17 ;
2010-10-19 22:24:27 +00:00
break ;
case 10 : // B8
2011-01-07 19:23:57 +00:00
colmat [ 2 ] = colmat [ 6 ] = colmat [ 10 ] = colmat [ 14 ] = 1.0f ;
cbufid = 18 ;
2010-10-19 22:24:27 +00:00
break ;
case 11 : // RG8
2011-01-07 19:23:57 +00:00
colmat [ 0 ] = colmat [ 4 ] = colmat [ 8 ] = colmat [ 13 ] = 1.0f ;
cbufid = 19 ;
2010-10-19 22:24:27 +00:00
break ;
case 12 : // GB8
2011-01-07 19:23:57 +00:00
colmat [ 1 ] = colmat [ 5 ] = colmat [ 9 ] = colmat [ 14 ] = 1.0f ;
cbufid = 20 ;
2010-10-19 22:24:27 +00:00
break ;
case 4 : // RGB565
2011-01-07 19:23:57 +00:00
colmat [ 0 ] = colmat [ 5 ] = colmat [ 10 ] = 1.0f ;
ColorMask [ 0 ] = ColorMask [ 2 ] = 31.0f ;
ColorMask [ 4 ] = ColorMask [ 6 ] = 1.0f / 31.0f ;
ColorMask [ 1 ] = 63.0f ;
ColorMask [ 5 ] = 1.0f / 63.0f ;
fConstAdd [ 3 ] = 1.0f ; // set alpha to 1
cbufid = 21 ;
2010-10-19 22:24:27 +00:00
break ;
case 5 : // RGB5A3
2011-01-07 19:23:57 +00:00
colmat [ 0 ] = colmat [ 5 ] = colmat [ 10 ] = colmat [ 15 ] = 1.0f ;
ColorMask [ 0 ] = ColorMask [ 1 ] = ColorMask [ 2 ] = 31.0f ;
ColorMask [ 4 ] = ColorMask [ 5 ] = ColorMask [ 6 ] = 1.0f / 31.0f ;
ColorMask [ 3 ] = 7.0f ;
ColorMask [ 7 ] = 1.0f / 7.0f ;
cbufid = 22 ;
break ;
2010-10-19 22:24:27 +00:00
case 6 : // RGBA8
2011-01-07 19:23:57 +00:00
colmat [ 0 ] = colmat [ 5 ] = colmat [ 10 ] = colmat [ 15 ] = 1.0f ;
cbufid = 23 ;
2010-10-19 22:24:27 +00:00
break ;
default :
2011-02-26 23:41:02 +00:00
ERROR_LOG ( VIDEO , " Unknown copy color format: 0x%x " , dstFormat ) ;
2011-01-07 19:23:57 +00:00
colmat [ 0 ] = colmat [ 5 ] = colmat [ 10 ] = colmat [ 15 ] = 1.0f ;
cbufid = 23 ;
2010-10-19 22:24:27 +00:00
break ;
}
}
2011-02-26 23:41:02 +00:00
const unsigned int tex_w = scaleByHalf ? srcRect . GetWidth ( ) / 2 : srcRect . GetWidth ( ) ;
const unsigned int tex_h = scaleByHalf ? srcRect . GetHeight ( ) / 2 : srcRect . GetHeight ( ) ;
2010-10-19 22:24:27 +00:00
2010-12-10 15:54:14 +00:00
unsigned int scaled_tex_w = g_ActiveConfig . bCopyEFBScaled ? Renderer : : EFBToScaledX ( tex_w ) : tex_w ;
unsigned int scaled_tex_h = g_ActiveConfig . bCopyEFBScaled ? Renderer : : EFBToScaledY ( tex_h ) : tex_h ;
2010-10-19 22:24:27 +00:00
bool texture_is_dynamic = false ;
2011-02-26 23:41:02 +00:00
TCacheEntryBase * entry = textures [ dstAddr ] ;
2010-10-19 22:24:27 +00:00
if ( entry )
{
2011-12-26 16:35:27 +00:00
if ( ( entry - > isRenderTarget & & entry - > virtual_width = = scaled_tex_w & & entry - > virtual_height = = scaled_tex_h )
| | ( entry - > isDynamic & & entry - > native_width = = tex_w & & entry - > native_height = = tex_h ) )
2010-10-19 22:24:27 +00:00
{
texture_is_dynamic = entry - > isDynamic ;
}
else
{
// remove it and recreate it as a render target
delete entry ;
entry = NULL ;
}
}
2010-10-20 00:12:41 +00:00
if ( texture_is_dynamic )
{
2010-10-19 22:24:27 +00:00
scaled_tex_w = tex_w ;
scaled_tex_h = tex_h ;
2010-10-20 00:12:41 +00:00
}
2010-10-19 22:24:27 +00:00
if ( NULL = = entry )
{
// create the texture
2011-02-26 23:41:02 +00:00
textures [ dstAddr ] = entry = g_texture_cache - > CreateRenderTargetTexture ( scaled_tex_w , scaled_tex_h ) ;
2010-10-19 22:24:27 +00:00
2011-12-26 17:05:01 +00:00
// TODO: Using the wrong dstFormat, dumb...
entry - > SetGeneralParameters ( dstAddr , 0 , dstFormat , 0 ) ;
entry - > SetDimensions ( tex_w , tex_h , scaled_tex_w , scaled_tex_h ) ;
entry - > SetEFBCopyParameters ( true , false ) ;
entry - > SetHashes ( TEXHASH_INVALID ) ;
2010-10-19 22:24:27 +00:00
}
entry - > frameCount = frameCount ;
2010-11-18 02:21:26 +00:00
g_renderer - > ResetAPIState ( ) ; // reset any game specific settings
2010-10-19 22:24:27 +00:00
2011-02-26 23:41:02 +00:00
entry - > FromRenderTarget ( dstAddr , dstFormat , srcFormat , srcRect , isIntensity , scaleByHalf , cbufid , colmat ) ;
2010-10-19 22:24:27 +00:00
2010-11-18 02:21:26 +00:00
g_renderer - > RestoreAPIState ( ) ;
2010-12-27 22:17:19 +00:00
}