Unverified Commit ee8e4cc9 authored by Aleksandr Veselov's avatar Aleksandr Veselov Committed by GitHub

Implement native methods for RuntimeEffect (#331)

parent 36cd5f84
......@@ -29,8 +29,7 @@ jobs:
- shell: bash
run: |
cd $GITHUB_WORKSPACE/skiko
./gradlew jvmTest
./gradlew publishToMavenLocal
./gradlew -Pskiko.native.enabled=true jvmTest
./gradlew -Pskiko.native.enabled=true macosX64Test iosX64Test
./gradlew -Pskiko.native.enabled=true publishToMavenLocal
- uses: actions/upload-artifact@v2
......
......@@ -351,7 +351,20 @@ kotlin {
}
}
val nativeJsMain by creating {
dependsOn(commonMain)
}
val nativeJsTest by creating {
dependsOn(commonTest)
}
val jsMain by getting {
dependsOn(nativeJsMain)
}
val jsTest by getting {
dependsOn(nativeJsTest)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0")
implementation(kotlin("test-js"))
......@@ -361,13 +374,13 @@ kotlin {
if (supportNative) {
// See https://kotlinlang.org/docs/mpp-share-on-platforms.html#configure-the-hierarchical-structure-manually
val nativeMain by creating {
dependsOn(commonMain)
dependsOn(nativeJsMain)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
}
}
val nativeTest by creating {
dependsOn(commonTest)
dependsOn(nativeJsTest)
}
if (hostOs == OS.Linux) {
val linuxMain by creating {
......
......@@ -3,7 +3,7 @@ package org.jetbrains.skia
import org.jetbrains.skia.impl.*
import org.jetbrains.skia.impl.Library.Companion.staticLoad
class ManagedString internal constructor(ptr: NativePointer) : Managed(ptr, _FinalizerHolder.PTR) {
class ManagedString internal constructor(ptr: NativePointer, managed: Boolean = true) : Managed(ptr, _FinalizerHolder.PTR, managed) {
companion object {
init {
staticLoad()
......
......@@ -5,14 +5,18 @@ import org.jetbrains.skia.impl.Library.Companion.staticLoad
class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) {
companion object {
fun makeForShader(sksl: String?): RuntimeEffect {
fun makeForShader(sksl: String): RuntimeEffect {
Stats.onNativeCall()
return RuntimeEffect(_nMakeForShader(sksl))
return interopScope {
makeFromResultPtr(_nMakeForShader(toInterop(sksl)))
}
}
fun makeForColorFilter(sksl: String?): RuntimeEffect {
fun makeForColorFilter(sksl: String): RuntimeEffect {
Stats.onNativeCall()
return RuntimeEffect(_nMakeForColorFilter(sksl))
return interopScope {
makeFromResultPtr(_nMakeForColorFilter(toInterop(sksl)))
}
}
init {
......@@ -30,21 +34,34 @@ class RuntimeEffect internal constructor(ptr: NativePointer) : RefCnt(ptr) {
for (i in 0 until childCount) childrenPtrs[i] = getPtr(children!![i])
val matrix = localMatrix?.mat
return interopScope {
Shader(_nMakeShader(_ptr, getPtr(uniforms), toInterop(childrenPtrs), toInterop(matrix), isOpaque))
Shader(_nMakeShader(_ptr, getPtr(uniforms), toInterop(childrenPtrs), childCount, toInterop(matrix), isOpaque))
}
}
}
internal expect fun RuntimeEffect.Companion.makeFromResultPtr(ptr: NativePointer): RuntimeEffect
@ExternalSymbolName("org_jetbrains_skia_RuntimeEffect__1nMakeShader")
private external fun _nMakeShader(
runtimeEffectPtr: NativePointer, uniformPtr: NativePointer, childrenPtrs: InteropPointer,
localMatrix: InteropPointer, isOpaque: Boolean
childCount: Int, localMatrix: InteropPointer, isOpaque: Boolean
): NativePointer
@ExternalSymbolName("org_jetbrains_skia_RuntimeEffect__1nMakeForShader")
private external fun _nMakeForShader(sksl: String?): NativePointer
private external fun _nMakeForShader(sksl: InteropPointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_RuntimeEffect__1nMakeForColorFilter")
private external fun _nMakeForColorFilter(sksl: String?): NativePointer
private external fun _nMakeForColorFilter(sksl: InteropPointer): NativePointer
// The functions below can be used only in JS and native targets
@ExternalSymbolName("org_jetbrains_skia_RuntimeEffect__1Result_nGetPtr")
internal external fun Result_nGetPtr(ptr: NativePointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_RuntimeEffect__1Result_nGetError")
internal external fun Result_nGetError(ptr: NativePointer): NativePointer
@ExternalSymbolName("org_jetbrains_skia_RuntimeEffect__1Result_nDestroy")
internal external fun Result_nDestroy(ptr: NativePointer)
\ No newline at end of file
......@@ -109,12 +109,27 @@ inline fun withResult(result: NativePointerArray, block: (InteropPointer) -> Uni
result
}
/**
* Creates String from SkString* result and deletes SkString*.
*/
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
inline fun withStringResult(block: () -> NativePointer): String {
val string = ManagedString(block())
return string.toString()
}
/**
* Creates String from SkString* result. Caller must ensure pointer to be valid.
* It is caller responsibility to destroy underlying SkString. Use it if pointer
* is received from reference (SkString&)
*/
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
inline fun withStringReferenceResult(block: () -> NativePointer): String {
val string = ManagedString(block(), false)
return string.toString()
}
interface ArrayInteropDecoder<T> {
fun getArrayElement(array: InteropPointer, index: Int): T
fun getArraySize(array: InteropPointer): Int
......
package org.jetbrains.skia
import kotlin.test.Test
class RuntimeEffectTest {
@Test
fun canCreateShader() {
val shaderSKSL = """
|half4 main(float2 coord) {
| float t = coord.x / 128;
| half4 white = half4(1);
| half4 black = half4(0,0,0,1);
| return mix(white, black, t);
|}""".trimMargin()
val effect = RuntimeEffect.makeForShader(shaderSKSL)
val shader = effect.makeShader(null, null, null, true)
val shader2SKSL = """
|uniform shader input_1;
|half4 main(float2 coord) {
| return input_1.eval(coord).bgra;
|}""".trimMargin()
val derivedEffect = RuntimeEffect.makeForShader(shader2SKSL)
derivedEffect.makeShader(null, arrayOf(shader), null, false)
val colorFilterSKSL = """
|half4 main(half4 inColor) {
| return inColor.bgra;
|}""".trimMargin()
RuntimeEffect.makeForColorFilter(colorFilterSKSL)
}
}
\ No newline at end of file
......@@ -9,6 +9,7 @@ Java_org_jetbrains_skia_RuntimeEffectKt__1nMakeShader(JNIEnv* env,
jlong ptr,
jlong uniformPtr,
jlongArray childrenPtrsArr,
jint _childCount,
jfloatArray localMatrixArr,
jboolean isOpaque) {
SkRuntimeEffect* runtimeEffect = jlongToPtr<SkRuntimeEffect*>(ptr);
......
package org.jetbrains.skia
import org.jetbrains.skia.impl.NativePointer
internal actual fun RuntimeEffect.Companion.makeFromResultPtr(ptr: NativePointer): RuntimeEffect
= RuntimeEffect(ptr)
......@@ -5,75 +5,62 @@
#include "common.h"
SKIKO_EXPORT KNativePointer org_jetbrains_skia_RuntimeEffect__1nMakeShader
(KNativePointer ptr, KNativePointer uniformPtr, KNativePointer childrenPtrsArr, KFloat* localMatrixArr, KBoolean isOpaque) {
TODO("implement org_jetbrains_skia_RuntimeEffect__1nMakeShader");
}
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_RuntimeEffect__1nMakeShader
(KNativePointer ptr, KNativePointer uniformPtr, KNativePointerArray childrenPtrsArr, KFloat* localMatrixArr, KBoolean isOpaque) {
SkRuntimeEffect* runtimeEffect = KNativePointerToPtr<SkRuntimeEffect*>(ptr);
SkData* uniform = KNativePointerToPtr<SkData*>(uniformPtr);
std::unique_ptr<SkMatrix> localMatrix = skMatrix(env, localMatrixArr);
(KNativePointer ptr, KNativePointer uniformPtr, KNativePointerArray childrenPtrsArr, KInt childCount, KFloat* localMatrixArr, KBoolean isOpaque) {
SkRuntimeEffect* runtimeEffect = reinterpret_cast<SkRuntimeEffect*>(ptr);
SkData* uniform = reinterpret_cast<SkData*>(uniformPtr);
std::unique_ptr<SkMatrix> localMatrix = skMatrix(localMatrixArr);
jsize childCount = env->GetArrayLength(childrenPtrsArr);
KNativePointer* childrenPtrs = env->GetLongArrayElements(childrenPtrsArr, 0);
KNativePointer* childrenPtrs = reinterpret_cast<KNativePointer*>(childrenPtrsArr);
std::vector<sk_sp<SkShader>> children(childCount);
for (size_t i = 0; i < childCount; i++) {
SkShader* si = KNativePointerToPtr<SkShader*>(childrenPtrs[i]);
SkShader* si = reinterpret_cast<SkShader*>(childrenPtrs[i]);
children[i] = sk_ref_sp(si);
}
env->ReleaseLongArrayElements(childrenPtrsArr, childrenPtrs, 0);
sk_sp<SkShader> shader = runtimeEffect->makeShader(sk_ref_sp<SkData>(uniform),
children.data(),
childCount,
localMatrix.get(),
isOpaque);
return ptrToKNativePointer(shader.release());
return reinterpret_cast<KNativePointer>(shader.release());
}
#endif
SKIKO_EXPORT KNativePointer org_jetbrains_skia_RuntimeEffect__1nMakeForShader
(KInteropPointer sksl) {
TODO("implement org_jetbrains_skia_RuntimeEffect__1nMakeForShader");
SkString skslProper = skString(sksl);
SkRuntimeEffect::Result* result = new SkRuntimeEffect::Result {
SkRuntimeEffect::MakeForShader(skslProper)
};
return reinterpret_cast<KNativePointer>(result);
}
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_RuntimeEffect__1nMakeForShader
SKIKO_EXPORT KNativePointer org_jetbrains_skia_RuntimeEffect__1nMakeForColorFilter
(KInteropPointer sksl) {
SkString skslProper = skString(env, sksl);
SkRuntimeEffect::Result result = SkRuntimeEffect::MakeForShader(skslProper);
if (result.errorText.isEmpty()) {
sk_sp<SkRuntimeEffect> effect = result.effect;
return ptrToKNativePointer(effect.release());
} else {
env->ThrowNew(java::lang::RuntimeException::cls, result.errorText.c_str());
return 0;
}
SkString skslProper = skString(sksl);
SkRuntimeEffect::Result* result = new SkRuntimeEffect::Result {
SkRuntimeEffect::MakeForColorFilter(skslProper)
};
return reinterpret_cast<KNativePointer>(result);
}
#endif
SKIKO_EXPORT KNativePointer org_jetbrains_skia_RuntimeEffect__1nMakeForColorFilter
(KInteropPointer sksl) {
TODO("implement org_jetbrains_skia_RuntimeEffect__1nMakeForColorFilter");
// Result
SKIKO_EXPORT KNativePointer org_jetbrains_skia_RuntimeEffect__1Result_nGetPtr
(KNativePointer ptr) {
auto result = reinterpret_cast<SkRuntimeEffect::Result*>(ptr);
return reinterpret_cast<KNativePointer>(result->effect.release());
}
#if 0
SKIKO_EXPORT KNativePointer org_jetbrains_skia_RuntimeEffect__1nMakeForColorFilter
(KInteropPointer sksl) {
SkString skslProper = skString(env, sksl);
SkRuntimeEffect::Result result = SkRuntimeEffect::MakeForColorFilter(skslProper);
if (result.errorText.isEmpty()) {
return ptrToKNativePointer(result.effect.release());
SKIKO_EXPORT KNativePointer org_jetbrains_skia_RuntimeEffect__1Result_nGetError
(KNativePointer ptr) {
auto result = reinterpret_cast<SkRuntimeEffect::Result*>(ptr);
if (result->errorText.isEmpty()) {
return static_cast<KNativePointer>(nullptr);
} else {
env->ThrowNew(java::lang::RuntimeException::cls, result.errorText.c_str());
return 0;
return reinterpret_cast<KNativePointer>(&(result->errorText));
}
}
#endif
SKIKO_EXPORT void org_jetbrains_skia_RuntimeEffect__1Result_nDestroy
(KNativePointer ptr) {
delete reinterpret_cast<SkRuntimeEffect::Result*>(ptr);
}
package org.jetbrains.skia
import org.jetbrains.skia.impl.Native
import org.jetbrains.skia.impl.NativePointer
import org.jetbrains.skia.impl.withStringReferenceResult
internal actual fun RuntimeEffect.Companion.makeFromResultPtr(ptr: NativePointer): RuntimeEffect {
val errorPtr = Result_nGetError(ptr)
if (errorPtr == Native.NullPointer) {
val effectPtr = Result_nGetPtr(ptr)
Result_nDestroy(ptr)
return RuntimeEffect(effectPtr)
} else {
// Error string is owned by Result
val error = withStringReferenceResult { errorPtr }
Result_nDestroy(ptr)
throw Error(error)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment