xref: /aosp_15_r20/external/skia/tools/skqp/src/jni_skqp.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include <mutex>
9 
10 #include <android/asset_manager.h>
11 #include <android/asset_manager_jni.h>
12 #include <jni.h>
13 #include <sys/stat.h>
14 
15 #include "include/core/SkStream.h"
16 #include "include/private/base/SkTo.h"
17 #include "src/utils/SkOSPath.h"
18 #include "tools/ResourceFactory.h"
19 
20 #include "tools/skqp/src/skqp.h"
21 
22 ////////////////////////////////////////////////////////////////////////////////
23 extern "C" {
24 JNIEXPORT void JNICALL Java_org_skia_skqp_SkQP_nInit(JNIEnv*, jobject, jobject, jstring);
25 JNIEXPORT jobjectArray JNICALL Java_org_skia_skqp_SkQP_nExecuteUnitTest(JNIEnv*, jobject, jint);
26 JNIEXPORT void JNICALL Java_org_skia_skqp_SkQP_nMakeReport(JNIEnv*, jobject);
27 }  // extern "C"
28 ////////////////////////////////////////////////////////////////////////////////
29 
30 static AAssetManager* sAAssetManager = nullptr;
31 
open_asset_data(const char * path)32 static sk_sp<SkData> open_asset_data(const char* path) {
33     sk_sp<SkData> data;
34     if (sAAssetManager) {
35         if (AAsset* asset = AAssetManager_open(sAAssetManager, path, AASSET_MODE_STREAMING)) {
36             if (size_t size = SkToSizeT(AAsset_getLength(asset))) {
37                 data = SkData::MakeUninitialized(size);
38                 int ret = AAsset_read(asset, data->writable_data(), size);
39                 if (ret != SkToInt(size)) {
40                     SK_ABORT("ERROR: AAsset_read != AAsset_getLength (%s)\n", path);
41                 }
42             }
43             AAsset_close(asset);
44         }
45     }
46     return data;
47 }
48 
49 namespace {
50 struct AndroidAssetManager : public SkQPAssetManager {
open__anon5028b0130111::AndroidAssetManager51     sk_sp<SkData> open(const char* path) override {
52         return open_asset_data(path);
53     }
54 
iterateDir__anon5028b0130111::AndroidAssetManager55     std::vector<std::string> iterateDir(const char* directory, const char* extension) override {
56         std::vector<std::string> paths;
57         AAssetDir* assetDir = AAssetManager_openDir(sAAssetManager, directory);
58 
59         while (const char* filename = AAssetDir_getNextFileName(assetDir)) {
60             const char* ext = strrchr(filename, '.');
61             if (!ext) {
62                 continue;
63             }
64             if (0 != strcasecmp(extension, ext)) {
65                 continue;
66             }
67             SkString path = SkOSPath::Join(directory, filename);
68             paths.push_back(path.c_str());
69         }
70 
71         AAssetDir_close(assetDir);
72         return paths;
73     }
74 };
75 }
76 
77 // TODO(halcanary): Should not have global variables; SkQP Java object should
78 // own pointers and manage concurency.
79 static AndroidAssetManager gAndroidAssetManager;
80 static std::mutex gMutex;
81 static SkQP gSkQP;
82 
83 #define jassert(env, cond, ret) do { if (!(cond)) { \
84     (env)->ThrowNew((env)->FindClass("java/lang/Exception"), \
85                     __FILE__ ": assert(" #cond ") failed."); \
86     return ret; } } while (0)
87 
88 ////////////////////////////////////////////////////////////////////////////////
89 
make_java_string_array(JNIEnv * env,jint arraySize)90 static jobjectArray make_java_string_array(JNIEnv* env, jint arraySize) {
91     jclass stringClass = env->FindClass("java/lang/String");
92     jassert(env, stringClass, nullptr);
93     jobjectArray jarray = env->NewObjectArray(arraySize, stringClass, nullptr);
94     jassert(env, jarray != nullptr, nullptr);
95     return jarray;
96 }
97 
set_string_array_element(JNIEnv * env,jobjectArray a,const char * s,unsigned i)98 static void set_string_array_element(JNIEnv* env, jobjectArray a, const char* s, unsigned i) {
99     jstring jstr = env->NewStringUTF(s);
100     jassert(env, jstr != nullptr,);
101     env->SetObjectArrayElement(a, (jsize)i, jstr);
102     env->DeleteLocalRef(jstr);
103 }
104 
105 template <typename T, typename F>
to_java_string_array(JNIEnv * env,const std::vector<T> & array,F stringizeFn)106 static jobjectArray to_java_string_array(JNIEnv* env,
107                                          const std::vector<T>& array,
108                                          F stringizeFn) {
109     jobjectArray jarray = make_java_string_array(env, (jint)array.size());
110     for (size_t i = 0; i < array.size(); ++i) {
111         set_string_array_element(env, jarray, stringizeFn(array[i]), i);
112     }
113     return jarray;
114 }
115 
to_string(JNIEnv * env,jstring jString)116 static std::string to_string(JNIEnv* env, jstring jString) {
117     const char* utf8String = env->GetStringUTFChars(jString, nullptr);
118     jassert(env, utf8String && utf8String[0], "");
119     std::string sString(utf8String);
120     env->ReleaseStringUTFChars(jString, utf8String);
121     return sString;
122 }
123 
get_sksl_error_name(const SkQP::SkSLErrorTest & t)124 static const char* get_sksl_error_name(const SkQP::SkSLErrorTest& t) {
125     return t.name.c_str();
126 }
127 
get_sksl_error_shader_text(const SkQP::SkSLErrorTest & t)128 static const char* get_sksl_error_shader_text(const SkQP::SkSLErrorTest& t) {
129     return t.shaderText.c_str();
130 }
131 
Java_org_skia_skqp_SkQP_nInit(JNIEnv * env,jobject object,jobject assetManager,jstring dataDir)132 void Java_org_skia_skqp_SkQP_nInit(JNIEnv* env, jobject object, jobject assetManager,
133                                    jstring dataDir) {
134     jclass SkQP_class = env->GetObjectClass(object);
135 
136     // tools/Resources
137     gResourceFactory = &open_asset_data;
138 
139     std::string reportDirectory = to_string(env, dataDir);
140 
141     jassert(env, assetManager,);
142     // This global must be set before using AndroidAssetManager
143     sAAssetManager = AAssetManager_fromJava(env, assetManager);
144     jassert(env, sAAssetManager,);
145 
146     std::lock_guard<std::mutex> lock(gMutex);
147     gSkQP.init(&gAndroidAssetManager, reportDirectory.c_str());
148 
149     const std::vector<SkQP::UnitTest>& unitTests = gSkQP.getUnitTests();
150     const std::vector<SkQP::SkSLErrorTest>& skslErrorTests = gSkQP.getSkSLErrorTests();
151 
152     constexpr char kStringArrayType[] = "[Ljava/lang/String;";
153     env->SetObjectField(object,
154                         env->GetFieldID(SkQP_class, "mUnitTests", kStringArrayType),
155                         to_java_string_array(env, unitTests, &SkQP::GetUnitTestName));
156     env->SetObjectField(object,
157                         env->GetFieldID(SkQP_class, "mSkSLErrorTestName", kStringArrayType),
158                         to_java_string_array(env, skslErrorTests, get_sksl_error_name));
159     env->SetObjectField(object,
160                         env->GetFieldID(SkQP_class, "mSkSLErrorTestShader", kStringArrayType),
161                         to_java_string_array(env, skslErrorTests, get_sksl_error_shader_text));
162 }
163 
Java_org_skia_skqp_SkQP_nExecuteUnitTest(JNIEnv * env,jobject object,jint index)164 jobjectArray Java_org_skia_skqp_SkQP_nExecuteUnitTest(JNIEnv* env,
165                                                       jobject object,
166                                                       jint index) {
167     std::vector<std::string> errors;
168     {
169         std::lock_guard<std::mutex> lock(gMutex);
170         jassert(env, index < (jint)gSkQP.getUnitTests().size(), nullptr);
171         errors = gSkQP.executeTest(gSkQP.getUnitTests()[index]);
172     }
173     if (errors.empty()) {
174         return nullptr;
175     }
176     jobjectArray array = make_java_string_array(env, errors.size());
177     for (size_t i = 0; i < errors.size(); ++i) {
178         set_string_array_element(env, array, errors[i].c_str(), i);
179     }
180     return (jobjectArray)env->NewGlobalRef(array);
181 }
182 
Java_org_skia_skqp_SkQP_nMakeReport(JNIEnv *,jobject)183 void Java_org_skia_skqp_SkQP_nMakeReport(JNIEnv*, jobject) {
184     std::lock_guard<std::mutex> lock(gMutex);
185     gSkQP.makeReport();
186 }
187 
188 ////////////////////////////////////////////////////////////////////////////////
189 
190