12f18b292ff155af7df35930474857b507dbf18feTony Barbour/*
22f18b292ff155af7df35930474857b507dbf18feTony Barbour * Copyright (C) 2016 Google, Inc.
32f18b292ff155af7df35930474857b507dbf18feTony Barbour *
443b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Licensed under the Apache License, Version 2.0 (the "License");
543b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * you may not use this file except in compliance with the License.
643b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * You may obtain a copy of the License at
72f18b292ff155af7df35930474857b507dbf18feTony Barbour *
843b53e83705f02245da6ae61e31273866a35b833Jon Ashburn *     http://www.apache.org/licenses/LICENSE-2.0
92f18b292ff155af7df35930474857b507dbf18feTony Barbour *
1043b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Unless required by applicable law or agreed to in writing, software
1143b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * distributed under the License is distributed on an "AS IS" BASIS,
1243b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1343b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * See the License for the specific language governing permissions and
1443b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * limitations under the License.
152f18b292ff155af7df35930474857b507dbf18feTony Barbour */
162f18b292ff155af7df35930474857b507dbf18feTony Barbour
172f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <cassert>
182f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <dlfcn.h>
192f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <time.h>
202f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <android/log.h>
212f18b292ff155af7df35930474857b507dbf18feTony Barbour
222f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Helpers.h"
232f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Game.h"
242f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "ShellAndroid.h"
252f18b292ff155af7df35930474857b507dbf18feTony Barbour
262f18b292ff155af7df35930474857b507dbf18feTony Barbournamespace {
272f18b292ff155af7df35930474857b507dbf18feTony Barbour
282f18b292ff155af7df35930474857b507dbf18feTony Barbour// copied from ShellXCB.cpp
292f18b292ff155af7df35930474857b507dbf18feTony Barbourclass PosixTimer {
302f18b292ff155af7df35930474857b507dbf18feTony Barbourpublic:
312f18b292ff155af7df35930474857b507dbf18feTony Barbour    PosixTimer()
322f18b292ff155af7df35930474857b507dbf18feTony Barbour    {
332f18b292ff155af7df35930474857b507dbf18feTony Barbour        reset();
342f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
352f18b292ff155af7df35930474857b507dbf18feTony Barbour
362f18b292ff155af7df35930474857b507dbf18feTony Barbour    void reset()
372f18b292ff155af7df35930474857b507dbf18feTony Barbour    {
382f18b292ff155af7df35930474857b507dbf18feTony Barbour        clock_gettime(CLOCK_MONOTONIC, &start_);
392f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
402f18b292ff155af7df35930474857b507dbf18feTony Barbour
412f18b292ff155af7df35930474857b507dbf18feTony Barbour    double get() const
422f18b292ff155af7df35930474857b507dbf18feTony Barbour    {
432f18b292ff155af7df35930474857b507dbf18feTony Barbour        struct timespec now;
442f18b292ff155af7df35930474857b507dbf18feTony Barbour        clock_gettime(CLOCK_MONOTONIC, &now);
452f18b292ff155af7df35930474857b507dbf18feTony Barbour
462f18b292ff155af7df35930474857b507dbf18feTony Barbour        constexpr long one_s_in_ns = 1000 * 1000 * 1000;
472f18b292ff155af7df35930474857b507dbf18feTony Barbour        constexpr double one_s_in_ns_d = static_cast<double>(one_s_in_ns);
482f18b292ff155af7df35930474857b507dbf18feTony Barbour
492f18b292ff155af7df35930474857b507dbf18feTony Barbour        time_t s = now.tv_sec - start_.tv_sec;
502f18b292ff155af7df35930474857b507dbf18feTony Barbour        long ns;
512f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (now.tv_nsec > start_.tv_nsec) {
522f18b292ff155af7df35930474857b507dbf18feTony Barbour            ns = now.tv_nsec - start_.tv_nsec;
532f18b292ff155af7df35930474857b507dbf18feTony Barbour        } else {
542f18b292ff155af7df35930474857b507dbf18feTony Barbour            assert(s > 0);
552f18b292ff155af7df35930474857b507dbf18feTony Barbour            s--;
562f18b292ff155af7df35930474857b507dbf18feTony Barbour            ns = one_s_in_ns - (start_.tv_nsec - now.tv_nsec);
572f18b292ff155af7df35930474857b507dbf18feTony Barbour        }
582f18b292ff155af7df35930474857b507dbf18feTony Barbour
592f18b292ff155af7df35930474857b507dbf18feTony Barbour        return static_cast<double>(s) + static_cast<double>(ns) / one_s_in_ns_d;
602f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
612f18b292ff155af7df35930474857b507dbf18feTony Barbour
622f18b292ff155af7df35930474857b507dbf18feTony Barbourprivate:
632f18b292ff155af7df35930474857b507dbf18feTony Barbour    struct timespec start_;
642f18b292ff155af7df35930474857b507dbf18feTony Barbour};
652f18b292ff155af7df35930474857b507dbf18feTony Barbour
662f18b292ff155af7df35930474857b507dbf18feTony Barbour} // namespace
672f18b292ff155af7df35930474857b507dbf18feTony Barbour
682f18b292ff155af7df35930474857b507dbf18feTony BarbourShellAndroid::ShellAndroid(android_app &app, Game &game) : Shell(game), app_(app)
692f18b292ff155af7df35930474857b507dbf18feTony Barbour{
702f18b292ff155af7df35930474857b507dbf18feTony Barbour    instance_extensions_.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
712f18b292ff155af7df35930474857b507dbf18feTony Barbour
722f18b292ff155af7df35930474857b507dbf18feTony Barbour    app_dummy();
732f18b292ff155af7df35930474857b507dbf18feTony Barbour    app_.userData = this;
742f18b292ff155af7df35930474857b507dbf18feTony Barbour    app_.onAppCmd = on_app_cmd;
752f18b292ff155af7df35930474857b507dbf18feTony Barbour    app_.onInputEvent = on_input_event;
762f18b292ff155af7df35930474857b507dbf18feTony Barbour
772f18b292ff155af7df35930474857b507dbf18feTony Barbour    init_vk();
782f18b292ff155af7df35930474857b507dbf18feTony Barbour}
792f18b292ff155af7df35930474857b507dbf18feTony Barbour
802f18b292ff155af7df35930474857b507dbf18feTony BarbourShellAndroid::~ShellAndroid()
812f18b292ff155af7df35930474857b507dbf18feTony Barbour{
822f18b292ff155af7df35930474857b507dbf18feTony Barbour    cleanup_vk();
832f18b292ff155af7df35930474857b507dbf18feTony Barbour    dlclose(lib_handle_);
842f18b292ff155af7df35930474857b507dbf18feTony Barbour}
852f18b292ff155af7df35930474857b507dbf18feTony Barbour
862f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid ShellAndroid::log(LogPriority priority, const char *msg)
872f18b292ff155af7df35930474857b507dbf18feTony Barbour{
882f18b292ff155af7df35930474857b507dbf18feTony Barbour    int prio;
892f18b292ff155af7df35930474857b507dbf18feTony Barbour
902f18b292ff155af7df35930474857b507dbf18feTony Barbour    switch (priority) {
912f18b292ff155af7df35930474857b507dbf18feTony Barbour    case LOG_DEBUG:
922f18b292ff155af7df35930474857b507dbf18feTony Barbour        prio = ANDROID_LOG_DEBUG;
932f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
942f18b292ff155af7df35930474857b507dbf18feTony Barbour    case LOG_INFO:
952f18b292ff155af7df35930474857b507dbf18feTony Barbour        prio = ANDROID_LOG_INFO;
962f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
972f18b292ff155af7df35930474857b507dbf18feTony Barbour    case LOG_WARN:
982f18b292ff155af7df35930474857b507dbf18feTony Barbour        prio = ANDROID_LOG_WARN;
992f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1002f18b292ff155af7df35930474857b507dbf18feTony Barbour    case LOG_ERR:
1012f18b292ff155af7df35930474857b507dbf18feTony Barbour        prio = ANDROID_LOG_ERROR;
1022f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1032f18b292ff155af7df35930474857b507dbf18feTony Barbour    default:
1042f18b292ff155af7df35930474857b507dbf18feTony Barbour        prio = ANDROID_LOG_UNKNOWN;
1052f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1062f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
1072f18b292ff155af7df35930474857b507dbf18feTony Barbour
1082f18b292ff155af7df35930474857b507dbf18feTony Barbour    __android_log_write(prio, settings_.name.c_str(), msg);
1092f18b292ff155af7df35930474857b507dbf18feTony Barbour}
1102f18b292ff155af7df35930474857b507dbf18feTony Barbour
1112f18b292ff155af7df35930474857b507dbf18feTony BarbourPFN_vkGetInstanceProcAddr ShellAndroid::load_vk()
1122f18b292ff155af7df35930474857b507dbf18feTony Barbour{
1132f18b292ff155af7df35930474857b507dbf18feTony Barbour    const char filename[] = "libvulkan.so";
1142f18b292ff155af7df35930474857b507dbf18feTony Barbour    void *handle = nullptr, *symbol = nullptr;
1152f18b292ff155af7df35930474857b507dbf18feTony Barbour
1162f18b292ff155af7df35930474857b507dbf18feTony Barbour    handle = dlopen(filename, RTLD_LAZY);
1172f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (handle)
1182f18b292ff155af7df35930474857b507dbf18feTony Barbour        symbol = dlsym(handle, "vkGetInstanceProcAddr");
1192f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (!symbol) {
1202f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (handle)
1212f18b292ff155af7df35930474857b507dbf18feTony Barbour            dlclose(handle);
1222f18b292ff155af7df35930474857b507dbf18feTony Barbour
1232f18b292ff155af7df35930474857b507dbf18feTony Barbour        throw std::runtime_error(dlerror());
1242f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
1252f18b292ff155af7df35930474857b507dbf18feTony Barbour
1262f18b292ff155af7df35930474857b507dbf18feTony Barbour    lib_handle_ = handle;
1272f18b292ff155af7df35930474857b507dbf18feTony Barbour
1282f18b292ff155af7df35930474857b507dbf18feTony Barbour    return reinterpret_cast<PFN_vkGetInstanceProcAddr>(symbol);
1292f18b292ff155af7df35930474857b507dbf18feTony Barbour}
1302f18b292ff155af7df35930474857b507dbf18feTony Barbour
1312f18b292ff155af7df35930474857b507dbf18feTony BarbourVkSurfaceKHR ShellAndroid::create_surface(VkInstance instance)
1322f18b292ff155af7df35930474857b507dbf18feTony Barbour{
1332f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkAndroidSurfaceCreateInfoKHR surface_info = {};
1342f18b292ff155af7df35930474857b507dbf18feTony Barbour    surface_info.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
1352f18b292ff155af7df35930474857b507dbf18feTony Barbour    surface_info.window = app_.window;
1362f18b292ff155af7df35930474857b507dbf18feTony Barbour
1372f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkSurfaceKHR surface;
1382f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::CreateAndroidSurfaceKHR(instance, &surface_info, nullptr, &surface));
1392f18b292ff155af7df35930474857b507dbf18feTony Barbour
1402f18b292ff155af7df35930474857b507dbf18feTony Barbour    return surface;
1412f18b292ff155af7df35930474857b507dbf18feTony Barbour}
1422f18b292ff155af7df35930474857b507dbf18feTony Barbour
1432f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid ShellAndroid::on_app_cmd(int32_t cmd)
1442f18b292ff155af7df35930474857b507dbf18feTony Barbour{
1452f18b292ff155af7df35930474857b507dbf18feTony Barbour    switch (cmd) {
1462f18b292ff155af7df35930474857b507dbf18feTony Barbour    case APP_CMD_INIT_WINDOW:
1472f18b292ff155af7df35930474857b507dbf18feTony Barbour        create_context();
1482f18b292ff155af7df35930474857b507dbf18feTony Barbour        resize_swapchain(0, 0);
1492f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1502f18b292ff155af7df35930474857b507dbf18feTony Barbour    case APP_CMD_TERM_WINDOW:
1512f18b292ff155af7df35930474857b507dbf18feTony Barbour        destroy_context();
1522f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1532f18b292ff155af7df35930474857b507dbf18feTony Barbour    case APP_CMD_WINDOW_RESIZED:
1542f18b292ff155af7df35930474857b507dbf18feTony Barbour        resize_swapchain(0, 0);
1552f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1562f18b292ff155af7df35930474857b507dbf18feTony Barbour    case APP_CMD_STOP:
1572f18b292ff155af7df35930474857b507dbf18feTony Barbour        ANativeActivity_finish(app_.activity);
1582f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1592f18b292ff155af7df35930474857b507dbf18feTony Barbour    default:
1602f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1612f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
1622f18b292ff155af7df35930474857b507dbf18feTony Barbour}
1632f18b292ff155af7df35930474857b507dbf18feTony Barbour
1642f18b292ff155af7df35930474857b507dbf18feTony Barbourint32_t ShellAndroid::on_input_event(const AInputEvent *event)
1652f18b292ff155af7df35930474857b507dbf18feTony Barbour{
1662f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (AInputEvent_getType(event) != AINPUT_EVENT_TYPE_MOTION)
1672f18b292ff155af7df35930474857b507dbf18feTony Barbour        return false;
1682f18b292ff155af7df35930474857b507dbf18feTony Barbour
1692f18b292ff155af7df35930474857b507dbf18feTony Barbour    bool handled = false;
1702f18b292ff155af7df35930474857b507dbf18feTony Barbour
1712f18b292ff155af7df35930474857b507dbf18feTony Barbour    switch (AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK) {
1722f18b292ff155af7df35930474857b507dbf18feTony Barbour    case AMOTION_EVENT_ACTION_UP:
1732f18b292ff155af7df35930474857b507dbf18feTony Barbour        game_.on_key(Game::KEY_SPACE);
1742f18b292ff155af7df35930474857b507dbf18feTony Barbour        handled = true;
1752f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1762f18b292ff155af7df35930474857b507dbf18feTony Barbour    default:
1772f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
1782f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
1792f18b292ff155af7df35930474857b507dbf18feTony Barbour
1802f18b292ff155af7df35930474857b507dbf18feTony Barbour    return handled;
1812f18b292ff155af7df35930474857b507dbf18feTony Barbour}
1822f18b292ff155af7df35930474857b507dbf18feTony Barbour
1832f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid ShellAndroid::quit()
1842f18b292ff155af7df35930474857b507dbf18feTony Barbour{
1852f18b292ff155af7df35930474857b507dbf18feTony Barbour    ANativeActivity_finish(app_.activity);
1862f18b292ff155af7df35930474857b507dbf18feTony Barbour}
1872f18b292ff155af7df35930474857b507dbf18feTony Barbour
1882f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid ShellAndroid::run()
1892f18b292ff155af7df35930474857b507dbf18feTony Barbour{
1902f18b292ff155af7df35930474857b507dbf18feTony Barbour    PosixTimer timer;
1912f18b292ff155af7df35930474857b507dbf18feTony Barbour
1922f18b292ff155af7df35930474857b507dbf18feTony Barbour    double current_time = timer.get();
1932f18b292ff155af7df35930474857b507dbf18feTony Barbour
1942f18b292ff155af7df35930474857b507dbf18feTony Barbour    while (true) {
1952f18b292ff155af7df35930474857b507dbf18feTony Barbour        struct android_poll_source *source;
1962f18b292ff155af7df35930474857b507dbf18feTony Barbour        while (true) {
1972f18b292ff155af7df35930474857b507dbf18feTony Barbour            int timeout = (settings_.animate && app_.window) ? 0 : -1;
1982f18b292ff155af7df35930474857b507dbf18feTony Barbour            if (ALooper_pollAll(timeout, nullptr, nullptr,
1992f18b292ff155af7df35930474857b507dbf18feTony Barbour                    reinterpret_cast<void **>(&source)) < 0)
2002f18b292ff155af7df35930474857b507dbf18feTony Barbour                break;
2012f18b292ff155af7df35930474857b507dbf18feTony Barbour
2022f18b292ff155af7df35930474857b507dbf18feTony Barbour            if (source)
2032f18b292ff155af7df35930474857b507dbf18feTony Barbour                source->process(&app_, source);
2042f18b292ff155af7df35930474857b507dbf18feTony Barbour        }
2052f18b292ff155af7df35930474857b507dbf18feTony Barbour
2062f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (app_.destroyRequested)
2072f18b292ff155af7df35930474857b507dbf18feTony Barbour            break;
2082f18b292ff155af7df35930474857b507dbf18feTony Barbour
2092f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (!app_.window)
2102f18b292ff155af7df35930474857b507dbf18feTony Barbour            continue;
2112f18b292ff155af7df35930474857b507dbf18feTony Barbour
2122f18b292ff155af7df35930474857b507dbf18feTony Barbour        acquire_back_buffer();
2132f18b292ff155af7df35930474857b507dbf18feTony Barbour
2142f18b292ff155af7df35930474857b507dbf18feTony Barbour        double t = timer.get();
2152f18b292ff155af7df35930474857b507dbf18feTony Barbour        add_game_time(static_cast<float>(t - current_time));
2162f18b292ff155af7df35930474857b507dbf18feTony Barbour
2172f18b292ff155af7df35930474857b507dbf18feTony Barbour        present_back_buffer();
2182f18b292ff155af7df35930474857b507dbf18feTony Barbour
2192f18b292ff155af7df35930474857b507dbf18feTony Barbour        current_time = t;
2202f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
2212f18b292ff155af7df35930474857b507dbf18feTony Barbour}
222