// // ViewController.m // // Created by rock88 // Modified by xSacha // Reworked by hrydgard #import "ViewController.h" #import "iOSCoreAudio.h" #import #import #include #include "Common/Net/Resolve.h" #include "Common/UI/Screen.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/thin3d_create.h" #include "Common/GPU/OpenGL/GLRenderManager.h" #include "Common/GPU/OpenGL/OpenGLGraphicsContext.h" #include "Common/System/Display.h" #include "Common/System/System.h" #include "Common/System/OSD.h" #include "Common/System/NativeApp.h" #include "Common/System/Request.h" #include "Common/File/VFS/VFS.h" #include "Common/Thread/ThreadUtil.h" #include "Common/Log.h" #include "Common/TimeUtil.h" #include "Common/Input/InputState.h" #include "Common/Input/KeyCodes.h" #include "Common/GPU/GraphicsContext.h" #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/EmuThread.h" #include "Core/KeyMap.h" #include "Core/System.h" #if !__has_feature(objc_arc) #error Must be built with ARC, please revise the flags for ViewController.mm to include -fobjc-arc. #endif static std::thread g_emuThread; PPSSPPBaseViewController *sharedViewController; @interface PPSSPPViewControllerGL () { GraphicsContext *graphicsContext; } @property (nonatomic, strong) EAGLContext *glContext; @property (nonatomic, strong) GLKView *glView; @property (nonatomic, strong) CADisplayLink *displayLink; @end @implementation PPSSPPViewControllerGL {} -(id) init { self = [super init]; if (self) { _preferredFramesPerSecond = 60; // default } return self; } - (bool)runGLRenderLoop { if (!graphicsContext) { ERROR_LOG(Log::G3D, "runGLRenderLoop: Tried to enter without a created graphics context."); return false; } if (g_emuThread.joinable()) { ERROR_LOG(Log::G3D, "runGLRenderLoop: Already running"); return false; } g_emuThread = EmuThread_Start(graphicsContext, new NativeApplication(), [](GraphicsContext *graphicsContext){ NativeFrame(graphicsContext); return true; }); return true; } - (void)requestExitGLRenderLoop { _assert_(g_emuThread.joinable()); EmuThread_Join(graphicsContext, g_emuThread); _assert_(!g_emuThread.joinable()); } - (void)viewDidLoad { [super viewDidLoad]; // 1) Create GL context self.glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; if (!self.glContext) { self.glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; } NSAssert(self.glContext != nil, @"Failed to create EAGLContext"); // 2) Create GLKView self.glView = [[GLKView alloc] initWithFrame:self.view.bounds context:self.glContext]; self.glView.delegate = self; self.glView.enableSetNeedsDisplay = NO; // We'll call display manually self.glView.drawableDepthFormat = GLKViewDrawableDepthFormat24; self.glView.drawableStencilFormat = GLKViewDrawableStencilFormat8; self.glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.glView.multipleTouchEnabled = YES; [self.view addSubview:self.glView]; // self.view.insetsLayoutMarginsFromSafeArea = NO; // self.view.clipsToBounds = YES; // Put context current for initial GL setup [EAGLContext setCurrentContext:self.glContext]; // Here we can do one time GL init if we want. // 3) Setup display link self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkFired:)]; if (@available(iOS 10.0, *)) { self.displayLink.preferredFramesPerSecond = (NSInteger)self.preferredFramesPerSecond; } else { // older iOS: approximate with frameInterval self.displayLink.frameInterval = MAX(1, (NSInteger)round(60.0 / self.preferredFramesPerSecond)); } [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; self.view.multipleTouchEnabled = YES; graphicsContext = new OpenGLGraphicsContext(); std::string errorMessage; if (!graphicsContext->InitAPI(nullptr, nullptr, &errorMessage)) { ERROR_LOG(Log::G3D, "InitAPI failed: %s", errorMessage.c_str()); } if (!graphicsContext->InitSurface(WINDOWSYSTEM_NONE, nullptr, nullptr, &errorMessage)) { ERROR_LOG(Log::G3D, "InitSurface failed: %s", errorMessage.c_str()); } /*self.iCadeView = [[iCadeReaderView alloc] init]; [self.view addSubview:self.iCadeView]; self.iCadeView.delegate = self; self.iCadeView.active = YES;*/ if ([[GCController controllers] count] > 0) { [self setupController:[[GCController controllers] firstObject]]; } [self hideKeyboard]; INFO_LOG(Log::G3D, "Done with viewDidLoad."); } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; self.glView.frame = self.view.bounds; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; INFO_LOG(Log::G3D, "viewWillAppear"); } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; INFO_LOG(Log::G3D, "viewWillDisappear"); } - (void)dealloc { [self.displayLink invalidate]; self.displayLink = nil; if ([EAGLContext currentContext] == self.glContext) { [EAGLContext setCurrentContext:nil]; } self.glContext = nil; } - (void)setPreferredFramesPerSecond:(NSInteger)preferredFramesPerSecond { _preferredFramesPerSecond = preferredFramesPerSecond; if (self.displayLink) { if (@available(iOS 10.0, *)) { self.displayLink.preferredFramesPerSecond = (NSInteger)preferredFramesPerSecond; } else { self.displayLink.frameInterval = MAX(1, (NSInteger)round(60.0 / preferredFramesPerSecond)); } } } - (void)displayLinkFired:(CADisplayLink *)dl { // Ensure context is current before drawing [EAGLContext setCurrentContext:self.glContext]; // Trigger GLKView draw [self.glView display]; } - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { if (!g_emuThread.joinable()) { INFO_LOG(Log::G3D, "Ignoring drawInRect"); return; } if (sharedViewController) { if (!graphicsContext->ThreadFrame()) { INFO_LOG(Log::G3D, "ThreadFrame returned false"); } } } - (void)didBecomeActive { [super didBecomeActive]; INFO_LOG(Log::System, "didBecomeActive begin"); [self updateResolutionWithView:self.view]; [self runGLRenderLoop]; INFO_LOG(Log::System, "didBecomeActive end"); self.displayLink.paused = NO; } - (void)willResignActive { INFO_LOG(Log::System, "willResignActive GL"); [self requestExitGLRenderLoop]; self.displayLink.paused = YES; [super willResignActive]; } - (void)shutdown { [super shutdown]; INFO_LOG(Log::System, "shutdown GL"); g_Config.Save("shutdown GL"); _dbg_assert_(graphicsContext); graphicsContext->ShutdownSurface(); graphicsContext->ShutdownAPI(); delete graphicsContext; graphicsContext = nullptr; INFO_LOG(Log::System, "Done shutting down GL"); } - (void)bindDefaultFBO { [(GLKView*)self.glView bindDrawable]; } // Can't consolidate this yet. - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [self.view endEditing:YES]; // clears any input focus [coordinator animateAlongsideTransition:^(id context) { NSLog(@"Rotating to size: %@", NSStringFromCGSize(size)); } completion:^(id context) { NSLog(@"Rotation finished"); // Reinitialize graphics context to match new size [self requestExitGLRenderLoop]; [self updateResolutionWithView:self.view]; [self runGLRenderLoop]; }]; } @end void bindDefaultFBO() { [sharedViewController bindDefaultFBO]; } void EnableFZ(){}; void DisableFZ(){};