Merge branch 'texcache-cleanup'

This commit is contained in:
NeoBrainX 2012-01-31 19:58:26 +01:00
commit 013bda74ee
20 changed files with 279 additions and 439 deletions

View File

@ -455,18 +455,14 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
wxStaticBoxSizer* const szr_safetex = new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("Texture Cache"));
// TODO: Use wxSL_MIN_MAX_LABELS or wxSL_VALUE_LABEL with wx 2.9.1
wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 3, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_BOTTOM);
wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 2, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_BOTTOM);
_connect_macro_(stc_slider, VideoConfigDiag::Event_Stc, wxEVT_COMMAND_SLIDER_UPDATED, this);
RegisterControl(stc_slider, wxGetTranslation(stc_desc));
if (vconfig.bSafeTextureCache)
{
if (vconfig.iSafeTextureCache_ColorSamples == 0) stc_slider->SetValue(0);
else if (vconfig.iSafeTextureCache_ColorSamples == 512) stc_slider->SetValue(1);
else if (vconfig.iSafeTextureCache_ColorSamples == 128) stc_slider->SetValue(2);
else stc_slider->Disable(); // Using custom number of samples; TODO: Inform the user why this is disabled..
}
else stc_slider->SetValue(3);
if (vconfig.iSafeTextureCache_ColorSamples == 0) stc_slider->SetValue(0);
else if (vconfig.iSafeTextureCache_ColorSamples == 512) stc_slider->SetValue(1);
else if (vconfig.iSafeTextureCache_ColorSamples == 128) stc_slider->SetValue(2);
else stc_slider->Disable(); // Using custom number of samples; TODO: Inform the user why this is disabled..
szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Accuracy:")), 0, wxALL, 5);
szr_safetex->AddStretchSpacer(1);

View File

@ -120,12 +120,7 @@ protected:
void Event_Stc(wxCommandEvent &ev)
{
int samples[] = { 0, 512, 128 };
if (ev.GetInt() < 3)
{
vconfig.iSafeTextureCache_ColorSamples = samples[ev.GetInt()];
vconfig.bSafeTextureCache = true;
}
else vconfig.bSafeTextureCache = false;
vconfig.iSafeTextureCache_ColorSamples = samples[ev.GetInt()];
ev.Skip();
}

View File

@ -21,7 +21,6 @@
#include "Common.h"
bool SaveTGA(const char* filename, int width, int height, void* pdata);
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height);
bool SaveData(const char* filename, const char* pdata);
#endif // _IMAGEWRITE_H

View File

@ -1,3 +1,19 @@
// Copyright (C) 2003 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "MemoryUtil.h"
@ -23,28 +39,19 @@ enum
TextureCache *g_texture_cache;
GC_ALIGNED16(u8 *TextureCache::temp) = NULL;
GC_ALIGNED16(u8 *TextureCache::temp) = NULL;
TextureCache::TexCache TextureCache::textures;
bool TextureCache::DeferredInvalidate;
TextureCache::TCacheEntryBase::~TCacheEntryBase()
{
if (0 == addr)
return;
if (!isRenderTarget && !g_ActiveConfig.bSafeTextureCache)
{
u32 *const ptr = (u32*)Memory::GetPointer(addr);
if (ptr && *ptr == hash)
*ptr = oldpixel;
}
}
TextureCache::TextureCache()
{
if (!temp)
temp =(u8*) AllocateAlignedMemory(TEMP_SIZE,16);
temp = (u8*)AllocateAlignedMemory(TEMP_SIZE,16);
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
if(g_ActiveConfig.bHiresTextures && !g_ActiveConfig.bDumpTextures)
HiresTextures::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
@ -88,12 +95,11 @@ TextureCache::~TextureCache()
void TextureCache::Cleanup()
{
TexCache::iterator
iter = textures.begin(),
tcend = textures.end();
TexCache::iterator iter = textures.begin();
TexCache::iterator tcend = textures.end();
while (iter != tcend)
{
if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount)
if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) // TODO: Deleting EFB copies might not be a good idea here...
{
delete iter->second;
textures.erase(iter++);
@ -135,7 +141,7 @@ void TextureCache::MakeRangeDynamic(u32 start_address, u32 size)
const int rangePosition = iter->second->IntersectsMemoryRange(start_address, size);
if (0 == rangePosition)
{
iter->second->hash = 0;
iter->second->SetHashes(TEXHASH_INVALID);
}
}
}
@ -167,19 +173,16 @@ void TextureCache::ClearRenderTargets()
iter = textures.begin(),
tcend = textures.end();
for (; iter!=tcend; ++iter)
iter->second->isRenderTarget = false;
iter->second->type = TCET_AUTOFETCH;
}
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;
u8* ptr = Memory::GetPointer(address);
// TexelSizeInNibbles(format)*width*height/16;
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1;
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1;
@ -188,108 +191,77 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
unsigned int expandedHeight = (height + bsh) & (~bsh);
const unsigned int nativeW = width;
const unsigned int nativeH = height;
bool isPow2;
u64 hash_value = 0;
u64 texHash = 0;
u32 texID = address;
u64 tex_hash = TEXHASH_INVALID; // Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup)
u64 tlut_hash = TEXHASH_INVALID;
u32 full_format = texformat;
const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
const u32 palette_size = TexDecoder_GetPaletteSize(texformat);
bool texture_is_dynamic = false;
unsigned int texLevels;
PC_TexFormat pcfmt = PC_TEX_FMT_NONE;
const bool isPaletteTexture = (texformat == GX_TF_C4 || texformat == GX_TF_C8 || texformat == GX_TF_C14X2);
if (isPaletteTexture)
full_format = texformat | (tlutfmt << 16);
// hires texture loading and texture dumping require accurate hashes
if (g_ActiveConfig.bSafeTextureCache || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures)
u8* ptr = Memory::GetPointer(address);
const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
tex_hash = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
if (isPaletteTexture)
{
texHash = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
const u32 palette_size = TexDecoder_GetPaletteSize(texformat);
tlut_hash = GetHash64(&texMem[tlutaddr], palette_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
if (isPaletteTexture)
{
// WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up)
// tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower.
// This trick (to change the texID depending on the TLUT addr) is a trick to get around
// an issue with metroid prime's fonts, where it has multiple sets of fonts on top of
// 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 texture with different tluts get different IDs.
const u64 tlutHash = GetHash64(texMem + tlutaddr, palette_size,
g_ActiveConfig.iSafeTextureCache_ColorSamples);
texHash ^= tlutHash;
if (g_ActiveConfig.bSafeTextureCache)
texID ^= ((u32)tlutHash) ^ (u32)(tlutHash >> 32);
}
if (g_ActiveConfig.bSafeTextureCache)
hash_value = texHash;
// 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
texID ^= ((u32)tlut_hash) ^(u32)(tlut_hash >> 32);
tex_hash ^= tlut_hash;
}
TCacheEntryBase *entry = textures[texID];
if (entry)
{
if (!g_ActiveConfig.bSafeTextureCache)
{
if (entry->isRenderTarget || entry->isDynamic)
{
if (!g_ActiveConfig.bCopyEFBToTexture)
{
hash_value = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
// 1. Calculate reference hash:
// calculated from RAM texture data for normal textures. Hashes for paletted textures are modified by tlut_hash. 0 for virtual EFB copies.
if (g_ActiveConfig.bCopyEFBToTexture && entry->IsEfbCopy())
tex_hash = TEXHASH_INVALID;
if (isPaletteTexture)
{
hash_value ^= GetHash64(&texMem[tlutaddr], palette_size,
g_ActiveConfig.iSafeTextureCache_ColorSamples);
}
}
else
{
hash_value = 0;
}
}
else
{
hash_value = *(u32*)ptr;
}
}
else if ((entry->isRenderTarget || entry->isDynamic) && g_ActiveConfig.bCopyEFBToTexture)
// 2. a) For EFB copies, only the hash and the texture address need to match
if (entry->IsEfbCopy() && tex_hash == entry->hash && address == entry->addr)
{
hash_value = 0;
}
if (((entry->isRenderTarget || entry->isDynamic) && hash_value == entry->hash && address == entry->addr)
|| ((address == entry->addr) && (hash_value == entry->hash) && full_format == entry->format && entry->mipLevels == maxlevel))
{
entry->isDynamic = false;
// 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())
goto return_entry;
}
// 2. b) For normal textures, all texture parameters need to match
if (address == entry->addr && tex_hash == 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.
//
// 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->type == TCET_AUTOFETCH && width == entry->native_width && height == entry->native_height && full_format == entry->format && entry->num_mipmaps == maxlevel)
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height))
{
// reuse the texture
}
else
{
// Let's reload the new texture data into the same texture,
// instead of destroying it and having to create a new one.
// Might speed up movie playback very, very slightly.
texture_is_dynamic = (entry->isRenderTarget || entry->isDynamic) && !g_ActiveConfig.bCopyEFBToTexture;
if (!entry->isRenderTarget &&
((!entry->isDynamic && width == entry->realW && height == entry->realH && full_format == entry->format && entry->mipLevels == maxlevel)
|| (entry->isDynamic && entry->realW == width && entry->realH == height)))
{
// reuse the texture
}
else
{
// delete the texture and make a new one
delete entry;
entry = NULL;
}
// delete the texture and make a new one
delete entry;
entry = NULL;
}
}
@ -301,23 +273,23 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
unsigned int newWidth = width;
unsigned int newHeight = height;
sprintf(texPathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (texHash & 0x00000000FFFFFFFFLL), texformat);
sprintf(texPathTemp, "%s_%08x_%i", SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(), (u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat);
pcfmt = HiresTextures::GetHiresTex(texPathTemp, &newWidth, &newHeight, texformat, temp);
if (pcfmt != PC_TEX_FMT_NONE)
{
expandedWidth = width = newWidth;
expandedHeight = height = newHeight;
// TODO: shouldn't generating mips be forced on now?
// native mips with a custom texture wouldn't make sense
}
}
if (pcfmt == PC_TEX_FMT_NONE)
pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth,
expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
bool isPow2;
unsigned int texLevels;
UseNativeMips = UseNativeMips && (width == nativeW && height == nativeH); // Only load native mips if their dimensions fit to our virtual texture dimensions
isPow2 = !((width & (width - 1)) || (height & (height - 1)));
texLevels = (isPow2 && UseNativeMips && maxlevel) ?
GetPow2(std::max(width, height)) : !isPow2;
@ -332,32 +304,19 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
// 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
entry->mipLevels = maxlevel;
//
// TODO: Won't we end up recreating textures all the time because maxlevel doesn't necessarily equal texLevels?
entry->num_mipmaps = maxlevel; // TODO: Does this actually work? We can't really adjust mipmap settings per-stage...
entry->type = TCET_AUTOFETCH;
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
}
entry->addr = address;
entry->format = full_format;
entry->size_in_bytes = texture_size;
entry->virtualW = width;
entry->virtualH = height;
entry->realW = nativeW;
entry->realH = nativeH;
entry->isRenderTarget = false;
entry->isNonPow2 = false;
entry->isDynamic = texture_is_dynamic;
entry->oldpixel = *(u32*)ptr;
if (g_ActiveConfig.bSafeTextureCache || entry->isDynamic)
entry->hash = hash_value;
else
// don't like rand() here
entry->hash = *(u32*)ptr = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF);
entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
entry->SetDimensions(nativeW, nativeH, width, height);
entry->hash = tex_hash;
if (g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_AUTOFETCH;
else if (entry->IsEfbCopy()) entry->type = TCET_EC_DYNAMIC;
// load texture
entry->Load(width, height, expandedWidth, 0, (texLevels == 0));
@ -381,7 +340,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
expandedHeight = (currentHeight + bsh) & (~bsh);
TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures);
entry->Load(currentWidth, currentHeight, expandedWidth, level);
entry->Load(currentWidth, currentHeight, expandedWidth, level, false);
ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
mipWidth >>= 1;
@ -404,7 +363,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage,
sprintf(szTemp, "%s/%s_%08x_%i.png", szDir.c_str(),
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str(),
(u32) (texHash & 0x00000000FFFFFFFFLL), texformat);
(u32) (tex_hash & 0x00000000FFFFFFFFLL), texformat);
if (false == File::Exists(szTemp))
entry->Save(szTemp);
@ -426,6 +385,45 @@ return_entry:
void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf)
{
// Emulation methods:
// - EFB to RAM:
// Encodes the requested EFB data at its native resolution to the emulated RAM using shaders.
// Load() decodes the data from there again (using TextureDecoder) if the EFB copy is being used as a texture again.
// Advantage: CPU can read data from the EFB copy and we don't lose any important updates to the texture
// Disadvantage: Encoding+decoding steps often are redundant because only some games read or modify EFB copies before using them as textures.
// - EFB to texture:
// Copies the requested EFB data to a texture object in VRAM, performing any color conversion using shaders.
// Advantage: Works for many games, since in most cases EFB copies aren't read or modified at all before being used as a texture again.
// Since we don't do any further encoding or decoding here, this method is much faster.
// It also allows enhancing the visual quality by doing scaled EFB copies.
// - hybrid EFB copies:
// 1a) Whenever this function gets called, encode the requested EFB data to RAM (like EFB to RAM)
// 1b) Set type to TCET_EC_DYNAMIC for all texture cache entries in the destination address range.
// If EFB copy caching is enabled, further checks will (try to) prevent redundant EFB copies.
// 2) Check if a texture cache entry for the specified dstAddr already exists (i.e. if an EFB copy was triggered to that address before):
// 2a) Entry doesn't exist:
// - Also copy the requested EFB data to a texture object in VRAM (like EFB to texture)
// - Create a texture cache entry for the target (type = TCET_EC_VRAM)
// - Store a hash of the encoded RAM data in the texcache entry.
// 2b) Entry exists AND type is TCET_EC_VRAM:
// - Like case 2a, but reuse the old texcache entry instead of creating a new one.
// 2c) Entry exists AND type is TCET_EC_DYNAMIC:
// - Only encode the texture to RAM (like EFB to RAM) and store a hash of the encoded data in the existing texcache entry.
// - Do NOT copy the requested EFB data to a VRAM object. Reason: the texture is dynamic, i.e. the CPU is modifying it. Storing a VRAM copy is useless, because we'd always end up deleting it and reloading the data from RAM anyway.
// 3) If the EFB copy gets used as a texture, compare the source RAM hash with the hash you stored when encoding the EFB data to RAM.
// 3a) If the two hashes match AND type is TCET_EC_VRAM, reuse the VRAM copy you created
// 3b) If the two hashes differ AND type is TCET_EC_VRAM, screw your existing VRAM copy. Set type to TCET_EC_DYNAMIC.
// Redecode the source RAM data to a VRAM object. The entry basically behaves like a normal texture now.
// 3c) If type is TCET_EC_DYNAMIC, treat the EFB copy like a normal texture.
// Advantage: Non-dynamic EFB copies can be visually enhanced like with EFB to texture.
// Compatibility is as good as EFB to RAM.
// Disadvantage: Slower than EFB to texture and often even slower than EFB to RAM.
// EFB copy cache depends on accurate texture hashing being enabled. However, with accurate hashing you end up being as slow as without a copy cache anyway.
//
// Disadvantage of all methods: Calling this function requires the GPU to perform a pipeline flush which stalls any further CPU processing.
//
// For historical reasons, Dolphin doesn't actually implement "pure" EFB to RAM emulation, but only EFB to texture and hybrid EFB copies.
float colmat[28] = {0};
float *const fConstAdd = colmat + 16;
float *const ColorMask = colmat + 20;
@ -628,15 +626,15 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
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;
bool texture_is_dynamic = false;
TCacheEntryBase *entry = textures[dstAddr];
if (entry)
{
if ((entry->isRenderTarget && entry->virtualW == scaled_tex_w && entry->virtualH == scaled_tex_h)
|| (entry->isDynamic && entry->realW == tex_w && entry->realH == tex_h))
if ((entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h)
|| (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h))
{
texture_is_dynamic = entry->isDynamic;
scaled_tex_w = tex_w;
scaled_tex_h = tex_h;
}
else
{
@ -646,32 +644,16 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
}
}
if (texture_is_dynamic)
{
scaled_tex_w = tex_w;
scaled_tex_h = tex_h;
}
if (NULL == entry)
{
// create the texture
textures[dstAddr] = entry = g_texture_cache->CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h);
entry->addr = dstAddr;
entry->hash = 0;
entry->realW = tex_w;
entry->realH = tex_h;
entry->virtualW = scaled_tex_w;
entry->virtualH = scaled_tex_h;
entry->format = dstFormat;
entry->mipLevels = 0;
entry->isRenderTarget = true;
entry->isNonPow2 = true;
entry->isDynamic = false;
// 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->SetHashes(TEXHASH_INVALID);
entry->type = TCET_EC_VRAM;
}
entry->frameCount = frameCount;

View File

@ -1,3 +1,19 @@
// Copyright (C) 2003 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _TEXTURECACHEBASE_H
#define _TEXTURECACHEBASE_H
@ -14,47 +30,57 @@
class TextureCache
{
public:
enum TexCacheEntryType
{
TCET_AUTOFETCH, // Most textures, automatically fetched whenever they change
// TCET_PRELOADED, // Textures which reside in TMEM areas which are manually managed by the game
TCET_EC_VRAM, // EFB copy which sits in VRAM and is ready to be used
TCET_EC_DYNAMIC, // EFB copy which sits in RAM and needs to be decoded before being used
};
struct TCacheEntryBase
{
// TODO: organize
#define TEXHASH_INVALID 0
// common members
u32 addr;
u32 size_in_bytes;
u64 hash;
//u32 paletteHash;
u32 oldpixel;
//u32 pal_hash;
u32 format;
enum TexCacheEntryType type;
unsigned int num_mipmaps;
unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view
unsigned int virtual_width, virtual_height; // Texture dimensions from OUR point of view - for hires textures or scaled EFB copies
// used to delete textures which haven't been used for TEXTURE_KILL_THRESHOLD frames
int frameCount;
unsigned int realW, realH; // Texture dimensions from the GameCube's point of view
unsigned int virtualW, virtualH; // Texture dimensions from OUR point of view
// Real and virtual dimensions are usually the same, but may be
// different if e.g. we use high-res textures. Then, realW,realH will
// be the dimensions of the original GameCube texture and
// virtualW,virtualH will be the dimensions of the high-res texture.
unsigned int mipLevels;
void SetGeneralParameters(u32 addr, u32 size, u32 format, unsigned int num_mipmaps)
{
this->addr = addr;
this->size_in_bytes = size;
this->format = format;
this->num_mipmaps = num_mipmaps;
}
bool isRenderTarget; // copied from EFB
bool isDynamic; // Used for hybrid EFB copies to enable checks for CPU modifications
bool isNonPow2; // doesn't seem to be used anywhere
void SetDimensions(unsigned int native_width, unsigned int native_height, unsigned int virtual_width, unsigned int virtual_height)
{
this->native_width = native_width;
this->native_height = native_height;
this->virtual_width = virtual_width;
this->virtual_height = virtual_height;
}
void SetHashes(u64 hash/*, u32 pal_hash*/)
{
this->hash = hash;
//this->pal_hash = pal_hash;
}
//TCacheEntryBase()
//{
// // TODO: remove these
// isRenderTarget = 0;
// hash = 0;
// //paletteHash = 0;
// oldpixel = 0;
// addr = 0;
// size_in_bytes = 0;
// frameCount = 0;
// isNonPow2 = true;
// w = 0;
// h = 0;
// scaledW = 0;
// scaledH = 0;
//}
virtual ~TCacheEntryBase();
@ -62,13 +88,15 @@ public:
virtual bool Save(const char filename[]) = 0;
virtual void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips = false) = 0;
unsigned int expanded_width, unsigned int level, bool autogen_mips) = 0;
virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
const float *colmat) = 0;
int IntersectsMemoryRange(u32 range_address, u32 range_size) const;
bool IsEfbCopy() { return (type == TCET_EC_VRAM || type == TCET_EC_DYNAMIC); }
};
virtual ~TextureCache(); // needs virtual for DX11 dtor

View File

@ -58,11 +58,7 @@ void VideoConfig::Load(const char *ini_file)
iniFile.Get("Settings", "UseXFB", &bUseXFB, 0);
iniFile.Get("Settings", "UseRealXFB", &bUseRealXFB, 0);
iniFile.Get("Settings", "UseNativeMips", &bUseNativeMips, false);
iniFile.Get("Settings", "SafeTextureCache", &bSafeTextureCache, true); // Settings
//Safe texture cache params
iniFile.Get("Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples,128);
iniFile.Get("Settings", "ShowFPS", &bShowFPS, false); // Settings
iniFile.Get("Settings", "ShowInputDisplay", &bShowInputDisplay, false);
iniFile.Get("Settings", "OverlayStats", &bOverlayStats, false);
@ -134,7 +130,6 @@ void VideoConfig::GameIniLoad(const char *ini_file)
iniFile.GetIfExists("Video_Settings", "UseXFB", &bUseXFB);
iniFile.GetIfExists("Video_Settings", "UseRealXFB", &bUseRealXFB);
iniFile.GetIfExists("Video_Settings", "UseNativeMips", &bUseNativeMips);
iniFile.GetIfExists("Video_Settings", "SafeTextureCache", &bSafeTextureCache);
iniFile.GetIfExists("Video_Settings", "SafeTextureCacheColorSamples", &iSafeTextureCache_ColorSamples);
iniFile.GetIfExists("Video_Settings", "DLOptimize", &iCompileDLsLevel);
iniFile.GetIfExists("Video_Settings", "HiresTextures", &bHiresTextures);
@ -196,11 +191,7 @@ void VideoConfig::Save(const char *ini_file)
iniFile.Set("Settings", "UseXFB", bUseXFB);
iniFile.Set("Settings", "UseRealXFB", bUseRealXFB);
iniFile.Set("Settings", "UseNativeMips", bUseNativeMips);
iniFile.Set("Settings", "SafeTextureCache", bSafeTextureCache);
//safe texture cache params
iniFile.Set("Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
iniFile.Set("Settings", "ShowFPS", bShowFPS);
iniFile.Set("Settings", "ShowInputDisplay", bShowInputDisplay);
iniFile.Set("Settings", "OverlayStats", bOverlayStats);
@ -279,7 +270,6 @@ void VideoConfig::GameIniSave(const char* default_ini, const char* game_ini)
SET_IF_DIFFERS("Video_Settings", "UseXFB", bUseXFB);
SET_IF_DIFFERS("Video_Settings", "UseRealXFB", bUseRealXFB);
SET_IF_DIFFERS("Video_Settings", "UseNativeMips", bUseNativeMips);
SET_IF_DIFFERS("Video_Settings", "SafeTextureCache", bSafeTextureCache);
SET_IF_DIFFERS("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
SET_IF_DIFFERS("Video_Settings", "DLOptimize", iCompileDLsLevel);
SET_IF_DIFFERS("Video_Settings", "HiresTextures", bHiresTextures);

View File

@ -129,7 +129,6 @@ struct VideoConfig
bool bOSDHotKey;
bool bCopyEFBToTexture;
bool bCopyEFBScaled;
bool bSafeTextureCache;
int iSafeTextureCache_ColorSamples;
int iPhackvalue[4];
std::string sPhackvalue[2];

View File

@ -1106,12 +1106,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
DLCache::ProgressiveCleanup();
TextureCache::Cleanup();
// reload textures if these settings changed
if (g_Config.bSafeTextureCache != g_ActiveConfig.bSafeTextureCache ||
g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
// Reload textures if this settings changes
if (g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
TextureCache::Invalidate(false);
// Enable any configuration changes
// Enable configuration changes
UpdateActiveConfig();
SetWindowSize(fbWidth, fbHeight);

View File

@ -102,12 +102,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
const float *colmat)
{
if (!isDynamic || g_ActiveConfig.bCopyEFBToTexture)
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
{
g_renderer->ResetAPIState();
// stretch picture with increased internal resolution
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)virtualW, (float)virtualH);
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)virtual_width, (float)virtual_height);
D3D::context->RSSetViewports(1, &vp);
// set transformation
@ -149,17 +149,15 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
if (!g_ActiveConfig.bCopyEFBToTexture)
{
u8* dst = Memory::GetPointer(dstAddr);
size_t encodeSize = g_encoder->Encode(dst, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf);
hash = GetHash64(dst, encodeSize, g_ActiveConfig.iSafeTextureCache_ColorSamples);
if (g_ActiveConfig.bEFBCopyCacheEnable)
{
// If the texture in RAM is already in the texture cache,
// do not copy it again as it has not changed.
if (TextureCache::Find(dstAddr, hash))
return;
}
size_t encoded_size = g_encoder->Encode(dst, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf);
TextureCache::MakeRangeDynamic(dstAddr, encodeSize);
hash = GetHash64(dst, (int)encoded_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
if (!g_ActiveConfig.bEFBCopyCacheEnable)
TextureCache::MakeRangeDynamic(addr, (u32)encoded_size);
else if (!TextureCache::Find(addr, hash))
TextureCache::MakeRangeDynamic(addr, (u32)encoded_size);
}
}

View File

@ -233,7 +233,7 @@ void VertexManager::vFlush()
if (tentry)
{
// 0s are probably for no manual wrapping needed.
PixelShaderManager::SetTexDims(i, tentry->realW, tentry->realH, 0, 0);
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
}
else
ERROR_LOG(VIDEO, "error loading texture");

View File

@ -1114,12 +1114,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
DLCache::ProgressiveCleanup();
TextureCache::Cleanup();
// reload textures if these settings changed
if (g_Config.bSafeTextureCache != g_ActiveConfig.bSafeTextureCache ||
g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
// Reload textures if these settings changed
if (g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
TextureCache::Invalidate(false);
// Enable any configuration changes
// Enable configuration changes
UpdateActiveConfig();
SetWindowSize(fbWidth, fbHeight);

View File

@ -21,6 +21,7 @@
#include "Statistics.h"
#include "MemoryUtil.h"
#include "Hash.h"
#include "HW/Memmap.h"
#include "CommonPaths.h"
#include "FileUtil.h"
@ -78,7 +79,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
FramebufferManager::GetEFBDepthTexture() :
FramebufferManager::GetEFBColorTexture();
if (!isDynamic || g_ActiveConfig.bCopyEFBToTexture)
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
{
LPDIRECT3DSURFACE9 Rendersurf = NULL;
texture->GetSurfaceLevel(0, &Rendersurf);
@ -90,15 +91,15 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
// Stretch picture with increased internal resolution
vp.X = 0;
vp.Y = 0;
vp.Width = virtualW;
vp.Height = virtualH;
vp.Width = virtual_width;
vp.Height = virtual_height;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
D3D::dev->SetViewport(&vp);
RECT destrect;
destrect.bottom = virtualH;
destrect.bottom = virtual_height;
destrect.left = 0;
destrect.right = virtualW;
destrect.right = virtual_width;
destrect.top = 0;
PixelShaderManager::SetColorMatrix(colmat); // set transformation
@ -133,7 +134,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
D3D::drawShadedTexQuad(read_texture, &sourcerect,
Renderer::GetTargetWidth(), Renderer::GetTargetHeight(),
virtualW, virtualH,
virtual_width, virtual_height,
// TODO: why is D3DFMT_D24X8 singled out here? why not D3DFMT_D24X4S4/D24S8/D24FS8/D32/D16/D15S1 too, or none of them?
PixelShaderCache::GetDepthMatrixProgram(SSAAMode, (srcFormat == PIXELFMT_Z24) && bformat != FOURCC_RAWZ && bformat != D3DFMT_D24X8),
VertexShaderCache::GetSimpleVertexShader(SSAAMode));
@ -143,16 +144,25 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
if (!g_ActiveConfig.bCopyEFBToTexture)
{
hash = TextureConverter::EncodeToRamFromTexture(
addr,
read_texture,
Renderer::GetTargetWidth(),
Renderer::GetTargetHeight(),
srcFormat == PIXELFMT_Z24,
isIntensity,
dstFormat,
scaleByHalf,
srcRect);
int encoded_size = TextureConverter::EncodeToRamFromTexture(
addr,
read_texture,
Renderer::GetTargetWidth(),
Renderer::GetTargetHeight(),
srcFormat == PIXELFMT_Z24,
isIntensity,
dstFormat,
scaleByHalf,
srcRect);
u8* dst = Memory::GetPointer(addr);
hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
if (!g_ActiveConfig.bEFBCopyCacheEnable)
TextureCache::MakeRangeDynamic(addr,encoded_size);
else if (!TextureCache::Find(addr, hash))
TextureCache::MakeRangeDynamic(addr,encoded_size);
}
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);

View File

@ -313,76 +313,7 @@ void EncodeToRamUsingShader(LPDIRECT3DPIXELSHADER9 shader, LPDIRECT3DTEXTURE9 sr
hr = s_texConvReadSurface->UnlockRect();
}
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
{
u32 format = copyfmt;
if (bFromZBuffer)
{
format |= _GX_TF_ZTF;
if (copyfmt == 11)
format = GX_TF_Z16;
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
format |= _GX_TF_CTF;
}
else
if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt))
format |= _GX_TF_CTF;
LPDIRECT3DPIXELSHADER9 texconv_shader = GetOrCreateEncodingShader(format);
if (!texconv_shader)
return;
u8 *dest_ptr = Memory::GetPointer(address);
LPDIRECT3DTEXTURE9 source_texture = bFromZBuffer ? FramebufferManager::GetEFBDepthTexture() : FramebufferManager::GetEFBColorTexture();
int width = (source.right - source.left) >> bScaleByHalf;
int height = (source.bottom - source.top) >> bScaleByHalf;
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
// Invalidate any existing texture covering this memory range.
// TODO - don't delete the texture if it already exists, just replace the contents.
TextureCache::InvalidateRange(address, size_in_bytes);
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
// only copy on cache line boundaries
// extra pixels are copied but not displayed in the resulting texture
s32 expandedWidth = (width + blkW) & (~blkW);
s32 expandedHeight = (height + blkH) & (~blkH);
float sampleStride = bScaleByHalf ? 2.f : 1.f;
TextureConversionShader::SetShaderParameters(
(float)expandedWidth,
(float)Renderer::EFBToScaledY(expandedHeight), // TODO: Why do we scale this?
(float)Renderer::EFBToScaledX(source.left),
(float)Renderer::EFBToScaledY(source.top),
Renderer::EFBToScaledXf(sampleStride),
Renderer::EFBToScaledYf(sampleStride),
(float)Renderer::GetTargetWidth(),
(float)Renderer::GetTargetHeight());
TargetRectangle scaledSource;
scaledSource.top = 0;
scaledSource.bottom = expandedHeight;
scaledSource.left = 0;
scaledSource.right = expandedWidth / samples;
int cacheBytes = 32;
if ((format & 0x0f) == 6)
cacheBytes = 64;
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
g_renderer->ResetAPIState();
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0,1.0f);
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
g_renderer->RestoreAPIState();
}
u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
int EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
{
u32 format = copyfmt;
@ -440,16 +371,7 @@ u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 So
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0,1.0f);
u64 hash = GetHash64(dest_ptr,size_in_bytes,g_ActiveConfig.iSafeTextureCache_ColorSamples);
if (g_ActiveConfig.bEFBCopyCacheEnable)
{
// If the texture in RAM is already in the texture cache, do not copy it again as it has not changed.
if (TextureCache::Find(address, hash))
return hash;
}
TextureCache::MakeRangeDynamic(address,size_in_bytes);
return hash;
return size_in_bytes; // TODO: D3D11 is calculating this value differently!
}
void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight,float Gamma)

View File

@ -35,15 +35,13 @@ namespace TextureConverter
void Init();
void Shutdown();
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc,
u8* destAddr, int dstWidth, int dstHeight,float Gamma);
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture);
u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
// returns size of the encoded data (in bytes)
int EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
}

View File

@ -142,7 +142,7 @@ void VertexManager::vFlush()
if (tentry)
{
// 0s are probably for no manual wrapping needed.
PixelShaderManager::SetTexDims(i, tentry->realW, tentry->realH, 0, 0);
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
}
else
ERROR_LOG(VIDEO, "error loading texture");

View File

@ -1394,8 +1394,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
g_Config.iSaveTargetId = 0;
// reload textures if these settings changed
if (g_Config.bSafeTextureCache != g_ActiveConfig.bSafeTextureCache ||
g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
if (g_Config.bUseNativeMips != g_ActiveConfig.bUseNativeMips)
TextureCache::Invalidate(false);
if (g_Config.bCopyEFBToTexture != g_ActiveConfig.bCopyEFBToTexture)

View File

@ -39,6 +39,7 @@
#include "Globals.h"
#include "Hash.h"
#include "HiresTextures.h"
#include "HW/Memmap.h"
#include "ImageWrite.h"
#include "MemoryUtil.h"
#include "PixelShaderCache.h"
@ -124,7 +125,7 @@ bool TextureCache::TCacheEntry::Save(const char filename[])
std::string tga_filename(filename);
tga_filename.replace(tga_filename.size() - 3, 3, "tga");
return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, realW, realH);
return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height);
}
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
@ -278,7 +279,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
GL_REPORT_ERRORD();
if (false == isDynamic || g_ActiveConfig.bCopyEFBToTexture)
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
{
if (s_TempFramebuffer == 0)
glGenFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
@ -294,7 +295,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, read_texture);
glViewport(0, 0, virtualW, virtualH);
glViewport(0, 0, virtual_width, virtual_height);
PixelShaderCache::SetCurrentShader((srcFormat == PIXELFMT_Z24) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram());
PixelShaderManager::SetColorMatrix(colmat); // set transformation
@ -317,7 +318,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
if (false == g_ActiveConfig.bCopyEFBToTexture)
{
hash = TextureConverter::EncodeToRamFromTexture(
int encoded_size = TextureConverter::EncodeToRamFromTexture(
addr,
read_texture,
srcFormat == PIXELFMT_Z24,
@ -325,6 +326,15 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
dstFormat,
scaleByHalf,
srcRect);
u8* dst = Memory::GetPointer(addr);
hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
if (!g_ActiveConfig.bEFBCopyCacheEnable)
TextureCache::MakeRangeDynamic(addr,encoded_size);
else if (!TextureCache::Find(addr, hash))
TextureCache::MakeRangeDynamic(addr,encoded_size);
}
FramebufferManager::SetFramebuffer(0);
@ -337,7 +347,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
{
static int count = 0;
SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
count++).c_str(), GL_TEXTURE_2D, texture, realW, realH);
count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height);
}
}

View File

@ -250,78 +250,7 @@ void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const Tar
}
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
{
u32 format = copyfmt;
if (bFromZBuffer)
{
format |= _GX_TF_ZTF;
if (copyfmt == 11)
format = GX_TF_Z16;
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
format |= _GX_TF_CTF;
}
else
if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt))
format |= _GX_TF_CTF;
FRAGMENTSHADER& texconv_shader = GetOrCreateEncodingShader(format);
if (texconv_shader.glprogid == 0)
return;
u8 *dest_ptr = Memory::GetPointer(address);
GLuint source_texture = bFromZBuffer ? FramebufferManager::ResolveAndGetDepthTarget(source) : FramebufferManager::ResolveAndGetRenderTarget(source);
int width = (source.right - source.left) >> bScaleByHalf;
int height = (source.bottom - source.top) >> bScaleByHalf;
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
// Invalidate any existing texture covering this memory range.
// TODO - don't delete the texture if it already exists, just replace the contents.
TextureCache::InvalidateRange(address, size_in_bytes);
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
// only copy on cache line boundaries
// extra pixels are copied but not displayed in the resulting texture
s32 expandedWidth = (width + blkW) & (~blkW);
s32 expandedHeight = (height + blkH) & (~blkH);
float sampleStride = bScaleByHalf ? 2.f : 1.f;
TextureConversionShader::SetShaderParameters(
(float)expandedWidth,
(float)Renderer::EFBToScaledY(expandedHeight), // TODO: Why do we scale this?
(float)Renderer::EFBToScaledX(source.left),
(float)Renderer::EFBToScaledY(EFB_HEIGHT - source.top - expandedHeight),
Renderer::EFBToScaledXf(sampleStride),
Renderer::EFBToScaledYf(sampleStride));
TargetRectangle scaledSource;
scaledSource.top = 0;
scaledSource.bottom = expandedHeight;
scaledSource.left = 0;
scaledSource.right = expandedWidth / samples;
int cacheBytes = 32;
if ((format & 0x0f) == 6)
cacheBytes = 64;
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
g_renderer->ResetAPIState();
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0);
FramebufferManager::SetFramebuffer(0);
VertexShaderManager::SetViewportChanged();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
TextureCache::DisableStage(0);
g_renderer->RestoreAPIState();
GL_REPORT_ERRORD();
}
u64 EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
{
u32 format = copyfmt;
@ -379,19 +308,8 @@ u64 EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource,
dest_ptr, expandedWidth / samples, expandedHeight, readStride,
true, bScaleByHalf > 0 && !bFromZBuffer);
return size_in_bytes; // TODO: D3D11 is calculating this value differently!
u64 hash = GetHash64(dest_ptr, size_in_bytes,
g_ActiveConfig.iSafeTextureCache_ColorSamples);
if (g_ActiveConfig.bEFBCopyCacheEnable)
{
// If the texture in RAM is already in the texture cache,
// do not copy it again as it has not changed.
if (TextureCache::Find(address, hash))
return hash;
}
TextureCache::MakeRangeDynamic(address,size_in_bytes);
return hash;
}
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight)

View File

@ -32,15 +32,13 @@ namespace TextureConverter
void Init();
void Shutdown();
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc,
u8* destAddr, int dstWidth, int dstHeight);
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);
u64 EncodeToRamFromTexture(u32 address, GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
// returns size of the encoded data (in bytes)
int EncodeToRamFromTexture(u32 address, GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
}

View File

@ -160,7 +160,7 @@ void VertexManager::vFlush()
if (tentry)
{
// 0s are probably for no manual wrapping needed.
PixelShaderManager::SetTexDims(i, tentry->realW, tentry->realH, 0, 0);
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
if (g_ActiveConfig.iLog & CONF_SAVETEXTURES)
{