1 // Copyright 2003 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include <EGL/egl.h>
6 #include <UICommon/GameFile.h>
7 #include <android/log.h>
8 #include <android/native_window_jni.h>
9 #include <cinttypes>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <jni.h>
13 #include <memory>
14 #include <mutex>
15 #include <optional>
16 #include <string>
17 #include <thread>
18 #include <utility>
19
20 #include "Common/AndroidAnalytics.h"
21 #include "Common/Assert.h"
22 #include "Common/CPUDetect.h"
23 #include "Common/CommonPaths.h"
24 #include "Common/CommonTypes.h"
25 #include "Common/Event.h"
26 #include "Common/FileUtil.h"
27 #include "Common/IniFile.h"
28 #include "Common/Logging/LogManager.h"
29 #include "Common/MsgHandler.h"
30 #include "Common/ScopeGuard.h"
31 #include "Common/Version.h"
32 #include "Common/WindowSystemInfo.h"
33
34 #include "Core/Analytics.h"
35 #include "Core/Boot/Boot.h"
36 #include "Core/BootManager.h"
37 #include "Core/ConfigLoaders/GameConfigLoader.h"
38 #include "Core/ConfigManager.h"
39 #include "Core/Core.h"
40 #include "Core/HW/DVD/DVDInterface.h"
41 #include "Core/HW/Wiimote.h"
42 #include "Core/HW/WiimoteReal/WiimoteReal.h"
43 #include "Core/Host.h"
44 #include "Core/PowerPC/JitInterface.h"
45 #include "Core/PowerPC/PowerPC.h"
46 #include "Core/PowerPC/Profiler.h"
47 #include "Core/State.h"
48 #include "Core/WiiUtils.h"
49
50 #include "DiscIO/Blob.h"
51 #include "DiscIO/Enums.h"
52 #include "DiscIO/ScrubbedBlob.h"
53 #include "DiscIO/Volume.h"
54
55 #include "InputCommon/ControllerInterface/Android/Android.h"
56 #include "InputCommon/ControllerInterface/Touch/ButtonManager.h"
57 #include "InputCommon/GCAdapter.h"
58
59 #include "UICommon/UICommon.h"
60
61 #include "VideoCommon/OnScreenDisplay.h"
62 #include "VideoCommon/RenderBase.h"
63 #include "VideoCommon/VideoBackendBase.h"
64
65 #include "../../Core/Common/WindowSystemInfo.h"
66 #include "jni/AndroidCommon/AndroidCommon.h"
67 #include "jni/AndroidCommon/IDCache.h"
68
69 namespace
70 {
71 constexpr char DOLPHIN_TAG[] = "DolphinEmuNative";
72
73 ANativeWindow* s_surf;
74 IniFile s_ini;
75
76 // The Core only supports using a single Host thread.
77 // If multiple threads want to call host functions then they need to queue
78 // sequentially for access.
79 std::mutex s_host_identity_lock;
80 Common::Event s_update_main_frame_event;
81 Common::Event s_emulation_end_event;
82 bool s_have_wm_user_stop = false;
83 } // Anonymous namespace
84
UpdatePointer()85 void UpdatePointer()
86 {
87 // Update touch pointer
88 JNIEnv* env = IDCache::GetEnvForThread();
89 env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetUpdateTouchPointer());
90 }
91
Host_NotifyMapLoaded()92 void Host_NotifyMapLoaded()
93 {
94 }
Host_RefreshDSPDebuggerWindow()95 void Host_RefreshDSPDebuggerWindow()
96 {
97 }
Host_UIBlocksControllerState()98 bool Host_UIBlocksControllerState()
99 {
100 return false;
101 }
102
Host_Message(HostMessageID id)103 void Host_Message(HostMessageID id)
104 {
105 if (id == HostMessageID::WMUserJobDispatch)
106 {
107 s_update_main_frame_event.Set();
108 }
109 else if (id == HostMessageID::WMUserStop)
110 {
111 s_have_wm_user_stop = true;
112 if (Core::IsRunning())
113 Core::QueueHostJob(&Core::Stop);
114 }
115 }
116
Host_UpdateTitle(const std::string & title)117 void Host_UpdateTitle(const std::string& title)
118 {
119 __android_log_write(ANDROID_LOG_INFO, DOLPHIN_TAG, title.c_str());
120 }
121
Host_UpdateDisasmDialog()122 void Host_UpdateDisasmDialog()
123 {
124 }
125
Host_UpdateMainFrame()126 void Host_UpdateMainFrame()
127 {
128 }
129
Host_RequestRenderWindowSize(int width,int height)130 void Host_RequestRenderWindowSize(int width, int height)
131 {
132 std::thread jnicall(UpdatePointer);
133 jnicall.join();
134 }
135
Host_RendererHasFocus()136 bool Host_RendererHasFocus()
137 {
138 return true;
139 }
140
Host_RendererIsFullscreen()141 bool Host_RendererIsFullscreen()
142 {
143 return false;
144 }
145
Host_YieldToUI()146 void Host_YieldToUI()
147 {
148 }
149
Host_TitleChanged()150 void Host_TitleChanged()
151 {
152 }
153
MsgAlert(const char * caption,const char * text,bool yes_no,Common::MsgType)154 static bool MsgAlert(const char* caption, const char* text, bool yes_no, Common::MsgType /*style*/)
155 {
156 JNIEnv* env = IDCache::GetEnvForThread();
157
158 // Execute the Java method.
159 jboolean result = env->CallStaticBooleanMethod(
160 IDCache::GetNativeLibraryClass(), IDCache::GetDisplayAlertMsg(), ToJString(env, caption),
161 ToJString(env, text), yes_no ? JNI_TRUE : JNI_FALSE);
162
163 return result != JNI_FALSE;
164 }
165
ReportSend(const std::string & endpoint,const std::string & report)166 static void ReportSend(const std::string& endpoint, const std::string& report)
167 {
168 JNIEnv* env = IDCache::GetEnvForThread();
169
170 jbyteArray output_array = env->NewByteArray(report.size());
171 jbyte* output = env->GetByteArrayElements(output_array, nullptr);
172 memcpy(output, report.data(), report.size());
173 env->ReleaseByteArrayElements(output_array, output, 0);
174 env->CallStaticVoidMethod(IDCache::GetAnalyticsClass(), IDCache::GetSendAnalyticsReport(),
175 ToJString(env, endpoint), output_array);
176 }
177
GetAnalyticValue(const std::string & key)178 static std::string GetAnalyticValue(const std::string& key)
179 {
180 JNIEnv* env = IDCache::GetEnvForThread();
181
182 auto value = reinterpret_cast<jstring>(env->CallStaticObjectMethod(
183 IDCache::GetAnalyticsClass(), IDCache::GetAnalyticsValue(), ToJString(env, key)));
184
185 std::string stdvalue = GetJString(env, value);
186
187 return stdvalue;
188 }
189
190 #ifdef __cplusplus
191 extern "C" {
192 #endif
193
194 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv* env,
195 jobject obj);
196 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv* env,
197 jobject obj);
198 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env,
199 jobject obj);
200 JNIEXPORT void JNICALL
201 Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv* env, jobject obj);
202 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv* env,
203 jobject obj);
204 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(
205 JNIEnv* env, jobject obj, jstring jDevice, jint Button, jint Action);
206 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent(
207 JNIEnv* env, jobject obj, jstring jDevice, jint Axis, jfloat Value);
208 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetMotionSensorsEnabled(
209 JNIEnv* env, jobject obj, jboolean accelerometer_enabled, jboolean gyroscope_enabled);
210 JNIEXPORT double JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetInputRadiusAtAngle(
211 JNIEnv* env, jobject obj, int emu_pad_id, int stick, double angle);
212 JNIEXPORT jstring JNICALL
213 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env, jobject obj);
214 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGitRevision(JNIEnv* env,
215 jobject obj);
216 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env,
217 jobject obj);
218 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv* env,
219 jobject obj,
220 jint api);
221 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetFilename(JNIEnv* env,
222 jobject obj,
223 jstring jFile);
224 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv* env,
225 jobject obj,
226 jint slot,
227 jboolean wait);
228 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveStateAs(JNIEnv* env,
229 jobject obj,
230 jstring path,
231 jboolean wait);
232 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv* env,
233 jobject obj,
234 jint slot);
235 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadStateAs(JNIEnv* env,
236 jobject obj,
237 jstring path);
238 JNIEXPORT void JNICALL
239 Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_CreateUserDirectories(JNIEnv* env,
240 jobject obj);
241 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(
242 JNIEnv* env, jobject obj, jstring jDirectory);
243 JNIEXPORT jstring JNICALL
244 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv* env, jobject obj);
245 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetCacheDirectory(
246 JNIEnv* env, jobject obj, jstring jDirectory);
247 JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCore(JNIEnv* env,
248 jobject obj);
249 JNIEXPORT jstring JNICALL
250 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendName(JNIEnv* env,
251 jobject obj);
252 JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv* env,
253 jobject obj);
254 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv* env,
255 jobject obj,
256 jboolean enable);
257 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Initialize(JNIEnv* env,
258 jobject obj);
259 JNIEXPORT void JNICALL
260 Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv* env, jobject obj);
261 JNIEXPORT void JNICALL
262 Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv* env, jobject obj);
263 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run__Ljava_lang_String_2(
264 JNIEnv* env, jobject obj, jstring jFile);
265 JNIEXPORT void JNICALL
266 Java_org_dolphinemu_dolphinemu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z(
267 JNIEnv* env, jobject obj, jstring jFile, jstring jSavestate, jboolean jDeleteSavestate);
268 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv* env,
269 jobject obj,
270 jobject surf);
271 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
272 jobject obj);
273
Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv * env,jobject obj)274 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv* env,
275 jobject obj)
276 {
277 std::lock_guard<std::mutex> guard(s_host_identity_lock);
278 Core::SetState(Core::State::Running);
279 }
Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv * env,jobject obj)280 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulation(JNIEnv* env,
281 jobject obj)
282 {
283 std::lock_guard<std::mutex> guard(s_host_identity_lock);
284 Core::SetState(Core::State::Paused);
285 }
286
Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv * env,jobject obj)287 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env,
288 jobject obj)
289 {
290 {
291 std::lock_guard<std::mutex> guard(s_host_identity_lock);
292 s_emulation_end_event.Reset();
293 Core::Stop();
294
295 // Kick the waiting event
296 s_update_main_frame_event.Set();
297 }
298
299 // Wait for shutdown, to avoid accessing the config at the same time as the shutdown code
300 s_emulation_end_event.Wait();
301 }
302
303 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv * env,jobject obj)304 Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv* env, jobject obj)
305 {
306 Core::WaitUntilDoneBooting();
307 }
308
Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv * env,jobject obj)309 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv* env,
310 jobject obj)
311 {
312 return Core::IsRunning();
313 }
314
315 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(JNIEnv* env,
316 jobject obj,
317 jstring jFile);
318
Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(JNIEnv * env,jobject obj,jstring jDevice,jint Button,jint Action)319 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadEvent(
320 JNIEnv* env, jobject obj, jstring jDevice, jint Button, jint Action)
321 {
322 return ButtonManager::GamepadEvent(GetJString(env, jDevice), Button, Action);
323 }
324
Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent(JNIEnv * env,jobject obj,jstring jDevice,jint Axis,jfloat Value)325 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_onGamePadMoveEvent(
326 JNIEnv* env, jobject obj, jstring jDevice, jint Axis, jfloat Value)
327 {
328 ButtonManager::GamepadAxisEvent(GetJString(env, jDevice), Axis, Value);
329 }
330
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetMotionSensorsEnabled(JNIEnv * env,jobject obj,jboolean accelerometer_enabled,jboolean gyroscope_enabled)331 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetMotionSensorsEnabled(
332 JNIEnv* env, jobject obj, jboolean accelerometer_enabled, jboolean gyroscope_enabled)
333 {
334 ciface::Android::SetMotionSensorsEnabled(accelerometer_enabled, gyroscope_enabled);
335 }
336
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetInputRadiusAtAngle(JNIEnv * env,jobject obj,int emu_pad_id,int stick,double angle)337 JNIEXPORT double JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetInputRadiusAtAngle(
338 JNIEnv* env, jobject obj, int emu_pad_id, int stick, double angle)
339 {
340 const auto casted_stick = static_cast<ButtonManager::ButtonType>(stick);
341 return ButtonManager::GetInputRadiusAtAngle(emu_pad_id, casted_stick, angle);
342 }
343
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv * env,jobject obj)344 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetVersionString(JNIEnv* env,
345 jobject obj)
346 {
347 return ToJString(env, Common::scm_rev_str);
348 }
349
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGitRevision(JNIEnv * env,jobject obj)350 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGitRevision(JNIEnv* env,
351 jobject obj)
352 {
353 return ToJString(env, Common::scm_rev_git_str);
354 }
355
Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv * env,jobject obj)356 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveScreenShot(JNIEnv* env,
357 jobject obj)
358 {
359 std::lock_guard<std::mutex> guard(s_host_identity_lock);
360 Core::SaveScreenShot();
361 }
362
Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv * env,jobject obj,jint api)363 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_eglBindAPI(JNIEnv* env,
364 jobject obj,
365 jint api)
366 {
367 eglBindAPI(api);
368 }
369
Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv * env,jobject obj,jint slot,jboolean wait)370 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveState(JNIEnv* env,
371 jobject obj,
372 jint slot,
373 jboolean wait)
374 {
375 std::lock_guard<std::mutex> guard(s_host_identity_lock);
376 State::Save(slot, wait);
377 }
378
Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveStateAs(JNIEnv * env,jobject obj,jstring path,jboolean wait)379 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SaveStateAs(JNIEnv* env,
380 jobject obj,
381 jstring path,
382 jboolean wait)
383 {
384 std::lock_guard<std::mutex> guard(s_host_identity_lock);
385 State::SaveAs(GetJString(env, path), wait);
386 }
387
Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv * env,jobject obj,jint slot)388 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadState(JNIEnv* env,
389 jobject obj,
390 jint slot)
391 {
392 std::lock_guard<std::mutex> guard(s_host_identity_lock);
393 State::Load(slot);
394 }
395
Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadStateAs(JNIEnv * env,jobject obj,jstring path)396 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_LoadStateAs(JNIEnv* env,
397 jobject obj,
398 jstring path)
399 {
400 std::lock_guard<std::mutex> guard(s_host_identity_lock);
401 State::LoadAs(GetJString(env, path));
402 }
403
Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_SetSysDirectory(JNIEnv * env,jobject obj,jstring jPath)404 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_SetSysDirectory(
405 JNIEnv* env, jobject obj, jstring jPath)
406 {
407 const std::string path = GetJString(env, jPath);
408 File::SetSysDirectory(path);
409 }
410
411 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_CreateUserDirectories(JNIEnv * env,jobject obj)412 Java_org_dolphinemu_dolphinemu_utils_DirectoryInitialization_CreateUserDirectories(JNIEnv* env,
413 jobject obj)
414 {
415 UICommon::CreateDirectories();
416 }
417
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(JNIEnv * env,jobject obj,jstring jDirectory)418 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirectory(
419 JNIEnv* env, jobject obj, jstring jDirectory)
420 {
421 std::lock_guard<std::mutex> guard(s_host_identity_lock);
422 UICommon::SetUserDirectory(GetJString(env, jDirectory));
423 }
424
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv * env,jobject obj)425 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv* env,
426 jobject obj)
427 {
428 return ToJString(env, File::GetUserPath(D_USER_IDX));
429 }
430
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetCacheDirectory(JNIEnv * env,jobject obj,jstring jDirectory)431 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetCacheDirectory(
432 JNIEnv* env, jobject obj, jstring jDirectory)
433 {
434 std::lock_guard<std::mutex> guard(s_host_identity_lock);
435 File::SetUserPath(D_CACHE_IDX, GetJString(env, jDirectory) + DIR_SEP);
436 }
437
Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCore(JNIEnv * env,jobject obj)438 JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCore(JNIEnv* env,
439 jobject obj)
440 {
441 return static_cast<jint>(PowerPC::DefaultCPUCore());
442 }
443
444 JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendName(JNIEnv * env,jobject obj)445 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendName(JNIEnv* env, jobject obj)
446 {
447 return ToJString(env, VideoBackendBase::GetDefaultBackendName());
448 }
449
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv * env,jobject obj)450 JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv* env,
451 jobject obj)
452 {
453 return static_cast<jint>(MAX_LOGLEVEL);
454 }
455
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv * env,jobject obj,jboolean enable)456 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv* env,
457 jobject obj,
458 jboolean enable)
459 {
460 std::lock_guard<std::mutex> guard(s_host_identity_lock);
461 Core::SetState(Core::State::Paused);
462 JitInterface::ClearCache();
463 JitInterface::SetProfilingState(enable ? JitInterface::ProfilingState::Enabled :
464 JitInterface::ProfilingState::Disabled);
465 Core::SetState(Core::State::Running);
466 }
467
Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv * env,jobject obj)468 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv* env,
469 jobject obj)
470 {
471 std::lock_guard<std::mutex> guard(s_host_identity_lock);
472 std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt";
473 File::CreateFullPath(filename);
474 JitInterface::WriteProfileResults(filename);
475 }
476
477 // Surface Handling
Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv * env,jobject obj,jobject surf)478 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChanged(JNIEnv* env,
479 jobject obj,
480 jobject surf)
481 {
482 s_surf = ANativeWindow_fromSurface(env, surf);
483 if (s_surf == nullptr)
484 __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null.");
485
486 if (g_renderer)
487 g_renderer->ChangeSurface(s_surf);
488 }
489
Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv * env,jobject obj)490 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
491 jobject obj)
492 {
493 if (g_renderer)
494 g_renderer->ChangeSurface(nullptr);
495
496 if (s_surf)
497 {
498 ANativeWindow_release(s_surf);
499 s_surf = nullptr;
500 }
501 }
502
503 JNIEXPORT jfloat JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameAspectRatio(JNIEnv * env,jobject obj)504 Java_org_dolphinemu_dolphinemu_NativeLibrary_GetGameAspectRatio(JNIEnv* env, jobject obj)
505 {
506 return g_renderer->CalculateDrawAspectRatio();
507 }
508
Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv * env,jobject obj)509 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv* env,
510 jobject obj)
511 {
512 std::lock_guard<std::mutex> guard(s_host_identity_lock);
513 WiimoteReal::Refresh();
514 }
515
Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadWiimoteConfig(JNIEnv * env,jobject obj)516 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadWiimoteConfig(JNIEnv* env,
517 jobject obj)
518 {
519 WiimoteReal::LoadSettings();
520 Wiimote::LoadConfig();
521 }
522
Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadConfig(JNIEnv * env,jobject obj)523 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadConfig(JNIEnv* env,
524 jobject obj)
525 {
526 SConfig::GetInstance().LoadSettings();
527 }
528
529 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_UpdateGCAdapterScanThread(JNIEnv * env,jobject obj)530 Java_org_dolphinemu_dolphinemu_NativeLibrary_UpdateGCAdapterScanThread(JNIEnv* env, jobject obj)
531 {
532 if (GCAdapter::UseAdapter())
533 {
534 GCAdapter::StartScanThread();
535 }
536 else
537 {
538 GCAdapter::StopScanThread();
539 }
540 }
541
Java_org_dolphinemu_dolphinemu_NativeLibrary_Initialize(JNIEnv * env,jobject obj)542 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Initialize(JNIEnv* env,
543 jobject obj)
544 {
545 Common::RegisterMsgAlertHandler(&MsgAlert);
546 Common::AndroidSetReportHandler(&ReportSend);
547 DolphinAnalytics::AndroidSetGetValFunc(&GetAnalyticValue);
548 UICommon::Init();
549 }
550
551 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv * env,jobject obj)552 Java_org_dolphinemu_dolphinemu_NativeLibrary_ReportStartToAnalytics(JNIEnv* env, jobject obj)
553 {
554 DolphinAnalytics::Instance().ReportDolphinStart(GetAnalyticValue("DEVICE_TYPE"));
555 }
556
557 // Returns the scale factor for imgui rendering.
558 // Based on the scaledDensity of the device's display metrics.
GetRenderSurfaceScale(JNIEnv * env)559 static float GetRenderSurfaceScale(JNIEnv* env)
560 {
561 jclass native_library_class = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary");
562 jmethodID get_render_surface_scale_method =
563 env->GetStaticMethodID(native_library_class, "getRenderSurfaceScale", "()F");
564 return env->CallStaticFloatMethod(native_library_class, get_render_surface_scale_method);
565 }
566
Run(JNIEnv * env,const std::vector<std::string> & paths,const std::optional<std::string> & savestate_path={},bool delete_savestate=false)567 static void Run(JNIEnv* env, const std::vector<std::string>& paths,
568 const std::optional<std::string>& savestate_path = {},
569 bool delete_savestate = false)
570 {
571 ASSERT(!paths.empty());
572 __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", paths[0].c_str());
573
574 std::unique_lock<std::mutex> guard(s_host_identity_lock);
575
576 WiimoteReal::InitAdapterClass();
577
578 // No use running the loop when booting fails
579 s_have_wm_user_stop = false;
580 std::unique_ptr<BootParameters> boot = BootParameters::GenerateFromFile(paths, savestate_path);
581 boot->delete_savestate = delete_savestate;
582 WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf, s_surf);
583 wsi.render_surface_scale = GetRenderSurfaceScale(env);
584 if (BootManager::BootCore(std::move(boot), wsi))
585 {
586 ButtonManager::Init(SConfig::GetInstance().GetGameID());
587 static constexpr int TIMEOUT = 10000;
588 static constexpr int WAIT_STEP = 25;
589 int time_waited = 0;
590 // A Core::CORE_ERROR state would be helpful here.
591 while (!Core::IsRunning() && time_waited < TIMEOUT && !s_have_wm_user_stop)
592 {
593 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_STEP));
594 time_waited += WAIT_STEP;
595 }
596 while (Core::IsRunning())
597 {
598 guard.unlock();
599 s_update_main_frame_event.Wait();
600 guard.lock();
601 Core::HostDispatchJobs();
602 }
603 }
604
605 Core::Shutdown();
606 ButtonManager::Shutdown();
607 guard.unlock();
608
609 if (s_surf)
610 {
611 ANativeWindow_release(s_surf);
612 s_surf = nullptr;
613 }
614
615 s_emulation_end_event.Set();
616 }
617
Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2(JNIEnv * env,jobject obj,jobjectArray jPaths)618 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2(
619 JNIEnv* env, jobject obj, jobjectArray jPaths)
620 {
621 Run(env, JStringArrayToVector(env, jPaths));
622 }
623
624 JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2Ljava_lang_String_2Z(JNIEnv * env,jobject obj,jobjectArray jPaths,jstring jSavestate,jboolean jDeleteSavestate)625 Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2Ljava_lang_String_2Z(
626 JNIEnv* env, jobject obj, jobjectArray jPaths, jstring jSavestate, jboolean jDeleteSavestate)
627 {
628 Run(env, JStringArrayToVector(env, jPaths), GetJString(env, jSavestate), jDeleteSavestate);
629 }
630
Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(JNIEnv * env,jobject obj,jstring jFile)631 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(JNIEnv* env,
632 jobject obj,
633 jstring jFile)
634 {
635 const std::string path = GetJString(env, jFile);
636 __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Change Disc: %s", path.c_str());
637 Core::RunAsCPUThread([&path] { DVDInterface::ChangeDisc(path); });
638 }
639
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetLogTypeNames(JNIEnv * env,jobject obj)640 JNIEXPORT jobject JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetLogTypeNames(JNIEnv* env,
641 jobject obj)
642 {
643 std::map<std::string, std::string> map = Common::Log::LogManager::GetInstance()->GetLogTypes();
644
645 auto map_size = static_cast<jsize>(map.size());
646 jobject linked_hash_map =
647 env->NewObject(IDCache::GetLinkedHashMapClass(), IDCache::GetLinkedHashMapInit(), map_size);
648 for (const auto& entry : map)
649 {
650 env->CallObjectMethod(linked_hash_map, IDCache::GetLinkedHashMapPut(),
651 ToJString(env, entry.first), ToJString(env, entry.second));
652 }
653 return linked_hash_map;
654 }
655
Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadLoggerConfig(JNIEnv * env,jobject obj)656 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadLoggerConfig(JNIEnv* env,
657 jobject obj)
658 {
659 Common::Log::LogManager::Init();
660 }
661
Java_org_dolphinemu_dolphinemu_NativeLibrary_InstallWAD(JNIEnv * env,jobject obj,jstring jFile)662 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_InstallWAD(JNIEnv* env,
663 jobject obj,
664 jstring jFile)
665 {
666 const std::string path = GetJString(env, jFile);
667 return static_cast<jboolean>(WiiUtils::InstallWAD(path));
668 }
669
Java_org_dolphinemu_dolphinemu_NativeLibrary_ConvertDiscImage(JNIEnv * env,jobject obj,jstring jInPath,jstring jOutPath,jint jPlatform,jint jFormat,jint jBlockSize,jint jCompression,jint jCompressionLevel,jboolean jScrub,jobject jCallback)670 JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ConvertDiscImage(
671 JNIEnv* env, jobject obj, jstring jInPath, jstring jOutPath, jint jPlatform, jint jFormat,
672 jint jBlockSize, jint jCompression, jint jCompressionLevel, jboolean jScrub, jobject jCallback)
673 {
674 const std::string in_path = GetJString(env, jInPath);
675 const std::string out_path = GetJString(env, jOutPath);
676 const DiscIO::Platform platform = static_cast<DiscIO::Platform>(jPlatform);
677 const DiscIO::BlobType format = static_cast<DiscIO::BlobType>(jFormat);
678 const DiscIO::WIARVZCompressionType compression =
679 static_cast<DiscIO::WIARVZCompressionType>(jCompression);
680 const bool scrub = static_cast<bool>(jScrub);
681
682 std::unique_ptr<DiscIO::BlobReader> blob_reader;
683 if (scrub)
684 blob_reader = DiscIO::ScrubbedBlob::Create(in_path);
685 else
686 blob_reader = DiscIO::CreateBlobReader(in_path);
687
688 if (!blob_reader)
689 return static_cast<jboolean>(false);
690
691 jobject jCallbackGlobal = env->NewGlobalRef(jCallback);
692 Common::ScopeGuard scope_guard([jCallbackGlobal, env] { env->DeleteGlobalRef(jCallbackGlobal); });
693
694 const auto callback = [&jCallbackGlobal](const std::string& text, float completion) {
695 JNIEnv* env = IDCache::GetEnvForThread();
696 return static_cast<bool>(env->CallBooleanMethod(
697 jCallbackGlobal, IDCache::GetCompressCallbackRun(), ToJString(env, text), completion));
698 };
699
700 bool success = false;
701
702 switch (format)
703 {
704 case DiscIO::BlobType::PLAIN:
705 success = DiscIO::ConvertToPlain(blob_reader.get(), in_path, out_path, callback);
706 break;
707
708 case DiscIO::BlobType::GCZ:
709 success =
710 DiscIO::ConvertToGCZ(blob_reader.get(), in_path, out_path,
711 platform == DiscIO::Platform::WiiDisc ? 1 : 0, jBlockSize, callback);
712 break;
713
714 case DiscIO::BlobType::WIA:
715 case DiscIO::BlobType::RVZ:
716 success = DiscIO::ConvertToWIAOrRVZ(blob_reader.get(), in_path, out_path,
717 format == DiscIO::BlobType::RVZ, compression,
718 jCompressionLevel, jBlockSize, callback);
719 break;
720
721 default:
722 ASSERT(false);
723 break;
724 }
725
726 return static_cast<jboolean>(success);
727 }
728
Java_org_dolphinemu_dolphinemu_NativeLibrary_FormatSize(JNIEnv * env,jobject obj,jlong bytes,jint decimals)729 JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_FormatSize(JNIEnv* env,
730 jobject obj,
731 jlong bytes,
732 jint decimals)
733 {
734 return ToJString(env, UICommon::FormatSize(bytes, decimals));
735 }
736
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredPixelsLeft(JNIEnv * env,jobject obj,jint width)737 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredPixelsLeft(
738 JNIEnv* env, jobject obj, jint width)
739 {
740 OSD::SetObscuredPixelsLeft(width);
741 }
742
Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredPixelsTop(JNIEnv * env,jobject obj,jint height)743 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetObscuredPixelsTop(
744 JNIEnv* env, jobject obj, jint height)
745 {
746 OSD::SetObscuredPixelsTop(height);
747 }
748
749 #ifdef __cplusplus
750 }
751 #endif
752