| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | // Copyright 2015 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2+
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Common/LinearDiskCache.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Core/ConfigManager.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "VideoBackends/D3D12/D3DCommandListManager.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/D3D12/D3DShader.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/D3D12/ShaderCache.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "VideoCommon/Debugger.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/Statistics.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace DX12 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | // Primitive topology type is always triangle, unless the GS stage is used. This is consumed
 | 
					
						
							|  |  |  | // by the PSO created in Renderer::ApplyState.
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static D3D12_PRIMITIVE_TOPOLOGY_TYPE s_current_primitive_topology = | 
					
						
							|  |  |  |     D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | using GsBytecodeCache = std::map<GeometryShaderUid, D3D12_SHADER_BYTECODE>; | 
					
						
							|  |  |  | using PsBytecodeCache = std::map<PixelShaderUid, D3D12_SHADER_BYTECODE>; | 
					
						
							|  |  |  | using VsBytecodeCache = std::map<VertexShaderUid, D3D12_SHADER_BYTECODE>; | 
					
						
							|  |  |  | GsBytecodeCache s_gs_bytecode_cache; | 
					
						
							|  |  |  | PsBytecodeCache s_ps_bytecode_cache; | 
					
						
							|  |  |  | VsBytecodeCache s_vs_bytecode_cache; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Used to keep track of blobs to release at Shutdown time.
 | 
					
						
							|  |  |  | static std::vector<ID3DBlob*> s_shader_blob_list; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Only used for shader debugging..
 | 
					
						
							|  |  |  | using GsHlslCache = std::map<GeometryShaderUid, std::string>; | 
					
						
							|  |  |  | using PsHlslCache = std::map<PixelShaderUid, std::string>; | 
					
						
							|  |  |  | using VsHlslCache = std::map<VertexShaderUid, std::string>; | 
					
						
							|  |  |  | static GsHlslCache s_gs_hlsl_cache; | 
					
						
							|  |  |  | static PsHlslCache s_ps_hlsl_cache; | 
					
						
							|  |  |  | static VsHlslCache s_vs_hlsl_cache; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static LinearDiskCache<GeometryShaderUid, u8> s_gs_disk_cache; | 
					
						
							|  |  |  | static LinearDiskCache<PixelShaderUid, u8> s_ps_disk_cache; | 
					
						
							|  |  |  | static LinearDiskCache<VertexShaderUid, u8> s_vs_disk_cache; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static UidChecker<GeometryShaderUid, ShaderCode> s_geometry_uid_checker; | 
					
						
							|  |  |  | static UidChecker<PixelShaderUid, ShaderCode> s_pixel_uid_checker; | 
					
						
							|  |  |  | static UidChecker<VertexShaderUid, ShaderCode> s_vertex_uid_checker; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static D3D12_SHADER_BYTECODE s_last_geometry_shader_bytecode; | 
					
						
							|  |  |  | static D3D12_SHADER_BYTECODE s_last_pixel_shader_bytecode; | 
					
						
							|  |  |  | static D3D12_SHADER_BYTECODE s_last_vertex_shader_bytecode; | 
					
						
							|  |  |  | static GeometryShaderUid s_last_geometry_shader_uid; | 
					
						
							|  |  |  | static PixelShaderUid s_last_pixel_shader_uid; | 
					
						
							|  |  |  | static VertexShaderUid s_last_vertex_shader_uid; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | template <class UidType, class ShaderCacheType, ShaderCacheType* cache> | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | class ShaderCacheInserter final : public LinearDiskCacheReader<UidType, u8> | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   void Read(const UidType& key, const u8* value, u32 value_size) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ID3DBlob* blob = nullptr; | 
					
						
							|  |  |  |     CheckHR(d3d_create_blob(value_size, &blob)); | 
					
						
							|  |  |  |     memcpy(blob->GetBufferPointer(), value, value_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ShaderCache::InsertByteCode<UidType, ShaderCacheType>(key, cache, blob); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShaderCache::Init() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // This class intentionally shares its shader cache files with DX11, as the shaders are (right
 | 
					
						
							|  |  |  |   // now) identical.
 | 
					
						
							|  |  |  |   // Reduces unnecessary compilation when switching between APIs.
 | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_last_geometry_shader_bytecode = {}; | 
					
						
							|  |  |  |   s_last_pixel_shader_bytecode = {}; | 
					
						
							|  |  |  |   s_last_vertex_shader_bytecode = {}; | 
					
						
							|  |  |  |   s_last_geometry_shader_uid = {}; | 
					
						
							|  |  |  |   s_last_pixel_shader_uid = {}; | 
					
						
							|  |  |  |   s_last_vertex_shader_uid = {}; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Ensure shader cache directory exists..
 | 
					
						
							|  |  |  |   std::string shader_cache_path = File::GetUserPath(D_SHADERCACHE_IDX); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (!File::Exists(shader_cache_path)) | 
					
						
							|  |  |  |     File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::string title_unique_id = SConfig::GetInstance().m_strUniqueID.c_str(); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::string gs_cache_filename = | 
					
						
							|  |  |  |       StringFromFormat("%sdx11-%s-gs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); | 
					
						
							|  |  |  |   std::string ps_cache_filename = | 
					
						
							|  |  |  |       StringFromFormat("%sdx11-%s-ps.cache", shader_cache_path.c_str(), title_unique_id.c_str()); | 
					
						
							|  |  |  |   std::string vs_cache_filename = | 
					
						
							|  |  |  |       StringFromFormat("%sdx11-%s-vs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ShaderCacheInserter<GeometryShaderUid, GsBytecodeCache, &s_gs_bytecode_cache> gs_inserter; | 
					
						
							|  |  |  |   s_gs_disk_cache.OpenAndRead(gs_cache_filename, gs_inserter); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ShaderCacheInserter<PixelShaderUid, PsBytecodeCache, &s_ps_bytecode_cache> ps_inserter; | 
					
						
							|  |  |  |   s_ps_disk_cache.OpenAndRead(ps_cache_filename, ps_inserter); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ShaderCacheInserter<VertexShaderUid, VsBytecodeCache, &s_vs_bytecode_cache> vs_inserter; | 
					
						
							|  |  |  |   s_vs_disk_cache.OpenAndRead(vs_cache_filename, vs_inserter); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Clear out cache when debugging shaders to ensure stale ones don't stick around..
 | 
					
						
							|  |  |  |   if (g_Config.bEnableShaderDebugging) | 
					
						
							|  |  |  |     Clear(); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SETSTAT(stats.numPixelShadersAlive, static_cast<int>(s_ps_bytecode_cache.size())); | 
					
						
							|  |  |  |   SETSTAT(stats.numPixelShadersCreated, static_cast<int>(s_ps_bytecode_cache.size())); | 
					
						
							|  |  |  |   SETSTAT(stats.numVertexShadersAlive, static_cast<int>(s_vs_bytecode_cache.size())); | 
					
						
							|  |  |  |   SETSTAT(stats.numVertexShadersCreated, static_cast<int>(s_vs_bytecode_cache.size())); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShaderCache::Clear() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (auto& iter : s_shader_blob_list) | 
					
						
							|  |  |  |     SAFE_RELEASE(iter); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_shader_blob_list.clear(); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_gs_bytecode_cache.clear(); | 
					
						
							|  |  |  |   s_ps_bytecode_cache.clear(); | 
					
						
							|  |  |  |   s_vs_bytecode_cache.clear(); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_last_geometry_shader_bytecode = {}; | 
					
						
							|  |  |  |   s_last_geometry_shader_uid = {}; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_last_pixel_shader_bytecode = {}; | 
					
						
							|  |  |  |   s_last_pixel_shader_uid = {}; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_last_vertex_shader_bytecode = {}; | 
					
						
							|  |  |  |   s_last_vertex_shader_uid = {}; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShaderCache::Shutdown() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   s_gs_disk_cache.Sync(); | 
					
						
							|  |  |  |   s_gs_disk_cache.Close(); | 
					
						
							|  |  |  |   s_ps_disk_cache.Sync(); | 
					
						
							|  |  |  |   s_ps_disk_cache.Close(); | 
					
						
							|  |  |  |   s_vs_disk_cache.Sync(); | 
					
						
							|  |  |  |   s_vs_disk_cache.Close(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (g_Config.bEnableShaderDebugging) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     s_gs_hlsl_cache.clear(); | 
					
						
							|  |  |  |     s_ps_hlsl_cache.clear(); | 
					
						
							|  |  |  |     s_vs_hlsl_cache.clear(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   s_geometry_uid_checker.Invalidate(); | 
					
						
							|  |  |  |   s_pixel_uid_checker.Invalidate(); | 
					
						
							|  |  |  |   s_vertex_uid_checker.Invalidate(); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShaderCache::LoadAndSetActiveShaders(DSTALPHA_MODE ps_dst_alpha_mode, u32 gs_primitive_type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SetCurrentPrimitiveTopology(gs_primitive_type); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-16 23:49:39 +13:00
										 |  |  |   GeometryShaderUid gs_uid = GetGeometryShaderUid(gs_primitive_type); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   PixelShaderUid ps_uid = GetPixelShaderUid(ps_dst_alpha_mode, API_D3D); | 
					
						
							| 
									
										
										
										
											2016-01-17 00:34:06 +13:00
										 |  |  |   VertexShaderUid vs_uid = GetVertexShaderUid(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   bool gs_changed = gs_uid != s_last_geometry_shader_uid; | 
					
						
							|  |  |  |   bool ps_changed = ps_uid != s_last_pixel_shader_uid; | 
					
						
							|  |  |  |   bool vs_changed = vs_uid != s_last_vertex_shader_uid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!gs_changed && !ps_changed && !vs_changed) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (gs_changed) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     HandleGSUIDChange(gs_uid, gs_primitive_type); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ps_changed) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     HandlePSUIDChange(ps_uid, ps_dst_alpha_mode); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (vs_changed) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     HandleVSUIDChange(vs_uid); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // A Uid has changed, so the PSO will need to be reset at next ApplyState.
 | 
					
						
							|  |  |  |   D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShaderCache::SetCurrentPrimitiveTopology(u32 gs_primitive_type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   switch (gs_primitive_type) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case PRIMITIVE_TRIANGLES: | 
					
						
							|  |  |  |     s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case PRIMITIVE_LINES: | 
					
						
							|  |  |  |     s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case PRIMITIVE_POINTS: | 
					
						
							|  |  |  |     s_current_primitive_topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     CHECK(0, "Invalid primitive type."); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShaderCache::HandleGSUIDChange(GeometryShaderUid gs_uid, u32 gs_primitive_type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_last_geometry_shader_uid = gs_uid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (g_ActiveConfig.bEnableShaderDebugging) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-01-16 23:49:39 +13:00
										 |  |  |     ShaderCode code = GenerateGeometryShaderCode(gs_primitive_type, API_D3D, gs_uid.GetUidData()); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     s_geometry_uid_checker.AddToIndexAndCheck(code, gs_uid, "Geometry", "g"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (gs_uid.GetUidData()->IsPassthrough()) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     s_last_geometry_shader_bytecode = {}; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   auto gs_iterator = s_gs_bytecode_cache.find(gs_uid); | 
					
						
							|  |  |  |   if (gs_iterator != s_gs_bytecode_cache.end()) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     s_last_geometry_shader_bytecode = gs_iterator->second; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-01-16 23:49:39 +13:00
										 |  |  |     ShaderCode gs_code = | 
					
						
							|  |  |  |         GenerateGeometryShaderCode(gs_primitive_type, API_D3D, gs_uid.GetUidData()); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     ID3DBlob* gs_bytecode = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!D3D::CompileGeometryShader(gs_code.GetBuffer(), &gs_bytecode)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s_last_geometry_shader_bytecode = InsertByteCode(gs_uid, &s_gs_bytecode_cache, gs_bytecode); | 
					
						
							|  |  |  |     s_gs_disk_cache.Append(gs_uid, reinterpret_cast<u8*>(gs_bytecode->GetBufferPointer()), | 
					
						
							|  |  |  |                            static_cast<u32>(gs_bytecode->GetBufferSize())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (g_ActiveConfig.bEnableShaderDebugging) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       s_gs_hlsl_cache[gs_uid] = gs_code.GetBuffer(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShaderCache::HandlePSUIDChange(PixelShaderUid ps_uid, DSTALPHA_MODE ps_dst_alpha_mode) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_last_pixel_shader_uid = ps_uid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (g_ActiveConfig.bEnableShaderDebugging) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ShaderCode code = GeneratePixelShaderCode(ps_dst_alpha_mode, API_D3D); | 
					
						
							|  |  |  |     s_pixel_uid_checker.AddToIndexAndCheck(code, ps_uid, "Pixel", "p"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   auto ps_iterator = s_ps_bytecode_cache.find(ps_uid); | 
					
						
							|  |  |  |   if (ps_iterator != s_ps_bytecode_cache.end()) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     s_last_pixel_shader_bytecode = ps_iterator->second; | 
					
						
							|  |  |  |     GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ShaderCode ps_code = GeneratePixelShaderCode(ps_dst_alpha_mode, API_D3D); | 
					
						
							|  |  |  |     ID3DBlob* ps_bytecode = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!D3D::CompilePixelShader(ps_code.GetBuffer(), &ps_bytecode)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s_last_pixel_shader_bytecode = InsertByteCode(ps_uid, &s_ps_bytecode_cache, ps_bytecode); | 
					
						
							|  |  |  |     s_ps_disk_cache.Append(ps_uid, reinterpret_cast<u8*>(ps_bytecode->GetBufferPointer()), | 
					
						
							|  |  |  |                            static_cast<u32>(ps_bytecode->GetBufferSize())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SETSTAT(stats.numPixelShadersAlive, static_cast<int>(s_ps_bytecode_cache.size())); | 
					
						
							|  |  |  |     INCSTAT(stats.numPixelShadersCreated); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (g_ActiveConfig.bEnableShaderDebugging) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       s_ps_hlsl_cache[ps_uid] = ps_code.GetBuffer(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShaderCache::HandleVSUIDChange(VertexShaderUid vs_uid) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_last_vertex_shader_uid = vs_uid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (g_ActiveConfig.bEnableShaderDebugging) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-01-17 00:34:06 +13:00
										 |  |  |     ShaderCode code = GenerateVertexShaderCode(API_D3D, vs_uid.GetUidData()); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     s_vertex_uid_checker.AddToIndexAndCheck(code, vs_uid, "Vertex", "v"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   auto vs_iterator = s_vs_bytecode_cache.find(vs_uid); | 
					
						
							|  |  |  |   if (vs_iterator != s_vs_bytecode_cache.end()) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     s_last_vertex_shader_bytecode = vs_iterator->second; | 
					
						
							|  |  |  |     GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-01-17 00:34:06 +13:00
										 |  |  |     ShaderCode vs_code = GenerateVertexShaderCode(API_D3D, vs_uid.GetUidData()); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     ID3DBlob* vs_bytecode = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!D3D::CompileVertexShader(vs_code.GetBuffer(), &vs_bytecode)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s_last_vertex_shader_bytecode = InsertByteCode(vs_uid, &s_vs_bytecode_cache, vs_bytecode); | 
					
						
							|  |  |  |     s_vs_disk_cache.Append(vs_uid, reinterpret_cast<u8*>(vs_bytecode->GetBufferPointer()), | 
					
						
							|  |  |  |                            static_cast<u32>(vs_bytecode->GetBufferSize())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SETSTAT(stats.numVertexShadersAlive, static_cast<int>(s_vs_bytecode_cache.size())); | 
					
						
							|  |  |  |     INCSTAT(stats.numVertexShadersCreated); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (g_ActiveConfig.bEnableShaderDebugging) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       s_vs_hlsl_cache[vs_uid] = vs_code.GetBuffer(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | template <class UidType, class ShaderCacheType> | 
					
						
							|  |  |  | D3D12_SHADER_BYTECODE ShaderCache::InsertByteCode(const UidType& uid, ShaderCacheType* shader_cache, | 
					
						
							|  |  |  |                                                   ID3DBlob* bytecode_blob) | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Note: Don't release the incoming bytecode, we need it to stick around, since in D3D12
 | 
					
						
							|  |  |  |   // the raw bytecode itself is bound. It is released at Shutdown() time.
 | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   s_shader_blob_list.push_back(bytecode_blob); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   D3D12_SHADER_BYTECODE shader_bytecode; | 
					
						
							|  |  |  |   shader_bytecode.pShaderBytecode = bytecode_blob->GetBufferPointer(); | 
					
						
							|  |  |  |   shader_bytecode.BytecodeLength = bytecode_blob->GetBufferSize(); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   (*shader_cache)[uid] = shader_bytecode; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return shader_bytecode; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | D3D12_PRIMITIVE_TOPOLOGY_TYPE ShaderCache::GetCurrentPrimitiveTopology() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return s_current_primitive_topology; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | D3D12_SHADER_BYTECODE ShaderCache::GetActiveGeometryShaderBytecode() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return s_last_geometry_shader_bytecode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | D3D12_SHADER_BYTECODE ShaderCache::GetActivePixelShaderBytecode() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return s_last_pixel_shader_bytecode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | D3D12_SHADER_BYTECODE ShaderCache::GetActiveVertexShaderBytecode() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return s_last_vertex_shader_bytecode; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | const GeometryShaderUid* ShaderCache::GetActiveGeometryShaderUid() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return &s_last_geometry_shader_uid; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | const PixelShaderUid* ShaderCache::GetActivePixelShaderUid() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return &s_last_pixel_shader_uid; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | const VertexShaderUid* ShaderCache::GetActiveVertexShaderUid() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return &s_last_vertex_shader_uid; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | D3D12_SHADER_BYTECODE ShaderCache::GetGeometryShaderFromUid(const GeometryShaderUid* uid) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   auto bytecode = s_gs_bytecode_cache.find(*uid); | 
					
						
							|  |  |  |   if (bytecode != s_gs_bytecode_cache.end()) | 
					
						
							|  |  |  |     return bytecode->second; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return D3D12_SHADER_BYTECODE(); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | D3D12_SHADER_BYTECODE ShaderCache::GetPixelShaderFromUid(const PixelShaderUid* uid) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   auto bytecode = s_ps_bytecode_cache.find(*uid); | 
					
						
							|  |  |  |   if (bytecode != s_ps_bytecode_cache.end()) | 
					
						
							|  |  |  |     return bytecode->second; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return D3D12_SHADER_BYTECODE(); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | D3D12_SHADER_BYTECODE ShaderCache::GetVertexShaderFromUid(const VertexShaderUid* uid) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   auto bytecode = s_vs_bytecode_cache.find(*uid); | 
					
						
							|  |  |  |   if (bytecode != s_vs_bytecode_cache.end()) | 
					
						
							|  |  |  |     return bytecode->second; | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return D3D12_SHADER_BYTECODE(); | 
					
						
							| 
									
										
										
										
											2016-01-07 19:40:35 -08:00
										 |  |  | } | 
					
						
							|  |  |  | } |