mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-19 20:41:16 +01:00
2f1a7cbee1
Skip ubershader mode works the same as hybrid ubershaders in that the shaders are compiled asynchronously. However, instead of using the ubershader to draw the object, it skips it entirely until the specialized shader is made available. This mode will likely result in broken effects where a game creates an EFB copy, and does not redraw it every frame. Therefore, it is not a recommended option, however, it may result in better performance on low-end systems.
285 lines
10 KiB
C++
285 lines
10 KiB
C++
#include "Core/Analytics.h"
|
|
|
|
#include <cinttypes>
|
|
#include <mbedtls/sha1.h>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <random>
|
|
#include <string>
|
|
|
|
#if defined(_WIN32)
|
|
#include <windows.h>
|
|
#elif defined(__APPLE__)
|
|
#include <CoreServices/CoreServices.h>
|
|
#endif
|
|
|
|
#include "Common/Analytics.h"
|
|
#include "Common/CPUDetect.h"
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/StringUtil.h"
|
|
#include "Common/Version.h"
|
|
#include "Core/ConfigManager.h"
|
|
#include "Core/HW/GCPad.h"
|
|
#include "Core/Movie.h"
|
|
#include "Core/NetPlayProto.h"
|
|
#include "InputCommon/GCAdapter.h"
|
|
#include "InputCommon/InputConfig.h"
|
|
#include "VideoCommon/VideoBackendBase.h"
|
|
#include "VideoCommon/VideoConfig.h"
|
|
|
|
namespace
|
|
{
|
|
constexpr const char* ANALYTICS_ENDPOINT = "https://analytics.dolphin-emu.org/report";
|
|
} // namespace
|
|
|
|
std::mutex DolphinAnalytics::s_instance_mutex;
|
|
std::shared_ptr<DolphinAnalytics> DolphinAnalytics::s_instance;
|
|
|
|
DolphinAnalytics::DolphinAnalytics()
|
|
{
|
|
ReloadConfig();
|
|
MakeBaseBuilder();
|
|
}
|
|
|
|
std::shared_ptr<DolphinAnalytics> DolphinAnalytics::Instance()
|
|
{
|
|
std::lock_guard<std::mutex> lk(s_instance_mutex);
|
|
if (!s_instance)
|
|
{
|
|
s_instance.reset(new DolphinAnalytics());
|
|
}
|
|
return s_instance;
|
|
}
|
|
|
|
void DolphinAnalytics::ReloadConfig()
|
|
{
|
|
std::lock_guard<std::mutex> lk(m_reporter_mutex);
|
|
|
|
// Install the HTTP backend if analytics support is enabled.
|
|
std::unique_ptr<Common::AnalyticsReportingBackend> new_backend;
|
|
if (SConfig::GetInstance().m_analytics_enabled)
|
|
{
|
|
new_backend = std::make_unique<Common::HttpAnalyticsBackend>(ANALYTICS_ENDPOINT);
|
|
}
|
|
m_reporter.SetBackend(std::move(new_backend));
|
|
|
|
// Load the unique ID or generate it if needed.
|
|
m_unique_id = SConfig::GetInstance().m_analytics_id;
|
|
if (m_unique_id.empty())
|
|
{
|
|
GenerateNewIdentity();
|
|
}
|
|
}
|
|
|
|
void DolphinAnalytics::GenerateNewIdentity()
|
|
{
|
|
std::random_device rd;
|
|
u64 id_high = (static_cast<u64>(rd()) << 32) | rd();
|
|
u64 id_low = (static_cast<u64>(rd()) << 32) | rd();
|
|
m_unique_id = StringFromFormat("%016" PRIx64 "%016" PRIx64, id_high, id_low);
|
|
|
|
// Save the new id in the configuration.
|
|
SConfig::GetInstance().m_analytics_id = m_unique_id;
|
|
SConfig::GetInstance().SaveSettings();
|
|
}
|
|
|
|
std::string DolphinAnalytics::MakeUniqueId(const std::string& data)
|
|
{
|
|
u8 digest[20];
|
|
std::string input = m_unique_id + data;
|
|
mbedtls_sha1(reinterpret_cast<const u8*>(input.c_str()), input.size(), digest);
|
|
|
|
// Convert to hex string and truncate to 64 bits.
|
|
std::string out;
|
|
for (int i = 0; i < 8; ++i)
|
|
{
|
|
out += StringFromFormat("%02hhx", digest[i]);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
void DolphinAnalytics::ReportDolphinStart(const std::string& ui_type)
|
|
{
|
|
Common::AnalyticsReportBuilder builder(m_base_builder);
|
|
builder.AddData("type", "dolphin-start");
|
|
builder.AddData("ui-type", ui_type);
|
|
builder.AddData("id", MakeUniqueId("dolphin-start"));
|
|
Send(builder);
|
|
}
|
|
|
|
void DolphinAnalytics::ReportGameStart()
|
|
{
|
|
MakePerGameBuilder();
|
|
|
|
Common::AnalyticsReportBuilder builder(m_per_game_builder);
|
|
builder.AddData("type", "game-start");
|
|
Send(builder);
|
|
}
|
|
|
|
void DolphinAnalytics::MakeBaseBuilder()
|
|
{
|
|
Common::AnalyticsReportBuilder builder;
|
|
|
|
// Version information.
|
|
builder.AddData("version-desc", Common::scm_desc_str);
|
|
builder.AddData("version-hash", Common::scm_rev_git_str);
|
|
builder.AddData("version-branch", Common::scm_branch_str);
|
|
builder.AddData("version-dist", Common::scm_distributor_str);
|
|
|
|
// CPU information.
|
|
builder.AddData("cpu-summary", cpu_info.Summarize());
|
|
|
|
// OS information.
|
|
#if defined(_WIN32)
|
|
builder.AddData("os-type", "windows");
|
|
|
|
// Windows 8 removes support for GetVersionEx and such. Stupid.
|
|
DWORD(WINAPI * RtlGetVersion)(LPOSVERSIONINFOEXW);
|
|
*(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlGetVersion");
|
|
|
|
OSVERSIONINFOEXW winver;
|
|
winver.dwOSVersionInfoSize = sizeof(winver);
|
|
if (RtlGetVersion != nullptr)
|
|
{
|
|
RtlGetVersion(&winver);
|
|
builder.AddData("win-ver-major", static_cast<u32>(winver.dwMajorVersion));
|
|
builder.AddData("win-ver-minor", static_cast<u32>(winver.dwMinorVersion));
|
|
builder.AddData("win-ver-build", static_cast<u32>(winver.dwBuildNumber));
|
|
builder.AddData("win-ver-spmajor", static_cast<u32>(winver.wServicePackMajor));
|
|
builder.AddData("win-ver-spminor", static_cast<u32>(winver.wServicePackMinor));
|
|
}
|
|
#elif defined(ANDROID)
|
|
builder.AddData("os-type", "android");
|
|
#elif defined(__APPLE__)
|
|
builder.AddData("os-type", "osx");
|
|
|
|
SInt32 osxmajor, osxminor, osxbugfix;
|
|
// Gestalt is deprecated, but the replacement (NSProcessInfo
|
|
// operatingSystemVersion) is only available on OS X 10.10, so we need to use
|
|
// it anyway. Change this someday when Dolphin depends on 10.10+.
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
Gestalt(gestaltSystemVersionMajor, &osxmajor);
|
|
Gestalt(gestaltSystemVersionMinor, &osxminor);
|
|
Gestalt(gestaltSystemVersionBugFix, &osxbugfix);
|
|
#pragma GCC diagnostic pop
|
|
|
|
builder.AddData("osx-ver-major", osxmajor);
|
|
builder.AddData("osx-ver-minor", osxminor);
|
|
builder.AddData("osx-ver-bugfix", osxbugfix);
|
|
#elif defined(__linux__)
|
|
builder.AddData("os-type", "linux");
|
|
#elif defined(__FreeBSD__)
|
|
builder.AddData("os-type", "freebsd");
|
|
#else
|
|
builder.AddData("os-type", "unknown");
|
|
#endif
|
|
|
|
m_base_builder = builder;
|
|
}
|
|
|
|
static const char* GetShaderCompilationMode(const VideoConfig& video_config)
|
|
{
|
|
switch (video_config.iShaderCompilationMode)
|
|
{
|
|
case ShaderCompilationMode::AsynchronousUberShaders:
|
|
return "async-ubershaders";
|
|
case ShaderCompilationMode::AsynchronousSkipRendering:
|
|
return "async-skip-rendering";
|
|
case ShaderCompilationMode::SynchronousUberShaders:
|
|
return "sync-ubershaders";
|
|
case ShaderCompilationMode::Synchronous:
|
|
default:
|
|
return "sync";
|
|
}
|
|
}
|
|
|
|
void DolphinAnalytics::MakePerGameBuilder()
|
|
{
|
|
Common::AnalyticsReportBuilder builder(m_base_builder);
|
|
|
|
// Gameid.
|
|
builder.AddData("gameid", SConfig::GetInstance().GetGameID());
|
|
|
|
// Unique id bound to the gameid.
|
|
builder.AddData("id", MakeUniqueId(SConfig::GetInstance().GetGameID()));
|
|
|
|
// Configuration.
|
|
builder.AddData("cfg-dsp-hle", SConfig::GetInstance().bDSPHLE);
|
|
builder.AddData("cfg-dsp-jit", SConfig::GetInstance().m_DSPEnableJIT);
|
|
builder.AddData("cfg-dsp-thread", SConfig::GetInstance().bDSPThread);
|
|
builder.AddData("cfg-cpu-thread", SConfig::GetInstance().bCPUThread);
|
|
builder.AddData("cfg-fastmem", SConfig::GetInstance().bFastmem);
|
|
builder.AddData("cfg-syncgpu", SConfig::GetInstance().bSyncGPU);
|
|
builder.AddData("cfg-audio-backend", SConfig::GetInstance().sBackend);
|
|
builder.AddData("cfg-oc-enable", SConfig::GetInstance().m_OCEnable);
|
|
builder.AddData("cfg-oc-factor", SConfig::GetInstance().m_OCFactor);
|
|
builder.AddData("cfg-render-to-main", SConfig::GetInstance().bRenderToMain);
|
|
if (g_video_backend)
|
|
{
|
|
builder.AddData("cfg-video-backend", g_video_backend->GetName());
|
|
}
|
|
|
|
// Video configuration.
|
|
builder.AddData("cfg-gfx-multisamples", g_Config.iMultisamples);
|
|
builder.AddData("cfg-gfx-ssaa", g_Config.bSSAA);
|
|
builder.AddData("cfg-gfx-anisotropy", g_Config.iMaxAnisotropy);
|
|
builder.AddData("cfg-gfx-vsync", g_Config.bVSync);
|
|
builder.AddData("cfg-gfx-aspect-ratio", static_cast<int>(g_Config.aspect_mode));
|
|
builder.AddData("cfg-gfx-efb-access", g_Config.bEFBAccessEnable);
|
|
builder.AddData("cfg-gfx-efb-copy-format-changes", g_Config.bEFBEmulateFormatChanges);
|
|
builder.AddData("cfg-gfx-efb-copy-ram", !g_Config.bSkipEFBCopyToRam);
|
|
builder.AddData("cfg-gfx-xfb-copy-ram", !g_Config.bSkipXFBCopyToRam);
|
|
builder.AddData("cfg-gfx-immediate-xfb", !g_Config.bImmediateXFB);
|
|
builder.AddData("cfg-gfx-efb-copy-scaled", g_Config.bCopyEFBScaled);
|
|
builder.AddData("cfg-gfx-internal-resolution", g_Config.iEFBScale);
|
|
builder.AddData("cfg-gfx-tc-samples", g_Config.iSafeTextureCache_ColorSamples);
|
|
builder.AddData("cfg-gfx-stereo-mode", static_cast<int>(g_Config.stereo_mode));
|
|
builder.AddData("cfg-gfx-per-pixel-lighting", g_Config.bEnablePixelLighting);
|
|
builder.AddData("cfg-gfx-shader-compilation-mode", GetShaderCompilationMode(g_Config));
|
|
builder.AddData("cfg-gfx-wait-for-shaders", g_Config.bWaitForShadersBeforeStarting);
|
|
builder.AddData("cfg-gfx-fast-depth", g_Config.bFastDepthCalc);
|
|
builder.AddData("cfg-gfx-vertex-rounding", g_Config.UseVertexRounding());
|
|
|
|
// GPU features.
|
|
if (g_Config.iAdapter < static_cast<int>(g_Config.backend_info.Adapters.size()))
|
|
{
|
|
builder.AddData("gpu-adapter", g_Config.backend_info.Adapters[g_Config.iAdapter]);
|
|
}
|
|
else if (!g_Config.backend_info.AdapterName.empty())
|
|
{
|
|
builder.AddData("gpu-adapter", g_Config.backend_info.AdapterName);
|
|
}
|
|
builder.AddData("gpu-has-exclusive-fullscreen",
|
|
g_Config.backend_info.bSupportsExclusiveFullscreen);
|
|
builder.AddData("gpu-has-dual-source-blend", g_Config.backend_info.bSupportsDualSourceBlend);
|
|
builder.AddData("gpu-has-primitive-restart", g_Config.backend_info.bSupportsPrimitiveRestart);
|
|
builder.AddData("gpu-has-oversized-viewports", g_Config.backend_info.bSupportsOversizedViewports);
|
|
builder.AddData("gpu-has-geometry-shaders", g_Config.backend_info.bSupportsGeometryShaders);
|
|
builder.AddData("gpu-has-3d-vision", g_Config.backend_info.bSupports3DVision);
|
|
builder.AddData("gpu-has-early-z", g_Config.backend_info.bSupportsEarlyZ);
|
|
builder.AddData("gpu-has-binding-layout", g_Config.backend_info.bSupportsBindingLayout);
|
|
builder.AddData("gpu-has-bbox", g_Config.backend_info.bSupportsBBox);
|
|
builder.AddData("gpu-has-fragment-stores-and-atomics",
|
|
g_Config.backend_info.bSupportsFragmentStoresAndAtomics);
|
|
builder.AddData("gpu-has-gs-instancing", g_Config.backend_info.bSupportsGSInstancing);
|
|
builder.AddData("gpu-has-post-processing", g_Config.backend_info.bSupportsPostProcessing);
|
|
builder.AddData("gpu-has-palette-conversion", g_Config.backend_info.bSupportsPaletteConversion);
|
|
builder.AddData("gpu-has-clip-control", g_Config.backend_info.bSupportsClipControl);
|
|
builder.AddData("gpu-has-ssaa", g_Config.backend_info.bSupportsSSAA);
|
|
|
|
// NetPlay / recording.
|
|
builder.AddData("netplay", NetPlay::IsNetPlayRunning());
|
|
builder.AddData("movie", Movie::IsMovieActive());
|
|
|
|
// Controller information
|
|
// We grab enough to tell what percentage of our users are playing with keyboard/mouse, some kind
|
|
// of gamepad
|
|
// or the official gamecube adapter.
|
|
builder.AddData("gcadapter-detected", GCAdapter::IsDetected());
|
|
builder.AddData("has-controller", Pad::GetConfig()->IsControllerControlledByGamepadDevice(0) ||
|
|
GCAdapter::IsDetected());
|
|
|
|
m_per_game_builder = builder;
|
|
}
|