diff options
author | Thomas Martitz <kugel@rockbox.org> | 2011-02-19 01:13:38 +0000 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2011-02-19 01:13:38 +0000 |
commit | 144df92bfb3bde9d843363ac5ab537c4d5ee24e3 (patch) | |
tree | 237abe424decc33b7c1e9c8caa89b5a18cf0dd88 /firmware/target | |
parent | 6cbb0e4229225adc1a8222acd21f6ce01b88e472 (diff) |
Android: Rewrite lcd subsystem to use the SurfaceView API.
That enables drawing from outside the apps UI thread, i.e. from within the Rockbox native thread, without needing synchronization means, and adds determinism as to when the draw happens.
It simplifies the drawing routines and adds a convinient way of detecting whether drawing should happen or not (surfaceCreated/Destroyed).
It also restores max. fps on my phone which went down drastically with the gingerbread(CM7) update.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29333 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/hosted/android/app/button-target.h | 2 | ||||
-rw-r--r-- | firmware/target/hosted/android/lcd-android.c | 140 |
2 files changed, 61 insertions, 81 deletions
diff --git a/firmware/target/hosted/android/app/button-target.h b/firmware/target/hosted/android/app/button-target.h index 6106b612f9..3b6028739c 100644 --- a/firmware/target/hosted/android/app/button-target.h +++ b/firmware/target/hosted/android/app/button-target.h @@ -58,6 +58,8 @@ void android_ignore_back_button(bool yes); #define BUTTON_BOTTOMMIDDLE 0x00080000 #define BUTTON_BOTTOMRIGHT 0x00100000 +#define BUTTON_FORCE_REDRAW 0x00200000 + /* No remote */ #define BUTTON_REMOTE 0 diff --git a/firmware/target/hosted/android/lcd-android.c b/firmware/target/hosted/android/lcd-android.c index 92e8f5b96f..f719329819 100644 --- a/firmware/target/hosted/android/lcd-android.c +++ b/firmware/target/hosted/android/lcd-android.c @@ -21,10 +21,12 @@ #include <jni.h> +#include <string.h> #include "config.h" #include "system.h" #include "kernel.h" #include "lcd.h" +#include "button.h" extern JNIEnv *env_ptr; extern jclass RockboxService_class; @@ -32,57 +34,48 @@ extern jobject RockboxService_instance; static jclass RockboxFramebuffer_class; static jobject RockboxFramebuffer_instance; -static jmethodID postInvalidate1; -static jmethodID postInvalidate2; +static jmethodID java_lcd_update; +static jmethodID java_lcd_update_rect; -static bool display_on; static int dpi; static int scroll_threshold; -static struct wakeup lcd_wakeup; -static struct mutex lcd_mtx; +static bool display_on; void lcd_init_device(void) { JNIEnv e = *env_ptr; - wakeup_init(&lcd_wakeup); - mutex_init(&lcd_mtx); - RockboxFramebuffer_class = e->FindClass(env_ptr, - "org/rockbox/RockboxFramebuffer"); - /* instantiate a RockboxFramebuffer instance - * - * Pass lcd width and height and our framebuffer so the java layer - * can create a Bitmap which directly maps to it - **/ - - /* map the framebuffer to a ByteBuffer, this way lcd updates will - * be directly feched from the framebuffer */ + /* get existing instance from the Service */ + jmethodID get_fb = e->GetMethodID(env_ptr, RockboxService_class, "get_fb", + "()Lorg/rockbox/RockboxFramebuffer;"); + RockboxFramebuffer_instance = e->CallObjectMethod(env_ptr, + RockboxService_instance, + get_fb); + RockboxFramebuffer_class = (*env_ptr)->GetObjectClass(env_ptr, + RockboxFramebuffer_instance); + + /* Get init function and set up what's left from the constructor */ + jmethodID java_lcd_init = (*env_ptr)->GetMethodID(env_ptr, + RockboxFramebuffer_class, + "java_lcd_init", + "(IILjava/nio/ByteBuffer;)V"); + jobject buf = e->NewDirectByteBuffer(env_ptr, lcd_framebuffer, (jlong)sizeof(lcd_framebuffer)); - jmethodID constructor = e->GetMethodID(env_ptr, - RockboxFramebuffer_class, - "<init>", - "(Landroid/content/Context;" /* Service */ - "II" /* lcd width/height */ - "Ljava/nio/ByteBuffer;)V"); /* ByteBuffer */ - - RockboxFramebuffer_instance = e->NewObject(env_ptr, - RockboxFramebuffer_class, - constructor, - RockboxService_instance, + e->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, java_lcd_init, (jint)LCD_WIDTH, (jint)LCD_HEIGHT, buf); /* cache update functions */ - postInvalidate1 = (*env_ptr)->GetMethodID(env_ptr, + java_lcd_update = (*env_ptr)->GetMethodID(env_ptr, RockboxFramebuffer_class, - "postInvalidate", + "java_lcd_update", "()V"); - postInvalidate2 = (*env_ptr)->GetMethodID(env_ptr, + java_lcd_update_rect = (*env_ptr)->GetMethodID(env_ptr, RockboxFramebuffer_class, - "postInvalidate", + "java_lcd_update_rect", "(IIII)V"); jmethodID get_dpi = e->GetMethodID(env_ptr, @@ -98,49 +91,54 @@ void lcd_init_device(void) get_dpi); scroll_threshold = e->CallIntMethod(env_ptr, RockboxFramebuffer_instance, get_scroll_threshold); - display_on = true; + /* must not draw until surface is created */ + display_on = false; } -/* the update mechanism is asynchronous since - * onDraw() must be called from the UI thread - * - * The Rockbox thread calling lcd_update() has to wait - * for the update to complete, so that it's synchronous, - * and we need to notify it (we could wait in the java layer, but - * that'd block the other Rockbox threads too) - * - * That should give more smoonth animations - */ void lcd_update(void) { - /* tell the system we're ready for drawing */ if (display_on) - { - mutex_lock(&lcd_mtx); - (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, postInvalidate1); - wakeup_wait(&lcd_wakeup, TIMEOUT_BLOCK); - mutex_unlock(&lcd_mtx); - } + (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, + java_lcd_update); } void lcd_update_rect(int x, int y, int width, int height) { if (display_on) - { - mutex_lock(&lcd_mtx); - (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, postInvalidate2, - (jint)x, (jint)y, (jint)x+width, (jint)y+height); - wakeup_wait(&lcd_wakeup, TIMEOUT_BLOCK); - mutex_unlock(&lcd_mtx); - } + (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, + java_lcd_update_rect, x, y, width, height); +} + +/* + * this is called when the surface is created, which called is everytime + * the activity is brought in front and the RockboxFramebuffer gains focus + * + * Note this is considered interrupt context + */ +JNIEXPORT void JNICALL +Java_org_rockbox_RockboxFramebuffer_surfaceCreated(JNIEnv *e, jobject this, + jobject surfaceholder) +{ + (void)e; (void)this; (void)surfaceholder; + + display_on = true; + send_event(LCD_EVENT_ACTIVATION, NULL); + /* Force an update, since the newly created surface is initially black + * waiting for the next normal update results in a longish black screen */ + queue_post(&button_queue, BUTTON_FORCE_REDRAW, 0); } +/* + * the surface is destroyed everytime the RockboxFramebuffer loses focus and + * goes invisible + */ JNIEXPORT void JNICALL -Java_org_rockbox_RockboxFramebuffer_post_1update_1done(JNIEnv *e, jobject this) +Java_org_rockbox_RockboxFramebuffer_surfaceDestroyed(JNIEnv *e, jobject this, + jobject surfaceholder) { - (void)e; - (void)this; - wakeup_signal(&lcd_wakeup); + (void)e; (void)this; (void)surfaceholder; + + display_on = false; } bool lcd_active(void) @@ -158,26 +156,6 @@ int touchscreen_get_scroll_threshold(void) return scroll_threshold; } -/* - * (un)block lcd updates. - * - * Notice: This is called from the activity thread, so take it - * as interrupt context and take care what the event callback does - * (it shouldn't block in particular - * - * the 1s are needed due to strange naming conventions... - **/ -JNIEXPORT void JNICALL -Java_org_rockbox_RockboxFramebuffer_set_1lcd_1active(JNIEnv *e, - jobject this, - jint active) -{ - (void)e; - (void)this; - display_on = active != 0; - if (active) - send_event(LCD_EVENT_ACTIVATION, NULL); -} /* below is a plain copy from lcd-sdl.c */ /** |