Android: Don't share the JNI environment across threads, but obtain it the
[maemo-rb.git] / firmware / target / hosted / android / lcd-android.c
blob66ddcd5e3e77abc63c6874627e28fff7bcaa16ba
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (c) 2010 Thomas Martitz
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #include <jni.h>
24 #include <string.h>
25 #include "config.h"
26 #include "system.h"
27 #include "kernel.h"
28 #include "lcd.h"
29 #include "button.h"
31 extern jobject RockboxService_instance;
33 static jobject RockboxFramebuffer_instance;
34 static jmethodID java_lcd_update;
35 static jmethodID java_lcd_update_rect;
36 static jmethodID java_lcd_init;
37 static jobject native_buffer;
39 static int dpi;
40 static int scroll_threshold;
41 static bool display_on;
43 /* this might actually be called before lcd_init_device() or even main(), so
44 * be sure to only access static storage initalized at library loading,
45 * and not more */
46 void connect_with_java(JNIEnv* env, jobject fb_instance)
48 JNIEnv e = *env;
50 /* Update RockboxFramebuffer_instance */
51 if (!e->IsSameObject(env, RockboxFramebuffer_instance, fb_instance)) {
52 if (RockboxFramebuffer_instance != NULL)
53 e->DeleteGlobalRef(env, RockboxFramebuffer_instance);
55 RockboxFramebuffer_instance = e->NewGlobalRef(env, fb_instance);
58 static bool have_class = false;
59 if (!have_class)
61 jclass fb_class = e->GetObjectClass(env, fb_instance);
62 /* cache update functions */
63 java_lcd_update = e->GetMethodID(env, fb_class,
64 "java_lcd_update",
65 "()V");
66 java_lcd_update_rect = e->GetMethodID(env, fb_class,
67 "java_lcd_update_rect",
68 "(IIII)V");
69 jmethodID get_dpi = e->GetMethodID(env, fb_class,
70 "getDpi", "()I");
71 jmethodID thresh = e->GetMethodID(env, fb_class,
72 "getScrollThreshold", "()I");
73 /* these don't change with new instances so call them now */
74 dpi = e->CallIntMethod(env, fb_instance, get_dpi);
75 scroll_threshold = e->CallIntMethod(env, fb_instance, thresh);
77 java_lcd_init = e->GetMethodID(env, fb_class,
78 "java_lcd_init",
79 "(IILjava/nio/ByteBuffer;)V");
81 jobject buffer = e->NewDirectByteBuffer(env,
82 lcd_framebuffer,
83 (jlong)sizeof(lcd_framebuffer));
85 native_buffer = e->NewGlobalRef(env, buffer);
87 have_class = true;
89 /* we need to setup parts for the java object every time */
90 (*env)->CallVoidMethod(env, fb_instance, java_lcd_init,
91 (jint)LCD_WIDTH, (jint)LCD_HEIGHT, native_buffer);
94 void lcd_deinit(void)
96 JNIEnv *env_ptr = getJavaEnvironment();
98 (*env_ptr)->DeleteGlobalRef(env_ptr, RockboxFramebuffer_instance);
99 (*env_ptr)->DeleteGlobalRef(env_ptr, native_buffer);
103 * Do nothing here and connect with the java object later (if it isn't already)
105 void lcd_init_device(void)
109 void lcd_update(void)
111 JNIEnv *env_ptr = getJavaEnvironment();
113 if (display_on)
114 (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance,
115 java_lcd_update);
118 void lcd_update_rect(int x, int y, int width, int height)
120 JNIEnv *env_ptr = getJavaEnvironment();
122 if (display_on)
123 (*env_ptr)->CallVoidMethod(env_ptr, RockboxFramebuffer_instance,
124 java_lcd_update_rect, x, y, width, height);
128 * this is called when the surface is created, which called is everytime
129 * the activity is brought in front and the RockboxFramebuffer gains focus
131 * Note this is considered interrupt context
133 JNIEXPORT void JNICALL
134 Java_org_rockbox_RockboxFramebuffer_surfaceCreated(JNIEnv *env, jobject this,
135 jobject surfaceholder)
137 (void)surfaceholder;
138 /* possibly a new instance - reconnect */
139 connect_with_java(env, this);
140 display_on = true;
142 send_event(LCD_EVENT_ACTIVATION, NULL);
143 /* Force an update, since the newly created surface is initially black
144 * waiting for the next normal update results in a longish black screen */
145 queue_post(&button_queue, BUTTON_FORCE_REDRAW, 0);
149 * the surface is destroyed everytime the RockboxFramebuffer loses focus and
150 * goes invisible
152 JNIEXPORT void JNICALL
153 Java_org_rockbox_RockboxFramebuffer_surfaceDestroyed(JNIEnv *e, jobject this,
154 jobject surfaceholder)
156 (void)e; (void)this; (void)surfaceholder;
158 display_on = false;
161 bool lcd_active(void)
163 return display_on;
166 int lcd_get_dpi(void)
168 return dpi;
171 int touchscreen_get_scroll_threshold(void)
173 return scroll_threshold;
176 /* below is a plain copy from lcd-sdl.c */
179 * |R| |1.000000 -0.000001 1.402000| |Y'|
180 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
181 * |B| |1.000000 1.772000 0.000000| |Pr|
182 * Scaled, normalized, rounded and tweaked to yield RGB 565:
183 * |R| |74 0 101| |Y' - 16| >> 9
184 * |G| = |74 -24 -51| |Cb - 128| >> 8
185 * |B| |74 128 0| |Cr - 128| >> 9
187 #define YFAC (74)
188 #define RVFAC (101)
189 #define GUFAC (-24)
190 #define GVFAC (-51)
191 #define BUFAC (128)
193 static inline int clamp(int val, int min, int max)
195 if (val < min)
196 val = min;
197 else if (val > max)
198 val = max;
199 return val;
202 void lcd_yuv_set_options(unsigned options)
204 (void)options;
207 /* Draw a partial YUV colour bitmap - similiar behavior to lcd_blit_yuv
208 in the core */
209 void lcd_blit_yuv(unsigned char * const src[3],
210 int src_x, int src_y, int stride,
211 int x, int y, int width, int height)
213 const unsigned char *ysrc, *usrc, *vsrc;
214 int linecounter;
215 fb_data *dst, *row_end;
216 long z;
218 /* width and height must be >= 2 and an even number */
219 width &= ~1;
220 linecounter = height >> 1;
222 #if LCD_WIDTH >= LCD_HEIGHT
223 dst = &lcd_framebuffer[y][x];
224 row_end = dst + width;
225 #else
226 dst = &lcd_framebuffer[x][LCD_WIDTH - y - 1];
227 row_end = dst + LCD_WIDTH * width;
228 #endif
230 z = stride * src_y;
231 ysrc = src[0] + z + src_x;
232 usrc = src[1] + (z >> 2) + (src_x >> 1);
233 vsrc = src[2] + (usrc - src[1]);
235 /* stride => amount to jump from end of last row to start of next */
236 stride -= width;
238 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
244 int y, cb, cr, rv, guv, bu, r, g, b;
246 y = YFAC*(*ysrc++ - 16);
247 cb = *usrc++ - 128;
248 cr = *vsrc++ - 128;
250 rv = RVFAC*cr;
251 guv = GUFAC*cb + GVFAC*cr;
252 bu = BUFAC*cb;
254 r = y + rv;
255 g = y + guv;
256 b = y + bu;
258 if ((unsigned)(r | g | b) > 64*256-1)
260 r = clamp(r, 0, 64*256-1);
261 g = clamp(g, 0, 64*256-1);
262 b = clamp(b, 0, 64*256-1);
265 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
267 #if LCD_WIDTH >= LCD_HEIGHT
268 dst++;
269 #else
270 dst += LCD_WIDTH;
271 #endif
273 y = YFAC*(*ysrc++ - 16);
274 r = y + rv;
275 g = y + guv;
276 b = y + bu;
278 if ((unsigned)(r | g | b) > 64*256-1)
280 r = clamp(r, 0, 64*256-1);
281 g = clamp(g, 0, 64*256-1);
282 b = clamp(b, 0, 64*256-1);
285 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
287 #if LCD_WIDTH >= LCD_HEIGHT
288 dst++;
289 #else
290 dst += LCD_WIDTH;
291 #endif
293 while (dst < row_end);
295 ysrc += stride;
296 usrc -= width >> 1;
297 vsrc -= width >> 1;
299 #if LCD_WIDTH >= LCD_HEIGHT
300 row_end += LCD_WIDTH;
301 dst += LCD_WIDTH - width;
302 #else
303 row_end -= 1;
304 dst -= LCD_WIDTH*width + 1;
305 #endif
309 int y, cb, cr, rv, guv, bu, r, g, b;
311 y = YFAC*(*ysrc++ - 16);
312 cb = *usrc++ - 128;
313 cr = *vsrc++ - 128;
315 rv = RVFAC*cr;
316 guv = GUFAC*cb + GVFAC*cr;
317 bu = BUFAC*cb;
319 r = y + rv;
320 g = y + guv;
321 b = y + bu;
323 if ((unsigned)(r | g | b) > 64*256-1)
325 r = clamp(r, 0, 64*256-1);
326 g = clamp(g, 0, 64*256-1);
327 b = clamp(b, 0, 64*256-1);
330 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
332 #if LCD_WIDTH >= LCD_HEIGHT
333 dst++;
334 #else
335 dst += LCD_WIDTH;
336 #endif
338 y = YFAC*(*ysrc++ - 16);
339 r = y + rv;
340 g = y + guv;
341 b = y + bu;
343 if ((unsigned)(r | g | b) > 64*256-1)
345 r = clamp(r, 0, 64*256-1);
346 g = clamp(g, 0, 64*256-1);
347 b = clamp(b, 0, 64*256-1);
350 *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9);
352 #if LCD_WIDTH >= LCD_HEIGHT
353 dst++;
354 #else
355 dst += LCD_WIDTH;
356 #endif
358 while (dst < row_end);
360 ysrc += stride;
361 usrc += stride >> 1;
362 vsrc += stride >> 1;
364 #if LCD_WIDTH >= LCD_HEIGHT
365 row_end += LCD_WIDTH;
366 dst += LCD_WIDTH - width;
367 #else
368 row_end -= 1;
369 dst -= LCD_WIDTH*width + 1;
370 #endif
372 while (--linecounter > 0);
374 #if LCD_WIDTH >= LCD_HEIGHT
375 lcd_update_rect(x, y, width, height);
376 #else
377 lcd_update_rect(LCD_WIDTH - y - height, x, height, width);
378 #endif