diff --git a/.ccls b/.ccls index 7ce6ab1c0..f37e98609 100644 --- a/.ccls +++ b/.ccls @@ -16,5 +16,6 @@ -I/c/Users/axsau/Programming/lib/vcpkg/installed/x64-linux/include/ -I./src/include/ -I./single_include/ +-I./vk_ndk_wrapper_include/ -I./test/compiled_shaders_include/ diff --git a/CMakeLists.txt b/CMakeLists.txt index c70a56317..c374887ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ -cmake_minimum_required(VERSION 3.17.0) +cmake_minimum_required(VERSION 3.4.1) project(kompute VERSION 0.3.0) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 14) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_VERBOSE_MAKEFILE on) @@ -11,7 +11,11 @@ option(KOMPUTE_OPT_BUILD_TESTS "Enable if you want to build tests" 0) option(KOMPUTE_OPT_BUILD_DOCS "Enable if you want to build documentation" 0) option(KOMPUTE_OPT_BUILD_SHADERS "Enable if you want to re-build all shader files" 0) option(KOMPUTE_OPT_BUILD_SINGLE_HEADER "Enable if you want to build the single header file" 0) +option(KOMPUTE_OPT_INSTALL "Enable if you want to enable installation" 1) option(KOMPUTE_OPT_ENABLE_SPDLOG "Extra compile flags for Kompute, see docs for full list" 0) +option(KOMPUTE_OPT_ANDOID_BUILD "Enable android compilation flags required" 0) +# TODO: Add on docs +option(KOMPUTE_OPT_DISABLE_VK_DEBUG_LAYERS "Explicitly disable debug layers even on debug" 0) set(KOMPUTE_EXTRA_CXX_FLAGS "" CACHE STRING "Extra compile flags for Kompute, see docs for full list") @@ -19,7 +23,15 @@ if(KOMPUTE_OPT_ENABLE_SPDLOG) set(KOMPUTE_EXTRA_CXX_FLAGS "${KOMPUTE_EXTRA_CXX_FLAGS} -DKOMPUTE_ENABLE_SPDLOG=1") endif() -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG=1 ${KOMPUTE_EXTRA_CXX_FLAGS}") +if(KOMPUTE_OPT_ANDOID_BUILD) + set(KOMPUTE_EXTRA_CXX_FLAGS "${KOMPUTE_EXTRA_CXX_FLAGS} -DVK_USE_PLATFORM_ANDROID_KHR") +endif() + +if(KOMPUTE_OPT_DISABLE_VK_DEBUG_LAYERS) + set(KOMPUTE_EXTRA_CXX_FLAGS "${KOMPUTE_EXTRA_CXX_FLAGS} -DKOMPUTE_DISABLE_VK_DEBUG_LAYERS=1") +endif() + +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG=1 ${KOMPUTE_EXTRA_CXX_FLAGS} -DUSE_DEBUG_EXTENTIONS") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DRELEASE=1 ${KOMPUTE_EXTRA_CXX_FLAGS}") # Allow scripts to call main kompute Makefile diff --git a/docs/images/android-editor.jpg b/docs/images/android-editor.jpg new file mode 100755 index 000000000..c071ea743 Binary files /dev/null and b/docs/images/android-editor.jpg differ diff --git a/docs/images/android-kompute.jpg b/docs/images/android-kompute.jpg new file mode 100755 index 000000000..3348a1508 Binary files /dev/null and b/docs/images/android-kompute.jpg differ diff --git a/examples/android/android-simple/.gitignore b/examples/android/android-simple/.gitignore new file mode 100644 index 000000000..f23ff3a66 --- /dev/null +++ b/examples/android/android-simple/.gitignore @@ -0,0 +1,11 @@ +.idea +.DS_Store +.gradle +build +*.iml +*~ +local.properties +.externalNativeBuild +.cxx +.cdep +cdep.sha256 diff --git a/examples/android/android-simple/README.md b/examples/android/android-simple/README.md new file mode 100644 index 000000000..5e8d53c45 --- /dev/null +++ b/examples/android/android-simple/README.md @@ -0,0 +1,31 @@ + + + + + + + + + + + +
+

Vulkan Kompute Android

+

Example Running Logistic Regression with Vulkan Kompute in Android Phones

+ +

+This example provides an end to end example that can be run using android studio. + +The example uses the Kompute build in the relative folder to build the respective binaries for android. + +The build structure provides a range of options to build in different Android hardware. This example was tested in various emulators including Pixel 2, and a physical Samsung S7 phone. +

+ + +
+ +
+ + + + diff --git a/examples/android/android-simple/app/build.gradle b/examples/android/android-simple/app/build.gradle new file mode 100644 index 000000000..3990324a3 --- /dev/null +++ b/examples/android/android-simple/app/build.gradle @@ -0,0 +1,71 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 29 + ndkVersion '21.2.6472646' + + defaultConfig { + applicationId "com.ethicalml.kompute" + minSdkVersion 23 + targetSdkVersion 29 + versionCode = 1 + versionName = "0.0.1" + externalNativeBuild { + cmake { + abiFilters "armeabi-v7a", 'arm64-v8a', 'x86', 'x86_64' + arguments '-DANDROID_TOOLCHAIN=clang', + '-DANDROID_STL=c++_static', + '-DKOMPUTE_OPT_ANDOID_BUILD=1', + '-DKOMPUTE_OPT_INSTALL=0', + '-DKOMPUTE_OPT_BUILD_SINGLE_HEADER=1', + '-DKOMPUTE_OPT_DISABLE_VK_DEBUG_LAYERS=1', + '-DKOMPUTE_EXTRA_CXX_FLAGS=-DKOMPUTE_VK_API_MINOR_VERSION=0' + } + } + } + + buildFeatures { + viewBinding true + } + buildTypes { + release { + minifyEnabled = false + proguardFiles getDefaultProguardFile('proguard-android.txt'), + 'proguard-rules.pro' + } + } + externalNativeBuild { + cmake { + path 'src/main/cpp/CMakeLists.txt' + } + } + + flavorDimensions 'cpuArch' + productFlavors { + arm8 { + dimension 'cpuArch' + ndk { + abiFilters 'arm64-v8a', 'armeabi-v7a' + } + } + x86_64 { + dimension 'cpuArch' + ndk { + abiFilters 'x86_64', 'x86' + } + } + universal { + dimension 'cpuArch' + // include all default ABIs. with NDK-r16, it is: + // armeabi-v7a, arm64-v8a, x86, x86_64 + } + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/examples/android/android-simple/app/proguard-rules.pro b/examples/android/android-simple/app/proguard-rules.pro new file mode 100644 index 000000000..b41fe70c7 --- /dev/null +++ b/examples/android/android-simple/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${ANDROID_SDK}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/examples/android/android-simple/app/src/main/AndroidManifest.xml b/examples/android/android-simple/app/src/main/AndroidManifest.xml new file mode 100755 index 000000000..4965abb44 --- /dev/null +++ b/examples/android/android-simple/app/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/examples/android/android-simple/app/src/main/assets/kompute.jpg b/examples/android/android-simple/app/src/main/assets/kompute.jpg new file mode 100755 index 000000000..e34ac98b0 Binary files /dev/null and b/examples/android/android-simple/app/src/main/assets/kompute.jpg differ diff --git a/examples/android/android-simple/app/src/main/assets/komputer-2.gif b/examples/android/android-simple/app/src/main/assets/komputer-2.gif new file mode 100644 index 000000000..b060632ab Binary files /dev/null and b/examples/android/android-simple/app/src/main/assets/komputer-2.gif differ diff --git a/examples/android/android-simple/app/src/main/cpp/CMakeLists.txt b/examples/android/android-simple/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 000000000..868be9ca7 --- /dev/null +++ b/examples/android/android-simple/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.4.1) + +add_subdirectory(../../../../../../../ ${CMAKE_CURRENT_BINARY_DIR}/kompute_build) + +set(VK_ANDROID_INCLUDE_DIR ${ANDROID_NDK}/sources/third_party/vulkan/src/include) + +add_library(kompute-jni SHARED + KomputeJniNative.cpp + KomputeModelML.cpp) + +include_directories( + ${VK_ANDROID_COMMON_DIR} + ${VK_ANDROID_INCLUDE_DIR} + ../../../../../../../single_include/ + ../../../../../../../vk_ndk_wrapper_include/) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 \ + -DVK_USE_PLATFORM_ANDROID_KHR=1 \ + -DKOMPUTE_DISABLE_VK_DEBUG_LAYERS=1") + +target_link_libraries(kompute-jni + # Libraries from kompute build + kompute + kompute_vk_ndk_wrapper + # Libraries from android build + log + android) \ No newline at end of file diff --git a/examples/android/android-simple/app/src/main/cpp/KomputeJniNative.cpp b/examples/android/android-simple/app/src/main/cpp/KomputeJniNative.cpp new file mode 100644 index 000000000..b15c89f3d --- /dev/null +++ b/examples/android/android-simple/app/src/main/cpp/KomputeJniNative.cpp @@ -0,0 +1,114 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// 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. + +#undef DEBUG +#define RELEASE 1 + +#include +#include + +#include +#include + +#include "kompute/Kompute.hpp" + +#include "KomputeModelML.hpp" + +#ifndef KOMPUTE_VK_INIT_RETRIES +#define KOMPUTE_VK_INIT_RETRIES 5 +#endif + +static std::vector jfloatArrayToVector(JNIEnv *env, const jfloatArray & fromArray) { + float *inCArray = env->GetFloatArrayElements(fromArray, NULL); + if (NULL == inCArray) return std::vector(); + int32_t length = env->GetArrayLength(fromArray); + + std::vector outVector(inCArray, inCArray + length); + return outVector; +} + +static jfloatArray vectorToJFloatArray(JNIEnv *env, const std::vector & fromVector) { + jfloatArray ret = env->NewFloatArray(fromVector.size()); + if (NULL == ret) return NULL; + env->SetFloatArrayRegion(ret, 0, fromVector.size(), fromVector.data()); + return ret; +} + +extern "C" { + +JNIEXPORT jboolean JNICALL +Java_com_ethicalml_kompute_KomputeJni_initVulkan(JNIEnv *env, jobject thiz) { + + SPDLOG_INFO("Initialising vulkan"); + + uint32_t totalRetries = 0; + + while (totalRetries < KOMPUTE_VK_INIT_RETRIES) { + SPDLOG_INFO("VULKAN LOAD TRY NUMBER: %u", totalRetries); + if(InitVulkan()) { + break; + } + sleep(1); + totalRetries++; + } + + return totalRetries < KOMPUTE_VK_INIT_RETRIES; +} + + +JNIEXPORT jfloatArray JNICALL +Java_com_ethicalml_kompute_KomputeJni_kompute( + JNIEnv *env, + jobject thiz, + jfloatArray xiJFloatArr, + jfloatArray xjJFloatArr, + jfloatArray yJFloatArr) { + + SPDLOG_INFO("Creating manager"); + + std::vector xiVector = jfloatArrayToVector(env, xiJFloatArr); + std::vector xjVector = jfloatArrayToVector(env, xjJFloatArr); + std::vector yVector = jfloatArrayToVector(env, yJFloatArr); + + KomputeModelML kml; + kml.train(yVector, xiVector, xjVector); + + std::vector pred = kml.predict(xiVector, xjVector); + + return vectorToJFloatArray(env, pred); +} + +JNIEXPORT jfloatArray JNICALL +Java_com_ethicalml_kompute_KomputeJni_komputeParams( + JNIEnv *env, + jobject thiz, + jfloatArray xiJFloatArr, + jfloatArray xjJFloatArr, + jfloatArray yJFloatArr) { + + SPDLOG_INFO("Creating manager"); + + std::vector xiVector = jfloatArrayToVector(env, xiJFloatArr); + std::vector xjVector = jfloatArrayToVector(env, xjJFloatArr); + std::vector yVector = jfloatArrayToVector(env, yJFloatArr); + + KomputeModelML kml; + kml.train(yVector, xiVector, xjVector); + + std::vector params = kml.get_params(); + + return vectorToJFloatArray(env, params); +} + +} diff --git a/examples/android/android-simple/app/src/main/cpp/KomputeModelML.cpp b/examples/android/android-simple/app/src/main/cpp/KomputeModelML.cpp new file mode 100755 index 000000000..3202764a2 --- /dev/null +++ b/examples/android/android-simple/app/src/main/cpp/KomputeModelML.cpp @@ -0,0 +1,131 @@ + +#include "KomputeModelML.hpp" + +KomputeModelML::KomputeModelML() { + +} + +KomputeModelML::~KomputeModelML() { + +} + +void KomputeModelML::train(std::vector yData, std::vector xIData, std::vector xJData) { + + std::vector zerosData; + + for (size_t i = 0; i < yData.size(); i++) { + zerosData.push_back(0); + } + + uint32_t ITERATIONS = 100; + float learningRate = 0.1; + + std::shared_ptr xI{ new kp::Tensor(xIData) }; + std::shared_ptr xJ{ new kp::Tensor(xJData) }; + + std::shared_ptr y{ new kp::Tensor(yData) }; + + std::shared_ptr wIn{ new kp::Tensor({ 0.001, 0.001 }) }; + std::shared_ptr wOutI{ new kp::Tensor(zerosData) }; + std::shared_ptr wOutJ{ new kp::Tensor(zerosData) }; + + std::shared_ptr bIn{ new kp::Tensor({ 0 }) }; + std::shared_ptr bOut{ new kp::Tensor(zerosData) }; + + std::shared_ptr lOut{ new kp::Tensor(zerosData) }; + + std::vector> params = { xI, xJ, y, + wIn, wOutI, wOutJ, + bIn, bOut, lOut }; + + { + kp::Manager mgr; + + if (std::shared_ptr sq = + mgr.getOrCreateManagedSequence("createTensors").lock()) { + + sq->begin(); + + sq->record(params); + + sq->end(); + sq->eval(); + + // Record op algo base + sq->begin(); + + sq->record({ wIn, bIn }); + +#ifdef KOMPUTE_ANDROID_SHADER_FROM_STRING + // Newer versions of Android are able to use shaderc to read raw string + sq->record>( + params, std::vector(LR_SHADER.begin(), LR_SHADER.end())); +#else + // Older versions of Android require the SPIRV binary directly + sq->record>( + params, std::vector( + kp::shader_data::shaders_glsl_logisticregression_comp_spv, + kp::shader_data::shaders_glsl_logisticregression_comp_spv + + kp::shader_data::shaders_glsl_logisticregression_comp_spv_len + )); +#endif + + sq->record({ wOutI, wOutJ, bOut, lOut }); + + sq->end(); + + // Iterate across all expected iterations + for (size_t i = 0; i < ITERATIONS; i++) { + + sq->eval(); + + for (size_t j = 0; j < bOut->size(); j++) { + wIn->data()[0] -= learningRate * wOutI->data()[j]; + wIn->data()[1] -= learningRate * wOutJ->data()[j]; + bIn->data()[0] -= learningRate * bOut->data()[j]; + } + } + } + } + + this->mWeights = kp::Tensor(wIn->data()); + this->mBias = kp::Tensor(bIn->data()); +} + +std::vector KomputeModelML::predict(std::vector xI, std::vector xJ) { + assert(xI.size() == xJ.size()); + + std::vector retVector; + + // We run the inference in the CPU for simplicity + // BUt you can also implement the inference on GPU + // GPU implementation would speed up minibatching + for (size_t i = 0; i < xI.size(); i++) { + float xIVal = xI[i]; + float xJVal = xJ[i]; + float result = (xIVal * this->mWeights.data()[0] + + xJVal * this->mWeights.data()[1] + + this->mBias.data()[0]); + + // Instead of using sigmoid we'll just return full numbers + float var = result > 0 ? 1 : 0; + retVector.push_back(var); + } + + return retVector; +} + +std::vector KomputeModelML::get_params() { + std::vector retVector; + + if(this->mWeights.size() + this->mBias.size() == 0) { + return retVector; + } + + retVector.push_back(this->mWeights.data()[0]); + retVector.push_back(this->mWeights.data()[1]); + retVector.push_back(this->mBias.data()[0]); + retVector.push_back(99.0); + + return retVector; +} diff --git a/examples/android/android-simple/app/src/main/cpp/KomputeModelML.hpp b/examples/android/android-simple/app/src/main/cpp/KomputeModelML.hpp new file mode 100755 index 000000000..335f05805 --- /dev/null +++ b/examples/android/android-simple/app/src/main/cpp/KomputeModelML.hpp @@ -0,0 +1,85 @@ + +#ifndef KOMPUTEMODELML_HPP +#define KOMPUTEMODELML_HPP + +#include +#include + +#include "kompute/Kompute.hpp" + +class KomputeModelML { + +public: + KomputeModelML(); + virtual ~KomputeModelML(); + + void train(std::vector yData, std::vector xIData, std::vector xJData); + + std::vector predict(std::vector xI, std::vector xJ); + + std::vector get_params(); + +private: + kp::Tensor mWeights; + kp::Tensor mBias; + +}; + +static std::string LR_SHADER = R"( +#version 450 + +layout (constant_id = 0) const uint M = 0; + +layout (local_size_x = 1) in; + +layout(set = 0, binding = 0) buffer bxi { float xi[]; }; +layout(set = 0, binding = 1) buffer bxj { float xj[]; }; +layout(set = 0, binding = 2) buffer by { float y[]; }; +layout(set = 0, binding = 3) buffer bwin { float win[]; }; +layout(set = 0, binding = 4) buffer bwouti { float wouti[]; }; +layout(set = 0, binding = 5) buffer bwoutj { float woutj[]; }; +layout(set = 0, binding = 6) buffer bbin { float bin[]; }; +layout(set = 0, binding = 7) buffer bbout { float bout[]; }; +layout(set = 0, binding = 8) buffer blout { float lout[]; }; + +float m = float(M); + +float sigmoid(float z) { + return 1.0 / (1.0 + exp(-z)); +} + +float inference(vec2 x, vec2 w, float b) { + // Compute the linear mapping function + float z = dot(w, x) + b; + // Calculate the y-hat with sigmoid + float yHat = sigmoid(z); + return yHat; +} + +float calculateLoss(float yHat, float y) { + return -(y * log(yHat) + (1.0 - y) * log(1.0 - yHat)); +} + +void main() { + uint idx = gl_GlobalInvocationID.x; + + vec2 wCurr = vec2(win[0], win[1]); + float bCurr = bin[0]; + + vec2 xCurr = vec2(xi[idx], xj[idx]); + float yCurr = y[idx]; + + float yHat = inference(xCurr, wCurr, bCurr); + + float dZ = yHat - yCurr; + vec2 dW = (1. / m) * xCurr * dZ; + float dB = (1. / m) * dZ; + wouti[idx] = dW.x; + woutj[idx] = dW.y; + bout[idx] = dB; + + lout[idx] = calculateLoss(yHat, yCurr); +} +)"; + +#endif //ANDROID_SIMPLE_KOMPUTEMODELML_HPP diff --git a/examples/android/android-simple/app/src/main/java/com/ethicalml/kompute/KomputeJni.kt b/examples/android/android-simple/app/src/main/java/com/ethicalml/kompute/KomputeJni.kt new file mode 100755 index 000000000..66808f434 --- /dev/null +++ b/examples/android/android-simple/app/src/main/java/com/ethicalml/kompute/KomputeJni.kt @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 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. + */ +package com.ethicalml.kompute + +import android.os.Bundle +import android.util.Log +import androidx.appcompat.app.AppCompatActivity +import android.widget.Toast +import android.view.View +import android.widget.EditText +import android.widget.TextView +import com.ethicalml.kompute.databinding.ActivityKomputeJniBinding + +class KomputeJni : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val binding = ActivityKomputeJniBinding.inflate(layoutInflater) + setContentView(binding.root) + + binding.komputeGifView.loadUrl("file:///android_asset/komputer-2.gif") + + binding.komputeGifView.getSettings().setUseWideViewPort(true) + binding.komputeGifView.getSettings().setLoadWithOverviewMode(true) + + val successVulkanInit = initVulkan() + if (successVulkanInit) { + Toast.makeText(applicationContext, "Vulkan Loaded SUCCESS", Toast.LENGTH_SHORT).show() + } else { + binding.KomputeButton.isEnabled = false + Toast.makeText(applicationContext, "Vulkan Load FAILED", Toast.LENGTH_SHORT).show() + } + Log.i("KomputeJni", "Vulkan Result: " + successVulkanInit) + + binding.predictionTextView.text = "N/A" + } + + fun KomputeButtonOnClick(v: View) { + + val xiEditText = findViewById(R.id.XIEditText) + val xjEditText = findViewById(R.id.XJEditText) + val yEditText = findViewById(R.id.YEditText) + + val wOneEditText = findViewById(R.id.wOneTextView) + val wTwoEditText = findViewById(R.id.wTwoTextView) + val biasEditText = findViewById(R.id.biasTextView) + + val komputeJniTextview = findViewById(R.id.predictionTextView) + + val xi = xiEditText.text.removeSurrounding("[", "]").split(",").map { it.toFloat() }.toFloatArray() + val xj = xjEditText.text.removeSurrounding("[", "]").split(",").map { it.toFloat() }.toFloatArray() + val y = yEditText.text.removeSurrounding("[", "]").split(",").map { it.toFloat() }.toFloatArray() + + val out = kompute(xi, xj, y) + + Log.i("KomputeJni", "RESULT:") + Log.i("KomputeJni", out.contentToString()) + + komputeJniTextview.text = out.contentToString() + + val params = komputeParams(xi, xj, y) + + Log.i("KomputeJni", "Params:") + Log.i("KomputeJni", params.contentToString()) + + wOneEditText.text = params[0].toString() + wTwoEditText.text = params[1].toString() + biasEditText.text = params[2].toString() + } + + external fun initVulkan(): Boolean + + external fun kompute(xi: FloatArray, xj: FloatArray, y: FloatArray): FloatArray + + external fun komputeParams(xi: FloatArray, xj: FloatArray, y: FloatArray): FloatArray + + companion object { + init { + System.loadLibrary("kompute-jni") + } + } +} + diff --git a/examples/android/android-simple/app/src/main/res/layout/activity_kompute_jni.xml b/examples/android/android-simple/app/src/main/res/layout/activity_kompute_jni.xml new file mode 100644 index 000000000..97b680177 --- /dev/null +++ b/examples/android/android-simple/app/src/main/res/layout/activity_kompute_jni.xml @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +