diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0faf784d..0b4a7d26 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,86 +13,17 @@ on: default: false jobs: - build-android-so: - strategy: - matrix: - arch: [ "x86", "x86_64", "arm64-v8a", "armeabi-v7a" ] - runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - steps: - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-region: us-west-2 - role-to-assume: ${{ secrets.ACTIONS_ROLE }} - - name: Checkout Code - uses: actions/checkout@v3 - with: - submodules: true - token: ${{ secrets.PAT_GITHUB }} - - - name: Update Java - uses: actions/setup-java@v2 - with: - distribution: 'zulu' - java-version: '17' - - - name: Installing pre-requisites - run: | - set -x - # Install some dependencies & premake5 - sudo apt update && sudo apt-get -y install build-essential cmake wget clang g++ libgl1-mesa-dev libvorbis-dev libvpx-dev ninja-build - wget https://github.com/premake/premake-core/releases/download/v5.0.0-alpha15/premake-5.0.0-alpha15-linux.tar.gz - tar -xf premake-5.0.0-alpha15-linux.tar.gz - mkdir bin - cp premake5 bin/premake5 - sudo chmod a+x premake5 - sudo mv premake5 /usr/local/bin - - - name: Cache NDK - id: cache-ndk - uses: actions/cache@v3 - with: - path: | - ${{github.workspace}}/android-ndk-r25b - # we are JUST going to cache for this workflow. - # really we could cache flutter way more (based on the flutter version) - key: android-ndk-r25b-linux - - name: Get and Unzip NDK - if: ${{steps.cache-ndk.outputs.cache-hit != 'true'}} - run: | - wget -q https://dl.google.com/android/repository/android-ndk-r25b-linux.zip - unzip android-ndk-r25b-linux - ls - - name: Build rive for ${{ matrix.arch }} - run: | - cd cpp && ./build.rive.for.sh -c -a ${{ matrix.arch }} - env: - NDK_PATH: ${{github.workspace}}/android-ndk-r25b - # NOTE: this is sneaky, we are adding multiple files from the matrix jobs into the same artifact - - uses: actions/upload-artifact@v3 - with: - name: android-so - path: kotlin/src/main/jniLibs/* - publish: name: Release build and publish - needs: build-android-so runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Update Java uses: actions/setup-java@v2 with: distribution: 'zulu' java-version: '17' - - uses: actions/download-artifact@v3 - with: - name: android-so - path: kotlin/src/main/jniLibs/ # Base64 decodes and pipes the GPG key content into the secret file - name: Prepare environment diff --git a/.gitignore b/.gitignore index 07372d9f..bd6d6732 100644 --- a/.gitignore +++ b/.gitignore @@ -7,16 +7,20 @@ ehthumbs.db Thumbs.db -cpp/*.o -cpp/*.so -cpp/build -cpp/deps -cpp/Toolchains +kotlin/src/main/cpp/*.o +kotlin/src/main/cpp/*.so +kotlin/src/main/cpp/build +kotlin/src/main/cpp/deps +kotlin/src/main/cpp/Toolchains +kotlin/src/main/cpp/test/build +kotlin/src/main/cpp/test/build_catch_tests +kotlin/src/main/cpp/test/output +kotlin/src/main/cpp/test/Catch2 + *.iml .gradle local.properties .idea -.DS_Store build captures build.pixel.sh @@ -25,4 +29,5 @@ build.nexus.sh .settings .classpath -kotlin/src/main/jniLibs/* \ No newline at end of file +kotlin/src/main/jniLibs/* +kotlin/.cxx \ No newline at end of file diff --git a/.rive_head b/.rive_head index 6aa03ad1..45184f9a 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -7ee5f7d5a9af82205d32bfb979fdaac412b51cad +797fb4cbd547509dac0a34e1039bfad5de8cd80c diff --git a/app/build.gradle b/app/build.gradle index 7cc18899..e2e5d090 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,6 +54,7 @@ android { excludes += '/META-INF/{AL2.0,LGPL2.1}' } } + ndkVersion '25.1.8937393' } dependencies { @@ -70,6 +71,7 @@ dependencies { implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation 'androidx.compose.material3:material3:1.2.0-alpha01' + implementation 'androidx.startup:startup-runtime:1.1.1' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/compatibilitytest/build.gradle b/compatibilitytest/build.gradle index 97228ef2..eaca188d 100644 --- a/compatibilitytest/build.gradle +++ b/compatibilitytest/build.gradle @@ -30,6 +30,8 @@ android { jvmTarget = '1.8' } namespace 'app.rive.runtime.compatibilitytest' + ndkVersion '25.1.8937393' + buildToolsVersion '30.0.3' } dependencies { diff --git a/cpp/src/bindings/bindings_init.cpp b/cpp/src/bindings/bindings_init.cpp deleted file mode 100644 index 3c82339c..00000000 --- a/cpp/src/bindings/bindings_init.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "helpers/general.hpp" -#include - -#if defined(DEBUG) || defined(LOG) -#include -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - using namespace rive_android; - - JNIEXPORT void JNICALL Java_app_rive_runtime_kotlin_core_Rive_cppInitialize(JNIEnv* env, - jobject thisObj) - { -#if defined(DEBUG) || defined(LOG) - // luigi: again ifdef this out for release (or murder completely, but - // it's nice to catch all fprintf to stderr). - std::thread t(logThread); - // detach so it outlives the ref - t.detach(); -#endif - // pretty much considered the entrypoint. - env->GetJavaVM(&::globalJavaVM); - } - -#ifdef __cplusplus -} -#endif diff --git a/kotlin/build.gradle b/kotlin/build.gradle index 84c8904d..8b611e84 100644 --- a/kotlin/build.gradle +++ b/kotlin/build.gradle @@ -6,6 +6,7 @@ apply plugin: 'org.jetbrains.dokka' android { compileSdkVersion 33 buildToolsVersion "30.0.3" + ndkVersion "25.1.8937393" defaultConfig { minSdkVersion 21 @@ -13,11 +14,24 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" + externalNativeBuild { + cmake { + abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64' + arguments "-DCMAKE_VERBOSE_MAKEFILE=1", "-DANDROID_ALLOW_UNDEFINED_SYMBOLS=ON", + '-DANDROID_CPP_FEATURES=no-exceptions no-rtti', "-DANDROID_STL=c++_shared" + } + } } kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() } + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } testOptions { unitTests.includeAndroidResources = true } @@ -42,7 +56,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.getkeepsafe.relinker:relinker:1.4.4' + implementation 'com.getkeepsafe.relinker:relinker:1.4.5' implementation 'androidx.startup:startup-runtime:1.1.1' testImplementation 'junit:junit:4.13.2' diff --git a/cpp/.ndk_version b/kotlin/src/main/cpp/.ndk_version similarity index 100% rename from cpp/.ndk_version rename to kotlin/src/main/cpp/.ndk_version diff --git a/cpp/.ndk_version.bots b/kotlin/src/main/cpp/.ndk_version.bots similarity index 100% rename from cpp/.ndk_version.bots rename to kotlin/src/main/cpp/.ndk_version.bots diff --git a/kotlin/src/main/cpp/CMakeLists.txt b/kotlin/src/main/cpp/CMakeLists.txt new file mode 100644 index 00000000..7d2a9443 --- /dev/null +++ b/kotlin/src/main/cpp/CMakeLists.txt @@ -0,0 +1,108 @@ +cmake_minimum_required(VERSION 3.18.1) + +project(rive-android VERSION 1.0.0 LANGUAGES CXX) + +# Compile detail will be in rive-android/kotlin/.cxx/Debug///compile_commands.json +# e.g: kotlin/.cxx/Debug/4o1b5h48/arm64-v8a/compile_commands.json +set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") + +#set(CMAKE_CXX_STANDARD 17) +#set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_FLAGS "-std=c++17 -Wall -fno-exceptions -fno-rtti") +set(CMAKE_CXX_FLAGS_RELEASE "-Oz") +set(CMAKE_VERBOSE_MAKEFILE ON) +set(RIVE_RUNTIME_DIR "${PROJECT_SOURCE_DIR}/../../../../../runtime") +message("LOOKED FOR: ${RIVE_RUNTIME_DIR}") +message("BUILD TYPE: ${CMAKE_BUILD_TYPE}") + + +#[[ CMake adds these flags depending on CMAKE_BUILD_TYPE + 1. Release: `-O3 -DNDEBUG` + 2. Debug: `-O0 -g` + 3. RelWithDebInfo: `-O2 -g -DNDEBUG` + 4. MinSizeRel: `-Os -DNDEBUG` +]] + +add_definitions(-DSK_GL) + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(SKIA_DIR_NAME "skia_debug") + set(DEBUG_FLAG "-d") + set(CONFIG "debug") +endif () + +if (CMAKE_BUILD_TYPE STREQUAL "Release" OR + CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" OR + CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") + set(SKIA_DIR_NAME "skia") + set(CONFIG "release") +endif () + +message("Skia location: ${SKIA_DIR_NAME}") + +# Build dependencies. +execute_process( + COMMAND bash ./build.rive.for.sh -a ${CMAKE_ANDROID_ARCH_ABI} -b ${DEBUG_FLAG} + OUTPUT_FILE ${CMAKE_SOURCE_DIR}/rive_build_${CMAKE_ANDROID_ARCH_ABI}.log + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE SCRIPT_RESULT + OUTPUT_VARIABLE SCRIPT_OUTPUT +) + +if(NOT SCRIPT_RESULT EQUAL "0") + message(FATAL_ERROR "Script returned with error: '${SCRIPT_OUTPUT}' - '${SCRIPT_RESULT}'") +endif() +include_directories( + include + ${RIVE_RUNTIME_DIR}/include + ${RIVE_RUNTIME_DIR}/renderer/library/include + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/ + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/include/core + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/include/effects + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/include/gpu + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/include/config + ${RIVE_RUNTIME_DIR}/skia/renderer/include +) + +file(GLOB SOURCES + src/*.cpp + src/bindings/*.cpp + src/helpers/*.cpp + src/models/*.cpp + ) + +add_library(rive-android SHARED ${SOURCES}) + +set(static_libs + rive + rive_skia_renderer + skia + ) + +foreach (X IN LISTS static_libs) + add_library(${X}-lib STATIC IMPORTED) + set_target_properties(${X}-lib + PROPERTIES IMPORTED_LOCATION + ${CMAKE_CURRENT_SOURCE_DIR}/build/${CONFIG}/${CMAKE_ANDROID_ARCH_ABI}/lib${X}.a + ) +endforeach () + +target_include_directories(rive-android PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + +find_library(log-lib log) +find_library(android-lib android) +find_library(egl-lib EGL) +find_library(gles-lib GLESv3) +find_library(gles-fdsalib GLESv3fdas) + +target_link_libraries(rive-android + rive-lib + rive_skia_renderer-lib + skia-lib + + ${log-lib} + ${android-lib} + ${egl-lib} + ${gles-lib} + # ${gles-fdsalib} + ) diff --git a/cpp/Makefile b/kotlin/src/main/cpp/Makefile similarity index 84% rename from cpp/Makefile rename to kotlin/src/main/cpp/Makefile index 6748aac8..b2eb92d7 100644 --- a/cpp/Makefile +++ b/kotlin/src/main/cpp/Makefile @@ -20,22 +20,27 @@ O_FILES = $(patsubst %.cpp,$(ODIR)/%.o,$(notdir $(SRC_FILES))) DEPS=$(O_FILES) \ $(BUILD_DIR)/librive.a \ - $(BUILD_DIR)/libc++_static.a \ $(BUILD_DIR)/libskia.a \ $(BUILD_DIR)/librive_skia_renderer.a \ -LDIR=-L$(SYSROOT)/usr/lib LIBS=-llog -landroid -lEGL -lGLESv3 # Build the .so object. jni_bridge: $(OBJ_FILES) - $(CXX) -shared $(DEPS) -o $(BUILD_DIR)/libjnirivebridge.so --sysroot=$(SYSROOT) -I$(RIVE_RUNTIME_DIR)/include -I${RIVE_RUNTIME_DIR}/renderer/library/include -I$(INCLUDE) -I$(INCLUDE_CXX) $(LDIR) $(LIBS) $(CXXFLAGS) -static-libstdc++ -static-libgcc -ldl -Wl,--hash-style=both + $(CXX) -shared -o $(BUILD_DIR)/libjnirivebridge.so \ + --target=$(TARGET_ARCH) \ + --sysroot=$(SYSROOT) \ + $(CXXFLAGS) \ + -static-libstdc++ -Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,--fatal-warnings -Wl,--gc-sections -Qunused-arguments \ + $(DEPS) \ + $(LIBS) -latomic -lm # BUILD all .o files - i.e. the files specified in OBJ_FILES. # Output all the .o files in ODIR $(ODIR)/%.o: $(SRC_DIR)/%.cpp $(CXX) -c $< -o $(ODIR)/$(notdir $@) \ -DSK_GL \ + -Iinclude \ -I$(RIVE_RUNTIME_DIR)/include \ -I$(RIVE_RUNTIME_DIR)/renderer/library/include \ -I${RIVE_RUNTIME_DIR}/skia/dependencies/$(SKIA_DIR_NAME)/ \ diff --git a/cpp/build.all.sh b/kotlin/src/main/cpp/build.all.sh similarity index 100% rename from cpp/build.all.sh rename to kotlin/src/main/cpp/build.all.sh diff --git a/cpp/build.clean.sh b/kotlin/src/main/cpp/build.clean.sh similarity index 100% rename from cpp/build.clean.sh rename to kotlin/src/main/cpp/build.clean.sh diff --git a/cpp/build.rive.for.sh b/kotlin/src/main/cpp/build.rive.for.sh similarity index 80% rename from cpp/build.rive.for.sh rename to kotlin/src/main/cpp/build.rive.for.sh index 208a8c2d..40d23ae4 100755 --- a/cpp/build.rive.for.sh +++ b/kotlin/src/main/cpp/build.rive.for.sh @@ -7,6 +7,7 @@ ARCH_X64=x86_64 ARCH_ARM=armeabi-v7a ARCH_ARM64=arm64-v8a +ONLY_DEPS='true' NEEDS_CLEAN='false' FLAGS="-flto=full -DNDEBUG" # we default to release @@ -36,10 +37,11 @@ if [ -z "$HOST_TAG" ]; then exit 1 fi -while getopts "a:cdl" opt; do +while getopts "a:cbdl" opt; do case "$opt" in a) ARCH_NAME="$OPTARG" ;; c) NEEDS_CLEAN="true" ;; + b) ONLY_DEPS="false" ;; d) CONFIG="debug" FLAGS="-DDEBUG -g" @@ -92,16 +94,22 @@ fi # Common variables. TOOLCHAIN="$NDK_PATH/toolchains/llvm/prebuilt/$HOST_TAG" -if [ -d "$PWD/../submodules/rive-cpp" ]; then - export RIVE_RUNTIME_DIR="$PWD/../submodules/rive-cpp" +if [ -z "${RIVE_RUNTIME_DIR}" ]; then + echo "RIVE_RUNTIME_DIR is not set" + if [ -d "$PWD/../../../../submodules/rive-cpp" ]; then + export RIVE_RUNTIME_DIR="$PWD/../../../../submodules/rive-cpp" + else + export RIVE_RUNTIME_DIR="$PWD/../../../../../runtime" + fi else - export RIVE_RUNTIME_DIR="$PWD/../../runtime" + echo "RIVE_RUNTIME_DIR already set: ${RIVE_RUNTIME_DIR}" fi export SYSROOT="$TOOLCHAIN/sysroot" export INCLUDE="$SYSROOT/usr/include" export INCLUDE_CXX="$INCLUDE/c++/v1" -export CXXFLAGS="-std=c++17 -Wall -fno-exceptions -fno-rtti -Iinclude -fPIC -Oz ${FLAGS}" +export CXXFLAGS="-std=c++17 -Wall -fno-exceptions -fno-rtti -fPIC -Oz ${FLAGS}" +# export CXXFLAGS="-std=c++17 -Wall -fno-exceptions -fno-rtti -fsanitize=hwaddress -fno-omit-frame-pointer -Iinclude -fPIC -O1 ${FLAGS}" export AR="$TOOLCHAIN/bin/llvm-ar" export SKIA_REPO=$CONFIG_SKIA_REPO @@ -121,6 +129,15 @@ buildFor() { ./make_skia_android.sh "$SKIA_ARCH" "$CONFIG" popd + # Build librive_pls_renderer (internally builds librive) + # pushd "$RIVE_RUNTIME_DIR"/../pls/out + # premake5 --os=android --arch=$SKIA_ARCH gmake2 + # if ${NEEDS_CLEAN}; then + # make config=$CONFIG clean + # fi + # make config=$CONFIG -j20 rive rive_pls_renderer + # popd + # Build librive_skia_renderer (internally builds librive) pushd "$RIVE_RUNTIME_DIR"/skia/renderer if ${NEEDS_CLEAN}; then @@ -138,13 +155,19 @@ buildFor() { # copy in newly built rive/skia/skia_renderer files. cp "$RIVE_RUNTIME_DIR"/build/android/"$SKIA_ARCH"/bin/"${CONFIG}"/librive.a "$BUILD_DIR" - cp "$RIVE_RUNTIME_DIR"/skia/dependencies/"$SKIA_DIR_NAME"/out/"${CONFIG}"/"$SKIA_ARCH"/libskia.a "$BUILD_DIR" cp "$RIVE_RUNTIME_DIR"/skia/renderer/build/android/"$SKIA_ARCH"/bin/${CONFIG}/librive_skia_renderer.a "$BUILD_DIR" - cp "$LIBCXX"/libc++_static.a "$BUILD_DIR" + # cp "$RIVE_RUNTIME_DIR/../pls/out/android_$CONFIG/librive_pls_renderer.a" "$BUILD_DIR" + cp "$RIVE_RUNTIME_DIR"/skia/dependencies/"$SKIA_DIR_NAME"/out/"${CONFIG}"/"$SKIA_ARCH"/libskia.a "$BUILD_DIR" + + if ! ${ONLY_DEPS}; then + # Skip building the library. + echo "ONLY DEPS!" + exit 0 + fi # build the android .so! mkdir -p "$BUILD_DIR"/obj - make -j7 + make -j20 JNI_DEST=../kotlin/src/main/jniLibs/$ARCH_NAME mkdir -p "$JNI_DEST" @@ -155,14 +178,16 @@ if [ "$ARCH_NAME" = "$ARCH_X86" ]; then echo "==== x86 ====" SKIA_ARCH=x86 ARCH=i686 + export TARGET_ARCH="$ARCH-linux-android$API" export BUILD_DIR=$PWD/build/$CONFIG/$ARCH_NAME - export CC=$TOOLCHAIN/bin/$ARCH-linux-android$API-clang export CXX=$TOOLCHAIN/bin/$ARCH-linux-android$API-clang++ + export CC=$TOOLCHAIN/bin/$ARCH-linux-android$API-clang LIBCXX=$SYSROOT/usr/lib/$ARCH-linux-android elif [ "$ARCH_NAME" = "$ARCH_X64" ]; then echo "==== x86_64 ====" ARCH=x86_64 SKIA_ARCH=x64 + export TARGET_ARCH="$ARCH-linux-android$API" export BUILD_DIR=$PWD/build/$CONFIG/$ARCH_NAME export CXX=$TOOLCHAIN/bin/$ARCH-linux-android$API-clang++ export CC=$TOOLCHAIN/bin/$ARCH-linux-android$API-clang @@ -172,6 +197,7 @@ elif [ "$ARCH_NAME" = "$ARCH_ARM" ]; then ARCH=arm ARCH_PREFIX=armv7a SKIA_ARCH=arm + export TARGET_ARCH="$ARCH_PREFIX-linux-androideabi$API" export BUILD_DIR=$PWD/build/$CONFIG/$ARCH_NAME export CXX=$TOOLCHAIN/bin/$ARCH_PREFIX-linux-androideabi$API-clang++ export CC=$TOOLCHAIN/bin/$ARCH_PREFIX-linux-androideabi$API-clang @@ -180,6 +206,7 @@ elif [ "$ARCH_NAME" = "$ARCH_ARM64" ]; then echo "==== ARM64 ====" ARCH=aarch64 SKIA_ARCH=arm64 + export TARGET_ARCH="$ARCH-linux-android$API" export BUILD_DIR=$PWD/build/$CONFIG/$ARCH_NAME export CXX=$TOOLCHAIN/bin/$ARCH-linux-android$API-clang++ export CC=$TOOLCHAIN/bin/$ARCH-linux-android$API-clang diff --git a/cpp/include/helpers/egl_share_thread_state.hpp b/kotlin/src/main/cpp/include/helpers/egl_share_thread_state.hpp similarity index 100% rename from cpp/include/helpers/egl_share_thread_state.hpp rename to kotlin/src/main/cpp/include/helpers/egl_share_thread_state.hpp diff --git a/cpp/include/helpers/egl_worker.hpp b/kotlin/src/main/cpp/include/helpers/egl_worker.hpp similarity index 100% rename from cpp/include/helpers/egl_worker.hpp rename to kotlin/src/main/cpp/include/helpers/egl_worker.hpp diff --git a/cpp/include/helpers/general.hpp b/kotlin/src/main/cpp/include/helpers/general.hpp similarity index 100% rename from cpp/include/helpers/general.hpp rename to kotlin/src/main/cpp/include/helpers/general.hpp diff --git a/cpp/include/helpers/rendering_stats.hpp b/kotlin/src/main/cpp/include/helpers/rendering_stats.hpp similarity index 100% rename from cpp/include/helpers/rendering_stats.hpp rename to kotlin/src/main/cpp/include/helpers/rendering_stats.hpp diff --git a/cpp/include/helpers/thread.hpp b/kotlin/src/main/cpp/include/helpers/thread.hpp similarity index 100% rename from cpp/include/helpers/thread.hpp rename to kotlin/src/main/cpp/include/helpers/thread.hpp diff --git a/cpp/include/helpers/tracer.hpp b/kotlin/src/main/cpp/include/helpers/tracer.hpp similarity index 100% rename from cpp/include/helpers/tracer.hpp rename to kotlin/src/main/cpp/include/helpers/tracer.hpp diff --git a/cpp/include/helpers/worker_thread.hpp b/kotlin/src/main/cpp/include/helpers/worker_thread.hpp similarity index 100% rename from cpp/include/helpers/worker_thread.hpp rename to kotlin/src/main/cpp/include/helpers/worker_thread.hpp diff --git a/cpp/include/jni_refs.hpp b/kotlin/src/main/cpp/include/jni_refs.hpp similarity index 100% rename from cpp/include/jni_refs.hpp rename to kotlin/src/main/cpp/include/jni_refs.hpp diff --git a/cpp/include/models/dimensions_helper.hpp b/kotlin/src/main/cpp/include/models/dimensions_helper.hpp similarity index 100% rename from cpp/include/models/dimensions_helper.hpp rename to kotlin/src/main/cpp/include/models/dimensions_helper.hpp diff --git a/cpp/include/models/jni_renderer_skia.hpp b/kotlin/src/main/cpp/include/models/jni_renderer_skia.hpp similarity index 100% rename from cpp/include/models/jni_renderer_skia.hpp rename to kotlin/src/main/cpp/include/models/jni_renderer_skia.hpp diff --git a/cpp/src/bindings/bindings_artboard.cpp b/kotlin/src/main/cpp/src/bindings/bindings_artboard.cpp similarity index 100% rename from cpp/src/bindings/bindings_artboard.cpp rename to kotlin/src/main/cpp/src/bindings/bindings_artboard.cpp diff --git a/cpp/src/bindings/bindings_file.cpp b/kotlin/src/main/cpp/src/bindings/bindings_file.cpp similarity index 100% rename from cpp/src/bindings/bindings_file.cpp rename to kotlin/src/main/cpp/src/bindings/bindings_file.cpp diff --git a/cpp/src/bindings/bindings_helper.cpp b/kotlin/src/main/cpp/src/bindings/bindings_helper.cpp similarity index 62% rename from cpp/src/bindings/bindings_helper.cpp rename to kotlin/src/main/cpp/src/bindings/bindings_helper.cpp index 98ce2a59..909b6eb3 100644 --- a/cpp/src/bindings/bindings_helper.cpp +++ b/kotlin/src/main/cpp/src/bindings/bindings_helper.cpp @@ -9,26 +9,6 @@ extern "C" #endif using namespace rive_android; - JNIEXPORT void JNICALL - Java_app_rive_runtime_kotlin_core_Rive_cppCalculateRequiredBounds(JNIEnv* env, - jobject thisObj, - jobject jfit, - jobject jalignment, - jobject availableBoundsRectF, - jobject artboardBoundsRectF, - jobject requiredBoundsRectF) - { - auto fit = ::getFit(env, jfit); - auto alignment = ::getAlignment(env, jalignment); - auto availableBounds = rectFToAABB(env, availableBoundsRectF); - auto artboardBounds = rectFToAABB(env, artboardBoundsRectF); - - DimensionsHelper helper; - - auto required = helper.computeDimensions(fit, alignment, availableBounds, artboardBounds); - aabbToRectF(env, required, requiredBoundsRectF); - } - JNIEXPORT jobject JNICALL Java_app_rive_runtime_kotlin_core_Helpers_cppConvertToArtboardSpace(JNIEnv* env, jobject thisObj, diff --git a/kotlin/src/main/cpp/src/bindings/bindings_init.cpp b/kotlin/src/main/cpp/src/bindings/bindings_init.cpp new file mode 100644 index 00000000..6bfd2468 --- /dev/null +++ b/kotlin/src/main/cpp/src/bindings/bindings_init.cpp @@ -0,0 +1,54 @@ +#include "jni_refs.hpp" +#include "helpers/general.hpp" +#include "models/dimensions_helper.hpp" +#include + +#if defined(DEBUG) || defined(LOG) + +#include + +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + using namespace rive_android; + + JNIEXPORT void JNICALL + Java_app_rive_runtime_kotlin_core_Rive_cppCalculateRequiredBounds(JNIEnv* env, + jobject thisObj, + jobject jfit, + jobject jalignment, + jobject availableBoundsRectF, + jobject artboardBoundsRectF, + jobject requiredBoundsRectF) + { + auto fit = ::getFit(env, jfit); + auto alignment = ::getAlignment(env, jalignment); + auto availableBounds = rectFToAABB(env, availableBoundsRectF); + auto artboardBounds = rectFToAABB(env, artboardBoundsRectF); + + DimensionsHelper helper; + + auto required = helper.computeDimensions(fit, alignment, availableBounds, artboardBounds); + aabbToRectF(env, required, requiredBoundsRectF); + } + + JNIEXPORT void JNICALL Java_app_rive_runtime_kotlin_core_Rive_cppInitialize(JNIEnv* env, + jobject thisObj) + { +#if defined(DEBUG) || defined(LOG) + // luigi: again ifdef this out for release (or murder completely, but + // it's nice to catch all fprintf to stderr). + std::thread t(logThread); + // detach so it outlives the ref + t.detach(); +#endif + // pretty much considered the entrypoint. + env->GetJavaVM(&::globalJavaVM); + } + +#ifdef __cplusplus +} +#endif diff --git a/cpp/src/bindings/bindings_layer_state.cpp b/kotlin/src/main/cpp/src/bindings/bindings_layer_state.cpp similarity index 100% rename from cpp/src/bindings/bindings_layer_state.cpp rename to kotlin/src/main/cpp/src/bindings/bindings_layer_state.cpp diff --git a/cpp/src/bindings/bindings_linear_animation_instance.cpp b/kotlin/src/main/cpp/src/bindings/bindings_linear_animation_instance.cpp similarity index 100% rename from cpp/src/bindings/bindings_linear_animation_instance.cpp rename to kotlin/src/main/cpp/src/bindings/bindings_linear_animation_instance.cpp diff --git a/cpp/src/bindings/bindings_renderer_skia.cpp b/kotlin/src/main/cpp/src/bindings/bindings_renderer_skia.cpp similarity index 100% rename from cpp/src/bindings/bindings_renderer_skia.cpp rename to kotlin/src/main/cpp/src/bindings/bindings_renderer_skia.cpp diff --git a/cpp/src/bindings/bindings_rive_texture_view.cpp b/kotlin/src/main/cpp/src/bindings/bindings_rive_texture_view.cpp similarity index 100% rename from cpp/src/bindings/bindings_rive_texture_view.cpp rename to kotlin/src/main/cpp/src/bindings/bindings_rive_texture_view.cpp diff --git a/cpp/src/bindings/bindings_state_machine_input_instance.cpp b/kotlin/src/main/cpp/src/bindings/bindings_state_machine_input_instance.cpp similarity index 100% rename from cpp/src/bindings/bindings_state_machine_input_instance.cpp rename to kotlin/src/main/cpp/src/bindings/bindings_state_machine_input_instance.cpp diff --git a/cpp/src/bindings/bindings_state_machine_instance.cpp b/kotlin/src/main/cpp/src/bindings/bindings_state_machine_instance.cpp similarity index 100% rename from cpp/src/bindings/bindings_state_machine_instance.cpp rename to kotlin/src/main/cpp/src/bindings/bindings_state_machine_instance.cpp diff --git a/cpp/src/helpers/egl_share_thread_state.cpp b/kotlin/src/main/cpp/src/helpers/egl_share_thread_state.cpp similarity index 99% rename from cpp/src/helpers/egl_share_thread_state.cpp rename to kotlin/src/main/cpp/src/helpers/egl_share_thread_state.cpp index 27b05851..021df895 100644 --- a/cpp/src/helpers/egl_share_thread_state.cpp +++ b/kotlin/src/main/cpp/src/helpers/egl_share_thread_state.cpp @@ -8,7 +8,7 @@ #include "gl/GrGLAssembleInterface.h" #include "SkSurface.h" -#if 0 +#if defined(DEBUG) || defined(LOG) #define EGL_ERR_CHECK() _check_egl_error(__FILE__, __LINE__) #else #define EGL_ERR_CHECK() diff --git a/cpp/src/helpers/egl_worker.cpp b/kotlin/src/main/cpp/src/helpers/egl_worker.cpp similarity index 100% rename from cpp/src/helpers/egl_worker.cpp rename to kotlin/src/main/cpp/src/helpers/egl_worker.cpp diff --git a/cpp/src/helpers/general.cpp b/kotlin/src/main/cpp/src/helpers/general.cpp similarity index 100% rename from cpp/src/helpers/general.cpp rename to kotlin/src/main/cpp/src/helpers/general.cpp diff --git a/cpp/src/helpers/thread.cpp b/kotlin/src/main/cpp/src/helpers/thread.cpp similarity index 100% rename from cpp/src/helpers/thread.cpp rename to kotlin/src/main/cpp/src/helpers/thread.cpp diff --git a/cpp/src/jni_refs.cpp b/kotlin/src/main/cpp/src/jni_refs.cpp similarity index 100% rename from cpp/src/jni_refs.cpp rename to kotlin/src/main/cpp/src/jni_refs.cpp diff --git a/cpp/src/models/dimensions_helper.cpp b/kotlin/src/main/cpp/src/models/dimensions_helper.cpp similarity index 100% rename from cpp/src/models/dimensions_helper.cpp rename to kotlin/src/main/cpp/src/models/dimensions_helper.cpp diff --git a/cpp/src/models/jni_renderer_skia.cpp b/kotlin/src/main/cpp/src/models/jni_renderer_skia.cpp similarity index 99% rename from cpp/src/models/jni_renderer_skia.cpp rename to kotlin/src/main/cpp/src/models/jni_renderer_skia.cpp index d2844ddd..07b3c3c8 100644 --- a/cpp/src/models/jni_renderer_skia.cpp +++ b/kotlin/src/main/cpp/src/models/jni_renderer_skia.cpp @@ -288,4 +288,4 @@ void JNIRendererSkia::calculateFps() mLastFrameTime = now; m_tracer->endSection(); } -} // namespace rive_android +} // namespace rive_android \ No newline at end of file diff --git a/kotlin/src/main/cpp/test/CMakeLists.txt b/kotlin/src/main/cpp/test/CMakeLists.txt new file mode 100644 index 00000000..56692010 --- /dev/null +++ b/kotlin/src/main/cpp/test/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.18.1) + +project(example LANGUAGES CXX VERSION 0.0.1) + +include(FetchContent) + +FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v3.3.2 +) + +FetchContent_MakeAvailable(Catch2) + +set(CMAKE_CXX_FLAGS "-std=c++17 -Wall -fno-exceptions -fno-rtti -Oz") +set(CMAKE_CXX_FLAGS_DEBUG "-g") +set(CMAKE_CXX_FLAGS_RELEASE "-Oz") +set(CMAKE_VERBOSE_MAKEFILE ON) + +set(SKIA_DIR_NAME "skia") +set(RIVE_ANDROID_CPP_DIR "${PROJECT_SOURCE_DIR}/../") +set(RIVE_RUNTIME_DIR "${PROJECT_SOURCE_DIR}/../../../runtime") + +add_library(rive-android-lib SHARED IMPORTED) +set_target_properties(rive-android-lib + PROPERTIES IMPORTED_LOCATION + ${CMAKE_CURRENT_SOURCE_DIR}/output/ninja/arm64-v8a/librive-android.so +) +add_executable(example_test_suite first_test.cpp) +target_link_libraries(example_test_suite PRIVATE + rive-android-lib + Catch2::Catch2WithMain +) + +list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras) + +include_directories( + ${RIVE_ANDROID_CPP_DIR}/include + ${RIVE_RUNTIME_DIR}/include + ${RIVE_RUNTIME_DIR}/renderer/library/include + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/ + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/include/core + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/include/effects + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/include/gpu + ${RIVE_RUNTIME_DIR}/skia/dependencies/${SKIA_DIR_NAME}/include/config + ${RIVE_RUNTIME_DIR}/skia/renderer/include +) diff --git a/kotlin/src/main/cpp/test/first_test.cpp b/kotlin/src/main/cpp/test/first_test.cpp new file mode 100644 index 00000000..b0cfe77e --- /dev/null +++ b/kotlin/src/main/cpp/test/first_test.cpp @@ -0,0 +1,53 @@ +// 010-TestCase.cpp +// And write tests in the same file: +#include +#include "helpers/egl_worker.hpp" + +using namespace rive_android; + +static int Factorial(int number) +{ + // return number <= 1 ? number : Factorial(number - 1) * number; // fail + return number <= 1 ? 1 : Factorial(number - 1) * number; // pass +} + +TEST_CASE("Factorial of 0 is 1 (fail)", "[single-file]") { REQUIRE(Factorial(0) == 1); } + +TEST_CASE("Factorials of 1 and higher are computed (pass)", "[single-file]") +{ + rive::rcp worker = EGLWorker::Current(); + printf("AM I ALIVE?!\n"); + // worker->run([=](EGLShareThreadState* ts) { printf("I am alive!?\n"); }); + REQUIRE(Factorial(1) == 1); + REQUIRE(Factorial(2) == 2); + REQUIRE(Factorial(3) == 6); + REQUIRE(Factorial(10) == 3628800); + printf("RELEASE...?\n"); + worker.release(); + printf("RELEASED!\n"); +} + +TEST_CASE("Test something in the Android world??", "[single-file]") +{ + REQUIRE(Factorial(1) == 1); + REQUIRE(Factorial(2) == 2); + REQUIRE(Factorial(3) == 6); + REQUIRE(Factorial(10) == 3628800); +} + +// Compile & run: +// - g++ -std=c++14 -Wall -I$(CATCH_SINGLE_INCLUDE) -o first_test first_test.cpp && first_test +// --success +// - g++ -std=c++14 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 010-TestCase 010-TestCase.cpp && 010-TestCase +// --success +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 010-TestCase.cpp && 010-TestCase --success + +// Expected compact output (all assertions): +// +// prompt> 010-TestCase --reporter compact --success +// 010-TestCase.cpp:14: failed: Factorial(0) == 1 for: 0 == 1 +// 010-TestCase.cpp:18: passed: Factorial(1) == 1 for: 1 == 1 +// 010-TestCase.cpp:19: passed: Factorial(2) == 2 for: 2 == 2 +// 010-TestCase.cpp:20: passed: Factorial(3) == 6 for: 6 == 6 +// 010-TestCase.cpp:21: passed: Factorial(10) == 3628800 for: 3628800 (0x375f00) == 3628800 +// (0x375f00) Failed 1 test case, failed 1 assertion. \ No newline at end of file diff --git a/kotlin/src/main/cpp/test/run_android_tests.sh b/kotlin/src/main/cpp/test/run_android_tests.sh new file mode 100755 index 00000000..a3179ab3 --- /dev/null +++ b/kotlin/src/main/cpp/test/run_android_tests.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +cd /data/local/tmp +export LD_LIBRARY_PATH="$PWD" +./example_test_suite +cd - +exit 0 diff --git a/kotlin/src/main/cpp/test/test.sh b/kotlin/src/main/cpp/test/test.sh new file mode 100755 index 00000000..2db21a57 --- /dev/null +++ b/kotlin/src/main/cpp/test/test.sh @@ -0,0 +1,138 @@ +#!/bin/bash +set -ex + +CONNECTED_ABI=$(adb shell getprop ro.product.cpu.abi) + +if [ ! "$CONNECTED_ABI" ]; then + echo "No devices connected?" + exit 1 +fi + +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + HOST_TAG=linux-x86_64 +elif [[ "$OSTYPE" == "darwin"* ]]; then + HOST_TAG=darwin-x86_64 +fi + +if [[ "$OSTYPE" == "darwin"* ]]; then + EXPECTED_NDK_VERSION=$(tr <../.ndk_version -d " \t\n\r") +else + EXPECTED_NDK_VERSION=$(tr <../.ndk_version.bots -d " \t\n\r") +fi + +# NDK_PATH must be set +if [[ -z ${NDK_PATH+x} ]]; then + echo "NDK_PATH is unset, should be somewhere like /Users//Library/Android/sdk/ndk/${EXPECTED_NDK_VERSION}" + exit 1 +# Check NDK version +elif [[ ${NDK_PATH} != *${EXPECTED_NDK_VERSION}* ]]; then + echo "Wrong NDK version" + echo "Expected: /Users//Library/Android/sdk/ndk/${EXPECTED_NDK_VERSION}" + echo " For bot builds, googles NDK distros" + echo " we are currently using: https://github.com/android/ndk/wiki/Unsupported-Downloads, you should be able to get android-ndk-r25b-darwin" + echo " For human builds" + echo " - open android studio" + echo " - settings search for android sdk, then SDK tools" + echo " - check "show package details" at the bottom" + echo " - select ${EXPECTED_NDK_VERSION} in NDK (Side by Side)" + echo "Found ${NDK_PATH}" + exit 1 +fi + +# Build our Android Library with CMake +CMAKE_BUILD_TREE=${PWD}/build +LIB_OUTPUT="${PWD}/output/ninja/${CONNECTED_ABI}" + +mkdir -p "$LIB_OUTPUT" +mkdir -p build + +pushd build + +"${ANDROID_HOME}"/cmake/3.22.1/bin/cmake \ + -H/Users/umbertosonnino/Projects/rive/packages/runtime_android/cpp \ + -DCMAKE_SYSTEM_NAME=Android \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_SYSTEM_VERSION=21 \ + -DANDROID_PLATFORM=android-21 \ + -DANDROID_ABI="${CONNECTED_ABI}" \ + -DCMAKE_ANDROID_ARCH_ABI="${CONNECTED_ABI}" \ + -DANDROID_NDK="$NDK_PATH" \ + -DCMAKE_ANDROID_NDK="$NDK_PATH" \ + -DCMAKE_TOOLCHAIN_FILE="$NDK_PATH"/build/cmake/android.toolchain.cmake \ + -DCMAKE_MAKE_PROGRAM="${ANDROID_HOME}"/cmake/3.22.1/bin/ninja \ + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="${LIB_OUTPUT}" \ + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY="${LIB_OUTPUT}" \ + -DCMAKE_BUILD_TYPE=Debug \ + -B"${CMAKE_BUILD_TREE}" \ + -GNinja \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DANDROID_ALLOW_UNDEFINED_SYMBOLS=ON \ + -DANDROID_CPP_FEATURES="no-exceptions no-rtti" \ + -DANDROID_STL=c++_shared + +pushd "${CMAKE_BUILD_TREE}" +cmake --build . +popd + +popd + +TEST_BUILD=build_catch_tests +mkdir -p ${TEST_BUILD} + +"${ANDROID_HOME}"/cmake/3.22.1/bin/cmake \ + -H. \ + -DCMAKE_SYSTEM_NAME=Android \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_SYSTEM_VERSION=21 \ + -DANDROID_PLATFORM=android-21 \ + -DANDROID_ABI="${CONNECTED_ABI}" \ + -DCMAKE_ANDROID_ARCH_ABI="${CONNECTED_ABI}" \ + -DANDROID_NDK="$NDK_PATH" \ + -DCMAKE_ANDROID_NDK="$NDK_PATH" \ + -DCMAKE_TOOLCHAIN_FILE="$NDK_PATH"/build/cmake/android.toolchain.cmake \ + -DCMAKE_MAKE_PROGRAM="${ANDROID_HOME}"/cmake/3.22.1/bin/ninja \ + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="${TEST_BUILD}" \ + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY="${TEST_BUILD}" \ + -DCMAKE_BUILD_TYPE=Debug \ + -B"${TEST_BUILD}" \ + -GNinja \ + -DCMAKE_VERBOSE_MAKEFILE=1 \ + -DANDROID_ALLOW_UNDEFINED_SYMBOLS=ON \ + -DANDROID_CPP_FEATURES="no-exceptions no-rtti" \ + -DANDROID_STL=c++_shared + +pushd ${TEST_BUILD} +cmake --build . +popd + +SYSROOT="$NDK_PATH/toolchains/llvm/prebuilt/$HOST_TAG/sysroot" +LIBCXX= + +case "${CONNECTED_ABI}" in +"x86") + echo "Lithuanian" + LIBCXX=$SYSROOT/usr/lib/i686-linux-android + ;; +"x86_64") + LIBCXX=$SYSROOT/usr/lib/x86_64-linux-android + echo "Romanian" + ;; +"armeabi-v7a") + LIBCXX=$SYSROOT/usr/lib/arm-linux-androideabi + echo "Italian" + ;; +"arm64-v8a") + LIBCXX=$SYSROOT/usr/lib/aarch64-linux-android + echo "Italian" + ;; +*) + echo "Unknown ABI" + exit 1 + ;; +esac + +adb push "${LIBCXX}"/libc++_shared.so /data/local/tmp +adb push "${LIB_OUTPUT}"/librive-android.so /data/local/tmp +adb push build_catch_tests/build_catch_tests/example_test_suite /data/local/tmp +adb push run_android_tests.sh /data/local/tmp/ +adb shell "cd /data/local/tmp && ./run_android_tests.sh" diff --git a/kotlin/src/main/java/app/rive/runtime/kotlin/core/Rive.kt b/kotlin/src/main/java/app/rive/runtime/kotlin/core/Rive.kt index a5147457..9ccc5101 100644 --- a/kotlin/src/main/java/app/rive/runtime/kotlin/core/Rive.kt +++ b/kotlin/src/main/java/app/rive/runtime/kotlin/core/Rive.kt @@ -2,6 +2,7 @@ package app.rive.runtime.kotlin.core import android.content.Context import android.graphics.RectF +import android.util.Log import com.getkeepsafe.relinker.ReLinker object Rive { @@ -14,6 +15,7 @@ object Rive { ) private const val JNIRiveBridge = "jnirivebridge" + private const val RiveAndroid = "rive-android" /** * Initialises Rive. @@ -27,7 +29,10 @@ object Rive { fun init(context: Context) { // NOTE: loadLibrary also allows us to specify a version, something we might want to take // advantage of - ReLinker.loadLibrary(context, JNIRiveBridge) + ReLinker + .log { Log.d("ReLinkerLogs", "(${Thread.currentThread().id}) $it") } + .loadLibrary(context, RiveAndroid) +// .loadLibrary(context, JNIRiveBridge) initializeCppEnvironment() } diff --git a/submodules/rive-cpp b/submodules/rive-cpp index 2131b362..cf1b2642 160000 --- a/submodules/rive-cpp +++ b/submodules/rive-cpp @@ -1 +1 @@ -Subproject commit 2131b36260aecb1bc9bbc1cca099c0ed353ef5c0 +Subproject commit cf1b2642e760248445b38dd06cd4faae86b619b8