SDL: Add pvr gles/gles2 context support

From 134dd4681983bbff18d5aa52ce21974d54f90b39 Mon Sep 17 00:00:00 2001
From: Ivan Epifanov <[EMAIL REDACTED]>
Date: Mon, 16 Aug 2021 19:08:12 +0300
Subject: [PATCH] Add pvr gles/gles2 context support

---
 CMakeLists.txt                    | 24 ++++++++
 include/SDL_config.h.cmake        |  1 +
 include/SDL_egl.h                 |  4 ++
 src/video/SDL_egl.c               | 12 ++--
 src/video/vita/SDL_vitagl_pvr.c   | 95 +++++++++++++++++++++++++++++++
 src/video/vita/SDL_vitagl_pvr_c.h | 35 ++++++++++++
 src/video/vita/SDL_vitavideo.c    | 26 ++++++++-
 src/video/vita/SDL_vitavideo.h    |  3 +
 8 files changed, 193 insertions(+), 7 deletions(-)
 create mode 100644 src/video/vita/SDL_vitagl_pvr.c
 create mode 100644 src/video/vita/SDL_vitagl_pvr_c.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2844e33c70..7dcff8e15e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -425,6 +425,7 @@ set_option(SDL_TEST            "Build the test directory" OFF)
 
 if(VITA)
     set_option(VIDEO_VITA_PIB  "Build with PSVita piglet gles2 support" OFF)
+    set_option(VIDEO_VITA_PVR  "Build with PSVita PVR gles/gles2 support" OFF)
 endif()
 
 # General source files
@@ -2205,6 +2206,29 @@ elseif(VITA)
       endif()
     endif()
 
+    if(VIDEO_VITA_PVR)
+      check_include_file(gpu_es4/psp2_pvr_hint.h HAVE_PVR_H)
+
+      if(HAVE_PVR_H)
+        add_definitions("-D__psp2__")
+        set(SDL_VIDEO_OPENGL_EGL 1)
+        set(HAVE_VIDEO_OPENGLES TRUE)
+        set(SDL_VIDEO_OPENGL_ES 1)
+        set(SDL_VIDEO_RENDER_OGL_ES 1)
+        set(SDL_VIDEO_OPENGL_ES2 1)
+        set(SDL_VIDEO_RENDER_OGL_ES2 1)
+
+        list(APPEND EXTRA_LIBS
+          libgpu_es4_ext_stub_weak
+          libIMGEGL_stub_weak
+        )
+        set(HAVE_VIDEO_VITA_PVR ON)
+        set(SDL_VIDEO_VITA_PVR 1)
+      else()
+        set(HAVE_VIDEO_VITA_PVR OFF)
+      endif()
+    endif()
+
     set(SDL_VIDEO_RENDER_VITA_GXM 1)
 
     list(APPEND EXTRA_LIBS
diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake
index 0352922428..7b20a1d686 100644
--- a/include/SDL_config.h.cmake
+++ b/include/SDL_config.h.cmake
@@ -481,6 +481,7 @@
 #cmakedefine SDL_IPHONE_LAUNCHSCREEN @SDL_IPHONE_LAUNCHSCREEN@
 
 #cmakedefine SDL_VIDEO_VITA_PIB @SDL_VIDEO_VITA_PIB@
+#cmakedefine SDL_VIDEO_VITA_PVR @SDL_VIDEO_VITA_PVR@
 
 #if !defined(__WIN32__) && !defined(__WINRT__)
 #  if !defined(_STDINT_H_) && !defined(_STDINT_H) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
diff --git a/include/SDL_egl.h b/include/SDL_egl.h
index 223357e5f4..62bc0b4283 100644
--- a/include/SDL_egl.h
+++ b/include/SDL_egl.h
@@ -26,6 +26,10 @@
  */
 #if !defined(_MSC_VER) && !defined(__ANDROID__)
 
+#if defined(__vita__) || defined(__psp2__)
+#include <psp2/types.h>
+#endif
+
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index de7999cf63..2bd2a08c0f 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -107,7 +107,7 @@
 #define EGL_PLATFORM_DEVICE_EXT 0x0
 #endif
 
-#ifdef SDL_VIDEO_STATIC_ANGLE
+#if defined(SDL_VIDEO_STATIC_ANGLE) || defined(SDL_VIDEO_DRIVER_VITA)
 #define LOAD_FUNC(NAME) \
 _this->egl_data->NAME = (void *)NAME;
 #else
@@ -123,7 +123,6 @@ if (!_this->egl_data->NAME) \
 #define LOAD_FUNC_EGLEXT(NAME) \
     _this->egl_data->NAME = _this->egl_data->eglGetProcAddress(#NAME);
 
-
 static const char * SDL_EGL_GetErrorName(EGLint eglErrorCode)
 {
 #define SDL_EGL_ERROR_TRANSLATE(e) case e: return #e;
@@ -245,7 +244,7 @@ SDL_EGL_GetProcAddress(_THIS, const char *proc)
         retval = _this->egl_data->eglGetProcAddress(proc);
     }
 
-    #ifndef __EMSCRIPTEN__  /* LoadFunction isn't needed on Emscripten and will call dlsym(), causing other problems. */
+    #if !defined(__EMSCRIPTEN__) && !defined(SDL_VIDEO_DRIVER_VITA)  /* LoadFunction isn't needed on Emscripten and will call dlsym(), causing other problems. */
     /* Try SDL_LoadFunction() first for EGL <= 1.4, or as a fallback for >= 1.5. */
     if (!retval) {
         static char procname[64];
@@ -344,7 +343,7 @@ SDL_EGL_LoadLibraryOnly(_THIS, const char *egl_path)
     }
 #endif
 
-#ifndef SDL_VIDEO_STATIC_ANGLE
+#if !defined(SDL_VIDEO_STATIC_ANGLE) && !defined(SDL_VIDEO_DRIVER_VITA)
     /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */
     path = SDL_getenv("SDL_VIDEO_GL_DRIVER");
     if (path != NULL) {
@@ -430,6 +429,9 @@ SDL_EGL_LoadLibraryOnly(_THIS, const char *egl_path)
 #endif
 
     _this->egl_data->dll_handle = dll_handle;
+#if SDL_VIDEO_DRIVER_VITA
+    _this->egl_data->egl_dll_handle = egl_dll_handle;
+#endif
 
     /* Load new function pointers */
     LOAD_FUNC(eglGetDisplay);
@@ -498,6 +500,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
     _this->egl_data->egl_display = EGL_NO_DISPLAY;
 
 #if !defined(__WINRT__)
+#if !defined(SDL_VIDEO_DRIVER_VITA)
     if (platform) {
         /* EGL 1.5 allows querying for client version with EGL_NO_DISPLAY
          * --
@@ -522,6 +525,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
             }
         }
     }
+#endif
     /* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */
     if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
         _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
diff --git a/src/video/vita/SDL_vitagl_pvr.c b/src/video/vita/SDL_vitagl_pvr.c
new file mode 100644
index 0000000000..809adc2a25
--- /dev/null
+++ b/src/video/vita/SDL_vitagl_pvr.c
@@ -0,0 +1,95 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR
+#include <stdlib.h>
+#include <string.h>
+#include <psp2/kernel/modulemgr.h>
+#include <gpu_es4/psp2_pvr_hint.h>
+
+#include "SDL_error.h"
+#include "SDL_log.h"
+#include "SDL_vitavideo.h"
+#include "../SDL_egl_c.h"
+#include "SDL_vitagl_pvr_c.h"
+
+#define MAX_PATH 256 // vita limits are somehow wrong
+
+int
+VITA_GL_LoadLibrary(_THIS, const char *path)
+{
+  PVRSRV_PSP2_APPHINT hint;
+  char* override = SDL_getenv("VITA_MODULE_PATH");
+  char* default_path = "app0:module/";
+  char target_path[MAX_PATH];
+
+  if (override != NULL)
+  {
+    default_path = override;
+  }
+
+  sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL);
+  sceKernelLoadStartModule("vs0:sys/external/libc.suprx", 0, NULL, 0, NULL, NULL);
+
+  SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libgpu_es4_ext.suprx");
+  sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
+
+  SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libIMGEGL.suprx");
+  sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
+
+  PVRSRVInitializeAppHint(&hint);
+
+  SDL_snprintf(hint.szGLES1, MAX_PATH, "%s/%s", default_path, "libGLESv1_CM.suprx");
+  SDL_snprintf(hint.szGLES2, MAX_PATH, "%s/%s", default_path, "libGLESv2.suprx");
+  SDL_snprintf(hint.szWindowSystem, MAX_PATH, "%s/%s", default_path, "libpvrPSP2_WSEGL.suprx");
+
+  PVRSRVCreateVirtualAppHint(&hint);
+
+  return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) 0, 0);
+}
+
+SDL_GLContext
+VITA_GL_CreateContext(_THIS, SDL_Window * window)
+{
+    return SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
+}
+
+int
+VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
+{
+    if (window && context) {
+        return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context);
+    } else {
+        return SDL_EGL_MakeCurrent(_this, NULL, NULL);
+    }
+}
+
+int
+VITA_GL_SwapWindow(_THIS, SDL_Window * window)
+{
+    return SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
+}
+
+
+#endif /* SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/vita/SDL_vitagl_pvr_c.h b/src/video/vita/SDL_vitagl_pvr_c.h
new file mode 100644
index 0000000000..c957cdcde2
--- /dev/null
+++ b/src/video/vita/SDL_vitagl_pvr_c.h
@@ -0,0 +1,35 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_vitagl_c_h_
+#define SDL_vitagl_c_h_
+
+#include "SDL_vitavideo.h"
+
+extern int VITA_GL_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context);
+extern int VITA_GL_SwapWindow(_THIS, SDL_Window * window);
+extern SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window);
+extern int VITA_GL_LoadLibrary(_THIS, const char *path);
+
+
+#endif /* SDL_vitagl_c_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/vita/SDL_vitavideo.c b/src/video/vita/SDL_vitavideo.c
index 0adf3b8a82..1c09a31e35 100644
--- a/src/video/vita/SDL_vitavideo.c
+++ b/src/video/vita/SDL_vitavideo.c
@@ -38,9 +38,19 @@
 #include "SDL_vitakeyboard.h"
 #include "SDL_vitamouse_c.h"
 #include "SDL_vitaframebuffer.h"
-#if SDL_VIDEO_VITA_PIB
-#include "SDL_vitagl_c.h"
+
+#if defined(SDL_VIDEO_VITA_PIB)
+  #include "SDL_vitagl_c.h"
+#elif defined(SDL_VIDEO_VITA_PVR)
+  #include "SDL_vitagl_pvr_c.h"
+  #include "../SDL_egl_c.h"
+  #define VITA_GL_GetProcAddress SDL_EGL_GetProcAddress
+  #define VITA_GL_UnloadLibrary SDL_EGL_UnloadLibrary
+  #define VITA_GL_SetSwapInterval SDL_EGL_SetSwapInterval
+  #define VITA_GL_GetSwapInterval SDL_EGL_GetSwapInterval
+  #define VITA_GL_DeleteContext SDL_EGL_DeleteContext
 #endif
+
 #include <psp2/ime_dialog.h>
 
 SDL_Window *Vita_Window;
@@ -130,7 +140,7 @@ VITA_Create()
     device->DestroyWindowFramebuffer = VITA_DestroyWindowFramebuffer;
 */
 
-#if SDL_VIDEO_VITA_PIB
+#if defined(SDL_VIDEO_VITA_PIB) || defined(SDL_VIDEO_VITA_PVR)
     device->GL_LoadLibrary = VITA_GL_LoadLibrary;
     device->GL_GetProcAddress = VITA_GL_GetProcAddress;
     device->GL_UnloadLibrary = VITA_GL_UnloadLibrary;
@@ -232,6 +242,16 @@ VITA_CreateWindow(_THIS, SDL_Window * window)
 
     Vita_Window = window;
 
+#if defined(SDL_VIDEO_VITA_PVR)
+    if ((window->flags & SDL_WINDOW_OPENGL) != 0) {
+      wdata->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) 0);
+
+      if (wdata->egl_surface == EGL_NO_SURFACE) {
+          return SDL_SetError("Could not create GLES window surface");
+      }
+    }
+#endif
+
     // fix input, we need to find a better way
     SDL_SetKeyboardFocus(window);
 
diff --git a/src/video/vita/SDL_vitavideo.h b/src/video/vita/SDL_vitavideo.h
index 13ea895db4..2670f2beb3 100644
--- a/src/video/vita/SDL_vitavideo.h
+++ b/src/video/vita/SDL_vitavideo.h
@@ -24,6 +24,7 @@
 
 #include "../../SDL_internal.h"
 #include "../SDL_sysvideo.h"
+#include "../SDL_egl_c.h"
 
 #include <psp2/types.h>
 #include <psp2/display.h>
@@ -51,6 +52,8 @@ typedef struct SDL_WindowData
     SDL_bool uses_gles;
     SceUID buffer_uid;
     void* buffer;
+    EGLSurface egl_surface;
+    EGLContext egl_context;
 
 } SDL_WindowData;