#pragma once #include #include "Common/Log.h" #include "Common/GPU/thin3d.h" #include "Common/TimeUtil.h" struct WindowDesc { WindowSystem winsys{}; void *data1 = nullptr; void *data2 = nullptr; bool Valid() const { return winsys != WindowSystem::WINDOWSYSTEM_UNINITIALIZED && data2; // Not all platforms use data1, so don't check it. } }; // Init is done differently on each platform, and done close to the creation, so it's // expected to be implemented by subclasses. class GraphicsContext { public: virtual ~GraphicsContext() = default; // Some implementations will separate init of the API and of the rendering surface. // wnd here is only to be used for messageboxes and similar, not for the surface. virtual bool InitAPI(void *wnd, std::string *deviceName, std::string *errorMessage) { return true; } virtual void ShutdownAPI() {} // These should be called on the render thread if NeedsRenderThread. virtual bool InitSurface(WindowSystem winsys, void *data1, void *data2, std::string *errorMessage) { return true; } virtual void ShutdownSurface() {} // Used during window resize on desktop ONLY. Must be called from the window thread, // not the rendering thread or CPU thread. virtual void Pause() {} virtual void Resume() {} virtual void Resize() = 0; virtual void NotifyWindowRestored() {} // Needs casting to the appropriate type, unfortunately. Should find a better solution.. virtual void *GetAPIContext() { return nullptr; } // OpenGL returns true here. Later we will need to do the same with Vulkan. virtual bool NeedsSeparateEmuThread() const { return false; } // Called from the render thread from threaded backends. virtual void ThreadStart() {} virtual bool ThreadFrame() { return true; } // Returns false when it's time to exit the loop. virtual void ThreadEnd() {} // When this is called, the emulation thread has stopped producing frames completely. // Called from the emu thread, so be ready for that. virtual void NotifyEmuThreadExit() {} // Useful for checks that need to be performed every frame. // Should strive to get rid of these. virtual void Poll() {} // TODO: Store in a protected variable? virtual Draw::DrawContext *GetDrawContext() = 0; }; // This is used by the headless build, for the case of software rendering where we really don't need any context, // unlike the standalone build where we do need a context anyway for UI and stuff. class NullGraphicsContext : public GraphicsContext { public: NullGraphicsContext() {} Draw::DrawContext *GetDrawContext() override { return nullptr; } void Resize() override {} bool NeedsSeparateEmuThread() const override { return false; } };