We will see the program flow of PPSSPP a PSP Emulator. PPSSPP using C++ programming language which starting or entry point from int main(argc, argv). On OSX port the PPSSPP using SDL+OPENGL and starting from SDL/SDLMain.cpp:
MainThread:
- glslang::InitializeProcess() [ext/glsllang/*/MachineIndependent/ShaderLang.cpp]
- argc, argv parsing
- NativeGetAppInfo: set app name, version variable [UI/NativeApp.cpp]
- SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO)
- SDL_GetCurrentDisplayMode
- SDL_GL_SetAttribute
- calculate screen size
- NativeInit [UI/NativeApp.cpp]
- ResetUIState(): globalUIState = UISTATE_MENU [Core/System.cpp]
- VFSRegister: set assets dir [ext/native/file/zip_read.cpp]
- set g_Config data directories and search paths.
- LogManager::Init [Common/LogManager.cpp]
- Config::Load [Core/Config.cpp]
- argc, argv parsing for game ROM.
- PostLoadConfig:
- i18nrepo.LoadIni: load language [ext/native/i18n/i18n.cpp]
- i18nrepo.GetCategory [ext/native/i18n/i18n.cpp]
- (global)screenManager = new ScreenManager() [ext/native/ui/screen.cpp]
- new LogoScreen [UI/MiscScreen.h]
- ScreenManager::switchScreen to LogoScreen Screen.
- StartWebServer for remote debug [Core/WebServer.cpp]
- CheckFailedGPUBackends:
- g_Config.iGPUBackend = GPUBackend::OPENGL
- SetGPUBackend(g_Config.iGPUBackend) [Core/System.cpp]:
- gpuBackend = GPUBackend::OPENGL
- new SDLGLGraphicsContext
- SDLGLGraphicsContext::Init [SDL/SDLGLGraphicsContext.cpp]:
- SetGLCoreContext [ext/native/gfx_es2/gpu_features.cpp]
- SDL_CreateWindow
- SDL_GL_CreateContext
- SDL_ShowWindow
- CheckGLExtensions [ext/native/gfx_es2/gpu_features.cpp]
- Draw::T3DCreateGLContext [ext/native/thin3d/thin3d_gl.cpp]:
- new Draw::OpenGLContext
- GLRenderManager::CreatePushBuffer [ext/native/thin3d/GLRenderManager.h]
- new Draw::OpenGLContext
- get GLRenderManager from Draw::OpenGLContext::GetNativeObject(NativeObject::RENDER_MANAGER)
- SetGPUBackend(GPUBackend::OPENGL) again
- Draw::DrawContext::CreatePresets [ext/native/thin3d/thin3d.cpp]: create fs & vs shader:
- Draw::DrawContext::CreateShader:
- Draw::DrawContext::GetSupportedShaderLanguages
- Draw::DrawContext::CreateShaderModule:
- new Draw::OpenGLShaderModule
- Draw::OpenGLShaderModule::Compile
- Draw::DrawContext::CreateShader:
- GLRenderManager::SetSwapFunction = [&]() { SDL_GL_SwapWindow }
- useEmuThread for OPENGL
- SDL_SetWindowTitle
SDLGLGraphicsContext::InitFromRenderThread- SDL_GL_SetSwapInterval(1)
- InitSDLAudioDevice():
- SDL_OpenAudioDevice
- SDL_PauseAudioDevice
- new SDLJoystick [SDL/SDLJoystick.cpp]:
- SDL_RWFromConstMem
- SDL_GameControllerAddMappingsFromRW
- setUpControllers:
- SDL_NumJoysticks
- setUpController:
- SDL_IsGameController
- SDL_JoystickOpen
- SDL_JoystickGetGUID
- SDL_JoystickGetGUIDString
- SDL_JoystickName
- SDL_GameControllerAddMapping
- SDL_JoystickClose
- SDL_GameControllerOpen
- SDL_GameControllerGetAttached
- SDL_GameControllerGetJoystick
- SDL_JoystickInstanceID
- SDL_GameControllerName
- SDL_GameControllerMapping
- EmuThreadStart:
- emuThreadState = EmuThreadState::START_REQUESTED;
- run [thread] EmuThreadFunc:
- setCurrentThreadName(“Emu”) [ext/native/thread/threadutil.cpp]
- emuThreadState = EmuThreadState::RUNNING
- NativeInitGraphics [UI/NativeApp.cpp]:
- Core_SetGraphicsContext [Core/Core.cpp]:
- PSP_CoreParameter use SDLGLGraphicsContext
- DrawBuffer::SetAtlas
- UIThemeInit
- new UIContext
- DrawBuffer::CreateInputLayout
- Draw::DrawContext::CreateInputLayout(Draw::InputLayoutDesc)
- Draw::DrawContext::CreateBlendState:
- new Draw::OpenGLBlendState
- Draw::DrawContext::CreateDepthStencilState
- new Draw::OpenGLDepthStencilState
- Draw::DrawContext::CreateRasterState:
- new Draw::OpenGLRasterState
- Draw::DrawContext::CreateGraphicsPipeline(Draw::PipelineDesc) with Draw::DrawContext::GetVshaderPreset and Draw::DrawContext::GetFshaderPreset
- DrawBuffer::Init:
- Draw::Pipeline::RequiresBuffer
- Draw::DrawContext::CreateBuffer
- UIContext::Init
- Draw::DrawContext::CreateSamplerState
TextDrawer::Create
- ScreenManager::setPostRenderCallback(RenderOverlays)
- ScreenManager::deviceRestored
- all Screen::deviceRestored
- new GameInfoCache [UI/GameInfoCache.cpp]:
- GameInfoCache::Init:
- new PrioritizedWorkQueue [ext/native/thread/prioritizedworkqueue.h]
- ProcessWorkQueueOnThreadWhile:
- run [thread] threadfunc:
- setCurrentThreadName(“PrioQueue”)
- continue in parallel… [2]
- run [thread] threadfunc:
- GameInfoCache::Init:
- GPUInterface::DeviceRestore
- Core_SetGraphicsContext [Core/Core.cpp]:
- continue in parallel … [1]
- SDLGLGraphicsContext::ThreadStart: [SDL/SDLGLGraphicsContext.h]:
- GLRenderManager::ThreadStart [ext/native/thin3d/GLRenderManager.h]
- GLQueueRunner::CreateDeviceObjects [ext/native/thin3d/GLQueueRunner.cpp]:
- glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT)
- glGenVertexArrays
- set GLBufferStrategy
- GLQueueRunner::CreateDeviceObjects [ext/native/thin3d/GLQueueRunner.cpp]:
- GLRenderManager::ThreadStart [ext/native/thin3d/GLRenderManager.h]
- reset framecount
- Entering MainLoop, main thread as Render thread:
- case SDL_PollEvent when:
- SDL_QUIT
- set QuitRequested
- SDL_WINDOWEVENT
- Core_NotifyWindowHidden [Core/Core.cpp]
- UpdateScreenScale [Core/Core.cpp]
- NativeMessageReceived(“gpu_resized”, “”)
- SDL_ShowCursor
- SDL_KEYDOWN | SDL_KEYUP | SDL_TEXTINPUT
- NativeKey [UI/NativeApp.cpp]
- ScreenManager::key
- (top)Screen::key
- ScreenManager::key
- NativeKey [UI/NativeApp.cpp]
- SDL_MOUSEBUTTONDOWN | SDL_MOUSEWHEEL | SDL_MOUSEMOTION | SDL_MOUSEBUTTONUP
- NativeTouch [UI/NativeApp.cpp]
- ScreenManager::touch
- (top)Screen::touch
- ScreenManager::touch
- NativeKey
- NativeTouch [UI/NativeApp.cpp]
- SDLJoystick::ProcessInput [SDL/SDLJoystick.cpp]
- SDL_CONTROLLERBUTTONDOWN | SDL_CONTROLLERBUTTONUP
- NativeKey
- SDL_CONTROLLERAXISMOTION
- NativeAxis [UI/NativeApp.cpp]
- ScreenManager::axis
- (top)Screen::axis
- ScreenManager::axis
- NativeAxis [UI/NativeApp.cpp]
- SDL_CONTROLLERDEVICEREMOVED
- SDL_CONTROLLERDEVICEADDED
- SDL_CONTROLLERBUTTONDOWN | SDL_CONTROLLERBUTTONUP
- SDL_AUDIODEVICEADDED | SDL_AUDIODEVICEREMOVED
- SDL_GetAudioDeviceName
- StopSDLAudioDevice
- InitSDLAudioDevice
- SDL_QUIT
- SDL_GetKeyboardState
- break if QuitRequested
- if EmuThreadState::DISABLED:
- UpdateRunLoop [Core/Core.cpp]
- [EmuThread] loop while not EmuThreadState::QUIT_REQUESTED [1]:
- UpdateRunLoop [Core/Core.cpp]
- if not EmuThreadState::DISABLED or not paused:
- SDGLGraphicsContext::ThreadFrame [SDL/SDLGLGraphicsContext.h]:
- GLRenderManager::ThreadFrame [ext/native/thin3d/GLRenderManager.h]:
- increment threadFrame index
- get FrameData by threadFrame index
- wait FrameData to readyForRun
- GLDeleter::Perform prev [ext/native/thin3d/GLRenderManager.cpp]
- GLDeleter::Take prev [ext/native/thin3d/GLRenderManager.h]
- GLRenderManager::Run(threadFrame index) [ext/native/thin3d/GLRenderManager.cpp]:
- BeginSubmitFrame
- GLQueueRunner::RunInitSteps (FrameData.stes) [ext/native/thin3d/GLQueueRunner.cpp]
- GLQueueRunner::RunSteps (FrameData.initSteps) [ext/native/thin3d/GLQueueRunner.cpp]
- EndSubmitFrame or EndSyncFrame
- do next FrameData within MAX_INFLIGHT_FRAMES if GLRRunType::END
- GLRenderManager::ThreadFrame [ext/native/thin3d/GLRenderManager.h]:
- SDGLGraphicsContext::ThreadFrame [SDL/SDLGLGraphicsContext.h]:
SDGLGraphicsContext::SwapBuffers- ToggleFullScreenIfFlagSet:
- SDL_GetWindowFlags
- SDL_SetWindowFullscreen
- if not UISTATE_INGAME or not PSP_IsInited or paused:
- sleep_ms: simple throttling
- increase framecount
- case SDL_PollEvent when:
- EmuThreadStop
- emuThreadState = EmuThreadState::QUIT_REQUESTED
- eat all SDLGLGraphicsContext::ThreadFrame
- EmuThreadJoin
- [EmuThread] emuThreadState = EmuThreadState::STOPPED
- [EmuThread] NativeShutdownGraphics [UI/NativeApp.cpp]
- [EmuThread] SDLGLGraphicsContext::StopThread
- GLRenderManager::WaitUntilQueueIdle
- wait all FrameData to ready
- GLRenderManager::StopThread
- GLRenderManager::Wipe
- GLRenderManager::WaitUntilQueueIdle
- ~SDLJoystick
- SDLGLGraphicsContext::ThreadEnd
- GLRenderManager::ThreadEnd
- GLQueueRunner::DestroyDeviceObjects
- GLDeleter::Perform
- GLRenderManager::ThreadEnd
- NativeShutdown
- SDLGLGraphicsContext::ShutdownFromRenderThread
- ~Draw::DrawContext
- SDL_GL_DeleteContext
- ~SDLGLGraphicsContext
- SDL_PauseAudioDevice
- SDL_CloseAudioDevice
- SDL_Quit
- glslang::FinalizeProcess
PrioritizedWorkerQueue [2]:
- PrioritizedWorkQueue::Pop()
- PrioritizedWorkQueueItem::run
- loop unless PrioritizedWorkQueueItem::Done
UpdateRunLoop
Running in: MainThread otherwise EmuThread depends on emuThreadState, on UI/NativeApp.cpp:
- NativeUpdate
- toProcess = pendingMessages
- for each toProcess:
- HandleGlobalMessage
- inputDeviceConnected
- inputbox_completed
- bgImage_updated
- savestate_displayslot
- gpu_resized | gpu_clearCache
- core_powerSaving
- permission_granted:storage
- ScreenManager::sendMessage
- recreateviews
- RecreateAllViews
- lost_focus
- (top)Screen::sendMessage
- recreateviews
- HandleGlobalMessage
- http::Downloader::Update
- ScreenManager::update
- ScreenManager::switchToNext() if needed
- (top)Screen::update
- NativeRender [UI/NativeApp.cpp]
- GameManager::update [Core/Util/GameManager.cpp]
- UpdateBackgroundAudio if not UISTATE_INGAME
- DrawBuffer::PushDrawMatrix(Lin::Matrix4x4::setOrtho)
- ScreenManager::render [ext/native/ui/screen.cpp]:
- (top)Screen::preRender
- (top)Screen::render
- (overlay)Screen::render
- PostRenderCallback
- (top)Screen::postRender
- ScreenManager::processFinishDialog
SDLGLGRaphicsContex::Resize- ScreenManager::resized
- each Screen::resized
- DrawBuffer::PopDrawMatrix
SCREENMANAGER
ScreenManager hold current (top)Screen to be shown(render) and which screen receive input. Here are the Screens which may appear in order:
- LogoScreen
- after few seconds it will do
ScreenManager::switchScreento MainScreen Screen
- after few seconds it will do
- MainScreen
- when user click one of the game it will trigger MainScreen::OnGameSelectedInstant to LaunchFile to tell
ScreenManager::switchScreento EmuScreen Screen
- when user click one of the game it will trigger MainScreen::OnGameSelectedInstant to LaunchFile to tell
- EmuScreen
- on each Screen::update call, several stuff being process based on state from loading the game, booting up, and on each Screen::render to running/emulate the game.