summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon
diff options
context:
space:
mode:
authorRodolfo Osvaldo Bogado <rodolfoosvaldobogado@gmail.com>2010-08-29 23:08:56 +0000
committerRodolfo Osvaldo Bogado <rodolfoosvaldobogado@gmail.com>2010-08-29 23:08:56 +0000
commit3e7dafbbd7708f574059bc4722c260b4f6edd6cb (patch)
tree84730fc53fdd895cf7f8fad7833f177f5272aef7 /Source/Core/VideoCommon
parent4229d9e01ec062714f9c784930ba60d0f0967456 (diff)
fully implemented display list cache with vertex data included and added in all the plugins.
still experimental, not totally optimized but must bring a nice speed up please test for regressions an error. an please Linux people fix scons :) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6149 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source/Core/VideoCommon')
-rw-r--r--Source/Core/VideoCommon/Src/DLCache.cpp598
-rw-r--r--Source/Core/VideoCommon/Src/DLCache.h32
-rw-r--r--Source/Core/VideoCommon/Src/NativeVertexWriter.h1
-rw-r--r--Source/Core/VideoCommon/Src/VertexLoader.cpp57
-rw-r--r--Source/Core/VideoCommon/Src/VertexLoader.h1
-rw-r--r--Source/Core/VideoCommon/Src/VertexLoaderManager.cpp8
-rw-r--r--Source/Core/VideoCommon/Src/VertexLoaderManager.h1
-rw-r--r--Source/Core/VideoCommon/VideoCommon.vcproj10
8 files changed, 707 insertions, 1 deletions
diff --git a/Source/Core/VideoCommon/Src/DLCache.cpp b/Source/Core/VideoCommon/Src/DLCache.cpp
new file mode 100644
index 0000000000..f542952c85
--- /dev/null
+++ b/Source/Core/VideoCommon/Src/DLCache.cpp
@@ -0,0 +1,598 @@
+// Copyright (C) 2003-2009 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/
+
+// TODO: Handle cache-is-full condition :p
+
+#include <map>
+
+#include "Common.h"
+#include "VideoCommon.h"
+#include "Hash.h"
+#include "MemoryUtil.h"
+#include "DataReader.h"
+#include "Statistics.h"
+#include "OpcodeDecoding.h" // For the GX_ constants.
+
+#include "XFMemory.h"
+#include "CPMemory.h"
+#include "BPMemory.h"
+
+#include "VertexLoaderManager.h"
+#include "NativeVertexWriter.h"
+#include "x64Emitter.h"
+#include "ABI.h"
+
+#include "DLCache.h"
+
+#define DL_CODE_CACHE_SIZE (1024*1024*16)
+extern int frameCount;
+
+using namespace Gen;
+
+namespace DLCache
+{
+
+// Currently just recompiles the DLs themselves, doesn't bother with the vertex data.
+// The speed boost is pretty small. The real big boost will come when we also store
+// vertex arrays in the cached DLs.
+
+enum DisplayListPass {
+ DLPASS_ANALYZE,
+ DLPASS_COMPILE,
+ DLPASS_RUN,
+};
+
+struct VDataHashRegion
+{
+ u32 hash;
+ u32 start_address;
+ int size;
+};
+typedef u8* DataPointer;
+typedef std::map<u8, DataPointer> VdataMap;
+
+struct CachedDisplayList
+{
+ CachedDisplayList()
+ : uncachable(false),
+ pass(DLPASS_ANALYZE),
+ next_check(1),
+ BufferCount(0),
+ num_xf_reg(0),
+ num_cp_reg(0),
+ num_bp_reg(0),
+ num_index_xf(0),
+ num_draw_call(0)
+ {
+ frame_count = frameCount;
+ }
+
+ bool uncachable; // if set, this DL will always be interpreted. This gets set if hash ever changes.
+
+ int pass;
+ u64 dl_hash;
+
+ int check;
+ int next_check;
+
+ int frame_count;
+
+ // ... Something containing cached vertex buffers here ...
+ u8 BufferCount;
+ VdataMap Vdata;
+
+ int num_xf_reg;
+ int num_cp_reg;
+ int num_bp_reg;
+ int num_index_xf;
+ int num_draw_call;
+
+ // Compile the commands themselves down to native code.
+ const u8* compiled_code;
+};
+
+// We want to allow caching DLs that start at the same address but have different lengths,
+// so the size has to be in the ID.
+inline u64 CreateMapId(u32 address, u32 size)
+{
+ return ((u64)address << 32) | size;
+}
+
+typedef std::map<u64, CachedDisplayList> DLMap;
+
+static DLMap dl_map;
+static DataPointer dlcode_cache;
+
+static Gen::XEmitter emitter;
+
+// First pass - analyze
+bool AnalyzeAndRunDisplayList(u32 address, int size, CachedDisplayList *dl)
+{
+ int num_xf_reg = 0;
+ int num_cp_reg = 0;
+ int num_bp_reg = 0;
+ int num_index_xf = 0;
+ int num_draw_call = 0;
+
+ u8* old_pVideoData = g_pVideoData;
+ u8* startAddress = Memory_GetPtr(address);
+
+ // Avoid the crash if Memory_GetPtr failed ..
+ if (startAddress != 0)
+ {
+ g_pVideoData = startAddress;
+
+ // temporarily swap dl and non-dl (small "hack" for the stats)
+ Statistics::SwapDL();
+
+ u8 *end = g_pVideoData + size;
+ while (g_pVideoData < end)
+ {
+ // Yet another reimplementation of the DL reading...
+ int cmd_byte = DataReadU8();
+ switch (cmd_byte)
+ {
+ case GX_NOP:
+ break;
+
+ case GX_LOAD_CP_REG: //0x08
+ {
+ u8 sub_cmd = DataReadU8();
+ u32 value = DataReadU32();
+ LoadCPReg(sub_cmd, value);
+ INCSTAT(stats.thisFrame.numCPLoads);
+ num_cp_reg++;
+ }
+ break;
+
+ case GX_LOAD_XF_REG:
+ {
+ u32 Cmd2 = DataReadU32();
+ int transfer_size = ((Cmd2 >> 16) & 15) + 1;
+ u32 xf_address = Cmd2 & 0xFFFF;
+ // TODO - speed this up. pshufb?
+ u32 data_buffer[16];
+ for (int i = 0; i < transfer_size; i++)
+ data_buffer[i] = DataReadU32();
+ LoadXFReg(transfer_size, xf_address, data_buffer);
+ INCSTAT(stats.thisFrame.numXFLoads);
+ num_xf_reg++;
+ }
+ break;
+
+ case GX_LOAD_INDX_A: //used for position matrices
+ {
+ LoadIndexedXF(DataReadU32(), 0xC);
+ num_index_xf++;
+ }
+ break;
+ case GX_LOAD_INDX_B: //used for normal matrices
+ {
+ LoadIndexedXF(DataReadU32(), 0xD);
+ num_index_xf++;
+ }
+ break;
+ case GX_LOAD_INDX_C: //used for postmatrices
+ {
+ LoadIndexedXF(DataReadU32(), 0xE);
+ num_index_xf++;
+ }
+ break;
+ case GX_LOAD_INDX_D: //used for lights
+ {
+ LoadIndexedXF(DataReadU32(), 0xF);
+ num_index_xf++;
+ }
+ break;
+ case GX_CMD_CALL_DL:
+ {
+ u32 addr = DataReadU32();
+ u32 count = DataReadU32();
+ ExecuteDisplayList(addr, count);
+ }
+ break;
+ case GX_CMD_UNKNOWN_METRICS: // zelda 4 swords calls it and checks the metrics registers after that
+ DEBUG_LOG(VIDEO, "GX 0x44: %08x", cmd_byte);
+ break;
+ case GX_CMD_INVL_VC: // Invalidate Vertex Cache
+ DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
+ break;
+ case GX_LOAD_BP_REG: //0x61
+ {
+ u32 bp_cmd = DataReadU32();
+ LoadBPReg(bp_cmd);
+ INCSTAT(stats.thisFrame.numBPLoads);
+ num_bp_reg++;
+ }
+ break;
+
+ // draw primitives
+ default:
+ if (cmd_byte & 0x80)
+ {
+ // load vertices (use computed vertex size from FifoCommandRunnable above)
+ u16 numVertices = DataReadU16();
+
+ VertexLoaderManager::RunVertices(
+ cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7)
+ (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT,
+ numVertices);
+ num_draw_call++;
+ }
+ else
+ {
+ ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte);
+ break;
+ }
+ break;
+ }
+ }
+ INCSTAT(stats.numDListsCalled);
+ INCSTAT(stats.thisFrame.numDListsCalled);
+ // un-swap
+ Statistics::SwapDL();
+ }
+ dl->num_bp_reg = num_bp_reg;
+ dl->num_cp_reg = num_cp_reg;
+ dl->num_draw_call = num_draw_call;
+ dl->num_index_xf = num_index_xf;
+ dl->num_xf_reg = num_xf_reg;
+ // reset to the old pointer
+ g_pVideoData = old_pVideoData;
+ return true;
+}
+
+// The only sensible way to detect changes to vertex data is to convert several times
+// and hash the output.
+
+// Second pass - compile
+// Since some commands can affect the size of other commands, we really have no choice
+// but to compile as we go, interpreting the list. We can't compile and then execute, we must
+// compile AND execute at the same time. The second time the display list gets called, we already
+// have the compiled code so we don't have to interpret anymore, we just run it.
+bool CompileAndRunDisplayList(u32 address, int size, CachedDisplayList *dl)
+{
+ u8* old_pVideoData = g_pVideoData;
+ u8* startAddress = Memory_GetPtr(address);
+
+ // Avoid the crash if Memory_GetPtr failed ..
+ if (startAddress != 0)
+ {
+ g_pVideoData = startAddress;
+
+ // temporarily swap dl and non-dl (small "hack" for the stats)
+ Statistics::SwapDL();
+
+ u8 *end = g_pVideoData + size;
+
+ emitter.AlignCode4();
+ dl->compiled_code = emitter.GetCodePtr();
+ emitter.ABI_EmitPrologue(4);
+
+ while (g_pVideoData < end)
+ {
+ // Yet another reimplementation of the DL reading...
+ int cmd_byte = DataReadU8();
+ switch (cmd_byte)
+ {
+ case GX_NOP:
+ // Execute
+ // Compile
+ break;
+
+ case GX_LOAD_CP_REG: //0x08
+ {
+ // Execute
+ u8 sub_cmd = DataReadU8();
+ u32 value = DataReadU32();
+ LoadCPReg(sub_cmd, value);
+ INCSTAT(stats.thisFrame.numCPLoads);
+
+ // Compile
+ emitter.ABI_CallFunctionCC((void *)&LoadCPReg, sub_cmd, value);
+ }
+ break;
+
+ case GX_LOAD_XF_REG:
+ {
+ // Execute
+ u32 Cmd2 = DataReadU32();
+ int transfer_size = ((Cmd2 >> 16) & 15) + 1;
+ u32 xf_address = Cmd2 & 0xFFFF;
+ // TODO - speed this up. pshufb?
+ DataPointer real_data_buffer = (DataPointer) new u8[transfer_size * 4];
+ u32 *data_buffer = (u32*)real_data_buffer;
+ for (int i = 0; i < transfer_size; i++)
+ data_buffer[i] = DataReadU32();
+ LoadXFReg(transfer_size, xf_address, data_buffer);
+ INCSTAT(stats.thisFrame.numXFLoads);
+ dl->Vdata[dl->BufferCount] = real_data_buffer;
+ dl->BufferCount++;
+ // Compile
+ emitter.ABI_CallFunctionCCP((void *)&LoadXFReg, transfer_size, xf_address, data_buffer);
+ }
+ break;
+
+ case GX_LOAD_INDX_A: //used for position matrices
+ {
+ u32 value = DataReadU32();
+ // Execute
+ LoadIndexedXF(value, 0xC);
+ // Compile
+ emitter.ABI_CallFunctionCC((void *)&LoadIndexedXF, value, 0xC);
+ }
+ break;
+ case GX_LOAD_INDX_B: //used for normal matrices
+ {
+ u32 value = DataReadU32();
+ // Execute
+ LoadIndexedXF(value, 0xD);
+ // Compile
+ emitter.ABI_CallFunctionCC((void *)&LoadIndexedXF, value, 0xD);
+ }
+ break;
+ case GX_LOAD_INDX_C: //used for postmatrices
+ {
+ u32 value = DataReadU32();
+ // Execute
+ LoadIndexedXF(value, 0xE);
+ // Compile
+ emitter.ABI_CallFunctionCC((void *)&LoadIndexedXF, value, 0xE);
+ }
+ break;
+ case GX_LOAD_INDX_D: //used for lights
+ {
+ u32 value = DataReadU32();
+ // Execute
+ LoadIndexedXF(value, 0xF);
+ // Compile
+ emitter.ABI_CallFunctionCC((void *)&LoadIndexedXF, value, 0xF);
+ }
+ break;
+
+ case GX_CMD_CALL_DL:
+ {
+ u32 addr= DataReadU32();
+ u32 count = DataReadU32();
+ ExecuteDisplayList(addr, count);
+ emitter.ABI_CallFunctionCC((void *)&ExecuteDisplayList, address, count);
+ }
+ break;
+
+ case GX_CMD_UNKNOWN_METRICS:
+ // zelda 4 swords calls it and checks the metrics registers after that
+ break;
+
+ case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
+ DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
+ break;
+
+ case GX_LOAD_BP_REG: //0x61
+ {
+ u32 bp_cmd = DataReadU32();
+ // Execute
+ LoadBPReg(bp_cmd);
+ INCSTAT(stats.thisFrame.numBPLoads);
+ // Compile
+ emitter.ABI_CallFunctionC((void *)&LoadBPReg, bp_cmd);
+ }
+ break;
+
+ // draw primitives
+ default:
+ if (cmd_byte & 0x80)
+ {
+ // load vertices (use computed vertex size from FifoCommandRunnable above)
+
+ // Execute
+ u16 numVertices = DataReadU16();
+
+ u64 pre_draw_video_data = (u64)g_pVideoData;
+
+ u8* StartAddress = VertexManager::s_pBaseBufferPointer;
+ VertexManager::Flush();
+ VertexLoaderManager::RunVertices(
+ cmd_byte & GX_VAT_MASK, // Vertex loader index (0 - 7)
+ (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT,
+ numVertices);
+ u8* EndAddress = VertexManager::s_pCurBufferPointer;
+ u32 Vdatasize = (u32)(EndAddress - StartAddress);
+ if (size > 0)
+ {
+ // Compile
+ DataPointer NewData = (DataPointer)new u8[Vdatasize];
+ memcpy(NewData,StartAddress,Vdatasize);
+ dl->Vdata[dl->BufferCount] = NewData;
+ dl->BufferCount++;
+ emitter.ABI_CallFunctionCCCP((void *)&VertexLoaderManager::RunCompiledVertices,cmd_byte & GX_VAT_MASK, (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices, NewData);
+ }
+ }
+ else
+ {
+ ERROR_LOG(VIDEO, "DLCache::CompileAndRun: Illegal command %02x", cmd_byte);
+ break;
+ }
+ break;
+ }
+ }
+ emitter.ABI_EmitEpilogue(4);
+ INCSTAT(stats.numDListsCalled);
+ INCSTAT(stats.thisFrame.numDListsCalled);
+ Statistics::SwapDL();
+ }
+ g_pVideoData = old_pVideoData;
+ return true;
+}
+
+void Init()
+{
+ dlcode_cache = (DataPointer)AllocateExecutableMemory(DL_CODE_CACHE_SIZE, false); // Don't need low memory.
+ emitter.SetCodePtr(dlcode_cache);
+}
+
+void Shutdown()
+{
+ Clear();
+ FreeMemoryPages(dlcode_cache, DL_CODE_CACHE_SIZE);
+ dlcode_cache = NULL;
+}
+
+void Clear()
+{
+ DLMap::iterator iter = dl_map.begin();
+ while (iter != dl_map.end()) {
+ CachedDisplayList &entry = iter->second;
+ VdataMap::iterator viter = entry.Vdata.begin();
+ while (viter != entry.Vdata.end())
+ {
+ DataPointer &ventry = viter->second;
+ delete [] ventry;
+ entry.Vdata.erase(viter++);
+ }
+ iter++;
+ }
+ dl_map.clear();
+ // Reset the cache pointers.
+ emitter.SetCodePtr(dlcode_cache);
+}
+
+void ProgressiveCleanup()
+{
+ DLMap::iterator iter = dl_map.begin();
+ while (iter != dl_map.end()) {
+ CachedDisplayList &entry = iter->second;
+ int limit = iter->second.uncachable ? 1200 : 400;
+ if (entry.frame_count < frameCount - limit) {
+ // entry.Destroy();
+ VdataMap::iterator viter = entry.Vdata.begin();
+ while (viter != entry.Vdata.end())
+ {
+ DataPointer &ventry = viter->second;
+ delete [] ventry;
+ entry.Vdata.erase(viter++);
+ }
+ dl_map.erase(iter++); // (this is gcc standard!)
+ }
+ else
+ ++iter;
+ }
+}
+
+} // namespace
+
+// NOTE - outside the namespace on purpose.
+bool HandleDisplayList(u32 address, u32 size)
+{
+ // Disable display list caching since the benefit isn't much to write home about
+ // right now...
+ //Fixed DlistCaching now is fully functional benefits still marginal but when vertex data is stored here the story will be diferent :)
+ //to test remove the next line;
+
+ if(size == 0) return false;
+ u64 dl_id = DLCache::CreateMapId(address, size);
+ DLCache::DLMap::iterator iter = DLCache::dl_map.find(dl_id);
+
+ stats.numDListsAlive = (int)DLCache::dl_map.size();
+ if (iter != DLCache::dl_map.end())
+ {
+ DLCache::CachedDisplayList &dl = iter->second;
+ if (dl.uncachable)
+ {
+ // We haven't compiled it - let's return false so it gets
+ // interpreted.
+ return false;
+ }
+
+ // Got one! And it's been compiled too, so let's run the compiled code!
+ switch (dl.pass)
+ {
+ case DLCache::DLPASS_ANALYZE:
+ PanicAlert("DLPASS_ANALYZE - should have been done the first pass");
+ break;
+ case DLCache::DLPASS_COMPILE:
+ // First, check that the hash is the same as the last time.
+ if (dl.dl_hash != GetHash64(Memory_GetPtr(address), size,0))
+ {
+ // PanicAlert("uncachable %08x", address);
+ dl.uncachable = true;
+ return false;
+ }
+ DLCache::CompileAndRunDisplayList(address, size, &dl);
+ dl.pass = DLCache::DLPASS_RUN;
+ break;
+ case DLCache::DLPASS_RUN:
+ {
+ // Every N draws, check hash
+ dl.check--;
+ if (dl.check <= 0)
+ {
+ if (dl.dl_hash != GetHash64(Memory_GetPtr(address), size,0))
+ {
+ dl.uncachable = true;
+ DLCache::VdataMap::iterator viter = dl.Vdata.begin();
+ while (viter != dl.Vdata.end())
+ {
+ DLCache::DataPointer &ventry = viter->second;
+ delete [] ventry;
+ dl.Vdata.erase(viter++);
+ }
+ dl.BufferCount = 0;
+ return false;
+ }
+ dl.check = dl.next_check;
+ dl.next_check *= 2;
+ if (dl.next_check > 1024)
+ dl.next_check = 1024;
+ }
+ dl.frame_count= frameCount;
+ u8 *old_datareader = g_pVideoData;
+ ((void (*)())(void*)(dl.compiled_code))();
+ Statistics::SwapDL();
+ ADDSTAT(stats.thisFrame.numCPLoadsInDL,dl.num_cp_reg);
+ ADDSTAT(stats.thisFrame.numXFLoadsInDL,dl.num_xf_reg);
+ ADDSTAT(stats.thisFrame.numBPLoadsInDL,dl.num_bp_reg);
+
+ ADDSTAT(stats.thisFrame.numCPLoads,dl.num_cp_reg);
+ ADDSTAT(stats.thisFrame.numXFLoads,dl.num_xf_reg);
+ ADDSTAT(stats.thisFrame.numBPLoads,dl.num_bp_reg);
+
+ INCSTAT(stats.numDListsCalled);
+ INCSTAT(stats.thisFrame.numDListsCalled);
+
+ Statistics::SwapDL();
+ g_pVideoData = old_datareader;
+ break;
+ }
+ }
+ return true;
+ }
+
+ DLCache::CachedDisplayList dl;
+
+ if (DLCache::AnalyzeAndRunDisplayList(address, size, &dl)) {
+ dl.dl_hash = GetHash64(Memory_GetPtr(address), size,0);
+ dl.pass = DLCache::DLPASS_COMPILE;
+ dl.check = 1;
+ dl.next_check = 1;
+ DLCache::dl_map[dl_id] = dl;
+ return true;
+ } else {
+ dl.uncachable = true;
+ DLCache::dl_map[dl_id] = dl;
+ return true; // don't also interpret the list.
+ }
+}
diff --git a/Source/Core/VideoCommon/Src/DLCache.h b/Source/Core/VideoCommon/Src/DLCache.h
new file mode 100644
index 0000000000..9286f52637
--- /dev/null
+++ b/Source/Core/VideoCommon/Src/DLCache.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2003-2009 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/
+
+#ifndef _DLCACHE_H
+#define _DLCACHE_H
+
+bool HandleDisplayList(u32 address, u32 size);
+
+namespace DLCache {
+
+void Init();
+void Shutdown();
+void ProgressiveCleanup();
+void Clear();
+
+} // namespace
+
+#endif // _DLCACHE_H
diff --git a/Source/Core/VideoCommon/Src/NativeVertexWriter.h b/Source/Core/VideoCommon/Src/NativeVertexWriter.h
index 6764c7abcd..d24af1feea 100644
--- a/Source/Core/VideoCommon/Src/NativeVertexWriter.h
+++ b/Source/Core/VideoCommon/Src/NativeVertexWriter.h
@@ -23,6 +23,7 @@ namespace VertexManager
{
void AddVertices(int primitive, int numvertices);
+void AddCompiledVertices(int primitive, int numvertices, u8* Vdata);
void Flush(); // flushes the current buffer
int GetRemainingSize(); // remaining space in the current buffer.
int GetRemainingVertices(int primitive); // remaining number of vertices that can be processed in one AddVertices call
diff --git a/Source/Core/VideoCommon/Src/VertexLoader.cpp b/Source/Core/VideoCommon/Src/VertexLoader.cpp
index a09d81c9b6..072e239d9e 100644
--- a/Source/Core/VideoCommon/Src/VertexLoader.cpp
+++ b/Source/Core/VideoCommon/Src/VertexLoader.cpp
@@ -680,6 +680,63 @@ void VertexLoader::RunVertices(int vtx_attr_group, int primitive, int count)
VertexManager::AddVertices(primitive, count - startv + extraverts);
}
+
+
+
+void VertexLoader::RunCompiledVertices(int vtx_attr_group, int primitive, int count, u8* Data)
+{
+ DVSTARTPROFILE();
+
+ m_numLoadedVertices += count;
+
+ // Flush if our vertex format is different from the currently set.
+ if (g_nativeVertexFmt != NULL && g_nativeVertexFmt != m_NativeFmt)
+ {
+ // We really must flush here. It's possible that the native representations
+ // of the two vtx formats are the same, but we have no way to easily check that
+ // now.
+ VertexManager::Flush();
+ // Also move the Set() here?
+ }
+ g_nativeVertexFmt = m_NativeFmt;
+
+ if (bpmem.genMode.cullmode == 3 && primitive < 5)
+ {
+ // if cull mode is none, ignore triangles and quads
+ DataSkip(count * m_VertexSize);
+ return;
+ }
+
+ m_NativeFmt->EnableComponents(m_NativeFmt->m_components);
+
+ // Load position and texcoord scale factors.
+ 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;
+
+ pVtxAttr = &m_VtxAttr;
+ posScale = 1.0f / float(1 << m_VtxAttr.PosFrac);
+ if (m_NativeFmt->m_components & VB_HAS_UVALL)
+ for (int i = 0; i < 8; i++)
+ tcScale[i] = texCoordFrac[m_VtxAttr.texCoord[i].Frac];
+ for (int i = 0; i < 2; i++)
+ colElements[i] = m_VtxAttr.color[i].Elements;
+
+ if(VertexManager::GetRemainingSize() < native_stride * count)
+ VertexManager::Flush();
+ memcpy_gc(VertexManager::s_pCurBufferPointer, Data, native_stride * count);
+ VertexManager::s_pCurBufferPointer += native_stride * count;
+ VertexManager::AddVertices(primitive, count);
+}
+
+
+
void VertexLoader::SetVAT(u32 _group0, u32 _group1, u32 _group2)
{
VAT vat;
diff --git a/Source/Core/VideoCommon/Src/VertexLoader.h b/Source/Core/VideoCommon/Src/VertexLoader.h
index 8c72954530..4ec3c5f64a 100644
--- a/Source/Core/VideoCommon/Src/VertexLoader.h
+++ b/Source/Core/VideoCommon/Src/VertexLoader.h
@@ -84,6 +84,7 @@ public:
int GetVertexSize() const {return m_VertexSize;}
void RunVertices(int vtx_attr_group, int primitive, int count);
+ void RunCompiledVertices(int vtx_attr_group, int primitive, int count, u8* Data);
// For debugging / profiling
void AppendToString(std::string *dest) const;
diff --git a/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp b/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp
index 176e9ad0c7..c03f0d94fd 100644
--- a/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp
+++ b/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp
@@ -143,6 +143,14 @@ void RunVertices(int vtx_attr_group, int primitive, int count)
g_VertexLoaders[vtx_attr_group]->RunVertices(vtx_attr_group, primitive, count);
}
+void RunCompiledVertices(int vtx_attr_group, int primitive, int count, u8* Data)
+{
+ if (!count || !Data)
+ return;
+ RefreshLoader(vtx_attr_group);
+ g_VertexLoaders[vtx_attr_group]->RunCompiledVertices(vtx_attr_group, primitive, count,Data);
+}
+
int GetVertexSize(int vtx_attr_group)
{
RefreshLoader(vtx_attr_group);
diff --git a/Source/Core/VideoCommon/Src/VertexLoaderManager.h b/Source/Core/VideoCommon/Src/VertexLoaderManager.h
index 91d8397870..e61977b07e 100644
--- a/Source/Core/VideoCommon/Src/VertexLoaderManager.h
+++ b/Source/Core/VideoCommon/Src/VertexLoaderManager.h
@@ -30,6 +30,7 @@ namespace VertexLoaderManager
int GetVertexSize(int vtx_attr_group);
void RunVertices(int vtx_attr_group, int primitive, int count);
+ void RunCompiledVertices(int vtx_attr_group, int primitive, int count, u8* Data);
// For debugging
void AppendListToString(std::string *dest);
diff --git a/Source/Core/VideoCommon/VideoCommon.vcproj b/Source/Core/VideoCommon/VideoCommon.vcproj
index af82f36aa4..fd9c57a138 100644
--- a/Source/Core/VideoCommon/VideoCommon.vcproj
+++ b/Source/Core/VideoCommon/VideoCommon.vcproj
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
- Version="9.00"
+ Version="9,00"
Name="VideoCommon"
ProjectGUID="{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}"
RootNamespace="VideoCommon"
@@ -635,6 +635,14 @@
>
</File>
<File
+ RelativePath=".\Src\DLCache.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Src\DLCache.h"
+ >
+ </File>
+ <File
RelativePath=".\Src\VertexLoader.cpp"
>
</File>