void DisplayMessage(const std::string& message, int time_in_ms) { if (!IsRunning()) return; OSD::AddMessage(message, time_in_ms); Host_UpdateTitle(message); }
void UpdateTitle() { u32 ElapseTime = (u32)s_timer.GetTimeDifference(); s_request_refresh_info = false; SConfig& _CoreParameter = SConfig::GetInstance(); if (ElapseTime == 0) ElapseTime = 1; float FPS = (float)(s_drawn_frame.load() * 1000.0 / ElapseTime); float VPS = (float)(s_drawn_video.load() * 1000.0 / ElapseTime); float Speed = (float)(s_drawn_video.load() * (100 * 1000.0) / (VideoInterface::GetTargetRefreshRate() * ElapseTime)); // Settings are shown the same for both extended and summary info std::string SSettings = StringFromFormat("%s %s | %s | %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC", g_video_backend->GetDisplayName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE"); std::string SFPS; if (Movie::IsPlayingInput()) SFPS = StringFromFormat("VI: %u/%u - Input: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed); else if (Movie::IsRecordingInput()) SFPS = StringFromFormat("VI: %u - Input: %u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed); else { SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed); if (SConfig::GetInstance().m_InterfaceExtendedFPSInfo) { // Use extended or summary information. The summary information does not print the ticks data, // that's more of a debugging interest, it can always be optional of course if someone is interested. static u64 ticks = 0; static u64 idleTicks = 0; u64 newTicks = CoreTiming::GetTicks(); u64 newIdleTicks = CoreTiming::GetIdleTicks(); u64 diff = (newTicks - ticks) / 1000000; u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; ticks = newTicks; idleTicks = newIdleTicks; float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100; SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)", _CoreParameter.bSkipIdle ? "~" : "", (int)(diff), (int)(diff - idleDiff), (int)(idleDiff), SystemTimers::GetTicksPerSecond() / 1000000, _CoreParameter.bSkipIdle ? "~" : "", TicksPercentage); } } // This is our final "frame counter" string std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str()); Host_UpdateTitle(SMessage); }
void DisplayMessage(const std::string& message, int time_in_ms) { // Actually displaying non-ASCII could cause things to go pear-shaped for (const char& c : message) { if (!std::isprint(c)) return; } g_video_backend->Video_AddMessage(message, time_in_ms); Host_UpdateTitle(message); }
void DisplayMessage(const std::string& message, int time_in_ms) { if (!IsRunning()) return; // Actually displaying non-ASCII could cause things to go pear-shaped for (const char& c : message) { if (!std::isprint(c)) return; } OSD::AddMessage(message, time_in_ms); Host_UpdateTitle(message); }
void DisplayMessage(const char *message, int time_in_ms) { SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; // Actually displaying non-ASCII could cause things to go pear-shaped for (const char *c = message; *c != '\0'; ++c) if (*c < ' ') return; g_video_backend->Video_AddMessage(message, time_in_ms); if (_CoreParameter.bRenderToMain && SConfig::GetInstance().m_InterfaceStatusbar) { Host_UpdateStatusBar(message); } else Host_UpdateTitle(message); }
void DisplayMessage(const std::string& message, int time_in_ms) { SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; // Actually displaying non-ASCII could cause things to go pear-shaped for (const char& c : message) { if (!std::isprint(c)) return; } g_video_backend->Video_AddMessage(message, time_in_ms); if (_CoreParameter.bRenderToMain && SConfig::GetInstance().m_InterfaceStatusbar) { Host_UpdateStatusBar(message); } else { Host_UpdateTitle(message); } }
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(); } }
})hlsl"; void VertexShaderCache::Init() { s_vshaders_lock.unlock(); s_compiler = &HLSLAsyncCompiler::getInstance(); const D3D11_INPUT_ELEMENT_DESC simpleelems[3] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 1, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 } }; const D3D11_INPUT_ELEMENT_DESC clearelems[2] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; bool use_partial_buffer_update = D3D::SupportPartialContantBufferUpdate(); u32 cbsize = VertexShaderManager::ConstantBufferSize * sizeof(float) * (use_partial_buffer_update ? 1024 : 1); // is always multiple of 16 vscbuf = new D3D::ConstantStreamBuffer(cbsize); ID3D11Buffer* buf = vscbuf->GetBuffer(); CHECK(buf != nullptr, "Create vertex shader constant buffer (size=%u)", cbsize); D3D::SetDebugObjectName(buf, "vertex shader constant buffer used to emulate the GX pipeline"); D3DBlob blob; D3D::CompileShader(D3D::ShaderType::Vertex, simple_shader_code, blob); D3D::device->CreateInputLayout(simpleelems, 3, blob.Data(), blob.Size(), D3D::ToAddr(s_simple_layout)); s_simple_vertex_shader = D3D::CreateVertexShaderFromByteCode(blob); if (s_simple_layout == nullptr || s_simple_vertex_shader == nullptr) PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__, __LINE__); D3D::SetDebugObjectName(s_simple_layout.get(), "simple input layout"); D3D::SetDebugObjectName(s_simple_vertex_shader.get(), "simple vertex shader"); D3D::CompileShader(D3D::ShaderType::Vertex, clear_shader_code, blob); D3D::device->CreateInputLayout(clearelems, 2, blob.Data(), blob.Size(), D3D::ToAddr(s_clear_layout)); s_clear_vertex_shader = D3D::CreateVertexShaderFromByteCode(blob); if (s_clear_layout == nullptr || s_clear_vertex_shader == nullptr) PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__, __LINE__); D3D::SetDebugObjectName(s_clear_vertex_shader.get(), "clear vertex shader"); D3D::SetDebugObjectName(s_clear_layout.get(), "clear input layout"); Clear(); if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str()); SETSTAT(stats.numVertexShadersCreated, 0); SETSTAT(stats.numVertexShadersAlive, 0); pKey_t gameid = (pKey_t)GetMurmurHash3(reinterpret_cast<const u8*>(SConfig::GetInstance().m_strGameID.data()), (u32)SConfig::GetInstance().m_strGameID.size(), 0); s_vshaders = VSCache::Create( gameid, VERTEXSHADERGEN_UID_VERSION, "Ishiiruka.vs", StringFromFormat("%s.vs", SConfig::GetInstance().m_strGameID.c_str()) ); std::string cache_filename = StringFromFormat("%sIDX11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), SConfig::GetInstance().m_strGameID.c_str()); VertexShaderCacheInserter inserter; g_vs_disk_cache.OpenAndRead(cache_filename, inserter); if (g_ActiveConfig.bCompileShaderOnStartup) { size_t shader_count = 0; s_vshaders->ForEachMostUsedByCategory(gameid, [&](const VertexShaderUid& it, size_t total) { VertexShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); CompileVShader(item, true); shader_count++; if ((shader_count & 7) == 0) { Host_UpdateTitle(StringFromFormat("Compiling Vertex Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total)); s_compiler->WaitForFinish(); } }, [](VSCacheEntry& entry) { return !entry.shader; } , true); s_compiler->WaitForFinish(); } s_last_entry = nullptr; }
void UpdateTitle() { u32 ElapseTime = (u32)Timer.GetTimeDifference(); g_requestRefreshInfo = false; SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; if (ElapseTime == 0) ElapseTime = 1; float FPS = (float) (Common::AtomicLoad(DrawnFrame) * 1000.0 / ElapseTime); float VPS = (float) (DrawnVideo * 1000.0 / ElapseTime); float Speed = (float) (DrawnVideo * (100 * 1000.0) / (VideoInterface::TargetRefreshRate * ElapseTime)); // Settings are shown the same for both extended and summary info std::string SSettings = StringFromFormat("%s %s | %s | %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC", g_video_backend->GetDisplayName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE"); std::string SFPS; if (Movie::IsPlayingInput()) SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed); else if (Movie::IsRecordingInput()) SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %.0f - VPS: %.0f - %.0f%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed); else { SFPS = StringFromFormat("FPS: %.0f - VPS: %.0f - %.0f%%", FPS, VPS, Speed); if (SConfig::GetInstance().m_InterfaceExtendedFPSInfo) { // Use extended or summary information. The summary information does not print the ticks data, // that's more of a debugging interest, it can always be optional of course if someone is interested. static u64 ticks = 0; static u64 idleTicks = 0; u64 newTicks = CoreTiming::GetTicks(); u64 newIdleTicks = CoreTiming::GetIdleTicks(); u64 diff = (newTicks - ticks) / 1000000; u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; ticks = newTicks; idleTicks = newIdleTicks; float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100; SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)", _CoreParameter.bSkipIdle ? "~" : "", (int)(diff), (int)(diff - idleDiff), (int)(idleDiff), SystemTimers::GetTicksPerSecond() / 1000000, _CoreParameter.bSkipIdle ? "~" : "", TicksPercentage); } } // This is our final "frame counter" string std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str()); std::string TMessage = StringFromFormat("%s | %s", scm_rev_str, SMessage.c_str()); // Show message g_video_backend->UpdateFPSDisplay(SMessage); // Update the audio timestretcher with the current speed if (soundStream) { CMixer* pMixer = soundStream->GetMixer(); pMixer->UpdateSpeed((float)Speed / 100); } if (_CoreParameter.bRenderToMain && SConfig::GetInstance().m_InterfaceStatusbar) { Host_UpdateStatusBar(SMessage); Host_UpdateTitle(scm_rev_str); } else { Host_UpdateTitle(TMessage); } }
void PixelShaderCache::Init() { s_pixel_shaders_lock.unlock(); for (u32 i = 0; i < PSRM_DEPTH_ONLY + 1; i++) { s_last_entry[i] = nullptr; } s_compiler = &HLSLAsyncCompiler::getInstance(); //program used for clear screen { char pprog[3072]; sprintf(pprog, "void main(\n" "out float4 ocol0 : COLOR0,\n" " in float4 incol0 : COLOR0){\n" "ocol0 = incol0;\n" "}\n"); s_clear_program = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); } int shaderModel = ((D3D::GetCaps().PixelShaderVersion >> 8) & 0xFF); int maxConstants = (shaderModel < 3) ? 32 : ((shaderModel < 4) ? 224 : 65536); // other screen copy/convert programs for (int copyMatrixType = 0; copyMatrixType < NUM_COPY_TYPES; copyMatrixType++) { for (int depthType = 0; depthType < NUM_DEPTH_CONVERSION_TYPES; depthType++) { for (int ssaaMode = 0; ssaaMode < MAX_SSAA_SHADERS; ssaaMode++) { if (ssaaMode && !s_copy_program[copyMatrixType][depthType][ssaaMode - 1] || depthType && !s_copy_program[copyMatrixType][depthType - 1][ssaaMode] || copyMatrixType && !s_copy_program[copyMatrixType - 1][depthType][ssaaMode]) { // if it failed at a lower setting, it's going to fail here for the same reason it did there, // so skip this attempt to avoid duplicate error messages. s_copy_program[copyMatrixType][depthType][ssaaMode] = NULL; } else { s_copy_program[copyMatrixType][depthType][ssaaMode] = CreateCopyShader(copyMatrixType, depthType, ssaaMode); } } } } Clear(); if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str()); SETSTAT(stats.numPixelShadersCreated, 0); SETSTAT(stats.numPixelShadersAlive, 0); pKey_t gameid = (pKey_t)GetMurmurHash3(reinterpret_cast<const u8*>(SConfig::GetInstance().m_strGameID.data()), (u32)SConfig::GetInstance().m_strGameID.size(), 0); s_pshaders = ObjectUsageProfiler<PixelShaderUid, pKey_t, PSCacheEntry, PixelShaderUid::ShaderUidHasher>::Create( gameid, PIXELSHADERGEN_UID_VERSION, "Ishiiruka.ps.dx9", StringFromFormat("%s.ps.dx9", SConfig::GetInstance().m_strGameID.c_str()) ); std::string cache_filename = StringFromFormat("%sIDX9-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), SConfig::GetInstance().m_strGameID.c_str()); PixelShaderCacheInserter inserter; g_ps_disk_cache.OpenAndRead(cache_filename, inserter); if (g_ActiveConfig.bCompileShaderOnStartup) { std::vector<PixelShaderUid> shaders; size_t shader_count = 0; s_pshaders->ForEachMostUsedByCategory(gameid, [&](const PixelShaderUid& item, size_t total) { PixelShaderUid newitem = item; pixel_shader_uid_data& uid_data = newitem.GetUidData<pixel_shader_uid_data>(); if (uid_data.render_mode == PSRM_DUAL_SOURCE_BLEND && !g_ActiveConfig.backend_info.bSupportsDualSourceBlend) { uid_data.render_mode = PSRM_DEFAULT; newitem.ClearHASH(); newitem.CalculateUIDHash(); CompilePShader(newitem, PIXEL_SHADER_RENDER_MODE::PSRM_DEFAULT, true); uid_data.render_mode = PSRM_ALPHA_PASS; uid_data.fog_proj = 0; uid_data.fog_RangeBaseEnabled = 0; newitem.ClearHASH(); newitem.CalculateUIDHash(); CompilePShader(newitem, PIXEL_SHADER_RENDER_MODE::PSRM_ALPHA_PASS, true); } else { newitem.ClearHASH(); newitem.CalculateUIDHash(); CompilePShader(newitem, PIXEL_SHADER_RENDER_MODE::PSRM_DEFAULT, 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(); } }, [](PSCacheEntry& entry) { return !entry.shader; }, true); s_compiler->WaitForFinish(); } }
)hlsl"; void GeometryShaderCache::Init() { s_compiler = &HLSLAsyncCompiler::getInstance(); s_geometry_shaders_lock.unlock(); bool use_partial_buffer_update = D3D::SupportPartialContantBufferUpdate(); u32 gbsize = static_cast<u32>(Common::AlignUpSizePow2(sizeof(GeometryShaderConstants), 16) * (use_partial_buffer_update ? 1024 : 1)); // must be a multiple of 16 gscbuf = new D3D::ConstantStreamBuffer(gbsize); ID3D11Buffer* buf = gscbuf->GetBuffer(); CHECK(buf != nullptr, "Create geometry shader constant buffer (size=%u)", gbsize); D3D::SetDebugObjectName(buf, "geometry shader constant buffer used to emulate the GX pipeline"); // used when drawing clear quads ClearGeometryShader = D3D::CompileAndCreateGeometryShader(gs_clear_shader_code); CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader"); D3D::SetDebugObjectName(ClearGeometryShader.get(), "clear geometry shader"); // used for buffer copy CopyGeometryShader = D3D::CompileAndCreateGeometryShader(gs_copy_shader_code); CHECK(CopyGeometryShader != nullptr, "Create copy geometry shader"); D3D::SetDebugObjectName(CopyGeometryShader.get(), "copy geometry shader"); Clear(); if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); pKey_t gameid = (pKey_t)GetMurmurHash3(reinterpret_cast<const u8*>(SConfig::GetInstance().m_strGameID.data()), (u32)SConfig::GetInstance().m_strGameID.size(), 0); s_geometry_shaders = GSCache::Create( gameid, GEOMETRYSHADERGEN_UID_VERSION, "Ishiiruka.gs", StringFromFormat("%s.gs", SConfig::GetInstance().m_strGameID.c_str()) ); std::string cache_filename = StringFromFormat("%sIDX11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), SConfig::GetInstance().m_strGameID.c_str()); GeometryShaderCacheInserter inserter; g_gs_disk_cache.OpenAndRead(cache_filename, inserter); if (g_ActiveConfig.bCompileShaderOnStartup) { size_t shader_count = 0; s_geometry_shaders->ForEachMostUsedByCategory(gameid, [&](const GeometryShaderUid& it, size_t total) { GeometryShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); CompileGShader(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(); } }, [](GSCacheEntry& entry) { return !entry.shader; } , true); s_compiler->WaitForFinish(); } s_last_entry = nullptr; }
// Apply Frame Limit and Display FPS info // This should only be called from VI void VideoThrottle() { u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 2) ? (SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate; // Disable the frame-limiter when the throttle (Tab) key is held down. Audio throttle: m_Framelimit = 2 if (SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t')) { u32 frametime = ((SConfig::GetInstance().b_UseFPS)? Common::AtomicLoad(DrawnFrame) : DrawnVideo) * 1000 / TargetVPS; u32 timeDifference = (u32)Timer.GetTimeDifference(); if (timeDifference < frametime) { Common::SleepCurrentThread(frametime - timeDifference - 1); } while ((u32)Timer.GetTimeDifference() < frametime) Common::YieldCPU(); //Common::SleepCurrentThread(1); } // Update info per second u32 ElapseTime = (u32)Timer.GetTimeDifference(); if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo) { g_requestRefreshInfo = false; SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; if (ElapseTime == 0) ElapseTime = 1; u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime; u32 VPS = DrawnVideo * 1000 / ElapseTime; u32 Speed = DrawnVideo * (100 * 1000) / (VideoInterface::TargetRefreshRate * ElapseTime); // Settings are shown the same for both extended and summary info std::string SSettings = StringFromFormat("%s %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC"); // Use extended or summary information. The summary information does not print the ticks data, // that's more of a debugging interest, it can always be optional of course if someone is interested. //#define EXTENDED_INFO #ifdef EXTENDED_INFO u64 newTicks = CoreTiming::GetTicks(); u64 newIdleTicks = CoreTiming::GetIdleTicks(); u64 diff = (newTicks - ticks) / 1000000; u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; ticks = newTicks; idleTicks = newIdleTicks; float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100; std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed); SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)", _CoreParameter.bSkipIdle ? "~" : "", (int)(diff), (int)(diff - idleDiff), (int)(idleDiff), SystemTimers::GetTicksPerSecond() / 1000000, _CoreParameter.bSkipIdle ? "~" : "", TicksPercentage); #else // Summary information std::string SFPS; if (Movie::IsPlayingInput()) SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed); else if (Movie::IsRecordingInput()) SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed); else SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed); #endif // This is our final "frame counter" string std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str()); std::string TMessage = StringFromFormat("%s | ", scm_rev_str) + SMessage; // Show message g_video_backend->UpdateFPSDisplay(SMessage.c_str()); if (_CoreParameter.bRenderToMain && SConfig::GetInstance().m_InterfaceStatusbar) { Host_UpdateStatusBar(SMessage.c_str()); Host_UpdateTitle(scm_rev_str); } else Host_UpdateTitle(TMessage.c_str()); // Reset counter Timer.Update(); Common::AtomicStore(DrawnFrame, 0); DrawnVideo = 0; } DrawnVideo++; }