Play-/Source/ui_ios/EmulatorViewController.mm

488 lines
17 KiB
Text
Raw Normal View History

2015-07-22 02:48:26 -04:00
#include "PathUtils.h"
#import "EmulatorViewController.h"
#import "SaveStateViewController.h"
#import "SettingsViewController.h"
#import "RenderView.h"
2015-07-22 02:48:26 -04:00
#include "../PS2VM.h"
#include "../PS2VM_Preferences.h"
#include "../AppConfig.h"
#include "PreferenceDefs.h"
2015-07-22 02:48:26 -04:00
#include "GSH_OpenGLiOS.h"
2021-08-04 10:23:51 -04:00
#ifdef HAS_GSH_VULKAN
#include "GSH_VulkaniOS.h"
2021-08-04 10:23:51 -04:00
#endif
#include "../ui_shared/BootablesProcesses.h"
#include "PH_Generic.h"
2016-04-04 11:51:15 -04:00
#include "../../tools/PsfPlayer/Source/SH_OpenAL.h"
#include "../ui_shared/StatsManager.h"
2015-07-22 02:48:26 -04:00
CPS2VM* g_virtualMachine = nullptr;
2019-08-16 17:34:57 -04:00
CGSHandler::NewFrameEvent::Connection g_newFrameConnection;
#ifdef PROFILE
CPS2VM::ProfileFrameDoneSignal::Connection g_profileFrameDoneConnection;
#endif
2015-07-22 02:48:26 -04:00
2021-07-05 22:26:53 -10:00
@interface EmulatorViewController () <SaveStateDelegate>
@property(nonatomic, strong) SaveStateViewController* saveStateViewController;
2015-07-22 02:48:26 -04:00
@end
@implementation EmulatorViewController
2020-12-02 18:37:31 -05:00
+ (void)registerPreferences
{
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREFERENCE_UI_SHOWFPS, false);
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREFERENCE_UI_SHOWVIRTUALPAD, true);
2016-04-04 11:51:15 -04:00
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREFERENCE_AUDIO_ENABLEOUTPUT, true);
CAppConfig::GetInstance().RegisterPreferenceInteger(PREFERENCE_VIDEO_GS_HANDLER, PREFERENCE_VALUE_VIDEO_GS_HANDLER_OPENGL);
2021-07-07 07:30:11 -10:00
CAppConfig::GetInstance().RegisterPreferenceInteger(PREFERENCE_UI_VIRTUALPADOPACITY, 100);
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREFERENCE_UI_HIDEVIRTUALPAD_CONTROLLER_CONNECTED, true);
2021-07-07 08:38:06 -10:00
CAppConfig::GetInstance().RegisterPreferenceBoolean(PREFERENCE_UI_VIRTUALPAD_HAPTICFEEDBACK, true);
}
2020-12-02 18:37:31 -05:00
- (void)viewDidLoad
2015-07-22 02:48:26 -04:00
{
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification* note) {
[self appResignedActive];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification* note) {
[self appBecameActive];
}];
2020-12-02 18:37:31 -05:00
self.iCadeReader = [[iCadeReaderView alloc] init];
[self.view addSubview:self.iCadeReader];
self.iCadeReader.delegate = self;
self.iCadeReader.active = YES;
2021-07-05 22:26:53 -10:00
self.saveStateViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"SaveStateViewController"];
self.saveStateViewController.delegate = self;
[self addChildViewController:self.saveStateViewController];
[self.saveStateViewController didMoveToParentViewController:self];
[self.view addSubview:self.saveStateViewController.view];
self.saveStateViewController.view.hidden = YES;
self.saveStateViewController.view.translatesAutoresizingMaskIntoConstraints = false;
[[self.saveStateViewController.view.topAnchor constraintEqualToAnchor:self.view.topAnchor] setActive:YES];
[[self.saveStateViewController.view.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor] setActive:YES];
[[self.saveStateViewController.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor] setActive:YES];
[[self.saveStateViewController.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor] setActive:YES];
}
2020-12-02 18:37:31 -05:00
- (void)viewDidAppear:(BOOL)animated
{
assert(g_virtualMachine == nullptr);
2015-07-22 02:48:26 -04:00
g_virtualMachine = new CPS2VM();
g_virtualMachine->Initialize();
auto gsHandlerId = CAppConfig::GetInstance().GetPreferenceInteger(PREFERENCE_VIDEO_GS_HANDLER);
switch(gsHandlerId)
{
default:
[[fallthrough]];
case PREFERENCE_VALUE_VIDEO_GS_HANDLER_OPENGL:
g_virtualMachine->CreateGSHandler(CGSH_OpenGLiOS::GetFactoryFunction((CAEAGLLayer*)self.view.layer));
break;
2021-08-04 10:23:51 -04:00
#ifdef HAS_GSH_VULKAN
case PREFERENCE_VALUE_VIDEO_GS_HANDLER_VULKAN:
g_virtualMachine->CreateGSHandler(CGSH_VulkaniOS::GetFactoryFunction((CAMetalLayer*)self.view.layer));
break;
2021-08-04 10:23:51 -04:00
#endif
}
2015-07-22 02:48:26 -04:00
self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification* note) {
if([[GCController controllers] count] == 1)
{
[self toggleHardwareController:YES];
}
}];
self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification* note) {
if(![[GCController controllers] count])
{
[self toggleHardwareController:NO];
}
}];
if([[GCController controllers] count])
{
[self toggleHardwareController:YES];
}
g_virtualMachine->CreatePadHandler(CPH_Generic::GetFactoryFunction());
2020-12-02 18:37:31 -05:00
2021-06-21 15:01:23 -04:00
[self setupSoundHandler];
2021-06-19 16:06:17 -04:00
[self updateOnScreenWidgets];
2020-12-02 18:37:31 -05:00
2015-07-22 02:48:26 -04:00
g_virtualMachine->Pause();
g_virtualMachine->Reset();
2019-10-17 21:27:28 -04:00
auto bootablePath = fs::path([self.bootablePath fileSystemRepresentation]);
2017-11-01 09:46:23 -04:00
if(IsBootableExecutablePath(bootablePath))
{
2017-11-01 09:46:23 -04:00
g_virtualMachine->m_ee->m_os->BootFromFile(bootablePath);
}
else
{
2018-08-29 10:43:10 -04:00
CAppConfig::GetInstance().SetPreferencePath(PREF_PS2_CDROM0_PATH, bootablePath);
g_virtualMachine->Reset();
2015-12-06 14:53:35 -05:00
g_virtualMachine->m_ee->m_os->BootFromCDROM();
}
2015-07-22 02:48:26 -04:00
g_virtualMachine->Resume();
}
2020-12-02 18:37:31 -05:00
- (void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self.connectObserver];
[[NSNotificationCenter defaultCenter] removeObserver:self.disconnectObserver];
[self toggleHardwareController:NO];
2021-06-19 16:06:17 -04:00
[self resetStatsTimer];
g_virtualMachine->Pause();
g_virtualMachine->Destroy();
delete g_virtualMachine;
g_virtualMachine = nullptr;
2019-08-16 17:34:57 -04:00
g_newFrameConnection.reset();
#ifdef PROFILE
g_profileFrameDoneConnection.reset();
#endif
}
- (void)appResignedActive
{
if(g_virtualMachine)
{
g_virtualMachine->Pause();
}
}
- (void)appBecameActive
{
if(g_virtualMachine)
{
g_virtualMachine->Resume();
}
}
2020-12-02 18:37:31 -05:00
- (void)toggleHardwareController:(BOOL)useHardware
2016-01-30 21:06:39 -05:00
{
if(useHardware)
{
self.gController = [GCController controllers][0];
if(self.gController.extendedGamepad)
2016-01-30 21:06:39 -05:00
{
self.gController.extendedGamepad.valueChangedHandler =
^(GCExtendedGamepad* gamepad, GCControllerElement* element) {
auto padHandler = static_cast<CPH_Generic*>(g_virtualMachine->GetPadHandler());
if(!padHandler) return;
if(element == gamepad.buttonA)
padHandler->SetButtonState(PS2::CControllerInfo::CROSS, gamepad.buttonA.pressed);
else if(element == gamepad.buttonB)
padHandler->SetButtonState(PS2::CControllerInfo::CIRCLE, gamepad.buttonB.pressed);
else if(element == gamepad.buttonX)
padHandler->SetButtonState(PS2::CControllerInfo::SQUARE, gamepad.buttonX.pressed);
else if(element == gamepad.buttonY)
padHandler->SetButtonState(PS2::CControllerInfo::TRIANGLE, gamepad.buttonY.pressed);
else if(element == gamepad.leftShoulder)
padHandler->SetButtonState(PS2::CControllerInfo::L1, gamepad.leftShoulder.pressed);
else if(element == gamepad.rightShoulder)
padHandler->SetButtonState(PS2::CControllerInfo::R1, gamepad.rightShoulder.pressed);
else if(element == gamepad.leftTrigger)
padHandler->SetButtonState(PS2::CControllerInfo::L2, gamepad.leftTrigger.pressed);
else if(element == gamepad.rightTrigger)
padHandler->SetButtonState(PS2::CControllerInfo::R2, gamepad.rightTrigger.pressed);
else if(element == gamepad.dpad)
{
padHandler->SetButtonState(PS2::CControllerInfo::DPAD_UP, gamepad.dpad.up.pressed);
padHandler->SetButtonState(PS2::CControllerInfo::DPAD_DOWN, gamepad.dpad.down.pressed);
padHandler->SetButtonState(PS2::CControllerInfo::DPAD_LEFT, gamepad.dpad.left.pressed);
padHandler->SetButtonState(PS2::CControllerInfo::DPAD_RIGHT, gamepad.dpad.right.pressed);
}
else if(element == gamepad.leftThumbstick)
{
padHandler->SetAxisState(PS2::CControllerInfo::ANALOG_LEFT_X, gamepad.leftThumbstick.xAxis.value);
padHandler->SetAxisState(PS2::CControllerInfo::ANALOG_LEFT_Y, -gamepad.leftThumbstick.yAxis.value);
}
else if(element == gamepad.rightThumbstick)
{
padHandler->SetAxisState(PS2::CControllerInfo::ANALOG_RIGHT_X, gamepad.rightThumbstick.xAxis.value);
padHandler->SetAxisState(PS2::CControllerInfo::ANALOG_RIGHT_Y, -gamepad.rightThumbstick.yAxis.value);
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 120100
if(@available(iOS 12.1, *))
{
if(element == gamepad.leftThumbstickButton)
padHandler->SetButtonState(PS2::CControllerInfo::L3, gamepad.leftThumbstickButton.pressed);
else if(element == gamepad.rightThumbstickButton)
padHandler->SetButtonState(PS2::CControllerInfo::R3, gamepad.rightThumbstickButton.pressed);
}
#endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
if(@available(iOS 13.0, *))
{
if(element == gamepad.buttonOptions)
padHandler->SetButtonState(PS2::CControllerInfo::SELECT, gamepad.buttonOptions.pressed);
else if(element == gamepad.buttonMenu)
padHandler->SetButtonState(PS2::CControllerInfo::START, gamepad.buttonMenu.pressed);
}
#endif
};
2016-01-30 21:06:39 -05:00
}
}
else
{
if(self.gController)
{
if(self.gController.extendedGamepad)
{
self.gController.extendedGamepad.valueChangedHandler = nil;
}
}
2016-01-30 21:06:39 -05:00
self.gController = nil;
}
2021-07-07 07:30:11 -10:00
[self updateOnScreenWidgets];
}
2021-06-19 16:06:17 -04:00
- (void)resetStatsTimer
{
if(self.fpsCounterTimer)
{
[self.fpsCounterTimer invalidate];
self.fpsCounterTimer = nil;
}
}
- (void)updateOnScreenWidgets
{
auto screenBounds = [[UIScreen mainScreen] bounds];
if(@available(iOS 11, *))
{
UIEdgeInsets insets = self.view.safeAreaInsets;
screenBounds = UIEdgeInsetsInsetRect(screenBounds, insets);
}
//Remove previous widgets
if(self.virtualPadView)
{
[self.virtualPadView removeFromSuperview];
self.virtualPadView = nil;
}
if(self.fpsCounterLabel)
{
[self.fpsCounterLabel removeFromSuperview];
self.fpsCounterLabel = nil;
}
#ifdef PROFILE
if(self.profilerStatsLabel)
{
[self.profilerStatsLabel removeFromSuperview];
self.profilerStatsLabel = nil;
}
#endif
[self resetStatsTimer];
if(CAppConfig::GetInstance().GetPreferenceBoolean(PREFERENCE_UI_SHOWVIRTUALPAD) &&
2021-07-07 07:30:11 -10:00
!(self.gController && CAppConfig::GetInstance().GetPreferenceBoolean(PREFERENCE_UI_HIDEVIRTUALPAD_CONTROLLER_CONNECTED)))
2021-06-19 16:06:17 -04:00
{
auto padHandler = static_cast<CPH_Generic*>(g_virtualMachine->GetPadHandler());
self.virtualPadView = [[VirtualPadView alloc] initWithFrame:screenBounds padHandler:padHandler];
[self.view addSubview:self.virtualPadView];
[self.view sendSubviewToBack:self.virtualPadView];
2021-07-07 07:30:11 -10:00
int prefTransparency = CAppConfig::GetInstance().GetPreferenceInteger(PREFERENCE_UI_VIRTUALPADOPACITY);
self.virtualPadView.alpha = CGFloat(prefTransparency / 100.0);
2021-06-19 16:06:17 -04:00
}
if(CAppConfig::GetInstance().GetPreferenceBoolean(PREFERENCE_UI_SHOWFPS))
{
[self setupFpsCounterWithBounds:screenBounds];
}
}
2021-06-21 15:01:23 -04:00
- (void)setupSoundHandler
{
if(CAppConfig::GetInstance().GetPreferenceBoolean(PREFERENCE_AUDIO_ENABLEOUTPUT))
{
g_virtualMachine->CreateSoundHandler(&CSH_OpenAL::HandlerFactory);
}
else
{
g_virtualMachine->DestroySoundHandler();
}
}
2020-12-02 18:37:31 -05:00
- (void)setupFpsCounterWithBounds:(CGRect)screenBounds
2015-11-24 10:31:44 -05:00
{
2020-12-02 18:37:31 -05:00
self.fpsCounterLabel = [[UILabel alloc] initWithFrame:screenBounds];
2015-11-24 10:31:44 -05:00
self.fpsCounterLabel.textColor = [UIColor whiteColor];
2020-12-02 18:37:31 -05:00
[self.view addSubview:self.fpsCounterLabel];
#ifdef PROFILE
2020-12-02 18:37:31 -05:00
self.profilerStatsLabel = [[UILabel alloc] initWithFrame:screenBounds];
self.profilerStatsLabel.textColor = [UIColor whiteColor];
2020-12-02 18:37:31 -05:00
self.profilerStatsLabel.font = [UIFont fontWithName:@"Courier" size:10.f];
self.profilerStatsLabel.numberOfLines = 0;
2020-12-02 18:37:31 -05:00
[self.view addSubview:self.profilerStatsLabel];
#endif
2020-12-02 18:37:31 -05:00
2022-01-20 14:54:07 -05:00
g_newFrameConnection = g_virtualMachine->GetGSHandler()->OnNewFrame.Connect(std::bind(&CStatsManager::OnNewFrame, &CStatsManager::GetInstance(), g_virtualMachine, std::placeholders::_1));
#ifdef PROFILE
2022-01-20 14:54:07 -05:00
g_profileFrameDoneConnection = g_virtualMachine->ProfileFrameDone.Connect(std::bind(&CStatsManager::OnProfileFrameDone, &CStatsManager::GetInstance(), std::placeholders::_1));
#endif
2020-12-02 18:37:31 -05:00
self.fpsCounterTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateFpsCounter) userInfo:nil repeats:YES];
2015-11-24 10:31:44 -05:00
}
2020-12-02 18:37:31 -05:00
- (void)updateFpsCounter
2015-11-24 10:31:44 -05:00
{
uint32 drawCallCount = CStatsManager::GetInstance().GetDrawCalls();
uint32 frames = CStatsManager::GetInstance().GetFrames();
uint32 dcpf = (frames != 0) ? (drawCallCount / frames) : 0;
2020-12-02 18:37:31 -05:00
self.fpsCounterLabel.text = [NSString stringWithFormat:@"%d f/s, %d dc/f", frames, dcpf];
2015-11-24 10:31:44 -05:00
[self.fpsCounterLabel sizeToFit];
#ifdef PROFILE
2020-12-02 18:37:31 -05:00
self.profilerStatsLabel.text = [NSString stringWithUTF8String:CStatsManager::GetInstance().GetProfilingInfo().c_str()];
#endif
CStatsManager::GetInstance().ClearStats();
2015-11-24 10:31:44 -05:00
}
2020-12-02 18:37:31 -05:00
- (void)onLoadStateButtonClick
2018-12-23 22:07:34 -05:00
{
2021-07-05 22:26:53 -10:00
self.saveStateViewController.action = SaveStateActionLoad;
self.saveStateViewController.view.hidden = false;
2018-12-23 22:07:34 -05:00
}
2020-12-02 18:37:31 -05:00
- (void)onSaveStateButtonClick
{
2021-07-05 22:26:53 -10:00
self.saveStateViewController.action = SaveStateActionSave;
self.saveStateViewController.view.hidden = false;
}
2020-12-02 18:37:31 -05:00
- (void)onExitButtonClick
2016-01-08 18:39:27 -05:00
{
2020-12-02 18:37:31 -05:00
[self dismissViewControllerAnimated:YES completion:nil];
2016-01-08 18:39:27 -05:00
}
2020-12-02 18:37:31 -05:00
- (IBAction)onPauseButtonClick:(id)sender
2018-12-23 22:07:34 -05:00
{
UIAlertControllerStyle style = UIAlertControllerStyleAlert;
if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
{
style = UIAlertControllerStyleActionSheet;
}
UIAlertController* alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:style];
2020-12-02 18:37:31 -05:00
2018-12-23 22:07:34 -05:00
//Load State
{
UIAlertAction* action = [UIAlertAction
2020-12-02 18:37:31 -05:00
actionWithTitle:@"Load State"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction*) {
[self onLoadStateButtonClick];
}];
[alert addAction:action];
2018-12-23 22:07:34 -05:00
}
//Save State
{
UIAlertAction* action = [UIAlertAction
2020-12-02 18:37:31 -05:00
actionWithTitle:@"Save State"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction*) {
[self onSaveStateButtonClick];
}];
[alert addAction:action];
2018-12-23 22:07:34 -05:00
}
//Settings
{
UIAlertAction* action = [UIAlertAction
actionWithTitle:@"Settings"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction*) {
[self performSegueWithIdentifier:@"showSettings" sender:self];
}];
[alert addAction:action];
}
2018-12-23 22:07:34 -05:00
//Resume
{
UIAlertAction* action = [UIAlertAction
2020-12-02 18:37:31 -05:00
actionWithTitle:@"Resume"
style:UIAlertActionStyleCancel
handler:nil];
[alert addAction:action];
2018-12-23 22:07:34 -05:00
}
2020-12-02 18:37:31 -05:00
2018-12-23 22:07:34 -05:00
//Exit
{
UIAlertAction* action = [UIAlertAction
2020-12-02 18:37:31 -05:00
actionWithTitle:@"Exit"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction*) {
[self onExitButtonClick];
}];
[alert addAction:action];
2018-12-23 22:07:34 -05:00
}
2020-12-02 18:37:31 -05:00
[self presentViewController:alert animated:YES completion:nil];
2018-12-23 22:07:34 -05:00
}
2020-12-02 18:37:31 -05:00
- (BOOL)prefersStatusBarHidden
2015-07-22 02:48:26 -04:00
{
return YES;
}
2020-12-02 18:37:31 -05:00
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
if([segue.identifier isEqualToString:@"showSettings"])
{
UINavigationController* navViewController = segue.destinationViewController;
SettingsViewController* settingsViewController = (SettingsViewController*)navViewController.visibleViewController;
settingsViewController.completionHandler = ^(bool) {
2021-06-21 15:01:23 -04:00
[self setupSoundHandler];
2021-06-19 16:06:17 -04:00
[self updateOnScreenWidgets];
auto gsHandler = g_virtualMachine->GetGSHandler();
if(gsHandler)
{
gsHandler->NotifyPreferencesChanged();
}
};
}
}
2021-07-05 22:26:53 -10:00
#pragma mark -
#pragma mark SaveStateDelegate
- (void)saveStateUsingPosition:(uint32_t)position
{
auto statePath = g_virtualMachine->GenerateStatePath(position);
g_virtualMachine->SaveState(statePath);
NSLog(@"Saved state to '%s'.", statePath.string().c_str());
}
2021-07-05 22:26:53 -10:00
- (void)loadStateUsingPosition:(uint32_t)position
{
auto statePath = g_virtualMachine->GenerateStatePath(position);
g_virtualMachine->LoadState(statePath);
NSLog(@"Loaded state from '%s'.", statePath.string().c_str());
}
2015-07-22 02:48:26 -04:00
@end