summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c')
-rw-r--r--contrib/SDL-3.2.8/src/video/vita/SDL_vitavideo.c592
1 files changed, 592 insertions, 0 deletions
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 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22#include "SDL_internal.h"
23
24#ifdef SDL_VIDEO_DRIVER_VITA
25
26// SDL internals
27#include "../SDL_sysvideo.h"
28#include "../../events/SDL_mouse_c.h"
29#include "../../events/SDL_keyboard_c.h"
30
31// VITA declarations
32#include <psp2/kernel/processmgr.h>
33#include "SDL_vitavideo.h"
34#include "SDL_vitatouch.h"
35#include "SDL_vitakeyboard.h"
36#include "SDL_vitamouse_c.h"
37#include "SDL_vitaframebuffer.h"
38#include "SDL_vitamessagebox.h"
39
40#ifdef SDL_VIDEO_VITA_PIB
41#include "SDL_vitagles_c.h"
42#elif defined(SDL_VIDEO_VITA_PVR)
43#include "SDL_vitagles_pvr_c.h"
44#ifdef SDL_VIDEO_VITA_PVR_OGL
45#include "SDL_vitagl_pvr_c.h"
46#endif
47#define VITA_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
48#define VITA_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
49#define VITA_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
50#define VITA_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
51#define VITA_GLES_DestroyContext SDL_EGL_DestroyContext
52#endif
53
54SDL_Window *Vita_Window;
55
56static void VITA_Destroy(SDL_VideoDevice *device)
57{
58 SDL_free(device->internal);
59 SDL_free(device);
60}
61
62static SDL_VideoDevice *VITA_Create(void)
63{
64 SDL_VideoDevice *device;
65 SDL_VideoData *phdata;
66#ifdef SDL_VIDEO_VITA_PIB
67 SDL_GLDriverData *gldata;
68#endif
69 // Initialize SDL_VideoDevice structure
70 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
71 if (!device) {
72 return NULL;
73 }
74
75 // Initialize internal VITA specific data
76 phdata = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
77 if (!phdata) {
78 SDL_free(device);
79 return NULL;
80 }
81#ifdef SDL_VIDEO_VITA_PIB
82
83 gldata = (SDL_GLDriverData *)SDL_calloc(1, sizeof(SDL_GLDriverData));
84 if (!gldata) {
85 SDL_free(device);
86 SDL_free(phdata);
87 return NULL;
88 }
89 device->gl_data = gldata;
90 phdata->egl_initialized = true;
91#endif
92 phdata->ime_active = false;
93
94 device->internal = phdata;
95
96 // Setup amount of available displays and current display
97 device->num_displays = 0;
98
99 // Set device free function
100 device->free = VITA_Destroy;
101
102 // Setup all functions which we can handle
103 device->VideoInit = VITA_VideoInit;
104 device->VideoQuit = VITA_VideoQuit;
105 device->CreateSDLWindow = VITA_CreateWindow;
106 device->SetWindowTitle = VITA_SetWindowTitle;
107 device->SetWindowPosition = VITA_SetWindowPosition;
108 device->SetWindowSize = VITA_SetWindowSize;
109 device->ShowWindow = VITA_ShowWindow;
110 device->HideWindow = VITA_HideWindow;
111 device->RaiseWindow = VITA_RaiseWindow;
112 device->MaximizeWindow = VITA_MaximizeWindow;
113 device->MinimizeWindow = VITA_MinimizeWindow;
114 device->RestoreWindow = VITA_RestoreWindow;
115 device->SetWindowMouseGrab = VITA_SetWindowGrab;
116 device->SetWindowKeyboardGrab = VITA_SetWindowGrab;
117 device->DestroyWindow = VITA_DestroyWindow;
118
119 /*
120 // Disabled, causes issues on high-framerate updates. SDL still emulates this.
121 device->CreateWindowFramebuffer = VITA_CreateWindowFramebuffer;
122 device->UpdateWindowFramebuffer = VITA_UpdateWindowFramebuffer;
123 device->DestroyWindowFramebuffer = VITA_DestroyWindowFramebuffer;
124 */
125
126#if defined(SDL_VIDEO_VITA_PIB) || defined(SDL_VIDEO_VITA_PVR)
127#ifdef SDL_VIDEO_VITA_PVR_OGL
128 if (SDL_GetHintBoolean(SDL_HINT_VITA_PVR_OPENGL, false)) {
129 device->GL_LoadLibrary = VITA_GL_LoadLibrary;
130 device->GL_CreateContext = VITA_GL_CreateContext;
131 device->GL_GetProcAddress = VITA_GL_GetProcAddress;
132 } else {
133#endif
134 device->GL_LoadLibrary = VITA_GLES_LoadLibrary;
135 device->GL_CreateContext = VITA_GLES_CreateContext;
136 device->GL_GetProcAddress = VITA_GLES_GetProcAddress;
137#ifdef SDL_VIDEO_VITA_PVR_OGL
138 }
139#endif
140
141 device->GL_UnloadLibrary = VITA_GLES_UnloadLibrary;
142 device->GL_MakeCurrent = VITA_GLES_MakeCurrent;
143 device->GL_SetSwapInterval = VITA_GLES_SetSwapInterval;
144 device->GL_GetSwapInterval = VITA_GLES_GetSwapInterval;
145 device->GL_SwapWindow = VITA_GLES_SwapWindow;
146 device->GL_DestroyContext = VITA_GLES_DestroyContext;
147#endif
148
149 device->HasScreenKeyboardSupport = VITA_HasScreenKeyboardSupport;
150 device->ShowScreenKeyboard = VITA_ShowScreenKeyboard;
151 device->HideScreenKeyboard = VITA_HideScreenKeyboard;
152 device->IsScreenKeyboardShown = VITA_IsScreenKeyboardShown;
153
154 device->PumpEvents = VITA_PumpEvents;
155
156 return device;
157}
158
159VideoBootStrap VITA_bootstrap = {
160 "vita",
161 "VITA Video Driver",
162 VITA_Create,
163 VITA_ShowMessageBox,
164 false
165};
166
167/*****************************************************************************/
168// SDL Video and Display initialization/handling functions
169/*****************************************************************************/
170bool VITA_VideoInit(SDL_VideoDevice *_this)
171{
172 SDL_DisplayMode mode;
173#ifdef SDL_VIDEO_VITA_PVR
174 const char *res = SDL_GetHint(SDL_HINT_VITA_RESOLUTION);
175#endif
176 SDL_zero(mode);
177
178#ifdef SDL_VIDEO_VITA_PVR
179 if (res) {
180 // 1088i for PSTV (Or Sharpscale)
181 if (SDL_strncmp(res, "1080", 4) == 0) {
182 mode.w = 1920;
183 mode.h = 1088;
184 }
185 // 725p for PSTV (Or Sharpscale)
186 else if (SDL_strncmp(res, "720", 3) == 0) {
187 mode.w = 1280;
188 mode.h = 725;
189 }
190 }
191 // 544p
192 else {
193#endif
194 mode.w = 960;
195 mode.h = 544;
196#ifdef SDL_VIDEO_VITA_PVR
197 }
198#endif
199
200 mode.refresh_rate = 60.0f;
201
202 // 32 bpp for default
203 mode.format = SDL_PIXELFORMAT_ABGR8888;
204
205 if (SDL_AddBasicVideoDisplay(&mode) == 0) {
206 return false;
207 }
208
209 VITA_InitTouch();
210 VITA_InitKeyboard();
211 VITA_InitMouse();
212
213 return true;
214}
215
216void VITA_VideoQuit(SDL_VideoDevice *_this)
217{
218 VITA_QuitTouch();
219}
220
221bool VITA_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
222{
223 SDL_WindowData *wdata;
224#ifdef SDL_VIDEO_VITA_PVR
225 Psp2NativeWindow win;
226 int temp_major = 2;
227 int temp_minor = 1;
228 int temp_profile = 0;
229#endif
230
231 // Allocate window internal data
232 wdata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
233 if (!wdata) {
234 return false;
235 }
236
237 // Setup driver data for this window
238 window->internal = wdata;
239
240 // Vita can only have one window
241 if (Vita_Window) {
242 return SDL_SetError("Only one window supported");
243 }
244
245 Vita_Window = window;
246
247#ifdef SDL_VIDEO_VITA_PVR
248 win.type = PSP2_DRAWABLE_TYPE_WINDOW;
249 win.numFlipBuffers = 2;
250 win.flipChainThrdAffinity = 0x20000;
251
252 // 1088i for PSTV (Or Sharpscale)
253 if (window->w == 1920) {
254 win.windowSize = PSP2_WINDOW_1920X1088;
255 }
256 // 725p for PSTV (Or Sharpscale)
257 else if (window->w == 1280) {
258 win.windowSize = PSP2_WINDOW_1280X725;
259 }
260 // 544p
261 else {
262 win.windowSize = PSP2_WINDOW_960X544;
263 }
264 if (window->flags & SDL_WINDOW_OPENGL) {
265 bool use_opengl = SDL_GetHintBoolean(SDL_HINT_VITA_PVR_OPENGL, false);
266 if (use_opengl) {
267 // Set version to 2.1 and PROFILE to ES
268 temp_major = _this->gl_config.major_version;
269 temp_minor = _this->gl_config.minor_version;
270 temp_profile = _this->gl_config.profile_mask;
271
272 _this->gl_config.major_version = 2;
273 _this->gl_config.minor_version = 1;
274 _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
275 }
276 wdata->egl_surface = SDL_EGL_CreateSurface(_this, window, &win);
277 if (wdata->egl_surface == EGL_NO_SURFACE) {
278 return SDL_SetError("Could not create GLES window surface");
279 }
280 if (use_opengl) {
281 // Revert
282 _this->gl_config.major_version = temp_major;
283 _this->gl_config.minor_version = temp_minor;
284 _this->gl_config.profile_mask = temp_profile;
285 }
286 }
287#endif
288
289 // fix input, we need to find a better way
290 SDL_SetKeyboardFocus(window);
291
292 // Window has been successfully created
293 return true;
294}
295
296void VITA_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
297{
298}
299bool VITA_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window)
300{
301 return SDL_Unsupported();
302}
303void VITA_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
304{
305}
306void VITA_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
307{
308}
309void VITA_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
310{
311}
312void VITA_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window)
313{
314}
315void VITA_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
316{
317}
318void VITA_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
319{
320}
321void VITA_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
322{
323}
324bool VITA_SetWindowGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed)
325{
326 return true;
327}
328
329void VITA_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
330{
331 SDL_WindowData *data;
332
333 data = window->internal;
334 if (data) {
335 // TODO: should we destroy egl context? No one sane should recreate ogl window as non-ogl
336 SDL_free(data);
337 }
338
339 window->internal = NULL;
340 Vita_Window = NULL;
341}
342
343bool VITA_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
344{
345 return true;
346}
347
348#ifndef SCE_IME_LANGUAGE_ENGLISH_US
349#define SCE_IME_LANGUAGE_ENGLISH_US SCE_IME_LANGUAGE_ENGLISH
350#endif
351
352static void utf16_to_utf8(const uint16_t *src, uint8_t *dst)
353{
354 int i;
355 for (i = 0; src[i]; i++) {
356 if (!(src[i] & 0xFF80)) {
357 *(dst++) = src[i] & 0xFF;
358 } else if (!(src[i] & 0xF800)) {
359 *(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0;
360 *(dst++) = (src[i] & 0x3F) | 0x80;
361 } else if ((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00) {
362 *(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0;
363 *(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80;
364 *(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF);
365 *(dst++) = (src[i + 1] & 0x3F) | 0x80;
366 i += 1;
367 } else {
368 *(dst++) = ((src[i] >> 12) & 0xF) | 0xE0;
369 *(dst++) = ((src[i] >> 6) & 0x3F) | 0x80;
370 *(dst++) = (src[i] & 0x3F) | 0x80;
371 }
372 }
373
374 *dst = '\0';
375}
376
377#ifdef SDL_VIDEO_VITA_PVR
378SceWChar16 libime_out[SCE_IME_MAX_PREEDIT_LENGTH + SCE_IME_MAX_TEXT_LENGTH + 1];
379char libime_initval[8] = { 1 };
380SceImeCaret caret_rev;
381
382void VITA_ImeEventHandler(void *arg, const SceImeEventData *e)
383{
384 SDL_VideoData *videodata = (SDL_VideoData *)arg;
385 uint8_t utf8_buffer[SCE_IME_MAX_TEXT_LENGTH];
386 switch (e->id) {
387 case SCE_IME_EVENT_UPDATE_TEXT:
388 if (e->param.text.caretIndex == 0) {
389 SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_BACKSPACE);
390 sceImeSetText((SceWChar16 *)libime_initval, 4);
391 } else {
392 utf16_to_utf8((SceWChar16 *)&libime_out[1], utf8_buffer);
393 if (utf8_buffer[0] == ' ') {
394 SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_SPACE);
395 } else {
396 SDL_SendKeyboardText((const char *)utf8_buffer);
397 }
398 SDL_memset(&caret_rev, 0, sizeof(SceImeCaret));
399 SDL_memset(libime_out, 0, ((SCE_IME_MAX_PREEDIT_LENGTH + SCE_IME_MAX_TEXT_LENGTH + 1) * sizeof(SceWChar16)));
400 caret_rev.index = 1;
401 sceImeSetCaret(&caret_rev);
402 sceImeSetText((SceWChar16 *)libime_initval, 4);
403 }
404 break;
405 case SCE_IME_EVENT_PRESS_ENTER:
406 SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_RETURN);
407 break;
408 case SCE_IME_EVENT_PRESS_CLOSE:
409 sceImeClose();
410 videodata->ime_active = false;
411 break;
412 }
413}
414#endif
415
416void VITA_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
417{
418 SDL_VideoData *videodata = _this->internal;
419 SceInt32 res;
420
421#ifdef SDL_VIDEO_VITA_PVR
422
423 SceUInt32 libime_work[SCE_IME_WORK_BUFFER_SIZE / sizeof(SceInt32)];
424 SceImeParam param;
425
426 sceImeParamInit(&param);
427
428 SDL_memset(libime_out, 0, ((SCE_IME_MAX_PREEDIT_LENGTH + SCE_IME_MAX_TEXT_LENGTH + 1) * sizeof(SceWChar16)));
429
430 param.supportedLanguages = SCE_IME_LANGUAGE_ENGLISH_US;
431 param.languagesForced = SCE_FALSE;
432 switch (SDL_GetTextInputType(props)) {
433 default:
434 case SDL_TEXTINPUT_TYPE_TEXT:
435 param.type = SCE_IME_TYPE_DEFAULT;
436 break;
437 case SDL_TEXTINPUT_TYPE_TEXT_NAME:
438 param.type = SCE_IME_TYPE_DEFAULT;
439 break;
440 case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
441 param.type = SCE_IME_TYPE_MAIL;
442 break;
443 case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
444 param.type = SCE_IME_TYPE_DEFAULT;
445 break;
446 case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
447 param.type = SCE_IME_TYPE_DEFAULT;
448 break;
449 case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
450 param.type = SCE_IME_TYPE_DEFAULT;
451 break;
452 case SDL_TEXTINPUT_TYPE_NUMBER:
453 param.type = SCE_IME_TYPE_NUMBER;
454 break;
455 case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
456 param.type = SCE_IME_TYPE_NUMBER;
457 break;
458 case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
459 param.type = SCE_IME_TYPE_NUMBER;
460 break;
461 }
462 param.option = 0;
463 if (SDL_GetTextInputCapitalization(props) != SDL_CAPITALIZE_SENTENCES) {
464 param.option |= SCE_IME_OPTION_NO_AUTO_CAPITALIZATION;
465 }
466 if (!SDL_GetTextInputAutocorrect(props)) {
467 param.option |= SCE_IME_OPTION_NO_ASSISTANCE;
468 }
469 if (SDL_GetTextInputMultiline(props)) {
470 param.option |= SCE_IME_OPTION_MULTILINE;
471 }
472 param.inputTextBuffer = libime_out;
473 param.maxTextLength = SCE_IME_MAX_TEXT_LENGTH;
474 param.handler = VITA_ImeEventHandler;
475 param.filter = NULL;
476 param.initialText = (SceWChar16 *)libime_initval;
477 param.arg = videodata;
478 param.work = libime_work;
479
480 res = sceImeOpen(&param);
481 if (res < 0) {
482 SDL_SetError("Failed to init IME");
483 return;
484 }
485
486#else
487 SceWChar16 *title = u"";
488 SceWChar16 *text = u"";
489
490 SceImeDialogParam param;
491 sceImeDialogParamInit(&param);
492
493 param.supportedLanguages = 0;
494 param.languagesForced = SCE_FALSE;
495 param.type = SCE_IME_TYPE_DEFAULT;
496 param.option = 0;
497 param.textBoxMode = SCE_IME_DIALOG_TEXTBOX_MODE_WITH_CLEAR;
498 param.maxTextLength = SCE_IME_DIALOG_MAX_TEXT_LENGTH;
499
500 param.title = title;
501 param.initialText = text;
502 param.inputTextBuffer = videodata->ime_buffer;
503
504 res = sceImeDialogInit(&param);
505 if (res < 0) {
506 SDL_SetError("Failed to init IME dialog");
507 return;
508 }
509
510#endif
511
512 videodata->ime_active = true;
513}
514
515void VITA_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
516{
517#ifndef SDL_VIDEO_VITA_PVR
518 SDL_VideoData *videodata = _this->internal;
519
520 SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus();
521
522 switch (dialogStatus) {
523 default:
524 case SCE_COMMON_DIALOG_STATUS_NONE:
525 case SCE_COMMON_DIALOG_STATUS_RUNNING:
526 break;
527 case SCE_COMMON_DIALOG_STATUS_FINISHED:
528 sceImeDialogTerm();
529 break;
530 }
531
532 videodata->ime_active = false;
533#endif
534}
535
536bool VITA_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
537{
538#ifdef SDL_VIDEO_VITA_PVR
539 SDL_VideoData *videodata = _this->internal;
540 return videodata->ime_active;
541#else
542 SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus();
543 return dialogStatus == SCE_COMMON_DIALOG_STATUS_RUNNING;
544#endif
545}
546
547void VITA_PumpEvents(SDL_VideoDevice *_this)
548{
549#ifndef SDL_VIDEO_VITA_PVR
550 SDL_VideoData *videodata = _this->internal;
551#endif
552
553 if (_this->suspend_screensaver) {
554 // cancel all idle timers to prevent vita going to sleep
555 sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DEFAULT);
556 }
557
558 VITA_PollTouch();
559 VITA_PollKeyboard();
560 VITA_PollMouse();
561
562#ifndef SDL_VIDEO_VITA_PVR
563 if (videodata->ime_active == true) {
564 // update IME status. Terminate, if finished
565 SceCommonDialogStatus dialogStatus = sceImeDialogGetStatus();
566 if (dialogStatus == SCE_COMMON_DIALOG_STATUS_FINISHED) {
567 uint8_t utf8_buffer[SCE_IME_DIALOG_MAX_TEXT_LENGTH];
568
569 SceImeDialogResult result;
570 SDL_memset(&result, 0, sizeof(SceImeDialogResult));
571 sceImeDialogGetResult(&result);
572
573 // Convert UTF16 to UTF8
574 utf16_to_utf8(videodata->ime_buffer, utf8_buffer);
575
576 // Send SDL event
577 SDL_SendKeyboardText((const char *)utf8_buffer);
578
579 // Send enter key only on enter
580 if (result.button == SCE_IME_DIALOG_BUTTON_ENTER) {
581 SDL_SendKeyboardKeyAutoRelease(0, SDL_SCANCODE_RETURN);
582 }
583
584 sceImeDialogTerm();
585
586 videodata->ime_active = false;
587 }
588 }
589#endif
590}
591
592#endif // SDL_VIDEO_DRIVER_VITA