From dabb35afce2539b312935d2fcfe264018d24dbec Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sun, 29 Jan 2012 21:17:22 +0100 Subject: [PATCH 1/3] Prepare texture preloading support --- .../Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp | 8 ++-- Source/Core/VideoCommon/Src/BPMemory.h | 41 +++++++++++++------ Source/Core/VideoCommon/Src/BPStructs.cpp | 27 ++++++++---- Source/Core/VideoCommon/Src/TextureDecoder.h | 4 +- .../Plugin_VideoSoftware/Src/BPMemLoader.cpp | 6 +-- 5 files changed, 56 insertions(+), 30 deletions(-) diff --git a/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp b/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp index 4b22e8f851..58ad9eded3 100644 --- a/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp +++ b/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp @@ -85,14 +85,14 @@ void LoadBPReg(const BPCmd &bp, BPMemory &bpMem) void GetTlutLoadData(u32 &tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &bpMem) { - tlutAddr = (bpMem.tlutXferDest & 0x3FF) << 9; - tlutXferCount = (bpMem.tlutXferDest & 0x1FFC00) >> 5; + tlutAddr = (bpMem.tmem_config.tlut_dest & 0x3FF) << 9; + tlutXferCount = (bpMem.tmem_config.tlut_dest & 0x1FFC00) >> 5; // TODO - figure out a cleaner way. if (Core::g_CoreStartupParameter.bWii) - memAddr = bpmem.tlutXferSrc << 5; + memAddr = bpmem.tmem_config.tlut_src << 5; else - memAddr = (bpmem.tlutXferSrc & 0xFFFFF) << 5; + memAddr = (bpmem.tmem_config.tlut_src & 0xFFFFF) << 5; } void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem) diff --git a/Source/Core/VideoCommon/Src/BPMemory.h b/Source/Core/VideoCommon/Src/BPMemory.h index 1f6f453a77..0bb2bf9013 100644 --- a/Source/Core/VideoCommon/Src/BPMemory.h +++ b/Source/Core/VideoCommon/Src/BPMemory.h @@ -65,10 +65,10 @@ #define BPMEM_UNKOWN_57 0x57 #define BPMEM_REVBITS 0x58 #define BPMEM_SCISSOROFFSET 0x59 -#define BPMEM_UNKNOWN_60 0x60 -#define BPMEM_UNKNOWN_61 0x61 -#define BPMEM_UNKNOWN_62 0x62 -#define BPMEM_TEXMODESYNC 0x63 +#define BPMEM_PRELOAD_ADDR 0x60 +#define BPMEM_PRELOAD_TMEMEVEN 0x61 +#define BPMEM_PRELOAD_TMEMODD 0x62 +#define BPMEM_PRELOAD_MODE 0x63 #define BPMEM_LOADTLUT0 0x64 #define BPMEM_LOADTLUT1 0x65 #define BPMEM_TEXINVALIDATE 0x66 @@ -487,10 +487,10 @@ union TexImage1 { struct { - u32 tmem_offset : 15; // we ignore texture caching for now, we do it ourselves - u32 cache_width : 3; + u32 tmem_even : 15; // tmem line index for even LODs + u32 cache_width : 3; u32 cache_height : 3; - u32 image_type : 1; + u32 image_type : 1; // 1 if this texture is managed manually (0 means we'll autofetch the texture data whenever it changes) }; u32 hex; }; @@ -499,7 +499,7 @@ union TexImage2 { struct { - u32 tmem_offset : 15; // we ignore texture caching for now, we do it ourselves + u32 tmem_odd : 15; // tmem line index for odd LODs u32 cache_width : 3; u32 cache_height : 3; }; @@ -893,6 +893,25 @@ union UPE_Copy } }; +union BPU_PreloadTileInfo +{ + u32 hex; + struct { + u32 count : 15; + u32 type : 2; + }; +}; + +struct BPS_TmemConfig +{ + u32 preload_addr; + u32 preload_tmem_even; + u32 preload_tmem_odd; + BPU_PreloadTileInfo preload_tile_info; + u32 tlut_src; + u32 tlut_dest; + u32 texinvalidate; +}; // All of BP memory @@ -951,10 +970,8 @@ struct BPMemory u32 boundbox1;//56 u32 unknown7[2];//57,58 X10Y10 scissorOffset; //59 - u32 unknown8[10]; //5a,5b,5c,5d, 5e,5f,60,61, 62, 63 (GXTexModeSync), 0x60-0x63 have to do with preloaded textures? - u32 tlutXferSrc; //64 - u32 tlutXferDest; //65 - u32 texinvalidate;//66 + u32 unknown8[6]; //5a,5b,5c,5d, 5e,5f + BPS_TmemConfig tmem_config; // 60-66 u32 metric; //67 FieldMode fieldmode;//68 u32 unknown10[7];//69-6F diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index d06f1de8b9..6cb102555b 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -30,6 +30,7 @@ #include "VertexLoader.h" #include "VertexShaderManager.h" #include "Thread.h" +#include "HW/Memmap.h" using namespace BPFunctions; @@ -301,14 +302,14 @@ void BPWritten(const BPCmd& bp) // TODO - figure out a cleaner way. if (GetConfig(CONFIG_ISWII)) - ptr = GetPointer(bpmem.tlutXferSrc << 5); + ptr = GetPointer(bpmem.tmem_config.tlut_src << 5); else - ptr = GetPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5); + ptr = GetPointer((bpmem.tmem_config.tlut_src & 0xFFFFF) << 5); if (ptr) memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount); else - PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5); + PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tmem_config.tlut_src, bpmem.tmem_config.tlut_src << 5, (bpmem.tmem_config.tlut_src & 0xFFFFF)<< 5); // TODO(ector) : kill all textures that use this palette // Not sure if it's a good idea, though. For now, we hash texture palettes @@ -466,14 +467,22 @@ void BPWritten(const BPCmd& bp) DEBUG_LOG(VIDEO, "Uknown BP Reg 0x57: %08x", bp.newvalue); break; - case BPMEM_UNKNOWN_60: - case BPMEM_UNKNOWN_61: - case BPMEM_UNKNOWN_62: - // Cases added due to: http://code.google.com/p/dolphin-emu/issues/detail?id=360#c90 - // Are these related to BBox? + case BPMEM_PRELOAD_ADDR: + case BPMEM_PRELOAD_TMEMEVEN: + case BPMEM_PRELOAD_TMEMODD: // Used when PRELOAD_MODE is set break; - case BPMEM_TEXMODESYNC: // Always set to 0 when GX_TexModeSync() is called. + case BPMEM_PRELOAD_MODE: // Set to 0 when GX_TexModeSync() is called. + // if this is different from 0, manual TMEM management is used. + if (bp.newvalue != 0) + { + // NOTE(neobrain): Apparently tmemodd doesn't affect hardware behavior at all (libogc uses it just as a buffer and switches its contents with tmemeven whenever this is called) + BPS_TmemConfig& tmem_cfg = bpmem.tmem_config; + u8* ram_ptr = Memory::GetPointer(tmem_cfg.preload_addr << 5); + u32 tmem_addr = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE; + u32 size = tmem_cfg.preload_tile_info.count * 32; + memcpy(texMem + tmem_addr, ram_ptr, size); + } break; // ------------------------------------------------ diff --git a/Source/Core/VideoCommon/Src/TextureDecoder.h b/Source/Core/VideoCommon/Src/TextureDecoder.h index d990d21545..1901c86d27 100644 --- a/Source/Core/VideoCommon/Src/TextureDecoder.h +++ b/Source/Core/VideoCommon/Src/TextureDecoder.h @@ -20,8 +20,8 @@ #include "Hash.h" enum { - TMEM_SIZE = 1024*1024, - HALFTMEM_SIZE = 512*1024 + TMEM_SIZE = 1024*1024, + TMEM_LINE_SIZE = 32, }; extern GC_ALIGNED16(u8 texMem[TMEM_SIZE]); diff --git a/Source/Plugins/Plugin_VideoSoftware/Src/BPMemLoader.cpp b/Source/Plugins/Plugin_VideoSoftware/Src/BPMemLoader.cpp index 404424f634..95ec555181 100644 --- a/Source/Plugins/Plugin_VideoSoftware/Src/BPMemLoader.cpp +++ b/Source/Plugins/Plugin_VideoSoftware/Src/BPMemLoader.cpp @@ -101,14 +101,14 @@ void SWBPWritten(int address, int newvalue) // TODO - figure out a cleaner way. if (Core::g_CoreStartupParameter.bWii) - ptr = Memory::GetPointer(bpmem.tlutXferSrc << 5); + ptr = Memory::GetPointer(bpmem.tmem_config.tlut_src << 5); else - ptr = Memory::GetPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5); + ptr = Memory::GetPointer((bpmem.tmem_config.tlut_src & 0xFFFFF) << 5); if (ptr) memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount); else - PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5); + PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tmem_config.tlut_src, bpmem.tmem_config.tlut_src << 5, (bpmem.tmem_config.tlut_src & 0xFFFFF)<< 5); break; } From eb01a110c9573ae0e822eefd3cc8c58d92774588 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sun, 29 Jan 2012 21:49:50 +0100 Subject: [PATCH 2/3] Implement texture preloading --- .../Core/VideoCommon/Src/TextureCacheBase.cpp | 42 ++++++++++++------- .../Core/VideoCommon/Src/TextureCacheBase.h | 5 +-- .../Plugin_VideoDX11/Src/VertexManager.cpp | 3 +- .../Plugin_VideoDX9/Src/VertexManager.cpp | 3 +- .../Plugin_VideoOGL/Src/VertexManager.cpp | 3 +- 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index f37e4b2dd5..7873d1474e 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -173,12 +173,12 @@ void TextureCache::ClearRenderTargets() iter = textures.begin(), tcend = textures.end(); for (; iter!=tcend; ++iter) - iter->second->type = TCET_AUTOFETCH; + iter->second->type = TCET_NORMAL; } 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) + unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem) { if (0 == address) return NULL; @@ -203,10 +203,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, if (isPaletteTexture) full_format = texformat | (tlutfmt << 16); - u8* ptr = Memory::GetPointer(address); const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat); + u8* src_data; + if (from_tmem) src_data = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE]; + else src_data = Memory::GetPointer(address); - tex_hash = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); + tex_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); if (isPaletteTexture) { const u32 palette_size = TexDecoder_GetPaletteSize(texformat); @@ -225,7 +227,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, tex_hash ^= tlut_hash; } - TCacheEntryBase *entry = textures[texID]; + TCacheEntryBase *entry = textures[texID]; // TODO: Should use a different texID for preloaded textures! if (entry) { // 1. Calculate reference hash: @@ -252,7 +254,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, // // 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) + if ((entry->type == TCET_NORMAL && 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 @@ -283,8 +285,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, } } + // TODO: RGBA8 textures are stored non-continuously in tmem, that might cause problems when preloading is enabled if (pcfmt == PC_TEX_FMT_NONE) - pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth, + pcfmt = TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures); bool isPow2; @@ -301,13 +304,13 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, if (NULL == entry) { textures[texID] = entry = g_texture_cache->CreateTexture(width, height, expandedWidth, texLevels, pcfmt); - // Sometimes, we can get around recreating a texture if only the number of mip levels gets changes + // Sometimes, we can get around recreating a texture if only the number of mip levels 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 // // 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; + entry->type = TCET_NORMAL; GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true); } @@ -315,13 +318,13 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, 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; + if (g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_NORMAL; else if (entry->IsEfbCopy()) entry->type = TCET_EC_DYNAMIC; // load texture entry->Load(width, height, expandedWidth, 0, (texLevels == 0)); - // load mips + // load mips - TODO: Loading mipmaps from tmem is untested! if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE) { const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat); @@ -329,20 +332,31 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, unsigned int level = 1; unsigned int mipWidth = (width + 1) >> 1; unsigned int mipHeight = (height + 1) >> 1; - ptr += texture_size; + + u8* ptr_even = NULL, *ptr_odd = NULL; + if (from_tmem) + { + ptr_even = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE + texture_size]; + ptr_odd = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE]; + } + src_data += texture_size; while ((mipHeight || mipWidth) && (level < texLevels)) { + u8** ptr; + if (from_tmem) ptr = (level % 2) ? &ptr_odd : &ptr_even; + else ptr = &src_data; + const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1; const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1; expandedWidth = (currentWidth + bsw) & (~bsw); expandedHeight = (currentHeight + bsh) & (~bsh); - TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures); + TexDecoder_Decode(temp, *ptr, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures); entry->Load(currentWidth, currentHeight, expandedWidth, level, false); - ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1); + *ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1); mipWidth >>= 1; mipHeight >>= 1; ++level; diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.h b/Source/Core/VideoCommon/Src/TextureCacheBase.h index 7ae650a927..2924c5871f 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.h +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.h @@ -32,8 +32,7 @@ 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_NORMAL, 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 }; @@ -115,7 +114,7 @@ public: virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 0; static TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, unsigned int height, - int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel); + int format, unsigned int tlutaddr, int tlutfmt, bool UseNativeMips, unsigned int maxlevel, bool from_tmem); static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, unsigned int srcFormat, const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf); diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp index 9087b6dac1..d0f5a1c338 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp @@ -228,7 +228,8 @@ void VertexManager::vFlush() tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, tex.texTlut[i&3].tlut_format, (tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips, - (tex.texMode1[i&3].max_lod >> 4)); + tex.texMode1[i&3].max_lod >> 4, + tex.texImage1[i&3].image_type); if (tentry) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp index c6bddb7468..c4e8225db1 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp @@ -137,7 +137,8 @@ void VertexManager::vFlush() tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, tex.texTlut[i&3].tlut_format, (tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips, - (tex.texMode1[i&3].max_lod >> 4)); + tex.texMode1[i&3].max_lod >> 4, + tex.texImage1[i&3].image_type); if (tentry) { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp index e3b55987ec..dff7f8299e 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp @@ -155,7 +155,8 @@ void VertexManager::vFlush() tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, tex.texTlut[i&3].tlut_format, (tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips, - (tex.texMode1[i&3].max_lod >> 4)); + tex.texMode1[i&3].max_lod >> 4, + tex.texImage1[i&3].image_type); if (tentry) { From 439613b83352d59ebaff25d35151e25f616804b4 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sat, 4 Feb 2012 13:01:52 +0100 Subject: [PATCH 3/3] TextureCacheBase: Remove a superfluous TODO (texture hashing takes care of that stuff) --- Source/Core/VideoCommon/Src/TextureCacheBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index 7873d1474e..cc14499330 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -227,7 +227,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, tex_hash ^= tlut_hash; } - TCacheEntryBase *entry = textures[texID]; // TODO: Should use a different texID for preloaded textures! + TCacheEntryBase *entry = textures[texID]; if (entry) { // 1. Calculate reference hash: