summaryrefslogtreecommitdiff
path: root/firmware/target/hosted/android
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-02-19 01:13:38 +0000
committerThomas Martitz <kugel@rockbox.org>2011-02-19 01:13:38 +0000
commit144df92bfb3bde9d843363ac5ab537c4d5ee24e3 (patch)
tree237abe424decc33b7c1e9c8caa89b5a18cf0dd88 /firmware/target/hosted/android
parent6cbb0e4229225adc1a8222acd21f6ce01b88e472 (diff)
downloadrockbox-144df92bfb3bde9d843363ac5ab537c4d5ee24e3.tar.gz
rockbox-144df92bfb3bde9d843363ac5ab537c4d5ee24e3.zip
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/hosted/android')
-rw-r--r--firmware/target/hosted/android/app/button-target.h2
-rw-r--r--firmware/target/hosted/android/lcd-android.c140
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);
58#define BUTTON_BOTTOMMIDDLE 0x00080000 58#define BUTTON_BOTTOMMIDDLE 0x00080000
59#define BUTTON_BOTTOMRIGHT 0x00100000 59#define BUTTON_BOTTOMRIGHT 0x00100000
60 60
61#define BUTTON_FORCE_REDRAW 0x00200000
62
61/* No remote */ 63/* No remote */
62#define BUTTON_REMOTE 0 64#define BUTTON_REMOTE 0
63 65
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 @@
21 21
22 22
23#include <jni.h> 23#include <jni.h>
24#include <string.h>
24#include "config.h" 25#include "config.h"
25#include "system.h" 26#include "system.h"
26#include "kernel.h" 27#include "kernel.h"
27#include "lcd.h" 28#include "lcd.h"
29#include "button.h"
28 30
29extern JNIEnv *env_ptr; 31extern JNIEnv *env_ptr;
30extern jclass RockboxService_class; 32extern jclass RockboxService_class;
@@ -32,57 +34,48 @@ extern jobject RockboxService_instance;
32 34
33static jclass RockboxFramebuffer_class; 35static jclass RockboxFramebuffer_class;
34static jobject RockboxFramebuffer_instance; 36static jobject RockboxFramebuffer_instance;
35static jmethodID postInvalidate1; 37static jmethodID java_lcd_update;
36static jmethodID postInvalidate2; 38static jmethodID java_lcd_update_rect;
37 39
38static bool display_on;
39static int dpi; 40static int dpi;
40static int scroll_threshold; 41static int scroll_threshold;
41static struct wakeup lcd_wakeup; 42static bool display_on;
42static struct mutex lcd_mtx;
43 43
44void lcd_init_device(void) 44void lcd_init_device(void)
45{ 45{
46 JNIEnv e = *env_ptr; 46 JNIEnv e = *env_ptr;
47 wakeup_init(&lcd_wakeup); 47 /* get existing instance from the Service */
48 mutex_init(&lcd_mtx); 48 jmethodID get_fb = e->GetMethodID(env_ptr, RockboxService_class, "get_fb",
49 RockboxFramebuffer_class = e->FindClass(env_ptr, 49 "()Lorg/rockbox/RockboxFramebuffer;");
50 "org/rockbox/RockboxFramebuffer"); 50 RockboxFramebuffer_instance = e->CallObjectMethod(env_ptr,
51 /* instantiate a RockboxFramebuffer instance 51 RockboxService_instance,
52 * 52 get_fb);
53 * Pass lcd width and height and our framebuffer so the java layer 53 RockboxFramebuffer_class = (*env_ptr)->GetObjectClass(env_ptr,
54 * can create a Bitmap which directly maps to it 54 RockboxFramebuffer_instance);
55 **/ 55
56 56 /* Get init function and set up what's left from the constructor */
57 /* map the framebuffer to a ByteBuffer, this way lcd updates will 57 jmethodID java_lcd_init = (*env_ptr)->GetMethodID(env_ptr,
58 * be directly feched from the framebuffer */ 58 RockboxFramebuffer_class,
59 "java_lcd_init",
60 "(IILjava/nio/ByteBuffer;)V");
61
59 jobject buf = e->NewDirectByteBuffer(env_ptr, 62 jobject buf = e->NewDirectByteBuffer(env_ptr,
60 lcd_framebuffer, 63 lcd_framebuffer,
61 (jlong)sizeof(lcd_framebuffer)); 64 (jlong)sizeof(lcd_framebuffer));
62 65
63 jmethodID constructor = e->GetMethodID(env_ptr, 66 e->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, java_lcd_init,
64 RockboxFramebuffer_class,
65 "<init>",
66 "(Landroid/content/Context;" /* Service */
67 "II" /* lcd width/height */
68 "Ljava/nio/ByteBuffer;)V"); /* ByteBuffer */
69
70 RockboxFramebuffer_instance = e->NewObject(env_ptr,
71 RockboxFramebuffer_class,
72 constructor,
73 RockboxService_instance,
74 (jint)LCD_WIDTH, 67 (jint)LCD_WIDTH,
75 (jint)LCD_HEIGHT, 68 (jint)LCD_HEIGHT,
76 buf); 69 buf);
77 70
78 /* cache update functions */ 71 /* cache update functions */
79 postInvalidate1 = (*env_ptr)->GetMethodID(env_ptr, 72 java_lcd_update = (*env_ptr)->GetMethodID(env_ptr,
80 RockboxFramebuffer_class, 73 RockboxFramebuffer_class,
81 "postInvalidate", 74 "java_lcd_update",
82 "()V"); 75 "()V");
83 postInvalidate2 = (*env_ptr)->GetMethodID(env_ptr, 76 java_lcd_update_rect = (*env_ptr)->GetMethodID(env_ptr,
84 RockboxFramebuffer_class, 77 RockboxFramebuffer_class,
85 "postInvalidate", 78 "java_lcd_update_rect",
86 "(IIII)V"); 79 "(IIII)V");
87 80
88 jmethodID get_dpi = e->GetMethodID(env_ptr, 81 jmethodID get_dpi = e->GetMethodID(env_ptr,
@@ -98,49 +91,54 @@ void lcd_init_device(void)
98 get_dpi); 91 get_dpi);
99 scroll_threshold = e->CallIntMethod(env_ptr, RockboxFramebuffer_instance, 92 scroll_threshold = e->CallIntMethod(env_ptr, RockboxFramebuffer_instance,
100 get_scroll_threshold); 93 get_scroll_threshold);
101 display_on = true; 94 /* must not draw until surface is created */
95 display_on = false;
102} 96}
103 97
104/* the update mechanism is asynchronous since
105 * onDraw() must be called from the UI thread
106 *
107 * The Rockbox thread calling lcd_update() has to wait
108 * for the update to complete, so that it's synchronous,
109 * and we need to notify it (we could wait in the java layer, but
110 * that'd block the other Rockbox threads too)
111 *
112 * That should give more smoonth animations
113 */
114void lcd_update(void) 98void lcd_update(void)
115{ 99{
116 /* tell the system we're ready for drawing */
117 if (display_on) 100 if (display_on)
118 { 101 (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance,
119 mutex_lock(&lcd_mtx); 102 java_lcd_update);
120 (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, postInvalidate1);
121 wakeup_wait(&lcd_wakeup, TIMEOUT_BLOCK);
122 mutex_unlock(&lcd_mtx);
123 }
124} 103}
125 104
126void lcd_update_rect(int x, int y, int width, int height) 105void lcd_update_rect(int x, int y, int width, int height)
127{ 106{
128 if (display_on) 107 if (display_on)
129 { 108 (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance,
130 mutex_lock(&lcd_mtx); 109 java_lcd_update_rect, x, y, width, height);
131 (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance, postInvalidate2, 110}
132 (jint)x, (jint)y, (jint)x+width, (jint)y+height); 111
133 wakeup_wait(&lcd_wakeup, TIMEOUT_BLOCK); 112/*
134 mutex_unlock(&lcd_mtx); 113 * this is called when the surface is created, which called is everytime
135 } 114 * the activity is brought in front and the RockboxFramebuffer gains focus
115 *
116 * Note this is considered interrupt context
117 */
118JNIEXPORT void JNICALL
119Java_org_rockbox_RockboxFramebuffer_surfaceCreated(JNIEnv *e, jobject this,
120 jobject surfaceholder)
121{
122 (void)e; (void)this; (void)surfaceholder;
123
124 display_on = true;
125 send_event(LCD_EVENT_ACTIVATION, NULL);
126 /* Force an update, since the newly created surface is initially black
127 * waiting for the next normal update results in a longish black screen */
128 queue_post(&button_queue, BUTTON_FORCE_REDRAW, 0);
136} 129}
137 130
131/*
132 * the surface is destroyed everytime the RockboxFramebuffer loses focus and
133 * goes invisible
134 */
138JNIEXPORT void JNICALL 135JNIEXPORT void JNICALL
139Java_org_rockbox_RockboxFramebuffer_post_1update_1done(JNIEnv *e, jobject this) 136Java_org_rockbox_RockboxFramebuffer_surfaceDestroyed(JNIEnv *e, jobject this,
137 jobject surfaceholder)
140{ 138{
141 (void)e; 139 (void)e; (void)this; (void)surfaceholder;
142 (void)this; 140
143 wakeup_signal(&lcd_wakeup); 141 display_on = false;
144} 142}
145 143
146bool lcd_active(void) 144bool lcd_active(void)
@@ -158,26 +156,6 @@ int touchscreen_get_scroll_threshold(void)
158 return scroll_threshold; 156 return scroll_threshold;
159} 157}
160 158
161/*
162 * (un)block lcd updates.
163 *
164 * Notice: This is called from the activity thread, so take it
165 * as interrupt context and take care what the event callback does
166 * (it shouldn't block in particular
167 *
168 * the 1s are needed due to strange naming conventions...
169 **/
170JNIEXPORT void JNICALL
171Java_org_rockbox_RockboxFramebuffer_set_1lcd_1active(JNIEnv *e,
172 jobject this,
173 jint active)
174{
175 (void)e;
176 (void)this;
177 display_on = active != 0;
178 if (active)
179 send_event(LCD_EVENT_ACTIVATION, NULL);
180}
181/* below is a plain copy from lcd-sdl.c */ 159/* below is a plain copy from lcd-sdl.c */
182 160
183/** 161/**