filename | src/gui_android.c |
changeset | 1245:01e0020adf88 |
prev | 1241:74f8e11ab4b8 |
next | 1253:5aa14eeaad5a |
author | nkeynes |
date | Sat Mar 03 16:06:58 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Fully clean the android part before building it - dependencies don't seem to work properly. Add install-adb rule for convenience |
file | annotate | diff | log | raw |
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00001.2 +++ b/src/gui_android.c Sat Mar 03 16:06:58 2012 +10001.3 @@ -0,0 +1,331 @@1.4 +/**1.5 + * $Id$1.6 + *1.7 + * Native shims for the Android front-end (implemented in Java).1.8 + *1.9 + * This is complicated by the fact that all the emulation runs in a1.10 + * separate thread.1.11 + *1.12 + * Copyright (c) 2012 Nathan Keynes.1.13 + *1.14 + * This program is free software; you can redistribute it and/or modify1.15 + * it under the terms of the GNU General Public License as published by1.16 + * the Free Software Foundation; either version 2 of the License, or1.17 + * (at your option) any later version.1.18 + *1.19 + * This program is distributed in the hope that it will be useful,1.20 + * but WITHOUT ANY WARRANTY; without even the implied warranty of1.21 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1.22 + * GNU General Public License for more details.1.23 + */1.24 +1.25 +#include <jni.h>1.26 +#include <pthread.h>1.27 +#include <android/log.h>1.28 +#include <android/native_window_jni.h>1.29 +#include <libisofs.h>1.30 +#include "dream.h"1.31 +#include "dreamcast.h"1.32 +#include "gui.h"1.33 +#include "config.h"1.34 +#include "lxpaths.h"1.35 +#include "tqueue.h"1.36 +#include "display.h"1.37 +#include "gdlist.h"1.38 +#include "gdrom/gdrom.h"1.39 +#include "hotkeys.h"1.40 +#include "serial.h"1.41 +#include "aica/audio.h"1.42 +#include "drivers/video_egl.h"1.43 +#include "maple/maple.h"1.44 +#include "vmu/vmulist.h"1.45 +1.46 +struct surface_info {1.47 + ANativeWindow *win;1.48 + int width, height, format;1.49 +};1.50 +1.51 +static struct surface_info current_surface;1.52 +static const char *appHome = NULL;1.53 +1.54 +/**1.55 + * Count of running nanoseconds - used to cut back on the GUI runtime1.56 + */1.57 +static uint32_t android_gui_nanos = 0;1.58 +static uint32_t android_gui_ticks = 0;1.59 +static struct timeval android_gui_lasttv;1.60 +1.61 +1.62 +void android_gui_start( void )1.63 +{1.64 + /* Dreamcast starting up hook */1.65 +}1.66 +1.67 +void android_gui_stop( void )1.68 +{1.69 + /* Dreamcast stopping hook */1.70 +}1.71 +1.72 +void android_gui_reset( void )1.73 +{1.74 + /* Dreamcast reset hook */1.75 +}1.76 +1.77 +/**1.78 + * The main emulation thread. (as opposed to the UI thread).1.79 + */1.80 +void *android_thread_main(void *data)1.81 +{1.82 + while(1) {1.83 + tqueue_process_wait();1.84 + }1.85 + return NULL;1.86 +}1.87 +1.88 +int android_set_surface(void *data)1.89 +{1.90 + struct surface_info *surface = (struct surface_info *)data;1.91 + video_egl_set_window(surface->win, surface->width, surface->height, surface->format);1.92 + return 0;1.93 +}1.94 +1.95 +int android_clear_surface(void *data)1.96 +{1.97 + struct surface_info *surface = (struct surface_info *)data;1.98 +1.99 + if( dreamcast_is_running() ) {1.100 + dreamcast_stop();1.101 + }1.102 + video_egl_clear_window();1.103 + ANativeWindow_release(surface->win);1.104 + surface->win = NULL;1.105 + return 0;1.106 +}1.107 +1.108 +static pthread_t dreamcast_thread;1.109 +1.110 +void android_start_thread()1.111 +{1.112 + pthread_attr_t attr;1.113 +1.114 + pthread_attr_init(&attr);1.115 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);1.116 + int status = pthread_create(&dreamcast_thread, &attr, android_thread_main, NULL);1.117 + if( status != 0 ) {1.118 + /* Handle errors */1.119 + }1.120 +}1.121 +1.122 +/** tqueue callback wrapper to get the right call type for simple events */1.123 +int android_callback_wrapper( void *fn )1.124 +{1.125 + void (*cast_fn)(void) = fn;1.126 + cast_fn();1.127 +}1.128 +1.129 +int android_mount_disc( void *data )1.130 +{1.131 + char *s = (char *)data;1.132 + ERROR err;1.133 + gboolean result = gdrom_mount_image( s, &err ); /* TODO: Report error */1.134 + return result;1.135 +}1.136 +1.137 +int android_toggle_run( void *data )1.138 +{1.139 + if( dreamcast_is_running() ) {1.140 + dreamcast_stop();1.141 + } else {1.142 + dreamcast_run();1.143 + }1.144 +}1.145 +1.146 +uint32_t android_gui_run_slice( uint32_t nanosecs )1.147 +{1.148 + android_gui_nanos += nanosecs;1.149 + if( android_gui_nanos > GUI_TICK_PERIOD ) { /* 10 ms */1.150 + android_gui_nanos -= GUI_TICK_PERIOD;1.151 + android_gui_ticks ++;1.152 + uint32_t current_period = android_gui_ticks * GUI_TICK_PERIOD;1.153 +1.154 + // Run the event loop1.155 + tqueue_process_all();1.156 +1.157 + struct timeval tv;1.158 + gettimeofday(&tv,NULL);1.159 + uint32_t ns = ((tv.tv_sec - android_gui_lasttv.tv_sec) * 1000000000) +1.160 + (tv.tv_usec - android_gui_lasttv.tv_usec)*1000;1.161 + if( (ns * 1.05) < current_period ) {1.162 + // We've gotten ahead - sleep for a little bit1.163 + struct timespec tv;1.164 + tv.tv_sec = 0;1.165 + tv.tv_nsec = current_period - ns;1.166 + nanosleep(&tv, &tv);1.167 + }1.168 +1.169 +#if 01.170 + /* Update the display every 10 ticks (ie 10 times a second) and1.171 + * save the current tv value */1.172 + if( android_gui_ticks > 10 ) {1.173 + android_gui_ticks -= 10;1.174 +1.175 + double speed = (float)( (double)current_period * 100.0 / ns );1.176 + android_gui_lasttv.tv_sec = tv.tv_sec;1.177 + android_gui_lasttv.tv_usec = tv.tv_usec;1.178 + main_window_set_speed( main_win, speed );1.179 + }1.180 +#endif1.181 + }1.182 + return nanosecs;1.183 +1.184 +1.185 +}1.186 +1.187 +struct dreamcast_module android_gui_module = { "gui", NULL,1.188 + android_gui_reset,1.189 + android_gui_start,1.190 + android_gui_run_slice,1.191 + android_gui_stop,1.192 + NULL, NULL };1.193 +1.194 +gboolean gui_error_dialog( const char *fmt, ... )1.195 +{1.196 + return FALSE; /* TODO */1.197 +}1.198 +1.199 +void gui_update_state()1.200 +{1.201 + /* TODO */1.202 +}1.203 +1.204 +void gui_set_use_grab( gboolean grab )1.205 +{1.206 + /* No implementation - mouse grab doesn't exist */1.207 +}1.208 +1.209 +void gui_update_io_activity( io_activity_type activity, gboolean active )1.210 +{1.211 + /* No implementation */1.212 +}1.213 +1.214 +void gui_do_later( do_later_callback_t func )1.215 +{1.216 + func(); /* TODO */1.217 +}1.218 +1.219 +static void android_init( const char *appHomeDir )1.220 +{1.221 + set_global_log_level("info");1.222 + appHome = appHomeDir;1.223 + const char *confFile = g_strdup_printf("%s/lxdreamrc", appHome);1.224 + set_user_data_path(appHome);1.225 + lxdream_set_config_filename( confFile );1.226 + lxdream_make_config_dir( );1.227 + lxdream_load_config( );1.228 + iso_init();1.229 + gdrom_list_init();1.230 + vmulist_init();1.231 + dreamcast_init(1);1.232 +1.233 + dreamcast_register_module( &android_gui_module );1.234 + audio_init_driver(NULL);1.235 + display_driver_t display_driver = get_display_driver_by_name(NULL);1.236 + display_set_driver(display_driver);1.237 +1.238 + hotkeys_init();1.239 + serial_init();1.240 + maple_reattach_all();1.241 + INFO( "%s! ready...", APP_NAME );1.242 + android_start_thread();1.243 +}1.244 +1.245 +1.246 +/************************* Dreamcast native entry points **************************/1.247 +1.248 +static char *getStringChars( JNIEnv *env, jstring str );1.249 +1.250 +/**1.251 + * Main initialization entry point. We need to do all the setup that main()1.252 + * would normally do, as well as any UI specific setup.1.253 + */1.254 +JNIEXPORT void JNICALL Java_org_lxdream_Dreamcast_init(JNIEnv * env, jclass obj, jstring homeDir )1.255 +{1.256 + android_init( getStringChars(env, homeDir) );1.257 +}1.258 +1.259 +JNIEXPORT void JNICALL Java_org_lxdream_Dreamcast_run(JNIEnv * env, jclass obj)1.260 +{1.261 + tqueue_post_message( android_callback_wrapper, dreamcast_run );1.262 +}1.263 +1.264 +JNIEXPORT void JNICALL Java_org_lxdream_Dreamcast_toggleRun(JNIEnv * env, jclass obj)1.265 +{1.266 + tqueue_post_message( android_toggle_run, NULL );1.267 +}1.268 +1.269 +JNIEXPORT void JNICALL Java_org_lxdream_Dreamcast_reset(JNIEnv * env, jclass obj)1.270 +{1.271 + tqueue_post_message( android_callback_wrapper, dreamcast_reset );1.272 +}1.273 +1.274 +JNIEXPORT void JNICALL Java_org_lxdream_Dreamcast_stop(JNIEnv * env, jclass obj)1.275 +{1.276 + /* Need to make sure this completely shuts down before we return */1.277 + tqueue_send_message( android_callback_wrapper, dreamcast_stop );1.278 +}1.279 +1.280 +JNIEXPORT jboolean JNICALL Java_org_lxdream_Dreamcast_isRunning(JNIEnv *env, jclass obj)1.281 +{1.282 + return dreamcast_is_running();1.283 +}1.284 +1.285 +JNIEXPORT jboolean JNICALL Java_org_lxdream_Dreamcast_isRunnable(JNIEnv *env, jclass obj)1.286 +{1.287 + return dreamcast_can_run();1.288 +}1.289 +1.290 +JNIEXPORT jboolean JNICALL Java_org_lxdream_Dreamcast_mount(JNIEnv *env, jclass obj, jstring str)1.291 +{1.292 + char *s = getStringChars(env, str);1.293 + return tqueue_send_message( android_mount_disc, s );1.294 +}1.295 +1.296 +JNIEXPORT jboolean JNICALL Java_org_lxdream_Dreamcast_unmount(JNIEnv *env, jclass obj)1.297 +{1.298 + tqueue_post_message( android_callback_wrapper, gdrom_unmount_disc );1.299 +}1.300 +1.301 +1.302 +/************************* LxdreamView native entry points **************************/1.303 +1.304 +JNIEXPORT void JNICALL Java_org_lxdream_LxdreamView_setSurface(JNIEnv * env, jobject view, jobject surface, jint width, jint height)1.305 +{1.306 + current_surface.win = ANativeWindow_fromSurface(env, surface);1.307 + current_surface.width = width;1.308 + current_surface.height = height;1.309 + int fmt = ANativeWindow_getFormat(current_surface.win);1.310 + if( fmt == WINDOW_FORMAT_RGB_565 ) {1.311 + current_surface.format = COLFMT_RGB565;1.312 + } else {1.313 + current_surface.format = COLFMT_RGB888;1.314 + }1.315 + tqueue_post_message( android_set_surface, ¤t_surface );1.316 +}1.317 +1.318 +JNIEXPORT void JNICALL Java_org_lxdream_LxdreamView_clearSurface(JNIEnv * env, jobject view, jobject surface)1.319 +{1.320 + /* Need to make sure this completely shuts down before we return */1.321 + tqueue_send_message( android_clear_surface, ¤t_surface );1.322 +}1.323 +1.324 +1.325 +/************************* JNI Support functions **************************/1.326 +1.327 +static char *getStringChars( JNIEnv *env, jstring str )1.328 +{1.329 + jboolean iscopy;1.330 + const char *p = (*env)->GetStringUTFChars(env, str, &iscopy);1.331 + char *result = strdup(p);1.332 + (*env)->ReleaseStringUTFChars(env,str,p);1.333 + return result;1.334 +}
.