Conversation
Try
left a comment
There was a problem hiding this comment.
Commented general stuff for now. Probably we would also need to refactor window initialization a bit
| void AndroidApi::implSetWindowTitle(SystemApi::Window*, const char*) { | ||
| } | ||
|
|
||
| int main(int argc, const char** argv); |
There was a problem hiding this comment.
You dont need to relay on static linking here.
dlopen(nullptr) + dlsym(..., "main") will get you function pointer to the main. And you allowed to always assume int(int, char** signature, since it's c-call.
There was a problem hiding this comment.
Removed the static main declaration and switched to dlsym. On Android 16, dlopen(nullptr) cannot see the locally loaded NativeActivity library, so this locates the library containing android_main with dladdr and opens that before resolving main.
|
|
||
| SystemApi::Window* createAndroidWindow(Tempest::Window* owner) { | ||
| if(mainWindow==nullptr) | ||
| mainWindow = new AndroidWindow(); |
There was a problem hiding this comment.
SystemApi::Window* is expected to be something usable directly to swapchain. Similar to HWND on windows.
In case if android that would be ANativeWindow*.
There was a problem hiding this comment.
Removed the wrapper. SystemApi::Window* is currently the ANativeWindow* itself. Replacing that pointer on surface recreation conflicts with the persistent Window::id contract, so that part remains unresolved in the later discussion: #108 (comment)
| int AndroidApi::implExec(AppCallBack& cb) { | ||
| running = true; | ||
| while(running) { | ||
| pollAndroid(active && hasWindow ? 0 : -1); |
There was a problem hiding this comment.
pollAndroid is already part of implProcessEvents
There was a problem hiding this comment.
Removed the duplicate polling from implExec. implProcessEvents owns normal event-loop polling. Initial window creation and activity shutdown also pump native events while waiting. In Solessfir@82fd004, an overlapping replacement activity pumps its own callbacks while waiting for the previous native session to finish, so Android's UI thread is not blocked.
|
|
||
| class AndroidApi final : SystemApi { | ||
| public: | ||
| using SystemApi::dispatchClose; |
There was a problem hiding this comment.
Should not be public.
I've noticed, that you are using it from free-standing function onAppCmd. You can move onAppCmd -> AndroidApi::onAppCmd(void*, int32_t) instead. Similar to how windowProc is implemented, on windows.
There was a problem hiding this comment.
Moved onAppCmd, focus and resize handling into private AndroidApi methods and removed the public dispatch aliases. A typed lambda bridges the native-app-glue callback to onAppCmd(void*, int32_t).
| return; | ||
|
|
||
| auto window = reinterpret_cast<SystemApi::Window*>(app->window); | ||
| AndroidApi::setWindowHandle(*mainWindow,window); |
There was a problem hiding this comment.
Window::id is expected to be persistent, and hot swapping should not be used.
I know, that this is general android issue, but engine has to have clean workaround and emulate same windowing as on any other platform.
I think, one option can be to spin-loop events in createAndroidWindow, unit APP_CMD_INIT_WINDOW or APP_CMD_DESTROY is met. APP_CMD_INIT_WINDOW = window created, all good. APP_CMD_DESTROY - exiting while creating window - return null (will be propagated to exception).
Correct me, if I'm wrong, but if AndroidManifest.xml (or activity) configured right way, then android wont sporadically kill the window, until the exit?
There was a problem hiding this comment.
Moved the initial wait into createAndroidWindow.
Android can still destroy and recreate the drawing surface when switching apps. Could we keep a stable Tempest window handle and replace only the ANativeWindow stored inside it?
Vulkan would handle the surface change internally, so Window::id stays unchanged.
| } | ||
| } | ||
|
|
||
| void pollAndroid(int timeout) { |
There was a problem hiding this comment.
no need to use namespace. For helper functions static is enough. static will hide your functions from linker.
There was a problem hiding this comment.
Removed the anonymous namespace and made the file-local functions and state static.
| } | ||
|
|
||
| SystemApi::Window* createAndroidWindow(Tempest::Window* owner) { | ||
| mainWindow = owner; |
There was a problem hiding this comment.
It looks like a general contract: only one window allowed at a time, on android. In this case, it's right to return null, if mainWindow is already initialized.
There was a problem hiding this comment.
Added the guard: attempting to create a second window returns nullptr without changing the existing owner.
| } | ||
|
|
||
| int AndroidApi::implExec(AppCallBack& cb) { | ||
| running.store(true); |
There was a problem hiding this comment.
nit:
int WindowsApi::implExec(AppCallBack& cb) {
// main message loop
while (!isExit.load()) {
implProcessEvents(cb);
}
return 0;
}
Swap running -> isExit would be nice for consistency.
Timers can be handled inside implProcessEvents
There was a problem hiding this comment.
Changed running to atomic isExit and moved timer handling into implProcessEvents. Exit also wakes the looper, and event processing checks the exit flag before rendering or running timers.
|
|
||
| Dl_info module = {}; | ||
| void* self = nullptr; | ||
| if(dladdr(reinterpret_cast<void*>(&android_main),&module)!=0) |
There was a problem hiding this comment.
probably this can be refactored away into separated function, and rewritten more clean with fail-fast approach (instead if multiple if-else)
There was a problem hiding this comment.
Extracted entry-point lookup and invocation into runMain with early returns. android_main now handles exceptions and activity shutdown.
Adds the first Android runtime layer on top of the existing APK packaging helper.
Changes:
Vulkan surfaces, input, audio and other platform services are intentionally left for separate PRs.
Validated with: