mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-06-05 22:30:29 +00:00
Android: add RPC commands from SDLActivity thread to SDL Main C thread.
- now SDLActivity defers most of SDL code internal execution to the Main thread. Since all code is now in Main thread, this prevents any race conditions within SDL code. - WatchEvents, including user ones, are now exected in SDL Main C thread This prevents race conditions that a user could add. - Simplify the locking/mutex internals between SDLActivity and Main. SDLActivity native code / synchronization is reduced to the minimum and fastest. - ordering between pause/resume and java surface create/changed/destroyed is kept. (prevent to do a "resume" before java surface isn't set up) - Fixed bug #11324 - Android opengles2: First SDL_RenderPresent() broken after resize Call ANativeWindow_setBuffersGeometry when size changes ( Android_NativeSurfaceResized ) NB: you can define SDL_ANDROID_GAMEPAD_AS_RPC in src/core/android/SDL_android.c so that the code that sends gamepad events is moved to main SDLThread (see #14925, #14962)
This commit is contained in:
parent
fc3a96e47a
commit
08c72af7aa
15 changed files with 1717 additions and 680 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -38,22 +38,8 @@ extern "C" {
|
|||
// this appears to be broken right now (on Android, not SDL, I think...?).
|
||||
#define ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES 0
|
||||
|
||||
// Life cycle
|
||||
typedef enum
|
||||
{
|
||||
SDL_ANDROID_LIFECYCLE_WAKE,
|
||||
SDL_ANDROID_LIFECYCLE_PAUSE,
|
||||
SDL_ANDROID_LIFECYCLE_RESUME,
|
||||
SDL_ANDROID_LIFECYCLE_LOWMEMORY,
|
||||
SDL_ANDROID_LIFECYCLE_DESTROY,
|
||||
SDL_NUM_ANDROID_LIFECYCLE_EVENTS
|
||||
} SDL_AndroidLifecycleEvent;
|
||||
|
||||
void Android_SendLifecycleEvent(SDL_AndroidLifecycleEvent event);
|
||||
bool Android_WaitLifecycleEvent(SDL_AndroidLifecycleEvent *event, Sint64 timeoutNS);
|
||||
|
||||
void Android_LockActivityMutex(void);
|
||||
void Android_UnlockActivityMutex(void);
|
||||
void Android_LockActivityState(void);
|
||||
void Android_UnlockActivityState(void);
|
||||
|
||||
void Android_SetAllowRecreateActivity(bool enabled);
|
||||
|
||||
|
|
@ -159,6 +145,11 @@ bool Android_JNI_ShowFileDialog(SDL_DialogFileCallback callback, void *userdata,
|
|||
const SDL_DialogFileFilter *filters, int nfilters, SDL_FileDialogType type,
|
||||
bool multiple, const char *initialPath);
|
||||
|
||||
// Pump RPC commands
|
||||
void Android_PumpRPC(SDL_Window *window);
|
||||
void Android_WaitForResume(void);
|
||||
|
||||
|
||||
// Ends C function definitions when using C++
|
||||
#ifdef __cplusplus
|
||||
/* *INDENT-OFF* */
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
#include "../video/SDL_sysvideo.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
#include "../core/android/SDL_android.h"
|
||||
#include "../video/android/SDL_androidevents.h"
|
||||
#endif
|
||||
|
||||
|
|
@ -1153,7 +1152,7 @@ static void SDL_CutEvent(SDL_EventEntry *entry)
|
|||
static void SDL_SendWakeupEvent(void)
|
||||
{
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
Android_SendLifecycleEvent(SDL_ANDROID_LIFECYCLE_WAKE);
|
||||
Android_WakeUp();
|
||||
#else
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
if (_this == NULL || !_this->SendWakeupEvent) {
|
||||
|
|
@ -1539,7 +1538,7 @@ static void SDL_PumpEventsInternal(bool push_sentinel)
|
|||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
// Android event processing is independent of the video subsystem
|
||||
Android_PumpEvents(0);
|
||||
Android_PumpEvents();
|
||||
#else
|
||||
// Get events from the video subsystem
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
|
@ -1573,7 +1572,12 @@ void SDL_PumpEvents(void)
|
|||
|
||||
bool SDL_PollEvent(SDL_Event *event)
|
||||
{
|
||||
return SDL_WaitEventTimeoutNS(event, 0);
|
||||
bool ret = SDL_WaitEventTimeoutNS(event, 0);
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
Android_BlockEventLoop();
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
#ifndef SDL_PLATFORM_ANDROID
|
||||
|
|
@ -1763,16 +1767,16 @@ bool SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS)
|
|||
return true;
|
||||
}
|
||||
|
||||
Uint64 delay = -1;
|
||||
Uint64 delay = SDL_MS_TO_NS(10);
|
||||
if (timeoutNS > 0) {
|
||||
Uint64 now = SDL_GetTicksNS();
|
||||
if (now >= expiration) {
|
||||
// Timeout expired and no events
|
||||
return false;
|
||||
}
|
||||
delay = (expiration - now);
|
||||
delay = SDL_min((expiration - now), delay);
|
||||
}
|
||||
Android_PumpEvents(delay);
|
||||
SDL_DelayNS(delay);
|
||||
}
|
||||
#else
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ static int numjoysticks = 0;
|
|||
* This code manipulation is done to get a sequential list of codes.
|
||||
* FIXME: This is only suited for the case where we use a fixed number of buttons determined by ANDROID_MAX_NBUTTONS
|
||||
*/
|
||||
static int keycode_to_SDL(int keycode)
|
||||
int Android_keycode_to_SDL(int keycode)
|
||||
{
|
||||
// FIXME: If this function gets too unwieldy in the future, replace with a lookup table
|
||||
int button = 0;
|
||||
|
|
@ -172,7 +172,7 @@ static int keycode_to_SDL(int keycode)
|
|||
return button;
|
||||
}
|
||||
|
||||
static int scancode_to_SDL(int scancode)
|
||||
int Android_scancode_to_SDL(int scancode)
|
||||
{
|
||||
int button = 0;
|
||||
switch (scancode) {
|
||||
|
|
@ -226,9 +226,9 @@ bool Android_OnPadDown(int device_id, int keycode, int scancode)
|
|||
{
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
SDL_joylist_item *item;
|
||||
int button = keycode_to_SDL(keycode);
|
||||
int button = Android_keycode_to_SDL(keycode);
|
||||
if (button < 0) {
|
||||
button = scancode_to_SDL(scancode);
|
||||
button = Android_scancode_to_SDL(scancode);
|
||||
}
|
||||
if (button >= 0) {
|
||||
SDL_LockJoysticks();
|
||||
|
|
@ -249,9 +249,9 @@ bool Android_OnPadUp(int device_id, int keycode, int scancode)
|
|||
{
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
SDL_joylist_item *item;
|
||||
int button = keycode_to_SDL(keycode);
|
||||
int button = Android_keycode_to_SDL(keycode);
|
||||
if (button < 0) {
|
||||
button = scancode_to_SDL(scancode);
|
||||
button = Android_scancode_to_SDL(scancode);
|
||||
}
|
||||
if (button >= 0) {
|
||||
SDL_LockJoysticks();
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
#include "../SDL_sysjoystick.h"
|
||||
|
||||
extern int Android_keycode_to_SDL(int keycode);
|
||||
extern int Android_scancode_to_SDL(int scancode);
|
||||
extern bool Android_OnPadDown(int device_id, int keycode, int scancode);
|
||||
extern bool Android_OnPadUp(int device_id, int keycode, int scancode);
|
||||
extern bool Android_OnJoy(int device_id, int axisnum, float value);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@
|
|||
#include "SDL_internal.h"
|
||||
#include "SDL_main_callbacks.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
#include "../video/android/SDL_androidevents.h"
|
||||
#endif
|
||||
|
||||
static SDL_AppEvent_func SDL_main_event_callback;
|
||||
static SDL_AppIterate_func SDL_main_iteration_callback;
|
||||
static SDL_AppQuit_func SDL_main_quit_callback;
|
||||
|
|
@ -123,6 +127,11 @@ SDL_AppResult SDL_IterateMainCallbacks(bool pump_events)
|
|||
if (pump_events) {
|
||||
SDL_PumpEvents();
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
Android_BlockEventLoop();
|
||||
#endif
|
||||
|
||||
SDL_DispatchMainCallbackEvents();
|
||||
|
||||
SDL_AppResult rc = (SDL_AppResult)SDL_GetAtomicInt(&apprc);
|
||||
|
|
|
|||
|
|
@ -1083,7 +1083,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
|
|||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (!Android_WaitActiveAndLockActivity()) {
|
||||
if (!Android_WaitActiveAndLockActivity(window)) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1263,7 +1263,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
|
|||
SDL_renderers = renderer;
|
||||
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
Android_UnlockActivityMutex();
|
||||
Android_UnlockActivityState();
|
||||
#endif
|
||||
|
||||
SDL_ClearError();
|
||||
|
|
@ -1272,7 +1272,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
|
|||
|
||||
error:
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
Android_UnlockActivityMutex();
|
||||
Android_UnlockActivityState();
|
||||
#endif
|
||||
|
||||
if (renderer) {
|
||||
|
|
|
|||
|
|
@ -33,10 +33,14 @@
|
|||
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
static void android_egl_context_restore(SDL_Window *window)
|
||||
// Restore EGL context when we have both:
|
||||
// nativeSurfaceCreated()
|
||||
// and SDLActivity hasFocus();
|
||||
void Android_egl_context_restore(SDL_Window *window)
|
||||
{
|
||||
if (window) {
|
||||
SDL_WindowData *data = window->internal;
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
if (data->backup_done && data->egl_surface != EGL_NO_SURFACE) {
|
||||
SDL_GL_MakeCurrent(window, NULL);
|
||||
if (!SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context)) {
|
||||
// The context is no longer valid, create a new one
|
||||
|
|
@ -54,24 +58,22 @@ static void android_egl_context_restore(SDL_Window *window)
|
|||
}
|
||||
}
|
||||
|
||||
static void android_egl_context_backup(SDL_Window *window)
|
||||
static void Android_egl_context_backup(SDL_Window *window)
|
||||
{
|
||||
if (window) {
|
||||
int interval = 0;
|
||||
// Keep a copy of the EGL Context so we can try to restore it when we resume
|
||||
SDL_WindowData *data = window->internal;
|
||||
data->egl_context = SDL_GL_GetCurrentContext();
|
||||
int interval = 0;
|
||||
// Keep a copy of the EGL Context so we can try to restore it when we resume
|
||||
SDL_WindowData *data = window->internal;
|
||||
data->egl_context = SDL_GL_GetCurrentContext();
|
||||
|
||||
// Save/Restore the swap interval / vsync
|
||||
if (SDL_GL_GetSwapInterval(&interval)) {
|
||||
data->has_swap_interval = 1;
|
||||
data->swap_interval = interval;
|
||||
}
|
||||
|
||||
// We need to do this so the EGLSurface can be freed
|
||||
SDL_GL_MakeCurrent(window, NULL);
|
||||
data->backup_done = true;
|
||||
// Save/Restore the swap interval / vsync
|
||||
if (SDL_GL_GetSwapInterval(&interval)) {
|
||||
data->has_swap_interval = 1;
|
||||
data->swap_interval = interval;
|
||||
}
|
||||
|
||||
// We need to do this so the EGLSurface can be freed
|
||||
SDL_GL_MakeCurrent(window, NULL);
|
||||
data->backup_done = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -103,6 +105,7 @@ static void Android_PauseAudio(void)
|
|||
|
||||
static void Android_ResumeAudio(void)
|
||||
{
|
||||
|
||||
if (Android_PausedAudio) {
|
||||
OPENSLES_ResumeDevices();
|
||||
AAUDIO_ResumeDevices();
|
||||
|
|
@ -110,7 +113,12 @@ static void Android_ResumeAudio(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void Android_OnPause(void)
|
||||
bool Android_RenderingAvailable()
|
||||
{
|
||||
return !Android_Paused;
|
||||
}
|
||||
|
||||
void Android_OnPause(SDL_Window *window)
|
||||
{
|
||||
SDL_OnApplicationWillEnterBackground();
|
||||
SDL_OnApplicationDidEnterBackground();
|
||||
|
|
@ -121,10 +129,8 @@ static void Android_OnPause(void)
|
|||
* was being queued.
|
||||
*/
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
if (Android_Window && !Android_Window->external_graphics_context) {
|
||||
Android_LockActivityMutex();
|
||||
android_egl_context_backup(Android_Window);
|
||||
Android_UnlockActivityMutex();
|
||||
if (window && !window->external_graphics_context) {
|
||||
Android_egl_context_backup(window);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -136,7 +142,7 @@ static void Android_OnPause(void)
|
|||
Android_Paused = true;
|
||||
}
|
||||
|
||||
static void Android_OnResume(void)
|
||||
void Android_OnResume(SDL_Window *window)
|
||||
{
|
||||
Android_Paused = false;
|
||||
|
||||
|
|
@ -146,22 +152,15 @@ static void Android_OnResume(void)
|
|||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
// Restore the GL Context from here, as this operation is thread dependent
|
||||
if (Android_Window && !Android_Window->external_graphics_context && !SDL_HasEvent(SDL_EVENT_QUIT)) {
|
||||
Android_LockActivityMutex();
|
||||
android_egl_context_restore(Android_Window);
|
||||
Android_UnlockActivityMutex();
|
||||
if (window && !window->external_graphics_context && !SDL_HasEvent(SDL_EVENT_QUIT)) {
|
||||
Android_egl_context_restore(window);
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_OnApplicationDidEnterForeground();
|
||||
}
|
||||
|
||||
static void Android_OnLowMemory(void)
|
||||
{
|
||||
SDL_SendAppEvent(SDL_EVENT_LOW_MEMORY);
|
||||
}
|
||||
|
||||
static void Android_OnDestroy(void)
|
||||
void Android_OnDestroy(void)
|
||||
{
|
||||
// Make sure we unblock any audio processing before we quit
|
||||
Android_ResumeAudio();
|
||||
|
|
@ -176,86 +175,77 @@ static void Android_OnDestroy(void)
|
|||
Android_Destroyed = true;
|
||||
}
|
||||
|
||||
static void Android_HandleLifecycleEvent(SDL_AndroidLifecycleEvent event)
|
||||
void Android_PumpEvents()
|
||||
{
|
||||
switch (event) {
|
||||
case SDL_ANDROID_LIFECYCLE_WAKE:
|
||||
// Nothing to do, just return
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_PAUSE:
|
||||
Android_OnPause();
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_RESUME:
|
||||
Android_OnResume();
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_LOWMEMORY:
|
||||
Android_OnLowMemory();
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_DESTROY:
|
||||
Android_OnDestroy();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static Sint64 GetLifecycleEventTimeout(bool paused, Sint64 timeoutNS)
|
||||
{
|
||||
if (Android_Paused) {
|
||||
if (Android_BlockOnPause) {
|
||||
timeoutNS = -1;
|
||||
} else if (timeoutNS == 0) {
|
||||
timeoutNS = SDL_MS_TO_NS(100);
|
||||
}
|
||||
}
|
||||
return timeoutNS;
|
||||
}
|
||||
|
||||
void Android_PumpEvents(Sint64 timeoutNS)
|
||||
{
|
||||
SDL_AndroidLifecycleEvent event;
|
||||
bool paused = Android_Paused;
|
||||
|
||||
while (!Android_Destroyed &&
|
||||
Android_WaitLifecycleEvent(&event, GetLifecycleEventTimeout(paused, timeoutNS))) {
|
||||
Android_HandleLifecycleEvent(event);
|
||||
|
||||
switch (event) {
|
||||
case SDL_ANDROID_LIFECYCLE_WAKE:
|
||||
// Finish handling events quickly if we're not paused
|
||||
timeoutNS = 0;
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_PAUSE:
|
||||
// Finish handling events at the current timeout and return to process events one more time before blocking.
|
||||
break;
|
||||
case SDL_ANDROID_LIFECYCLE_RESUME:
|
||||
// Finish handling events at the resume state timeout
|
||||
paused = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Android_WaitActiveAndLockActivity(void)
|
||||
{
|
||||
/* Make sure we have pumped all events so that Android_Paused state is correct */
|
||||
SDL_AndroidLifecycleEvent event;
|
||||
while (!Android_Destroyed && Android_WaitLifecycleEvent(&event, 0)) {
|
||||
Android_HandleLifecycleEvent(event);
|
||||
}
|
||||
|
||||
while (Android_Paused && !Android_Destroyed) {
|
||||
Android_PumpEvents(-1);
|
||||
}
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
SDL_Window *window = _this ? _this->windows : NULL;
|
||||
|
||||
if (Android_Destroyed) {
|
||||
SDL_SetError("Android activity has been destroyed");
|
||||
return;
|
||||
}
|
||||
|
||||
Android_PumpRPC(window);
|
||||
}
|
||||
|
||||
|
||||
// return 'true' if app has been blocked
|
||||
bool Android_BlockEventLoop()
|
||||
{
|
||||
if (Android_Destroyed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Android_LockActivityMutex();
|
||||
if (Android_Paused) {
|
||||
if (Android_BlockOnPause) {
|
||||
SDL_Log("BlockOnPause");
|
||||
Android_WaitForResume();
|
||||
SDL_Log("BlockOnPause...resume");
|
||||
|
||||
// app has been blocked. now we're unblocked.
|
||||
// pump to get 'resume' command (eg RPC_cmd_nativeResume).
|
||||
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
SDL_Window *window = _this ? _this->windows : NULL;
|
||||
Android_PumpRPC(window);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Android_WaitActiveAndLockActivity(SDL_Window *window)
|
||||
{
|
||||
retry:
|
||||
|
||||
// Lock first.
|
||||
// So no new lifecycle event comes in the meantimes from the SDLActivity,
|
||||
// Hence SDLActivity won't change state.
|
||||
Android_LockActivityState();
|
||||
|
||||
// Pump all events so that Android_Paused state is correct
|
||||
Android_PumpRPC(window);
|
||||
|
||||
if (Android_Destroyed) {
|
||||
SDL_SetError("Android activity has been destroyed");
|
||||
Android_UnlockActivityState();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Android_Paused) {
|
||||
// SDLActivity is Active. return lock'ed
|
||||
return true;
|
||||
} else {
|
||||
// Still Paused
|
||||
// Unlock and wait for the SDLActivity to send new cycle events
|
||||
// or for the user to move the app to foreground.
|
||||
Android_UnlockActivityState();
|
||||
SDL_Delay(10);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,16 @@
|
|||
#include "SDL_internal.h"
|
||||
|
||||
extern void Android_InitEvents(void);
|
||||
extern void Android_PumpEvents(Sint64 timeoutNS);
|
||||
extern bool Android_WaitActiveAndLockActivity(void);
|
||||
extern void Android_PumpEvents(void);
|
||||
extern bool Android_BlockEventLoop(void);
|
||||
extern bool Android_WaitActiveAndLockActivity(SDL_Window *window);
|
||||
extern void Android_QuitEvents(void);
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
void Android_egl_context_restore(SDL_Window *window);
|
||||
#endif
|
||||
|
||||
void Android_OnPause(SDL_Window *window);
|
||||
void Android_OnResume(SDL_Window *window);
|
||||
void Android_OnDestroy(void);
|
||||
void Android_WakeUp(void);
|
||||
bool Android_RenderingAvailable(void);
|
||||
|
|
|
|||
|
|
@ -49,13 +49,13 @@ SDL_GLContext Android_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *win
|
|||
{
|
||||
SDL_GLContext result;
|
||||
|
||||
if (!Android_WaitActiveAndLockActivity()) {
|
||||
if (!Android_WaitActiveAndLockActivity(window)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = SDL_EGL_CreateContext(_this, window->internal->egl_surface);
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
Android_UnlockActivityState();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -64,8 +64,6 @@ bool Android_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
{
|
||||
bool result;
|
||||
|
||||
Android_LockActivityMutex();
|
||||
|
||||
/* The following two calls existed in the original Java code
|
||||
* If you happen to have a device that's affected by their removal,
|
||||
* please report to our bug tracker. -- Gabriel
|
||||
|
|
@ -75,8 +73,6 @@ bool Android_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
_this->egl_data->eglWaitGL();*/
|
||||
result = SDL_EGL_SwapBuffers(_this, window->internal->egl_surface);
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ void Android_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
|
||||
void Android_RestoreScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
if (_this->screen_keyboard_shown) {
|
||||
if (_this && _this->screen_keyboard_shown && window) {
|
||||
Android_ShowScreenKeyboard(_this, window, window->text_input_props);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,17 +298,22 @@ void Android_SendResize(SDL_Window *window)
|
|||
if (window) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, Android_SurfaceWidth, Android_SurfaceHeight);
|
||||
}
|
||||
|
||||
// onNativeResize() should probably merged in to onNativeSurfaceChanged() so that
|
||||
// both RPC commands are executed atomically without user app trying to render inbetween
|
||||
// (and so Android_NativeSurfaceResized is called from Android_NativeSurfaceChanged())
|
||||
Android_NativeSurfaceResized(window);
|
||||
}
|
||||
|
||||
void Android_SetWindowSafeAreaInsets(int left, int right, int top, int bottom)
|
||||
void Android_SetWindowSafeAreaInsets(SDL_Window *window, int left, int right, int top, int bottom)
|
||||
{
|
||||
Android_SafeInsetLeft = left;
|
||||
Android_SafeInsetRight = right;
|
||||
Android_SafeInsetTop = top;
|
||||
Android_SafeInsetBottom = bottom;
|
||||
|
||||
if (Android_Window) {
|
||||
SDL_SetWindowSafeAreaInsets(Android_Window, left, right, top, bottom);
|
||||
if (window) {
|
||||
SDL_SetWindowSafeAreaInsets(window, left, right, top, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ extern void Android_SetScreenResolution(int surfaceWidth, int surfaceHeight, int
|
|||
extern void Android_SetFormat(int format_wanted, int format_got);
|
||||
extern void Android_SetOrientation(SDL_DisplayOrientation orientation);
|
||||
extern void Android_SendResize(SDL_Window *window);
|
||||
extern void Android_SetWindowSafeAreaInsets(int left, int right, int top, int bottom);
|
||||
extern void Android_SetWindowSafeAreaInsets(SDL_Window *window, int left, int right, int top, int bottom);
|
||||
extern void Android_SetDarkMode(bool enabled);
|
||||
|
||||
// Private display data
|
||||
|
|
|
|||
|
|
@ -34,18 +34,32 @@
|
|||
|
||||
|
||||
// Currently only one window
|
||||
SDL_Window *Android_Window = NULL;
|
||||
static bool window_created = false;
|
||||
|
||||
bool Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
bool result = true;
|
||||
|
||||
if (!Android_WaitActiveAndLockActivity()) {
|
||||
// Android_WaitActiveAndLockActivity() process some RPC:
|
||||
// "onSurfaceCreated" that needs "window->internal"
|
||||
// and also "nativeSetScreenResolution"
|
||||
|
||||
data = (SDL_WindowData *)SDL_calloc(1, sizeof(*data));
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Android_Window) {
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
data->egl_surface = EGL_NO_SURFACE;
|
||||
#endif
|
||||
window->internal = data;
|
||||
|
||||
if (!Android_WaitActiveAndLockActivity(window)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (window_created) {
|
||||
result = SDL_SetError("Android only supports one window");
|
||||
goto endfunction;
|
||||
}
|
||||
|
|
@ -63,44 +77,23 @@ bool Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper
|
|||
SDL_SetMouseFocus(window);
|
||||
SDL_SetKeyboardFocus(window);
|
||||
|
||||
data = (SDL_WindowData *)SDL_calloc(1, sizeof(*data));
|
||||
if (!data) {
|
||||
if (!Android_NativeSurfaceCreated(window)) {
|
||||
result = false;
|
||||
goto endfunction;
|
||||
}
|
||||
|
||||
data->native_window = Android_JNI_GetNativeWindow();
|
||||
if (!data->native_window) {
|
||||
SDL_free(data);
|
||||
result = SDL_SetError("Could not fetch native window");
|
||||
if (!Android_NativeSurfaceChanged(window)) {
|
||||
result = false;
|
||||
goto endfunction;
|
||||
}
|
||||
SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, data->native_window);
|
||||
|
||||
/* Do not create EGLSurface for Vulkan window since it will then make the window
|
||||
incompatible with vkCreateAndroidSurfaceKHR */
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
if (window->flags & SDL_WINDOW_OPENGL) {
|
||||
data->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)data->native_window);
|
||||
|
||||
if (data->egl_surface == EGL_NO_SURFACE) {
|
||||
ANativeWindow_release(data->native_window);
|
||||
SDL_free(data);
|
||||
result = false;
|
||||
goto endfunction;
|
||||
}
|
||||
}
|
||||
SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_ANDROID_SURFACE_POINTER, data->egl_surface);
|
||||
#endif
|
||||
|
||||
SDL_SetWindowSafeAreaInsets(window, Android_SafeInsetLeft, Android_SafeInsetRight, Android_SafeInsetTop, Android_SafeInsetBottom);
|
||||
|
||||
window->internal = data;
|
||||
Android_Window = window;
|
||||
window_created = true;
|
||||
|
||||
endfunction:
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
Android_UnlockActivityState();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -112,54 +105,48 @@ void Android_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
|
|||
|
||||
SDL_FullscreenResult Android_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen)
|
||||
{
|
||||
Android_LockActivityMutex();
|
||||
SDL_WindowData *data;
|
||||
int old_w, old_h, new_w, new_h;
|
||||
|
||||
if (window == Android_Window) {
|
||||
SDL_WindowData *data;
|
||||
int old_w, old_h, new_w, new_h;
|
||||
// If the window is being destroyed don't change visible state
|
||||
if (!window->is_destroying) {
|
||||
Android_JNI_SetWindowStyle(fullscreen);
|
||||
}
|
||||
|
||||
// If the window is being destroyed don't change visible state
|
||||
if (!window->is_destroying) {
|
||||
Android_JNI_SetWindowStyle(fullscreen);
|
||||
/* Ensure our size matches reality after we've executed the window style change.
|
||||
*
|
||||
* It is possible that we've set width and height to the full-size display, but on
|
||||
* Samsung DeX or Chromebooks or other windowed Android environments, our window may
|
||||
* still not be the full display size.
|
||||
*/
|
||||
if (!SDL_IsDeXMode() && !SDL_IsChromebook()) {
|
||||
goto endfunction;
|
||||
}
|
||||
|
||||
data = window->internal;
|
||||
if (!data || !data->native_window) {
|
||||
if (data && !data->native_window) {
|
||||
SDL_SetError("Missing native window");
|
||||
}
|
||||
goto endfunction;
|
||||
}
|
||||
|
||||
/* Ensure our size matches reality after we've executed the window style change.
|
||||
*
|
||||
* It is possible that we've set width and height to the full-size display, but on
|
||||
* Samsung DeX or Chromebooks or other windowed Android environments, our window may
|
||||
* still not be the full display size.
|
||||
*/
|
||||
if (!SDL_IsDeXMode() && !SDL_IsChromebook()) {
|
||||
goto endfunction;
|
||||
}
|
||||
old_w = window->w;
|
||||
old_h = window->h;
|
||||
|
||||
data = window->internal;
|
||||
if (!data || !data->native_window) {
|
||||
if (data && !data->native_window) {
|
||||
SDL_SetError("Missing native window");
|
||||
}
|
||||
goto endfunction;
|
||||
}
|
||||
new_w = ANativeWindow_getWidth(data->native_window);
|
||||
new_h = ANativeWindow_getHeight(data->native_window);
|
||||
|
||||
old_w = window->w;
|
||||
old_h = window->h;
|
||||
if (new_w < 0 || new_h < 0) {
|
||||
SDL_SetError("ANativeWindow_getWidth/Height() fails");
|
||||
}
|
||||
|
||||
new_w = ANativeWindow_getWidth(data->native_window);
|
||||
new_h = ANativeWindow_getHeight(data->native_window);
|
||||
|
||||
if (new_w < 0 || new_h < 0) {
|
||||
SDL_SetError("ANativeWindow_getWidth/Height() fails");
|
||||
}
|
||||
|
||||
if (old_w != new_w || old_h != new_h) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, new_w, new_h);
|
||||
}
|
||||
if (old_w != new_w || old_h != new_h) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, new_w, new_h);
|
||||
}
|
||||
|
||||
endfunction:
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
|
||||
return SDL_FULLSCREEN_SUCCEEDED;
|
||||
}
|
||||
|
||||
|
|
@ -176,29 +163,108 @@ void Android_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool
|
|||
|
||||
void Android_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
Android_LockActivityMutex();
|
||||
window_created = false;
|
||||
|
||||
if (window == Android_Window) {
|
||||
Android_Window = NULL;
|
||||
|
||||
if (window->internal) {
|
||||
SDL_WindowData *data = window->internal;
|
||||
if (window->internal) {
|
||||
Android_NativeSurfaceDestroyed(window);
|
||||
SDL_free(window->internal);
|
||||
window->internal = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
if (data->egl_surface != EGL_NO_SURFACE) {
|
||||
SDL_EGL_DestroySurface(_this, data->egl_surface);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data->native_window) {
|
||||
ANativeWindow_release(data->native_window);
|
||||
}
|
||||
SDL_free(window->internal);
|
||||
window->internal = NULL;
|
||||
// Those functions called from RPC onNativeSurface{Created,Changed,Destroyed}()
|
||||
// and SDL_{Create,Destroy}Window();
|
||||
|
||||
bool Android_NativeSurfaceCreated(SDL_Window *window)
|
||||
{
|
||||
if (window) {
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
data->native_window = Android_JNI_GetNativeWindow();
|
||||
SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, data->native_window);
|
||||
if (data->native_window == NULL) {
|
||||
SDL_SetError("Could not fetch native window");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Android_UnlockActivityMutex();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Resize surface
|
||||
void Android_NativeSurfaceResized(SDL_Window *window)
|
||||
{
|
||||
if (window) {
|
||||
SDL_WindowData *data = window->internal;
|
||||
if (data->native_window) {
|
||||
int format = 0;
|
||||
int new_w = ANativeWindow_getWidth(data->native_window);
|
||||
int new_h = ANativeWindow_getHeight(data->native_window);
|
||||
ANativeWindow_setBuffersGeometry(data->native_window, new_w, new_h, format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Android_NativeSurfaceChanged(SDL_Window *window)
|
||||
{
|
||||
if (window) {
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
/* Do not create EGLSurface for Vulkan window since it will then make the window
|
||||
incompatible with vkCreateAndroidSurfaceKHR */
|
||||
if (window->flags & SDL_WINDOW_OPENGL) {
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
// Make sure native_window is valid
|
||||
if (!data->native_window) {
|
||||
if (!Android_NativeSurfaceCreated(window)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the surface has been previously destroyed by onNativeSurfaceDestroyed
|
||||
// or if it is the first time, recreate it.
|
||||
if (data->egl_surface == EGL_NO_SURFACE) {
|
||||
data->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)data->native_window);
|
||||
SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_ANDROID_SURFACE_POINTER, data->egl_surface);
|
||||
}
|
||||
|
||||
if (data->egl_surface == EGL_NO_SURFACE) {
|
||||
if (data->native_window) {
|
||||
ANativeWindow_release(data->native_window);
|
||||
data->native_window = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Android_NativeSurfaceDestroyed(SDL_Window *window)
|
||||
{
|
||||
if (window) {
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
if (data->egl_surface != EGL_NO_SURFACE) {
|
||||
SDL_EGL_DestroySurface(SDL_GetVideoDevice(), data->egl_surface);
|
||||
data->egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data->native_window) {
|
||||
ANativeWindow_release(data->native_window);
|
||||
data->native_window = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_ANDROID
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ extern void Android_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
|||
extern void Android_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable);
|
||||
|
||||
extern void Android_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern SDL_Window *Android_Window;
|
||||
|
||||
struct SDL_WindowData
|
||||
{
|
||||
|
|
@ -48,4 +47,9 @@ struct SDL_WindowData
|
|||
|
||||
};
|
||||
|
||||
bool Android_NativeSurfaceCreated(SDL_Window *window);
|
||||
bool Android_NativeSurfaceChanged(SDL_Window *window);
|
||||
void Android_NativeSurfaceDestroyed(SDL_Window *window);
|
||||
void Android_NativeSurfaceResized(SDL_Window *window);
|
||||
|
||||
#endif // SDL_androidwindow_h_
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue