• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <cassert>
18 #include <dlfcn.h>
19 #include <time.h>
20 #include <android/log.h>
21 
22 #include "Helpers.h"
23 #include "Game.h"
24 #include "ShellAndroid.h"
25 
26 namespace {
27 
28 // copied from ShellXCB.cpp
29 class PosixTimer {
30 public:
PosixTimer()31     PosixTimer()
32     {
33         reset();
34     }
35 
reset()36     void reset()
37     {
38         clock_gettime(CLOCK_MONOTONIC, &start_);
39     }
40 
get() const41     double get() const
42     {
43         struct timespec now;
44         clock_gettime(CLOCK_MONOTONIC, &now);
45 
46         constexpr long one_s_in_ns = 1000 * 1000 * 1000;
47         constexpr double one_s_in_ns_d = static_cast<double>(one_s_in_ns);
48 
49         time_t s = now.tv_sec - start_.tv_sec;
50         long ns;
51         if (now.tv_nsec > start_.tv_nsec) {
52             ns = now.tv_nsec - start_.tv_nsec;
53         } else {
54             assert(s > 0);
55             s--;
56             ns = one_s_in_ns - (start_.tv_nsec - now.tv_nsec);
57         }
58 
59         return static_cast<double>(s) + static_cast<double>(ns) / one_s_in_ns_d;
60     }
61 
62 private:
63     struct timespec start_;
64 };
65 
66 } // namespace
67 
ShellAndroid(android_app & app,Game & game)68 ShellAndroid::ShellAndroid(android_app &app, Game &game) : Shell(game), app_(app)
69 {
70     instance_extensions_.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
71 
72     app_dummy();
73     app_.userData = this;
74     app_.onAppCmd = on_app_cmd;
75     app_.onInputEvent = on_input_event;
76 
77     init_vk();
78 }
79 
~ShellAndroid()80 ShellAndroid::~ShellAndroid()
81 {
82     cleanup_vk();
83     dlclose(lib_handle_);
84 }
85 
log(LogPriority priority,const char * msg)86 void ShellAndroid::log(LogPriority priority, const char *msg)
87 {
88     int prio;
89 
90     switch (priority) {
91     case LOG_DEBUG:
92         prio = ANDROID_LOG_DEBUG;
93         break;
94     case LOG_INFO:
95         prio = ANDROID_LOG_INFO;
96         break;
97     case LOG_WARN:
98         prio = ANDROID_LOG_WARN;
99         break;
100     case LOG_ERR:
101         prio = ANDROID_LOG_ERROR;
102         break;
103     default:
104         prio = ANDROID_LOG_UNKNOWN;
105         break;
106     }
107 
108     __android_log_write(prio, settings_.name.c_str(), msg);
109 }
110 
load_vk()111 PFN_vkGetInstanceProcAddr ShellAndroid::load_vk()
112 {
113     const char filename[] = "libvulkan.so";
114     void *handle = nullptr, *symbol = nullptr;
115 
116     handle = dlopen(filename, RTLD_LAZY);
117     if (handle)
118         symbol = dlsym(handle, "vkGetInstanceProcAddr");
119     if (!symbol) {
120         if (handle)
121             dlclose(handle);
122 
123         throw std::runtime_error(dlerror());
124     }
125 
126     lib_handle_ = handle;
127 
128     return reinterpret_cast<PFN_vkGetInstanceProcAddr>(symbol);
129 }
130 
create_surface(VkInstance instance)131 VkSurfaceKHR ShellAndroid::create_surface(VkInstance instance)
132 {
133     VkAndroidSurfaceCreateInfoKHR surface_info = {};
134     surface_info.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
135     surface_info.window = app_.window;
136 
137     VkSurfaceKHR surface;
138     vk::assert_success(vk::CreateAndroidSurfaceKHR(instance, &surface_info, nullptr, &surface));
139 
140     return surface;
141 }
142 
on_app_cmd(int32_t cmd)143 void ShellAndroid::on_app_cmd(int32_t cmd)
144 {
145     switch (cmd) {
146     case APP_CMD_INIT_WINDOW:
147         create_context();
148         resize_swapchain(0, 0);
149         break;
150     case APP_CMD_TERM_WINDOW:
151         destroy_context();
152         break;
153     case APP_CMD_WINDOW_RESIZED:
154         resize_swapchain(0, 0);
155         break;
156     case APP_CMD_STOP:
157         ANativeActivity_finish(app_.activity);
158         break;
159     default:
160         break;
161     }
162 }
163 
on_input_event(const AInputEvent * event)164 int32_t ShellAndroid::on_input_event(const AInputEvent *event)
165 {
166     if (AInputEvent_getType(event) != AINPUT_EVENT_TYPE_MOTION)
167         return false;
168 
169     bool handled = false;
170 
171     switch (AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK) {
172     case AMOTION_EVENT_ACTION_UP:
173         game_.on_key(Game::KEY_SPACE);
174         handled = true;
175         break;
176     default:
177         break;
178     }
179 
180     return handled;
181 }
182 
quit()183 void ShellAndroid::quit()
184 {
185     ANativeActivity_finish(app_.activity);
186 }
187 
run()188 void ShellAndroid::run()
189 {
190     PosixTimer timer;
191 
192     double current_time = timer.get();
193 
194     while (true) {
195         struct android_poll_source *source;
196         while (true) {
197             int timeout = (settings_.animate && app_.window) ? 0 : -1;
198             if (ALooper_pollAll(timeout, nullptr, nullptr,
199                     reinterpret_cast<void **>(&source)) < 0)
200                 break;
201 
202             if (source)
203                 source->process(&app_, source);
204         }
205 
206         if (app_.destroyRequested)
207             break;
208 
209         if (!app_.window)
210             continue;
211 
212         acquire_back_buffer();
213 
214         double t = timer.get();
215         add_game_time(static_cast<float>(t - current_time));
216 
217         present_back_buffer();
218 
219         current_time = t;
220     }
221 }
222