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:
parent
681a40dd36
commit
f77624147d
|
@ -39,6 +39,8 @@ struct Statistics
|
||||||
|
|
||||||
int numJoins;
|
int numJoins;
|
||||||
|
|
||||||
|
int numVertexLoaders;
|
||||||
|
|
||||||
struct ThisFrame
|
struct ThisFrame
|
||||||
{
|
{
|
||||||
int numBPLoads;
|
int numBPLoads;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,7 +242,6 @@ 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)) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -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++) {
|
||||||
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue