| 
									
										
										
										
											2008-09-07 10:29:46 +00:00
										 |  |  | // Copyright (C) 2003-2008 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/
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | #include "D3DBase.h"
 | 
					
						
							| 
									
										
										
										
											2008-10-22 20:54:40 +00:00
										 |  |  | #include "Statistics.h"
 | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | #include "Utils.h"
 | 
					
						
							| 
									
										
										
										
											2008-10-17 11:30:14 +00:00
										 |  |  | #include "Profiler.h"
 | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | #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-10-22 18:39:46 +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 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2008-10-22 18:39:46 +00:00
										 |  |  | 			iter++; | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	SETSTAT(stats.numPixelShadersAlive, (int)pshaders.size()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VShaderCache::Init() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VShaderCache::Shutdown() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	VSCache::iterator iter = vshaders.begin(); | 
					
						
							| 
									
										
										
										
											2008-10-22 18:39:46 +00:00
										 |  |  | 	for (; iter != vshaders.end(); iter++) | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 		iter->second.Destroy(); | 
					
						
							|  |  |  | 	vshaders.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VShaderCache::SetShader() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-09-12 19:04:13 +00:00
										 |  |  | 	static LPDIRECT3DVERTEXSHADER9 shader = NULL; | 
					
						
							| 
									
										
										
										
											2008-08-26 23:11:15 +00:00
										 |  |  | 	if (D3D::GetShaderVersion() < 2) | 
					
						
							|  |  |  | 		return; // we are screwed
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-22 18:39:46 +00:00
										 |  |  | 	if (shader) { | 
					
						
							| 
									
										
										
										
											2008-09-12 19:04:13 +00:00
										 |  |  | 		//D3D::dev->SetVertexShader(shader);
 | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											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(); | 
					
						
							| 
									
										
										
										
											2008-09-12 19:04:13 +00:00
										 |  |  | 	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; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-09-12 19:04:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 	D3D::dev->SetVertexShader(shader); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	INCSTAT(stats.numVertexShadersCreated); | 
					
						
							|  |  |  | 	SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VShaderCache::Cleanup() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-09-23 20:55:01 +00:00
										 |  |  | 	for (VSCache::iterator iter=vshaders.begin(); iter!=vshaders.end();) | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		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-09-23 20:55:01 +00:00
										 |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			++iter; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-08-26 23:11:15 +00:00
										 |  |  | 	SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); | 
					
						
							| 
									
										
										
										
											2008-07-12 17:40:22 +00:00
										 |  |  | } |