void ShaderCache::LoadAndSetActiveShaders(DSTALPHA_MODE ps_dst_alpha_mode, u32 gs_primitive_type) { SetCurrentPrimitiveTopology(gs_primitive_type); GeometryShaderUid gs_uid = GetGeometryShaderUid(gs_primitive_type); PixelShaderUid ps_uid = GetPixelShaderUid(ps_dst_alpha_mode); VertexShaderUid vs_uid = GetVertexShaderUid(); 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); }
void ShaderCache::PrepareShaders(PIXEL_SHADER_RENDER_MODE render_mode, u32 gs_primitive_type, u32 components, const XFMemory &xfr, const BPMemory &bpm, bool on_gpu_thread) { SetCurrentPrimitiveTopology(gs_primitive_type); GeometryShaderUid gs_uid; GetGeometryShaderUid(gs_uid, gs_primitive_type, xfr, components); PixelShaderUid ps_uid; GetPixelShaderUID(ps_uid, render_mode, components, xfr, bpm); VertexShaderUid vs_uid; GetVertexShaderUID(vs_uid, components, xfr, bpm); TessellationShaderUid ts_uid; bool tessellationenabled = false; if (gs_primitive_type == PrimitiveType::PRIMITIVE_TRIANGLES && g_ActiveConfig.TessellationEnabled() && xfr.projection.type == GX_PERSPECTIVE && (g_ActiveConfig.bForcedLighting || g_ActiveConfig.PixelLightingEnabled(xfr, components))) { GetTessellationShaderUID(ts_uid, xfr, bpm, components); tessellationenabled = true; } bool gs_changed = false; bool ps_changed = false; bool vs_changed = false; bool ts_changed = false; if (on_gpu_thread) { s_compiler->ProcCompilationResults(); gs_changed = gs_uid != s_last_geometry_shader_uid; ps_changed = ps_uid != s_last_pixel_shader_uid; vs_changed = vs_uid != s_last_vertex_shader_uid; ts_changed = tessellationenabled && ts_uid != s_last_tessellation_shader_uid; } else { gs_changed = gs_uid != s_last_cpu_geometry_shader_uid; ps_changed = ps_uid != s_last_cpu_pixel_shader_uid; vs_changed = vs_uid != s_last_cpu_vertex_shader_uid; ts_changed = tessellationenabled && ts_uid != s_last_cpu_tessellation_shader_uid; } if (!gs_changed && !ps_changed && !vs_changed && !ts_changed) { return; } if (on_gpu_thread) { if (gs_changed) { s_last_geometry_shader_uid = gs_uid; } if (ps_changed) { s_last_pixel_shader_uid = ps_uid; } if (vs_changed) { s_last_vertex_shader_uid = vs_uid; } if (ts_changed) { s_last_tessellation_shader_uid = ts_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); } else { if (gs_changed) { s_last_cpu_geometry_shader_uid = gs_uid; } if (ps_changed) { s_last_cpu_pixel_shader_uid = ps_uid; } if (vs_changed) { s_last_cpu_vertex_shader_uid = vs_uid; } if (ts_changed) { s_last_cpu_tessellation_shader_uid = ts_uid; } } if (vs_changed) { HandleVSUIDChange(vs_uid, on_gpu_thread); } if (ts_changed) { HandleTSUIDChange(ts_uid, on_gpu_thread); } else { if (on_gpu_thread) { s_last_domain_shader_bytecode = &s_pass_entry; s_last_hull_shader_bytecode = &s_pass_entry; } } if (gs_changed) { HandleGSUIDChange(gs_uid, on_gpu_thread); } if (ps_changed) { HandlePSUIDChange(ps_uid, on_gpu_thread); } }
void ShaderCache::Init() { s_compiler = &HLSLAsyncCompiler::getInstance(); s_shaders_lock.unlock(); s_pass_entry.m_compiled = true; s_pass_entry.m_initialized.test_and_set(); // This class intentionally shares its shader cache files with DX11, as the shaders are (right now) identical. // Reduces unnecessary compilation when switching between APIs. s_last_domain_shader_bytecode = &s_pass_entry; s_last_hull_shader_bytecode = &s_pass_entry; s_last_geometry_shader_bytecode = &s_pass_entry; s_last_pixel_shader_bytecode = nullptr; s_last_vertex_shader_bytecode = nullptr; s_last_geometry_shader_uid = {}; s_last_pixel_shader_uid = {}; s_last_vertex_shader_uid = {}; s_last_tessellation_shader_uid = {}; s_last_cpu_geometry_shader_uid = {}; s_last_cpu_pixel_shader_uid = {}; s_last_cpu_vertex_shader_uid = {}; s_last_cpu_tessellation_shader_uid = {}; // Ensure shader cache directory exists.. std::string shader_cache_path = File::GetUserPath(D_SHADERCACHE_IDX); if (!File::Exists(shader_cache_path)) File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); std::string title_unique_id = SConfig::GetInstance().m_strGameID; std::string ds_cache_filename = StringFromFormat("%sIDX11-%s-ds.cache", shader_cache_path.c_str(), title_unique_id.c_str()); std::string hs_cache_filename = StringFromFormat("%sIDX11-%s-hs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); std::string gs_cache_filename = StringFromFormat("%sIDX11-%s-gs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); std::string ps_cache_filename = StringFromFormat("%sIDX11-%s-ps.cache", shader_cache_path.c_str(), title_unique_id.c_str()); std::string vs_cache_filename = StringFromFormat("%sIDX11-%s-vs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); pKey_t gameid = (pKey_t)GetMurmurHash3(reinterpret_cast<const u8*>(SConfig::GetInstance().m_strGameID.data()), (u32)SConfig::GetInstance().m_strGameID.size(), 0); vs_bytecode_cache = VsBytecodeCache::Create( gameid, VERTEXSHADERGEN_UID_VERSION, "Ishiiruka.vs", StringFromFormat("%s.vs", title_unique_id.c_str()) ); ps_bytecode_cache = PsBytecodeCache::Create( gameid, PIXELSHADERGEN_UID_VERSION, "Ishiiruka.ps", StringFromFormat("%s.ps", title_unique_id.c_str()) ); gs_bytecode_cache = GsBytecodeCache::Create( gameid, GEOMETRYSHADERGEN_UID_VERSION, "Ishiiruka.gs", StringFromFormat("%s.gs", title_unique_id.c_str()) ); ts_bytecode_cache = TsBytecodeCache::Create( gameid, TESSELLATIONSHADERGEN_UID_VERSION, "Ishiiruka.ts", StringFromFormat("%s.ts", title_unique_id.c_str()) ); DShaderCacheInserter ds_inserter; s_ds_disk_cache.OpenAndRead(ds_cache_filename, ds_inserter); HShaderCacheInserter hs_inserter; s_hs_disk_cache.OpenAndRead(hs_cache_filename, hs_inserter); ShaderCacheInserter<GeometryShaderUid, GsBytecodeCache, &gs_bytecode_cache> gs_inserter; s_gs_disk_cache.OpenAndRead(gs_cache_filename, gs_inserter); ShaderCacheInserter<PixelShaderUid, PsBytecodeCache, &ps_bytecode_cache> ps_inserter; s_ps_disk_cache.OpenAndRead(ps_cache_filename, ps_inserter); ShaderCacheInserter<VertexShaderUid, VsBytecodeCache, &vs_bytecode_cache> vs_inserter; s_vs_disk_cache.OpenAndRead(vs_cache_filename, vs_inserter); // Clear out disk cache when debugging shaders to ensure stale ones don't stick around.. SETSTAT(stats.numGeometryShadersAlive, static_cast<int>(gs_bytecode_cache->size())); SETSTAT(stats.numGeometryShadersCreated, 0); SETSTAT(stats.numPixelShadersAlive, static_cast<int>(ps_bytecode_cache->size())); SETSTAT(stats.numPixelShadersCreated, 0); SETSTAT(stats.numVertexShadersAlive, static_cast<int>(vs_bytecode_cache->size())); SETSTAT(stats.numVertexShadersCreated, 0); if (g_ActiveConfig.bCompileShaderOnStartup) { size_t shader_count = 0; ps_bytecode_cache->ForEachMostUsedByCategory(gameid, [&](const PixelShaderUid& it, size_t total) { PixelShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); HandlePSUIDChange(item, true); shader_count++; if ((shader_count & 7) == 0) { Host_UpdateTitle(StringFromFormat("Compiling Pixel Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total)); s_compiler->WaitForFinish(); } }, [](ByteCodeCacheEntry& entry) { return !entry.m_shader_bytecode.pShaderBytecode; } , true); shader_count = 0; vs_bytecode_cache->ForEachMostUsedByCategory(gameid, [&](const VertexShaderUid& it, size_t total) { VertexShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); HandleVSUIDChange(item, true); shader_count++; if ((shader_count & 31) == 0) { Host_UpdateTitle(StringFromFormat("Compiling Vertex Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total)); s_compiler->WaitForFinish(); } }, [](ByteCodeCacheEntry& entry) { return !entry.m_shader_bytecode.pShaderBytecode; } , true); shader_count = 0; gs_bytecode_cache->ForEachMostUsedByCategory(gameid, [&](const GeometryShaderUid& it, size_t total) { GeometryShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); HandleGSUIDChange(item, true); shader_count++; if ((shader_count & 7) == 0) { Host_UpdateTitle(StringFromFormat("Compiling Geometry Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total)); s_compiler->WaitForFinish(); } }, [](ByteCodeCacheEntry& entry) { return !entry.m_shader_bytecode.pShaderBytecode; } , true); shader_count = 0; ts_bytecode_cache->ForEachMostUsedByCategory(gameid, [&](const TessellationShaderUid& it, size_t total) { TessellationShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); HandleTSUIDChange(item, true); shader_count++; if ((shader_count & 31) == 0) { Host_UpdateTitle(StringFromFormat("Compiling Tessellation Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total)); s_compiler->WaitForFinish(); } }, [](std::pair<ByteCodeCacheEntry, ByteCodeCacheEntry>& entry) { return !entry.first.m_shader_bytecode.pShaderBytecode; } , true); s_compiler->WaitForFinish(); } }