dolphin/Source/Core/VideoCommon/VideoConfig.cpp
Lioncash cac66317aa VideoCommon/Statistics: Remove global system accessor from s_after_frame_event
Instead, we make the event take a reference to the system and then pass
it in when the event is triggered.

This does introduce two other accessors, but these are much easier to
refactor out over time, and without modification to the existing event
interface.
2024-01-31 13:12:09 -05:00

400 lines
17 KiB
C++

// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoCommon/VideoConfig.h"
#include <algorithm>
#include "Common/CPUDetect.h"
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Core/CPUThreadConfigCallback.h"
#include "Core/Config/GraphicsSettings.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/Movie.h"
#include "Core/System.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/DriverDetails.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/FreeLookCamera.h"
#include "VideoCommon/GraphicsModSystem/Config/GraphicsMod.h"
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/ShaderGenCommon.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/VertexManagerBase.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() &&
Config::Get(Config::MAIN_EMULATION_SPEED) == 1.0;
}
void UpdateActiveConfig()
{
auto& movie = Core::System::GetInstance().GetMovie();
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 the video thread first, update the config and correct
// it, then resume emulation, after which the video thread will detect the config has
// changed and act accordingly.
CPUThreadConfigCallback::AddConfigChangedCallback([]() {
auto& system = Core::System::GetInstance();
const bool lock_gpu_thread = Core::IsRunningAndStarted();
if (lock_gpu_thread)
system.GetFifo().PauseAndLock(true, false);
g_Config.Refresh();
g_Config.VerifyValidity();
if (lock_gpu_thread)
system.GetFifo().PauseAndLock(false, true);
});
s_has_registered_callback = true;
}
bVSync = Config::Get(Config::GFX_VSYNC);
iAdapter = Config::Get(Config::GFX_ADAPTER);
iManuallyUploadBuffers = Config::Get(Config::GFX_MTL_MANUALLY_UPLOAD_BUFFERS);
iUsePresentDrawable = Config::Get(Config::GFX_MTL_USE_PRESENT_DRAWABLE);
bWidescreenHack = Config::Get(Config::GFX_WIDESCREEN_HACK);
aspect_mode = Config::Get(Config::GFX_ASPECT_RATIO);
custom_aspect_width = Config::Get(Config::GFX_CUSTOM_ASPECT_RATIO_WIDTH);
custom_aspect_height = Config::Get(Config::GFX_CUSTOM_ASPECT_RATIO_HEIGHT);
suggested_aspect_mode = Config::Get(Config::GFX_SUGGESTED_ASPECT_RATIO);
widescreen_heuristic_transition_threshold =
Config::Get(Config::GFX_WIDESCREEN_HEURISTIC_TRANSITION_THRESHOLD);
widescreen_heuristic_aspect_ratio_slop =
Config::Get(Config::GFX_WIDESCREEN_HEURISTIC_ASPECT_RATIO_SLOP);
widescreen_heuristic_standard_ratio =
Config::Get(Config::GFX_WIDESCREEN_HEURISTIC_STANDARD_RATIO);
widescreen_heuristic_widescreen_ratio =
Config::Get(Config::GFX_WIDESCREEN_HEURISTIC_WIDESCREEN_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);
bShowFTimes = Config::Get(Config::GFX_SHOW_FTIMES);
bShowVPS = Config::Get(Config::GFX_SHOW_VPS);
bShowVTimes = Config::Get(Config::GFX_SHOW_VTIMES);
bShowGraphs = Config::Get(Config::GFX_SHOW_GRAPHS);
bShowSpeed = Config::Get(Config::GFX_SHOW_SPEED);
bShowSpeedColors = Config::Get(Config::GFX_SHOW_SPEED_COLORS);
iPerfSampleUSec = Config::Get(Config::GFX_PERF_SAMP_WINDOW) * 1000;
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);
bOverlayScissorStats = Config::Get(Config::GFX_OVERLAY_SCISSOR_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);
sDumpPixelFormat = Config::Get(Config::GFX_DUMP_PIXEL_FORMAT);
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);
bPreferVSForLinePointExpansion = Config::Get(Config::GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION);
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);
bCPUCull = Config::Get(Config::GFX_CPU_CULL);
texture_filtering_mode = Config::Get(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING);
iMaxAnisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY);
output_resampling_mode = Config::Get(Config::GFX_ENHANCE_OUTPUT_RESAMPLING);
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);
bHDR = Config::Get(Config::GFX_ENHANCE_HDR_OUTPUT);
color_correction.bCorrectColorSpace = Config::Get(Config::GFX_CC_CORRECT_COLOR_SPACE);
color_correction.game_color_space = Config::Get(Config::GFX_CC_GAME_COLOR_SPACE);
color_correction.bCorrectGamma = Config::Get(Config::GFX_CC_CORRECT_GAMMA);
color_correction.fGameGamma = Config::Get(Config::GFX_CC_GAME_GAMMA);
color_correction.bSDRDisplayGammaSRGB = Config::Get(Config::GFX_CC_SDR_DISPLAY_GAMMA_SRGB);
color_correction.fSDRDisplayCustomGamma = Config::Get(Config::GFX_CC_SDR_DISPLAY_CUSTOM_GAMMA);
color_correction.fHDRPaperWhiteNits = Config::Get(Config::GFX_CC_HDR_PAPER_WHITE_NITS);
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);
bVISkip = Config::Get(Config::GFX_HACK_VI_SKIP);
bSkipPresentingDuplicateXFBs = bVISkip || 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_ROUNDING);
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);
#ifdef __APPLE__
bNoMipmapping = Config::Get(Config::GFX_HACK_NO_MIPMAPPING);
#endif
bPerfQueriesEnable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE);
bGraphicMods = Config::Get(Config::GFX_MODS_ENABLE);
customDriverLibraryName = Config::Get(Config::GFX_DRIVER_LIB_NAME);
}
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.
return static_cast<u32>(std::clamp(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<u32>(std::max(cpu_info.num_cores - 2, 1));
}
u32 VideoConfig::GetShaderCompilerThreads() const
{
if (!backend_info.bSupportsBackgroundCompiling)
return 0;
if (iShaderCompilerThreads >= 0)
return static_cast<u32>(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;
if (iShaderPrecompilerThreads >= 0)
return static_cast<u32>(iShaderPrecompilerThreads);
else if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_MULTITHREADED_SHADER_PRECOMPILATION))
return GetNumAutoShaderPreCompilerThreads();
else
return 1;
}
void CheckForConfigChanges()
{
const ShaderHostConfig old_shader_host_config = ShaderHostConfig::GetCurrent();
const StereoMode old_stereo = g_ActiveConfig.stereo_mode;
const u32 old_multisamples = g_ActiveConfig.iMultisamples;
const int old_anisotropy = g_ActiveConfig.iMaxAnisotropy;
const int old_efb_access_tile_size = g_ActiveConfig.iEFBAccessTileSize;
const auto old_texture_filtering_mode = g_ActiveConfig.texture_filtering_mode;
const bool old_vsync = g_ActiveConfig.bVSyncActive;
const bool old_bbox = g_ActiveConfig.bBBoxEnable;
const int old_efb_scale = g_ActiveConfig.iEFBScale;
const u32 old_game_mod_changes =
g_ActiveConfig.graphics_mod_config ? g_ActiveConfig.graphics_mod_config->GetChangeCount() : 0;
const bool old_graphics_mods_enabled = g_ActiveConfig.bGraphicMods;
const AspectMode old_aspect_mode = g_ActiveConfig.aspect_mode;
const AspectMode old_suggested_aspect_mode = g_ActiveConfig.suggested_aspect_mode;
const bool old_widescreen_hack = g_ActiveConfig.bWidescreenHack;
const auto old_post_processing_shader = g_ActiveConfig.sPostProcessingShader;
const auto old_hdr = g_ActiveConfig.bHDR;
UpdateActiveConfig();
FreeLook::UpdateActiveConfig();
g_vertex_manager->OnConfigChange();
g_freelook_camera.SetControlType(FreeLook::GetActiveConfig().camera_config.control_type);
if (g_ActiveConfig.bGraphicMods && !old_graphics_mods_enabled)
{
g_ActiveConfig.graphics_mod_config = GraphicsModGroupConfig(SConfig::GetInstance().GetGameID());
g_ActiveConfig.graphics_mod_config->Load();
}
if (g_ActiveConfig.graphics_mod_config &&
(old_game_mod_changes != g_ActiveConfig.graphics_mod_config->GetChangeCount()))
{
g_graphics_mod_manager->Load(*g_ActiveConfig.graphics_mod_config);
}
// Update texture cache settings with any changed options.
g_texture_cache->OnConfigChanged(g_ActiveConfig);
// EFB tile cache doesn't need to notify the backend.
if (old_efb_access_tile_size != g_ActiveConfig.iEFBAccessTileSize)
g_framebuffer_manager->SetEFBCacheTileSize(std::max(g_ActiveConfig.iEFBAccessTileSize, 0));
// Determine which (if any) settings have changed.
ShaderHostConfig new_host_config = ShaderHostConfig::GetCurrent();
u32 changed_bits = 0;
if (old_shader_host_config.bits != new_host_config.bits)
changed_bits |= CONFIG_CHANGE_BIT_HOST_CONFIG;
if (old_stereo != g_ActiveConfig.stereo_mode)
changed_bits |= CONFIG_CHANGE_BIT_STEREO_MODE;
if (old_multisamples != g_ActiveConfig.iMultisamples)
changed_bits |= CONFIG_CHANGE_BIT_MULTISAMPLES;
if (old_anisotropy != g_ActiveConfig.iMaxAnisotropy)
changed_bits |= CONFIG_CHANGE_BIT_ANISOTROPY;
if (old_texture_filtering_mode != g_ActiveConfig.texture_filtering_mode)
changed_bits |= CONFIG_CHANGE_BIT_FORCE_TEXTURE_FILTERING;
if (old_vsync != g_ActiveConfig.bVSyncActive)
changed_bits |= CONFIG_CHANGE_BIT_VSYNC;
if (old_bbox != g_ActiveConfig.bBBoxEnable)
changed_bits |= CONFIG_CHANGE_BIT_BBOX;
if (old_efb_scale != g_ActiveConfig.iEFBScale)
changed_bits |= CONFIG_CHANGE_BIT_TARGET_SIZE;
if (old_aspect_mode != g_ActiveConfig.aspect_mode)
changed_bits |= CONFIG_CHANGE_BIT_ASPECT_RATIO;
if (old_suggested_aspect_mode != g_ActiveConfig.suggested_aspect_mode)
changed_bits |= CONFIG_CHANGE_BIT_ASPECT_RATIO;
if (old_widescreen_hack != g_ActiveConfig.bWidescreenHack)
changed_bits |= CONFIG_CHANGE_BIT_ASPECT_RATIO;
if (old_post_processing_shader != g_ActiveConfig.sPostProcessingShader)
changed_bits |= CONFIG_CHANGE_BIT_POST_PROCESSING_SHADER;
if (old_hdr != g_ActiveConfig.bHDR)
changed_bits |= CONFIG_CHANGE_BIT_HDR;
// No changes?
if (changed_bits == 0)
return;
float old_scale = g_framebuffer_manager->GetEFBScale();
// Framebuffer changed?
if (changed_bits & (CONFIG_CHANGE_BIT_MULTISAMPLES | CONFIG_CHANGE_BIT_STEREO_MODE |
CONFIG_CHANGE_BIT_TARGET_SIZE | CONFIG_CHANGE_BIT_HDR))
{
g_framebuffer_manager->RecreateEFBFramebuffer();
}
if (old_scale != g_framebuffer_manager->GetEFBScale())
{
auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager();
pixel_shader_manager.Dirty();
}
// Reload shaders if host config has changed.
if (changed_bits & (CONFIG_CHANGE_BIT_HOST_CONFIG | CONFIG_CHANGE_BIT_MULTISAMPLES))
{
OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL);
g_gfx->WaitForGPUIdle();
g_vertex_manager->InvalidatePipelineObject();
g_vertex_manager->NotifyCustomShaderCacheOfHostChange(new_host_config);
g_shader_cache->SetHostConfig(new_host_config);
g_shader_cache->Reload();
g_framebuffer_manager->RecompileShaders();
}
// Viewport and scissor rect have to be reset since they will be scaled differently.
if (changed_bits & CONFIG_CHANGE_BIT_TARGET_SIZE)
{
BPFunctions::SetScissorAndViewport();
}
// Notify all listeners
ConfigChangedEvent::Trigger(changed_bits);
// TODO: Move everything else to the ConfigChanged event
}
static Common::EventHook s_check_config_event = AfterFrameEvent::Register(
[](Core::System&) { CheckForConfigChanges(); }, "CheckForConfigChanges");