|  | /* | 
|  | * Copyright (C) 2022 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. | 
|  | */ | 
|  |  | 
|  | #include <SkMesh.h> | 
|  |  | 
|  | #include "GraphicsJNI.h" | 
|  | #include "graphics_jni_helpers.h" | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | using Attribute = SkMeshSpecification::Attribute; | 
|  | using Varying = SkMeshSpecification::Varying; | 
|  |  | 
|  | static struct { | 
|  | jclass clazz{}; | 
|  | jfieldID type{}; | 
|  | jfieldID offset{}; | 
|  | jfieldID name{}; | 
|  | } gAttributeInfo; | 
|  |  | 
|  | static struct { | 
|  | jclass clazz{}; | 
|  | jfieldID type{}; | 
|  | jfieldID name{}; | 
|  | } gVaryingInfo; | 
|  |  | 
|  | std::vector<Attribute> extractAttributes(JNIEnv* env, jobjectArray attributes) { | 
|  | int size = env->GetArrayLength(attributes); | 
|  | std::vector<Attribute> attVector; | 
|  | attVector.reserve(size); | 
|  | for (int i = 0; i < size; i++) { | 
|  | jobject attribute = env->GetObjectArrayElement(attributes, i); | 
|  | auto name = (jstring)env->GetObjectField(attribute, gAttributeInfo.name); | 
|  | auto attName = ScopedUtfChars(env, name); | 
|  | Attribute temp{Attribute::Type(env->GetIntField(attribute, gAttributeInfo.type)), | 
|  | static_cast<size_t>(env->GetIntField(attribute, gAttributeInfo.offset)), | 
|  | SkString(attName.c_str())}; | 
|  | attVector.push_back(std::move(temp)); | 
|  | } | 
|  | return attVector; | 
|  | } | 
|  |  | 
|  | std::vector<Varying> extractVaryings(JNIEnv* env, jobjectArray varyings) { | 
|  | int size = env->GetArrayLength(varyings); | 
|  | std::vector<Varying> varyVector; | 
|  | varyVector.reserve(size); | 
|  | for (int i = 0; i < size; i++) { | 
|  | jobject varying = env->GetObjectArrayElement(varyings, i); | 
|  | auto name = (jstring)env->GetObjectField(varying, gVaryingInfo.name); | 
|  | auto varyName = ScopedUtfChars(env, name); | 
|  | Varying temp{Varying::Type(env->GetIntField(varying, gVaryingInfo.type)), | 
|  | SkString(varyName.c_str())}; | 
|  | varyVector.push_back(std::move(temp)); | 
|  | } | 
|  |  | 
|  | return varyVector; | 
|  | } | 
|  |  | 
|  | static jlong Make(JNIEnv* env, jobject thiz, jobjectArray attributeArray, jint vertexStride, | 
|  | jobjectArray varyingArray, jstring vertexShader, jstring fragmentShader) { | 
|  | auto attributes = extractAttributes(env, attributeArray); | 
|  | auto varyings = extractVaryings(env, varyingArray); | 
|  | auto skVertexShader = ScopedUtfChars(env, vertexShader); | 
|  | auto skFragmentShader = ScopedUtfChars(env, fragmentShader); | 
|  | auto meshSpecResult = SkMeshSpecification::Make(attributes, vertexStride, varyings, | 
|  | SkString(skVertexShader.c_str()), | 
|  | SkString(skFragmentShader.c_str())); | 
|  | if (meshSpecResult.specification.get() == nullptr) { | 
|  | jniThrowException(env, "java/lang/IllegalArgumentException", meshSpecResult.error.c_str()); | 
|  | } | 
|  |  | 
|  | return reinterpret_cast<jlong>(meshSpecResult.specification.release()); | 
|  | } | 
|  |  | 
|  | static jlong MakeWithCS(JNIEnv* env, jobject thiz, jobjectArray attributeArray, jint vertexStride, | 
|  | jobjectArray varyingArray, jstring vertexShader, jstring fragmentShader, | 
|  | jlong colorSpace) { | 
|  | auto attributes = extractAttributes(env, attributeArray); | 
|  | auto varyings = extractVaryings(env, varyingArray); | 
|  | auto skVertexShader = ScopedUtfChars(env, vertexShader); | 
|  | auto skFragmentShader = ScopedUtfChars(env, fragmentShader); | 
|  | auto meshSpecResult = SkMeshSpecification::Make( | 
|  | attributes, vertexStride, varyings, SkString(skVertexShader.c_str()), | 
|  | SkString(skFragmentShader.c_str()), GraphicsJNI::getNativeColorSpace(colorSpace)); | 
|  |  | 
|  | if (meshSpecResult.specification.get() == nullptr) { | 
|  | jniThrowException(env, "java/lang/IllegalArgumentException", meshSpecResult.error.c_str()); | 
|  | } | 
|  |  | 
|  | return reinterpret_cast<jlong>(meshSpecResult.specification.release()); | 
|  | } | 
|  |  | 
|  | static jlong MakeWithAlpha(JNIEnv* env, jobject thiz, jobjectArray attributeArray, | 
|  | jint vertexStride, jobjectArray varyingArray, jstring vertexShader, | 
|  | jstring fragmentShader, jlong colorSpace, jint alphaType) { | 
|  | auto attributes = extractAttributes(env, attributeArray); | 
|  | auto varyings = extractVaryings(env, varyingArray); | 
|  | auto skVertexShader = ScopedUtfChars(env, vertexShader); | 
|  | auto skFragmentShader = ScopedUtfChars(env, fragmentShader); | 
|  | auto meshSpecResult = SkMeshSpecification::Make( | 
|  | attributes, vertexStride, varyings, SkString(skVertexShader.c_str()), | 
|  | SkString(skFragmentShader.c_str()), GraphicsJNI::getNativeColorSpace(colorSpace), | 
|  | SkAlphaType(alphaType)); | 
|  |  | 
|  | if (meshSpecResult.specification.get() == nullptr) { | 
|  | jniThrowException(env, "java/lang/IllegalArgumentException", meshSpecResult.error.c_str()); | 
|  | } | 
|  |  | 
|  | return reinterpret_cast<jlong>(meshSpecResult.specification.release()); | 
|  | } | 
|  |  | 
|  | static void MeshSpecification_safeUnref(SkMeshSpecification* meshSpec) { | 
|  | SkSafeUnref(meshSpec); | 
|  | } | 
|  |  | 
|  | static jlong getMeshSpecificationFinalizer() { | 
|  | return static_cast<jlong>(reinterpret_cast<uintptr_t>(&MeshSpecification_safeUnref)); | 
|  | } | 
|  |  | 
|  | static const JNINativeMethod gMeshSpecificationMethods[] = { | 
|  | {"nativeGetFinalizer", "()J", (void*)getMeshSpecificationFinalizer}, | 
|  | {"nativeMake", | 
|  | "([Landroid/graphics/MeshSpecification$Attribute;I[Landroid/graphics/" | 
|  | "MeshSpecification$Varying;" | 
|  | "Ljava/lang/String;Ljava/lang/String;)J", | 
|  | (void*)Make}, | 
|  | {"nativeMakeWithCS", | 
|  | "([Landroid/graphics/MeshSpecification$Attribute;I" | 
|  | "[Landroid/graphics/MeshSpecification$Varying;Ljava/lang/String;Ljava/lang/String;J)J", | 
|  | (void*)MakeWithCS}, | 
|  | {"nativeMakeWithAlpha", | 
|  | "([Landroid/graphics/MeshSpecification$Attribute;I" | 
|  | "[Landroid/graphics/MeshSpecification$Varying;Ljava/lang/String;Ljava/lang/String;JI)J", | 
|  | (void*)MakeWithAlpha}}; | 
|  |  | 
|  | int register_android_graphics_MeshSpecification(JNIEnv* env) { | 
|  | android::RegisterMethodsOrDie(env, "android/graphics/MeshSpecification", | 
|  | gMeshSpecificationMethods, NELEM(gMeshSpecificationMethods)); | 
|  |  | 
|  | gAttributeInfo.clazz = env->FindClass("android/graphics/MeshSpecification$Attribute"); | 
|  | gAttributeInfo.type = env->GetFieldID(gAttributeInfo.clazz, "mType", "I"); | 
|  | gAttributeInfo.offset = env->GetFieldID(gAttributeInfo.clazz, "mOffset", "I"); | 
|  | gAttributeInfo.name = env->GetFieldID(gAttributeInfo.clazz, "mName", "Ljava/lang/String;"); | 
|  |  | 
|  | gVaryingInfo.clazz = env->FindClass("android/graphics/MeshSpecification$Varying"); | 
|  | gVaryingInfo.type = env->GetFieldID(gVaryingInfo.clazz, "mType", "I"); | 
|  | gVaryingInfo.name = env->GetFieldID(gVaryingInfo.clazz, "mName", "Ljava/lang/String;"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | }  // namespace android |