From ac219fa09c976ff3825092dbbc0f4eacaba292bc Mon Sep 17 00:00:00 2001 From: mgood7123 Date: Mon, 28 Jun 2021 14:51:30 +1000 Subject: [PATCH] fixes edge cases in Android Native App rendering Squashed commit of the following: commit ba7271fd340f4eeab9363a3518fd973bc24d48ab Author: mgood7123 Date: Sat Jul 3 03:12:45 2021 +1000 use std::atomic instead of std::mutex commit 54e39737c941d8f1c773bb3a46cd80b33b54b960 Author: mgood7123 Date: Tue Jun 29 07:52:35 2021 +1000 fixes edge cases in Android Native App rendering Revert "fix possible rendering edge cases" This reverts commit 3d76fb8687d180027f6ab6daf8042cfc0783f864. fix possible rendering edge cases Update AndroidMain.cpp add functions for app status apply validator suggestions Update AndroidAppBase.hpp Update AndroidAppBase.cpp remove unused variables --- NativeApp/include/Android/AndroidAppBase.hpp | 32 +++- NativeApp/src/Android/AndroidAppBase.cpp | 164 +++++++++++++++---- NativeApp/src/Android/AndroidMain.cpp | 3 + 3 files changed, 163 insertions(+), 36 deletions(-) diff --git a/NativeApp/include/Android/AndroidAppBase.hpp b/NativeApp/include/Android/AndroidAppBase.hpp index 79c5c3e5..000546da 100644 --- a/NativeApp/include/Android/AndroidAppBase.hpp +++ b/NativeApp/include/Android/AndroidAppBase.hpp @@ -26,8 +26,10 @@ #pragma once #include +#include #include +#include "FlagEnum.h" #include "AppBase.hpp" #include "NDKHelper.h" @@ -52,6 +54,31 @@ class AndroidAppBase : public AppBase static int32_t HandleInput(android_app* app, AInputEvent* event); static void HandleCmd(android_app* app, int32_t cmd); + // Android lifecycle status flags. Not app-specific + enum APP_STATUS_FLAGS + { + APP_STATUS_FLAG_NONE = 0x00000000, + + // Set between onCreate and onDestroy + APP_STATUS_FLAG_RUNNING = 0x00000001, + + // Set between onResume and onPause + APP_STATUS_FLAG_ACTIVE = 0x00000002, + + // Set between onWindowFocusChanged(true) and (false) + APP_STATUS_FLAG_FOCUSED = 0x00000004, + + // Set when the app's SurfaceHolder points to a + // valid, nonzero-sized surface + APP_STATUS_FLAG_HAS_REAL_SURFACE = 0x00000008 + }; + + APP_STATUS_FLAGS GetAppStatus(); + void AddAppStatusFlag(APP_STATUS_FLAGS Flag); + void RemoveAppStatusFlag(APP_STATUS_FLAGS Flag); + bool ValueHasAppStatusFlag(APP_STATUS_FLAGS Value, APP_STATUS_FLAGS Flag); + bool HasAppStatusFlag(APP_STATUS_FLAGS Flag); + protected: virtual void Initialize() { @@ -89,11 +116,14 @@ class AndroidAppBase : public AppBase void UpdateFPS(float fFPS); bool initialized_resources_ = false; - bool has_focus_ = false; + + std::atomic app_status_{APP_STATUS_FLAG_NONE}; ASensorManager* sensor_manager_ = nullptr; const ASensor* accelerometer_sensor_ = nullptr; ASensorEventQueue* sensor_event_queue_ = nullptr; }; +DEFINE_FLAG_ENUM_OPERATORS(AndroidAppBase::APP_STATUS_FLAGS) + } // namespace Diligent diff --git a/NativeApp/src/Android/AndroidAppBase.cpp b/NativeApp/src/Android/AndroidAppBase.cpp index 5091b832..107896d0 100644 --- a/NativeApp/src/Android/AndroidAppBase.cpp +++ b/NativeApp/src/Android/AndroidAppBase.cpp @@ -24,6 +24,7 @@ */ #include "AndroidAppBase.hpp" +#include "Errors.hpp" #include "Timer.hpp" #include @@ -118,22 +119,44 @@ void AndroidAppBase::HandleCmd(struct android_app* app, int32_t cmd) AndroidAppBase* eng = (AndroidAppBase*)app->userData; switch (cmd) { - case APP_CMD_SAVE_STATE: - break; - case APP_CMD_INIT_WINDOW: - // The window is being shown, get it ready. - if (app->window != NULL) + LOG_INFO_MESSAGE("APP_CMD_INIT_WINDOW"); + app->window = app->pendingWindow; + if (app->window && + ANativeWindow_getWidth(app->window) && + ANativeWindow_getHeight(app->window)) { + LOG_INFO_MESSAGE("INIT DISPLAY - HAS SURFACE"); eng->InitDisplay(); eng->DrawFrame(); + eng->AddAppStatusFlag(APP_STATUS_FLAG_HAS_REAL_SURFACE); + } + else + { + LOG_INFO_MESSAGE("NO SURFACE"); + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_HAS_REAL_SURFACE); } break; - case APP_CMD_CONFIG_CHANGED: + case APP_CMD_TERM_WINDOW: + LOG_INFO_MESSAGE("APP_CMD_TERM_WINDOW - LOST SURFACE - TERM DISPLAY"); + { + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_HAS_REAL_SURFACE); + } + eng->TermDisplay(); + break; + + // Note that as of NDK r21b (21.1.6352462), APP_CMD_CONTENT_RECT_CHANGED event is never + // generated by android_native_app_glue + case APP_CMD_CONTENT_RECT_CHANGED: { - // This callback is not reliable for handling orientation changes. Depending on the - // device, it may be called before or after the surface has been actually resized. + LOG_INFO_MESSAGE("APP_CMD_CONTENT_RECT_CHANGED"); + + int32_t new_window_width = + app->contentRect.right - app->contentRect.left; + int32_t new_window_height = + app->contentRect.bottom - app->contentRect.top; + eng->WindowResize(new_window_width, new_window_height); break; } @@ -144,45 +167,82 @@ void AndroidAppBase::HandleCmd(struct android_app* app, int32_t cmd) // does not work either - the callback is only called once after the window has been created. case APP_CMD_WINDOW_RESIZED: { - auto new_window_width = ANativeWindow_getWidth(app->window); - auto new_window_height = ANativeWindow_getHeight(app->window); - eng->WindowResize(new_window_width, new_window_height); + LOG_INFO_MESSAGE("APP_CMD_WINDOW_RESIZED"); + if (app->window) + { + int32_t new_window_width = ANativeWindow_getWidth(app->window); + int32_t new_window_height = ANativeWindow_getHeight(app->window); + if (new_window_width && new_window_height) + { + eng->WindowResize(new_window_width, new_window_height); + } + } break; } - // Note that as of NDK r21b (21.1.6352462), APP_CMD_CONTENT_RECT_CHANGED event is never - // generated by android_native_app_glue - case APP_CMD_CONTENT_RECT_CHANGED: - { - auto new_window_width = app->contentRect.right - app->contentRect.left; - auto new_window_height = app->contentRect.bottom - app->contentRect.top; - eng->WindowResize(new_window_width, new_window_height); + case APP_CMD_GAINED_FOCUS: + LOG_INFO_MESSAGE("APP_CMD_GAINED_FOCUS - HAS FOCUS"); + { + eng->AddAppStatusFlag(APP_STATUS_FLAG_FOCUSED); + } + eng->ResumeSensors(); + break; + + case APP_CMD_LOST_FOCUS: + LOG_INFO_MESSAGE("APP_CMD_LOST_FOCUS - LOST FOCUS"); + { + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_FOCUSED); + } + eng->SuspendSensors(); + break; + + case APP_CMD_RESUME: + LOG_INFO_MESSAGE("APP_CMD_RESUME - IS ACTIVE"); + { + eng->AddAppStatusFlag(APP_STATUS_FLAG_ACTIVE); + } + break; + + case APP_CMD_START: + LOG_INFO_MESSAGE("APP_CMD_START"); break; - } - case APP_CMD_TERM_WINDOW: case APP_CMD_PAUSE: - // The window is being hidden or closed, clean it up. - eng->TermDisplay(); - eng->has_focus_ = false; + LOG_INFO_MESSAGE("APP_CMD_PAUSE - IS NOT ACTIVE"); + { + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_ACTIVE); + } break; case APP_CMD_STOP: + LOG_INFO_MESSAGE("APP_CMD_STOP"); break; - case APP_CMD_GAINED_FOCUS: - eng->ResumeSensors(); - //Start animation - eng->has_focus_ = true; + case APP_CMD_CONFIG_CHANGED: + LOG_INFO_MESSAGE("APP_CMD_CONFIG_CHANGED"); + // AConfiguration_fromAssetManager(app->config, app->activity->assetManager); + // This callback is not reliable for handling orientation changes. Depending on the + // device, it may be called before or after the surface has been actually resized. break; - case APP_CMD_LOST_FOCUS: - eng->SuspendSensors(); - // Also stop animating. - eng->has_focus_ = false; + case APP_CMD_DESTROY: + LOG_INFO_MESSAGE("APP_CMD_DESTROY - IS NOT RUNNING"); + { + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_RUNNING); + } + break; + + case APP_CMD_WINDOW_REDRAW_NEEDED: + LOG_INFO_MESSAGE("APP_CMD_WINDOW_REDRAW_NEEDED"); + if (eng->IsReady()) eng->DrawFrame(); + break; + + case APP_CMD_SAVE_STATE: + LOG_INFO_MESSAGE("APP_CMD_SAVE_STATE"); break; case APP_CMD_LOW_MEMORY: + LOG_INFO_MESSAGE("APP_CMD_LOW_MEMORY"); //Free up GL resources eng->TrimMemory(); break; @@ -244,10 +304,11 @@ void AndroidAppBase::SetState(android_app* state, const char* native_activity_cl bool AndroidAppBase::IsReady() { - if (has_focus_) - return true; - - return false; + APP_STATUS_FLAGS app_status = GetAppStatus(); + return ValueHasAppStatusFlag(app_status, APP_STATUS_FLAG_RUNNING) && + ValueHasAppStatusFlag(app_status, APP_STATUS_FLAG_ACTIVE) && + ValueHasAppStatusFlag(app_status, APP_STATUS_FLAG_FOCUSED) && + ValueHasAppStatusFlag(app_status, APP_STATUS_FLAG_HAS_REAL_SURFACE); } //void Engine::TransformPosition( ndk_helper::Vec2& vec ) @@ -285,4 +346,37 @@ void AndroidAppBase::UpdateFPS(float fFPS) return; } +AndroidAppBase::APP_STATUS_FLAGS AndroidAppBase::GetAppStatus() +{ + return app_status_.load(); +} + +void AndroidAppBase::AddAppStatusFlag(AndroidAppBase::APP_STATUS_FLAGS Flag) +{ + auto LastStoredValue = app_status_.load(); + while (!app_status_.compare_exchange_weak(LastStoredValue, static_cast(LastStoredValue | Flag))) + { + // If exchange fails, LastStoredValue will hold the actual value of app_status_. + } +} + +void AndroidAppBase::RemoveAppStatusFlag(AndroidAppBase::APP_STATUS_FLAGS Flag) +{ + auto LastStoredValue = app_status_.load(); + while (!app_status_.compare_exchange_weak(LastStoredValue, static_cast(LastStoredValue & ~Flag))) + { + // If exchange fails, LastStoredValue will hold the actual value of app_status_. + } +} + +bool AndroidAppBase::ValueHasAppStatusFlag(AndroidAppBase::APP_STATUS_FLAGS Value, AndroidAppBase::APP_STATUS_FLAGS Flag) +{ + return (Value & Flag) != APP_STATUS_FLAG_NONE; +} + +bool AndroidAppBase::HasAppStatusFlag(AndroidAppBase::APP_STATUS_FLAGS Flag) +{ + return ValueHasAppStatusFlag(app_status_.load(), Flag); +} + } // namespace Diligent diff --git a/NativeApp/src/Android/AndroidMain.cpp b/NativeApp/src/Android/AndroidMain.cpp index 5186c8d2..b7ded455 100644 --- a/NativeApp/src/Android/AndroidMain.cpp +++ b/NativeApp/src/Android/AndroidMain.cpp @@ -42,6 +42,9 @@ using namespace Diligent; void android_main(android_app* state) { std::unique_ptr theApp(CreateApplication()); + + theApp->AddAppStatusFlag(AndroidAppBase::APP_STATUS_FLAG_RUNNING); + theApp->SetState(state, NATIVEACTIVITY_CLASS_NAME); //Init helper functions