Files
ppsspp/Common/GPU/GraphicsContext.h
T
Henrik RydgårdandClaude Opus 5 812d8f4c09 Android GL: Delete the JavaGL path, leaving only native EGL
The EGL path from the previous commit is now the only one, so GLSurfaceView
and everything that existed to serve it are gone:

- NativeRenderer.java and NativeGLSurfaceView.java, deleted.
- The javaGL branches in PpssppActivity. GL and Vulkan now share one
  lifecycle: a plain SurfaceView, startRenderLoopThread() when the surface
  arrives, joinRenderLoopThread() when it goes away.
- The "androidJavaGL" queryConfig, and the AndroidNativeEGL setting and its
  developer-tools checkbox.
- displayInit/displayRender, and with them the "Second time, joining the
  emuthread and starting it up again" dance - restarting the emu thread from
  inside a JNI callback because a lost context was only observable as a
  second onSurfaceCreated.
- GraphicsContext::NotifyContextLost, which existed solely because that join
  drained the render queue on a thread with no current context. The render
  thread now joins the emu thread with the context still current, so the
  drain is real work and nothing has to be skipped.
- g_emuThread, now that nothing starts an emu thread outside the render loop.

Three things displayInit/displayRender did that nothing else did, moved
rather than dropped:

- EnterVR and the per-frame StartVRRender/UpdateVRInput/FinishVRRender hooks
  now live in RenderLoopThread's GL branch. Java's GL thread could simply
  return early and wait for the next vsync when the VR session was inactive;
  this loop drives itself, so that case sleeps 16ms instead of spinning.
  Not tested - no headset here.
- RECREATE_VIEWS after the emu thread starts, as before. Vulkan never did
  this, so it's a candidate for removal when the two paths converge.
- The thin3d error callback, which surfaces GL errors as OSD messages. That
  one moved into AndroidEGLGraphicsContext::InitSurface, next to the rest of
  the context's own setup, matching WindowsGLContext.

Tested on a nubia Z2464N (Unisoc UMS9632, Mali-G57, Android 15): cold start,
UI, booting a homebrew, backgrounding and resuming both in the menu and
in-game, and a density change, which destroys and recreates the activity the
way a rotation does. Every cycle tears the EGL context down and builds a new
one, and the renderer comes back with FBOs and textures intact. The config
ladder's first choice, RGBA8888 D24S8, is what the Java chooser landed on
here too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01152igCdjTNhT29qvphPyPC
2026-10-08 15:22:25 +02:00

74 lines
2.6 KiB
C++

#pragma once
#include <string>
#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; }
};