| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | #include "D3DBase.h"
 | 
					
						
							|  |  |  | #include "Utils.h"
 | 
					
						
							|  |  |  | #include "Globals.h"
 | 
					
						
							|  |  |  | #include "ShaderManager.h"
 | 
					
						
							| 
									
										
										
										
											2008-08-26 23:11:15 +00:00
										 |  |  | #include "VertexLoader.h"
 | 
					
						
							| 
									
										
										
										
											2008-07-20 12:26:32 +00:00
										 |  |  | #include "BPMemory.h"
 | 
					
						
							|  |  |  | #include "XFMemory.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //I hope we don't get too many hash collisions :p
 | 
					
						
							|  |  |  | //all these magic numbers are primes, it should help a bit
 | 
					
						
							|  |  |  | tevhash GetCurrentTEV() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 hash = bpmem.genMode.numindstages + bpmem.genMode.numtevstages*11 + bpmem.genMode.numtexgens*8*17; | 
					
						
							|  |  |  | 	for (int i = 0; i < (int)bpmem.genMode.numtevstages+1; i++) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hash = _rotl(hash,3) ^ (bpmem.combiners[i].colorC.hex*13); | 
					
						
							|  |  |  | 		hash = _rotl(hash,7) ^ ((bpmem.combiners[i].alphaC.hex&0xFFFFFFFC)*3); | 
					
						
							|  |  |  | 		hash = _rotl(hash,9) ^ xfregs.texcoords[i].texmtxinfo.projection*451; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for (int i = 0; i < (int)bpmem.genMode.numtevstages/2+1; i++) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hash = _rotl(hash,13) ^ (bpmem.tevorders[i].hex*7); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for (int i = 0; i < 8; i++) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap1; | 
					
						
							|  |  |  | 		hash = _rotl(hash,3) ^ bpmem.tevksel[i].swap2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	hash ^= bpmem.dstalpha.enable ^ 0xc0debabe; | 
					
						
							|  |  |  | 	hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp0*7; | 
					
						
							|  |  |  | 	hash = _rotl(hash,4) ^ bpmem.alphaFunc.comp1*13; | 
					
						
							|  |  |  | 	hash = _rotl(hash,4) ^ bpmem.alphaFunc.logic*11; | 
					
						
							|  |  |  | 	return hash; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | PShaderCache::PSCache PShaderCache::pshaders; | 
					
						
							|  |  |  | VShaderCache::VSCache VShaderCache::vshaders; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PShaderCache::Init() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PShaderCache::Shutdown() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	PSCache::iterator iter = pshaders.begin(); | 
					
						
							|  |  |  | 	for (;iter!=pshaders.end();iter++) | 
					
						
							|  |  |  | 		iter->second.Destroy(); | 
					
						
							| 
									
										
										
										
											2008-08-26 23:11:15 +00:00
										 |  |  | 	pshaders.clear();  | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PShaderCache::SetShader() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (D3D::GetShaderVersion() < 2) | 
					
						
							|  |  |  | 		return; // we are screwed
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static LPDIRECT3DPIXELSHADER9 lastShader = 0; | 
					
						
							|  |  |  |     DVSTARTPROFILE(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tevhash currentHash = GetCurrentTEV(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	PSCache::iterator iter; | 
					
						
							|  |  |  | 	iter = pshaders.find(currentHash); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (iter != pshaders.end()) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2008-07-15 20:11:18 +00:00
										 |  |  | 		iter->second.frameCount = frameCount; | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 		PSCacheEntry &entry = iter->second; | 
					
						
							|  |  |  | 		if (!lastShader || entry.shader != lastShader) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			D3D::dev->SetPixelShader(entry.shader); | 
					
						
							|  |  |  | 			lastShader = entry.shader; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-20 12:26:32 +00:00
										 |  |  | 	const char *code = GeneratePixelShader(); | 
					
						
							| 
									
										
										
										
											2008-08-26 23:11:15 +00:00
										 |  |  | 	LPDIRECT3DPIXELSHADER9 shader = D3D::CompilePShader(code, int(strlen(code))); | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 	if (shader) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		//Make an entry in the table
 | 
					
						
							|  |  |  | 		PSCacheEntry newentry; | 
					
						
							|  |  |  | 		newentry.shader = shader; | 
					
						
							| 
									
										
										
										
											2008-07-15 20:11:18 +00:00
										 |  |  | 		newentry.frameCount = frameCount; | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 		pshaders[currentHash] = newentry; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	D3D::dev->SetPixelShader(shader); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	INCSTAT(stats.numPixelShadersCreated); | 
					
						
							|  |  |  | 	SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PShaderCache::Cleanup() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-15 20:11:18 +00:00
										 |  |  | 	PSCache::iterator iter; | 
					
						
							|  |  |  | 	iter = pshaders.begin(); | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-15 20:11:18 +00:00
										 |  |  | 	while(iter != pshaders.end()) | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		PSCacheEntry &entry = iter->second; | 
					
						
							| 
									
										
										
										
											2008-07-15 20:11:18 +00:00
										 |  |  | 		if (entry.frameCount < frameCount-30) | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			entry.Destroy(); | 
					
						
							|  |  |  | 			iter = pshaders.erase(iter); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  iter++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VShaderCache::Init() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VShaderCache::Shutdown() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	VSCache::iterator iter = vshaders.begin(); | 
					
						
							|  |  |  | 	for (;iter!=vshaders.end();iter++) | 
					
						
							|  |  |  | 		iter->second.Destroy(); | 
					
						
							|  |  |  | 	vshaders.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VShaderCache::SetShader() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-08-26 23:11:15 +00:00
										 |  |  | 	if (D3D::GetShaderVersion() < 2) | 
					
						
							|  |  |  | 		return; // we are screwed
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 	static LPDIRECT3DVERTEXSHADER9 lastShader = 0; | 
					
						
							| 
									
										
										
										
											2008-08-26 23:11:15 +00:00
										 |  |  | 	DVSTARTPROFILE(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tevhash currentHash = GetCurrentTEV(); | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	VSCache::iterator iter; | 
					
						
							|  |  |  | 	iter = vshaders.find(currentHash); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (iter != vshaders.end()) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		iter->second.frameCount=frameCount; | 
					
						
							|  |  |  | 		VSCacheEntry &entry = iter->second; | 
					
						
							|  |  |  | 		if (!lastShader || entry.shader != lastShader) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			D3D::dev->SetVertexShader(entry.shader); | 
					
						
							|  |  |  | 			lastShader = entry.shader; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-26 23:11:15 +00:00
										 |  |  | 	const char *code = GenerateVertexShader(); | 
					
						
							|  |  |  | 	LPDIRECT3DVERTEXSHADER9 shader = D3D::CompileVShader(code, int(strlen(code))); | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 	if (shader) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		//Make an entry in the table
 | 
					
						
							|  |  |  | 		VSCacheEntry entry; | 
					
						
							|  |  |  | 		entry.shader = shader; | 
					
						
							|  |  |  | 		entry.frameCount=frameCount; | 
					
						
							|  |  |  | 		vshaders[currentHash] = entry; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	D3D::dev->SetVertexShader(shader); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	INCSTAT(stats.numVertexShadersCreated); | 
					
						
							|  |  |  | 	SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VShaderCache::Cleanup() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	for (VSCache::iterator iter=vshaders.begin(); iter!=vshaders.end();iter++) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		VSCacheEntry &entry = iter->second; | 
					
						
							| 
									
										
										
										
											2008-08-30 16:05:32 +00:00
										 |  |  | 		if (entry.frameCount < frameCount - 30) | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			entry.Destroy(); | 
					
						
							|  |  |  | 			iter = vshaders.erase(iter); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-08-26 23:11:15 +00:00
										 |  |  | 	SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | } |