20 Commits

Author SHA1 Message Date
Duckey77 fa107635c9 Attempt to create Metal Renderer 2023-03-08 11:41:15 -07:00
C.W. Betts e58e557efc Hide more symbols from included libraries. 2023-03-03 15:55:12 -07:00
C.W. Betts bc2f72c49e Merge branch 'moreMetalAttempt' of https://github.com/OpenEmu/dolphin into moreMetalAttempt
Also bump the version to match the Dolphin version.
2023-03-03 15:02:34 -07:00
C.W. Betts 1798ae9e27 Well, it almost links... 2023-03-03 14:25:49 -07:00
Duckey77 19d945f88b update OGLfx compatfile (still need to find and make modifications for OE) 2023-03-03 14:21:37 -07:00
Duckey77 dcbbd8d589 Add missing files and externals for build 2023-03-03 14:20:49 -07:00
C.W. Betts 37704af83d Adding missing classes to the Xcode project. 2023-03-03 02:49:09 -07:00
C.W. Betts 630e35efd9 More recent Dolphin pokes
TODO:
* include Speex library.
* Find a way to generate glsl_intrinsic_header.h
* Build SPIRV-Cross
2023-03-03 02:32:37 -07:00
C.W. Betts 513e5e9a9b Metal attempt 1.
Currently doesn't build.
2023-03-02 21:06:03 -07:00
C.W. Betts e26c0ecc02 Mess with compiling prefix headers.
Trim down the configurations to Debug and Release.
2022-04-08 01:54:03 -06:00
C.W. Betts b6de4314df Add a path seperator to SetUserPath. 2022-04-04 22:24:20 -06:00
C.W. Betts 46e332c285 Poke, prod, scream. 2022-04-04 21:49:39 -06:00
C.W. Betts 7d18802b8f Restore OpenGL rendering. 2022-04-04 20:24:23 -06:00
C.W. Betts 6b2bb1c916 Pokes, prods, I'll never be happy. 2022-04-04 19:22:23 -06:00
C.W. Betts ed6da11aff Sort Xcode groups. 2022-04-04 17:28:50 -06:00
C.W. Betts 0cce0577f3 More Xcode project maintenance. 2022-04-04 02:31:46 -06:00
C.W. Betts 0b43c77d5d Mess with visibility of symbols. 2022-04-04 00:07:09 -06:00
C.W. Betts 36c6681975 Initial Universal build fix. 2022-04-03 22:13:48 -06:00
C.W. Betts d61f4e0170 Cleanup:
* Prepare for Apple Silicon support... but don't compile yet due to the Dolphin version used being outdated.
* Clean-up the Xcode project, including making the Dolphin bundle link to all the static libraries instead of having static libraries link to static libraries, fixing references to zstd so it doesn't conflict with other projects, and making the groups better match the folder layouts.
2022-04-03 17:51:27 -06:00
Neil Haverlandt 66455f2a22 Disable Rumble pack feature by default.Should fix #4413 2021-01-26 10:09:42 -07:00
31 changed files with 9196 additions and 15406 deletions
Executable
+3
View File
@@ -0,0 +1,3 @@
#ifdef __cplusplus
#include "Source/PCH/pch.h"
#endif
+49 -39
View File
@@ -9,9 +9,11 @@
#include "Common/Common.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
// This shouldn't be a global, at least not here.
extern std::unique_ptr<SoundStream> g_sound_stream;
std::unique_ptr<SoundStream> g_sound_stream;
static bool s_audio_dump_start = false;
@@ -22,34 +24,42 @@ namespace AudioCommon
static const int AUDIO_VOLUME_MIN = 0;
static const int AUDIO_VOLUME_MAX = 100;
void InitSoundStream()
void InitSoundStream(Core::System& system)
{
g_sound_stream = std::make_unique<OpenEmuAudioStream>();
if (!g_sound_stream->Init())
{
WARN_LOG(AUDIO, "Could not initialize backend");
WARN_LOG_FMT(AUDIO, "Could not initialize backend");
g_sound_stream = std::make_unique<NullSound>();
}
UpdateSoundStream();
SetSoundStreamRunning(true);
if (SConfig::GetInstance().m_DumpAudio && !s_audio_dump_start)
StartAudioDump();
UpdateSoundStream(system);
SetSoundStreamRunning(system, true);
}
void ShutdownSoundStream()
void PostInitSoundStream(Core::System& system)
{
INFO_LOG(AUDIO, "Shutting down sound stream");
// This needs to be called after AudioInterface::Init and SerialInterface::Init (for GBA devices)
// where input sample rates are set
UpdateSoundStream(system);
SetSoundStreamRunning(system, true);
if (SConfig::GetInstance().m_DumpAudio && s_audio_dump_start)
StopAudioDump();
if (Config::Get(Config::MAIN_DUMP_AUDIO) && !s_audio_dump_start)
StartAudioDump(system);
}
void ShutdownSoundStream(Core::System& system)
{
INFO_LOG_FMT(AUDIO, "Shutting down sound stream");
SetSoundStreamRunning(false);
if (Config::Get(Config::MAIN_DUMP_AUDIO) && s_audio_dump_start)
StopAudioDump(system);
SetSoundStreamRunning(system, false);
g_sound_stream.reset();
INFO_LOG(AUDIO, "Done shutting down sound stream");
INFO_LOG_FMT(AUDIO, "Done shutting down sound stream");
}
std::string GetDefaultSoundBackend()
@@ -88,16 +98,16 @@ DPL2Quality GetDefaultDPL2Quality()
return false;
}
void UpdateSoundStream()
void UpdateSoundStream(Core::System& system)
{
if (g_sound_stream)
{
int volume = SConfig::GetInstance().m_IsMuted ? 0 : SConfig::GetInstance().m_Volume;
int volume = Config::Get(Config::MAIN_AUDIO_MUTED) ? 0 : Config::Get(Config::MAIN_AUDIO_VOLUME);
g_sound_stream->SetVolume(volume);
}
}
void SetSoundStreamRunning(bool running)
void SetSoundStreamRunning(Core::System& system, bool running)
{
if (!g_sound_stream)
return;
@@ -109,20 +119,20 @@ DPL2Quality GetDefaultDPL2Quality()
if (g_sound_stream->SetRunning(running))
return;
if (running)
ERROR_LOG(AUDIO, "Error starting stream.");
ERROR_LOG_FMT(AUDIO, "Error starting stream.");
else
ERROR_LOG(AUDIO, "Error stopping stream.");
ERROR_LOG_FMT(AUDIO, "Error stopping stream.");
}
void SendAIBuffer(const short* samples, unsigned int num_samples)
void SendAIBuffer(Core::System& system, const short* samples, unsigned int num_samples)
{
if (!g_sound_stream)
return;
if (SConfig::GetInstance().m_DumpAudio && !s_audio_dump_start)
StartAudioDump();
else if (!SConfig::GetInstance().m_DumpAudio && s_audio_dump_start)
StopAudioDump();
if (Config::Get(Config::MAIN_DUMP_AUDIO) && !s_audio_dump_start)
StartAudioDump(system);
else if (!Config::Get(Config::MAIN_DUMP_AUDIO) && s_audio_dump_start)
StopAudioDump(system);
Mixer* pMixer = g_sound_stream->GetMixer();
@@ -130,11 +140,9 @@ DPL2Quality GetDefaultDPL2Quality()
{
pMixer->PushSamples(samples, num_samples);
}
g_sound_stream->Update();
}
void StartAudioDump()
void StartAudioDump(Core::System& system)
{
std::string audio_file_name_dtk = File::GetUserPath(D_DUMPAUDIO_IDX) + "dtkdump.wav";
std::string audio_file_name_dsp = File::GetUserPath(D_DUMPAUDIO_IDX) + "dspdump.wav";
@@ -145,7 +153,7 @@ DPL2Quality GetDefaultDPL2Quality()
s_audio_dump_start = true;
}
void StopAudioDump()
void StopAudioDump(Core::System& system)
{
if (!g_sound_stream)
return;
@@ -154,30 +162,32 @@ DPL2Quality GetDefaultDPL2Quality()
s_audio_dump_start = false;
}
void IncreaseVolume(unsigned short offset)
void IncreaseVolume(Core::System& system, unsigned short offset)
{
SConfig::GetInstance().m_IsMuted = false;
int& currentVolume = SConfig::GetInstance().m_Volume;
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, false);
int currentVolume = Config::Get(Config::MAIN_AUDIO_VOLUME);
currentVolume += offset;
if (currentVolume > AUDIO_VOLUME_MAX)
currentVolume = AUDIO_VOLUME_MAX;
UpdateSoundStream();
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, currentVolume);
UpdateSoundStream(system);
}
void DecreaseVolume(unsigned short offset)
void DecreaseVolume(Core::System& system, unsigned short offset)
{
SConfig::GetInstance().m_IsMuted = false;
int& currentVolume = SConfig::GetInstance().m_Volume;
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, false);
int currentVolume = Config::Get(Config::MAIN_AUDIO_VOLUME);
currentVolume -= offset;
if (currentVolume < AUDIO_VOLUME_MIN)
currentVolume = AUDIO_VOLUME_MIN;
UpdateSoundStream();
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, currentVolume);
UpdateSoundStream(system);
}
void ToggleMuteVolume()
void ToggleMuteVolume(Core::System& system)
{
bool& isMuted = SConfig::GetInstance().m_IsMuted;
isMuted = !isMuted;
UpdateSoundStream();
bool isMuted = Config::Get(Config::MAIN_AUDIO_MUTED);
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, !isMuted);
UpdateSoundStream(system);
}
} // namespace AudioCommon
+29
View File
@@ -0,0 +1,29 @@
// Copyright (c) 2022, OpenEmu Team
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the OpenEmu Team nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef __x86_64__
#include "../../dolphin/Source/Core/Common/x64CPUDetect.cpp"
#elif defined(__arm64__)
#include "../../dolphin/Source/Core/Common/ArmCPUDetect.cpp"
#endif
+27
View File
@@ -0,0 +1,27 @@
// Copyright (c) 2022, OpenEmu Team
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the OpenEmu Team nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef __x86_64__
#include "../../dolphin/Source/Core/Common/x64FPURoundMode.cpp"
#endif
+403 -480
View File
File diff suppressed because it is too large Load Diff
+26 -652
View File
@@ -16,7 +16,6 @@
#include "AudioCommon/AudioCommon.h"
#include "Common/Assert.h"
#include "Common/CDUtils.h"
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
#include "Common/Config/Config.h"
@@ -28,13 +27,13 @@
#include "Common/StringUtil.h"
#include "Common/scmrev.h"
#include "Core/Analytics.h"
#include "Core/Boot/Boot.h"
#include "Core/CommonTitles.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/SYSCONFSettings.h"
#include "Core/ConfigLoaders/GameConfigLoader.h"
#include "Core/Core.h"
#include "Core/System.h"
#include "Core/FifoPlayer/FifoDataFile.h"
#include "Core/HLE/HLE.h"
#include "Core/HW/DVD/DVDInterface.h"
@@ -82,538 +81,13 @@ SConfig::~SConfig()
void SConfig::SaveSettings()
{
NOTICE_LOG_FMT(BOOT, "Saving settings to {}", File::GetUserPath(F_DOLPHINCONFIG_IDX));
IniFile ini;
ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); // load first to not kill unknown stuff
SaveGeneralSettings(ini);
SaveInterfaceSettings(ini);
SaveGameListSettings(ini);
SaveCoreSettings(ini);
SaveMovieSettings(ini);
SaveDSPSettings(ini);
SaveInputSettings(ini);
SaveFifoPlayerSettings(ini);
SaveBluetoothPassthroughSettings(ini);
SaveUSBPassthroughSettings(ini);
SaveAutoUpdateSettings(ini);
SaveJitDebugSettings(ini);
ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
Config::Save();
}
void SConfig::SaveGeneralSettings(IniFile& ini)
{
IniFile::Section* general = ini.GetOrCreateSection("General");
// General
general->Set("ShowLag", m_ShowLag);
general->Set("ShowFrameCount", m_ShowFrameCount);
// ISO folders
// Clear removed folders
int oldPaths;
int numPaths = (int)m_ISOFolder.size();
general->Get("ISOPaths", &oldPaths, 0);
for (int i = numPaths; i < oldPaths; i++)
{
ini.DeleteKey("General", fmt::format("ISOPath{}", i));
}
general->Set("ISOPaths", numPaths);
for (int i = 0; i < numPaths; i++)
{
general->Set(fmt::format("ISOPath{}", i), m_ISOFolder[i]);
}
general->Set("WirelessMac", m_WirelessMac);
#ifdef USE_GDBSTUB
#ifndef _WIN32
general->Set("GDBSocket", gdb_socket);
#endif
general->Set("GDBPort", iGDBPort);
#endif
}
void SConfig::SaveInterfaceSettings(IniFile& ini)
{
IniFile::Section* interface = ini.GetOrCreateSection("Interface");
interface->Set("ConfirmStop", bConfirmStop);
interface->Set("HideCursor", bHideCursor);
interface->Set("LanguageCode", m_InterfaceLanguage);
interface->Set("ExtendedFPSInfo", m_InterfaceExtendedFPSInfo);
interface->Set("ShowActiveTitle", m_show_active_title);
interface->Set("UseBuiltinTitleDatabase", m_use_builtin_title_database);
interface->Set("ThemeName", theme_name);
interface->Set("PauseOnFocusLost", m_PauseOnFocusLost);
interface->Set("DebugModeEnabled", bEnableDebugging);
}
void SConfig::SaveGameListSettings(IniFile& ini)
{
IniFile::Section* gamelist = ini.GetOrCreateSection("GameList");
gamelist->Set("ListDrives", m_ListDrives);
gamelist->Set("ListWad", m_ListWad);
gamelist->Set("ListElfDol", m_ListElfDol);
gamelist->Set("ListWii", m_ListWii);
gamelist->Set("ListGC", m_ListGC);
gamelist->Set("ListJap", m_ListJap);
gamelist->Set("ListPal", m_ListPal);
gamelist->Set("ListUsa", m_ListUsa);
gamelist->Set("ListAustralia", m_ListAustralia);
gamelist->Set("ListFrance", m_ListFrance);
gamelist->Set("ListGermany", m_ListGermany);
gamelist->Set("ListItaly", m_ListItaly);
gamelist->Set("ListKorea", m_ListKorea);
gamelist->Set("ListNetherlands", m_ListNetherlands);
gamelist->Set("ListRussia", m_ListRussia);
gamelist->Set("ListSpain", m_ListSpain);
gamelist->Set("ListTaiwan", m_ListTaiwan);
gamelist->Set("ListWorld", m_ListWorld);
gamelist->Set("ListUnknown", m_ListUnknown);
gamelist->Set("ListSort", m_ListSort);
gamelist->Set("ListSortSecondary", m_ListSort2);
gamelist->Set("ColumnPlatform", m_showSystemColumn);
gamelist->Set("ColumnBanner", m_showBannerColumn);
gamelist->Set("ColumnDescription", m_showDescriptionColumn);
gamelist->Set("ColumnTitle", m_showTitleColumn);
gamelist->Set("ColumnNotes", m_showMakerColumn);
gamelist->Set("ColumnFileName", m_showFileNameColumn);
gamelist->Set("ColumnFilePath", m_showFilePathColumn);
gamelist->Set("ColumnID", m_showIDColumn);
gamelist->Set("ColumnRegion", m_showRegionColumn);
gamelist->Set("ColumnSize", m_showSizeColumn);
gamelist->Set("ColumnFileFormat", m_showFileFormatColumn);
gamelist->Set("ColumnBlockSize", m_showBlockSizeColumn);
gamelist->Set("ColumnCompression", m_showCompressionColumn);
gamelist->Set("ColumnTags", m_showTagsColumn);
}
void SConfig::SaveCoreSettings(IniFile& ini)
{
IniFile::Section* core = ini.GetOrCreateSection("Core");
core->Set("SkipIPL", bHLE_BS2);
core->Set("TimingVariance", iTimingVariance);
core->Set("CPUCore", cpu_core);
core->Set("Fastmem", bFastmem);
core->Set("CPUThread", bCPUThread);
core->Set("DSPHLE", bDSPHLE);
core->Set("SyncOnSkipIdle", bSyncGPUOnSkipIdleHack);
core->Set("SyncGPU", bSyncGPU);
core->Set("SyncGpuMaxDistance", iSyncGpuMaxDistance);
core->Set("SyncGpuMinDistance", iSyncGpuMinDistance);
core->Set("SyncGpuOverclock", fSyncGpuOverclock);
core->Set("FPRF", bFPRF);
core->Set("AccurateNaNs", bAccurateNaNs);
core->Set("EnableCheats", bEnableCheats);
core->Set("SelectedLanguage", SelectedLanguage);
core->Set("OverrideRegionSettings", bOverrideRegionSettings);
core->Set("DPL2Decoder", bDPL2Decoder);
core->Set("AudioLatency", iLatency);
core->Set("AudioStretch", m_audio_stretch);
core->Set("AudioStretchMaxLatency", m_audio_stretch_max_latency);
core->Set("AgpCartAPath", m_strGbaCartA);
core->Set("AgpCartBPath", m_strGbaCartB);
core->Set("SlotA", m_EXIDevice[0]);
core->Set("SlotB", m_EXIDevice[1]);
core->Set("SerialPort1", m_EXIDevice[2]);
core->Set("BBA_MAC", m_bba_mac);
core->Set("BBA_XLINK_IP", m_bba_xlink_ip);
core->Set("BBA_XLINK_CHAT_OSD", m_bba_xlink_chat_osd);
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{
core->Set(fmt::format("SIDevice{}", i), m_SIDevice[i]);
core->Set(fmt::format("AdapterRumble{}", i), m_AdapterRumble[i]);
core->Set(fmt::format("SimulateKonga{}", i), m_AdapterKonga[i]);
}
core->Set("WiiSDCard", m_WiiSDCard);
core->Set("WiiKeyboard", m_WiiKeyboard);
core->Set("WiimoteContinuousScanning", m_WiimoteContinuousScanning);
core->Set("WiimoteEnableSpeaker", m_WiimoteEnableSpeaker);
core->Set("WiimoteControllerInterface", connect_wiimotes_for_ciface);
core->Set("RunCompareServer", bRunCompareServer);
core->Set("RunCompareClient", bRunCompareClient);
core->Set("MMU", bMMU);
core->Set("EmulationSpeed", m_EmulationSpeed);
core->Set("Overclock", m_OCFactor);
core->Set("OverclockEnable", m_OCEnable);
core->Set("GPUDeterminismMode", m_strGPUDeterminismMode);
core->Set("PerfMapDir", m_perfDir);
core->Set("EnableCustomRTC", bEnableCustomRTC);
core->Set("CustomRTCValue", m_customRTCValue);
}
void SConfig::SaveMovieSettings(IniFile& ini)
{
IniFile::Section* movie = ini.GetOrCreateSection("Movie");
movie->Set("PauseMovie", m_PauseMovie);
movie->Set("Author", m_strMovieAuthor);
movie->Set("DumpFrames", m_DumpFrames);
movie->Set("DumpFramesSilent", m_DumpFramesSilent);
movie->Set("ShowInputDisplay", m_ShowInputDisplay);
movie->Set("ShowRTC", m_ShowRTC);
}
void SConfig::SaveDSPSettings(IniFile& ini)
{
IniFile::Section* dsp = ini.GetOrCreateSection("DSP");
dsp->Set("EnableJIT", m_DSPEnableJIT);
dsp->Set("DumpAudio", m_DumpAudio);
dsp->Set("DumpAudioSilent", m_DumpAudioSilent);
dsp->Set("DumpUCode", m_DumpUCode);
dsp->Set("Backend", sBackend);
dsp->Set("Volume", m_Volume);
dsp->Set("CaptureLog", m_DSPCaptureLog);
#ifdef _WIN32
dsp->Set("WASAPIDevice", sWASAPIDevice);
#endif
}
void SConfig::SaveInputSettings(IniFile& ini)
{
IniFile::Section* input = ini.GetOrCreateSection("Input");
input->Set("BackgroundInput", m_BackgroundInput);
}
void SConfig::SaveFifoPlayerSettings(IniFile& ini)
{
IniFile::Section* fifoplayer = ini.GetOrCreateSection("FifoPlayer");
fifoplayer->Set("LoopReplay", bLoopFifoReplay);
}
void SConfig::SaveBluetoothPassthroughSettings(IniFile& ini)
{
IniFile::Section* section = ini.GetOrCreateSection("BluetoothPassthrough");
section->Set("Enabled", m_bt_passthrough_enabled);
section->Set("VID", m_bt_passthrough_vid);
section->Set("PID", m_bt_passthrough_pid);
section->Set("LinkKeys", m_bt_passthrough_link_keys);
}
void SConfig::SaveUSBPassthroughSettings(IniFile& ini)
{
IniFile::Section* section = ini.GetOrCreateSection("USBPassthrough");
std::ostringstream oss;
for (const auto& device : m_usb_passthrough_devices)
oss << fmt::format("{:04x}:{:04x}", device.first, device.second) << ',';
std::string devices_string = oss.str();
if (!devices_string.empty())
devices_string.pop_back();
section->Set("Devices", devices_string);
}
void SConfig::SaveAutoUpdateSettings(IniFile& ini)
{
IniFile::Section* section = ini.GetOrCreateSection("AutoUpdate");
section->Set("UpdateTrack", m_auto_update_track);
section->Set("HashOverride", m_auto_update_hash_override);
}
void SConfig::SaveJitDebugSettings(IniFile& ini)
{
IniFile::Section* section = ini.GetOrCreateSection("Debug");
section->Set("JitOff", bJITOff);
section->Set("JitLoadStoreOff", bJITLoadStoreOff);
section->Set("JitLoadStoreFloatingOff", bJITLoadStoreFloatingOff);
section->Set("JitLoadStorePairedOff", bJITLoadStorePairedOff);
section->Set("JitFloatingPointOff", bJITFloatingPointOff);
section->Set("JitIntegerOff", bJITIntegerOff);
section->Set("JitPairedOff", bJITPairedOff);
section->Set("JitSystemRegistersOff", bJITSystemRegistersOff);
section->Set("JitBranchOff", bJITBranchOff);
section->Set("JitRegisterCacheOff", bJITRegisterCacheOff);
}
void SConfig::LoadSettings()
{
Config::Load();
INFO_LOG_FMT(BOOT, "Loading Settings from {}", File::GetUserPath(F_DOLPHINCONFIG_IDX));
IniFile ini;
ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
LoadGeneralSettings(ini);
LoadInterfaceSettings(ini);
LoadGameListSettings(ini);
LoadCoreSettings(ini);
LoadMovieSettings(ini);
LoadDSPSettings(ini);
LoadInputSettings(ini);
LoadFifoPlayerSettings(ini);
LoadBluetoothPassthroughSettings(ini);
LoadUSBPassthroughSettings(ini);
LoadAutoUpdateSettings(ini);
LoadJitDebugSettings(ini);
}
void SConfig::LoadGeneralSettings(IniFile& ini)
{
IniFile::Section* general = ini.GetOrCreateSection("General");
general->Get("ShowLag", &m_ShowLag, false);
general->Get("ShowFrameCount", &m_ShowFrameCount, false);
#ifdef USE_GDBSTUB
#ifndef _WIN32
general->Get("GDBSocket", &gdb_socket, "");
#endif
general->Get("GDBPort", &(iGDBPort), -1);
#endif
m_ISOFolder.clear();
int numISOPaths;
if (general->Get("ISOPaths", &numISOPaths, 0))
{
for (int i = 0; i < numISOPaths; i++)
{
std::string tmpPath;
general->Get(fmt::format("ISOPath{}", i), &tmpPath, "");
m_ISOFolder.push_back(std::move(tmpPath));
}
}
general->Get("WirelessMac", &m_WirelessMac);
}
void SConfig::LoadInterfaceSettings(IniFile& ini)
{
IniFile::Section* interface = ini.GetOrCreateSection("Interface");
interface->Get("ConfirmStop", &bConfirmStop, true);
interface->Get("HideCursor", &bHideCursor, false);
interface->Get("LanguageCode", &m_InterfaceLanguage, "");
interface->Get("ExtendedFPSInfo", &m_InterfaceExtendedFPSInfo, false);
interface->Get("ShowActiveTitle", &m_show_active_title, true);
interface->Get("UseBuiltinTitleDatabase", &m_use_builtin_title_database, true);
interface->Get("ThemeName", &theme_name, DEFAULT_THEME_DIR);
interface->Get("PauseOnFocusLost", &m_PauseOnFocusLost, false);
interface->Get("DebugModeEnabled", &bEnableDebugging, false);
}
void SConfig::LoadGameListSettings(IniFile& ini)
{
IniFile::Section* gamelist = ini.GetOrCreateSection("GameList");
gamelist->Get("ListDrives", &m_ListDrives, false);
gamelist->Get("ListWad", &m_ListWad, true);
gamelist->Get("ListElfDol", &m_ListElfDol, true);
gamelist->Get("ListWii", &m_ListWii, true);
gamelist->Get("ListGC", &m_ListGC, true);
gamelist->Get("ListJap", &m_ListJap, true);
gamelist->Get("ListPal", &m_ListPal, true);
gamelist->Get("ListUsa", &m_ListUsa, true);
gamelist->Get("ListAustralia", &m_ListAustralia, true);
gamelist->Get("ListFrance", &m_ListFrance, true);
gamelist->Get("ListGermany", &m_ListGermany, true);
gamelist->Get("ListItaly", &m_ListItaly, true);
gamelist->Get("ListKorea", &m_ListKorea, true);
gamelist->Get("ListNetherlands", &m_ListNetherlands, true);
gamelist->Get("ListRussia", &m_ListRussia, true);
gamelist->Get("ListSpain", &m_ListSpain, true);
gamelist->Get("ListTaiwan", &m_ListTaiwan, true);
gamelist->Get("ListWorld", &m_ListWorld, true);
gamelist->Get("ListUnknown", &m_ListUnknown, true);
gamelist->Get("ListSort", &m_ListSort, 3);
gamelist->Get("ListSortSecondary", &m_ListSort2, 0);
// Gamelist columns toggles
gamelist->Get("ColumnPlatform", &m_showSystemColumn, true);
gamelist->Get("ColumnDescription", &m_showDescriptionColumn, false);
gamelist->Get("ColumnBanner", &m_showBannerColumn, true);
gamelist->Get("ColumnTitle", &m_showTitleColumn, true);
gamelist->Get("ColumnNotes", &m_showMakerColumn, true);
gamelist->Get("ColumnFileName", &m_showFileNameColumn, false);
gamelist->Get("ColumnFilePath", &m_showFilePathColumn, false);
gamelist->Get("ColumnID", &m_showIDColumn, false);
gamelist->Get("ColumnRegion", &m_showRegionColumn, true);
gamelist->Get("ColumnSize", &m_showSizeColumn, true);
gamelist->Get("ColumnFileFormat", &m_showFileFormatColumn, false);
gamelist->Get("ColumnBlockSize", &m_showBlockSizeColumn, false);
gamelist->Get("ColumnCompression", &m_showCompressionColumn, false);
gamelist->Get("ColumnTags", &m_showTagsColumn, false);
}
void SConfig::LoadCoreSettings(IniFile& ini)
{
IniFile::Section* core = ini.GetOrCreateSection("Core");
core->Get("SkipIPL", &bHLE_BS2, true);
#ifdef _M_X86
core->Get("CPUCore", &cpu_core, PowerPC::CPUCore::JIT64);
#elif _M_ARM_64
core->Get("CPUCore", &cpu_core, PowerPC::CPUCore::JITARM64);
#else
core->Get("CPUCore", &cpu_core, PowerPC::CPUCore::Interpreter);
#endif
core->Get("JITFollowBranch", &bJITFollowBranch, true);
core->Get("Fastmem", &bFastmem, true);
core->Get("DSPHLE", &bDSPHLE, true);
core->Get("TimingVariance", &iTimingVariance, 40);
core->Get("CPUThread", &bCPUThread, true);
core->Get("SyncOnSkipIdle", &bSyncGPUOnSkipIdleHack, true);
core->Get("EnableCheats", &bEnableCheats, false);
core->Get("SelectedLanguage", &SelectedLanguage, 0);
core->Get("OverrideRegionSettings", &bOverrideRegionSettings, false);
core->Get("DPL2Decoder", &bDPL2Decoder, false);
core->Get("AudioLatency", &iLatency, 20);
core->Get("AudioStretch", &m_audio_stretch, false);
core->Get("AudioStretchMaxLatency", &m_audio_stretch_max_latency, 80);
core->Get("AgpCartAPath", &m_strGbaCartA);
core->Get("AgpCartBPath", &m_strGbaCartB);
core->Get("SlotA", (int*)&m_EXIDevice[0], ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER);
core->Get("SlotB", (int*)&m_EXIDevice[1], ExpansionInterface::EXIDEVICE_NONE);
core->Get("SerialPort1", (int*)&m_EXIDevice[2], ExpansionInterface::EXIDEVICE_NONE);
core->Get("BBA_MAC", &m_bba_mac);
core->Get("BBA_XLINK_IP", &m_bba_xlink_ip, "127.0.0.1");
core->Get("BBA_XLINK_CHAT_OSD", &m_bba_xlink_chat_osd, true);
for (size_t i = 0; i < std::size(m_SIDevice); ++i)
{
//OpenEmu change all controllers to GaceCube Controllers
//core->Get(fmt::format("SIDevice{}", i), &m_SIDevice[i],
//(i == 0) ? SerialInterface::SIDEVICE_GC_CONTROLLER : SerialInterface::SIDEVICE_NONE);
core->Get(fmt::format("SIDevice{}", i), &m_SIDevice[i], SerialInterface::SIDEVICE_GC_CONTROLLER);
core->Get(fmt::format("AdapterRumble{}", i), &m_AdapterRumble[i], true);
core->Get(fmt::format("SimulateKonga{}", i), &m_AdapterKonga[i], false);
}
core->Get("WiiSDCard", &m_WiiSDCard, true);
core->Get("WiiKeyboard", &m_WiiKeyboard, false);
core->Get("WiimoteContinuousScanning", &m_WiimoteContinuousScanning, false);
core->Get("WiimoteEnableSpeaker", &m_WiimoteEnableSpeaker, false);
core->Get("WiimoteControllerInterface", &connect_wiimotes_for_ciface, false);
core->Get("RunCompareServer", &bRunCompareServer, false);
core->Get("RunCompareClient", &bRunCompareClient, false);
core->Get("MMU", &bMMU, bMMU);
core->Get("BBDumpPort", &iBBDumpPort, -1);
core->Get("SyncGPU", &bSyncGPU, false);
core->Get("SyncGpuMaxDistance", &iSyncGpuMaxDistance, 200000);
core->Get("SyncGpuMinDistance", &iSyncGpuMinDistance, -200000);
core->Get("SyncGpuOverclock", &fSyncGpuOverclock, 1.0f);
core->Get("FastDiscSpeed", &bFastDiscSpeed, false);
core->Get("LowDCBZHack", &bLowDCBZHack, false);
core->Get("FPRF", &bFPRF, false);
core->Get("AccurateNaNs", &bAccurateNaNs, false);
core->Get("EmulationSpeed", &m_EmulationSpeed, 1.0f);
core->Get("Overclock", &m_OCFactor, 1.0f);
core->Get("OverclockEnable", &m_OCEnable, false);
core->Get("GPUDeterminismMode", &m_strGPUDeterminismMode, "auto");
core->Get("PerfMapDir", &m_perfDir, "");
core->Get("EnableCustomRTC", &bEnableCustomRTC, false);
// Default to seconds between 1.1.1970 and 1.1.2000
core->Get("CustomRTCValue", &m_customRTCValue, 946684800);
}
void SConfig::LoadMovieSettings(IniFile& ini)
{
IniFile::Section* movie = ini.GetOrCreateSection("Movie");
movie->Get("PauseMovie", &m_PauseMovie, false);
movie->Get("Author", &m_strMovieAuthor, "");
movie->Get("DumpFrames", &m_DumpFrames, false);
movie->Get("DumpFramesSilent", &m_DumpFramesSilent, false);
movie->Get("ShowInputDisplay", &m_ShowInputDisplay, false);
movie->Get("ShowRTC", &m_ShowRTC, false);
}
void SConfig::LoadDSPSettings(IniFile& ini)
{
IniFile::Section* dsp = ini.GetOrCreateSection("DSP");
dsp->Get("EnableJIT", &m_DSPEnableJIT, true);
dsp->Get("DumpAudio", &m_DumpAudio, false);
dsp->Get("DumpAudioSilent", &m_DumpAudioSilent, false);
dsp->Get("DumpUCode", &m_DumpUCode, false);
dsp->Get("Backend", &sBackend, AudioCommon::GetDefaultSoundBackend());
dsp->Get("Volume", &m_Volume, 100);
dsp->Get("CaptureLog", &m_DSPCaptureLog, false);
#ifdef _WIN32
dsp->Get("WASAPIDevice", &sWASAPIDevice, "default");
#endif
m_IsMuted = false;
}
void SConfig::LoadInputSettings(IniFile& ini)
{
IniFile::Section* input = ini.GetOrCreateSection("Input");
input->Get("BackgroundInput", &m_BackgroundInput, false);
}
void SConfig::LoadFifoPlayerSettings(IniFile& ini)
{
IniFile::Section* fifoplayer = ini.GetOrCreateSection("FifoPlayer");
fifoplayer->Get("LoopReplay", &bLoopFifoReplay, true);
}
void SConfig::LoadBluetoothPassthroughSettings(IniFile& ini)
{
IniFile::Section* section = ini.GetOrCreateSection("BluetoothPassthrough");
section->Get("Enabled", &m_bt_passthrough_enabled, false);
section->Get("VID", &m_bt_passthrough_vid, -1);
section->Get("PID", &m_bt_passthrough_pid, -1);
section->Get("LinkKeys", &m_bt_passthrough_link_keys, "");
}
void SConfig::LoadUSBPassthroughSettings(IniFile& ini)
{
IniFile::Section* section = ini.GetOrCreateSection("USBPassthrough");
m_usb_passthrough_devices.clear();
std::string devices_string;
section->Get("Devices", &devices_string, "");
for (const auto& pair : SplitString(devices_string, ','))
{
const auto index = pair.find(':');
if (index == std::string::npos)
continue;
const u16 vid = static_cast<u16>(strtol(pair.substr(0, index).c_str(), nullptr, 16));
const u16 pid = static_cast<u16>(strtol(pair.substr(index + 1).c_str(), nullptr, 16));
if (vid && pid)
m_usb_passthrough_devices.emplace(vid, pid);
}
}
void SConfig::LoadAutoUpdateSettings(IniFile& ini)
{
IniFile::Section* section = ini.GetOrCreateSection("AutoUpdate");
section->Get("UpdateTrack", &m_auto_update_track, SCM_UPDATE_TRACK_STR);
section->Get("HashOverride", &m_auto_update_hash_override, "");
}
void SConfig::LoadJitDebugSettings(IniFile& ini)
{
IniFile::Section* section = ini.GetOrCreateSection("Debug");
section->Get("JitOff", &bJITOff, false);
section->Get("JitLoadStoreOff", &bJITLoadStoreOff, false);
section->Get("JitLoadStoreFloatingOff", &bJITLoadStoreFloatingOff, false);
section->Get("JitLoadStorePairedOff", &bJITLoadStorePairedOff, false);
section->Get("JitFloatingPointOff", &bJITFloatingPointOff, false);
section->Get("JitIntegerOff", &bJITIntegerOff, false);
section->Get("JitPairedOff", &bJITPairedOff, false);
section->Get("JitSystemRegistersOff", &bJITSystemRegistersOff, false);
section->Get("JitBranchOff", &bJITBranchOff, false);
section->Get("JitRegisterCacheOff", &bJITRegisterCacheOff, false);
Config::Load();
}
void SConfig::ResetRunningGameMetadata()
@@ -695,130 +169,25 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri
m_title_description = title_database.Describe(m_gametdb_id, language);
NOTICE_LOG_FMT(CORE, "Active title: {}", m_title_description);
Host_TitleChanged();
if (Core::IsRunning())
{
Core::UpdateTitle();
}
Config::AddLayer(ConfigLoaders::GenerateGlobalGameConfigLoader(game_id, revision));
Config::AddLayer(ConfigLoaders::GenerateLocalGameConfigLoader(game_id, revision));
if (Core::IsRunning())
{
// TODO: have a callback mechanism for title changes?
if (!g_symbolDB.IsEmpty())
{
g_symbolDB.Clear();
Host_NotifyMapLoaded();
}
CBoot::LoadMapFromFilename();
HLE::Reload();
PatchEngine::Reload();
HiresTexture::Update();
DolphinAnalytics::Instance().ReportGameStart();
}
}
void SConfig::LoadDefaults()
{
bEnableDebugging = false;
bAutomaticStart = false;
bBootToPause = false;
#ifdef USE_GDBSTUB
iGDBPort = -1;
#ifndef _WIN32
gdb_socket = "";
#endif
#endif
cpu_core = PowerPC::DefaultCPUCore();
iTimingVariance = 40;
bCPUThread = false;
bSyncGPUOnSkipIdleHack = true;
bRunCompareServer = false;
bDSPHLE = true;
bFastmem = true;
bFPRF = false;
bAccurateNaNs = false;
bMMU = false;
bLowDCBZHack = false;
iBBDumpPort = -1;
bSyncGPU = false;
bFastDiscSpeed = false;
bEnableMemcardSdWriting = true;
SelectedLanguage = 0;
bOverrideRegionSettings = false;
bWii = false;
bDPL2Decoder = false;
iLatency = 20;
m_audio_stretch = false;
m_audio_stretch_max_latency = 80;
bLoopFifoReplay = true;
bJITOff = false; // debugger only settings
bJITLoadStoreOff = false;
bJITLoadStoreFloatingOff = false;
bJITLoadStorePairedOff = false;
bJITFloatingPointOff = false;
bJITIntegerOff = false;
bJITPairedOff = false;
bJITSystemRegistersOff = false;
bJITBranchOff = false;
bJITRegisterCacheOff = false;
ResetRunningGameMetadata();
}
bool SConfig::IsUSBDeviceWhitelisted(const std::pair<u16, u16> vid_pid) const
{
return m_usb_passthrough_devices.find(vid_pid) != m_usb_passthrough_devices.end();
}
// The reason we need this function is because some memory card code
// expects to get a non-NTSC-K region even if we're emulating an NTSC-K Wii.
DiscIO::Region SConfig::ToGameCubeRegion(DiscIO::Region region)
{
if (region != DiscIO::Region::NTSC_K)
return region;
// GameCube has no NTSC-K region. No choice of replacement value is completely
// non-arbitrary, but let's go with NTSC-J since Korean GameCubes are NTSC-J.
return DiscIO::Region::NTSC_J;
}
const char* SConfig::GetDirectoryForRegion(DiscIO::Region region)
{
if (region == DiscIO::Region::Unknown)
region = ToGameCubeRegion(GetFallbackRegion());
switch (region)
{
case DiscIO::Region::NTSC_J:
return JAP_DIR;
case DiscIO::Region::NTSC_U:
return USA_DIR;
case DiscIO::Region::PAL:
return EUR_DIR;
case DiscIO::Region::NTSC_K:
ASSERT_MSG(BOOT, false, "NTSC-K is not a valid GameCube region");
return JAP_DIR; // See ToGameCubeRegion
default:
ASSERT_MSG(BOOT, false, "Default case should not be reached");
return EUR_DIR;
}
}
std::string SConfig::GetBootROMPath(const std::string& region_directory) const
{
const std::string path =
File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + region_directory + DIR_SEP GC_IPL;
if (!File::Exists(path))
return File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + region_directory + DIR_SEP GC_IPL;
return path;
}
struct SetGameMetadata
{
SetGameMetadata(SConfig* config_, DiscIO::Region* region_) : config(config_), region(region_) {}
@@ -920,29 +289,23 @@ bool SConfig::SetPathsAndGameMetadata(const BootParameters& boot)
return false;
if (m_region == DiscIO::Region::Unknown)
m_region = GetFallbackRegion();
m_region = Config::Get(Config::MAIN_FALLBACK_REGION);
// Set up paths
const std::string region_dir = GetDirectoryForRegion(ToGameCubeRegion(m_region));
const std::string region_dir = Config::GetDirectoryForRegion(Config::ToGameCubeRegion(m_region));
m_strSRAM = File::GetUserPath(F_GCSRAM_IDX);
m_strBootROM = GetBootROMPath(region_dir);
m_strBootROM = Config::GetBootROMPath(region_dir);
return true;
}
DiscIO::Region SConfig::GetFallbackRegion()
{
return Config::Get(Config::MAIN_FALLBACK_REGION);
}
DiscIO::Language SConfig::GetCurrentLanguage(bool wii) const
{
int language_value;
DiscIO::Language language;
if (wii)
language_value = Config::Get(Config::SYSCONF_LANGUAGE);
language = static_cast<DiscIO::Language>(Config::Get(Config::SYSCONF_LANGUAGE));
else
language_value = SConfig::GetInstance().SelectedLanguage + 1;
DiscIO::Language language = static_cast<DiscIO::Language>(language_value);
language = DiscIO::FromGameCubeLanguage(Config::Get(Config::MAIN_GC_LANGUAGE));
// Get rid of invalid values (probably doesn't matter, but might as well do it)
if (language > DiscIO::Language::Unknown || language < DiscIO::Language::Japanese)
@@ -960,7 +323,7 @@ DiscIO::Language SConfig::GetLanguageAdjustedForRegion(bool wii, DiscIO::Region
if (!wii && region == DiscIO::Region::NTSC_J && language == DiscIO::Language::English)
return DiscIO::Language::Japanese; // English and Japanese both use the value 0 in GC SRAM
if (!bOverrideRegionSettings)
if (!Config::Get(Config::MAIN_OVERRIDE_REGION_SETTINGS))
{
if (region == DiscIO::Region::NTSC_J)
return DiscIO::Language::Japanese;
@@ -1025,7 +388,18 @@ IniFile SConfig::LoadGameIni(const std::string& id, std::optional<u16> revision)
return game_ini;
}
bool SConfig::ShouldUseDPL2Decoder() const
void SConfig::OnNewTitleLoad(const Core::CPUThreadGuard &guard)
{
return bDPL2Decoder && !bDSPHLE;
if (!Core::IsRunning())
return;
if (!g_symbolDB.IsEmpty())
{
g_symbolDB.Clear();
Host_NotifyMapLoaded();
}
CBoot::LoadMapFromFilename(guard);
HLE::Reload(Core::System::GetInstance());
PatchEngine::Reload();
HiresTexture::Update();
}
+59
View File
@@ -0,0 +1,59 @@
// Copyright (c) 2022, OpenEmu Team
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the OpenEmu Team nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef __x86_64__
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit64_Tables.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit_Branch.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit_Paired.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64Common/BlockCache.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64Common/ConstantPool.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64Common/EmuCodeBlock.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64Common/FarCodeCache.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/Jit64Common/TrampolineCache.cpp"
#elif defined(__arm64__)
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/Jit.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp"
#include "../../dolphin/Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp"
#endif
+37 -14
View File
@@ -44,6 +44,7 @@
#endif
ControllerInterface g_controller_interface;
static bool m_is_populating_devices = false;
void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
{
@@ -81,7 +82,7 @@ void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
// nothing needed
#endif
#ifdef CIFACE_USE_DUALSHOCKUDPCLIENT
ciface::DualShockUDPClient::Init();
m_input_backends.emplace_back(ciface::DualShockUDPClient::CreateInputBackend(this));
#endif
//OpenEmu initalize OpenEmu Input
@@ -93,7 +94,34 @@ void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
m_is_populating_devices = false;
}
void ControllerInterface::ChangeWindow(void* hwnd)
static thread_local ciface::InputChannel tls_input_channel = ciface::InputChannel::Host;
void ControllerInterface::SetCurrentInputChannel(ciface::InputChannel input_channel)
{
tls_input_channel = input_channel;
}
ciface::InputChannel ControllerInterface::GetCurrentInputChannel()
{
return tls_input_channel;
}
void ControllerInterface::PlatformPopulateDevices(std::function<void()> callback)
{
if (!m_is_init)
return;
std::lock_guard lk_population(m_devices_population_mutex);
m_populating_devices_counter.fetch_add(1);
callback();
if (m_populating_devices_counter.fetch_sub(1) == 1)
InvokeDevicesChangedCallbacks();
}
void ControllerInterface::ChangeWindow(void* hwnd, WindowChangeReason reason)
{
if (!m_is_init)
return;
@@ -103,7 +131,7 @@ void ControllerInterface::ChangeWindow(void* hwnd)
RefreshDevices();
}
void ControllerInterface::RefreshDevices()
void ControllerInterface::RefreshDevices(RefreshReason reason)
{
if (!m_is_init)
return;
@@ -145,9 +173,6 @@ void ControllerInterface::RefreshDevices()
#ifdef CIFACE_USE_PIPES
ciface::Pipes::PopulateDevices();
#endif
#ifdef CIFACE_USE_DUALSHOCKUDPCLIENT
ciface::DualShockUDPClient::PopulateDevices();
#endif
WiimoteReal::ProcessWiimotePool();
@@ -200,16 +225,13 @@ void ControllerInterface::Shutdown()
#ifdef CIFACE_USE_EVDEV
ciface::evdev::Shutdown();
#endif
#ifdef CIFACE_USE_DUALSHOCKUDPCLIENT
ciface::DualShockUDPClient::DeInit();
#endif
}
void ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device)
bool ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device)
{
// If we are shutdown (or in process of shutting down) ignore this request:
if (!m_is_init)
return;
return false;
{
std::lock_guard lk(m_devices_mutex);
@@ -237,22 +259,23 @@ void ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device
device->SetId(id);
}
NOTICE_LOG(SERIALINTERFACE, "Added device: %s", device->GetQualifiedName().c_str());
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Added device: {}", device->GetQualifiedName());
m_devices.emplace_back(std::move(device));
}
if (!m_is_populating_devices)
InvokeDevicesChangedCallbacks();
return true;
}
void ControllerInterface::RemoveDevice(std::function<bool(const ciface::Core::Device*)> callback)
void ControllerInterface::RemoveDevice(std::function<bool(const ciface::Core::Device*)> callback, bool force_devices_release)
{
{
std::lock_guard lk(m_devices_mutex);
auto it = std::remove_if(m_devices.begin(), m_devices.end(), [&callback](const auto& dev) {
if (callback(dev.get()))
{
NOTICE_LOG(SERIALINTERFACE, "Removed device: %s", dev->GetQualifiedName().c_str());
NOTICE_LOG_FMT(SERIALINTERFACE, "Removed device: {}", dev->GetQualifiedName());
return true;
}
return false;
+4 -9
View File
@@ -26,7 +26,7 @@ InputConfig::InputConfig(const std::string& ini_name, const std::string& gui_nam
InputConfig::~InputConfig() = default;
bool InputConfig::LoadConfig(bool isGC)
bool InputConfig::LoadConfig(InputClass type)
{
//OpenEmu Stub
return false;
@@ -45,7 +45,7 @@ void InputConfig::SaveConfig()
inifile.Save(ini_filename);
}
ControllerEmu::EmulatedController* InputConfig::GetController(int index)
ControllerEmu::EmulatedController* InputConfig::GetController(int index) const
{
return m_controllers.at(index).get();
}
@@ -60,9 +60,9 @@ bool InputConfig::ControllersNeedToBeCreated() const
return m_controllers.empty();
}
std::size_t InputConfig::GetControllerCount() const
int InputConfig::GetControllerCount() const
{
return m_controllers.size();
return static_cast<int>(m_controllers.size());
}
void InputConfig::RegisterHotplugCallback()
@@ -80,11 +80,6 @@ void InputConfig::UnregisterHotplugCallback()
g_controller_interface.UnregisterDevicesChangedCallback(m_hotplug_callback_handle);
}
void InputConfig::OnControllerCreated(ControllerEmu::EmulatedController& controller)
{
controller.SetDynamicInputTextureManager(&m_dynamic_input_tex_config_manager);
}
bool InputConfig::IsControllerControlledByGamepadDevice(int index) const
{
if (static_cast<size_t>(index) >= m_controllers.size())
+3 -1
View File
@@ -4,6 +4,8 @@
#include "OpenEmuController.h"
#include "Core/ConfigManager.h"
#include "Common/Config/Config.h"
#include "Core/Config/MainSettings.h"
void input_poll_f()
{
@@ -14,7 +16,7 @@ void input_poll_f()
int16_t input_state_f(unsigned port, unsigned device, unsigned index, unsigned button)
{
if (SConfig::GetInstance().bWii && !SConfig::GetInstance().m_bt_passthrough_enabled)
if (SConfig::GetInstance().bWii && !Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED))
{
//This is where we must translate the OpenEmu frontend keys presses stored in the keymap to bitmasks for Dolphin.
return WiiRemotes[port].wiimote_keymap[button].value;
+11 -8
View File
@@ -5,6 +5,9 @@
#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Common/IniFile.h"
#include "Common/Config/Config.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/WiimoteSettings.h"
#include "Core/ConfigManager.h"
#include "Core/HW/GCKeyboard.h"
#include "Core/HW/GCPad.h"
@@ -273,7 +276,7 @@ static bool init_wiimotes = false;
Pad::Initialize();
Keyboard::Initialize();
if (SConfig::GetInstance().bWii && !SConfig::GetInstance().m_bt_passthrough_enabled)
if (SConfig::GetInstance().bWii && !Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED))
{
init_wiimotes = true;
Wiimote::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES);
@@ -371,7 +374,7 @@ void Input::openemu_set_controller_port_device(unsigned port, unsigned device)
gcPad->UpdateReferences(g_controller_interface);
Pad::GetConfig()->SaveConfig();
if (SConfig::GetInstance().bWii && !SConfig::GetInstance().m_bt_passthrough_enabled)
if (SConfig::GetInstance().bWii && !Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED))
{
WiimoteEmu::Wiimote* wm = (WiimoteEmu::Wiimote*)Wiimote::GetConfig()->GetController(port);
// load an empty inifile section, clears everything
@@ -506,34 +509,34 @@ void Input::openemu_set_controller_port_device(unsigned port, unsigned device)
{
case OEWiimote:
wmExtension->SetSelectedAttachment(ExtensionNumber::NONE);
WiimoteCommon::SetSource(port, WiimoteSource::Emulated);
Config::SetCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Emulated);
break;
case OEWiimoteSW:
wmExtension->SetSelectedAttachment(ExtensionNumber::NONE);
static_cast<ControllerEmu::NumericSetting<bool>*>(wmOptions->numeric_settings[2].get())
->SetValue(true); // Sideways Wiimote
WiimoteCommon::SetSource(port, WiimoteSource::Emulated);
Config::SetCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Emulated);
break;
case OEWiimoteNC:
wmExtension->SetSelectedAttachment(ExtensionNumber::NUNCHUK);
WiimoteCommon::SetSource(port, WiimoteSource::Emulated);
Config::SetCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Emulated);
break;
case OEWiimoteCC:
case OEWiimoteCC_Pro:
wmExtension->SetSelectedAttachment(ExtensionNumber::CLASSIC);
WiimoteCommon::SetSource(port, WiimoteSource::Emulated);
Config::SetCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Emulated);
break;
case OEWiiMoteReal:
//desc = Libretro::Input::descEmpty;
WiimoteCommon::SetSource(port, WiimoteSource::Real);
Config::SetCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Real);
default:
//desc = Libretro::Input::descGC;
WiimoteCommon::SetSource(port, WiimoteSource::None);
Config::SetCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::None);
break;
}
wm->UpdateReferences(g_controller_interface);
+524
View File
@@ -0,0 +1,524 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/Metal/MTLGfx.h"
#include "VideoBackends/Metal/MTLBoundingBox.h"
#include "VideoBackends/Metal/MTLObjectCache.h"
#include "VideoBackends/Metal/MTLPipeline.h"
#include "VideoBackends/Metal/MTLStateTracker.h"
#include "VideoBackends/Metal/MTLTexture.h"
#include "VideoBackends/Metal/MTLUtil.h"
#include "VideoBackends/Metal/MTLVertexFormat.h"
#include "VideoBackends/Metal/MTLVertexManager.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoBackendBase.h"
#import "DolphinGameCore.h"
#include <fstream>
Metal::Gfx::Gfx(MRCOwned<CAMetalLayer*> layer) : m_layer(std::move(layer))
{
UpdateActiveConfig();
[m_layer setDisplaySyncEnabled:g_ActiveConfig.bVSyncActive];
SetupSurface();
g_state_tracker->FlushEncoders();
}
Metal::Gfx::~Gfx() = default;
bool Metal::Gfx::IsHeadless() const
{
return m_layer == nullptr;
}
// MARK: Texture Creation
std::unique_ptr<AbstractTexture> Metal::Gfx::CreateTexture(const TextureConfig& config,
std::string_view name)
{
@autoreleasepool
{
MRCOwned<MTLTextureDescriptor*> desc = MRCTransfer([MTLTextureDescriptor new]);
[desc setTextureType:config.samples > 1 ? MTLTextureType2DMultisampleArray :
MTLTextureType2DArray];
[desc setPixelFormat:Util::FromAbstract(config.format)];
[desc setWidth:config.width];
[desc setHeight:config.height];
[desc setMipmapLevelCount:config.levels];
[desc setArrayLength:config.layers];
[desc setSampleCount:config.samples];
[desc setStorageMode:MTLStorageModePrivate];
MTLTextureUsage usage = MTLTextureUsageShaderRead;
if (config.IsRenderTarget())
usage |= MTLTextureUsageRenderTarget;
if (config.IsComputeImage())
usage |= MTLTextureUsageShaderWrite;
[desc setUsage:usage];
id<MTLTexture> texture = [g_device newTextureWithDescriptor:desc];
if (!texture)
return nullptr;
if (name.empty())
[texture setLabel:[NSString stringWithFormat:@"Texture %d", m_texture_counter++]];
else
[texture setLabel:MRCTransfer([[NSString alloc] initWithBytes:name.data()
length:name.size()
encoding:NSUTF8StringEncoding])];
return std::make_unique<Texture>(MRCTransfer(texture), config);
}
}
std::unique_ptr<AbstractStagingTexture>
Metal::Gfx::CreateStagingTexture(StagingTextureType type, const TextureConfig& config)
{
@autoreleasepool
{
const size_t stride = config.GetStride();
const size_t buffer_size = stride * static_cast<size_t>(config.height);
MTLResourceOptions options = MTLStorageModeShared;
if (type == StagingTextureType::Upload)
options |= MTLResourceCPUCacheModeWriteCombined;
id<MTLBuffer> buffer = [g_device newBufferWithLength:buffer_size options:options];
if (!buffer)
return nullptr;
[buffer
setLabel:[NSString stringWithFormat:@"Staging Texture %d", m_staging_texture_counter++]];
return std::make_unique<StagingTexture>(MRCTransfer(buffer), type, config);
}
}
std::unique_ptr<AbstractFramebuffer>
Metal::Gfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment)
{
AbstractTexture* const either_attachment = color_attachment ? color_attachment : depth_attachment;
return std::make_unique<Framebuffer>(
color_attachment, depth_attachment, either_attachment->GetWidth(),
either_attachment->GetHeight(), either_attachment->GetLayers(),
either_attachment->GetSamples());
}
// MARK: Pipeline Creation
std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromSource(ShaderStage stage,
std::string_view source,
std::string_view name)
{
std::optional<std::string> msl = Util::TranslateShaderToMSL(stage, source);
if (!msl.has_value())
{
PanicAlertFmt("Failed to convert shader {} to MSL", name);
return nullptr;
}
return CreateShaderFromMSL(stage, std::move(*msl), source, name);
}
std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromBinary(ShaderStage stage,
const void* data, size_t length,
std::string_view name)
{
return CreateShaderFromMSL(stage, std::string(static_cast<const char*>(data), length), {}, name);
}
// clang-format off
static const char* StageFilename(ShaderStage stage)
{
switch (stage)
{
case ShaderStage::Vertex: return "vs";
case ShaderStage::Geometry: return "gs";
case ShaderStage::Pixel: return "ps";
case ShaderStage::Compute: return "cs";
}
}
static NSString* GenericShaderName(ShaderStage stage)
{
switch (stage)
{
case ShaderStage::Vertex: return @"Vertex shader %d";
case ShaderStage::Geometry: return @"Geometry shader %d";
case ShaderStage::Pixel: return @"Pixel shader %d";
case ShaderStage::Compute: return @"Compute shader %d";
}
}
// clang-format on
std::unique_ptr<AbstractShader> Metal::Gfx::CreateShaderFromMSL(ShaderStage stage, std::string msl,
std::string_view glsl,
std::string_view name)
{
@autoreleasepool
{
NSError* err = nullptr;
auto DumpBadShader = [&](std::string_view msg) {
static int counter = 0;
std::string filename = VideoBackendBase::BadShaderFilename(StageFilename(stage), counter++);
std::ofstream stream(filename);
if (stream.good())
{
stream << msl << std::endl;
stream << "/*" << std::endl;
stream << msg << std::endl;
stream << "Error:" << std::endl;
stream << [[err localizedDescription] UTF8String] << std::endl;
if (!glsl.empty())
{
stream << "Original GLSL:" << std::endl;
stream << glsl << std::endl;
}
else
{
stream << "Shader was created with cached MSL so no GLSL is available." << std::endl;
}
}
stream << std::endl;
stream << "Dolphin Version: " << Common::GetScmRevStr() << std::endl;
stream << "Video Backend: " << g_video_backend->GetDisplayName() << std::endl;
stream << "*/" << std::endl;
stream.close();
PanicAlertFmt("{} (written to {})\n", msg, filename);
};
auto lib = MRCTransfer([g_device newLibraryWithSource:[NSString stringWithUTF8String:msl.data()]
options:nil
error:&err]);
if (err)
{
DumpBadShader(fmt::format("Failed to compile {}", name));
return nullptr;
}
auto fn = MRCTransfer([lib newFunctionWithName:@"main0"]);
if (!fn)
{
DumpBadShader(fmt::format("Shader {} is missing its main0 function", name));
return nullptr;
}
if (!name.empty())
[fn setLabel:MRCTransfer([[NSString alloc] initWithBytes:name.data()
length:name.size()
encoding:NSUTF8StringEncoding])];
else
[fn setLabel:[NSString stringWithFormat:GenericShaderName(stage),
m_shader_counter[static_cast<u32>(stage)]++]];
[lib setLabel:[fn label]];
if (stage == ShaderStage::Compute)
{
MTLComputePipelineReflection* reflection = nullptr;
auto desc = [MTLComputePipelineDescriptor new];
[desc setComputeFunction:fn];
[desc setLabel:[fn label]];
MRCOwned<id<MTLComputePipelineState>> pipeline =
MRCTransfer([g_device newComputePipelineStateWithDescriptor:desc
options:MTLPipelineOptionArgumentInfo
reflection:&reflection
error:&err]);
if (err)
{
DumpBadShader(fmt::format("Failed to compile compute pipeline {}", name));
return nullptr;
}
return std::make_unique<ComputePipeline>(stage, reflection, std::move(msl), std::move(fn),
std::move(pipeline));
}
return std::make_unique<Shader>(stage, std::move(msl), std::move(fn));
}
}
std::unique_ptr<NativeVertexFormat>
Metal::Gfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
@autoreleasepool
{
return std::make_unique<VertexFormat>(vtx_decl);
}
}
std::unique_ptr<AbstractPipeline> Metal::Gfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return g_object_cache->CreatePipeline(config);
}
void Metal::Gfx::Flush()
{
@autoreleasepool
{
g_state_tracker->FlushEncoders();
}
}
void Metal::Gfx::WaitForGPUIdle()
{
@autoreleasepool
{
g_state_tracker->FlushEncoders();
g_state_tracker->WaitForFlushedEncoders();
}
}
void Metal::Gfx::OnConfigChanged(u32 bits)
{
AbstractGfx::OnConfigChanged(bits);
if (bits & CONFIG_CHANGE_BIT_VSYNC)
[m_layer setDisplaySyncEnabled:g_ActiveConfig.bVSyncActive];
if (bits & CONFIG_CHANGE_BIT_ANISOTROPY)
{
g_object_cache->ReloadSamplers();
g_state_tracker->ReloadSamplers();
}
}
void Metal::Gfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool color_enable,
bool alpha_enable, bool z_enable, u32 color, u32 z)
{
u32 framebuffer_width = m_current_framebuffer->GetWidth();
u32 framebuffer_height = m_current_framebuffer->GetHeight();
// All Metal render passes are fullscreen, so we can only run a fast clear if the target is too
if (target_rc == MathUtil::Rectangle<int>(0, 0, framebuffer_width, framebuffer_height))
{
// Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha
// channel to 0xFF. This hopefully allows us to use the fast path in most cases.
if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16 ||
bpmem.zcontrol.pixel_format == PixelFormat::RGB8_Z24 ||
bpmem.zcontrol.pixel_format == PixelFormat::Z24)
{
// Force alpha writes, and clear the alpha channel. This is different from the other backends,
// where the existing values of the alpha channel are preserved.
alpha_enable = true;
color &= 0x00FFFFFF;
}
bool c_ok = (color_enable && alpha_enable) ||
g_state_tracker->GetCurrentFramebuffer()->GetColorFormat() ==
AbstractTextureFormat::Undefined;
bool z_ok = z_enable || g_state_tracker->GetCurrentFramebuffer()->GetDepthFormat() ==
AbstractTextureFormat::Undefined;
if (c_ok && z_ok)
{
@autoreleasepool
{
// clang-format off
MTLClearColor clear_color = MTLClearColorMake(
static_cast<double>((color >> 16) & 0xFF) / 255.0,
static_cast<double>((color >> 8) & 0xFF) / 255.0,
static_cast<double>((color >> 0) & 0xFF) / 255.0,
static_cast<double>((color >> 24) & 0xFF) / 255.0);
// clang-format on
float z_normalized = static_cast<float>(z & 0xFFFFFF) / 16777216.0f;
if (!g_Config.backend_info.bSupportsReversedDepthRange)
z_normalized = 1.f - z_normalized;
g_state_tracker->BeginClearRenderPass(clear_color, z_normalized);
return;
}
}
}
g_state_tracker->EnableEncoderLabel(false);
AbstractGfx::ClearRegion(target_rc, color_enable, alpha_enable, z_enable, color, z);
g_state_tracker->EnableEncoderLabel(true);
}
void Metal::Gfx::SetPipeline(const AbstractPipeline* pipeline)
{
g_state_tracker->SetPipeline(static_cast<const Pipeline*>(pipeline));
}
void Metal::Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
// Shouldn't be bound as a texture.
if (AbstractTexture* color = framebuffer->GetColorAttachment())
g_state_tracker->UnbindTexture(static_cast<Texture*>(color)->GetMTLTexture());
if (AbstractTexture* depth = framebuffer->GetDepthAttachment())
g_state_tracker->UnbindTexture(static_cast<Texture*>(depth)->GetMTLTexture());
m_current_framebuffer = framebuffer;
g_state_tracker->SetCurrentFramebuffer(static_cast<Framebuffer*>(framebuffer));
}
void Metal::Gfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
@autoreleasepool
{
SetFramebuffer(framebuffer);
g_state_tracker->BeginRenderPass(MTLLoadActionDontCare);
}
}
void Metal::Gfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
const ClearColor& color_value, float depth_value)
{
@autoreleasepool
{
SetFramebuffer(framebuffer);
MTLClearColor color =
MTLClearColorMake(color_value[0], color_value[1], color_value[2], color_value[3]);
g_state_tracker->BeginClearRenderPass(color, depth_value);
}
}
void Metal::Gfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{
g_state_tracker->SetScissor(rc);
}
void Metal::Gfx::SetTexture(u32 index, const AbstractTexture* texture)
{
g_state_tracker->SetTexture(
index, texture ? static_cast<const Texture*>(texture)->GetMTLTexture() : nullptr);
}
void Metal::Gfx::SetSamplerState(u32 index, const SamplerState& state)
{
g_state_tracker->SetSampler(index, state);
}
void Metal::Gfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{
g_state_tracker->SetComputeTexture(static_cast<const Texture*>(texture));
}
void Metal::Gfx::UnbindTexture(const AbstractTexture* texture)
{
g_state_tracker->UnbindTexture(static_cast<const Texture*>(texture)->GetMTLTexture());
}
void Metal::Gfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
g_state_tracker->SetViewport(x, y, width, height, near_depth, far_depth);
}
void Metal::Gfx::Draw(u32 base_vertex, u32 num_vertices)
{
@autoreleasepool
{
g_state_tracker->Draw(base_vertex, num_vertices);
}
}
void Metal::Gfx::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{
@autoreleasepool
{
g_state_tracker->DrawIndexed(base_index, num_indices, base_vertex);
}
}
void Metal::Gfx::DispatchComputeShader(const AbstractShader* shader, //
u32 groupsize_x, u32 groupsize_y, u32 groupsize_z,
u32 groups_x, u32 groups_y, u32 groups_z)
{
@autoreleasepool
{
g_state_tracker->SetPipeline(static_cast<const ComputePipeline*>(shader));
g_state_tracker->DispatchComputeShader(groupsize_x, groupsize_y, groupsize_z, //
groups_x, groups_y, groups_z);
}
}
void Metal::Gfx::BindBackbuffer(const ClearColor& clear_color)
{
@autoreleasepool
{
CheckForSurfaceChange();
CheckForSurfaceResize();
m_drawable = MRCRetain([m_layer nextDrawable]);
m_bb_texture->SetMTLTexture(MRCRetain([m_drawable texture]));
SetAndClearFramebuffer(m_backbuffer.get(), clear_color);
}
}
void Metal::Gfx::PresentBackbuffer()
{
@autoreleasepool
{
g_state_tracker->EndRenderPass();
if (m_drawable)
{
//OpenEmu Blit to GameCoore Texture for Rendering
id<MTLBlitCommandEncoder> blitCommandEncoder = [g_state_tracker->GetRenderCmdBuf() blitCommandEncoder];
if (@available(macOS 10.15, *)) {
[blitCommandEncoder copyFromTexture:[m_drawable texture] toTexture:id<MTLTexture>([_current metalTexture])];
} else {
// Fallback on earlier versions
// TODO: Add pre 10.15 metal blit
}
[blitCommandEncoder endEncoding];
// PresentDrawable refuses to allow Dolphin to present faster than the display's refresh rate
// when windowed (or fullscreen with vsync enabled, but that's more understandable).
// On the other hand, it helps Xcode's GPU captures start and stop on frame boundaries
// which is convenient. Put it here as a default-off config, which we can override in Xcode.
// It also seems to improve frame pacing, so enable it by default with vsync
if (g_ActiveConfig.iUsePresentDrawable == TriState::On ||
(g_ActiveConfig.iUsePresentDrawable == TriState::Auto && g_ActiveConfig.bVSyncActive))
[g_state_tracker->GetRenderCmdBuf() presentDrawable:m_drawable];
else
[g_state_tracker->GetRenderCmdBuf()
addScheduledHandler:[drawable = std::move(m_drawable)](id) { [drawable present]; }];
m_bb_texture->SetMTLTexture(nullptr);
m_drawable = nullptr;
}
g_state_tracker->FlushEncoders();
}
}
void Metal::Gfx::CheckForSurfaceChange()
{
if (!g_presenter->SurfaceChangedTestAndClear())
return;
m_layer = MRCRetain(static_cast<CAMetalLayer*>(g_presenter->GetNewSurfaceHandle()));
SetupSurface();
}
void Metal::Gfx::CheckForSurfaceResize()
{
if (!g_presenter->SurfaceResizedTestAndClear())
return;
SetupSurface();
}
void Metal::Gfx::SetupSurface()
{
auto info = GetSurfaceInfo();
[m_layer setDrawableSize:{static_cast<double>(info.width), static_cast<double>(info.height)}];
TextureConfig cfg(info.width, info.height, 1, 1, 1, info.format,
AbstractTextureFlag_RenderTarget);
m_bb_texture = std::make_unique<Texture>(nullptr, cfg);
m_backbuffer = std::make_unique<Framebuffer>(m_bb_texture.get(), nullptr, //
info.width, info.height, 1, 1);
if (g_presenter)
g_presenter->SetBackbuffer(info);
}
SurfaceInfo Metal::Gfx::GetSurfaceInfo() const
{
if (!m_layer) // Headless
return {};
CGSize size = [m_layer bounds].size;
const float scale = [m_layer contentsScale];
return {static_cast<u32>(size.width * scale), static_cast<u32>(size.height * scale), scale,
Util::ToAbstract([m_layer pixelFormat])};
}
+160
View File
@@ -0,0 +1,160 @@
// Copyright 2022 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/Metal/VideoBackend.h"
// This must be included before we use any TARGET_OS_* macros.
#include <TargetConditionals.h>
#if TARGET_OS_OSX
#include <AppKit/AppKit.h>
#endif
#include <Metal/Metal.h>
#include <QuartzCore/QuartzCore.h>
#include "Common/Common.h"
#include "Common/MsgHandler.h"
#include "VideoBackends/Metal/MTLBoundingBox.h"
#include "VideoBackends/Metal/MTLGfx.h"
#include "VideoBackends/Metal/MTLObjectCache.h"
#include "VideoBackends/Metal/MTLPerfQuery.h"
#include "VideoBackends/Metal/MTLStateTracker.h"
#include "VideoBackends/Metal/MTLUtil.h"
#include "VideoBackends/Metal/MTLVertexManager.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
#import "DolphinGameCore.h"
std::string Metal::VideoBackend::GetName() const
{
return NAME;
}
std::string Metal::VideoBackend::GetDisplayName() const
{
// i18n: Apple's Metal graphics API (https://developer.apple.com/metal/)
return _trans("Metal");
}
std::optional<std::string> Metal::VideoBackend::GetWarningMessage() const
{
// if (Util::GetAdapterList().empty())
// {
// return _trans("No Metal-compatible GPUs were found. "
// "Use the OpenGL backend or upgrade your computer/GPU");
// }
return std::nullopt;
}
static bool WindowSystemTypeSupportsMetal(WindowSystemType type)
{
// switch (type)
// {
// case WindowSystemType::MacOS:
// case WindowSystemType::Headless:
return true;
// default:
// return false;
// }
}
bool Metal::VideoBackend::Initialize(const WindowSystemInfo& wsi)
{
@autoreleasepool
{
const bool surface_ok = wsi.type == WindowSystemType::Headless || wsi.render_surface;
if (!WindowSystemTypeSupportsMetal(wsi.type) || !surface_ok)
{
PanicAlertFmt("Bad WindowSystemInfo for Metal renderer.");
return false;
}
Util::PopulateBackendInfo(&g_Config);
std::vector<MRCOwned<id<MTLDevice>>> adapters;
adapters.push_back(MRCTransfer([_current metalDevice]));
Util::PopulateBackendInfoAdapters(&g_Config, adapters);
if (!adapters.empty())
{
// Use the selected adapter, or the first to fill features.
size_t index = static_cast<size_t>(g_Config.iAdapter);
if (index >= adapters.size())
index = 0;
Util::PopulateBackendInfoFeatures(&g_Config, adapters[index]);
}
// Since we haven't called InitializeShared yet, iAdapter may be out of range,
// so we have to check it ourselves.
size_t selected_adapter_index = static_cast<size_t>(g_Config.iAdapter);
if (selected_adapter_index >= adapters.size())
{
WARN_LOG_FMT(VIDEO, "Metal adapter index out of range, selecting default adapter.");
selected_adapter_index = 0;
}
MRCOwned<id<MTLDevice>> adapter = MRCOwned<id<MTLDevice>>(MRCRetain([_current metalDevice]));
Util::PopulateBackendInfoFeatures(&g_Config, adapter);
UpdateActiveConfig();
MRCOwned<CAMetalLayer*> layer = MRCRetain(static_cast<CAMetalLayer*>(wsi.render_surface));
//MRCOwned<CAMetalLayer*> layer = MRCRetain([CAMetalLayer layer]);
layer.Get().framebufferOnly=NO;
[layer setDevice:adapter];
if (Util::ToAbstract([layer pixelFormat]) == AbstractTextureFormat::Undefined)
[layer setPixelFormat:MTLPixelFormatBGRA8Unorm];
ObjectCache::Initialize(std::move(adapter));
g_state_tracker = std::make_unique<StateTracker>();
return InitializeShared(
std::make_unique<Metal::Gfx>(std::move(layer)), std::make_unique<Metal::VertexManager>(),
std::make_unique<Metal::PerfQuery>(), std::make_unique<Metal::BoundingBox>());
}
}
void Metal::VideoBackend::Shutdown()
{
ShutdownShared();
g_state_tracker.reset();
ObjectCache::Shutdown();
}
void Metal::VideoBackend::InitBackendInfo()
{
@autoreleasepool
{
Util::PopulateBackendInfo(&g_Config);
std::vector<MRCOwned<id<MTLDevice>>> adapters;
adapters.push_back(MRCTransfer([_current metalDevice]));
Util::PopulateBackendInfoAdapters(&g_Config, adapters);
if (!adapters.empty())
{
// Use the selected adapter, or the first to fill features.
size_t index = static_cast<size_t>(g_Config.iAdapter);
if (index >= adapters.size())
index = 0;
Util::PopulateBackendInfoFeatures(&g_Config, adapters[index]);
}
}
}
void Metal::VideoBackend::PrepareWindow(WindowSystemInfo& wsi)
{
//#if TARGET_OS_OSX
// if (wsi.type != WindowSystemType::MacOS)
// return;
// NSView* view = static_cast<NSView*>(wsi.render_surface);
CAMetalLayer* layer = [CAMetalLayer layer];
// [view setWantsLayer:YES];
// [view setLayer:layer];
wsi.render_surface = layer;
//#endif
}
+731
View File
@@ -0,0 +1,731 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "VideoBackends/OGL/OGLGfx.h"
#include "Common/GL/GLContext.h"
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "Common/Logging/LogManager.h"
#include "Core/Config/GraphicsSettings.h"
#include "VideoBackends/OGL/OGLConfig.h"
#include "VideoBackends/OGL/OGLPipeline.h"
#include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/OGLTexture.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "VideoBackends/OGL/SamplerCache.h"
#include "VideoCommon/AsyncShaderCompiler.h"
#include "VideoCommon/DriverDetails.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VideoConfig.h"
#include <string_view>
namespace OGL
{
VideoConfig g_ogl_config;
static void APIENTRY ErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const char* message, const void* userParam)
{
const char* s_source;
const char* s_type;
// Performance - DualCore driver performance warning:
// DualCore application thread syncing with server thread
if (id == 0x200b0)
return;
switch (source)
{
case GL_DEBUG_SOURCE_API_ARB:
s_source = "API";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
s_source = "Window System";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
s_source = "Shader Compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
s_source = "Third Party";
break;
case GL_DEBUG_SOURCE_APPLICATION_ARB:
s_source = "Application";
break;
case GL_DEBUG_SOURCE_OTHER_ARB:
s_source = "Other";
break;
default:
s_source = "Unknown";
break;
}
switch (type)
{
case GL_DEBUG_TYPE_ERROR_ARB:
s_type = "Error";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
s_type = "Deprecated";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
s_type = "Undefined";
break;
case GL_DEBUG_TYPE_PORTABILITY_ARB:
s_type = "Portability";
break;
case GL_DEBUG_TYPE_PERFORMANCE_ARB:
s_type = "Performance";
break;
case GL_DEBUG_TYPE_OTHER_ARB:
s_type = "Other";
break;
default:
s_type = "Unknown";
break;
}
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH_ARB:
ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
case GL_DEBUG_SEVERITY_MEDIUM_ARB:
WARN_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
case GL_DEBUG_SEVERITY_LOW_ARB:
DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
DEBUG_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
default:
ERROR_LOG_FMT(HOST_GPU, "id: {:x}, source: {}, type: {} - {}", id, s_source, s_type, message);
break;
}
}
// Two small Fallbacks to avoid GL_ARB_ES2_compatibility
static void APIENTRY DepthRangef(GLfloat neardepth, GLfloat fardepth)
{
glDepthRange(neardepth, fardepth);
}
static void APIENTRY ClearDepthf(GLfloat depthval)
{
glClearDepth(depthval);
}
OGLGfx::OGLGfx(std::unique_ptr<GLContext> main_gl_context, float backbuffer_scale)
: m_main_gl_context(std::move(main_gl_context)),
m_current_rasterization_state(RenderState::GetInvalidRasterizationState()),
m_current_depth_state(RenderState::GetInvalidDepthState()),
m_current_blend_state(RenderState::GetInvalidBlendingState()),
m_backbuffer_scale(backbuffer_scale)
{
// Create the window framebuffer.
if (!m_main_gl_context->IsHeadless())
{
m_system_framebuffer = std::make_unique<OGLFramebuffer>(
nullptr, nullptr, AbstractTextureFormat::RGBA8, AbstractTextureFormat::Undefined,
std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
std::max(m_main_gl_context->GetBackBufferHeight(), 1u), 1, 1, g_Config.iRenderFBO);
m_current_framebuffer = m_system_framebuffer.get();
}
if (!m_main_gl_context->IsGLES())
{
// OpenGL 3 doesn't provide GLES like float functions for depth.
// They are in core in OpenGL 4.1, so almost every driver should support them.
// But for the oldest ones, we provide fallbacks to the old double functions.
if (!GLExtensions::Supports("GL_ARB_ES2_compatibility"))
{
glDepthRangef = DepthRangef;
glClearDepthf = ClearDepthf;
}
}
if (!PopulateConfig(m_main_gl_context.get()))
{
// Not all needed extensions are supported, so we have to stop here.
// Else some of the next calls might crash.
return;
}
InitDriverInfo();
// Setup Debug logging
if (g_ogl_config.bSupportsDebug)
{
if (GLExtensions::Supports("GL_KHR_debug"))
{
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
glDebugMessageCallback(ErrorCallback, nullptr);
}
else
{
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, true);
glDebugMessageCallbackARB(ErrorCallback, nullptr);
}
if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
Common::Log::LogLevel::LERROR))
{
glEnable(GL_DEBUG_OUTPUT);
}
else
{
glDisable(GL_DEBUG_OUTPUT);
}
}
// Handle VSync on/off
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
if (g_ActiveConfig.backend_info.bSupportsClipControl)
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glEnable(GL_CLIP_DISTANCE0);
glEnable(GL_CLIP_DISTANCE1);
glEnable(GL_DEPTH_CLAMP);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
glGenFramebuffers(1, &m_shared_read_framebuffer);
glGenFramebuffers(1, &m_shared_draw_framebuffer);
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
GLUtil::EnablePrimitiveRestart(m_main_gl_context.get());
UpdateActiveConfig();
}
OGLGfx::~OGLGfx()
{
glDeleteFramebuffers(1, &m_shared_draw_framebuffer);
glDeleteFramebuffers(1, &m_shared_read_framebuffer);
}
bool OGLGfx::IsHeadless() const
{
return m_main_gl_context->IsHeadless();
}
std::unique_ptr<AbstractTexture> OGLGfx::CreateTexture(const TextureConfig& config,
std::string_view name)
{
return std::make_unique<OGLTexture>(config, name);
}
std::unique_ptr<AbstractStagingTexture> OGLGfx::CreateStagingTexture(StagingTextureType type,
const TextureConfig& config)
{
return OGLStagingTexture::Create(type, config);
}
std::unique_ptr<AbstractFramebuffer> OGLGfx::CreateFramebuffer(AbstractTexture* color_attachment,
AbstractTexture* depth_attachment)
{
return OGLFramebuffer::Create(static_cast<OGLTexture*>(color_attachment),
static_cast<OGLTexture*>(depth_attachment));
}
std::unique_ptr<AbstractShader>
OGLGfx::CreateShaderFromSource(ShaderStage stage, std::string_view source, std::string_view name)
{
return OGLShader::CreateFromSource(stage, source, name);
}
std::unique_ptr<AbstractShader>
OGLGfx::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length,
[[maybe_unused]] std::string_view name)
{
return nullptr;
}
std::unique_ptr<AbstractPipeline> OGLGfx::CreatePipeline(const AbstractPipelineConfig& config,
const void* cache_data,
size_t cache_data_length)
{
return OGLPipeline::Create(config, cache_data, cache_data_length);
}
void OGLGfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
{
glScissor(rc.left, rc.top, rc.GetWidth(), rc.GetHeight());
}
void OGLGfx::SetViewport(float x, float y, float width, float height, float near_depth,
float far_depth)
{
if (g_ogl_config.bSupportViewportFloat)
{
glViewportIndexedf(0, x, y, width, height);
}
else
{
auto iceilf = [](float f) { return static_cast<GLint>(std::ceil(f)); };
glViewport(iceilf(x), iceilf(y), iceilf(width), iceilf(height));
}
glDepthRangef(near_depth, far_depth);
}
void OGLGfx::Draw(u32 base_vertex, u32 num_vertices)
{
glDrawArrays(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(), base_vertex,
num_vertices);
}
void OGLGfx::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex)
{
if (g_ogl_config.bSupportsGLBaseVertex)
{
glDrawElementsBaseVertex(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT,
static_cast<u16*>(nullptr) + base_index, base_vertex);
}
else
{
glDrawElements(static_cast<const OGLPipeline*>(m_current_pipeline)->GetGLPrimitive(),
num_indices, GL_UNSIGNED_SHORT, static_cast<u16*>(nullptr) + base_index);
}
}
void OGLGfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
{
glUseProgram(static_cast<const OGLShader*>(shader)->GetGLComputeProgramID());
glDispatchCompute(groups_x, groups_y, groups_z);
// We messed up the program binding, so restore it.
ProgramShaderCache::InvalidateLastProgram();
if (m_current_pipeline)
static_cast<const OGLPipeline*>(m_current_pipeline)->GetProgram()->shader.Bind();
// Barrier to texture can be used for reads.
if (m_bound_image_texture)
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
}
void OGLGfx::SelectLeftBuffer()
{
glDrawBuffer(GL_BACK_LEFT);
}
void OGLGfx::SelectRightBuffer()
{
glDrawBuffer(GL_BACK_RIGHT);
}
void OGLGfx::SelectMainBuffer()
{
glDrawBuffer(GL_BACK);
}
void OGLGfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
{
if (m_current_framebuffer == framebuffer)
return;
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<OGLFramebuffer*>(framebuffer)->GetFBO());
m_current_framebuffer = framebuffer;
}
void OGLGfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
{
// EXT_discard_framebuffer could be used here to save bandwidth on tilers.
SetFramebuffer(framebuffer);
}
void OGLGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value,
float depth_value)
{
SetFramebuffer(framebuffer);
glDisable(GL_SCISSOR_TEST);
GLbitfield clear_mask = 0;
if (framebuffer->HasColorBuffer())
{
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(color_value[0], color_value[1], color_value[2], color_value[3]);
clear_mask |= GL_COLOR_BUFFER_BIT;
}
if (framebuffer->HasDepthBuffer())
{
glDepthMask(GL_TRUE);
glClearDepthf(depth_value);
clear_mask |= GL_DEPTH_BUFFER_BIT;
}
glClear(clear_mask);
glEnable(GL_SCISSOR_TEST);
// Restore color/depth mask.
if (framebuffer->HasColorBuffer())
{
glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
}
if (framebuffer->HasDepthBuffer())
glDepthMask(m_current_depth_state.updateenable);
}
void OGLGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEnable,
bool alphaEnable, bool zEnable, u32 color, u32 z)
{
u32 clear_mask = 0;
if (colorEnable || alphaEnable)
{
glColorMask(colorEnable, colorEnable, colorEnable, alphaEnable);
glClearColor(float((color >> 16) & 0xFF) / 255.0f, float((color >> 8) & 0xFF) / 255.0f,
float((color >> 0) & 0xFF) / 255.0f, float((color >> 24) & 0xFF) / 255.0f);
clear_mask = GL_COLOR_BUFFER_BIT;
}
if (zEnable)
{
glDepthMask(zEnable ? GL_TRUE : GL_FALSE);
glClearDepthf(float(z & 0xFFFFFF) / 16777216.0f);
clear_mask |= GL_DEPTH_BUFFER_BIT;
}
// Update rect for clearing the picture
// glColorMask/glDepthMask/glScissor affect glClear (glViewport does not)
g_gfx->SetScissorRect(target_rc);
glClear(clear_mask);
// Restore color/depth mask.
if (colorEnable || alphaEnable)
{
glColorMask(m_current_blend_state.colorupdate, m_current_blend_state.colorupdate,
m_current_blend_state.colorupdate, m_current_blend_state.alphaupdate);
}
if (zEnable)
glDepthMask(m_current_depth_state.updateenable);
}
void OGLGfx::BindBackbuffer(const ClearColor& clear_color)
{
CheckForSurfaceChange();
CheckForSurfaceResize();
SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color);
}
void OGLGfx::PresentBackbuffer()
{
if (g_ogl_config.bSupportsDebug)
{
if (Common::Log::LogManager::GetInstance()->IsEnabled(Common::Log::LogType::HOST_GPU,
Common::Log::LogLevel::LERROR))
{
glEnable(GL_DEBUG_OUTPUT);
}
else
{
glDisable(GL_DEBUG_OUTPUT);
}
}
// Swap the back and front buffers, presenting the image.
m_main_gl_context->Swap();
}
void OGLGfx::OnConfigChanged(u32 bits)
{
AbstractGfx::OnConfigChanged(bits);
if (bits & CONFIG_CHANGE_BIT_VSYNC && !DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
m_main_gl_context->SwapInterval(g_ActiveConfig.bVSyncActive);
if (bits & CONFIG_CHANGE_BIT_ANISOTROPY)
g_sampler_cache->Clear();
}
void OGLGfx::Flush()
{
// ensure all commands are sent to the GPU.
// Otherwise the driver could batch several frames together.
glFlush();
}
void OGLGfx::WaitForGPUIdle()
{
glFinish();
}
void OGLGfx::CheckForSurfaceChange()
{
if (!g_presenter->SurfaceChangedTestAndClear())
return;
m_main_gl_context->UpdateSurface(g_presenter->GetNewSurfaceHandle());
u32 width = m_main_gl_context->GetBackBufferWidth();
u32 height = m_main_gl_context->GetBackBufferHeight();
// With a surface change, the window likely has new dimensions.
g_presenter->SetBackbuffer(width, height);
m_system_framebuffer->UpdateDimensions(width, height);
}
void OGLGfx::CheckForSurfaceResize()
{
if (!g_presenter->SurfaceResizedTestAndClear())
return;
m_main_gl_context->Update();
u32 width = m_main_gl_context->GetBackBufferWidth();
u32 height = m_main_gl_context->GetBackBufferHeight();
g_presenter->SetBackbuffer(width, height);
m_system_framebuffer->UpdateDimensions(width, height);
}
void OGLGfx::BeginUtilityDrawing()
{
AbstractGfx::BeginUtilityDrawing();
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glDisable(GL_CLIP_DISTANCE0);
glDisable(GL_CLIP_DISTANCE1);
}
}
void OGLGfx::EndUtilityDrawing()
{
AbstractGfx::EndUtilityDrawing();
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
glEnable(GL_CLIP_DISTANCE0);
glEnable(GL_CLIP_DISTANCE1);
}
}
void OGLGfx::ApplyRasterizationState(const RasterizationState state)
{
if (m_current_rasterization_state == state)
return;
// none, ccw, cw, ccw
if (state.cullmode != CullMode::None)
{
// TODO: GX_CULL_ALL not supported, yet!
glEnable(GL_CULL_FACE);
glFrontFace(state.cullmode == CullMode::Front ? GL_CCW : GL_CW);
}
else
{
glDisable(GL_CULL_FACE);
}
m_current_rasterization_state = state;
}
void OGLGfx::ApplyDepthState(const DepthState state)
{
if (m_current_depth_state == state)
return;
const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS};
if (state.testenable)
{
glEnable(GL_DEPTH_TEST);
glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE);
glDepthFunc(glCmpFuncs[u32(state.func.Value())]);
}
else
{
// if the test is disabled write is disabled too
// TODO: When PE performance metrics are being emulated via occlusion queries, we should
// (probably?) enable depth test with depth function ALWAYS here
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
}
m_current_depth_state = state;
}
void OGLGfx::ApplyBlendingState(const BlendingState state)
{
if (m_current_blend_state == state)
return;
bool useDualSource = state.usedualsrc;
const GLenum src_factors[8] = {GL_ZERO,
GL_ONE,
GL_DST_COLOR,
GL_ONE_MINUS_DST_COLOR,
useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
(GLenum)GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA};
const GLenum dst_factors[8] = {GL_ZERO,
GL_ONE,
GL_SRC_COLOR,
GL_ONE_MINUS_SRC_COLOR,
useDualSource ? GL_SRC1_ALPHA : (GLenum)GL_SRC_ALPHA,
useDualSource ? GL_ONE_MINUS_SRC1_ALPHA :
(GLenum)GL_ONE_MINUS_SRC_ALPHA,
GL_DST_ALPHA,
GL_ONE_MINUS_DST_ALPHA};
if (state.blendenable)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
// Always call glBlendEquationSeparate and glBlendFuncSeparate, even when
// GL_BLEND is disabled, as a workaround for some bugs (possibly graphics
// driver issues?). See https://bugs.dolphin-emu.org/issues/10120 : "Sonic
// Adventure 2 Battle: graphics crash when loading first Dark level"
GLenum equation = state.subtract ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
GLenum equationAlpha = state.subtractAlpha ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD;
glBlendEquationSeparate(equation, equationAlpha);
glBlendFuncSeparate(src_factors[u32(state.srcfactor.Value())],
dst_factors[u32(state.dstfactor.Value())],
src_factors[u32(state.srcfactoralpha.Value())],
dst_factors[u32(state.dstfactoralpha.Value())]);
const GLenum logic_op_codes[16] = {
GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP,
GL_XOR, GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE,
GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET};
// Logic ops aren't available in GLES3
if (!IsGLES())
{
if (state.logicopenable)
{
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(logic_op_codes[u32(state.logicmode.Value())]);
}
else
{
glDisable(GL_COLOR_LOGIC_OP);
}
}
glColorMask(state.colorupdate, state.colorupdate, state.colorupdate, state.alphaupdate);
m_current_blend_state = state;
}
void OGLGfx::SetPipeline(const AbstractPipeline* pipeline)
{
if (m_current_pipeline == pipeline)
return;
if (pipeline)
{
ApplyRasterizationState(static_cast<const OGLPipeline*>(pipeline)->GetRasterizationState());
ApplyDepthState(static_cast<const OGLPipeline*>(pipeline)->GetDepthState());
ApplyBlendingState(static_cast<const OGLPipeline*>(pipeline)->GetBlendingState());
ProgramShaderCache::BindVertexFormat(
static_cast<const OGLPipeline*>(pipeline)->GetVertexFormat());
static_cast<const OGLPipeline*>(pipeline)->GetProgram()->shader.Bind();
}
else
{
ProgramShaderCache::InvalidateLastProgram();
glUseProgram(0);
}
m_current_pipeline = pipeline;
}
void OGLGfx::SetTexture(u32 index, const AbstractTexture* texture)
{
const OGLTexture* gl_texture = static_cast<const OGLTexture*>(texture);
if (m_bound_textures[index] == gl_texture)
return;
glActiveTexture(GL_TEXTURE0 + index);
if (gl_texture)
glBindTexture(gl_texture->GetGLTarget(), gl_texture->GetGLTextureId());
else
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
m_bound_textures[index] = gl_texture;
}
void OGLGfx::SetSamplerState(u32 index, const SamplerState& state)
{
g_sampler_cache->SetSamplerState(index, state);
}
void OGLGfx::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write)
{
if (m_bound_image_texture == texture)
return;
if (texture)
{
const GLenum access = read ? (write ? GL_READ_WRITE : GL_READ_ONLY) : GL_WRITE_ONLY;
glBindImageTexture(0, static_cast<OGLTexture*>(texture)->GetGLTextureId(), 0, GL_TRUE, 0,
access, static_cast<OGLTexture*>(texture)->GetGLFormatForImageTexture());
}
else
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
}
m_bound_image_texture = texture;
}
void OGLGfx::UnbindTexture(const AbstractTexture* texture)
{
for (size_t i = 0; i < m_bound_textures.size(); i++)
{
if (m_bound_textures[i] != texture)
continue;
glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + i));
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
m_bound_textures[i] = nullptr;
}
if (m_bound_image_texture == texture)
{
glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
m_bound_image_texture = nullptr;
}
}
std::unique_ptr<VideoCommon::AsyncShaderCompiler> OGLGfx::CreateAsyncShaderCompiler()
{
return std::make_unique<SharedContextAsyncShaderCompiler>();
}
bool OGLGfx::IsGLES() const
{
return m_main_gl_context->IsGLES();
}
void OGLGfx::BindSharedReadFramebuffer()
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_shared_read_framebuffer);
}
void OGLGfx::BindSharedDrawFramebuffer()
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_shared_draw_framebuffer);
}
void OGLGfx::RestoreFramebufferBinding()
{
glBindFramebuffer(
GL_FRAMEBUFFER,
m_current_framebuffer ? static_cast<OGLFramebuffer*>(m_current_framebuffer)->GetFBO() : 0);
}
SurfaceInfo OGLGfx::GetSurfaceInfo() const
{
return {std::max(m_main_gl_context->GetBackBufferWidth(), 1u),
std::max(m_main_gl_context->GetBackBufferHeight(), 1u), m_backbuffer_scale,
AbstractTextureFormat::RGBA8};
}
} // namespace OGL
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,27 @@
// Copyright (c) 2022, OpenEmu Team
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the OpenEmu Team nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef __x86_64__
#include "../../dolphin/Source/Core/VideoCommon/TextureDecoder_x64.cpp"
#endif
@@ -0,0 +1,29 @@
// Copyright (c) 2022, OpenEmu Team
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the OpenEmu Team nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef __x86_64__
#include "../../dolphin/Source/Core/VideoCommon/VertexLoaderX64.cpp"
#elif defined(__arm64__)
#include "../../dolphin/Source/Core/VideoCommon/VertexLoaderARM64.cpp"
#endif
+201 -118
View File
@@ -16,6 +16,8 @@
#include <vector>
#include "Common/CommonTypes.h"
#include "VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.h"
#include "VideoCommon/VideoCommon.h"
enum class APIType;
@@ -53,43 +55,80 @@ enum class ShaderCompilationMode : int
AsynchronousSkipRendering
};
enum class TextureFilteringMode : int
{
Default,
Nearest,
Linear,
};
enum class TriState : int
{
Off,
On,
Auto
};
// Bitmask containing information about which configuration has changed for the backend.
enum ConfigChangeBits : u32
{
CONFIG_CHANGE_BIT_HOST_CONFIG = (1 << 0),
CONFIG_CHANGE_BIT_MULTISAMPLES = (1 << 1),
CONFIG_CHANGE_BIT_STEREO_MODE = (1 << 2),
CONFIG_CHANGE_BIT_TARGET_SIZE = (1 << 3),
CONFIG_CHANGE_BIT_ANISOTROPY = (1 << 4),
CONFIG_CHANGE_BIT_FORCE_TEXTURE_FILTERING = (1 << 5),
CONFIG_CHANGE_BIT_VSYNC = (1 << 6),
CONFIG_CHANGE_BIT_BBOX = (1 << 7),
CONFIG_CHANGE_BIT_ASPECT_RATIO = (1 << 8),
CONFIG_CHANGE_BIT_POST_PROCESSING_SHADER = (1 << 9),
};
// NEVER inherit from this class.
struct VideoConfig final
{
VideoConfig();
VideoConfig() = default;
void Refresh();
void VerifyValidity();
// General
bool bVSync;
bool bVSyncActive;
bool bWidescreenHack;
AspectMode aspect_mode;
AspectMode suggested_aspect_mode;
bool bCrop; // Aspect ratio controls.
bool bShaderCache;
bool bVSync = false;
bool bVSyncActive = false;
bool bWidescreenHack = false;
AspectMode aspect_mode{};
AspectMode suggested_aspect_mode{};
bool bCrop = false; // Aspect ratio controls.
bool bShaderCache = false;
// Enhancements
u32 iMultisamples;
bool bSSAA;
int iEFBScale;
bool bForceFiltering;
int iMaxAnisotropy;
u32 iMultisamples = 0;
bool bSSAA = false;
int iEFBScale = 0;
TextureFilteringMode texture_filtering_mode = TextureFilteringMode::Default;
int iMaxAnisotropy = 0;
std::string sPostProcessingShader;
bool bForceTrueColor;
bool bDisableCopyFilter;
bool bArbitraryMipmapDetection;
float fArbitraryMipmapDetectionThreshold;
bool bForceTrueColor = false;
bool bDisableCopyFilter = false;
bool bArbitraryMipmapDetection = false;
float fArbitraryMipmapDetectionThreshold = 0;
// Information
bool bShowFPS;
bool bShowNetPlayPing;
bool bShowNetPlayMessages;
bool bOverlayStats;
bool bOverlayProjStats;
bool bTexFmtOverlayEnable;
bool bTexFmtOverlayCenter;
bool bLogRenderTimeToFile;
bool bShowFPS = false;
bool bShowFTimes = false;
bool bShowVPS = false;
bool bShowVTimes = false;
bool bShowGraphs = false;
bool bShowSpeed = false;
bool bShowSpeedColors = false;
int iPerfSampleUSec = 0;
bool bShowNetPlayPing = false;
bool bShowNetPlayMessages = false;
bool bOverlayStats = false;
bool bOverlayProjStats = false;
bool bOverlayScissorStats = false;
bool bTexFmtOverlayEnable = false;
bool bTexFmtOverlayCenter = false;
bool bLogRenderTimeToFile = false;
// Render
bool bWireFrame;
@@ -99,94 +138,101 @@ struct VideoConfig final
int iRenderFBO = 0;
// Utility
bool bDumpTextures;
bool bDumpMipmapTextures;
bool bDumpBaseTextures;
bool bHiresTextures;
bool bCacheHiresTextures;
bool bDumpEFBTarget;
bool bDumpXFBTarget;
bool bDumpFramesAsImages;
bool bUseFFV1;
bool bDumpTextures = false;
bool bDumpMipmapTextures = false;
bool bDumpBaseTextures = false;
bool bHiresTextures = false;
bool bCacheHiresTextures = false;
bool bDumpEFBTarget = false;
bool bDumpXFBTarget = false;
bool bDumpFramesAsImages = false;
bool bUseFFV1 = false;
std::string sDumpCodec;
std::string sDumpPixelFormat;
std::string sDumpEncoder;
std::string sDumpFormat;
std::string sDumpPath;
bool bInternalResolutionFrameDumps;
bool bBorderlessFullscreen;
bool bEnableGPUTextureDecoding;
int iBitrateKbps;
bool bInternalResolutionFrameDumps = false;
bool bBorderlessFullscreen = false;
bool bEnableGPUTextureDecoding = false;
bool bPreferVSForLinePointExpansion = false;
int iBitrateKbps = 0;
bool bGraphicMods = false;
std::optional<GraphicsModGroupConfig> graphics_mod_config;
// Hacks
bool bEFBAccessEnable;
bool bEFBAccessDeferInvalidation;
bool bPerfQueriesEnable;
bool bBBoxEnable;
bool bForceProgressive;
bool bEFBAccessEnable = false;
bool bEFBAccessDeferInvalidation = false;
bool bPerfQueriesEnable = false;
bool bBBoxEnable = false;
bool bForceProgressive = false;
bool bCPUCull = false;
bool bEFBEmulateFormatChanges;
bool bSkipEFBCopyToRam;
bool bSkipXFBCopyToRam;
bool bDisableCopyToVRAM;
bool bDeferEFBCopies;
bool bImmediateXFB;
bool bSkipPresentingDuplicateXFBs;
bool bCopyEFBScaled;
int iSafeTextureCache_ColorSamples;
float fAspectRatioHackW, fAspectRatioHackH;
bool bEnablePixelLighting;
bool bFastDepthCalc;
bool bVertexRounding;
int iEFBAccessTileSize;
int iLog; // CONF_ bits
int iSaveTargetId; // TODO: Should be dropped
bool bEFBEmulateFormatChanges = false;
bool bSkipEFBCopyToRam = false;
bool bSkipXFBCopyToRam = false;
bool bDisableCopyToVRAM = false;
bool bDeferEFBCopies = false;
bool bImmediateXFB = false;
bool bSkipPresentingDuplicateXFBs = false;
bool bCopyEFBScaled = false;
int iSafeTextureCache_ColorSamples = 0;
float fAspectRatioHackW = 1; // Initial value needed for the first frame
float fAspectRatioHackH = 1;
bool bEnablePixelLighting = false;
bool bFastDepthCalc = false;
bool bVertexRounding = false;
bool bVISkip = false;
int iEFBAccessTileSize = 0;
int iSaveTargetId = 0; // TODO: Should be dropped
u32 iMissingColorValue = 0;
bool bFastTextureSampling = false;
#ifdef __APPLE__
bool bNoMipmapping = false; // Used by macOS fifoci to work around an M1 bug
#endif
// Stereoscopy
StereoMode stereo_mode;
int iStereoDepth;
int iStereoConvergence;
int iStereoConvergencePercentage;
bool bStereoSwapEyes;
bool bStereoEFBMonoDepth;
int iStereoDepthPercentage;
StereoMode stereo_mode{};
int iStereoDepth = 0;
int iStereoConvergence = 0;
int iStereoConvergencePercentage = 0;
bool bStereoSwapEyes = false;
bool bStereoEFBMonoDepth = false;
int iStereoDepthPercentage = 0;
// D3D only config, mostly to be merged into the above
int iAdapter;
int iAdapter = 0;
// VideoSW Debugging
int drawStart;
int drawEnd;
bool bZComploc;
bool bZFreeze;
bool bDumpObjects;
bool bDumpTevStages;
bool bDumpTevTextureFetches;
// Metal only config
TriState iManuallyUploadBuffers = TriState::Auto;
TriState iUsePresentDrawable = TriState::Auto;
// Enable API validation layers, currently only supported with Vulkan.
bool bEnableValidationLayer;
bool bEnableValidationLayer = false;
// Multithreaded submission, currently only supported with Vulkan.
bool bBackendMultithreading;
bool bBackendMultithreading = true;
// Early command buffer execution interval in number of draws.
// Currently only supported with Vulkan.
int iCommandBufferExecuteInterval;
int iCommandBufferExecuteInterval = 0;
// Shader compilation settings.
bool bWaitForShadersBeforeStarting;
ShaderCompilationMode iShaderCompilationMode;
bool bWaitForShadersBeforeStarting = false;
ShaderCompilationMode iShaderCompilationMode{};
// Number of shader compiler threads.
// 0 disables background compilation.
// -1 uses an automatic number based on the CPU threads.
int iShaderCompilerThreads;
int iShaderPrecompilerThreads;
int iShaderCompilerThreads = 0;
int iShaderPrecompilerThreads = 0;
// Static config per API
// TODO: Move this out of VideoConfig
struct
{
APIType api_type;
APIType api_type = APIType::Nothing;
std::string DisplayName;
std::vector<std::string> Adapters; // for D3D
std::vector<u32> AAModes;
@@ -194,45 +240,62 @@ struct VideoConfig final
// TODO: merge AdapterName and Adapters array
std::string AdapterName; // for OpenGL
u32 MaxTextureSize;
bool bUsesLowerLeftOrigin;
u32 MaxTextureSize = 16384;
bool bUsesLowerLeftOrigin = false;
bool bUsesExplictQuadBuffering = false;
bool bSupportsExclusiveFullscreen;
bool bSupportsDualSourceBlend;
bool bSupportsPrimitiveRestart;
bool bSupportsOversizedViewports;
bool bSupportsGeometryShaders;
bool bSupportsComputeShaders;
bool bSupports3DVision;
bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon
bool bSupportsBindingLayout; // Needed by ShaderGen, so must stay in VideoCommon
bool bSupportsBBox;
bool bSupportsGSInstancing; // Needed by GeometryShaderGen, so must stay in VideoCommon
bool bSupportsPostProcessing;
bool bSupportsPaletteConversion;
bool bSupportsClipControl; // Needed by VertexShaderGen, so must stay in VideoCommon
bool bSupportsSSAA;
bool bSupportsFragmentStoresAndAtomics; // a.k.a. OpenGL SSBOs a.k.a. Direct3D UAVs
bool bSupportsDepthClamp; // Needed by VertexShaderGen, so must stay in VideoCommon
bool bSupportsReversedDepthRange;
bool bSupportsLogicOp;
bool bSupportsMultithreading;
bool bSupportsGPUTextureDecoding;
bool bSupportsST3CTextures;
bool bSupportsCopyToVram;
bool bSupportsBitfield; // Needed by UberShaders, so must stay in VideoCommon
bool bSupportsDynamicSamplerIndexing; // Needed by UberShaders, so must stay in VideoCommon
bool bSupportsBPTCTextures;
bool bSupportsFramebufferFetch; // Used as an alternative to dual-source blend on GLES
bool bSupportsBackgroundCompiling;
bool bSupportsLargePoints;
bool bSupportsPartialDepthCopies;
bool bSupportsDepthReadback;
bool bSupportsShaderBinaries;
bool bSupportsPipelineCacheData;
bool bSupportsExclusiveFullscreen = false;
bool bSupportsDualSourceBlend = false;
bool bSupportsPrimitiveRestart = false;
bool bSupportsGeometryShaders = false;
bool bSupportsComputeShaders = false;
bool bSupports3DVision = false;
bool bSupportsEarlyZ = false; // needed by PixelShaderGen, so must stay in VideoCommon
bool bSupportsBindingLayout = false; // Needed by ShaderGen, so must stay in VideoCommon
bool bSupportsBBox = false;
bool bSupportsGSInstancing = false; // Needed by GeometryShaderGen, so must stay in VideoCommon
bool bSupportsPostProcessing = false;
bool bSupportsPaletteConversion = false;
bool bSupportsClipControl = false; // Needed by VertexShaderGen, so must stay in VideoCommon
bool bSupportsSSAA = false;
bool bSupportsFragmentStoresAndAtomics = false; // a.k.a. OpenGL SSBOs a.k.a. Direct3D UAVs
bool bSupportsDepthClamp = false; // Needed by VertexShaderGen, so must stay in VideoCommon
bool bSupportsReversedDepthRange = false;
bool bSupportsLogicOp = false;
bool bSupportsMultithreading = false;
bool bSupportsGPUTextureDecoding = false;
bool bSupportsST3CTextures = false;
bool bSupportsCopyToVram = false;
bool bSupportsBitfield = false; // Needed by UberShaders, so must stay in VideoCommon
// Needed by UberShaders, so must stay in VideoCommon
bool bSupportsDynamicSamplerIndexing = false;
bool bSupportsBPTCTextures = false;
bool bSupportsFramebufferFetch = false; // Used as an alternative to dual-source blend on GLES
bool bSupportsBackgroundCompiling = false;
bool bSupportsLargePoints = false;
bool bSupportsPartialDepthCopies = false;
bool bSupportsDepthReadback = false;
bool bSupportsShaderBinaries = false;
bool bSupportsPipelineCacheData = false;
bool bSupportsCoarseDerivatives = false;
bool bSupportsTextureQueryLevels = false;
bool bSupportsLodBiasInSampler = false;
bool bSupportsSettingObjectNames = false;
bool bSupportsPartialMultisampleResolve = false;
bool bSupportsDynamicVertexLoader = false;
bool bSupportsVSLinePointExpand = false;
bool bSupportsGLLayerInFS = true;
} backend_info;
// Utility
bool UseVSForLinePointExpand() const
{
if (!backend_info.bSupportsVSLinePointExpand)
return false;
if (!backend_info.bSupportsGeometryShaders)
return true;
return bPreferVSForLinePointExpansion;
}
bool MultisamplingEnabled() const { return iMultisamples > 1; }
bool ExclusiveFullscreenEnabled() const
{
@@ -243,6 +306,26 @@ struct VideoConfig final
return backend_info.bSupportsGPUTextureDecoding && bEnableGPUTextureDecoding;
}
bool UseVertexRounding() const { return bVertexRounding && iEFBScale != 1; }
bool ManualTextureSamplingWithCustomTextureSizes() const
{
// If manual texture sampling is disabled, we don't need to do anything.
if (bFastTextureSampling)
return false;
// Hi-res textures break the wrapping logic used by manual texture sampling, as a texture's
// size won't match the size the game sets.
if (bHiresTextures)
return true;
// Hi-res EFB copies (but not native-resolution EFB copies at higher internal resolutions)
// also result in different texture sizes that need special handling.
if (iEFBScale != 1 && bCopyEFBScaled)
return true;
// Stereoscopic 3D changes the number of layers some textures have (EFB copies have 2 layers,
// while game textures still have 1), meaning bounds checks need to be added.
if (stereo_mode != StereoMode::Off)
return true;
// Otherwise, manual texture sampling can use the sizes games specify directly.
return false;
}
bool UsingUberShaders() const;
u32 GetShaderCompilerThreads() const;
u32 GetShaderPrecompilerThreads() const;
+1 -1
View File
@@ -1,5 +1,5 @@
/* Default visibility */
#define DEFAULT_VISIBILITY __attribute__((visibility("default")))
#define DEFAULT_VISIBILITY __attribute__((visibility("hidden")))
/* Start with debug message logging enabled */
#undef ENABLE_DEBUG_LOGGING
+1 -1
View File
@@ -281,7 +281,7 @@
/* Define to 1 or 0, depending whether the compiler supports simple visibility
declarations. */
#define HAVE_VISIBILITY 1
#define HAVE_VISIBILITY 0
/* Define to 1 if you have the `wcwidth' function. */
#define HAVE_WCWIDTH 1
+1 -1
View File
@@ -32,7 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Core/ActionReplay.h"
#include "Core/ARDecrypt.h"
#include "InputCommon/ControllerInterface/Device.h"
#include "InputCommon/ControllerInterface/CoreDevice.h"
#include "DolphinNoGUI/Platform.h"
+45 -23
View File
@@ -44,12 +44,14 @@
#include "Common/Thread.h"
#include "Common/Version.h"
#include "Core/Analytics.h"
#include "Core/DolphinAnalytics.h"
#include "Core/Boot/Boot.h"
#include "Core/BootManager.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/WiimoteSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/System.h"
#include "Core/Host.h"
#include "Core/HW/CPU.h"
#include "Core/HW/Wiimote.h"
@@ -78,6 +80,9 @@
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
DolHost* DolHost::m_instance = nullptr;
static Common::Event updateMainFrameEvent;
static Common::Flag s_running{true};
@@ -111,33 +116,33 @@ void DolHost::Init(std::string supportDirectoryPath, std::string cpath)
UICommon::Init();
// Database Settings
SConfig::GetInstance().m_use_builtin_title_database = true;
Config::SetBase(Config::MAIN_USE_BUILT_IN_TITLE_DATABASE, true);
//Setup the CPU Settings
SConfig::GetInstance().bMMU = true;
SConfig::GetInstance().bEnableCheats = true;
Config::SetBase(Config::MAIN_MMU, true);
Config::SetBase(Config::MAIN_ENABLE_CHEATS, true);
SConfig::GetInstance().bBootToPause = false;
//Debug Settings
SConfig::GetInstance().bEnableDebugging = false;
Config::SetBase(Config::MAIN_ENABLE_DEBUGGING, false);
#ifdef DEBUG
Config::SetBase(Config::MAIN_OSD_MESSAGES, true);
#else
Config::SetBase(Config::MAIN_OSD_MESSAGES, false);
#endif
SConfig::GetInstance().m_ShowFrameCount = false;
Config::SetBase(Config::MAIN_SHOW_FRAME_COUNT, false);
//Video
Config::SetBase(Config::MAIN_GFX_BACKEND, "OGL");
Config::SetBase(Config::MAIN_GFX_BACKEND, "MTL");
VideoBackendBase::ActivateBackend(Config::Get(Config::MAIN_GFX_BACKEND));
//Set the Sound
SConfig::GetInstance().bDSPHLE = true;
SConfig::GetInstance().bDSPThread = true;
SConfig::GetInstance().m_Volume = 0;
Config::SetBase(Config::MAIN_DSP_HLE, true);
Config::SetBase(Config::MAIN_DSP_THREAD, true);
Config::SetBase(Config::MAIN_AUDIO_VOLUME, 0);
//Split CPU thread from GPU
SConfig::GetInstance().bCPUThread = true;
Config::SetBase(Config::MAIN_CPU_THREAD, true);
//Analitics
Config::SetBase(Config::MAIN_ANALYTICS_PERMISSION_ASKED, true);
@@ -148,10 +153,10 @@ void DolHost::Init(std::string supportDirectoryPath, std::string cpath)
SConfig::GetInstance().SaveSettings();
//Choose Wiimote Type
WiimoteCommon::SetSource(0, WiimoteSource::Emulated);
WiimoteCommon::SetSource(1, WiimoteSource::Emulated);
WiimoteCommon::SetSource(2, WiimoteSource::Emulated);
WiimoteCommon::SetSource(3, WiimoteSource::Emulated);
Config::SetCurrent(Config::GetInfoForWiimoteSource(0), WiimoteSource::Emulated);
Config::SetCurrent(Config::GetInfoForWiimoteSource(1), WiimoteSource::Emulated);
Config::SetCurrent(Config::GetInfoForWiimoteSource(2), WiimoteSource::Emulated);
Config::SetCurrent(Config::GetInfoForWiimoteSource(3), WiimoteSource::Emulated);
//Get game info from file path
GetGameInfo();
@@ -189,7 +194,7 @@ void DolHost::Init(std::string supportDirectoryPath, std::string cpath)
// SConfig::GetInstance().m_enable_signature_checks = false;
// Disable wiimote continuous scanning
SConfig::GetInstance().m_WiimoteContinuousScanning = false;
Config::SetBase(Config::MAIN_WIIMOTE_CONTINUOUS_SCANNING, false);
//Set the Wiimote type
// WiimoteReal::ChangeWiimoteSource(0, _wiiMoteType);
@@ -202,7 +207,7 @@ void DolHost::Init(std::string supportDirectoryPath, std::string cpath)
# pragma mark - Execution
bool DolHost::LoadFileAtPath()
{
Core::SetOnStateChangedCallback([](Core::State state) {
Core::AddOnStateChangedCallback([](Core::State state) {
if (state == Core::State::Uninitialized)
s_running.Clear();
});
@@ -245,7 +250,7 @@ void DolHost::Pause(bool flag)
void DolHost::RequestStop()
{
Core::SetState(Core::State::Running);
ProcessorInterface::PowerButton_Tap();
Core::System::GetInstance().GetProcessorInterface().PowerButton_Tap();
Core::Stop();
while (CPU::GetState() != CPU::State::PowerDown)
@@ -257,7 +262,7 @@ void DolHost::RequestStop()
void DolHost::Reset()
{
ProcessorInterface::ResetButton_Tap();
Core::System::GetInstance().GetProcessorInterface().ResetButton_Tap();
}
void DolHost::UpdateFrame()
@@ -291,8 +296,8 @@ void DolHost::SetBackBufferSize(int width, int height) {
# pragma mark - Audio
void DolHost::SetVolume(float value)
{
SConfig::GetInstance().m_Volume = value * 100;
AudioCommon::UpdateSoundStream();
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, value * 100);
AudioCommon::UpdateSoundStream(Core::System::GetInstance());
}
# pragma mark - Save states
@@ -456,7 +461,9 @@ void DolHost::SetCheat(std::string code, std::string type, bool enabled)
if(!exists)
arcodes.push_back(arcode);
ActionReplay::RunAllActive();
// TODO: move to a better place
Core::CPUThreadGuard guard;
ActionReplay::RunAllActive(guard);
}
# pragma mark - Controls
@@ -612,15 +619,30 @@ void Host_RequestRenderWindowSize(int width, int height){}
void Host_SetStartupDebuggingParameters()
{
SConfig& StartUp = SConfig::GetInstance();
StartUp.bEnableDebugging = false;
StartUp.bBootToPause = false;
}
std::vector<std::string> Host_GetPreferredLocales()
{
return {};
}
bool Host_UINeedsControllerState(){ return false; }
bool Host_UIBlocksControllerState() { return false; }
bool Host_RendererHasFocus() { return true; }
bool Host_RendererHasFullFocus() { return true; }
bool Host_RendererIsFullscreen() { return false; }
void Host_ShowVideoConfig(void*, const std::string&) {}
void Host_YieldToUI() {}
void Host_TitleChanged() {}
void Host_UpdateProgressDialog(const char* caption, int position, int total) {}
void Host_UpdateDiscordClientID(const std::string& client_id) {}
bool Host_UpdateDiscordPresenceRaw(const std::string& details, const std::string& state,
const std::string& large_image_key,
const std::string& large_image_text,
const std::string& small_image_key,
const std::string& small_image_text,
const int64_t start_timestamp,
const int64_t end_timestamp, const int party_size,
const int party_max) { return false; }
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -182,7 +182,7 @@ extern std::unique_ptr<SoundStream> g_sound_stream;
# pragma mark - Video
- (OEGameCoreRendering)gameCoreRendering
{
return OEGameCoreRenderingOpenGL3Video;
return OEGameCoreRenderingMetal2Video;
}
- (BOOL)hasAlternateRenderingThread
@@ -226,7 +226,7 @@ extern std::unique_ptr<SoundStream> g_sound_stream;
- (GLenum)pixelType
{
return GL_UNSIGNED_BYTE;
return GL_UNSIGNED_INT_8_8_8_8_REV;
}
- (GLenum)internalPixelFormat
+3 -3
View File
@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
@@ -19,7 +19,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>5.0.13467</string>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string>OEGameCoreController</string>
<key>OEGameCoreClass</key>
@@ -49,7 +49,7 @@
<string>openemu.system.wii</string>
</array>
<key>SUEnableAutomaticChecks</key>
<string>1</string>
<true/>
<key>SUFeedURL</key>
<string>https://raw.github.com/OpenEmu/OpenEmu-Update/master/dolphin_appcast.xml</string>
</dict>
+1 -1
Submodule dolphin updated: 79a234eff7...a93b5a4a35