| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | // 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.
 | 
					
						
							| 
									
										
										
										
											2011-01-31 01:28:32 +00:00
										 |  |  | #include "HW/Memmap.h"
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "XFMemory.h"
 | 
					
						
							|  |  |  | #include "CPMemory.h"
 | 
					
						
							|  |  |  | #include "BPMemory.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "VertexLoaderManager.h"
 | 
					
						
							| 
									
										
										
										
											2010-10-03 00:41:06 +00:00
										 |  |  | #include "VertexManagerBase.h"
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | #include "x64Emitter.h"
 | 
					
						
							|  |  |  | #include "ABI.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "DLCache.h"
 | 
					
						
							| 
									
										
										
										
											2010-08-30 15:18:43 +00:00
										 |  |  | #include "VideoConfig.h"
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define DL_CODE_CACHE_SIZE (1024*1024*16)
 | 
					
						
							| 
									
										
										
										
											2011-02-25 20:27:57 +00:00
										 |  |  | #define DL_CODE_CLEAR_THRESHOLD (16 * 1024)
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | extern int frameCount; | 
					
						
							| 
									
										
										
										
											2011-02-08 11:02:34 +00:00
										 |  |  | static u32 CheckContextId; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | using namespace Gen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace DLCache | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum DisplayListPass { | 
					
						
							|  |  |  | 	DLPASS_ANALYZE, | 
					
						
							|  |  |  | 	DLPASS_COMPILE, | 
					
						
							|  |  |  | 	DLPASS_RUN, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | #define DL_HASH_STEPS 512
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ReferencedDataRegion | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 	ReferencedDataRegion() | 
					
						
							|  |  |  | 		:hash(0), | 
					
						
							|  |  |  | 		start_address(NULL), | 
					
						
							| 
									
										
										
										
											2011-02-08 11:02:34 +00:00
										 |  |  | 		NextRegion(NULL), | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 		size(0), | 
					
						
							| 
									
										
										
										
											2011-02-25 20:27:57 +00:00
										 |  |  | 		MustClean(0) | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 	{} | 
					
						
							|  |  |  | 	u64 hash; | 
					
						
							|  |  |  | 	u8* start_address; | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	ReferencedDataRegion* NextRegion; | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 	u32 size; | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	u32 MustClean; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int IntersectsMemoryRange(u8* range_address, u32 range_size) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (start_address + size < range_address) | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		if (start_address >= range_address + range_size) | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct CachedDisplayList | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CachedDisplayList() | 
					
						
							| 
									
										
										
										
											2011-02-08 11:02:34 +00:00
										 |  |  | 			: Regions(NULL), | 
					
						
							|  |  |  | 			LastRegion(NULL), | 
					
						
							|  |  |  | 			uncachable(false), | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 			num_xf_reg(0), | 
					
						
							|  |  |  | 			num_cp_reg(0), | 
					
						
							|  |  |  | 			num_bp_reg(0),  | 
					
						
							|  |  |  | 			num_index_xf(0), | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 			num_draw_call(0), | 
					
						
							| 
									
										
										
										
											2010-09-16 04:22:27 +00:00
										 |  |  | 			pass(DLPASS_ANALYZE), | 
					
						
							| 
									
										
										
										
											2011-02-08 11:02:34 +00:00
										 |  |  | 			BufferCount(0) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		frame_count = frameCount; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	u64 dl_hash; | 
					
						
							| 
									
										
										
										
											2011-02-25 20:27:57 +00:00
										 |  |  | 	// ... Something containing cached vertex buffers here ...
 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	ReferencedDataRegion* Regions; | 
					
						
							|  |  |  | 	ReferencedDataRegion* LastRegion; | 
					
						
							| 
									
										
										
										
											2011-02-25 20:27:57 +00:00
										 |  |  | 	// Compile the commands themselves down to native code.
 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	const u8* compiled_code; | 
					
						
							|  |  |  | 	u32 uncachable;  // if set, this DL will always be interpreted. This gets set if hash ever changes.
 | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 	// Analitic data
 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	u32 num_xf_reg; | 
					
						
							|  |  |  | 	u32 num_cp_reg; | 
					
						
							|  |  |  | 	u32 num_bp_reg;  | 
					
						
							|  |  |  | 	u32 num_index_xf; | 
					
						
							| 
									
										
										
										
											2011-02-25 20:27:57 +00:00
										 |  |  | 	u32 num_draw_call;	 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	u32 pass; | 
					
						
							|  |  |  | 	u32 check; | 
					
						
							| 
									
										
										
										
											2011-02-25 20:27:57 +00:00
										 |  |  | 	int frame_count;	 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	u32 BufferCount; | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	void InsertRegion(ReferencedDataRegion* NewRegion) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if(LastRegion) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			LastRegion->NextRegion = NewRegion;			 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		LastRegion = NewRegion; | 
					
						
							|  |  |  | 		if(!Regions) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Regions = LastRegion; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		BufferCount++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-25 20:27:57 +00:00
										 |  |  | 	void InsertOverlapingRegion(u8* RegionStartAddress, u32 Size) | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		ReferencedDataRegion* NewRegion = FindOverlapingRegion(RegionStartAddress, Size); | 
					
						
							|  |  |  | 		if(NewRegion) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			bool RegionChanged = false; | 
					
						
							|  |  |  | 			if(RegionStartAddress < NewRegion->start_address) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				NewRegion->start_address = RegionStartAddress; | 
					
						
							|  |  |  | 				RegionChanged = true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(RegionStartAddress + Size > NewRegion->start_address + NewRegion->size) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2011-01-29 22:53:00 +00:00
										 |  |  | 				NewRegion->size += (u32)((RegionStartAddress + Size) - (NewRegion->start_address + NewRegion->size)); | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 				RegionChanged = true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(RegionChanged) | 
					
						
							|  |  |  | 				NewRegion->hash = GetHash64(NewRegion->start_address, NewRegion->size, DL_HASH_STEPS); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			NewRegion = new ReferencedDataRegion; | 
					
						
							|  |  |  | 			NewRegion->MustClean = false; | 
					
						
							|  |  |  | 			NewRegion->size = Size; | 
					
						
							|  |  |  | 			NewRegion->start_address = RegionStartAddress;  | 
					
						
							| 
									
										
										
										
											2011-02-25 20:27:57 +00:00
										 |  |  | 			NewRegion->hash = GetHash64(RegionStartAddress, Size, DL_HASH_STEPS); | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 			InsertRegion(NewRegion); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool CheckRegions() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ReferencedDataRegion* Current = Regions; | 
					
						
							|  |  |  | 		while(Current) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if(Current->hash) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if(Current->hash != GetHash64(Current->start_address,  Current->size, DL_HASH_STEPS)) | 
					
						
							|  |  |  | 					return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			Current = Current->NextRegion; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	}	 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	ReferencedDataRegion* FindOverlapingRegion(u8* RegionStart, u32 Regionsize) | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		ReferencedDataRegion* Current = Regions; | 
					
						
							|  |  |  | 		while(Current) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if(!Current->IntersectsMemoryRange(RegionStart, Regionsize)) | 
					
						
							|  |  |  | 					return Current;			 | 
					
						
							|  |  |  | 			Current = Current->NextRegion; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return Current; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void ClearRegions() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ReferencedDataRegion* Current = Regions; | 
					
						
							|  |  |  | 		while(Current) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			ReferencedDataRegion* temp = Current; | 
					
						
							|  |  |  | 			Current = Current->NextRegion; | 
					
						
							|  |  |  | 			if(temp->MustClean) | 
					
						
							|  |  |  | 				delete [] temp->start_address; | 
					
						
							|  |  |  | 			delete temp; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		LastRegion = NULL; | 
					
						
							|  |  |  | 		Regions = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | inline u64 CreateVMapId(u32 VATUSED) | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-02-27 23:13:28 +00:00
										 |  |  | 	u64 vmap_id = 0x9368e53c2f6af274ULL ^ g_VtxDesc.Hex; | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 	for(int i = 0; i < 8 ; i++) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if(VATUSED & (1 << i)) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2011-02-27 18:06:55 +00:00
										 |  |  | 			vmap_id ^= (((u64)g_VtxAttr[i].g0.Hex) | (((u64)g_VtxAttr[i].g1.Hex) << 32)) ^ (((u64)g_VtxAttr[i].g2.Hex) << i); | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	for(int i = 0; i < 12; i++) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if(VATUSED & (1 << (i + 16))) | 
					
						
							| 
									
										
										
										
											2011-05-25 02:05:48 +00:00
										 |  |  | 			vmap_id  ^= (((u64)arraybases[i]) ^ (((u64)arraystrides[i]) << 32)); | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-02-27 18:06:55 +00:00
										 |  |  | 	return vmap_id; | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | typedef std::map<u64, CachedDisplayList> DLMap; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | struct VDlist | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	DLMap dl_map; | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	u32 VATUsed; | 
					
						
							|  |  |  | 	u32 count; | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef std::map<u64, VDlist> VDLMap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static VDLMap dl_map; | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | static u8* dlcode_cache; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static Gen::XEmitter emitter; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | // First pass - analyze
 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | u32 AnalyzeAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 	u8* old_pVideoData = g_pVideoData; | 
					
						
							| 
									
										
										
										
											2011-01-31 01:28:32 +00:00
										 |  |  | 	u8* startAddress = Memory::GetPointer(address); | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	u32 num_xf_reg = 0; | 
					
						
							|  |  |  | 	u32 num_cp_reg = 0; | 
					
						
							|  |  |  | 	u32 num_bp_reg = 0;  | 
					
						
							|  |  |  | 	u32 num_index_xf = 0; | 
					
						
							|  |  |  | 	u32 num_draw_call = 0; | 
					
						
							|  |  |  | 	u32 result = 0; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-31 01:28:32 +00:00
										 |  |  | 	// Avoid the crash if Memory::GetPointer failed ..
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 	if (startAddress != 0) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		g_pVideoData = startAddress; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		// temporarily swap dl and non-dl (small "hack" for the stats)
 | 
					
						
							|  |  |  | 		Statistics::SwapDL(); | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		u8 *end = g_pVideoData + size; | 
					
						
							|  |  |  | 		while (g_pVideoData < end) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Yet another reimplementation of the DL reading...
 | 
					
						
							|  |  |  | 			int cmd_byte = DataReadU8(); | 
					
						
							|  |  |  | 			switch (cmd_byte) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			case GX_NOP: | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			case GX_LOAD_XF_REG: | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					u32 Cmd2 = DataReadU32(); | 
					
						
							|  |  |  | 					int transfer_size = ((Cmd2 >> 16) & 15) + 1; | 
					
						
							|  |  |  | 					u32 xf_address = Cmd2 & 0xFFFF; | 
					
						
							| 
									
										
										
										
											2011-01-11 04:54:35 +00:00
										 |  |  | 					GC_ALIGNED128(u32 data_buffer[16]); | 
					
						
							| 
									
										
										
										
											2010-12-30 19:17:08 +00:00
										 |  |  | 					DataReadU32xFuncs[transfer_size-1](data_buffer); | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 					LoadXFReg(transfer_size, xf_address, data_buffer); | 
					
						
							|  |  |  | 					INCSTAT(stats.thisFrame.numXFLoads); | 
					
						
							|  |  |  | 					num_xf_reg++; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			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: | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2010-08-28 15:53:01 +00:00
										 |  |  | 					u32 addr = DataReadU32(); | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 					u32 count = DataReadU32(); | 
					
						
							| 
									
										
										
										
											2010-08-28 15:53:01 +00:00
										 |  |  | 					ExecuteDisplayList(addr, count); | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 				}			 | 
					
						
							|  |  |  | 				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); | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 					num_bp_reg++; | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// draw primitives 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			default: | 
					
						
							|  |  |  | 				if (cmd_byte & 0x80) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					// load vertices (use computed vertex size from FifoCommandRunnable above)
 | 
					
						
							|  |  |  | 					u16 numVertices = DataReadU16(); | 
					
						
							| 
									
										
										
										
											2011-05-25 02:05:48 +00:00
										 |  |  | 					if(numVertices > 0) | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2011-05-25 02:05:48 +00:00
										 |  |  | 						result |= 1 << (cmd_byte & GX_VAT_MASK); | 
					
						
							|  |  |  | 						VertexLoaderManager::RunVertices( | 
					
						
							|  |  |  | 							cmd_byte & GX_VAT_MASK,   // Vertex loader index (0 - 7)
 | 
					
						
							|  |  |  | 							(cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, | 
					
						
							|  |  |  | 							numVertices); | 
					
						
							|  |  |  | 						num_draw_call++; | 
					
						
							|  |  |  | 						const int tc[12] = { | 
					
						
							|  |  |  | 							g_VtxDesc.Position, g_VtxDesc.Normal, g_VtxDesc.Color0, g_VtxDesc.Color1, g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord,  | 
					
						
							|  |  |  | 							g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const int)((g_VtxDesc.Hex >> 31) & 3) | 
					
						
							|  |  |  | 						}; | 
					
						
							|  |  |  | 						for(int i = 0; i < 12; i++) | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2011-05-25 02:05:48 +00:00
										 |  |  | 							if(tc[i] > 1) | 
					
						
							|  |  |  | 							{ | 
					
						
							|  |  |  | 								result |= 1 << (i + 16); | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					ERROR_LOG(VIDEO, "OpcodeDecoding::Decode: Illegal command %02x", cmd_byte); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		INCSTAT(stats.numDListsCalled); | 
					
						
							|  |  |  | 		INCSTAT(stats.thisFrame.numDListsCalled); | 
					
						
							|  |  |  | 		// un-swap
 | 
					
						
							|  |  |  | 		Statistics::SwapDL(); | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  |     // reset to the old pointer
 | 
					
						
							|  |  |  | 	g_pVideoData = old_pVideoData;	 | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 	return result; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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.
 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | void CompileAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 	u8* old_pVideoData = g_pVideoData; | 
					
						
							| 
									
										
										
										
											2011-01-31 01:28:32 +00:00
										 |  |  | 	u8* startAddress = Memory::GetPointer(address); | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-31 01:28:32 +00:00
										 |  |  | 	// Avoid the crash if Memory::GetPointer failed ..
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 	if (startAddress != 0) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		g_pVideoData = startAddress; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		// temporarily swap dl and non-dl (small "hack" for the stats)
 | 
					
						
							|  |  |  | 		Statistics::SwapDL(); | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		u8 *end = g_pVideoData + size; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		emitter.AlignCode4(); | 
					
						
							|  |  |  | 		dl->compiled_code = emitter.GetCodePtr(); | 
					
						
							|  |  |  | 		emitter.ABI_EmitPrologue(4); | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		while (g_pVideoData < end) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// Yet another reimplementation of the DL reading...
 | 
					
						
							|  |  |  | 			int cmd_byte = DataReadU8(); | 
					
						
							|  |  |  | 			switch (cmd_byte) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			case GX_NOP: | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 				// Execute
 | 
					
						
							|  |  |  | 				// Compile
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			case GX_LOAD_XF_REG: | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					// Execute
 | 
					
						
							|  |  |  | 					u32 Cmd2 = DataReadU32(); | 
					
						
							|  |  |  | 					int transfer_size = ((Cmd2 >> 16) & 15) + 1; | 
					
						
							|  |  |  | 					u32 xf_address = Cmd2 & 0xFFFF; | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 					ReferencedDataRegion* NewRegion = new ReferencedDataRegion; | 
					
						
							|  |  |  | 					NewRegion->MustClean = true; | 
					
						
							|  |  |  | 					NewRegion->size = transfer_size * 4; | 
					
						
							| 
									
										
										
										
											2011-01-11 05:38:12 +00:00
										 |  |  | 					NewRegion->start_address = (u8*) new u8[NewRegion->size+15+12];  // alignment and guaranteed space
 | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 					NewRegion->hash = 0;					 | 
					
						
							|  |  |  | 					dl->InsertRegion(NewRegion); | 
					
						
							| 
									
										
										
										
											2011-01-11 04:54:35 +00:00
										 |  |  | 					u32 *data_buffer = (u32*)(u8*)(((size_t)NewRegion->start_address+0xf)&~0xf); | 
					
						
							| 
									
										
										
										
											2010-12-30 19:17:08 +00:00
										 |  |  | 					DataReadU32xFuncs[transfer_size-1](data_buffer); | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 					LoadXFReg(transfer_size, xf_address, data_buffer); | 
					
						
							|  |  |  | 					INCSTAT(stats.thisFrame.numXFLoads); | 
					
						
							|  |  |  | 					// Compile
 | 
					
						
							|  |  |  | 					emitter.ABI_CallFunctionCCP((void *)&LoadXFReg, transfer_size, xf_address, data_buffer); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			case GX_CMD_CALL_DL: | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 					u32 addr= DataReadU32(); | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 					u32 count = DataReadU32(); | 
					
						
							| 
									
										
										
										
											2010-08-28 15:53:01 +00:00
										 |  |  | 					ExecuteDisplayList(addr, count); | 
					
						
							| 
									
										
										
										
											2010-09-03 14:06:34 +00:00
										 |  |  | 					emitter.ABI_CallFunctionCC((void *)&ExecuteDisplayList, addr, count); | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			case GX_CMD_UNKNOWN_METRICS: | 
					
						
							|  |  |  | 				// zelda 4 swords calls it and checks the metrics registers after that
 | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			case GX_CMD_INVL_VC:// Invalidate	(vertex cache?)	
 | 
					
						
							|  |  |  | 				DEBUG_LOG(VIDEO, "Invalidate	(vertex cache?)"); | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 				// draw primitives 
 | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				if (cmd_byte & 0x80) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					// load vertices (use computed vertex size from FifoCommandRunnable above)
 | 
					
						
							| 
									
										
										
										
											2011-05-25 02:05:48 +00:00
										 |  |  | 					 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 					u16 numVertices = DataReadU16(); | 
					
						
							| 
									
										
										
										
											2011-05-25 02:05:48 +00:00
										 |  |  | 					if(numVertices > 0) | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2011-05-25 02:05:48 +00:00
										 |  |  | 						// Execute
 | 
					
						
							|  |  |  | 						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 (Vdatasize > 0) | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2011-05-25 02:05:48 +00:00
										 |  |  | 							// Compile
 | 
					
						
							|  |  |  | 							ReferencedDataRegion* NewRegion = new ReferencedDataRegion; | 
					
						
							|  |  |  | 							NewRegion->MustClean = true; | 
					
						
							|  |  |  | 							NewRegion->size = Vdatasize; | 
					
						
							|  |  |  | 							NewRegion->start_address = (u8*)new u8[Vdatasize];  | 
					
						
							|  |  |  | 							NewRegion->hash = 0;					 | 
					
						
							|  |  |  | 							dl->InsertRegion(NewRegion); | 
					
						
							|  |  |  | 							memcpy(NewRegion->start_address, StartAddress, Vdatasize); | 
					
						
							|  |  |  | 							emitter.ABI_CallFunctionCCCP((void *)&VertexLoaderManager::RunCompiledVertices, cmd_byte & GX_VAT_MASK, (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices, NewRegion->start_address); | 
					
						
							|  |  |  | 							const int tc[12] = { | 
					
						
							|  |  |  | 							g_VtxDesc.Position, g_VtxDesc.Normal, g_VtxDesc.Color0, g_VtxDesc.Color1, g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord,  | 
					
						
							|  |  |  | 							g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const int)((g_VtxDesc.Hex >> 31) & 3) | 
					
						
							|  |  |  | 							}; | 
					
						
							|  |  |  | 							for(int i = 0; i < 12; i++) | 
					
						
							|  |  |  | 							{ | 
					
						
							|  |  |  | 								if(tc[i] > 1) | 
					
						
							|  |  |  | 								{ | 
					
						
							|  |  |  | 									u8* saddr = cached_arraybases[i]; | 
					
						
							|  |  |  | 									int arraySize = arraystrides[i] * ((tc[i] == 2)? numVertices : ((numVertices < 1024)? 2 * numVertices : numVertices)); | 
					
						
							|  |  |  | 									dl->InsertOverlapingRegion(saddr, arraySize); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2011-05-25 02:05:48 +00:00
										 |  |  | 					 | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					ERROR_LOG(VIDEO, "DLCache::CompileAndRun: Illegal command %02x", cmd_byte); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 		emitter.ABI_EmitEpilogue(4); | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 		INCSTAT(stats.numDListsCalled); | 
					
						
							|  |  |  | 		INCSTAT(stats.thisFrame.numDListsCalled); | 
					
						
							|  |  |  | 		Statistics::SwapDL(); | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 	g_pVideoData = old_pVideoData; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | void Init() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-02-08 00:28:28 +00:00
										 |  |  | 	CheckContextId = 0; | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 	dlcode_cache = (u8*)AllocateExecutableMemory(DL_CODE_CACHE_SIZE, false);  // Don't need low memory.
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	emitter.SetCodePtr(dlcode_cache); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Shutdown() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Clear(); | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 	FreeMemoryPages(dlcode_cache, DL_CODE_CACHE_SIZE);	 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	dlcode_cache = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Clear()  | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 	VDLMap::iterator iter = dl_map.begin(); | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 	while (iter != dl_map.end()) { | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 		VDlist &ParentEntry = iter->second; | 
					
						
							|  |  |  | 		DLMap::iterator childiter = ParentEntry.dl_map.begin(); | 
					
						
							|  |  |  | 		while (childiter != ParentEntry.dl_map.end()) { | 
					
						
							|  |  |  | 			CachedDisplayList &entry = childiter->second; | 
					
						
							|  |  |  | 			entry.ClearRegions(); | 
					
						
							|  |  |  | 			childiter++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ParentEntry.dl_map.clear(); | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 		iter++; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	dl_map.clear(); | 
					
						
							|  |  |  | 	// Reset the cache pointers.
 | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 	emitter.SetCodePtr(dlcode_cache);	 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ProgressiveCleanup() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 	VDLMap::iterator iter = dl_map.begin(); | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	while (iter != dl_map.end()) { | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 		VDlist &ParentEntry = iter->second; | 
					
						
							|  |  |  | 		DLMap::iterator childiter = ParentEntry.dl_map.begin(); | 
					
						
							|  |  |  | 		while (childiter != ParentEntry.dl_map.end())  | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			CachedDisplayList &entry = childiter->second; | 
					
						
							|  |  |  | 			int limit = 3600; | 
					
						
							|  |  |  | 			if (entry.frame_count < frameCount - limit) { | 
					
						
							|  |  |  | 				entry.ClearRegions(); | 
					
						
							|  |  |  | 				ParentEntry.dl_map.erase(childiter++);  // (this is gcc standard!)
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				++childiter; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(ParentEntry.dl_map.empty()) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			dl_map.erase(iter++); | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 			iter++; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-22 03:50:44 +00:00
										 |  |  | static size_t GetSpaceLeft() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return DL_CODE_CACHE_SIZE - (emitter.GetCodePtr() - dlcode_cache); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | }  // namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NOTE - outside the namespace on purpose.
 | 
					
						
							|  |  |  | bool HandleDisplayList(u32 address, u32 size) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-08-30 15:18:43 +00:00
										 |  |  | 	//Fixed DlistCaching now is fully functional still some things to workout
 | 
					
						
							| 
									
										
										
										
											2010-08-30 15:33:37 +00:00
										 |  |  | 	if(!g_ActiveConfig.bDlistCachingEnable) | 
					
						
							| 
									
										
										
										
											2010-08-30 15:18:43 +00:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2010-08-28 15:09:42 +00:00
										 |  |  | 	if(size == 0) return false; | 
					
						
							| 
									
										
										
										
											2010-10-22 03:50:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Is this thread safe?
 | 
					
						
							|  |  |  | 	if (DLCache::GetSpaceLeft() < DL_CODE_CLEAR_THRESHOLD) { | 
					
						
							|  |  |  | 		DLCache::Clear(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	u64 dl_id = DLCache::CreateMapId(address, size); | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 	u64 vhash = 0; | 
					
						
							|  |  |  | 	DLCache::VDLMap::iterator Parentiter = DLCache::dl_map.find(dl_id); | 
					
						
							|  |  |  | 	DLCache::DLMap::iterator iter; | 
					
						
							|  |  |  | 	bool childexist = false; | 
					
						
							|  |  |  | 	if (Parentiter != DLCache::dl_map.end()) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		vhash = DLCache::CreateVMapId(Parentiter->second.VATUsed); | 
					
						
							|  |  |  | 		iter = 	Parentiter->second.dl_map.find(vhash); | 
					
						
							|  |  |  | 		childexist = iter != Parentiter->second.dl_map.end();		 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (Parentiter != DLCache::dl_map.end() && childexist) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		DLCache::CachedDisplayList &dl = iter->second; | 
					
						
							|  |  |  | 		if (dl.uncachable) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 			return false;			 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (dl.pass) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		case DLCache::DLPASS_COMPILE: | 
					
						
							|  |  |  | 			// First, check that the hash is the same as the last time.
 | 
					
						
							| 
									
										
										
										
											2011-01-31 01:28:32 +00:00
										 |  |  | 			if (dl.dl_hash != GetHash64(Memory::GetPointer(address), size, 0)) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2010-09-14 22:48:22 +00:00
										 |  |  | 				dl.uncachable = true;				 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 				return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			DLCache::CompileAndRunDisplayList(address, size, &dl); | 
					
						
							|  |  |  | 			dl.pass = DLCache::DLPASS_RUN; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case DLCache::DLPASS_RUN: | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2011-02-08 12:00:41 +00:00
										 |  |  | 				bool DlistChanged = false; | 
					
						
							| 
									
										
										
										
											2011-02-08 00:28:28 +00:00
										 |  |  | 				if (dl.check != CheckContextId) | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2011-02-08 00:28:28 +00:00
										 |  |  | 					dl.check = CheckContextId; | 
					
						
							| 
									
										
										
										
											2011-02-08 12:00:41 +00:00
										 |  |  | 					DlistChanged = !dl.CheckRegions() || dl.dl_hash != GetHash64(Memory::GetPointer(address), size, 0);					 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (DlistChanged)  | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					dl.uncachable = true; | 
					
						
							|  |  |  | 					dl.ClearRegions();						 | 
					
						
							|  |  |  | 					return false; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 				dl.frame_count= frameCount; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 				u8 *old_datareader = g_pVideoData; | 
					
						
							|  |  |  | 				((void (*)())(void*)(dl.compiled_code))(); | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 				Statistics::SwapDL(); | 
					
						
							| 
									
										
										
										
											2010-09-03 14:06:34 +00:00
										 |  |  | 				ADDSTAT(stats.thisFrame.numCPLoadsInDL, dl.num_cp_reg); | 
					
						
							|  |  |  | 				ADDSTAT(stats.thisFrame.numXFLoadsInDL, dl.num_xf_reg); | 
					
						
							|  |  |  | 				ADDSTAT(stats.thisFrame.numBPLoadsInDL, dl.num_bp_reg); | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-03 14:06:34 +00:00
										 |  |  | 				ADDSTAT(stats.thisFrame.numCPLoads, dl.num_cp_reg); | 
					
						
							|  |  |  | 				ADDSTAT(stats.thisFrame.numXFLoads, dl.num_xf_reg); | 
					
						
							|  |  |  | 				ADDSTAT(stats.thisFrame.numBPLoads, dl.num_bp_reg); | 
					
						
							| 
									
										
										
										
											2010-08-29 23:08:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				INCSTAT(stats.numDListsCalled); | 
					
						
							|  |  |  | 				INCSTAT(stats.thisFrame.numDListsCalled); | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 				Statistics::SwapDL(); | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 				g_pVideoData = old_datareader; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DLCache::CachedDisplayList dl; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	u32 dlvatused = DLCache::AnalyzeAndRunDisplayList(address, size, &dl); | 
					
						
							| 
									
										
										
										
											2011-01-31 01:28:32 +00:00
										 |  |  | 	dl.dl_hash = GetHash64(Memory::GetPointer(address), size,0); | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 	dl.pass = DLCache::DLPASS_COMPILE; | 
					
						
							| 
									
										
										
										
											2011-02-08 00:28:28 +00:00
										 |  |  | 	dl.check = CheckContextId; | 
					
						
							| 
									
										
										
										
											2011-02-07 22:35:46 +00:00
										 |  |  | 	vhash = DLCache::CreateVMapId(dlvatused); | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 	if(Parentiter != DLCache::dl_map.end()) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		DLCache::VDlist &vdl = Parentiter->second; | 
					
						
							|  |  |  | 		vdl.dl_map[vhash] = dl; | 
					
						
							|  |  |  | 		vdl.VATUsed = dlvatused;  | 
					
						
							|  |  |  | 		vdl.count++; | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-11-14 14:42:11 +00:00
										 |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		DLCache::VDlist vdl; | 
					
						
							|  |  |  | 		vdl.dl_map[vhash] = dl; | 
					
						
							|  |  |  | 		vdl.VATUsed = dlvatused;  | 
					
						
							|  |  |  | 		vdl.count = 1; | 
					
						
							|  |  |  | 		DLCache::dl_map[dl_id] = vdl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-05-28 23:14:16 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-02-08 00:28:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void IncrementCheckContextId() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CheckContextId++; | 
					
						
							|  |  |  | } |