mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-27 00:05:34 +01:00
d616f132d7
Debugger panel is displayed only if Dolphin is started with /d option. Dump features are not implemented. Pause/Resume buttons works, only if the plugin is built in DEBUG or DEBUGFAST configuration, not in RELEASE. These features are really only for devs, not for regular gamers. You will be able to pause frame by frame, or by n frames, or by n primitive flushes. Other pausing options are not implemented yet. When other pausing and dumping features are implemented, debugging will be much easier. I have changed the DX9 project setting to use unicode character set in order to use wxWidge tools. If this causes Dolphin building problems for you, check your project setting.txt git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4154 8ced0084-cf51-0410-be5f-012b33b47a6e
288 lines
7.6 KiB
C++
288 lines
7.6 KiB
C++
// 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 <d3dx9.h>
|
|
|
|
#include "Globals.h"
|
|
#include "Statistics.h"
|
|
#include "MemoryUtil.h"
|
|
#include "Hash.h"
|
|
|
|
#include "CommonPaths.h"
|
|
#include "FileUtil.h"
|
|
|
|
#include "D3DBase.h"
|
|
#include "D3DTexture.h"
|
|
|
|
#include "Render.h"
|
|
|
|
#include "TextureDecoder.h"
|
|
#include "TextureCache.h"
|
|
|
|
#include "../../../Core/Core/Src/ConfigManager.h" // FIXME
|
|
|
|
u8 *TextureCache::temp = NULL;
|
|
TextureCache::TexCache TextureCache::textures;
|
|
|
|
extern int frameCount;
|
|
|
|
#define TEMP_SIZE (1024*1024*4)
|
|
#define TEXTURE_KILL_THRESHOLD 200
|
|
|
|
void TextureCache::TCacheEntry::Destroy(bool shutdown)
|
|
{
|
|
if (texture)
|
|
texture->Release();
|
|
texture = 0;
|
|
if (!isRenderTarget && !shutdown) {
|
|
u32 *ptr = (u32*)g_VideoInitialize.pGetMemoryPointer(addr + hashoffset*4);
|
|
if (ptr && *ptr == hash)
|
|
*ptr = oldpixel;
|
|
}
|
|
}
|
|
|
|
void TextureCache::Init()
|
|
{
|
|
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
|
|
TexDecoder_SetTexFmtOverlayOptions(g_Config.bTexFmtOverlayEnable, g_Config.bTexFmtOverlayCenter);
|
|
}
|
|
|
|
void TextureCache::Invalidate(bool shutdown)
|
|
{
|
|
for (TexCache::iterator iter = textures.begin(); iter != textures.end(); iter++)
|
|
iter->second.Destroy(shutdown);
|
|
textures.clear();
|
|
}
|
|
|
|
void TextureCache::Shutdown()
|
|
{
|
|
Invalidate(true);
|
|
|
|
FreeMemoryPages(temp, TEMP_SIZE);
|
|
temp = NULL;
|
|
}
|
|
|
|
void TextureCache::Cleanup()
|
|
{
|
|
TexCache::iterator iter=textures.begin();
|
|
|
|
while(iter != textures.end())
|
|
{
|
|
if (frameCount> TEXTURE_KILL_THRESHOLD + iter->second.frameCount)
|
|
{
|
|
if (!iter->second.isRenderTarget)
|
|
{
|
|
iter->second.Destroy(false);
|
|
iter = textures.erase(iter);
|
|
}
|
|
else
|
|
{
|
|
// Used to be just iter++
|
|
iter->second.Destroy(false);
|
|
iter = textures.erase(iter);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iter++;
|
|
}
|
|
}
|
|
}
|
|
|
|
TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, int height, int format, int tlutaddr, int tlutfmt)
|
|
{
|
|
|
|
if (address == 0)
|
|
return NULL;
|
|
TexCache::iterator iter = textures.find(address);
|
|
|
|
u8 *ptr = g_VideoInitialize.pGetMemoryPointer(address);
|
|
|
|
int palSize = TexDecoder_GetPaletteSize(format);
|
|
u32 palhash = 0xc0debabe;
|
|
if (palSize)
|
|
{
|
|
if (palSize>16)
|
|
palSize = 16; //let's not do excessive amount of checking
|
|
u8 *pal = g_VideoInitialize.pGetMemoryPointer(tlutaddr);
|
|
if (pal != 0)
|
|
{
|
|
for (int i=0; i<palSize; i++)
|
|
{
|
|
palhash = _rotl(palhash,13);
|
|
palhash ^= pal[i];
|
|
palhash += 31;
|
|
}
|
|
}
|
|
}
|
|
|
|
static LPDIRECT3DTEXTURE9 lastTexture[8] = {0,0,0,0,0,0,0,0};
|
|
|
|
int bs = TexDecoder_GetBlockWidthInTexels(format)-1; //TexelSizeInNibbles(format)*width*height/16;
|
|
int expandedWidth = (width+bs) & (~bs);
|
|
u32 hash_value = TexDecoder_GetSafeTextureHash(ptr, expandedWidth, height, format, 0);
|
|
|
|
if (iter != textures.end())
|
|
{
|
|
TCacheEntry &entry = iter->second;
|
|
|
|
if (entry.isRenderTarget || ((address == entry.addr) && (hash_value == entry.hash)))
|
|
{
|
|
entry.frameCount = frameCount;
|
|
if (lastTexture[stage] == entry.texture)
|
|
{
|
|
return &entry;
|
|
}
|
|
lastTexture[stage] = entry.texture;
|
|
|
|
// D3D::dev->SetTexture(stage,iter->second.texture);
|
|
Renderer::SetTexture( stage, entry.texture );
|
|
|
|
return &entry;
|
|
}
|
|
else
|
|
{
|
|
/* if (width == iter->second.w && height==entry.h && format==entry.fmt)
|
|
{
|
|
LPDIRECT3DTEXTURE9 tex = entry.texture;
|
|
int bs = TexDecoder_GetBlockWidthInTexels(format)-1; //TexelSizeInNibbles(format)*width*height/16;
|
|
int expandedWidth = (width+bs) & (~bs);
|
|
D3DFORMAT dfmt = TexDecoder_Decode(temp,ptr,expandedWidth,height,format, tlutaddr, tlutfmt);
|
|
D3D::ReplaceTexture2D(tex,temp,width,height,expandedWidth,dfmt);
|
|
D3D::dev->SetTexture(stage,tex);
|
|
return;
|
|
}
|
|
else
|
|
{*/
|
|
entry.Destroy(false);
|
|
textures.erase(iter);
|
|
//}
|
|
}
|
|
}
|
|
|
|
PC_TexFormat pcfmt = TexDecoder_Decode(temp,ptr,expandedWidth,height,format, tlutaddr, tlutfmt);
|
|
D3DFORMAT d3d_fmt;
|
|
switch (pcfmt) {
|
|
case PC_TEX_FMT_BGRA32:
|
|
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_A4L4;
|
|
break;
|
|
case PC_TEX_FMT_I8:
|
|
case PC_TEX_FMT_I4_AS_I8:
|
|
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
|
|
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[address];
|
|
|
|
entry.hashoffset = 0;
|
|
entry.hash = hash_value;
|
|
//entry.hash = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF);
|
|
entry.paletteHash = palhash;
|
|
entry.oldpixel = ((u32 *)ptr)[entry.hashoffset];
|
|
//((u32 *)ptr)[entry.hashoffset] = entry.hash;
|
|
|
|
entry.addr = address;
|
|
entry.isRenderTarget = false;
|
|
entry.isNonPow2 = ((width & (width - 1)) || (height & (height - 1)));
|
|
entry.texture = D3D::CreateTexture2D((BYTE*)temp, width, height, expandedWidth, d3d_fmt);
|
|
entry.frameCount = frameCount;
|
|
entry.w = width;
|
|
entry.h = height;
|
|
entry.fmt = format;
|
|
entry.mode = bpmem.tex[stage > 3].texMode0[stage & 3];
|
|
|
|
if (g_Config.bDumpTextures)
|
|
{ // dump texture to file
|
|
char szTemp[MAX_PATH];
|
|
char szDir[MAX_PATH];
|
|
bool bCheckedDumpDir = false;
|
|
sprintf(szDir,"%s/%s",FULL_DUMP_TEXTURES_DIR,((struct SConfig *)globals->config)->m_LocalCoreStartupParameter.GetUniqueID().c_str());
|
|
if(!bCheckedDumpDir)
|
|
{
|
|
if (!File::Exists(szDir) || !File::IsDirectory(szDir))
|
|
File::CreateDir(szDir);
|
|
|
|
bCheckedDumpDir = true;
|
|
}
|
|
sprintf(szTemp, "%s/%s_%08x_%i.png",szDir, ((struct SConfig *)globals->config)->m_LocalCoreStartupParameter.GetUniqueID().c_str(), hash_value, 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::dev->SetTexture(stage,entry.texture);
|
|
Renderer::SetTexture( stage, entry.texture );
|
|
|
|
lastTexture[stage] = entry.texture;
|
|
|
|
return &entry;
|
|
}
|
|
|
|
|
|
void TextureCache::CopyEFBToRenderTarget(u32 address, RECT *source)
|
|
{
|
|
TexCache::iterator iter;
|
|
LPDIRECT3DTEXTURE9 tex;
|
|
iter = textures.find(address);
|
|
if (iter != textures.end())
|
|
{
|
|
if (!iter->second.isRenderTarget)
|
|
{
|
|
g_VideoInitialize.pLog("Using non-rendertarget texture as render target!!! WTF?", FALSE);
|
|
//TODO: remove it and recreate it as a render target
|
|
}
|
|
tex = iter->second.texture;
|
|
iter->second.frameCount=frameCount;
|
|
}
|
|
else
|
|
{
|
|
TCacheEntry entry;
|
|
entry.isRenderTarget=true;
|
|
entry.hash = 0;
|
|
entry.hashoffset = 0;
|
|
entry.frameCount = frameCount;
|
|
// TODO(ector): infer this size in some sensible way
|
|
D3D::dev->CreateTexture(512,512,1,D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &entry.texture, 0);
|
|
textures[address] = entry;
|
|
tex = entry.texture;
|
|
}
|
|
LPDIRECT3DSURFACE9 srcSurface,destSurface;
|
|
tex->GetSurfaceLevel(0,&destSurface);
|
|
srcSurface = D3D::GetBackBufferSurface();
|
|
D3D::dev->StretchRect(srcSurface,source,destSurface,0,D3DTEXF_NONE);
|
|
destSurface->Release();
|
|
}
|