Merged common texture cache code from video plugins into VideoCommon. (DX11 native mipmaps currently broken, disabled) Hopefully everything else should still be working.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6288 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak
2010-10-19 22:24:27 +00:00
parent 16ff21b0d5
commit cf05cca7a6
25 changed files with 1485 additions and 1922 deletions

View File

@ -95,7 +95,7 @@ void Shutdown()
textureMap.clear();
}
PC_TexFormat GetHiresTex(const char *fileName, int *pWidth, int *pHeight, int texformat, u8 *data)
PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned int *pHeight, int texformat, u8 *data)
{
std::string key(fileName);

View File

@ -26,7 +26,7 @@ namespace HiresTextures
{
void Init(const char *gameCode);
void Shutdown();
PC_TexFormat GetHiresTex(const char *fileName, int *pWidth, int *pHeight, int texformat, u8 *data);
PC_TexFormat GetHiresTex(const char *fileName, unsigned int *pWidth, unsigned int *pHeight, int texformat, u8 *data);
};

View File

@ -30,6 +30,7 @@ files = [
'TextureConversionShader.cpp',
'ImageWrite.cpp',
'VertexManagerBase.cpp',
'TextureCacheBase.cpp',
'Statistics.cpp',
'Fifo.cpp',
'VideoState.cpp',

View File

@ -0,0 +1,659 @@
#include "MemoryUtil.h"
#include "VideoConfig.h"
#include "Statistics.h"
#include "HiresTextures.h"
#include "Render.h"
#include "FileUtil.h"
#include "Profiler.h"
#include "PluginSpecs.h"
#include "TextureCacheBase.h"
// ugly
extern int frameCount;
enum
{
TEMP_SIZE = (1024 * 1024 * 4),
TEXTURE_KILL_THRESHOLD = 200,
};
TextureCache *g_texture_cache;
u8 *TextureCache::temp;
TextureCache::TexCache TextureCache::textures;
// returns the exponent of the smallest power of two which is greater than val
unsigned int GetPow2(unsigned int val)
{
unsigned int ret = 0;
for (; val; val >>= 1)
++ret;
return ret;
}
TextureCache::TCacheEntryBase::~TCacheEntryBase()
{
if (0 == addr)
return;
if (!isRenderTarget && !g_ActiveConfig.bSafeTextureCache)
{
u32 *const ptr = (u32*)g_VideoInitialize.pGetMemoryPointer(addr);
if (ptr && *ptr == hash)
*ptr = oldpixel;
}
}
// TODO: uglyness
extern PLUGIN_GLOBALS *globals;
TextureCache::TextureCache()
{
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
HiresTextures::Init(globals->unique_id);
}
void TextureCache::Invalidate(bool shutdown)
{
TexCache::iterator
iter = textures.begin(),
tcend = textures.end();
for (; iter != tcend; ++iter)
{
if (shutdown)
iter->second->addr = 0;
delete iter->second;
}
textures.clear();
HiresTextures::Shutdown();
}
TextureCache::~TextureCache()
{
Invalidate(true);
FreeMemoryPages(temp, TEMP_SIZE);
temp = NULL;
}
void TextureCache::Cleanup()
{
TexCache::iterator
iter = textures.begin(),
tcend = textures.end();
while (iter != tcend)
{
if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount)
{
delete iter->second;
textures.erase(iter++);
}
else
++iter;
}
}
void TextureCache::InvalidateRange(u32 start_address, u32 size)
{
TexCache::iterator
iter = textures.begin(),
tcend = textures.end();
while (iter != tcend)
{
const int rangePosition = iter->second->IntersectsMemoryRange(start_address, size);
if (0 == rangePosition)
{
delete iter->second;
textures.erase(iter++);
}
else
++iter;
}
}
void TextureCache::MakeRangeDynamic(u32 start_address, u32 size)
{
TexCache::iterator
iter = textures.begin(),
tcend = textures.end();
for (; iter != tcend; ++iter)
{
const int rangePosition = iter->second->IntersectsMemoryRange(start_address, size);
if (0 == rangePosition)
{
iter->second->hash = 0;
}
}
}
int TextureCache::TCacheEntryBase::IntersectsMemoryRange(u32 range_address, u32 range_size) const
{
if (addr + size_in_bytes < range_address)
return -1;
if (addr >= range_address + range_size)
return 1;
return 0;
}
void TextureCache::ClearRenderTargets()
{
TexCache::iterator
iter = textures.begin(),
tcend = textures.end();
for (; iter!=tcend; ++iter)
iter->second->isRenderTarget = false;
}
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 = g_VideoInitialize.pGetMemoryPointer(address);
// TexelSizeInNibbles(format)*width*height/16;
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1;
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1;
unsigned int expandedWidth = (width + bsw) & (~bsw);
unsigned int expandedHeight = (height + bsh) & (~bsh);
u64 hash_value = 0;
u64 texHash = 0;
u32 texID = address;
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;
// someone who understands this var could rename it :p
const bool isC4_C8_C14X2 = (texformat == GX_TF_C4 || texformat == GX_TF_C8 || texformat == GX_TF_C14X2);
if (isC4_C8_C14X2)
full_format = texformat | (tlutfmt << 16);
// hires texture loading and texture dumping require accurate hashes
if (g_ActiveConfig.bSafeTextureCache || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures)
{
texHash = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
if (isC4_C8_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.
const u64 tlutHash = GetHash64(texMem + tlutaddr, palette_size,
g_ActiveConfig.iSafeTextureCache_ColorSamples);
texHash ^= tlutHash;
if (g_ActiveConfig.bSafeTextureCache)
texID ^= ((u32)tlutHash) ^ (tlutHash >> 32);
}
if (g_ActiveConfig.bSafeTextureCache)
hash_value = texHash;
}
TCacheEntryBase *entry = textures[texID];
if (entry)
{
if (false == g_ActiveConfig.bSafeTextureCache)
{
if (entry->isRenderTarget || entry->isDynamic)
{
if (false == g_ActiveConfig.bCopyEFBToTexture)
{
hash_value = GetHash64(ptr, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
if (isC4_C8_C14X2)
{
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)
{
hash_value = 0;
}
// TODO: Is the mipLevels check needed?
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;
goto 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.
texture_is_dynamic = (entry->isRenderTarget || entry->isDynamic) && !g_ActiveConfig.bCopyEFBToTexture;
// TODO: Is the mipLevels check needed?
if (!entry->isRenderTarget &&
((!entry->isDynamic && width == entry->w && height == entry->h && full_format == entry->format && entry->mipLevels == maxlevel)
|| (entry->isDynamic && entry->w == width && entry->h == height)))
{
// reuse the texture
}
else
{
// delete the texture and make a new one
delete entry;
entry = NULL;
}
}
}
const unsigned int nativeW = width;
const unsigned int nativeH = height;
PC_TexFormat pcfmt = PC_TEX_FMT_NONE;
if (g_ActiveConfig.bHiresTextures)
{
// Load Custom textures
char texPathTemp[MAX_PATH];
unsigned int newWidth = width;
unsigned int newHeight = height;
sprintf(texPathTemp, "%s_%08x_%i", globals->unique_id, texHash, 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_texture_cache->isOGL());
const bool isPow2 = !((width & (width - 1)) || (height & (height - 1)));
unsigned int texLevels = (isPow2 && UseNativeMips && maxlevel) ?
GetPow2(std::max(width, height)) : !isPow2;
if ((texLevels > (maxlevel + 1)) && maxlevel)
texLevels = maxlevel + 1;
// create the entry/texture
if (NULL == entry)
{
textures[texID] = entry = g_texture_cache->CreateTexture(width, height, expandedWidth, texLevels, pcfmt);
entry->addr = address;
entry->format = full_format;
entry->mipLevels = maxlevel;
entry->size_in_bytes = texture_size;
entry->scaledW = entry->w = width;
entry->scaledH = entry->h = height;
entry->nativeH = nativeH;
entry->nativeW = nativeW;
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);
}
// load texture
entry->Load(width, height, expandedWidth, 0);
// load mips
if (texLevels > 1 && pcfmt != PC_TEX_FMT_NONE)
{
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(texformat);
unsigned int level = 1;
unsigned int mipWidth = (width + 1) >> 1;
unsigned int mipHeight = (height + 1) >> 1;
ptr += texture_size;
while ((mipHeight || mipWidth) && (level < texLevels))
{
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_texture_cache->isOGL());
entry->Load(currentWidth, currentHeight, expandedWidth, level);
ptr += ((std::max(mipWidth, bsw) * std::max(mipHeight, bsh) * bsdepth) >> 1);
mipWidth >>= 1;
mipHeight >>= 1;
++level;
}
}
// TODO: won't this cause loaded hires textures to be dumped as well?
// dump texture to file
if (g_ActiveConfig.bDumpTextures)
{
char szTemp[MAX_PATH];
char szDir[MAX_PATH];
// make sure that the directory exists
sprintf(szDir, "%s%s", File::GetUserPath(D_DUMPTEXTURES_IDX), globals->unique_id);
if (false == File::Exists(szDir) || false == File::IsDirectory(szDir))
File::CreateDir(szDir);
sprintf(szTemp, "%s/%s_%08x_%i.png", szDir, globals->unique_id, texHash, texformat);
if (false == File::Exists(szTemp))
entry->Save(szTemp);
}
INCSTAT(stats.numTexturesCreated);
SETSTAT(stats.numTexturesAlive, textures.size());
return_entry:
entry->frameCount = frameCount;
entry->Bind(stage);
return entry;
}
void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer,
bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect)
{
DVSTARTPROFILE();
float colmat[20] = {};
// last four floats of colmat for fConstAdd
float *const fConstAdd = colmat + 16;
unsigned int cbufid = -1;
if (bFromZBuffer)
{
// TODO: these values differ slightly from the DX9/11 values,
// do they need to? or can this be removed
if (g_texture_cache->isOGL())
{
switch(copyfmt)
{
case 0: // Z4
case 1: // Z8
colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1;
break;
case 3: // Z16 //?
colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1;
break;
case 11: // Z16 (reverse order)
colmat[2] = colmat[6] = colmat[10] = colmat[13] = 1;
break;
case 6: // Z24X8
colmat[2] = colmat[5] = colmat[8] = colmat[15] = 1;
break;
case 9: // Z8M
colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1;
break;
case 10: // Z8L
colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1;
break;
case 12: // Z16L
colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1;
break;
default:
ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", copyfmt);
colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
break;
}
}
else
{
switch (copyfmt)
{
case 0: // Z4
case 1: // Z8
colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f;
cbufid = 12;
break;
case 3: // Z16 //?
colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f;
cbufid = 13;
break;
case 11: // Z16 (reverse order)
colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f;
cbufid = 14;
break;
case 6: // Z24X8
colmat[0] = colmat[5] = colmat[10] = 1.0f;
cbufid = 15;
break;
case 9: // Z8M
colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f;
cbufid = 16;
break;
case 10: // Z8L
colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f;
cbufid = 17;
break;
case 12: // Z16L
colmat[2] = colmat[6] = colmat[10] = colmat[13] = 1.0f;
cbufid = 18;
break;
default:
ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", copyfmt);
colmat[2] = colmat[5] = colmat[8] = 1.0f;
cbufid = 19;
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;
cbufid = 0;
}
else// alpha
{
colmat[15] = 1;
cbufid = 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;
cbufid = 2;
break;
case 2: // RA4
case 3: // RA8
colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1;
cbufid = 3;
break;
case 7: // A8
colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1;
cbufid = 4;
break;
case 9: // G8
colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1;
cbufid = 5;
break;
case 10: // B8
colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1;
cbufid = 6;
break;
case 11: // RG8
colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1;
cbufid = 7;
break;
case 12: // GB8
colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1;
cbufid = 8;
break;
case 4: // RGB565
colmat[0] = colmat[5] = colmat[10] = 1;
fConstAdd[3] = 1; // set alpha to 1
cbufid = 9;
break;
case 5: // RGB5A3
case 6: // RGBA8
colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
cbufid = 10;
break;
default:
ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", copyfmt);
colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
cbufid = 11;
break;
}
}
const unsigned int tex_w = (abs(source_rect.GetWidth()) >> (int)bScaleByHalf);
const unsigned int tex_h = (abs(source_rect.GetHeight()) >> (int)bScaleByHalf);
const float xScale = Renderer::GetTargetScaleX();
const float yScale = Renderer::GetTargetScaleY();
unsigned int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? (int)(tex_w * xScale) : tex_w;
unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? (int)(tex_h * yScale) : tex_h;
bool texture_is_dynamic = false;
TCacheEntryBase *entry = textures[address];
if (entry)
{
if ((entry->isRenderTarget && entry->scaledW == scaled_tex_w && entry->scaledH == scaled_tex_h)
|| (entry->isDynamic && entry->w == tex_w && entry->h == tex_h))
{
texture_is_dynamic = entry->isDynamic;
}
else
{
// remove it and recreate it as a render target
delete entry;
entry = NULL;
}
}
if (texture_is_dynamic)
{
scaled_tex_w = tex_w;
scaled_tex_h = tex_h;
}
if (NULL == entry)
{
// create the texture
textures[address] = entry = g_texture_cache->CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h);
entry->addr = address;
entry->hash = 0;
entry->w = entry->nativeW = tex_w;
entry->h = entry->nativeH = tex_h;
entry->scaledW = scaled_tex_w;
entry->scaledH = scaled_tex_h;
entry->format = copyfmt;
entry->mipLevels = 0;
entry->isRenderTarget = true;
entry->isNonPow2 = true;
entry->isDynamic = false;
}
entry->frameCount = frameCount;
Renderer::ResetAPIState(); // reset any game specific settings
entry->FromRenderTarget(bFromZBuffer, bScaleByHalf, cbufid, colmat, source_rect, bIsIntensityFmt, copyfmt);
Renderer::RestoreAPIState();
}

View File

@ -0,0 +1,99 @@
#ifndef _TEXTURECACHEBASE_H
#define _TEXTURECACHEBASE_H
#include <map>
//#include "VideoCommon.h"
#include "TextureDecoder.h"
#include "BPMemory.h"
#include "CommonTypes.h"
class TextureCache
{
public:
struct TCacheEntryBase
{
// TODO: organize
u32 addr;
u32 size_in_bytes;
u64 hash;
//u32 paletteHash;
u32 oldpixel;
u32 format;
int frameCount;
unsigned int w, h, mipLevels;
// TODO: it looks like scaledW/H can be removed and w/h can be used in their place
unsigned int scaledW, scaledH, nativeW, nativeH;
bool isRenderTarget;
bool isDynamic; // mofified from cpu
bool isNonPow2; // doesn't seem to be used anywhere
//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();
virtual void Bind(unsigned int stage) = 0;
virtual bool Save(const char filename[]) = 0;
virtual void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level) = 0;
virtual void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
unsigned int cbufid, const float *colmat, const EFBRectangle &source_rect,
bool bIsIntensityFmt, u32 copyfmt) = 0;
int IntersectsMemoryRange(u32 range_address, u32 range_size) const;
};
virtual ~TextureCache(); // needs virtual for DX11 dtor
static void Cleanup();
static void Invalidate(bool shutdown);
static void InvalidateRange(u32 start_address, u32 size);
static void MakeRangeDynamic(u32 start_address, u32 size);
static void ClearRenderTargets(); // currently only used by OGL
virtual TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) = 0;
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);
static void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect);
protected:
TextureCache();
static u8 *temp;
private:
typedef std::map<u32, TCacheEntryBase*> TexCache;
static TexCache textures;
virtual bool isOGL() { return false; } // Hacks for TextureDecode_real support
};
extern TextureCache *g_texture_cache;
#endif

View File

@ -4,6 +4,12 @@
#include "Statistics.h"
#include "OpcodeDecoding.h"
#include "IndexGenerator.h"
#include "VertexShaderManager.h"
#include "PixelShaderManager.h"
#include "NativeVertexFormat.h"
#include "TextureCacheBase.h"
#include "Render.h"
#include "Profiler.h"
#include "VertexManagerBase.h"
@ -151,8 +157,158 @@ void VertexManager::AddVertices(int primitive, int numVertices)
AddIndices(primitive, numVertices);
}
// TODO: merge this func, (need to merge TextureCache)
void VertexManager::Flush()
{
g_vertex_manager->vFlush();
}
// TODO: need to merge more stuff into VideoCommon to use this
#if (0)
void VertexManager::Flush()
{
if (LocalVBuffer == s_pCurBufferPointer || Flushed)
return;
Flushed = true;
VideoFifo_CheckEFBAccess();
#if defined(_DEBUG) || defined(DEBUGFAST)
PRIM_LOG("frame%d:\n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d", g_ActiveConfig.iSaveTargetId, xfregs.numTexGens,
xfregs.nNumChans, (int)xfregs.bEnableDualTexTransform, bpmem.ztex2.op,
bpmem.blendmode.colorupdate, bpmem.blendmode.alphaupdate, bpmem.zmode.updateenable);
for (int i = 0; i < xfregs.nNumChans; ++i)
{
LitChannel* ch = &xfregs.colChans[i].color;
PRIM_LOG("colchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i, ch->matsource, ch->GetFullLightMask(), ch->ambsource, ch->diffusefunc, ch->attnfunc);
ch = &xfregs.colChans[i].alpha;
PRIM_LOG("alpchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i, ch->matsource, ch->GetFullLightMask(), ch->ambsource, ch->diffusefunc, ch->attnfunc);
}
for (int i = 0; i < xfregs.numTexGens; ++i)
{
TexMtxInfo tinfo = xfregs.texcoords[i].texmtxinfo;
if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP) tinfo.hex &= 0x7ff;
if (tinfo.texgentype != XF_TEXGEN_REGULAR) tinfo.projection = 0;
PRIM_LOG("txgen%d: proj=%d, input=%d, gentype=%d, srcrow=%d, embsrc=%d, emblght=%d, postmtx=%d, postnorm=%d",
i, tinfo.projection, tinfo.inputform, tinfo.texgentype, tinfo.sourcerow, tinfo.embosssourceshift, tinfo.embosslightshift,
xfregs.texcoords[i].postmtxinfo.index, xfregs.texcoords[i].postmtxinfo.normalize);
}
PRIM_LOG("pixel: tev=%d, ind=%d, texgen=%d, dstalpha=%d, alphafunc=0x%x", bpmem.genMode.numtevstages+1, bpmem.genMode.numindstages,
bpmem.genMode.numtexgens, (u32)bpmem.dstalpha.enable, (bpmem.alphaFunc.hex>>16)&0xff);
#endif
DVSTARTPROFILE();
// set the textures
DVSTARTSUBPROFILE("VertexManager::Flush:textures");
u32 usedtextures = 0;
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
if (bpmem.tevorders[i / 2].getEnable(i & 1))
usedtextures |= 1 << bpmem.tevorders[i/2].getTexMap(i & 1);
if (bpmem.genMode.numindstages > 0)
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
usedtextures |= 1 << bpmem.tevindref.getTexMap(bpmem.tevind[i].bt);
for (u32 i = 0; i < 8; ++i)
{
if (usedtextures & (1 << i))
{
// TODO:
//glActiveTexture(GL_TEXTURE0 + i);
Renderer::SetSamplerState(i & 3, i >> 2);
FourTexUnits &tex = bpmem.tex[i >> 2];
TCacheEntry::TCacheEntryBase* tentry = TextureCache::Load(i,
(tex.texImage3[i&3].image_base/* & 0x1FFFFF*/) << 5,
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
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));
if (tentry)
{
// 0s are probably for no manual wrapping needed.
PixelShaderManager::SetTexDims(i, tentry->nativeW, tentry->nativeH, 0, 0);
// TODO:
//if (g_ActiveConfig.iLog & CONF_SAVETEXTURES)
//{
// // save the textures
// char strfile[255];
// sprintf(strfile, "%stex%.3d_%d.tga", File::GetUserPath(D_DUMPFRAMES_IDX), g_Config.iSaveTargetId, i);
// SaveTexture(strfile, GL_TEXTURE_2D, tentry->texture, tentry->w, tentry->h);
//}
}
else
ERROR_LOG(VIDEO, "error loading texture");
}
}
// set global constants
VertexShaderManager::SetConstants();
PixelShaderManager::SetConstants();
// finally bind
if (false == PixelShaderCache::SetShader(false, g_nativeVertexFmt->m_components))
goto shader_fail;
if (false == VertexShaderCache::SetShader(g_nativeVertexFmt->m_components))
goto shader_fail;
const int stride = g_nativeVertexFmt->GetVertexStride();
//if (g_nativeVertexFmt)
g_nativeVertexFmt->SetupVertexPointers();
g_vertex_manager->Draw(stride, false);
// run through vertex groups again to set alpha
if (false == g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate)
{
if (false == PixelShaderCache::SetShader(true, g_nativeVertexFmt->m_components))
goto shader_fail;
g_vertex_manager->Draw(stride, true);
}
// TODO:
//IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer);
#if defined(_DEBUG) || defined(DEBUGFAST)
if (g_ActiveConfig.iLog & CONF_SAVESHADERS)
{
// save the shaders
char strfile[255];
sprintf(strfile, "%sps%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX), g_ActiveConfig.iSaveTargetId);
std::ofstream fps(strfile);
fps << ps->strprog.c_str();
sprintf(strfile, "%svs%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX), g_ActiveConfig.iSaveTargetId);
std::ofstream fvs(strfile);
fvs << vs->strprog.c_str();
}
if (g_ActiveConfig.iLog & CONF_SAVETARGETS)
{
char str[128];
sprintf(str, "%starg%.3d.tga", File::GetUserPath(D_DUMPFRAMES_IDX), g_ActiveConfig.iSaveTargetId);
TargetRectangle tr;
tr.left = 0;
tr.right = Renderer::GetTargetWidth();
tr.top = 0;
tr.bottom = Renderer::GetTargetHeight();
Renderer::SaveRenderTarget(str, tr);
}
#endif
++g_Config.iSaveTargetId;
shader_fail:
ResetBuffer();
}
#endif

View File

@ -48,8 +48,10 @@ protected:
private:
static void AddIndices(int primitive, int numVertices);
// temporary
//virtual void Draw(u32 stride, bool alphapass) = 0;
// temp
virtual void vFlush() = 0;
};
extern VertexManager *g_vertex_manager;

View File

@ -730,6 +730,14 @@
<Filter
Name="Base"
>
<File
RelativePath=".\Src\TextureCacheBase.cpp"
>
</File>
<File
RelativePath=".\Src\TextureCacheBase.h"
>
</File>
<File
RelativePath=".\Src\VertexManagerBase.cpp"
>