diff --git a/OsmAnd/jni/cpufeatures_proxy/Android.mk b/OsmAnd/jni/cpufeatures_proxy/Android.mk index a2636730c7..f92f7caf3b 100755 --- a/OsmAnd/jni/cpufeatures_proxy/Android.mk +++ b/OsmAnd/jni/cpufeatures_proxy/Android.mk @@ -1,6 +1,5 @@ -# This is built only for ARMv5 -ifneq ($(TARGET_ARCH_ABI),armeabi-v7a) -ifneq ($(LOCAL_ARM_NEON),true) +# Do not build for NEON +ifneq ($(OSMAND_NEON),true) LOCAL_PATH := $(call my-dir) @@ -19,4 +18,3 @@ include $(BUILD_SHARED_LIBRARY) $(call import-module,android/cpufeatures) endif -endif \ No newline at end of file diff --git a/OsmAnd/jni/osmand/Android.mk b/OsmAnd/jni/osmand/Android.mk index 8748408cf5..890e4e95eb 100644 --- a/OsmAnd/jni/osmand/Android.mk +++ b/OsmAnd/jni/osmand/Android.mk @@ -53,6 +53,6 @@ else LOCAL_STATIC_LIBRARIES := proto_neon skia_neon endif -LOCAL_LDLIBS := -llog +LOCAL_LDLIBS := -llog -ljnigraphics include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/OsmAnd/jni/osmand/rendering.cpp b/OsmAnd/jni/osmand/rendering.cpp index 7a05d2554c..7e021ca59f 100644 --- a/OsmAnd/jni/osmand/rendering.cpp +++ b/OsmAnd/jni/osmand/rendering.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -697,10 +698,118 @@ void loadJNIRendering(){ #ifdef __cplusplus extern "C" { #endif + +JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_generateRendering_1Direct( JNIEnv* ienv, jobject obj, + jobject renderingContext, jint searchResult, + jobject targetBitmap, + jboolean useEnglishNames, jobject renderingRuleSearchRequest, jint defaultColor) { + setGlobalEnv(ienv); + + // Gain information about bitmap + AndroidBitmapInfo bitmapInfo; + if(AndroidBitmap_getInfo(ienv, targetBitmap, &bitmapInfo) != ANDROID_BITMAP_RESUT_SUCCESS) { + __android_log_print(ANDROID_LOG_ERROR, "net.osmand", "Failed to execute AndroidBitmap_getInfo"); + } + + sprintf(debugMessage, "Creating SkBitmap in native w:%d h:%d s:%d f:%d!", bitmapInfo.width, bitmapInfo.height, bitmapInfo.stride, bitmapInfo.format); + __android_log_print(ANDROID_LOG_WARN, "net.osmand", debugMessage); + + SkBitmap* bitmap = new SkBitmap(); + if(bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) { + int rowBytes = bitmapInfo.stride; + sprintf(debugMessage, "Row bytes for RGBA_8888 is %d", rowBytes); + __android_log_print(ANDROID_LOG_WARN, "net.osmand", debugMessage); + bitmap->setConfig(SkBitmap::kARGB_8888_Config, bitmapInfo.width, bitmapInfo.height, rowBytes); + } else if(bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565) { + int rowBytes = bitmapInfo.stride; + sprintf(debugMessage, "Row bytes for RGB_565 is %d", rowBytes); + __android_log_print(ANDROID_LOG_WARN, "net.osmand", debugMessage); + bitmap->setConfig(SkBitmap::kRGB_565_Config, bitmapInfo.width, bitmapInfo.height, rowBytes); + } else { + __android_log_print(ANDROID_LOG_ERROR, "net.osmand", "Unknown target bitmap format"); + } + + void* lockedBitmapData = NULL; + if(AndroidBitmap_lockPixels(ienv, targetBitmap, &lockedBitmapData) != ANDROID_BITMAP_RESUT_SUCCESS || !lockedBitmapData) { + __android_log_print(ANDROID_LOG_ERROR, "net.osmand", "Failed to execute AndroidBitmap_lockPixels"); + } + sprintf(debugMessage, "Locked %d bytes at %p", bitmap->getSize(), lockedBitmapData); + __android_log_print(ANDROID_LOG_WARN, "net.osmand", debugMessage); + + bitmap->setPixels(lockedBitmapData); + + SkCanvas* canvas = new SkCanvas(*bitmap); + canvas->drawColor(defaultColor); + + SkPaint* paint = new SkPaint; + paint->setAntiAlias(true); + __android_log_print(ANDROID_LOG_WARN, "net.osmand", "Initializing rendering"); + watcher initObjects; + initObjects.start(); + + RenderingRuleSearchRequest* req = initSearchRequest(renderingRuleSearchRequest); + RenderingContext rc; + copyRenderingContext(renderingContext, &rc); + rc.useEnglishNames = useEnglishNames; + SearchResult* result = ((SearchResult*) searchResult); +// std::vector mapDataObjects = marshalObjects(binaryMapDataObjects); + + __android_log_print(ANDROID_LOG_WARN, "net.osmand", "Rendering image"); + initObjects.pause(); + + + // Main part do rendering + rc.nativeOperations.start(); + if(result != NULL) { + doRendering(result->result, canvas, paint, req, &rc); + } + rc.nativeOperations.pause(); + + mergeRenderingContext(renderingContext, &rc); + __android_log_print(ANDROID_LOG_WARN, "net.osmand", "End Rendering image"); + if(AndroidBitmap_unlockPixels(ienv, targetBitmap) != ANDROID_BITMAP_RESUT_SUCCESS) { + __android_log_print(ANDROID_LOG_ERROR, "net.osmand", "Failed to execute AndroidBitmap_unlockPixels"); + } + + // delete variables + delete paint; + delete canvas; + delete req; + delete bitmap; +// deleteObjects(mapDataObjects); + + jclass resultClass = ienv->FindClass("net/osmand/plus/render/NativeOsmandLibrary$RenderingGenerationResult"); + if(!resultClass) + resultClass = ienv->FindClass("net/osmand/render/NativeOsmandLibrary$RenderingGenerationResult"); + sprintf(debugMessage, "Result class = %p", resultClass); + __android_log_print(ANDROID_LOG_WARN, "net.osmand", debugMessage); + + jmethodID resultClassCtorId = ienv->GetMethodID(resultClass, "", "(Ljava/nio/ByteBuffer;Ljava/lang/String;)V"); + + sprintf(debugMessage, "Result class ctor = %p", resultClassCtorId); + __android_log_print(ANDROID_LOG_WARN, "net.osmand", debugMessage); + +#ifdef DEBUG_NAT_OPERATIONS + sprintf(debugMessage, "Native ok (init %d, native op %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime()); +#else + sprintf(debugMessage, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime()); +#endif + __android_log_print(ANDROID_LOG_WARN, "net.osmand", debugMessage); + + // Allocate ctor paramters + jstring message = globalEnv()->NewStringUTF(debugMessage); + + /* Construct a result object */ + jobject resultObject = ienv->NewObject(resultClass, resultClassCtorId, NULL, message); + + return resultObject; +} + void* bitmapData = NULL; size_t bitmapDataSize = 0; -JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_generateRendering( JNIEnv* ienv, jobject obj, - jobject renderingContext, jint searchResult, jint requestedBitmapWidth, jint requestedBitmapHeight, jboolean isTransparent, +JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_generateRendering_1Indirect( JNIEnv* ienv, jobject obj, + jobject renderingContext, jint searchResult, + jint requestedBitmapWidth, jint requestedBitmapHeight, jint rowBytes, jboolean isTransparent, jboolean useEnglishNames, jobject renderingRuleSearchRequest, jint defaultColor) { setGlobalEnv(ienv); @@ -709,11 +818,10 @@ JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera SkBitmap* bitmap = new SkBitmap(); if(isTransparent == JNI_TRUE) - bitmap->setConfig(SkBitmap::kARGB_8888_Config, requestedBitmapWidth, requestedBitmapHeight); + bitmap->setConfig(SkBitmap::kARGB_8888_Config, requestedBitmapWidth, requestedBitmapHeight, rowBytes); else - bitmap->setConfig(SkBitmap::kRGB_565_Config, requestedBitmapWidth, requestedBitmapHeight); + bitmap->setConfig(SkBitmap::kRGB_565_Config, requestedBitmapWidth, requestedBitmapHeight, rowBytes); - // re]allocate buffer only if size changed in greated direction? if(bitmapData != NULL && bitmapDataSize != bitmap->getSize()) { free(bitmapData); bitmapData = NULL; @@ -794,23 +902,6 @@ JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_genera return resultObject; } -JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_releaseRenderingGenerationResults( JNIEnv* ienv, jobject obj, - jobject results) { - setGlobalEnv(ienv); - - // Not needed - /* - jclass resultClass = ienv->FindClass("net/osmand/plus/render/NativeOsmandLibrary$RenderingGenerationResult"); - if(!resultClass) - resultClass = ienv->FindClass("net/osmand/render/NativeOsmandLibrary$RenderingGenerationResult"); - jfieldID resultClass_bitmapBuffer = globalEnv()->GetFieldID(resultClass, "bitmapBuffer", "Ljava/nio/ByteBuffer;"); - jobject bitmapBuffer = globalEnv()->GetObjectField(results, resultClass_bitmapBuffer); - - void *buffer = ienv->GetDirectBufferAddress(bitmapBuffer); - free(buffer); - */ -} - #ifdef __cplusplus } #endif diff --git a/OsmAnd/src/net/osmand/plus/render/NativeOsmandLibrary.java b/OsmAnd/src/net/osmand/plus/render/NativeOsmandLibrary.java index 946e02b3f9..4a98473e17 100644 --- a/OsmAnd/src/net/osmand/plus/render/NativeOsmandLibrary.java +++ b/OsmAnd/src/net/osmand/plus/render/NativeOsmandLibrary.java @@ -26,6 +26,10 @@ public class NativeOsmandLibrary { System.loadLibrary("stlport_shared"); log.debug("Loading native cpufeatures_proxy..."); //$NON-NLS-1$ System.loadLibrary("cpufeatures_proxy"); + if(android.os.Build.VERSION.SDK_INT >= 8) { + log.debug("Loading jnigraphics, since Android >= 2.2 ..."); //$NON-NLS-1$ + System.loadLibrary("jnigraphics"); + } if(!cpuHasNeonSupport()) { log.debug("Loading native osmand..."); //$NON-NLS-1$ System.loadLibrary("osmand"); @@ -66,12 +70,16 @@ public class NativeOsmandLibrary { } public RenderingGenerationResult generateRendering(RenderingContext rc, NativeSearchResult searchResultHandler, - int requestedBitmapWidth, int requestedBitmapHeight, boolean isTransparent, + Bitmap bitmap, int requestedBitmapWidth, int requestedBitmapHeight, int rowBytes, boolean isTransparent, boolean useEnglishNames, RenderingRuleSearchRequest render, int defaultColor) { if (searchResultHandler == null) { return new RenderingGenerationResult(null, "Error searchresult = null"); } - return generateRendering(rc, searchResultHandler.nativeHandler, requestedBitmapWidth, requestedBitmapHeight, isTransparent, useEnglishNames, render, defaultColor); + + if(android.os.Build.VERSION.SDK_INT >= 8) // Android 2.2+ + return generateRendering_Direct(rc, searchResultHandler.nativeHandler, bitmap, useEnglishNames, render, defaultColor); + else + return generateRendering_Indirect(rc, searchResultHandler.nativeHandler, requestedBitmapWidth, requestedBitmapHeight, rowBytes, isTransparent, useEnglishNames, render, defaultColor); } /** @@ -139,10 +147,12 @@ public class NativeOsmandLibrary { private static native void initRenderingRulesStorage(RenderingRulesStorage storage); - private static native RenderingGenerationResult generateRendering(RenderingContext rc, int searchResultHandler, - int requestedBitmapWidth, int requestedBitmapHeight, boolean isTransparent, boolean useEnglishNames, + private static native RenderingGenerationResult generateRendering_Indirect(RenderingContext rc, int searchResultHandler, + int requestedBitmapWidth, int requestedBitmapHeight, int rowBytes, boolean isTransparent, boolean useEnglishNames, + RenderingRuleSearchRequest render, int defaultColor); + private static native RenderingGenerationResult generateRendering_Direct(RenderingContext rc, int searchResultHandler, + Bitmap bitmap, boolean useEnglishNames, RenderingRuleSearchRequest render, int defaultColor); - public static native void releaseRenderingGenerationResults(RenderingGenerationResult results); private static native int searchObjectsForRendering(int sleft, int sright, int stop, int sbottom, int zoom, String mapnaem, RenderingRuleSearchRequest request, boolean skipDuplicates, int searchResultHandler, Object objectWithInterruptedField); diff --git a/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java b/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java index e2265106c9..dac909876c 100644 --- a/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java +++ b/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java @@ -214,8 +214,13 @@ public class OsmandRenderer { final Handler h = new Handler(Looper.getMainLooper()); notifyListenersWithDelay(rc, notifyList, h); } - final NativeOsmandLibrary.RenderingGenerationResult res = library.generateRendering(rc, searchResultHandler, - bmp.getWidth(), bmp.getHeight(), bmp.hasAlpha(), + + // Native library will decide on it's own best way of rendering + // If res.bitmapBuffer is null, it indicates that rendering was done directly to + // memory of passed bitmap, but this is supported only on Android >= 2.2 + final NativeOsmandLibrary.RenderingGenerationResult res = library.generateRendering( + rc, searchResultHandler, + bmp, bmp.getWidth(), bmp.getHeight(), bmp.getRowBytes(), bmp.hasAlpha(), useEnglishNames, render, defaultColor); rc.ended = true; notifyListeners(notifyList); @@ -224,9 +229,9 @@ public class OsmandRenderer { + "(%s points, %s points inside, %s of %s objects visible)\n" + res.debugMessage,//$NON-NLS-1$ time, rc.textRenderingTime, rc.pointCount, rc.pointInsideCount, rc.visible, rc.allObjects); + // See upper note if(res.bitmapBuffer != null) { bmp.copyPixelsFromBuffer(res.bitmapBuffer); - NativeOsmandLibrary.releaseRenderingGenerationResults(res); } } catch (Exception e) { e.printStackTrace();