diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h b/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h index a31c5af74..d0ff05277 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h @@ -192,6 +192,11 @@ typedef void ANativeActivity_createFunc(ANativeActivity* activity, */ extern ANativeActivity_createFunc ANativeActivity_onCreate; +void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format); + +void ANativeActivity_setWindowFlags(ANativeActivity* activity, + uint32_t addFlags, uint32_t removeFlags); + #ifdef __cplusplus }; #endif diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h index 678ba3d7c..7599d7e55 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window.h @@ -14,10 +14,11 @@ * limitations under the License. */ - #ifndef ANDROID_NATIVE_WINDOW_H #define ANDROID_NATIVE_WINDOW_H +#include + #ifdef __cplusplus extern "C" { #endif @@ -34,6 +35,27 @@ enum { struct ANativeWindow; typedef struct ANativeWindow ANativeWindow; +typedef struct ANativeWindow_Buffer { + int32_t width; + int32_t height; + int32_t stride; + int32_t format; + void* bits; + + uint32_t reserved[6]; +} ANativeWindow_Buffer; + +/** + * Acquire a reference on the given ANativeWindow object. This prevents the object + * from being deleted until the reference is removed. + */ +void ANativeWindow_acquire(ANativeWindow* window); + +/** + * Remove a reference that was previously acquired with ANativeWindow_acquire(). + */ +void ANativeWindow_release(ANativeWindow* window); + /* * Return the current width in pixels of the window surface. Returns a * negative value on error. @@ -60,13 +82,22 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window); * window's physical size, then it buffer will be scaled to match that size * when compositing it to the screen. * - * The format may be one of the window format constants above. - * - * For all of these parameters, if 0 is supplied than the window's base + * For all of these parameters, if 0 is supplied then the window's base * value will come back in force. */ -int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, - int32_t height, int32_t format); +int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height); + +/** + * Lock the window's next drawing surface for writing. + */ +int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, + ARect* inOutDirtyBounds); + +/** + * Unlock the window's drawing surface after previously locking it, + * posting the new buffer to the display. + */ +int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); #ifdef __cplusplus }; diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/native_window_jni.h b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window_jni.h new file mode 100644 index 000000000..b9e72efb7 --- /dev/null +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/native_window_jni.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_NATIVE_WINDOW_JNI_H +#define ANDROID_NATIVE_WINDOW_JNI_H + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return the ANativeWindow associated with a Java Surface object, + * for interacting with it through native code. This acquires a reference + * on the ANativeWindow that is returned; be sure to use ANativeWindow_release() + * when done with it so that it doesn't leak. + */ +ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_NATIVE_WINDOW_H diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/rect.h b/ndk/platforms/android-9/arch-arm/usr/include/android/rect.h new file mode 100644 index 000000000..3e81f531d --- /dev/null +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/rect.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ANDROID_RECT_H +#define ANDROID_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ARect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} ARect; + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_RECT_H diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/window.h b/ndk/platforms/android-9/arch-arm/usr/include/android/window.h new file mode 100644 index 000000000..2ab192b74 --- /dev/null +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/window.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ANDROID_WINDOW_H +#define ANDROID_WINDOW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Window flags, as per the Java API at android.view.WindowManager.LayoutParams. + */ +enum { + AWINDOW_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, + AWINDOW_FLAG_DIM_BEHIND = 0x00000002, + AWINDOW_FLAG_BLUR_BEHIND = 0x00000004, + AWINDOW_FLAG_NOT_FOCUSABLE = 0x00000008, + AWINDOW_FLAG_NOT_TOUCHABLE = 0x00000010, + AWINDOW_FLAG_NOT_TOUCH_MODAL = 0x00000020, + AWINDOW_FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, + AWINDOW_FLAG_KEEP_SCREEN_ON = 0x00000080, + AWINDOW_FLAG_LAYOUT_IN_SCREEN = 0x00000100, + AWINDOW_FLAG_LAYOUT_NO_LIMITS = 0x00000200, + AWINDOW_FLAG_FULLSCREEN = 0x00000400, + AWINDOW_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, + AWINDOW_FLAG_DITHER = 0x00001000, + AWINDOW_FLAG_SECURE = 0x00002000, + AWINDOW_FLAG_SCALED = 0x00004000, + AWINDOW_FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, + AWINDOW_FLAG_LAYOUT_INSET_DECOR = 0x00010000, + AWINDOW_FLAG_ALT_FOCUSABLE_IM = 0x00020000, + AWINDOW_FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, + AWINDOW_FLAG_SHOW_WHEN_LOCKED = 0x00080000, + AWINDOW_FLAG_SHOW_WALLPAPER = 0x00100000, + AWINDOW_FLAG_TURN_SCREEN_ON = 0x00200000, + AWINDOW_FLAG_DISMISS_KEYGUARD = 0x00400000, +}; + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_WINDOW_H diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android_glue/threaded_app.h b/ndk/platforms/android-9/arch-arm/usr/include/android_glue/threaded_app.h index 80de3bf2b..491389bb0 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android_glue/threaded_app.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android_glue/threaded_app.h @@ -52,10 +52,6 @@ struct android_app { // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. int activityState; - // This is non-zero when the application's NativeActivity is being - // destroyed and waiting for the app thread to complete. - int destroyRequested; - // ------------------------------------------------- // Below are "private" implementation of the glue code. @@ -67,6 +63,10 @@ struct android_app { pthread_t thread; + // This is non-zero when the application's NativeActivity is being + // destroyed and waiting for the app thread to complete. + int destroyRequested; + int running; int destroyed; AInputQueue* pendingInputQueue; @@ -158,8 +158,11 @@ int8_t android_app_read_cmd(struct android_app* android_app); /** * Call with the command returned by android_app_read_cmd() to do the * default processing of the given command. + * + * Important: returns 0 if the app should exit. You must ALWAYS check for + * a zero return and, if found, exit your android_main() function. */ -void android_app_exec_cmd(struct android_app* android_app, int8_t cmd); +int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd); /** * This is the function that application code must implement, representing diff --git a/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so b/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so index 002b92946..ba26010a7 100644 Binary files a/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so and b/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so differ diff --git a/ndk/platforms/android-9/arch-arm/usr/lib/libthreaded_app.a b/ndk/platforms/android-9/arch-arm/usr/lib/libthreaded_app.a index 9b6e7dd8c..a21c7e553 100644 Binary files a/ndk/platforms/android-9/arch-arm/usr/lib/libthreaded_app.a and b/ndk/platforms/android-9/arch-arm/usr/lib/libthreaded_app.a differ diff --git a/ndk/samples/bitmap-plasma/default.properties b/ndk/samples/bitmap-plasma/default.properties index 0b9250e02..9d135cb85 100644 --- a/ndk/samples/bitmap-plasma/default.properties +++ b/ndk/samples/bitmap-plasma/default.properties @@ -8,4 +8,4 @@ # project structure. # Project target. -target=android-8 +target=android-7 diff --git a/ndk/samples/bitmap-plasma/jni/Application.mk b/ndk/samples/bitmap-plasma/jni/Application.mk index f03ce44ac..8c8530737 100644 --- a/ndk/samples/bitmap-plasma/jni/Application.mk +++ b/ndk/samples/bitmap-plasma/jni/Application.mk @@ -1,2 +1,3 @@ # The ARMv7 is significanly faster due to the use of the hardware FPU APP_ABI := armeabi armeabi-v7a +APP_PLATFORM := android-8 diff --git a/ndk/samples/native-activity/AndroidManifest.xml b/ndk/samples/native-activity/AndroidManifest.xml index 44538d341..e0e6bf08a 100644 --- a/ndk/samples/native-activity/AndroidManifest.xml +++ b/ndk/samples/native-activity/AndroidManifest.xml @@ -3,7 +3,7 @@ package="com.example.native_activity" android:versionCode="1" android:versionName="1.0"> - + app); switch (cmd) { case APP_CMD_WINDOW_CHANGED: engine_term_display(engine); - android_app_exec_cmd(engine->app, cmd); + res = android_app_exec_cmd(engine->app, cmd); if (engine->app->window != NULL) { engine_init_display(engine); engine_draw_frame(engine); } break; case APP_CMD_LOST_FOCUS: - android_app_exec_cmd(engine->app, cmd); + res = android_app_exec_cmd(engine->app, cmd); engine->animating = 0; engine_draw_frame(engine); break; default: - android_app_exec_cmd(engine->app, cmd); + res = android_app_exec_cmd(engine->app, cmd); break; } + + return res; } void android_main(struct android_app* state) { @@ -185,10 +188,15 @@ void android_main(struct android_app* state) { int events; void* data; while ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events, &data)) >= 0) { - LOGI("Poll returned: %d", (int)data); switch ((int)data) { case LOOPER_ID_MAIN: - engine_do_main_cmd(&engine); + if (!engine_do_main_cmd(&engine)) { + LOGI("Engine thread destroy requested!"); + engine_term_display(&engine); + android_app_destroy(state); + // Can't touch android_app object after this. + return; + } break; case LOOPER_ID_EVENT: engine_do_ui_event(&engine); @@ -196,14 +204,6 @@ void android_main(struct android_app* state) { } } - if (state->destroyRequested) { - LOGI("Engine thread destroy requested!"); - engine_term_display(&engine); - android_app_destroy(state); - // Can't touch android_app object after this. - return; - } - if (engine.animating) { // Done with events; draw next animation frame. engine.angle += .01f; diff --git a/ndk/samples/native-plasma/AndroidManifest.xml b/ndk/samples/native-plasma/AndroidManifest.xml new file mode 100644 index 000000000..28408b9b0 --- /dev/null +++ b/ndk/samples/native-plasma/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/ndk/samples/native-plasma/default.properties b/ndk/samples/native-plasma/default.properties new file mode 100644 index 000000000..9d135cb85 --- /dev/null +++ b/ndk/samples/native-plasma/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-7 diff --git a/ndk/samples/native-plasma/jni/Android.mk b/ndk/samples/native-plasma/jni/Android.mk new file mode 100644 index 000000000..e9dcaea70 --- /dev/null +++ b/ndk/samples/native-plasma/jni/Android.mk @@ -0,0 +1,9 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := native-plasma +LOCAL_SRC_FILES := plasma.c +LOCAL_LDLIBS := -lthreaded_app -lm -llog -landroid + +include $(BUILD_SHARED_LIBRARY) diff --git a/ndk/samples/native-plasma/jni/Application.mk b/ndk/samples/native-plasma/jni/Application.mk new file mode 100644 index 000000000..23fa139dd --- /dev/null +++ b/ndk/samples/native-plasma/jni/Application.mk @@ -0,0 +1,3 @@ +# The ARMv7 is significanly faster due to the use of the hardware FPU +APP_ABI := armeabi armeabi-v7a +APP_PLATFORM := android-9 diff --git a/ndk/samples/native-plasma/jni/plasma.c b/ndk/samples/native-plasma/jni/plasma.c new file mode 100644 index 000000000..3ccb6058c --- /dev/null +++ b/ndk/samples/native-plasma/jni/plasma.c @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define LOG_TAG "libplasma" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) + +/* Set to 1 to enable debug log traces. */ +#define DEBUG 0 + +/* Set to 1 to optimize memory stores when generating plasma. */ +#define OPTIMIZE_WRITES 1 + +/* Return current time in milliseconds */ +static double now_ms(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*1000. + tv.tv_usec/1000.; +} + +/* We're going to perform computations for every pixel of the target + * bitmap. floating-point operations are very slow on ARMv5, and not + * too bad on ARMv7 with the exception of trigonometric functions. + * + * For better performance on all platforms, we're going to use fixed-point + * arithmetic and all kinds of tricks + */ + +typedef int32_t Fixed; + +#define FIXED_BITS 16 +#define FIXED_ONE (1 << FIXED_BITS) +#define FIXED_AVERAGE(x,y) (((x) + (y)) >> 1) + +#define FIXED_FROM_INT(x) ((x) << FIXED_BITS) +#define FIXED_TO_INT(x) ((x) >> FIXED_BITS) + +#define FIXED_FROM_FLOAT(x) ((Fixed)((x)*FIXED_ONE)) +#define FIXED_TO_FLOAT(x) ((x)/(1.*FIXED_ONE)) + +#define FIXED_MUL(x,y) (((int64_t)(x) * (y)) >> FIXED_BITS) +#define FIXED_DIV(x,y) (((int64_t)(x) * FIXED_ONE) / (y)) + +#define FIXED_DIV2(x) ((x) >> 1) +#define FIXED_AVERAGE(x,y) (((x) + (y)) >> 1) + +#define FIXED_FRAC(x) ((x) & ((1 << FIXED_BITS)-1)) +#define FIXED_TRUNC(x) ((x) & ~((1 << FIXED_BITS)-1)) + +#define FIXED_FROM_INT_FLOAT(x,f) (Fixed)((x)*(FIXED_ONE*(f))) + +typedef int32_t Angle; + +#define ANGLE_BITS 9 + +#if ANGLE_BITS < 8 +# error ANGLE_BITS must be at least 8 +#endif + +#define ANGLE_2PI (1 << ANGLE_BITS) +#define ANGLE_PI (1 << (ANGLE_BITS-1)) +#define ANGLE_PI2 (1 << (ANGLE_BITS-2)) +#define ANGLE_PI4 (1 << (ANGLE_BITS-3)) + +#define ANGLE_FROM_FLOAT(x) (Angle)((x)*ANGLE_PI/M_PI) +#define ANGLE_TO_FLOAT(x) ((x)*M_PI/ANGLE_PI) + +#if ANGLE_BITS <= FIXED_BITS +# define ANGLE_FROM_FIXED(x) (Angle)((x) >> (FIXED_BITS - ANGLE_BITS)) +# define ANGLE_TO_FIXED(x) (Fixed)((x) << (FIXED_BITS - ANGLE_BITS)) +#else +# define ANGLE_FROM_FIXED(x) (Angle)((x) << (ANGLE_BITS - FIXED_BITS)) +# define ANGLE_TO_FIXED(x) (Fixed)((x) >> (ANGLE_BITS - FIXED_BITS)) +#endif + +static Fixed angle_sin_tab[ANGLE_2PI+1]; + +static void init_angles(void) +{ + int nn; + for (nn = 0; nn < ANGLE_2PI+1; nn++) { + double radians = nn*M_PI/ANGLE_PI; + angle_sin_tab[nn] = FIXED_FROM_FLOAT(sin(radians)); + } +} + +static __inline__ Fixed angle_sin( Angle a ) +{ + return angle_sin_tab[(uint32_t)a & (ANGLE_2PI-1)]; +} + +static __inline__ Fixed angle_cos( Angle a ) +{ + return angle_sin(a + ANGLE_PI2); +} + +static __inline__ Fixed fixed_sin( Fixed f ) +{ + return angle_sin(ANGLE_FROM_FIXED(f)); +} + +static __inline__ Fixed fixed_cos( Fixed f ) +{ + return angle_cos(ANGLE_FROM_FIXED(f)); +} + +/* Color palette used for rendering the plasma */ +#define PALETTE_BITS 8 +#define PALETTE_SIZE (1 << PALETTE_BITS) + +#if PALETTE_BITS > FIXED_BITS +# error PALETTE_BITS must be smaller than FIXED_BITS +#endif + +static uint16_t palette[PALETTE_SIZE]; + +static uint16_t make565(int red, int green, int blue) +{ + return (uint16_t)( ((red << 8) & 0xf800) | + ((green << 2) & 0x03e0) | + ((blue >> 3) & 0x001f) ); +} + +static void init_palette(void) +{ + int nn, mm = 0; + /* fun with colors */ + for (nn = 0; nn < PALETTE_SIZE/4; nn++) { + int jj = (nn-mm)*4*255/PALETTE_SIZE; + palette[nn] = make565(255, jj, 255-jj); + } + + for ( mm = nn; nn < PALETTE_SIZE/2; nn++ ) { + int jj = (nn-mm)*4*255/PALETTE_SIZE; + palette[nn] = make565(255-jj, 255, jj); + } + + for ( mm = nn; nn < PALETTE_SIZE*3/4; nn++ ) { + int jj = (nn-mm)*4*255/PALETTE_SIZE; + palette[nn] = make565(0, 255-jj, 255); + } + + for ( mm = nn; nn < PALETTE_SIZE; nn++ ) { + int jj = (nn-mm)*4*255/PALETTE_SIZE; + palette[nn] = make565(jj, 0, 255); + } +} + +static __inline__ uint16_t palette_from_fixed( Fixed x ) +{ + if (x < 0) x = -x; + if (x >= FIXED_ONE) x = FIXED_ONE-1; + int idx = FIXED_FRAC(x) >> (FIXED_BITS - PALETTE_BITS); + return palette[idx & (PALETTE_SIZE-1)]; +} + +/* Angles expressed as fixed point radians */ + +static void init_tables(void) +{ + init_palette(); + init_angles(); +} + +static void fill_plasma(ANativeWindow_Buffer* buffer, double t) +{ + Fixed ft = FIXED_FROM_FLOAT(t/1000.); + Fixed yt1 = FIXED_FROM_FLOAT(t/1230.); + Fixed yt2 = yt1; + Fixed xt10 = FIXED_FROM_FLOAT(t/3000.); + Fixed xt20 = xt10; + +#define YT1_INCR FIXED_FROM_FLOAT(1/100.) +#define YT2_INCR FIXED_FROM_FLOAT(1/163.) + + void* pixels = buffer->bits; + LOGI("width=%d height=%d stride=%d format=%d", buffer->width, buffer->height, + buffer->stride, buffer->format); + + int yy; + for (yy = 0; yy < buffer->height; yy++) { + uint16_t* line = (uint16_t*)pixels; + Fixed base = fixed_sin(yt1) + fixed_sin(yt2); + Fixed xt1 = xt10; + Fixed xt2 = xt20; + + yt1 += YT1_INCR; + yt2 += YT2_INCR; + +#define XT1_INCR FIXED_FROM_FLOAT(1/173.) +#define XT2_INCR FIXED_FROM_FLOAT(1/242.) + +#if OPTIMIZE_WRITES + /* optimize memory writes by generating one aligned 32-bit store + * for every pair of pixels. + */ + uint16_t* line_end = line + buffer->width; + + if (line < line_end) { + if (((uint32_t)line & 3) != 0) { + Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); + + xt1 += XT1_INCR; + xt2 += XT2_INCR; + + line[0] = palette_from_fixed(ii >> 2); + line++; + } + + while (line + 2 <= line_end) { + Fixed i1 = base + fixed_sin(xt1) + fixed_sin(xt2); + xt1 += XT1_INCR; + xt2 += XT2_INCR; + + Fixed i2 = base + fixed_sin(xt1) + fixed_sin(xt2); + xt1 += XT1_INCR; + xt2 += XT2_INCR; + + uint32_t pixel = ((uint32_t)palette_from_fixed(i1 >> 2) << 16) | + (uint32_t)palette_from_fixed(i2 >> 2); + + ((uint32_t*)line)[0] = pixel; + line += 2; + } + + if (line < line_end) { + Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); + line[0] = palette_from_fixed(ii >> 2); + line++; + } + } +#else /* !OPTIMIZE_WRITES */ + int xx; + for (xx = 0; xx < buffer->width; xx++) { + + Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); + + xt1 += XT1_INCR; + xt2 += XT2_INCR; + + line[xx] = palette_from_fixed(ii / 4); + } +#endif /* !OPTIMIZE_WRITES */ + + // go to next line + pixels = (uint16_t*)pixels + buffer->stride; + } +} + +/* simple stats management */ +typedef struct { + double renderTime; + double frameTime; +} FrameStats; + +#define MAX_FRAME_STATS 200 +#define MAX_PERIOD_MS 1500 + +typedef struct { + double firstTime; + double lastTime; + double frameTime; + + int firstFrame; + int numFrames; + FrameStats frames[ MAX_FRAME_STATS ]; +} Stats; + +static void +stats_init( Stats* s ) +{ + s->lastTime = now_ms(); + s->firstTime = 0.; + s->firstFrame = 0; + s->numFrames = 0; +} + +static void +stats_startFrame( Stats* s ) +{ + s->frameTime = now_ms(); +} + +static void +stats_endFrame( Stats* s ) +{ + double now = now_ms(); + double renderTime = now - s->frameTime; + double frameTime = now - s->lastTime; + int nn; + + if (now - s->firstTime >= MAX_PERIOD_MS) { + if (s->numFrames > 0) { + double minRender, maxRender, avgRender; + double minFrame, maxFrame, avgFrame; + int count; + + nn = s->firstFrame; + minRender = maxRender = avgRender = s->frames[nn].renderTime; + minFrame = maxFrame = avgFrame = s->frames[nn].frameTime; + for (count = s->numFrames; count > 0; count-- ) { + nn += 1; + if (nn >= MAX_FRAME_STATS) + nn -= MAX_FRAME_STATS; + double render = s->frames[nn].renderTime; + if (render < minRender) minRender = render; + if (render > maxRender) maxRender = render; + double frame = s->frames[nn].frameTime; + if (frame < minFrame) minFrame = frame; + if (frame > maxFrame) maxFrame = frame; + avgRender += render; + avgFrame += frame; + } + avgRender /= s->numFrames; + avgFrame /= s->numFrames; + + LOGI("frame/s (avg,min,max) = (%.1f,%.1f,%.1f) " + "render time ms (avg,min,max) = (%.1f,%.1f,%.1f)\n", + 1000./avgFrame, 1000./maxFrame, 1000./minFrame, + avgRender, minRender, maxRender); + } + s->numFrames = 0; + s->firstFrame = 0; + s->firstTime = now; + } + + nn = s->firstFrame + s->numFrames; + if (nn >= MAX_FRAME_STATS) + nn -= MAX_FRAME_STATS; + + s->frames[nn].renderTime = renderTime; + s->frames[nn].frameTime = frameTime; + + if (s->numFrames < MAX_FRAME_STATS) { + s->numFrames += 1; + } else { + s->firstFrame += 1; + if (s->firstFrame >= MAX_FRAME_STATS) + s->firstFrame -= MAX_FRAME_STATS; + } + + s->lastTime = now; +} + +// ---------------------------------------------------------------------- + +struct engine { + struct android_app* app; + + Stats stats; + + int animating; +}; + +static void engine_draw_frame(struct engine* engine) { + if (engine->app->window == NULL) { + // No window. + return; + } + + ANativeWindow_Buffer buffer; + if (ANativeWindow_lock(engine->app->window, &buffer, NULL) < 0) { + LOGW("Unable to lock window buffer"); + return; + } + + stats_startFrame(&engine->stats); + + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + int64_t time_ms = (((int64_t)t.tv_sec)*1000000000LL + t.tv_nsec)/1000000; + + /* Now fill the values with a nice little plasma */ + fill_plasma(&buffer, time_ms); + + ANativeWindow_unlockAndPost(engine->app->window); + + stats_endFrame(&engine->stats); +} + +static int engine_term_display(struct engine* engine) { + engine->animating = 0; +} + +static int engine_do_ui_event(struct engine* engine) { + AInputEvent* event = NULL; + if (AInputQueue_getEvent(engine->app->inputQueue, &event) >= 0) { + if (AInputEvent_getType(event) == INPUT_EVENT_TYPE_MOTION) { + engine->animating = 1; + AInputQueue_finishEvent(engine->app->inputQueue, event, 1); + } else { + AInputQueue_finishEvent(engine->app->inputQueue, event, 0); + } + } else { + LOGI("Failure reading next input event: %s\n", strerror(errno)); + } + + return 1; +} + +static int32_t engine_do_main_cmd(struct engine* engine) { + int32_t res; + int8_t cmd = android_app_read_cmd(engine->app); + switch (cmd) { + case APP_CMD_WINDOW_CHANGED: + engine_term_display(engine); + res = android_app_exec_cmd(engine->app, cmd); + if (engine->app->window != NULL) { + engine_draw_frame(engine); + } + break; + case APP_CMD_LOST_FOCUS: + res = android_app_exec_cmd(engine->app, cmd); + engine->animating = 0; + engine_draw_frame(engine); + break; + default: + res = android_app_exec_cmd(engine->app, cmd); + break; + } + + return res; +} + +void android_main(struct android_app* state) { + static int init; + + struct engine engine; + + memset(&engine, 0, sizeof(engine)); + state->userData = &engine; + engine.app = state; + + if (!init) { + init_tables(); + init = 1; + } + + stats_init(&engine.stats); + + // loop waiting for stuff to do. + + while (1) { + // Read all pending events. + int fd; + int events; + void* data; + while ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events, &data)) >= 0) { + switch ((int)data) { + case LOOPER_ID_MAIN: + if (!engine_do_main_cmd(&engine)) { + LOGI("Engine thread destroy requested!"); + engine_term_display(&engine); + android_app_destroy(state); + // Can't touch android_app object after this. + return; + } + break; + case LOOPER_ID_EVENT: + engine_do_ui_event(&engine); + break; + } + } + + if (engine.animating) { + engine_draw_frame(&engine); + } + } +} diff --git a/ndk/samples/native-plasma/res/values/strings.xml b/ndk/samples/native-plasma/res/values/strings.xml new file mode 100644 index 000000000..269ec3dda --- /dev/null +++ b/ndk/samples/native-plasma/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Native Plasma + diff --git a/ndk/samples/native-activity/src/Dummy.java b/ndk/samples/native-plasma/src/Dummy.java similarity index 100% rename from ndk/samples/native-activity/src/Dummy.java rename to ndk/samples/native-plasma/src/Dummy.java