diff --git a/jme3-android-native/bufferallocator.gradle b/jme3-android-native/bufferallocator.gradle new file mode 100644 index 0000000000..f03027e275 --- /dev/null +++ b/jme3-android-native/bufferallocator.gradle @@ -0,0 +1,59 @@ +// build file for native buffer allocator, created by pavl_g on 5/17/22. + +// directories for native source +String bufferAllocatorAndroidPath = 'src/native/jme_bufferallocator' +String bufferAllocatorHeaders = 'src/native/headers' + +//Pre-compiled libs directory +def rootPath = rootProject.projectDir.absolutePath +String bufferAllocatorPreCompiledLibsDir = + rootPath + File.separator + "build" + File.separator + 'native' + File.separator + 'android' + File.separator + 'allocator' + +// directories for build +String bufferAllocatorBuildDir = "$buildDir" + File.separator + "bufferallocator" +String bufferAllocatorJniDir = bufferAllocatorBuildDir + File.separator + "jni" +String bufferAllocatorHeadersBuildDir = bufferAllocatorJniDir + File.separator + "headers" +String bufferAllocatorBuildLibsDir = bufferAllocatorBuildDir + File.separator + "libs" + +// copy native src to build dir +task copyJmeBufferAllocator(type: Copy) { + from file(bufferAllocatorAndroidPath) + into file(bufferAllocatorJniDir) +} + +// copy native headers to build dir +task copyJmeHeadersBufferAllocator(type: Copy, dependsOn: copyJmeBufferAllocator) { + from file(bufferAllocatorHeaders) + into file(bufferAllocatorHeadersBuildDir) +} + +// compile and build copied natives in build dir +task buildBufferAllocatorNativeLib(type: Exec, dependsOn: [copyJmeBufferAllocator, copyJmeHeadersBufferAllocator]) { + workingDir bufferAllocatorBuildDir + executable rootProject.ndkCommandPath + args "-j" + Runtime.runtime.availableProcessors() +} + +task updatePreCompiledLibsBufferAllocator(type: Copy, dependsOn: buildBufferAllocatorNativeLib) { + from file(bufferAllocatorBuildLibsDir) + into file(bufferAllocatorPreCompiledLibsDir) +} + +// Copy pre-compiled libs to build directory (when not building new libs) +task copyPreCompiledLibsBufferAllocator(type: Copy) { + from file(bufferAllocatorPreCompiledLibsDir) + into file(bufferAllocatorBuildLibsDir) +} + +// ndkExists is a boolean from the build.gradle in the root project +// buildNativeProjects is a string set to "true" +if (ndkExists && buildNativeProjects == "true") { + // build native libs and update stored pre-compiled libs to commit + compileJava.dependsOn { updatePreCompiledLibsBufferAllocator } +} else { + // use pre-compiled native libs (not building new ones) + compileJava.dependsOn { copyPreCompiledLibsBufferAllocator } +} + +// package the native object files inside the lib folder in a production jar +jar.into("lib") { from bufferAllocatorBuildLibsDir } diff --git a/jme3-android-native/build.gradle b/jme3-android-native/build.gradle index d0618bb1ea..cc78ab4722 100644 --- a/jme3-android-native/build.gradle +++ b/jme3-android-native/build.gradle @@ -35,3 +35,4 @@ apply from: file('openalsoft.gradle') // apply from: file('stb_image.gradle') // apply from: file('tremor.gradle') apply from: file('decode.gradle') +apply from: file('bufferallocator.gradle') diff --git a/jme3-android-native/src/native/jme_bufferallocator/Android.mk b/jme3-android-native/src/native/jme_bufferallocator/Android.mk new file mode 100644 index 0000000000..d735478fb6 --- /dev/null +++ b/jme3-android-native/src/native/jme_bufferallocator/Android.mk @@ -0,0 +1,50 @@ +# +# Copyright (c) 2009-2022 jMonkeyEngine +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of 'jMonkeyEngine' nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## +# Created by pavl_g on 5/17/22. +# For more : https://developer.android.com/ndk/guides/android_mk. +## +TARGET_PLATFORM := android-19 + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_LDLIBS := -llog -Wl,-s + +LOCAL_MODULE := bufferallocatorjme + +LOCAL_C_INCLUDES := $(LOCAL_PATH) + +LOCAL_SRC_FILES := com_jme3_util_AndroidNativeBufferAllocator.c + +include $(BUILD_SHARED_LIBRARY) diff --git a/jme3-android-native/src/native/jme_bufferallocator/Application.mk b/jme3-android-native/src/native/jme_bufferallocator/Application.mk new file mode 100644 index 0000000000..4bcc2ef85e --- /dev/null +++ b/jme3-android-native/src/native/jme_bufferallocator/Application.mk @@ -0,0 +1,39 @@ +# +# Copyright (c) 2009-2022 jMonkeyEngine +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of 'jMonkeyEngine' nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## +# Created by pavl_g on 5/17/22. +# For more : https://developer.android.com/ndk/guides/application_mk. +## +APP_PLATFORM := android-19 +# change this to 'debug' to see android logs +APP_OPTIM := release +APP_ABI := all \ No newline at end of file diff --git a/jme3-android-native/src/native/jme_bufferallocator/com_jme3_util_AndroidNativeBufferAllocator.c b/jme3-android-native/src/native/jme_bufferallocator/com_jme3_util_AndroidNativeBufferAllocator.c new file mode 100644 index 0000000000..4f5cd66d09 --- /dev/null +++ b/jme3-android-native/src/native/jme_bufferallocator/com_jme3_util_AndroidNativeBufferAllocator.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2009-2022 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file com_jme3_util_AndroidNativeBufferAllocator.c + * @author pavl_g. + * @brief Creates and releases direct byte buffers for {com.jme3.util.AndroidNativeBufferAllocator}. + * @date 2022-05-17. + * @note + * Find more at : + * - JNI Direct byte buffers : https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#NewDirectByteBuffer. + * - JNI Get Direct byte buffer : https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#GetDirectBufferAddress. + * - GNU Basic allocation : https://www.gnu.org/software/libc/manual/html_node/Basic-Allocation.html. + * - GNU Allocating Cleared Space : https://www.gnu.org/software/libc/manual/html_node/Allocating-Cleared-Space.html. + * - GNU No Memory error : https://www.gnu.org/software/libc/manual/html_node/Error-Codes.html#index-ENOMEM. + * - GNU Freeing memory : https://www.gnu.org/software/libc/manual/html_node/Freeing-after-Malloc.html. + * - Android logging : https://developer.android.com/ndk/reference/group/logging. + * - Android logging example : https://github.com/android/ndk-samples/blob/7a8ff4c5529fce6ec4c5796efbe773f5d0e569cc/hello-libs/app/src/main/cpp/hello-libs.cpp#L25-L26. + */ + +#include "headers/com_jme3_util_AndroidNativeBufferAllocator.h" +#include +#include +#include + +#ifndef NDEBUG +#include +#define LOG(LOG_ID, ...) __android_log_print(LOG_ID, \ + "AndroidNativeBufferAllocator", ##__VA_ARGS__); +#else +#define LOG(...) +#endif + +bool isDeviceOutOfMemory(void*); + +/** + * @brief Tests if the device is out of memory. + * + * @return true if the buffer to allocate is a NULL pointer and the errno is ENOMEM (Error-no-memory). + * @return false otherwise. + */ +bool isDeviceOutOfMemory(void* buffer) { + return buffer == NULL && errno == ENOMEM; +} + +JNIEXPORT void JNICALL Java_com_jme3_util_AndroidNativeBufferAllocator_releaseDirectByteBuffer +(JNIEnv * env, jobject object, jobject bufferObject) +{ + void* buffer = (*env)->GetDirectBufferAddress(env, bufferObject); + // deallocates the buffer pointer + free(buffer); + // log the destruction by mem address + LOG(ANDROID_LOG_INFO, "Buffer released (mem_address, size) -> (%p, %lu)", buffer, sizeof(buffer)); + // avoid accessing this memory space by resetting the memory address + buffer = NULL; + LOG(ANDROID_LOG_INFO, "Buffer mem_address formatted (mem_address, size) -> (%p, %u)", buffer, sizeof(buffer)); +} + +JNIEXPORT jobject JNICALL Java_com_jme3_util_AndroidNativeBufferAllocator_createDirectByteBuffer +(JNIEnv * env, jobject object, jlong size) +{ + void* buffer = calloc(1, size); + if (isDeviceOutOfMemory(buffer)) { + LOG(ANDROID_LOG_FATAL, "Device is out of memory exiting with %u", errno); + exit(errno); + } else { + LOG(ANDROID_LOG_INFO, "Buffer created successfully (mem_address, size) -> (%p %lli)", buffer, size); + } + return (*env)->NewDirectByteBuffer(env, buffer, size); +} \ No newline at end of file diff --git a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java index 6d34238100..a80eb7cccd 100644 --- a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java +++ b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java @@ -54,8 +54,8 @@ import com.jme3.renderer.android.AndroidGL; import com.jme3.renderer.opengl.*; import com.jme3.system.*; -import com.jme3.util.AndroidBufferAllocator; import com.jme3.util.BufferAllocatorFactory; +import com.jme3.util.AndroidNativeBufferAllocator; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -82,7 +82,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex final String implementation = BufferAllocatorFactory.PROPERTY_BUFFER_ALLOCATOR_IMPLEMENTATION; if (System.getProperty(implementation) == null) { - System.setProperty(implementation, AndroidBufferAllocator.class.getName()); + System.setProperty(implementation, AndroidNativeBufferAllocator.class.getName()); } } diff --git a/jme3-android/src/main/java/com/jme3/util/AndroidBufferAllocator.java b/jme3-android/src/main/java/com/jme3/util/AndroidBufferAllocator.java index 596bafc138..6ddc00f17e 100644 --- a/jme3-android/src/main/java/com/jme3/util/AndroidBufferAllocator.java +++ b/jme3-android/src/main/java/com/jme3/util/AndroidBufferAllocator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2019 jMonkeyEngine + * Copyright (c) 2009-2022 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,7 +40,9 @@ /** * @author Jesus Oliver + * @deprecated implemented {@link AndroidNativeBufferAllocator} instead. */ +@Deprecated public class AndroidBufferAllocator implements BufferAllocator { // We make use of the ReflectionAllocator to remove the inner buffer diff --git a/jme3-android/src/main/java/com/jme3/util/AndroidNativeBufferAllocator.java b/jme3-android/src/main/java/com/jme3/util/AndroidNativeBufferAllocator.java new file mode 100644 index 0000000000..f91334db7e --- /dev/null +++ b/jme3-android/src/main/java/com/jme3/util/AndroidNativeBufferAllocator.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2009-2022 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.util; + +import java.nio.Buffer; +import java.nio.ByteBuffer; + +/** + * Allocates and destroys direct byte buffers using native code. + * + * @author pavl_g. + */ +public final class AndroidNativeBufferAllocator implements BufferAllocator { + + static { + System.loadLibrary("bufferallocatorjme"); + } + + @Override + public void destroyDirectBuffer(Buffer toBeDestroyed) { + releaseDirectByteBuffer(toBeDestroyed); + } + + @Override + public ByteBuffer allocate(int size) { + return createDirectByteBuffer(size); + } + + /** + * Releases the memory of a direct buffer using a buffer object reference. + * + * @param buffer the buffer reference to release its memory. + * @see AndroidNativeBufferAllocator#destroyDirectBuffer(Buffer) + */ + private native void releaseDirectByteBuffer(Buffer buffer); + + /** + * Creates a new direct byte buffer explicitly with a specific size. + * + * @param size the byte buffer size used for allocating the buffer. + * @return a new direct byte buffer object. + * @see AndroidNativeBufferAllocator#allocate(int) + */ + private native ByteBuffer createDirectByteBuffer(long size); +} \ No newline at end of file