From 0a46dead9c2a00e2c1c1bc9a700916f14230f113 Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Thu, 17 Jun 2010 14:21:31 +0000 Subject: [PATCH] DX11: Implement safe texture cache. Fix screenshot functionality. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5732 8ced0084-cf51-0410-be5f-012b33b47a6e --- .../Plugins/Plugin_VideoDX11/Src/Render.cpp | 26 +++++++++++++- .../Plugin_VideoDX11/Src/TextureCache.cpp | 34 +++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp index 719ac61c49..75bdcb1c94 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp @@ -879,7 +879,31 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) } if (s_bScreenshot) { - HRESULT hr = D3DX11SaveTextureToFileA(D3D::context, D3D::GetBackBuffer()->GetTex(), D3DX11_IFF_PNG, s_sScreenshotName); + // copy back buffer to system memory + ID3D11Texture2D* buftex; + D3D11_TEXTURE2D_DESC tex_desc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight(), 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE); + HRESULT hr = D3D::device->CreateTexture2D(&tex_desc, NULL, &buftex); + if (FAILED(hr)) PanicAlert("Failed to create screenshot buffer texture"); + D3D::context->CopyResource(buftex, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex()); + + // D3DX11SaveTextureToFileA doesn't allow us to ignore the alpha channel, so we need to strip it out ourselves + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(buftex, 0, D3D11_MAP_READ_WRITE, 0, &map); + for (unsigned int y = 0; y < D3D::GetBackBufferHeight(); ++y) + { + u32* ptr = (u32*)((u8*)map.pData + y * map.RowPitch); + for (unsigned int x = 0; x < D3D::GetBackBufferWidth(); ++x) + { + *ptr = 0xFF000000 | (*ptr & 0xFFFFFF); + ptr++; + } + } + D3D::context->Unmap(buftex, 0); + + // ready to be saved + hr = D3DX11SaveTextureToFileA(D3D::context, buftex, D3DX11_IFF_PNG, s_sScreenshotName); + if (FAILED(hr)) PanicAlert("Failed to save screenshot"); + buftex->Release(); s_bScreenshot = false; } diff --git a/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.cpp index 426a219e50..13fc867a32 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/TextureCache.cpp @@ -56,7 +56,8 @@ extern int frameCount; void TextureCache::TCacheEntry::Destroy(bool shutdown) { SAFE_RELEASE(texture); - if (!isRenderTarget && !shutdown) + + if (!isRenderTarget && !shutdown && !g_ActiveConfig.bSafeTextureCache) { u32* ptr = (u32*)g_VideoInitialize.pGetMemoryPointer(addr); if (ptr && *ptr == hash) @@ -193,10 +194,35 @@ TextureCache::TCacheEntry* TextureCache::Load(unsigned int stage, u32 address, u u64 hash_value; u32 texID = address; + u64 texHash; u32 FullFormat = tex_format; if ((tex_format == GX_TF_C4) || (tex_format == GX_TF_C8) || (tex_format == GX_TF_C14X2)) u32 FullFormat = (tex_format | (tlutfmt << 16)); + // hires textures and texture dumping not supported, yet + if (g_ActiveConfig.bSafeTextureCache/* || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures*/) + { + texHash = TexDecoder_GetHash64(ptr,TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, tex_format),g_ActiveConfig.iSafeTextureCache_ColorSamples); + if ((tex_format == GX_TF_C4) || (tex_format == GX_TF_C8) || (tex_format == GX_TF_C14X2)) + { + // 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. + u64 tlutHash = TexDecoder_GetHash64(&texMem[tlutaddr], TexDecoder_GetPaletteSize(tex_format),g_ActiveConfig.iSafeTextureCache_ColorSamples); + texHash ^= tlutHash; + if (g_ActiveConfig.bSafeTextureCache) + { + texID = texID ^ ((u32)(tlutHash & 0xFFFFFFFF)) ^ ((u32)((tlutHash >> 32) & 0xFFFFFFFF)); + } + } + if (g_ActiveConfig.bSafeTextureCache) + hash_value = texHash; + } + bool skip_texture_create = false; TexCache::iterator iter = textures.find(texID); @@ -204,7 +230,8 @@ TextureCache::TCacheEntry* TextureCache::Load(unsigned int stage, u32 address, u { TCacheEntry &entry = iter->second; - hash_value = ((u32*)ptr)[0]; + if (!g_ActiveConfig.bSafeTextureCache) + hash_value = ((u32*)ptr)[0]; // TODO: Is the (entry.MipLevels == maxlevel) check needed? if (entry.isRenderTarget || ((address == entry.addr) && (hash_value == entry.hash) && FullFormat == entry.fmt && entry.MipLevels == maxlevel)) @@ -243,7 +270,8 @@ TextureCache::TCacheEntry* TextureCache::Load(unsigned int stage, u32 address, u bool swap_r_b = false; entry.oldpixel = ((u32*)ptr)[0]; - entry.hash = ((u32*)ptr)[0] = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF); + if (g_ActiveConfig.bSafeTextureCache) entry.hash = hash_value; + else entry.hash = ((u32*)ptr)[0] = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF); entry.addr = address; entry.size_in_bytes = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, tex_format);