Cachable vertex loaders. Not a very big speedup in itself, but makes it easier to speed up vertex loading in the future.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@960 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2008-10-25 15:53:43 +00:00
parent 681a40dd36
commit f77624147d
11 changed files with 609 additions and 618 deletions

View File

@ -39,6 +39,8 @@ struct Statistics
int numJoins; int numJoins;
int numVertexLoaders;
struct ThisFrame struct ThisFrame
{ {
int numBPLoads; int numBPLoads;

View File

@ -23,8 +23,8 @@
#include "TextureDecoder.h" #include "TextureDecoder.h"
#include "Fifo.h" #include "Fifo.h"
static void DoState(PointerWrap &p) { static void DoState(PointerWrap &p)
{
// BP Memory // BP Memory
p.Do(bpmem); p.Do(bpmem);
// CP Memory // CP Memory

View File

@ -171,7 +171,7 @@ void PixelShaderMngr::Cleanup()
PSCache::iterator iter = pshaders.begin(); PSCache::iterator iter = pshaders.begin();
while (iter != pshaders.end()) { while (iter != pshaders.end()) {
PSCacheEntry &entry = iter->second; PSCacheEntry &entry = iter->second;
if (entry.frameCount < frameCount - 200) { if (entry.frameCount < frameCount - 400) {
entry.Destroy(); entry.Destroy();
#ifdef _WIN32 #ifdef _WIN32
iter = pshaders.erase(iter); iter = pshaders.erase(iter);
@ -242,10 +242,9 @@ void PixelShaderMngr::SetConstants()
{ {
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
if (s_nColorsChanged[i]) { if (s_nColorsChanged[i]) {
int baseind = i ? C_KCOLORS : C_COLORS;
int baseind = i?C_KCOLORS:C_COLORS;
for (int j = 0; j < 4; ++j) { for (int j = 0; j < 4; ++j) {
if (s_nColorsChanged[i] & (1<<j)) { if (s_nColorsChanged[i] & (1 << j)) {
SetPSConstant4fv(baseind+j, &lastRGBAfull[i][j][0]); SetPSConstant4fv(baseind+j, &lastRGBAfull[i][j][0]);
} }
} }
@ -258,7 +257,7 @@ void PixelShaderMngr::SetConstants()
if (bpmem.tevorders[i/2].getEnable(i&1)) { if (bpmem.tevorders[i/2].getEnable(i&1)) {
int texmap = bpmem.tevorders[i/2].getTexMap(i&1); int texmap = bpmem.tevorders[i/2].getTexMap(i&1);
maptocoord[texmap] = bpmem.tevorders[i/2].getTexCoord(i&1); maptocoord[texmap] = bpmem.tevorders[i/2].getTexCoord(i&1);
newmask |= 1<<texmap; newmask |= 1 << texmap;
SetTexDimsChanged(texmap); SetTexDimsChanged(texmap);
} }
} }
@ -266,7 +265,7 @@ void PixelShaderMngr::SetConstants()
if (maptocoord_mask != newmask) { if (maptocoord_mask != newmask) {
//u32 changes = maptocoord_mask ^ newmask; //u32 changes = maptocoord_mask ^ newmask;
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
if (newmask&(1<<i)) { if (newmask & (1 << i)) {
SetTexDimsChanged(i); SetTexDimsChanged(i);
} }
else { else {

View File

@ -773,6 +773,7 @@ void Renderer::SwapBuffers()
p+=sprintf(p,"Num CP loads (DL): %i\n",stats.thisFrame.numCPLoadsInDL); p+=sprintf(p,"Num CP loads (DL): %i\n",stats.thisFrame.numCPLoadsInDL);
p+=sprintf(p,"Num BP loads: %i\n",stats.thisFrame.numBPLoads); p+=sprintf(p,"Num BP loads: %i\n",stats.thisFrame.numBPLoads);
p+=sprintf(p,"Num BP loads (DL): %i\n",stats.thisFrame.numBPLoadsInDL); p+=sprintf(p,"Num BP loads (DL): %i\n",stats.thisFrame.numBPLoadsInDL);
p+=sprintf(p,"Num vertex loaders: %i\n",stats.numVertexLoaders);
Renderer::RenderText(st, 20, 20, 0xFF00FFFF); Renderer::RenderText(st, 20, 20, 0xFF00FFFF);
} }

View File

@ -50,7 +50,9 @@ int TextureMngr::nTex2DEnabled, TextureMngr::nTexRECTEnabled;
extern int frameCount; extern int frameCount;
static u32 s_TempFramebuffer = 0; static u32 s_TempFramebuffer = 0;
#define TEMP_SIZE (1024*1024*4) #define TEMP_SIZE (1024*1024*4)
#define TEXTURE_KILL_THRESHOLD 200
const GLint c_MinLinearFilter[8] = { const GLint c_MinLinearFilter[8] = {
GL_NEAREST, GL_NEAREST,
@ -119,7 +121,7 @@ void TextureMngr::Init()
void TextureMngr::Invalidate() void TextureMngr::Invalidate()
{ {
TexCache::iterator iter = textures.begin(); TexCache::iterator iter = textures.begin();
for (;iter!=textures.end();iter++) for (; iter!=textures.end(); iter++)
iter->second.Destroy(); iter->second.Destroy();
textures.clear(); textures.clear();
TexDecoder_SetTexFmtOverlayOptions(g_Config.bTexFmtOverlayEnable, g_Config.bTexFmtOverlayCenter); TexDecoder_SetTexFmtOverlayOptions(g_Config.bTexFmtOverlayEnable, g_Config.bTexFmtOverlayCenter);
@ -134,7 +136,7 @@ void TextureMngr::Shutdown()
} }
mapDepthTargets.clear(); mapDepthTargets.clear();
if( s_TempFramebuffer ) { if (s_TempFramebuffer) {
glDeleteFramebuffersEXT(1, (GLuint *)&s_TempFramebuffer); glDeleteFramebuffersEXT(1, (GLuint *)&s_TempFramebuffer);
s_TempFramebuffer = 0; s_TempFramebuffer = 0;
} }
@ -147,7 +149,7 @@ void TextureMngr::Cleanup()
{ {
TexCache::iterator iter = textures.begin(); TexCache::iterator iter = textures.begin();
while (iter != textures.end()) { while (iter != textures.end()) {
if (frameCount > 20 + iter->second.frameCount) { if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second.frameCount) {
if (!iter->second.isRenderTarget) { if (!iter->second.isRenderTarget) {
iter->second.Destroy(); iter->second.Destroy();
#ifdef _WIN32 #ifdef _WIN32
@ -215,10 +217,10 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width
if (iter != textures.end()) { if (iter != textures.end()) {
TCacheEntry &entry = iter->second; TCacheEntry &entry = iter->second;
if(entry.isRenderTarget || (((u32 *)ptr)[entry.hashoffset] == entry.hash && palhash == entry.paletteHash)) { //stupid, improve if (entry.isRenderTarget || (((u32 *)ptr)[entry.hashoffset] == entry.hash && palhash == entry.paletteHash)) { //stupid, improve
entry.frameCount = frameCount; entry.frameCount = frameCount;
//glEnable(entry.isNonPow2?GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D); //glEnable(entry.isNonPow2?GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D);
glBindTexture(entry.isNonPow2?GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D, entry.texture); glBindTexture(entry.isNonPow2 ? GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D, entry.texture);
if (entry.mode.hex != tm0.hex) if (entry.mode.hex != tm0.hex)
entry.SetTextureParameters(tm0); entry.SetTextureParameters(tm0);
return &entry; return &entry;

View File

@ -17,29 +17,18 @@
#include "Globals.h" #include "Globals.h"
#include <fstream>
#include <assert.h> #include <assert.h>
#include "Common.h" #include "Common.h"
#include "Config.h" #include "Config.h"
#include "ImageWrite.h"
#include "Profiler.h" #include "Profiler.h"
#include "StringUtil.h"
#include "Render.h"
#include "VertexShader.h"
#include "VertexManager.h" #include "VertexManager.h"
#include "VertexLoaderManager.h" #include "VertexLoaderManager.h"
#include "VertexLoader.h" #include "VertexLoader.h"
#include "BPStructs.h" #include "BPStructs.h"
#include "DataReader.h" #include "DataReader.h"
#include "VertexShaderManager.h"
#include "PixelShaderManager.h"
#include "TextureMngr.h"
#include <fstream>
NativeVertexFormat *g_nativeVertexFmt; NativeVertexFormat *g_nativeVertexFmt;
//these don't need to be saved //these don't need to be saved
@ -54,8 +43,6 @@ static int colIndex;
#define inline #define inline
#endif #endif
// ==============================================================================
// Direct // Direct
// ============================================================================== // ==============================================================================
static u8 s_curposmtx; static u8 s_curposmtx;
@ -65,7 +52,7 @@ static int s_texmtxread = 0;
void LOADERDECL PosMtx_ReadDirect_UByte(const void *_p) void LOADERDECL PosMtx_ReadDirect_UByte(const void *_p)
{ {
s_curposmtx = DataReadU8()&0x3f; s_curposmtx = DataReadU8() & 0x3f;
PRIM_LOG("posmtx: %d, ", s_curposmtx); PRIM_LOG("posmtx: %d, ", s_curposmtx);
} }
@ -110,12 +97,17 @@ void LOADERDECL TexMtx_Write_Short3(const void *_p)
#include "VertexLoader_Color.h" #include "VertexLoader_Color.h"
#include "VertexLoader_TextCoord.h" #include "VertexLoader_TextCoord.h"
VertexLoader::VertexLoader() VertexLoader::VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr)
{ {
m_VertexSize = 0; m_VertexSize = 0;
m_AttrDirty = AD_DIRTY;
m_numPipelineStages = 0; m_numPipelineStages = 0;
VertexLoader_Normal::Init(); VertexLoader_Normal::Init();
m_VtxDesc = vtx_desc;
SetVAT(vtx_attr.g0.Hex, vtx_attr.g1.Hex, vtx_attr.g2.Hex);
ComputeVertexSize();
CompileVertexTranslator();
} }
VertexLoader::~VertexLoader() VertexLoader::~VertexLoader()
@ -124,20 +116,6 @@ VertexLoader::~VertexLoader()
int VertexLoader::ComputeVertexSize() int VertexLoader::ComputeVertexSize()
{ {
if (m_AttrDirty == AD_CLEAN) {
// Compare the 33 desc bits.
if (m_VtxDesc.Hex0 == g_VtxDesc.Hex0 &&
(m_VtxDesc.Hex1 & 1) == (g_VtxDesc.Hex1 & 1))
return m_VertexSize;
m_VtxDesc.Hex = g_VtxDesc.Hex;
}
else {
// Attributes are dirty so we have to recompute everything anyway.
m_VtxDesc.Hex = g_VtxDesc.Hex;
}
m_AttrDirty = AD_DIRTY;
m_VertexSize = 0; m_VertexSize = 0;
// Position Matrix Index // Position Matrix Index
if (m_VtxDesc.PosMatIdx) if (m_VtxDesc.PosMatIdx)
@ -245,22 +223,6 @@ int VertexLoader::ComputeVertexSize()
void VertexLoader::CompileVertexTranslator() void VertexLoader::CompileVertexTranslator()
{ {
if (m_AttrDirty == AD_CLEAN)
{
// Check if local cached desc (in this VL) matches global desc
if (m_VtxDesc.Hex0 == g_VtxDesc.Hex0 &&
(m_VtxDesc.Hex1 & 1) == (g_VtxDesc.Hex1 & 1))
{
return; // same
}
}
else
{
m_AttrDirty = AD_CLEAN;
}
m_VtxDesc.Hex = g_VtxDesc.Hex;
// Reset pipeline // Reset pipeline
m_numPipelineStages = 0; m_numPipelineStages = 0;
@ -514,12 +476,11 @@ void VertexLoader::WriteCall(TPipelineFunction func)
m_PipelineStages[m_numPipelineStages++] = func; m_PipelineStages[m_numPipelineStages++] = func;
} }
void VertexLoader::RunVertices(int primitive, int count) void VertexLoader::RunVertices(int vtx_attr_group, int primitive, int count)
{ {
DVSTARTPROFILE(); DVSTARTPROFILE();
// Flush if our vertex format is different from the currently set. // Flush if our vertex format is different from the currently set.
// TODO - this check should be moved.
if (g_nativeVertexFmt != NULL && g_nativeVertexFmt != &m_NativeFmt) if (g_nativeVertexFmt != NULL && g_nativeVertexFmt != &m_NativeFmt)
{ {
VertexManager::Flush(); VertexManager::Flush();
@ -527,9 +488,6 @@ void VertexLoader::RunVertices(int primitive, int count)
} }
g_nativeVertexFmt = &m_NativeFmt; g_nativeVertexFmt = &m_NativeFmt;
// This has dirty handling - won't actually recompute unless necessary.
ComputeVertexSize();
if (bpmem.genMode.cullmode == 3 && primitive < 5) if (bpmem.genMode.cullmode == 3 && primitive < 5)
{ {
// if cull mode is none, ignore triangles and quads // if cull mode is none, ignore triangles and quads
@ -537,13 +495,21 @@ void VertexLoader::RunVertices(int primitive, int count)
return; return;
} }
// This has dirty handling - won't actually recompute unless necessary.
CompileVertexTranslator();
VertexManager::EnableComponents(m_NativeFmt.m_components); VertexManager::EnableComponents(m_NativeFmt.m_components);
// Load position and texcoord scale factors. // Load position and texcoord scale factors.
// Hm, this could be done when the VtxAttr is set, instead. // TODO - figure out if we should leave these independent, or compile them into
// the vertexloaders.
m_VtxAttr.PosFrac = g_VtxAttr[vtx_attr_group].g0.PosFrac;
m_VtxAttr.texCoord[0].Frac = g_VtxAttr[vtx_attr_group].g0.Tex0Frac;
m_VtxAttr.texCoord[1].Frac = g_VtxAttr[vtx_attr_group].g1.Tex1Frac;
m_VtxAttr.texCoord[2].Frac = g_VtxAttr[vtx_attr_group].g1.Tex2Frac;
m_VtxAttr.texCoord[3].Frac = g_VtxAttr[vtx_attr_group].g1.Tex3Frac;
m_VtxAttr.texCoord[4].Frac = g_VtxAttr[vtx_attr_group].g2.Tex4Frac;
m_VtxAttr.texCoord[5].Frac = g_VtxAttr[vtx_attr_group].g2.Tex5Frac;
m_VtxAttr.texCoord[6].Frac = g_VtxAttr[vtx_attr_group].g2.Tex6Frac;
m_VtxAttr.texCoord[7].Frac = g_VtxAttr[vtx_attr_group].g2.Tex7Frac;
posScale = shiftLookup[m_VtxAttr.PosFrac]; posScale = shiftLookup[m_VtxAttr.PosFrac];
if (m_NativeFmt.m_components & VB_HAS_UVALL) { if (m_NativeFmt.m_components & VB_HAS_UVALL) {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
@ -559,11 +525,11 @@ void VertexLoader::RunVertices(int primitive, int count)
switch (primitive) { switch (primitive) {
case 3: // strip case 3: // strip
case 4: // fan case 4: // fan
if (VertexManager::GetRemainingSize() < 3 * m_NativeFmt.m_VBVertexStride ) if (VertexManager::GetRemainingSize() < 3 * m_NativeFmt.m_VBVertexStride)
VertexManager::Flush(); VertexManager::Flush();
break; break;
case 6: // line strip case 6: // line strip
if (VertexManager::GetRemainingSize() < 2 * m_NativeFmt.m_VBVertexStride ) if (VertexManager::GetRemainingSize() < 2 * m_NativeFmt.m_VBVertexStride)
VertexManager::Flush(); VertexManager::Flush();
break; break;
case 0: // quads case 0: // quads
@ -627,7 +593,8 @@ void VertexLoader::RunVertices(int primitive, int count)
colIndex = 0; colIndex = 0;
s_texmtxwrite = s_texmtxread = 0; s_texmtxwrite = s_texmtxread = 0;
RunPipelineOnce(); for (int i = 0; i < m_numPipelineStages; i++)
m_PipelineStages[i](&m_VtxAttr);
VertexManager::s_pCurBufferPointer += m_NativeFmt.m_VBStridePad; VertexManager::s_pCurBufferPointer += m_NativeFmt.m_VBStridePad;
PRIM_LOG("\n"); PRIM_LOG("\n");
@ -637,71 +604,48 @@ void VertexLoader::RunVertices(int primitive, int count)
VertexManager::AddVertices(primitive, count - startv + extraverts); VertexManager::AddVertices(primitive, count - startv + extraverts);
} }
void VertexLoader::RunPipelineOnce() const void VertexLoader::SetVAT(u32 _group0, u32 _group1, u32 _group2)
{ {
for (int i = 0; i < m_numPipelineStages; i++) VAT vat;
m_PipelineStages[i](&m_VtxAttr); vat.g0.Hex = _group0;
} vat.g1.Hex = _group1;
vat.g2.Hex = _group2;
void VertexLoader::SetVAT_group0(u32 _group0) m_VtxAttr.PosElements = vat.g0.PosElements;
{ m_VtxAttr.PosFormat = vat.g0.PosFormat;
// ignore frac bits - we don't need to recompute if all that's changed was the frac bits. m_VtxAttr.PosFrac = vat.g0.PosFrac;
if ((m_group0.Hex & ~VAT_0_FRACBITS) != (_group0 & ~VAT_0_FRACBITS)) { m_VtxAttr.NormalElements = vat.g0.NormalElements;
m_AttrDirty = AD_VAT_DIRTY; m_VtxAttr.NormalFormat = vat.g0.NormalFormat;
} m_VtxAttr.color[0].Elements = vat.g0.Color0Elements;
m_group0.Hex = _group0; m_VtxAttr.color[0].Comp = vat.g0.Color0Comp;
m_VtxAttr.color[1].Elements = vat.g0.Color1Elements;
m_VtxAttr.color[1].Comp = vat.g0.Color1Comp;
m_VtxAttr.texCoord[0].Elements = vat.g0.Tex0CoordElements;
m_VtxAttr.texCoord[0].Format = vat.g0.Tex0CoordFormat;
m_VtxAttr.texCoord[0].Frac = vat.g0.Tex0Frac;
m_VtxAttr.ByteDequant = vat.g0.ByteDequant;
m_VtxAttr.NormalIndex3 = vat.g0.NormalIndex3;
m_VtxAttr.PosElements = m_group0.PosElements; m_VtxAttr.texCoord[1].Elements = vat.g1.Tex1CoordElements;
m_VtxAttr.PosFormat = m_group0.PosFormat; m_VtxAttr.texCoord[1].Format = vat.g1.Tex1CoordFormat;
m_VtxAttr.PosFrac = m_group0.PosFrac; m_VtxAttr.texCoord[1].Frac = vat.g1.Tex1Frac;
m_VtxAttr.NormalElements = m_group0.NormalElements; m_VtxAttr.texCoord[2].Elements = vat.g1.Tex2CoordElements;
m_VtxAttr.NormalFormat = m_group0.NormalFormat; m_VtxAttr.texCoord[2].Format = vat.g1.Tex2CoordFormat;
m_VtxAttr.color[0].Elements = m_group0.Color0Elements; m_VtxAttr.texCoord[2].Frac = vat.g1.Tex2Frac;
m_VtxAttr.color[0].Comp = m_group0.Color0Comp; m_VtxAttr.texCoord[3].Elements = vat.g1.Tex3CoordElements;
m_VtxAttr.color[1].Elements = m_group0.Color1Elements; m_VtxAttr.texCoord[3].Format = vat.g1.Tex3CoordFormat;
m_VtxAttr.color[1].Comp = m_group0.Color1Comp; m_VtxAttr.texCoord[3].Frac = vat.g1.Tex3Frac;
m_VtxAttr.texCoord[0].Elements = m_group0.Tex0CoordElements; m_VtxAttr.texCoord[4].Elements = vat.g1.Tex4CoordElements;
m_VtxAttr.texCoord[0].Format = m_group0.Tex0CoordFormat; m_VtxAttr.texCoord[4].Format = vat.g1.Tex4CoordFormat;
m_VtxAttr.texCoord[0].Frac = m_group0.Tex0Frac;
m_VtxAttr.ByteDequant = m_group0.ByteDequant; m_VtxAttr.texCoord[4].Frac = vat.g2.Tex4Frac;
m_VtxAttr.NormalIndex3 = m_group0.NormalIndex3; m_VtxAttr.texCoord[5].Elements = vat.g2.Tex5CoordElements;
}; m_VtxAttr.texCoord[5].Format = vat.g2.Tex5CoordFormat;
m_VtxAttr.texCoord[5].Frac = vat.g2.Tex5Frac;
void VertexLoader::SetVAT_group1(u32 _group1) m_VtxAttr.texCoord[6].Elements = vat.g2.Tex6CoordElements;
{ m_VtxAttr.texCoord[6].Format = vat.g2.Tex6CoordFormat;
if ((m_group1.Hex & ~VAT_1_FRACBITS) != (_group1 & ~VAT_1_FRACBITS)) { m_VtxAttr.texCoord[6].Frac = vat.g2.Tex6Frac;
m_AttrDirty = AD_VAT_DIRTY; m_VtxAttr.texCoord[7].Elements = vat.g2.Tex7CoordElements;
} m_VtxAttr.texCoord[7].Format = vat.g2.Tex7CoordFormat;
m_group1.Hex = _group1; m_VtxAttr.texCoord[7].Frac = vat.g2.Tex7Frac;
m_VtxAttr.texCoord[1].Elements = m_group1.Tex1CoordElements;
m_VtxAttr.texCoord[1].Format = m_group1.Tex1CoordFormat;
m_VtxAttr.texCoord[1].Frac = m_group1.Tex1Frac;
m_VtxAttr.texCoord[2].Elements = m_group1.Tex2CoordElements;
m_VtxAttr.texCoord[2].Format = m_group1.Tex2CoordFormat;
m_VtxAttr.texCoord[2].Frac = m_group1.Tex2Frac;
m_VtxAttr.texCoord[3].Elements = m_group1.Tex3CoordElements;
m_VtxAttr.texCoord[3].Format = m_group1.Tex3CoordFormat;
m_VtxAttr.texCoord[3].Frac = m_group1.Tex3Frac;
m_VtxAttr.texCoord[4].Elements = m_group1.Tex4CoordElements;
m_VtxAttr.texCoord[4].Format = m_group1.Tex4CoordFormat;
};
void VertexLoader::SetVAT_group2(u32 _group2)
{
if ((m_group2.Hex & ~VAT_2_FRACBITS) != (_group2 & ~VAT_2_FRACBITS)) {
m_AttrDirty = AD_VAT_DIRTY;
}
m_group2.Hex = _group2;
m_VtxAttr.texCoord[4].Frac = m_group2.Tex4Frac;
m_VtxAttr.texCoord[5].Elements = m_group2.Tex5CoordElements;
m_VtxAttr.texCoord[5].Format = m_group2.Tex5CoordFormat;
m_VtxAttr.texCoord[5].Frac = m_group2.Tex5Frac;
m_VtxAttr.texCoord[6].Elements = m_group2.Tex6CoordElements;
m_VtxAttr.texCoord[6].Format = m_group2.Tex6CoordFormat;
m_VtxAttr.texCoord[6].Frac = m_group2.Tex6Frac;
m_VtxAttr.texCoord[7].Elements = m_group2.Tex7CoordElements;
m_VtxAttr.texCoord[7].Format = m_group2.Tex7CoordFormat;
m_VtxAttr.texCoord[7].Frac = m_group2.Tex7Frac;
}; };

View File

@ -23,66 +23,72 @@
#include "NativeVertexFormat.h" #include "NativeVertexFormat.h"
class VertexLoaderUID
{
u32 id[5];
public:
VertexLoaderUID() {}
void InitFromCurrentState(int vtx_attr_group) {
id[0] = g_VtxDesc.Hex & 0xFFFFFFFF;
id[1] = g_VtxDesc.Hex >> 32;
id[2] = g_VtxAttr[vtx_attr_group].g0.Hex & ~VAT_0_FRACBITS;
id[3] = g_VtxAttr[vtx_attr_group].g1.Hex & ~VAT_1_FRACBITS;
id[4] = g_VtxAttr[vtx_attr_group].g2.Hex & ~VAT_2_FRACBITS;
}
bool operator < (const VertexLoaderUID &other) const {
if (id[0] < other.id[0])
return true;
else if (id[0] > other.id[0])
return false;
for (int i = 1; i < 5; ++i) {
if (id[i] < other.id[i])
return true;
else if (id[i] > other.id[i])
return false;
}
return false;
}
};
class VertexLoader class VertexLoader
{ {
public: public:
VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr);
~VertexLoader();
int GetVertexSize() const {return m_VertexSize;}
void RunVertices(int vtx_attr_group, int primitive, int count);
private:
enum enum
{ {
NRM_ZERO = 0, NRM_ZERO = 0,
NRM_ONE = 1, NRM_ONE = 1,
NRM_THREE = 3 NRM_THREE = 3,
}; };
private:
// The 3 possible values (0, 1, 2) should be documented here.
enum {
AD_CLEAN = 0,
AD_DIRTY = 1,
AD_VAT_DIRTY = 2,
} m_AttrDirty;
int m_VertexSize; // number of bytes of a raw GC vertex int m_VertexSize; // number of bytes of a raw GC vertex
// Flipper vertex format // GC vertex format
TVtxAttr m_VtxAttr; // VAT decoded into easy format
TVtxDesc m_VtxDesc; // Not really used currently - or well it is, but could be easily avoided.
// Raw VAttr // PC vertex format
UVAT_group0 m_group0;
UVAT_group1 m_group1;
UVAT_group2 m_group2;
TVtxAttr m_VtxAttr; // Decoded into easy format
// Vtx desc
TVtxDesc m_VtxDesc;
// PC vertex format, + converter
NativeVertexFormat m_NativeFmt; NativeVertexFormat m_NativeFmt;
// Pipeline. To be JIT compiled in the future. // Pipeline. To be JIT compiled in the future.
TPipelineFunction m_PipelineStages[32]; TPipelineFunction m_PipelineStages[32]; // TODO - figure out real max. it's lower.
int m_numPipelineStages; int m_numPipelineStages;
void SetupColor(int num, int _iMode, int _iFormat, int _iElements); void SetupColor(int num, int _iMode, int _iFormat, int _iElements);
void SetupTexCoord(int num, int _iMode, int _iFormat, int _iElements, int _iFrac); void SetupTexCoord(int num, int _iMode, int _iFormat, int _iElements, int _iFrac);
void RunPipelineOnce() const;
public: void SetVAT(u32 _group0, u32 _group1, u32 _group2);
// constructor
VertexLoader();
~VertexLoader();
// run the pipeline
void CompileVertexTranslator();
void RunVertices(int primitive, int count);
void WriteCall(TPipelineFunction);
int GetGCVertexSize() const { _assert_( !m_AttrDirty ); return m_VertexSize; }
int GetVBVertexStride() const { _assert_( !m_AttrDirty); return m_NativeFmt.m_VBVertexStride; }
int ComputeVertexSize(); int ComputeVertexSize();
void CompileVertexTranslator();
void SetVAT_group0(u32 _group0); void WriteCall(TPipelineFunction);
void SetVAT_group1(u32 _group1);
void SetVAT_group2(u32 _group2);
}; };
#endif #endif

View File

@ -15,43 +15,78 @@
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#include <map>
#include "Statistics.h"
#include "VertexShaderManager.h" #include "VertexShaderManager.h"
#include "VertexLoader.h" #include "VertexLoader.h"
#include "VertexLoaderManager.h" #include "VertexLoaderManager.h"
static bool s_desc_dirty; static int s_attr_dirty; // bitfield
static bool s_attr_dirty[8];
// TODO - change into array of pointers. Keep a map of all seen so far. static VertexLoader *g_VertexLoaders[8];
static VertexLoader g_VertexLoaders[8];
namespace VertexLoaderManager namespace VertexLoaderManager
{ {
typedef std::map<VertexLoaderUID, VertexLoader *> VertexLoaderMap;
static VertexLoaderMap g_VertexLoaderMap;
// TODO - change into array of pointers. Keep a map of all seen so far.
void Init() void Init()
{ {
s_desc_dirty = false; MarkAllDirty();
for (int i = 0; i < 8; i++)
s_attr_dirty[i] = false;
} }
void Shutdown() void Shutdown()
{ {
for (VertexLoaderMap::iterator iter = g_VertexLoaderMap.begin(); iter != g_VertexLoaderMap.end(); ++iter)
{
delete iter->second;
}
g_VertexLoaderMap.clear();
}
void MarkAllDirty()
{
s_attr_dirty = 0xff;
}
void RefreshLoader(int vtx_attr_group)
{
if (((s_attr_dirty >> vtx_attr_group) & 1) || !g_VertexLoaders[vtx_attr_group])
{
VertexLoaderUID uid;
uid.InitFromCurrentState(vtx_attr_group);
VertexLoaderMap::iterator iter = g_VertexLoaderMap.find(uid);
if (iter != g_VertexLoaderMap.end())
{
g_VertexLoaders[vtx_attr_group] = iter->second;
}
else
{
VertexLoader *loader = new VertexLoader(g_VtxDesc, g_VtxAttr[vtx_attr_group]);
g_VertexLoaderMap[uid] = loader;
g_VertexLoaders[vtx_attr_group] = loader;
INCSTAT(stats.numVertexLoaders);
}
}
s_attr_dirty &= ~(1 << vtx_attr_group);
} }
void RunVertices(int vtx_attr_group, int primitive, int count) void RunVertices(int vtx_attr_group, int primitive, int count)
{ {
if (!count) if (!count)
return; return;
// TODO - grab & load the correct vertex loader if anything is dirty. RefreshLoader(vtx_attr_group);
g_VertexLoaders[vtx_attr_group].RunVertices(primitive, count); g_VertexLoaders[vtx_attr_group]->RunVertices(vtx_attr_group, primitive, count);
} }
int GetVertexSize(int vtx_attr_group) int GetVertexSize(int vtx_attr_group)
{ {
// The vertex loaders will soon cache the vertex size. RefreshLoader(vtx_attr_group);
return g_VertexLoaders[vtx_attr_group].ComputeVertexSize(); return g_VertexLoaders[vtx_attr_group]->GetVertexSize();
} }
} // namespace } // namespace
@ -71,34 +106,31 @@ void LoadCPReg(u32 sub_cmd, u32 value)
case 0x50: case 0x50:
g_VtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits g_VtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits
g_VtxDesc.Hex |= value; g_VtxDesc.Hex |= value;
s_desc_dirty = true; s_attr_dirty = 0xFF;
break; break;
case 0x60: case 0x60:
g_VtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits g_VtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits
g_VtxDesc.Hex |= (u64)value << 17; g_VtxDesc.Hex |= (u64)value << 17;
s_desc_dirty = true; s_attr_dirty = 0xFF;
break; break;
case 0x70: case 0x70:
_assert_((sub_cmd & 0x0F) < 8); _assert_((sub_cmd & 0x0F) < 8);
g_VtxAttr[sub_cmd & 7].g0.Hex = value; g_VtxAttr[sub_cmd & 7].g0.Hex = value;
g_VertexLoaders[sub_cmd & 7].SetVAT_group0(value); s_attr_dirty |= 1 << (sub_cmd & 7);
s_attr_dirty[sub_cmd & 7] = true;
break; break;
case 0x80: case 0x80:
_assert_((sub_cmd & 0x0F) < 8); _assert_((sub_cmd & 0x0F) < 8);
g_VtxAttr[sub_cmd & 7].g1.Hex = value; g_VtxAttr[sub_cmd & 7].g1.Hex = value;
g_VertexLoaders[sub_cmd & 7].SetVAT_group1(value); s_attr_dirty |= 1 << (sub_cmd & 7);
s_attr_dirty[sub_cmd & 7] = true;
break; break;
case 0x90: case 0x90:
_assert_((sub_cmd & 0x0F) < 8); _assert_((sub_cmd & 0x0F) < 8);
g_VtxAttr[sub_cmd & 7].g2.Hex = value; g_VtxAttr[sub_cmd & 7].g2.Hex = value;
g_VertexLoaders[sub_cmd & 7].SetVAT_group2(value); s_attr_dirty |= 1 << (sub_cmd & 7);
s_attr_dirty[sub_cmd & 7] = true;
break; break;
// Pointers to vertex arrays in GC RAM // Pointers to vertex arrays in GC RAM

View File

@ -25,6 +25,8 @@ namespace VertexLoaderManager
void Init(); void Init();
void Shutdown(); void Shutdown();
void MarkAllDirty();
int GetVertexSize(int vtx_attr_group); int GetVertexSize(int vtx_attr_group);
void RunVertices(int vtx_attr_group, int primitive, int count); void RunVertices(int vtx_attr_group, int primitive, int count);

View File

@ -104,7 +104,7 @@ VERTEXSHADER* VertexShaderMngr::GetShader(u32 components)
VSCache::iterator iter = vshaders.find(uid); VSCache::iterator iter = vshaders.find(uid);
if (iter != vshaders.end()) { if (iter != vshaders.end()) {
iter->second.frameCount=frameCount; iter->second.frameCount = frameCount;
VSCacheEntry &entry = iter->second; VSCacheEntry &entry = iter->second;
if (&entry.shader != pShaderLast) { if (&entry.shader != pShaderLast) {
pShaderLast = &entry.shader; pShaderLast = &entry.shader;

View File

@ -116,7 +116,7 @@ void DllConfig(HWND _hParent)
resFound = (resos[b] == strBuffer); resFound = (resos[b] == strBuffer);
b++; b++;
} }
if(!resFound) if (!resFound)
//and add the res //and add the res
{ {
resos[i] = strBuffer; resos[i] = strBuffer;
@ -196,8 +196,11 @@ void Video_Initialize(SVideoInitialize* _pVideoInitialize)
void Video_DoState(unsigned char **ptr, int mode) { void Video_DoState(unsigned char **ptr, int mode) {
// Clear all caches // Clear all caches that touch RAM
TextureMngr::Invalidate(); TextureMngr::Invalidate();
// DisplayListManager::Invalidate();
VertexLoaderManager::MarkAllDirty();
PointerWrap p(ptr, mode); PointerWrap p(ptr, mode);
VideoCommon_DoState(p); VideoCommon_DoState(p);