From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c | 592 +++++++++++++++++++++++ 1 file changed, 592 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c (limited to 'contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c') diff --git a/contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c b/contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c new file mode 100644 index 0000000..6b5dbd7 --- /dev/null +++ b/contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c @@ -0,0 +1,592 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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" + +#ifdef SDL_VIDEO_DRIVER_VITA + +// SDL internals +#include "../SDL_sysvideo.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_keyboard_c.h" + +// VITA declarations +#include +#include "SDL_vitavideo.h" +#include "SDL_vitatouch.h" +#include "SDL_vitakeyboard.h" +#include "SDL_vitamouse_c.h" +#include "SDL_vitaframebuffer.h" +#include "SDL_vitamessagebox.h" + +#ifdef SDL_VIDEO_VITA_PIB +#include "SDL_vitagles_c.h" +#elif defined(SDL_VIDEO_VITA_PVR) +#include "SDL_vitagles_pvr_c.h" +#ifdef SDL_VIDEO_VITA_PVR_OGL +#include "SDL_vitagl_pvr_c.h" +#endif +#define VITA_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal +#define VITA_GLES_UnloadLibrary SDL_EGL_UnloadLibrary +#define VITA_GLES_SetSwapInterval SDL_EGL_SetSwapInterval +#define VITA_GLES_GetSwapInterval SDL_EGL_GetSwapInterval +#define VITA_GLES_DestroyContext SDL_EGL_DestroyContext +#endif + +SDL_Window *Vita_Window; + +static void VITA_Destroy(SDL_VideoDevice *device) +{ + SDL_free(device->internal); + SDL_free(device); +} + +static SDL_VideoDevice *VITA_Create(void) +{ + SDL_VideoDevice *device; + SDL_VideoData *phdata; +#ifdef SDL_VIDEO_VITA_PIB + SDL_GLDriverData *gldata; +#endif + // Initialize SDL_VideoDevice structure + device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (!device) { + return NULL; + } + + // Initialize internal VITA specific data + phdata = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData)); + if (!phdata) { + SDL_free(device); + return NULL; + } +#ifdef SDL_VIDEO_VITA_PIB + + gldata = (SDL_GLDriverData *)SDL_calloc(1, sizeof(SDL_GLDriverData)); + if (!gldata) { + SDL_free(device); + SDL_free(phdata); + return NULL; + } + device->gl_data = gldata; + phdata->egl_initialized = true; +#endif + phdata->ime_active = false; + + device->internal = phdata; + + // Setup amount of available displays and current display + device->num_displays = 0; + + // Set device free function + device->free = VITA_Destroy; + + // Setup all functions which we can handle + device->VideoInit = VITA_VideoInit; + device->VideoQuit = VITA_VideoQuit; + device->CreateSDLWindow = VITA_CreateWindow; + device->SetWindowTitle = VITA_SetWindowTitle; + device->SetWindowPosition = VITA_SetWindowPosition; + device->SetWindowSize = VITA_SetWindowSize; + device->ShowWindow = VITA_ShowWindow; + device->HideWindow = VITA_HideWindow; + device->RaiseWindow = VITA_RaiseWindow; + device->MaximizeWindow = VITA_MaximizeWindow; + device->MinimizeWindow = VITA_MinimizeWindow; + device->RestoreWindow = VITA_RestoreWindow; + device->SetWindowMouseGrab = VITA_SetWindowGrab; + device->SetWindowKeyboardGrab = VITA_SetWindowGrab; + device->DestroyWindow = VITA_DestroyWindow; + + /* + // Disabled, causes issues on high-framerate updates. SDL still emulates this. + device->CreateWindowFramebuffer = VITA_CreateWindowFramebuffer; + device->UpdateWindowFramebuffer = VITA_UpdateWindowFramebuffer; + device->DestroyWindowFramebuffer = VITA_DestroyWindowFramebuffer; + */ + +#if defined(SDL_VIDEO_VITA_PIB) || defined(SDL_VIDEO_VITA_PVR) +#ifdef SDL_VIDEO_VITA_PVR_OGL + if (SDL_GetHintBoolean(SDL_HINT_VITA_PVR_OPENGL, false)) { + device->GL_LoadLibrary = VITA_GL_LoadLibrary; + device->GL_CreateContext = VITA_GL_CreateContext; + device->GL_GetProcAddress = VITA_GL_GetProcAddress; + } else { +#endif + device->GL_LoadLibrary = VITA_GLES_LoadLibrary; + device->GL_CreateContext = VITA_GLES_CreateContext; + device->GL_GetProcAddress = VITA_GLES_GetProcAddress; +#ifdef SDL_VIDEO_VITA_PVR_OGL + } +#endif + + device->GL_UnloadLibrary = VITA_GLES_UnloadLibrary; + device->GL_MakeCurrent = VITA_GLES_MakeCurrent; + device->GL_SetSwapInterval = VITA_GLES_SetSwapInterval; + device->GL_GetSwapInterval = VITA_GLES_GetSwapInterval; + device->GL_SwapWindow = VITA_GLES_SwapWindow; + device->GL_DestroyContext = VITA_GLES_DestroyContext; +#endif + + device->HasScreenKeyboardSupport = VITA_HasScreenKeyboardSupport; + device->ShowScreenKeyboard = VITA_ShowScreenKeyboard; + device->HideScreenKeyboard = VITA_HideScreenKeyboard; + device->IsScreenKeyboardShown = VITA_IsScreenKeyboardShown; + + device->PumpEvents = VITA_PumpEvents; + + return device; +} + +VideoBootStrap VITA_bootstrap = { + "vita", + "VITA Video Driver", + VITA_Create, + VITA_ShowMessageBox, + false +}; + +/*****************************************************************************/ +// SDL Video and Display initialization/handling functions +/*****************************************************************************/ +bool VITA_VideoInit(SDL_VideoDevice *_this) +{ + SDL_DisplayMode mode; +#ifdef SDL_VIDEO_VITA_PVR + const char *res = SDL_GetHint(SDL_HINT_VITA_RESOLUTION); +#endif + SDL_zero(mode); + +#ifdef SDL_VIDEO_VITA_PVR + if (res) { + // 1088i for PSTV (Or Sharpscale) + if (SDL_strncmp(res, "1080", 4) == 0) { + mode.w = 1920; + mode.h = 1088; + } + // 725p for PSTV (Or Sharpscale) + else if (SDL_strncmp(res, "720", 3) == 0) { + mode.w = 1280; + mode.h = 725; + } + } + // 544p + else { +#endif + mode.w = 960; + mode.h = 544; +#ifdef SDL_VIDEO_VITA_PVR + } +#endif + + mode.refresh_rate = 60.0f; + + // 32 bpp for default + mode.format = SDL_PIXELFORMAT_ABGR8888; + + if (SDL_AddBasicVideoDisplay(&mode) == 0) { + return false; + } + + VITA_InitTouch(); + VITA_InitKeyboard(); + VITA_InitMouse(); + + return true; +} + +void VITA_VideoQuit(SDL_VideoDevice *_this) +{ + VITA_QuitTouch(); +} + +bool VITA_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) +{ + SDL_WindowData *wdata; +#ifdef SDL_VIDEO_VITA_PVR + Psp2NativeWindow win; + int temp_major = 2; + int temp_minor = 1; + int temp_profile = 0; +#endif + + // Allocate window internal data + wdata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData)); + if (!wdata) { + return false; + } + + // Setup driver data for this window + window->internal = wdata; + + // Vita can only have one window + if (Vita_Window) { + return SDL_SetError("Only one window supported"); + } + + Vita_Window = window; + +#ifdef SDL_VIDEO_VITA_PVR + win.type = PSP2_DRAWABLE_TYPE_WINDOW; + win.numFlipBuffers = 2; + win.flipChainThrdAffinity = 0x20000; + + // 1088i for PSTV (Or Sharpscale) + if (window->w == 1920) { + win.windowSize = PSP2_WINDOW_1920X1088; + } + // 725p for PSTV (Or Sharpscale) + else if (window->w == 1280) { + win.windowSize = PSP2_WINDOW_1280X725; + } + // 544p + else { + win.windowSize = PSP2_WINDOW_960X544; + } + if (window->flags & SDL_WINDOW_OPENGL) { + bool use_opengl = SDL_GetHintBoolean(SDL_HINT_VITA_PVR_OPENGL, false); + if (use_opengl) { + // Set version to 2.1 and PROFILE to ES + temp_major = _this->gl_config.major_version; + temp_minor = _this->gl_config.minor_version; + temp_profile = _this->gl_config.profile_mask; + + _this->gl_config.major_version = 2; + _this->gl_config.minor_version = 1; + _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; + } + wdata->egl_surface = SDL_EGL_CreateSurface(_this, window, &win); + if (wdata->egl_surface == EGL_NO_SURFACE) { + return SDL_SetError("Could not create GLES window surface"); + } + if (use_opengl) { + // Revert + _this->gl_config.major_version = temp_major; + _this->gl_config.minor_version = temp_minor; + _this->gl_config.profile_mask = temp_profile; + } + } +#endif + + // fix input, we need to find a better way + SDL_SetKeyboardFocus(window); + + // Window has been successfully created + return true; +} + +void VITA_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +bool VITA_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window) +{ + return SDL_Unsupported(); +} +void VITA_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void VITA_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void VITA_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void VITA_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void VITA_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void VITA_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +void VITA_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ +} +bool VITA_SetWindowGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed) +{ + return true; +} + +void VITA_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ + SDL_WindowData *data; + + data = window->internal; + if (data) { + // TODO: should we destroy egl context? No one sane should recreate ogl window as non-ogl + SDL_free(data); + } + + window->internal = NULL; + Vita_Window = NULL; +} + +bool VITA_HasScreenKeyboardSupport(SDL_VideoDevice *_this) +{ + return true; +} + +#ifndef SCE_IME_LANGUAGE_ENGLISH_US +#define SCE_IME_LANGUAGE_ENGLISH_US SCE_IME_LANGUAGE_ENGLISH +#endif + +static void utf16_to_utf8(const uint16_t *src, uint8_t *dst) +{ + int i; + for (i = 0; src[i]; i++) { + if (!(src[i] & 0xFF80)) { + *(dst++) = src[i] & 0xFF; + } else if (!(src[i] & 0xF800)) { + *(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0; + *(dst++) = (src[i] & 0x3F) | 0x80; + } else if ((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00) { + *(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0; + *(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80; + *(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF); + *(dst++) = (src[i + 1] & 0x3F) | 0x80; + i += 1; + } else { + *(dst++) = ((src[i] >> 12) & 0xF) | 0xE0; + *(dst++) = ((src[i] >> 6) & 0x3F) | 0x80; + *(dst++) = (src[i] & 0x3F) | 0x80; + } + } + + *dst = '\0'; +} + +#ifdef SDL_VIDEO_VITA_PVR +SceWChar16 libime_out[SCE_IME_MAX_PREEDIT_LENGTH + SCE_IME_MAX_TEXT_LENGTH + 1]; +char libime_initval[8] = { 1 }; +SceImeCaret caret_rev; + +void VITA_ImeEventHandler(void *arg, const SceImeEventData *e) +{ + SDL_VideoData *videodata = (SDL_VideoData *)arg; + uint8_t utf8_buffer[SCE_IME_MAX_TEXT_LENGTH]; + switch (e->id) { + case SCE_IME_EVENT_UPDATE_TEXT: + if (e->param.text.caretIndex == 0) { + SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_BACKSPACE); + sceImeSetText((SceWChar16 *)libime_initval, 4); + } else { + utf16_to_utf8((SceWChar16 *)&libime_out[1], utf8_buffer); + if (utf8_buffer[0] == ' ') { + SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_SPACE); + } else { + SDL_SendKeyboardText((const char *)utf8_buffer); + } + SDL_memset(&caret_rev, 0, sizeof(SceImeCaret)); + SDL_memset(libime_out, 0, ((SCE_IME_MAX_PREEDIT_LENGTH + SCE_IME_MAX_TEXT_LENGTH + 1) * sizeof(SceWChar16))); + caret_rev.index = 1; + sceImeSetCaret(&caret_rev); + sceImeSetText((SceWChar16 *)libime_initval, 4); + } + break; + case SCE_IME_EVENT_PRESS_ENTER: + SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_RETURN); + break; + case SCE_IME_EVENT_PRESS_CLOSE: + sceImeClose(); + videodata->ime_active = false; + break; + } +} +#endif + +void VITA_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props) +{ + SDL_VideoData *videodata = _this->internal; + SceInt32 res; + +#ifdef SDL_VIDEO_VITA_PVR + + SceUInt32 libime_work[SCE_IME_WORK_BUFFER_SIZE / sizeof(SceInt32)]; + SceImeParam param; + + sceImeParamInit(¶m); + + SDL_memset(libime_out, 0, ((SCE_IME_MAX_PREEDIT_LENGTH + SCE_IME_MAX_TEXT_LENGTH + 1) * sizeof(SceWChar16))); + + param.supportedLanguages = SCE_IME_LANGUAGE_ENGLISH_US; + param.languagesForced = SCE_FALSE; + switch (SDL_GetTextInputType(props)) { + default: + case SDL_TEXTINPUT_TYPE_TEXT: + param.type = SCE_IME_TYPE_DEFAULT; + break; + case SDL_TEXTINPUT_TYPE_TEXT_NAME: + param.type = SCE_IME_TYPE_DEFAULT; + break; + case SDL_TEXTINPUT_TYPE_TEXT_EMAIL: + param.type = SCE_IME_TYPE_MAIL; + break; + case SDL_TEXTINPUT_TYPE_TEXT_USERNAME: + param.type = SCE_IME_TYPE_DEFAULT; + break; + case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN: + param.type = SCE_IME_TYPE_DEFAULT; + break; + case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE: + param.type = SCE_IME_TYPE_DEFAULT; + break; + case SDL_TEXTINPUT_TYPE_NUMBER: + param.type = SCE_IME_TYPE_NUMBER; + break; + case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN: + param.type = SCE_IME_TYPE_NUMBER; + break; + case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE: + param.type = SCE_IME_TYPE_NUMBER; + break; + } + param.option = 0; + if (SDL_GetTextInputCapitalization(props) != SDL_CAPITALIZE_SENTENCES) { + param.option |= SCE_IME_OPTION_NO_AUTO_CAPITALIZATION; + } + if (!SDL_GetTextInputAutocorrect(props)) { + param.option |= SCE_IME_OPTION_NO_ASSISTANCE; + } + if (SDL_GetTextInputMultiline(props)) { + param.option |= SCE_IME_OPTION_MULTILINE; + } + param.inputTextBuffer = libime_out; + param.maxTextLength = SCE_IME_MAX_TEXT_LENGTH; + param.handler = VITA_ImeEventHandler; + param.filter = NULL; + param.initialText = (SceWChar16 *)libime_initval; + param.arg = videodata; + param.work = libime_work; + + res = sceImeOpen(¶m); + if (res < 0) { + SDL_SetError("Failed to init IME"); + return; + } + +#else + SceWChar16 *title = u""; + SceWChar16 *text = u""; + + SceImeDialogParam param; + sceImeDialogParamInit(¶m); + + param.supportedLanguages = 0; + param.languagesForced = SCE_FALSE; + param.type = SCE_IME_TYPE_DEFAULT; + param.option = 0; + param.textBoxMode = SCE_IME_DIALOG_TEXTBOX_MODE_WITH_CLEAR; + param.maxTextLength = SCE_IME_DIALOG_MAX_TEXT_LENGTH; + + param.title = title; + param.initialText = text; + param.inputTextBuffer = videodata->ime_buffer; + + res = sceImeDialogInit(¶m); + if (res < 0) { + SDL_SetError("Failed to init IME dialog"); + return; + } + +#endif + + videodata->ime_active = true; +} + +void VITA_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window) +{ +#ifndef SDL_VIDEO_VITA_PVR + SDL_VideoData *videodata = _this->internal; + + SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus(); + + switch (dialogStatus) { + default: + case SCE_COMMON_DIALOG_STATUS_NONE: + case SCE_COMMON_DIALOG_STATUS_RUNNING: + break; + case SCE_COMMON_DIALOG_STATUS_FINISHED: + sceImeDialogTerm(); + break; + } + + videodata->ime_active = false; +#endif +} + +bool VITA_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window) +{ +#ifdef SDL_VIDEO_VITA_PVR + SDL_VideoData *videodata = _this->internal; + return videodata->ime_active; +#else + SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus(); + return dialogStatus == SCE_COMMON_DIALOG_STATUS_RUNNING; +#endif +} + +void VITA_PumpEvents(SDL_VideoDevice *_this) +{ +#ifndef SDL_VIDEO_VITA_PVR + SDL_VideoData *videodata = _this->internal; +#endif + + if (_this->suspend_screensaver) { + // cancel all idle timers to prevent vita going to sleep + sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DEFAULT); + } + + VITA_PollTouch(); + VITA_PollKeyboard(); + VITA_PollMouse(); + +#ifndef SDL_VIDEO_VITA_PVR + if (videodata->ime_active == true) { + // update IME status. Terminate, if finished + SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus(); + if (dialogStatus == SCE_COMMON_DIALOG_STATUS_FINISHED) { + uint8_t utf8_buffer[SCE_IME_DIALOG_MAX_TEXT_LENGTH]; + + SceImeDialogResult result; + SDL_memset(&result, 0, sizeof(SceImeDialogResult)); + sceImeDialogGetResult(&result); + + // Convert UTF16 to UTF8 + utf16_to_utf8(videodata->ime_buffer, utf8_buffer); + + // Send SDL event + SDL_SendKeyboardText((const char *)utf8_buffer); + + // Send enter key only on enter + if (result.button == SCE_IME_DIALOG_BUTTON_ENTER) { + SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_RETURN); + } + + sceImeDialogTerm(); + + videodata->ime_active = false; + } + } +#endif +} + +#endif // SDL_VIDEO_DRIVER_VITA -- cgit v1.2.3