// Copyright 2008 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "VideoCommon/VideoConfig.h" #include #include "Common/CPUDetect.h" #include "Common/CommonTypes.h" #include "Common/StringUtil.h" #include "Core/Config/GraphicsSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/Movie.h" #include "VideoCommon/DriverDetails.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/VideoCommon.h" VideoConfig g_Config; VideoConfig g_ActiveConfig; static bool s_has_registered_callback = false; static bool IsVSyncActive(bool enabled) { // Vsync is disabled when the throttler is disabled by the tab key. return enabled && !Core::GetIsThrottlerTempDisabled() && SConfig::GetInstance().m_EmulationSpeed == 1.0; } void UpdateActiveConfig() { if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) Movie::SetGraphicsConfig(); g_ActiveConfig = g_Config; g_ActiveConfig.bVSyncActive = IsVSyncActive(g_ActiveConfig.bVSync); } void VideoConfig::Refresh() { if (!s_has_registered_callback) { // There was a race condition between the video thread and the host thread here, if // corrections need to be made by VerifyValidity(). Briefly, the config will contain // invalid values. Instead, pause emulation first, which will flush the video thread, // update the config and correct it, then resume emulation, after which the video // thread will detect the config has changed and act accordingly. Config::AddConfigChangedCallback([]() { Core::RunAsCPUThread([]() { g_Config.Refresh(); }); }); s_has_registered_callback = true; } bVSync = Config::Get(Config::GFX_VSYNC); iAdapter = Config::Get(Config::GFX_ADAPTER); bWidescreenHack = Config::Get(Config::GFX_WIDESCREEN_HACK); aspect_mode = Config::Get(Config::GFX_ASPECT_RATIO); suggested_aspect_mode = Config::Get(Config::GFX_SUGGESTED_ASPECT_RATIO); bCrop = Config::Get(Config::GFX_CROP); iSafeTextureCache_ColorSamples = Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES); bShowFPS = Config::Get(Config::GFX_SHOW_FPS); bShowNetPlayPing = Config::Get(Config::GFX_SHOW_NETPLAY_PING); bShowNetPlayMessages = Config::Get(Config::GFX_SHOW_NETPLAY_MESSAGES); bLogRenderTimeToFile = Config::Get(Config::GFX_LOG_RENDER_TIME_TO_FILE); bOverlayStats = Config::Get(Config::GFX_OVERLAY_STATS); bOverlayProjStats = Config::Get(Config::GFX_OVERLAY_PROJ_STATS); bDumpTextures = Config::Get(Config::GFX_DUMP_TEXTURES); bDumpMipmapTextures = Config::Get(Config::GFX_DUMP_MIP_TEXTURES); bDumpBaseTextures = Config::Get(Config::GFX_DUMP_BASE_TEXTURES); bHiresTextures = Config::Get(Config::GFX_HIRES_TEXTURES); bCacheHiresTextures = Config::Get(Config::GFX_CACHE_HIRES_TEXTURES); bDumpEFBTarget = Config::Get(Config::GFX_DUMP_EFB_TARGET); bDumpXFBTarget = Config::Get(Config::GFX_DUMP_XFB_TARGET); bDumpFramesAsImages = Config::Get(Config::GFX_DUMP_FRAMES_AS_IMAGES); bUseFFV1 = Config::Get(Config::GFX_USE_FFV1); sDumpFormat = Config::Get(Config::GFX_DUMP_FORMAT); sDumpCodec = Config::Get(Config::GFX_DUMP_CODEC); sDumpEncoder = Config::Get(Config::GFX_DUMP_ENCODER); sDumpPath = Config::Get(Config::GFX_DUMP_PATH); iBitrateKbps = Config::Get(Config::GFX_BITRATE_KBPS); bInternalResolutionFrameDumps = Config::Get(Config::GFX_INTERNAL_RESOLUTION_FRAME_DUMPS); bEnableGPUTextureDecoding = Config::Get(Config::GFX_ENABLE_GPU_TEXTURE_DECODING); bEnablePixelLighting = Config::Get(Config::GFX_ENABLE_PIXEL_LIGHTING); bFastDepthCalc = Config::Get(Config::GFX_FAST_DEPTH_CALC); iMultisamples = Config::Get(Config::GFX_MSAA); bSSAA = Config::Get(Config::GFX_SSAA); iEFBScale = Config::Get(Config::GFX_EFB_SCALE); bTexFmtOverlayEnable = Config::Get(Config::GFX_TEXFMT_OVERLAY_ENABLE); bTexFmtOverlayCenter = Config::Get(Config::GFX_TEXFMT_OVERLAY_CENTER); bWireFrame = Config::Get(Config::GFX_ENABLE_WIREFRAME); bDisableFog = Config::Get(Config::GFX_DISABLE_FOG); bBorderlessFullscreen = Config::Get(Config::GFX_BORDERLESS_FULLSCREEN); bEnableValidationLayer = Config::Get(Config::GFX_ENABLE_VALIDATION_LAYER); bBackendMultithreading = Config::Get(Config::GFX_BACKEND_MULTITHREADING); iCommandBufferExecuteInterval = Config::Get(Config::GFX_COMMAND_BUFFER_EXECUTE_INTERVAL); bShaderCache = Config::Get(Config::GFX_SHADER_CACHE); bWaitForShadersBeforeStarting = Config::Get(Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING); iShaderCompilationMode = Config::Get(Config::GFX_SHADER_COMPILATION_MODE); iShaderCompilerThreads = Config::Get(Config::GFX_SHADER_COMPILER_THREADS); iShaderPrecompilerThreads = Config::Get(Config::GFX_SHADER_PRECOMPILER_THREADS); bZComploc = Config::Get(Config::GFX_SW_ZCOMPLOC); bZFreeze = Config::Get(Config::GFX_SW_ZFREEZE); bDumpObjects = Config::Get(Config::GFX_SW_DUMP_OBJECTS); bDumpTevStages = Config::Get(Config::GFX_SW_DUMP_TEV_STAGES); bDumpTevTextureFetches = Config::Get(Config::GFX_SW_DUMP_TEV_TEX_FETCHES); drawStart = Config::Get(Config::GFX_SW_DRAW_START); drawEnd = Config::Get(Config::GFX_SW_DRAW_END); bForceFiltering = Config::Get(Config::GFX_ENHANCE_FORCE_FILTERING); iMaxAnisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY); sPostProcessingShader = Config::Get(Config::GFX_ENHANCE_POST_SHADER); bForceTrueColor = Config::Get(Config::GFX_ENHANCE_FORCE_TRUE_COLOR); bDisableCopyFilter = Config::Get(Config::GFX_ENHANCE_DISABLE_COPY_FILTER); bArbitraryMipmapDetection = Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION); fArbitraryMipmapDetectionThreshold = Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION_THRESHOLD); stereo_mode = Config::Get(Config::GFX_STEREO_MODE); iStereoDepth = Config::Get(Config::GFX_STEREO_DEPTH); iStereoConvergencePercentage = Config::Get(Config::GFX_STEREO_CONVERGENCE_PERCENTAGE); bStereoSwapEyes = Config::Get(Config::GFX_STEREO_SWAP_EYES); iStereoConvergence = Config::Get(Config::GFX_STEREO_CONVERGENCE); bStereoEFBMonoDepth = Config::Get(Config::GFX_STEREO_EFB_MONO_DEPTH); iStereoDepthPercentage = Config::Get(Config::GFX_STEREO_DEPTH_PERCENTAGE); bEFBAccessEnable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE); bEFBAccessDeferInvalidation = Config::Get(Config::GFX_HACK_EFB_DEFER_INVALIDATION); bBBoxEnable = Config::Get(Config::GFX_HACK_BBOX_ENABLE); bForceProgressive = Config::Get(Config::GFX_HACK_FORCE_PROGRESSIVE); bSkipEFBCopyToRam = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM); bSkipXFBCopyToRam = Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM); bDisableCopyToVRAM = Config::Get(Config::GFX_HACK_DISABLE_COPY_TO_VRAM); bDeferEFBCopies = Config::Get(Config::GFX_HACK_DEFER_EFB_COPIES); bImmediateXFB = Config::Get(Config::GFX_HACK_IMMEDIATE_XFB); bSkipPresentingDuplicateXFBs = Config::Get(Config::GFX_HACK_SKIP_DUPLICATE_XFBS); bCopyEFBScaled = Config::Get(Config::GFX_HACK_COPY_EFB_SCALED); bEFBEmulateFormatChanges = Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES); bVertexRounding = Config::Get(Config::GFX_HACK_VERTEX_ROUDING); iEFBAccessTileSize = Config::Get(Config::GFX_HACK_EFB_ACCESS_TILE_SIZE); iMissingColorValue = Config::Get(Config::GFX_HACK_MISSING_COLOR_VALUE); bFastTextureSampling = Config::Get(Config::GFX_HACK_FAST_TEXTURE_SAMPLING); bPerfQueriesEnable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE); VerifyValidity(); } void VideoConfig::VerifyValidity() { // TODO: Check iMaxAnisotropy value if (iAdapter < 0 || iAdapter > ((int)backend_info.Adapters.size() - 1)) iAdapter = 0; if (std::find(backend_info.AAModes.begin(), backend_info.AAModes.end(), iMultisamples) == backend_info.AAModes.end()) iMultisamples = 1; if (stereo_mode != StereoMode::Off) { if (!backend_info.bSupportsGeometryShaders) { OSD::AddMessage( "Stereoscopic 3D isn't supported by your GPU, support for OpenGL 3.2 is required.", 10000); stereo_mode = StereoMode::Off; } } } bool VideoConfig::UsingUberShaders() const { return iShaderCompilationMode == ShaderCompilationMode::SynchronousUberShaders || iShaderCompilationMode == ShaderCompilationMode::AsynchronousUberShaders; } static u32 GetNumAutoShaderCompilerThreads() { // Automatic number. We use clamp(cpus - 3, 1, 4). return static_cast(std::min(std::max(cpu_info.num_cores - 3, 1), 4)); } static u32 GetNumAutoShaderPreCompilerThreads() { // Automatic number. We use clamp(cpus - 2, 1, infty) here. // We chose this because we don't want to limit our speed-up // and at the same time leave two logical cores for the dolphin UI and the rest of the OS. return static_cast(std::max(cpu_info.num_cores - 2, 1)); } u32 VideoConfig::GetShaderCompilerThreads() const { if (!backend_info.bSupportsBackgroundCompiling) return 0; if (iShaderCompilerThreads >= 0) return static_cast(iShaderCompilerThreads); else return GetNumAutoShaderCompilerThreads(); } u32 VideoConfig::GetShaderPrecompilerThreads() const { // When using background compilation, always keep the same thread count. if (!bWaitForShadersBeforeStarting) return GetShaderCompilerThreads(); if (!backend_info.bSupportsBackgroundCompiling) return 0; const bool bugDatabaseSupported = backend_info.api_type == APIType::OpenGL || backend_info.api_type == APIType::Vulkan; // DirectX has always worked in our tests in PR#9414 const bool multiThreadingWorking = !bugDatabaseSupported || !DriverDetails::HasBug(DriverDetails::BUG_BROKEN_MULTITHREADED_SHADER_PRECOMPILATION); if (iShaderPrecompilerThreads >= 0) return static_cast(iShaderPrecompilerThreads); else if (multiThreadingWorking) return GetNumAutoShaderPreCompilerThreads(); else return 1; }