CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/headless/SDLHeadlessHost.cpp
Views: 1401
// Copyright (c) 2017- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#ifdef SDL1819#include <cstdio>2021#include "ppsspp_config.h"22#if PPSSPP_PLATFORM(MAC)23#include "SDL2/SDL.h"24#else25#include "SDL.h"26#endif2728#include "headless/SDLHeadlessHost.h"29#include "Common/GPU/OpenGL/GLCommon.h"30#include "Common/GPU/OpenGL/GLFeatures.h"31#include "Common/GPU/thin3d_create.h"32#include "Common/GPU/OpenGL/GLRenderManager.h"33#include "Common/File/VFS/VFS.h"34#include "Common/File/VFS/DirectoryReader.h"35#include "Common/GraphicsContext.h"36#include "Common/TimeUtil.h"37#include "Core/Config.h"38#include "Core/System.h"39#include "GPU/GPUState.h"4041const bool WINDOW_VISIBLE = false;42const int WINDOW_WIDTH = 480;43const int WINDOW_HEIGHT = 272;4445SDL_Window *CreateHiddenWindow() {46Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS;47if (!WINDOW_VISIBLE) {48flags |= SDL_WINDOW_HIDDEN;49}50return SDL_CreateWindow("PPSSPPHeadless", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, flags);51}5253class GLDummyGraphicsContext : public GraphicsContext {54public:55GLDummyGraphicsContext() {56}57~GLDummyGraphicsContext() { delete draw_; }5859bool InitFromRenderThread(std::string *errorMessage) override;6061void ShutdownFromRenderThread() override {62delete draw_;63draw_ = nullptr;6465SDL_GL_DeleteContext(glContext_);66glContext_ = nullptr;67SDL_DestroyWindow(screen_);68screen_ = nullptr;6970SDL_Quit();71}7273Draw::DrawContext *GetDrawContext() override {74return draw_;75}7677void ThreadStart() override {78renderManager_->ThreadStart(draw_);79}8081bool ThreadFrame() override {82return renderManager_->ThreadFrame();83}8485void ThreadEnd() override {86renderManager_->ThreadEnd();87}8889void StopThread() override {90if (renderManager_) {91renderManager_->StopThread();92}93}9495void Shutdown() override {}96void Resize() override {}9798private:99Draw::DrawContext *draw_ = nullptr;100GLRenderManager *renderManager_ = nullptr;101SDL_Window *screen_;102SDL_GLContext glContext_;103};104105bool GLDummyGraphicsContext::InitFromRenderThread(std::string *errorMessage) {106SDL_Init(SDL_INIT_VIDEO);107108// TODO109//SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);110//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);111//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);112113SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);114SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);115SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);116SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);117SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);118SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);119120screen_ = CreateHiddenWindow();121if (!screen_) {122const char *err = SDL_GetError();123printf("Failed to create offscreen window: %s\n", err ? err : "(unknown error)");124return false;125}126glContext_ = SDL_GL_CreateContext(screen_);127if (!glContext_) {128const char *err = SDL_GetError();129printf("Failed to create GL context: %s\n", err ? err : "(unknown error)");130return false;131}132133// Ensure that the swap interval is set after context creation (needed for kmsdrm)134SDL_GL_SetSwapInterval(0);135136#ifndef USING_GLES2137// Some core profile drivers elide certain extensions from GL_EXTENSIONS/etc.138// glewExperimental allows us to force GLEW to search for the pointers anyway.139if (gl_extensions.IsCoreContext)140glewExperimental = true;141if (GLEW_OK != glewInit()) {142printf("Failed to initialize glew!\n");143return false;144}145// Unfortunately, glew will generate an invalid enum error, ignore.146if (gl_extensions.IsCoreContext)147glGetError();148149if (GLEW_VERSION_2_0) {150printf("OpenGL 2.0 or higher.\n");151} else {152printf("Sorry, this program requires OpenGL 2.0.\n");153return false;154}155#endif156157CheckGLExtensions();158draw_ = Draw::T3DCreateGLContext(false);159renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);160renderManager_->SetInflightFrames(g_Config.iInflightFrames);161SetGPUBackend(GPUBackend::OPENGL);162bool success = draw_->CreatePresets();163_assert_(success);164renderManager_->SetSwapFunction([&]() {165SDL_GL_SwapWindow(screen_);166});167return success;168}169170bool SDLHeadlessHost::InitGraphics(std::string *error_message, GraphicsContext **ctx, GPUCore core) {171GraphicsContext *graphicsContext = new GLDummyGraphicsContext();172*ctx = graphicsContext;173gfx_ = graphicsContext;174175std::thread th([&]{176while (threadState_ == RenderThreadState::IDLE)177sleep_ms(1);178threadState_ = RenderThreadState::STARTING;179180std::string err;181if (!gfx_->InitFromRenderThread(&err)) {182threadState_ = RenderThreadState::START_FAILED;183return;184}185gfx_->ThreadStart();186threadState_ = RenderThreadState::STARTED;187188while (threadState_ != RenderThreadState::STOP_REQUESTED) {189if (!gfx_->ThreadFrame()) {190break;191}192}193194threadState_ = RenderThreadState::STOPPING;195gfx_->ThreadEnd();196gfx_->ShutdownFromRenderThread();197threadState_ = RenderThreadState::STOPPED;198});199th.detach();200201threadState_ = RenderThreadState::START_REQUESTED;202while (threadState_ == RenderThreadState::START_REQUESTED || threadState_ == RenderThreadState::STARTING)203sleep_ms(1);204205return threadState_ == RenderThreadState::STARTED;206}207208void SDLHeadlessHost::ShutdownGraphics() {209gfx_->StopThread();210while (threadState_ != RenderThreadState::STOPPED && threadState_ != RenderThreadState::START_FAILED)211sleep_ms(1);212213gfx_->Shutdown();214delete gfx_;215gfx_ = nullptr;216}217218void SDLHeadlessHost::SwapBuffers() {219}220221#endif222223224