2009-07-28 21:32:10 +00:00
|
|
|
// Copyright (C) 2003 Dolphin Project.
|
2008-12-08 05:25:12 +00:00
|
|
|
|
|
|
|
// 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 <d3dx9.h>
|
|
|
|
|
2009-09-01 11:14:58 +00:00
|
|
|
#include "Globals.h"
|
2008-12-08 05:25:12 +00:00
|
|
|
#include "Statistics.h"
|
2009-03-07 18:05:29 +00:00
|
|
|
#include "MemoryUtil.h"
|
2009-09-01 11:14:58 +00:00
|
|
|
#include "Hash.h"
|
|
|
|
|
|
|
|
#include "CommonPaths.h"
|
|
|
|
#include "FileUtil.h"
|
2008-12-08 05:25:12 +00:00
|
|
|
|
|
|
|
#include "D3DBase.h"
|
|
|
|
#include "D3DTexture.h"
|
2009-11-08 20:35:11 +00:00
|
|
|
#include "D3DUtil.h"
|
2009-09-13 17:46:33 +00:00
|
|
|
#include "FramebufferManager.h"
|
2009-11-08 20:35:11 +00:00
|
|
|
#include "PixelShaderCache.h"
|
|
|
|
#include "PixelShaderManager.h"
|
|
|
|
#include "VertexShaderManager.h"
|
|
|
|
#include "VertexShaderCache.h"
|
2008-12-08 05:25:12 +00:00
|
|
|
|
|
|
|
#include "Render.h"
|
|
|
|
|
|
|
|
#include "TextureDecoder.h"
|
|
|
|
#include "TextureCache.h"
|
2009-12-22 06:47:42 +00:00
|
|
|
#include "HiresTextures.h"
|
2008-12-08 05:25:12 +00:00
|
|
|
|
2009-09-18 03:12:32 +00:00
|
|
|
#include "debugger/debugger.h"
|
|
|
|
|
2008-12-08 05:25:12 +00:00
|
|
|
u8 *TextureCache::temp = NULL;
|
|
|
|
TextureCache::TexCache TextureCache::textures;
|
|
|
|
|
|
|
|
extern int frameCount;
|
|
|
|
|
|
|
|
#define TEMP_SIZE (1024*1024*4)
|
2009-03-07 18:05:29 +00:00
|
|
|
#define TEXTURE_KILL_THRESHOLD 200
|
2008-12-08 05:25:12 +00:00
|
|
|
|
2009-03-06 16:47:04 +00:00
|
|
|
void TextureCache::TCacheEntry::Destroy(bool shutdown)
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
|
|
|
if (texture)
|
|
|
|
texture->Release();
|
|
|
|
texture = 0;
|
2009-09-19 13:14:55 +00:00
|
|
|
if (!isRenderTarget && !shutdown && !g_ActiveConfig.bSafeTextureCache)
|
2009-09-13 08:21:35 +00:00
|
|
|
{
|
2009-09-15 21:05:31 +00:00
|
|
|
u32 *ptr = (u32*)g_VideoInitialize.pGetMemoryPointer(addr);
|
2009-03-07 18:05:29 +00:00
|
|
|
if (ptr && *ptr == hash)
|
2008-12-08 05:25:12 +00:00
|
|
|
*ptr = oldpixel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextureCache::Init()
|
|
|
|
{
|
2009-03-07 18:05:29 +00:00
|
|
|
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
|
2009-09-13 08:21:35 +00:00
|
|
|
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
|
2009-12-22 06:47:42 +00:00
|
|
|
HiresTextures::Init(globals->unique_id);
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
|
|
|
|
2009-03-06 16:47:04 +00:00
|
|
|
void TextureCache::Invalidate(bool shutdown)
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
2009-03-07 18:05:29 +00:00
|
|
|
for (TexCache::iterator iter = textures.begin(); iter != textures.end(); iter++)
|
2009-03-06 16:47:04 +00:00
|
|
|
iter->second.Destroy(shutdown);
|
2008-12-08 05:25:12 +00:00
|
|
|
textures.clear();
|
2009-12-22 06:47:42 +00:00
|
|
|
HiresTextures::Shutdown();
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
|
|
|
|
2009-11-14 17:50:51 +00:00
|
|
|
void TextureCache::InvalidateRange(u32 start_address, u32 size)
|
|
|
|
{
|
|
|
|
TexCache::iterator iter = textures.begin();
|
|
|
|
while (iter != textures.end())
|
|
|
|
{
|
|
|
|
if (iter->second.IntersectsMemoryRange(start_address, size))
|
|
|
|
{
|
|
|
|
iter->second.Destroy(false);
|
|
|
|
ERASE_THROUGH_ITERATOR(textures, iter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TextureCache::TCacheEntry::IntersectsMemoryRange(u32 range_address, u32 range_size)
|
|
|
|
{
|
|
|
|
if (addr + size_in_bytes < range_address)
|
|
|
|
return false;
|
|
|
|
if (addr >= range_address + range_size)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-12-08 05:25:12 +00:00
|
|
|
void TextureCache::Shutdown()
|
|
|
|
{
|
2009-03-06 16:47:04 +00:00
|
|
|
Invalidate(true);
|
2009-03-07 18:05:29 +00:00
|
|
|
FreeMemoryPages(temp, TEMP_SIZE);
|
|
|
|
temp = NULL;
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextureCache::Cleanup()
|
|
|
|
{
|
2009-09-13 08:21:35 +00:00
|
|
|
TexCache::iterator iter = textures.begin();
|
|
|
|
while (iter != textures.end())
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
2009-09-02 15:38:04 +00:00
|
|
|
if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second.frameCount)
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
|
|
|
if (!iter->second.isRenderTarget)
|
|
|
|
{
|
2009-03-06 16:47:04 +00:00
|
|
|
iter->second.Destroy(false);
|
2008-12-08 05:25:12 +00:00
|
|
|
iter = textures.erase(iter);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-03-07 18:05:29 +00:00
|
|
|
// Used to be just iter++
|
|
|
|
iter->second.Destroy(false);
|
|
|
|
iter = textures.erase(iter);
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-07 18:48:31 +00:00
|
|
|
/*TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, int height, int tex_format, int tlutaddr, int tlutfmt)
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
2009-09-02 18:55:36 +00:00
|
|
|
if (address == 0)
|
|
|
|
return NULL;
|
2009-09-13 17:46:33 +00:00
|
|
|
|
2008-12-08 05:25:12 +00:00
|
|
|
u8 *ptr = g_VideoInitialize.pGetMemoryPointer(address);
|
2009-09-19 13:14:55 +00:00
|
|
|
int bsw = TexDecoder_GetBlockWidthInTexels(tex_format) - 1; //TexelSizeInNibbles(format)*width*height/16;
|
|
|
|
int bsh = TexDecoder_GetBlockHeightInTexels(tex_format) - 1; //TexelSizeInNibbles(format)*width*height/16;
|
|
|
|
int expandedWidth = (width + bsw) & (~bsw);
|
|
|
|
int expandedHeight = (height + bsh) & (~bsh);
|
2009-09-02 06:33:41 +00:00
|
|
|
|
2009-09-19 13:14:55 +00:00
|
|
|
u32 hash_value;
|
|
|
|
u32 texID = address;
|
|
|
|
u32 texHash;
|
2008-12-08 05:25:12 +00:00
|
|
|
|
2009-09-19 13:14:55 +00:00
|
|
|
if (g_ActiveConfig.bSafeTextureCache || g_ActiveConfig.bDumpTextures)
|
2009-09-04 05:26:19 +00:00
|
|
|
{
|
2009-09-19 13:14:55 +00:00
|
|
|
texHash = TexDecoder_GetSafeTextureHash(ptr, expandedWidth, expandedHeight, tex_format, 0);
|
|
|
|
if (g_ActiveConfig.bSafeTextureCache)
|
|
|
|
hash_value = texHash;
|
|
|
|
if ((tex_format == GX_TF_C4) || (tex_format == GX_TF_C8) || (tex_format == GX_TF_C14X2))
|
2009-09-04 05:26:19 +00:00
|
|
|
{
|
2009-09-19 13:14:55 +00:00
|
|
|
// 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.
|
|
|
|
u32 tlutHash = TexDecoder_GetTlutHash(&texMem[tlutaddr], (tex_format == GX_TF_C4) ? 32 : 128);
|
|
|
|
texHash ^= tlutHash;
|
2009-09-13 08:21:35 +00:00
|
|
|
if (g_ActiveConfig.bSafeTextureCache)
|
2009-09-11 05:05:00 +00:00
|
|
|
texID ^= tlutHash;
|
2009-09-04 05:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
2009-09-02 06:33:41 +00:00
|
|
|
|
2009-09-19 13:14:55 +00:00
|
|
|
bool skip_texture_create = false;
|
2009-09-11 05:05:00 +00:00
|
|
|
TexCache::iterator iter = textures.find(texID);
|
2009-09-19 13:14:55 +00:00
|
|
|
|
2008-12-08 05:25:12 +00:00
|
|
|
if (iter != textures.end())
|
|
|
|
{
|
|
|
|
TCacheEntry &entry = iter->second;
|
2009-09-19 13:14:55 +00:00
|
|
|
|
|
|
|
if (!g_ActiveConfig.bSafeTextureCache)
|
|
|
|
hash_value = ((u32 *)ptr)[0];
|
|
|
|
|
2009-03-07 18:05:29 +00:00
|
|
|
if (entry.isRenderTarget || ((address == entry.addr) && (hash_value == entry.hash)))
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
2009-03-07 18:05:29 +00:00
|
|
|
entry.frameCount = frameCount;
|
2009-09-13 08:21:35 +00:00
|
|
|
D3D::SetTexture(stage, entry.texture);
|
2009-03-07 18:05:29 +00:00
|
|
|
return &entry;
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-09-19 13:14:55 +00:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
if (width == entry.w && height==entry.h && tex_format == entry.fmt)
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
2009-09-19 13:14:55 +00:00
|
|
|
skip_texture_create = true;
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
|
|
|
else
|
2009-09-19 13:14:55 +00:00
|
|
|
{
|
2009-03-07 18:05:29 +00:00
|
|
|
entry.Destroy(false);
|
2008-12-08 05:25:12 +00:00
|
|
|
textures.erase(iter);
|
2009-09-19 13:14:55 +00:00
|
|
|
}
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-07 18:48:31 +00:00
|
|
|
//PC_TexFormat pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth, height, tex_format, tlutaddr, tlutfmt);
|
|
|
|
PC_TexFormat pcfmt = GetPC_TexFormat(tex_format, tlutfmt);
|
|
|
|
|
|
|
|
D3DFORMAT d3d_fmt;
|
|
|
|
switch (pcfmt) {
|
|
|
|
case PC_TEX_FMT_BGRA32:
|
|
|
|
case PC_TEX_FMT_RGBA32:
|
|
|
|
d3d_fmt = D3DFMT_A8R8G8B8;
|
|
|
|
break;
|
|
|
|
case PC_TEX_FMT_RGB565:
|
|
|
|
d3d_fmt = D3DFMT_R5G6B5;
|
|
|
|
break;
|
|
|
|
case PC_TEX_FMT_IA4_AS_IA8:
|
|
|
|
d3d_fmt = D3DFMT_A8L8;
|
|
|
|
break;
|
|
|
|
case PC_TEX_FMT_I8:
|
2009-12-09 13:51:28 +00:00
|
|
|
case PC_TEX_FMT_I4_AS_I8:
|
2009-12-07 18:48:31 +00:00
|
|
|
d3d_fmt = D3DFMT_A8L8;
|
|
|
|
break;
|
|
|
|
case PC_TEX_FMT_IA8:
|
|
|
|
d3d_fmt = D3DFMT_A8L8;
|
|
|
|
break;
|
|
|
|
case PC_TEX_FMT_DXT1:
|
|
|
|
d3d_fmt = D3DFMT_DXT1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Make an entry in the table
|
|
|
|
TCacheEntry& entry = textures[texID];
|
|
|
|
|
|
|
|
entry.oldpixel = ((u32 *)ptr)[0];
|
|
|
|
if (g_ActiveConfig.bSafeTextureCache)
|
|
|
|
entry.hash = hash_value;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entry.hash = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF);
|
|
|
|
((u32 *)ptr)[0] = entry.hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.addr = address;
|
|
|
|
entry.size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, tex_format);
|
|
|
|
entry.isRenderTarget = false;
|
|
|
|
entry.isNonPow2 = ((width & (width - 1)) || (height & (height - 1)));
|
|
|
|
if (!skip_texture_create) {
|
|
|
|
entry.texture = D3D::CreateOnlyTexture2D(width, height, d3d_fmt);
|
|
|
|
}
|
|
|
|
D3DLOCKED_RECT Lock;
|
|
|
|
entry.texture->LockRect(0, &Lock, NULL, 0);
|
2009-12-09 13:51:28 +00:00
|
|
|
if(pcfmt != PC_TEX_FMT_I8 && pcfmt != PC_TEX_FMT_I4_AS_I8)
|
2009-12-07 18:48:31 +00:00
|
|
|
TexDecoder_DirectDecode((u8*)Lock.pBits,ptr,expandedWidth,height,Lock.Pitch,tex_format,tlutaddr,tlutfmt);
|
|
|
|
entry.texture->UnlockRect(0);
|
|
|
|
entry.frameCount = frameCount;
|
|
|
|
entry.w = width;
|
|
|
|
entry.h = height;
|
|
|
|
entry.fmt = tex_format;
|
|
|
|
|
|
|
|
if (g_ActiveConfig.bDumpTextures)
|
|
|
|
{
|
|
|
|
// dump texture to file
|
|
|
|
char szTemp[MAX_PATH];
|
|
|
|
char szDir[MAX_PATH];
|
|
|
|
const char* uniqueId = globals->unique_id;
|
|
|
|
bool bCheckedDumpDir = false;
|
|
|
|
sprintf(szDir, "%s/%s", FULL_DUMP_TEXTURES_DIR, uniqueId);
|
|
|
|
if (!bCheckedDumpDir)
|
|
|
|
{
|
|
|
|
if (!File::Exists(szDir) || !File::IsDirectory(szDir))
|
|
|
|
File::CreateDir(szDir);
|
|
|
|
|
|
|
|
bCheckedDumpDir = true;
|
|
|
|
}
|
|
|
|
sprintf(szTemp, "%s/%s_%08x_%i.png", szDir, uniqueId, texHash, tex_format);
|
|
|
|
//sprintf(szTemp, "%s\\txt_%04i_%i.png", g_Config.texDumpPath.c_str(), counter++, format); <-- Old method
|
|
|
|
if (!File::Exists(szTemp))
|
|
|
|
D3DXSaveTextureToFileA(szTemp,D3DXIFF_BMP,entry.texture,0);
|
|
|
|
}
|
|
|
|
|
|
|
|
INCSTAT(stats.numTexturesCreated);
|
|
|
|
SETSTAT(stats.numTexturesAlive, (int)textures.size());
|
|
|
|
|
|
|
|
//Set the texture!
|
|
|
|
D3D::SetTexture(stage, entry.texture);
|
|
|
|
|
|
|
|
DEBUGGER_PAUSE_LOG_AT(NEXT_NEW_TEXTURE,true,{printf("A new texture (%d x %d) is loaded", width, height);});
|
|
|
|
return &entry;
|
|
|
|
}*/
|
|
|
|
|
|
|
|
TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, int height, int tex_format, int tlutaddr, int tlutfmt)
|
|
|
|
{
|
|
|
|
if (address == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
u8 *ptr = g_VideoInitialize.pGetMemoryPointer(address);
|
|
|
|
int bsw = TexDecoder_GetBlockWidthInTexels(tex_format) - 1; //TexelSizeInNibbles(format)*width*height/16;
|
|
|
|
int bsh = TexDecoder_GetBlockHeightInTexels(tex_format) - 1; //TexelSizeInNibbles(format)*width*height/16;
|
|
|
|
int expandedWidth = (width + bsw) & (~bsw);
|
|
|
|
int expandedHeight = (height + bsh) & (~bsh);
|
|
|
|
|
|
|
|
u32 hash_value;
|
|
|
|
u32 texID = address;
|
|
|
|
u32 texHash;
|
|
|
|
|
2009-12-22 06:47:42 +00:00
|
|
|
if (g_ActiveConfig.bSafeTextureCache || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures)
|
2009-12-07 18:48:31 +00:00
|
|
|
{
|
|
|
|
texHash = TexDecoder_GetSafeTextureHash(ptr, expandedWidth, expandedHeight, tex_format, 0);
|
|
|
|
if (g_ActiveConfig.bSafeTextureCache)
|
|
|
|
hash_value = texHash;
|
|
|
|
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.
|
|
|
|
u32 tlutHash = TexDecoder_GetTlutHash(&texMem[tlutaddr], (tex_format == GX_TF_C4) ? 32 : 128);
|
|
|
|
texHash ^= tlutHash;
|
|
|
|
if (g_ActiveConfig.bSafeTextureCache)
|
|
|
|
texID ^= tlutHash;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool skip_texture_create = false;
|
|
|
|
TexCache::iterator iter = textures.find(texID);
|
|
|
|
|
|
|
|
if (iter != textures.end())
|
|
|
|
{
|
|
|
|
TCacheEntry &entry = iter->second;
|
|
|
|
|
|
|
|
if (!g_ActiveConfig.bSafeTextureCache)
|
|
|
|
hash_value = ((u32 *)ptr)[0];
|
|
|
|
|
|
|
|
if (entry.isRenderTarget || ((address == entry.addr) && (hash_value == entry.hash)))
|
|
|
|
{
|
|
|
|
entry.frameCount = frameCount;
|
|
|
|
D3D::SetTexture(stage, entry.texture);
|
|
|
|
return &entry;
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
|
|
|
|
if (width == entry.w && height==entry.h &&(tex_format | (tlutfmt << 16)) == entry.fmt)
|
|
|
|
{
|
|
|
|
skip_texture_create = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entry.Destroy(false);
|
|
|
|
textures.erase(iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-12-22 06:47:42 +00:00
|
|
|
|
|
|
|
//Make an entry in the table
|
|
|
|
TCacheEntry& entry = textures[texID];
|
|
|
|
PC_TexFormat pcfmt = PC_TEX_FMT_NONE;
|
|
|
|
|
|
|
|
if (g_ActiveConfig.bHiresTextures)
|
|
|
|
{
|
|
|
|
//Load Custom textures
|
|
|
|
char texPathTemp[MAX_PATH];
|
|
|
|
int oldWidth = width;
|
|
|
|
int oldHeight = height;
|
|
|
|
|
|
|
|
sprintf(texPathTemp, "%s_%08x_%i", globals->unique_id, texHash, tex_format);
|
|
|
|
pcfmt = HiresTextures::GetHiresTex(texPathTemp, &width, &height, tex_format, temp);
|
|
|
|
|
|
|
|
if (pcfmt != PC_TEX_FMT_NONE)
|
|
|
|
{
|
|
|
|
expandedWidth = width;
|
|
|
|
expandedHeight = height;
|
|
|
|
entry.scaleX = (float) width / oldWidth;
|
|
|
|
entry.scaleY = (float) height / oldHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pcfmt == PC_TEX_FMT_NONE)
|
|
|
|
pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, tex_format, tlutaddr, tlutfmt);
|
2009-09-19 13:14:55 +00:00
|
|
|
|
2008-12-08 05:25:12 +00:00
|
|
|
D3DFORMAT d3d_fmt;
|
|
|
|
switch (pcfmt) {
|
|
|
|
case PC_TEX_FMT_BGRA32:
|
2009-11-14 17:50:51 +00:00
|
|
|
case PC_TEX_FMT_RGBA32:
|
2008-12-08 05:25:12 +00:00
|
|
|
d3d_fmt = D3DFMT_A8R8G8B8;
|
|
|
|
break;
|
2009-02-12 22:32:33 +00:00
|
|
|
case PC_TEX_FMT_RGB565:
|
|
|
|
d3d_fmt = D3DFMT_R5G6B5;
|
|
|
|
break;
|
2009-05-13 02:06:02 +00:00
|
|
|
case PC_TEX_FMT_IA4_AS_IA8:
|
2009-09-02 18:55:36 +00:00
|
|
|
d3d_fmt = D3DFMT_A8L8;
|
2009-02-14 09:04:40 +00:00
|
|
|
break;
|
2009-02-12 13:54:08 +00:00
|
|
|
case PC_TEX_FMT_I8:
|
2009-08-31 06:35:43 +00:00
|
|
|
case PC_TEX_FMT_I4_AS_I8:
|
2009-02-16 23:01:37 +00:00
|
|
|
d3d_fmt = D3DFMT_A8P8; // A hack which means the format is a packed
|
|
|
|
// 8-bit intensity texture. It is unpacked
|
|
|
|
// to A8L8 in D3DTexture.cpp
|
2009-02-13 14:14:45 +00:00
|
|
|
break;
|
|
|
|
case PC_TEX_FMT_IA8:
|
2009-02-12 13:54:08 +00:00
|
|
|
d3d_fmt = D3DFMT_A8L8;
|
|
|
|
break;
|
2009-02-16 23:01:37 +00:00
|
|
|
case PC_TEX_FMT_DXT1:
|
|
|
|
d3d_fmt = D3DFMT_DXT1;
|
|
|
|
break;
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
2009-03-07 18:05:29 +00:00
|
|
|
|
2009-09-15 21:05:31 +00:00
|
|
|
entry.oldpixel = ((u32 *)ptr)[0];
|
2009-09-19 13:14:55 +00:00
|
|
|
if (g_ActiveConfig.bSafeTextureCache)
|
|
|
|
entry.hash = hash_value;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entry.hash = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF);
|
|
|
|
((u32 *)ptr)[0] = entry.hash;
|
|
|
|
}
|
2008-12-08 05:25:12 +00:00
|
|
|
|
|
|
|
entry.addr = address;
|
2009-09-19 13:14:55 +00:00
|
|
|
entry.size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, tex_format);
|
2009-03-07 18:05:29 +00:00
|
|
|
entry.isRenderTarget = false;
|
|
|
|
entry.isNonPow2 = ((width & (width - 1)) || (height & (height - 1)));
|
2009-09-19 13:14:55 +00:00
|
|
|
if (!skip_texture_create) {
|
|
|
|
entry.texture = D3D::CreateTexture2D((BYTE*)temp, width, height, expandedWidth, d3d_fmt);
|
|
|
|
} else {
|
|
|
|
D3D::ReplaceTexture2D(entry.texture, (BYTE*)temp, width, height, expandedWidth, d3d_fmt);
|
|
|
|
}
|
2008-12-08 05:25:12 +00:00
|
|
|
entry.frameCount = frameCount;
|
2009-03-07 18:05:29 +00:00
|
|
|
entry.w = width;
|
|
|
|
entry.h = height;
|
2009-12-07 18:48:31 +00:00
|
|
|
entry.fmt = tex_format | (tlutfmt << 16);
|
2008-12-08 05:25:12 +00:00
|
|
|
|
2009-09-13 08:21:35 +00:00
|
|
|
if (g_ActiveConfig.bDumpTextures)
|
2009-09-19 13:14:55 +00:00
|
|
|
{
|
|
|
|
// dump texture to file
|
2008-12-08 05:25:12 +00:00
|
|
|
char szTemp[MAX_PATH];
|
2009-09-01 11:14:58 +00:00
|
|
|
char szDir[MAX_PATH];
|
2009-09-13 08:54:46 +00:00
|
|
|
const char* uniqueId = globals->unique_id;
|
2009-09-01 11:14:58 +00:00
|
|
|
bool bCheckedDumpDir = false;
|
2009-12-22 06:47:42 +00:00
|
|
|
|
2009-09-15 21:05:31 +00:00
|
|
|
sprintf(szDir, "%s/%s", FULL_DUMP_TEXTURES_DIR, uniqueId);
|
2009-12-22 06:47:42 +00:00
|
|
|
|
2009-09-15 21:05:31 +00:00
|
|
|
if (!bCheckedDumpDir)
|
2009-09-01 11:14:58 +00:00
|
|
|
{
|
|
|
|
if (!File::Exists(szDir) || !File::IsDirectory(szDir))
|
|
|
|
File::CreateDir(szDir);
|
|
|
|
|
|
|
|
bCheckedDumpDir = true;
|
|
|
|
}
|
2009-12-22 06:47:42 +00:00
|
|
|
|
2009-09-19 13:14:55 +00:00
|
|
|
sprintf(szTemp, "%s/%s_%08x_%i.png", szDir, uniqueId, texHash, tex_format);
|
2009-12-22 06:47:42 +00:00
|
|
|
|
2009-09-01 11:14:58 +00:00
|
|
|
if (!File::Exists(szTemp))
|
2009-09-02 06:33:41 +00:00
|
|
|
D3DXSaveTextureToFileA(szTemp,D3DXIFF_BMP,entry.texture,0);
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
INCSTAT(stats.numTexturesCreated);
|
|
|
|
SETSTAT(stats.numTexturesAlive, (int)textures.size());
|
|
|
|
|
|
|
|
//Set the texture!
|
2009-09-13 08:21:35 +00:00
|
|
|
D3D::SetTexture(stage, entry.texture);
|
2008-12-08 05:25:12 +00:00
|
|
|
|
2009-09-18 03:12:32 +00:00
|
|
|
DEBUGGER_PAUSE_LOG_AT(NEXT_NEW_TEXTURE,true,{printf("A new texture (%d x %d) is loaded", width, height);});
|
2009-03-07 18:05:29 +00:00
|
|
|
return &entry;
|
2009-12-09 13:51:28 +00:00
|
|
|
}
|
2009-09-04 06:09:21 +00:00
|
|
|
void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle &source_rect)
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
2009-09-03 21:56:08 +00:00
|
|
|
int efb_w = source_rect.GetWidth();
|
|
|
|
int efb_h = source_rect.GetHeight();
|
|
|
|
|
2009-09-04 06:09:21 +00:00
|
|
|
int tex_w = (abs(source_rect.GetWidth()) >> bScaleByHalf);
|
|
|
|
int tex_h = (abs(source_rect.GetHeight()) >> bScaleByHalf);
|
2009-12-15 01:40:54 +00:00
|
|
|
|
|
|
|
int Scaledtex_w = (g_ActiveConfig.bCopyEFBScaled)?((int)(Renderer::GetTargetScaleX() * tex_w)):tex_w;
|
|
|
|
int Scaledtex_h = (g_ActiveConfig.bCopyEFBScaled)?((int)(Renderer::GetTargetScaleY() * tex_h)):tex_h;
|
2008-12-08 05:25:12 +00:00
|
|
|
TexCache::iterator iter;
|
|
|
|
LPDIRECT3DTEXTURE9 tex;
|
|
|
|
iter = textures.find(address);
|
|
|
|
if (iter != textures.end())
|
|
|
|
{
|
2009-12-15 01:40:54 +00:00
|
|
|
if (iter->second.isRenderTarget && iter->second.Scaledw == Scaledtex_w && iter->second.Scaledh == Scaledtex_h)
|
2009-11-08 20:35:11 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
tex = iter->second.texture;
|
|
|
|
iter->second.frameCount = frameCount;
|
|
|
|
goto have_texture;
|
|
|
|
}
|
|
|
|
else
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
2009-09-03 21:56:08 +00:00
|
|
|
// Remove it and recreate it as a render target
|
|
|
|
iter->second.texture->Release();
|
|
|
|
iter->second.texture = 0;
|
|
|
|
textures.erase(iter);
|
|
|
|
}
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|
2009-09-03 21:56:08 +00:00
|
|
|
|
2008-12-08 05:25:12 +00:00
|
|
|
{
|
|
|
|
TCacheEntry entry;
|
2009-09-02 18:55:36 +00:00
|
|
|
entry.isRenderTarget = true;
|
2008-12-08 05:25:12 +00:00
|
|
|
entry.hash = 0;
|
|
|
|
entry.frameCount = frameCount;
|
2009-09-03 21:56:08 +00:00
|
|
|
entry.w = tex_w;
|
|
|
|
entry.h = tex_h;
|
2009-12-15 01:40:54 +00:00
|
|
|
entry.Scaledw = Scaledtex_w;
|
|
|
|
entry.Scaledh = Scaledtex_h;
|
2009-11-08 20:35:11 +00:00
|
|
|
entry.fmt = copyfmt;
|
|
|
|
|
2009-12-15 01:40:54 +00:00
|
|
|
D3D::dev->CreateTexture(Scaledtex_w, Scaledtex_h, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &entry.texture, 0);
|
2008-12-08 05:25:12 +00:00
|
|
|
textures[address] = entry;
|
|
|
|
tex = entry.texture;
|
|
|
|
}
|
2009-09-02 18:55:36 +00:00
|
|
|
|
2009-11-14 17:50:51 +00:00
|
|
|
have_texture:
|
2009-11-08 20:35:11 +00:00
|
|
|
float colmat[16]= {0.0f};
|
|
|
|
float fConstAdd[4] = {0.0f};
|
|
|
|
|
|
|
|
if (bFromZBuffer)
|
|
|
|
{
|
2009-11-10 12:45:03 +00:00
|
|
|
switch(copyfmt)
|
2009-11-08 20:35:11 +00:00
|
|
|
{
|
|
|
|
case 0: // Z4
|
|
|
|
case 1: // Z8
|
2009-11-22 02:37:00 +00:00
|
|
|
colmat[0] = colmat[4] = colmat[8] = colmat[12] =1.0f;
|
2009-11-08 20:35:11 +00:00
|
|
|
break;
|
|
|
|
case 3: // Z16 //?
|
2009-11-22 02:37:00 +00:00
|
|
|
colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f;
|
2009-11-08 20:35:11 +00:00
|
|
|
case 11: // Z16 (reverse order)
|
2009-11-22 02:37:00 +00:00
|
|
|
colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f;
|
2009-11-08 20:35:11 +00:00
|
|
|
break;
|
|
|
|
case 6: // Z24X8
|
2009-11-22 02:37:00 +00:00
|
|
|
colmat[0] = colmat[5] = colmat[10] = 1.0f;
|
2009-11-08 20:35:11 +00:00
|
|
|
break;
|
|
|
|
case 9: // Z8M
|
2009-11-22 02:37:00 +00:00
|
|
|
colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f;
|
2009-11-08 20:35:11 +00:00
|
|
|
break;
|
|
|
|
case 10: // Z8L
|
2009-11-22 02:37:00 +00:00
|
|
|
colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f;
|
2009-11-08 20:35:11 +00:00
|
|
|
break;
|
|
|
|
case 12: // Z16L
|
2009-11-22 02:37:00 +00:00
|
|
|
colmat[2] = colmat[6] = colmat[10] = colmat[13] = 1.0f;
|
2009-11-08 20:35:11 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", copyfmt);
|
2009-11-22 02:37:00 +00:00
|
|
|
colmat[2] = colmat[5] = colmat[8] = 1.0f;
|
2009-11-08 20:35:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (bIsIntensityFmt)
|
|
|
|
{
|
|
|
|
fConstAdd[0] = fConstAdd[1] = fConstAdd[2] = 16.0f/255.0f;
|
|
|
|
switch (copyfmt)
|
|
|
|
{
|
|
|
|
case 0: // I4
|
|
|
|
case 1: // I8
|
|
|
|
case 2: // IA4
|
|
|
|
case 3: // IA8
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
if (copyfmt < 2)
|
|
|
|
{
|
|
|
|
fConstAdd[3] = 16.0f / 255.0f;
|
|
|
|
colmat[12] = 0.257f; colmat[13] = 0.504f; colmat[14] = 0.098f;
|
|
|
|
}
|
|
|
|
else// alpha
|
|
|
|
colmat[15] = 1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%x", copyfmt);
|
|
|
|
colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (copyfmt)
|
|
|
|
{
|
|
|
|
case 0: // R4
|
|
|
|
case 8: // R8
|
|
|
|
colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1;
|
|
|
|
break;
|
|
|
|
case 2: // RA4
|
|
|
|
case 3: // RA8
|
|
|
|
colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 7: // A8
|
|
|
|
colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1;
|
|
|
|
break;
|
|
|
|
case 9: // G8
|
|
|
|
colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1;
|
|
|
|
break;
|
|
|
|
case 10: // B8
|
|
|
|
colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1;
|
|
|
|
break;
|
|
|
|
case 11: // RG8
|
|
|
|
colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1;
|
|
|
|
break;
|
|
|
|
case 12: // GB8
|
|
|
|
colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: // RGB565
|
|
|
|
colmat[0] = colmat[5] = colmat[10] = 1;
|
|
|
|
fConstAdd[3] = 1; // set alpha to 1
|
|
|
|
break;
|
|
|
|
case 5: // RGB5A3
|
|
|
|
case 6: // RGBA8
|
|
|
|
colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", copyfmt);
|
|
|
|
colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Make sure to resolve anything we need to read from.
|
|
|
|
LPDIRECT3DTEXTURE9 read_texture = bFromZBuffer ? FBManager::GetEFBDepthTexture(source_rect) : FBManager::GetEFBColorTexture(source_rect);
|
|
|
|
|
|
|
|
// We have to run a pixel shader, for color conversion.
|
|
|
|
Renderer::ResetAPIState(); // reset any game specific settings
|
|
|
|
LPDIRECT3DSURFACE9 Rendersurf = NULL;
|
Well this commit has 2 parts:
first part if fixing, fixed, i thing, the flickering that everyone has reported, at least in my case i only have flickering in the one texture in one game and now is fixed. The other fix is not for an reported issue, is more a correctness fix, running dolphin with pix to review debug errors, result in a ton of warnings and error, now with this commit, at least for ati, there no more error or warnings, this means, correct management and state change, no accurate emulation, for this still a lot of work to do.
for this part of the commit please give me feedback and let me know of remaining issues
Te second part is the partial implementation of efb to ram copy in d3d, this won't brake anything because is commented but i commit this to ask for help from ector and donko in some errors remaining in the implementation related to differences between opengl an d3d.
if you want to test this you have to uncomment line 150 to 155 of bpstruct.cpp
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4594 8ced0084-cf51-0410-be5f-012b33b47a6e
2009-11-20 18:46:30 +00:00
|
|
|
tex->GetSurfaceLevel(0,&Rendersurf);
|
2009-11-08 20:35:11 +00:00
|
|
|
D3D::dev->SetDepthStencilSurface(NULL);
|
|
|
|
D3D::dev->SetRenderTarget(0, Rendersurf);
|
|
|
|
|
|
|
|
D3DVIEWPORT9 vp;
|
|
|
|
|
|
|
|
// Stretch picture with increased internal resolution
|
|
|
|
vp.X = 0;
|
|
|
|
vp.Y = 0;
|
2009-12-15 01:40:54 +00:00
|
|
|
vp.Width = Scaledtex_w;
|
|
|
|
vp.Height = Scaledtex_h;
|
2009-11-08 20:35:11 +00:00
|
|
|
vp.MinZ = 0.0f;
|
|
|
|
vp.MaxZ = 1.0f;
|
Well this commit has 2 parts:
first part if fixing, fixed, i thing, the flickering that everyone has reported, at least in my case i only have flickering in the one texture in one game and now is fixed. The other fix is not for an reported issue, is more a correctness fix, running dolphin with pix to review debug errors, result in a ton of warnings and error, now with this commit, at least for ati, there no more error or warnings, this means, correct management and state change, no accurate emulation, for this still a lot of work to do.
for this part of the commit please give me feedback and let me know of remaining issues
Te second part is the partial implementation of efb to ram copy in d3d, this won't brake anything because is commented but i commit this to ask for help from ector and donko in some errors remaining in the implementation related to differences between opengl an d3d.
if you want to test this you have to uncomment line 150 to 155 of bpstruct.cpp
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4594 8ced0084-cf51-0410-be5f-012b33b47a6e
2009-11-20 18:46:30 +00:00
|
|
|
D3D::dev->SetViewport(&vp);
|
2009-11-08 20:35:11 +00:00
|
|
|
RECT destrect;
|
2009-12-15 01:40:54 +00:00
|
|
|
destrect.bottom = Scaledtex_h;
|
2009-11-08 20:35:11 +00:00
|
|
|
destrect.left = 0;
|
2009-12-15 01:40:54 +00:00
|
|
|
destrect.right = Scaledtex_w;
|
2009-11-08 20:35:11 +00:00
|
|
|
destrect.top = 0;
|
|
|
|
|
2009-09-20 03:29:43 +00:00
|
|
|
|
2009-11-08 20:35:11 +00:00
|
|
|
PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation
|
2009-11-14 17:50:51 +00:00
|
|
|
TargetRectangle targetSource = Renderer::ConvertEFBRectangle(source_rect);
|
2009-11-08 20:35:11 +00:00
|
|
|
RECT sourcerect;
|
2009-11-14 17:50:51 +00:00
|
|
|
sourcerect.bottom = targetSource.bottom;
|
|
|
|
sourcerect.left = targetSource.left;
|
|
|
|
sourcerect.right = targetSource.right;
|
|
|
|
sourcerect.top = targetSource.top;
|
2009-12-02 04:17:18 +00:00
|
|
|
|
|
|
|
if(bScaleByHalf)
|
2009-12-03 20:09:15 +00:00
|
|
|
{
|
2009-12-02 04:17:18 +00:00
|
|
|
D3D::dev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
2009-12-03 20:09:15 +00:00
|
|
|
D3D::dev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
|
|
|
}
|
2009-12-02 04:17:18 +00:00
|
|
|
else
|
2009-12-03 20:09:15 +00:00
|
|
|
{
|
2009-11-22 02:37:00 +00:00
|
|
|
D3D::dev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
2009-12-03 20:09:15 +00:00
|
|
|
D3D::dev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
|
|
|
|
}
|
|
|
|
|
2009-12-02 04:17:18 +00:00
|
|
|
|
2009-11-22 02:37:00 +00:00
|
|
|
D3DFORMAT bformat = FBManager::GetEFBDepthRTSurfaceFormat();
|
|
|
|
D3D::drawShadedTexQuad(read_texture,&sourcerect, Renderer::GetTargetWidth() , Renderer::GetTargetHeight(),&destrect,((bformat != FOURCC_RAWZ && bformat != D3DFMT_D24X8) && bFromZBuffer)? PixelShaderCache::GetDepthMatrixProgram(): PixelShaderCache::GetColorMatrixProgram(),VertexShaderCache::GetSimpleVertexShader());
|
2009-12-02 04:17:18 +00:00
|
|
|
|
|
|
|
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);
|
2009-12-03 20:09:15 +00:00
|
|
|
D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER);
|
2009-11-08 20:35:11 +00:00
|
|
|
|
|
|
|
D3D::dev->SetRenderTarget(0, FBManager::GetEFBColorRTSurface());
|
2009-11-23 14:08:08 +00:00
|
|
|
D3D::dev->SetDepthStencilSurface(FBManager::GetEFBDepthRTSurface());
|
2009-11-08 20:35:11 +00:00
|
|
|
Renderer::RestoreAPIState();
|
|
|
|
Rendersurf->Release();
|
2008-12-08 05:25:12 +00:00
|
|
|
}
|