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