jni_skqp.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. #include <mutex>
  8. #include <android/asset_manager.h>
  9. #include <android/asset_manager_jni.h>
  10. #include <jni.h>
  11. #include <sys/stat.h>
  12. #include "include/core/SkStream.h"
  13. #include "include/private/SkTo.h"
  14. #include "tools/ResourceFactory.h"
  15. #include "tools/skqp/src/skqp.h"
  16. ////////////////////////////////////////////////////////////////////////////////
  17. extern "C" {
  18. JNIEXPORT void JNICALL Java_org_skia_skqp_SkQP_nInit(JNIEnv*, jobject, jobject, jstring);
  19. JNIEXPORT jlong JNICALL Java_org_skia_skqp_SkQP_nExecuteGM(JNIEnv*, jobject, jint, jint);
  20. JNIEXPORT jobjectArray JNICALL Java_org_skia_skqp_SkQP_nExecuteUnitTest(JNIEnv*, jobject, jint);
  21. JNIEXPORT void JNICALL Java_org_skia_skqp_SkQP_nMakeReport(JNIEnv*, jobject);
  22. } // extern "C"
  23. ////////////////////////////////////////////////////////////////////////////////
  24. static AAssetManager* gAAssetManager = nullptr;
  25. static sk_sp<SkData> open_asset_data(const char* path) {
  26. sk_sp<SkData> data;
  27. if (gAAssetManager) {
  28. if (AAsset* asset = AAssetManager_open(gAAssetManager, path, AASSET_MODE_STREAMING)) {
  29. if (size_t size = SkToSizeT(AAsset_getLength(asset))) {
  30. data = SkData::MakeUninitialized(size);
  31. int ret = AAsset_read(asset, data->writable_data(), size);
  32. if (ret != SkToInt(size)) {
  33. SkDebugf("ERROR: AAsset_read != AAsset_getLength (%s)\n", path);
  34. }
  35. }
  36. AAsset_close(asset);
  37. }
  38. }
  39. return data;
  40. }
  41. namespace {
  42. struct AndroidAssetManager : public SkQPAssetManager {
  43. sk_sp<SkData> open(const char* path) override { return open_asset_data(path); }
  44. };
  45. }
  46. // TODO(halcanary): Should not have global variables; SkQP Java object should
  47. // own pointers and manage concurency.
  48. static AndroidAssetManager gAndroidAssetManager;
  49. static std::mutex gMutex;
  50. static SkQP gSkQP;
  51. #define jassert(env, cond, ret) do { if (!(cond)) { \
  52. (env)->ThrowNew((env)->FindClass("java/lang/Exception"), \
  53. __FILE__ ": assert(" #cond ") failed."); \
  54. return ret; } } while (0)
  55. static void set_string_array_element(JNIEnv* env, jobjectArray a, const char* s, unsigned i) {
  56. jstring jstr = env->NewStringUTF(s);
  57. jassert(env, jstr != nullptr,);
  58. env->SetObjectArrayElement(a, (jsize)i, jstr);
  59. env->DeleteLocalRef(jstr);
  60. }
  61. ////////////////////////////////////////////////////////////////////////////////
  62. sk_sp<SkData> get_resource(const char* resource) {
  63. return open_asset_data((std::string("resources/") + resource).c_str());
  64. }
  65. ////////////////////////////////////////////////////////////////////////////////
  66. template <typename T, typename F>
  67. jobjectArray to_java_string_array(JNIEnv* env,
  68. const std::vector<T>& array,
  69. F toString) {
  70. jclass stringClass = env->FindClass("java/lang/String");
  71. jassert(env, stringClass, nullptr);
  72. jobjectArray jarray = env->NewObjectArray((jint)array.size(), stringClass, nullptr);
  73. jassert(env, jarray != nullptr, nullptr);
  74. for (unsigned i = 0; i < array.size(); ++i) {
  75. set_string_array_element(env, jarray, std::string(toString(array[i])).c_str(), i);
  76. }
  77. return jarray;
  78. }
  79. static std::string to_string(JNIEnv* env, jstring jString) {
  80. const char* utf8String = env->GetStringUTFChars(jString, nullptr);
  81. jassert(env, utf8String && utf8String[0], "");
  82. std::string sString(utf8String);
  83. env->ReleaseStringUTFChars(jString, utf8String);
  84. return sString;
  85. }
  86. void Java_org_skia_skqp_SkQP_nInit(JNIEnv* env, jobject object, jobject assetManager,
  87. jstring dataDir) {
  88. jclass SkQP_class = env->GetObjectClass(object);
  89. // tools/Resources
  90. gResourceFactory = &get_resource;
  91. std::string reportDirectory = to_string(env, dataDir);
  92. jassert(env, assetManager,);
  93. // This global must be set before using AndroidAssetManager
  94. gAAssetManager = AAssetManager_fromJava(env, assetManager);
  95. jassert(env, gAAssetManager,);
  96. std::lock_guard<std::mutex> lock(gMutex);
  97. gSkQP.init(&gAndroidAssetManager, reportDirectory.c_str());
  98. auto backends = gSkQP.getSupportedBackends();
  99. jassert(env, backends.size() > 0,);
  100. auto gms = gSkQP.getGMs();
  101. jassert(env, gms.size() > 0,);
  102. auto unitTests = gSkQP.getUnitTests();
  103. jassert(env, unitTests.size() > 0,);
  104. constexpr char kStringArrayType[] = "[Ljava/lang/String;";
  105. env->SetObjectField(object, env->GetFieldID(SkQP_class, "mBackends", kStringArrayType),
  106. to_java_string_array(env, backends, SkQP::GetBackendName));
  107. env->SetObjectField(object, env->GetFieldID(SkQP_class, "mUnitTests", kStringArrayType),
  108. to_java_string_array(env, unitTests, SkQP::GetUnitTestName));
  109. env->SetObjectField(object, env->GetFieldID(SkQP_class, "mGMs", kStringArrayType),
  110. to_java_string_array(env, gms, SkQP::GetGMName));
  111. }
  112. jlong Java_org_skia_skqp_SkQP_nExecuteGM(JNIEnv* env,
  113. jobject object,
  114. jint gmIndex,
  115. jint backendIndex) {
  116. SkQP::RenderOutcome outcome;
  117. std::string except;
  118. {
  119. std::lock_guard<std::mutex> lock(gMutex);
  120. jassert(env, backendIndex < (jint)gSkQP.getSupportedBackends().size(), -1);
  121. jassert(env, gmIndex < (jint)gSkQP.getGMs().size(), -1);
  122. SkQP::SkiaBackend backend = gSkQP.getSupportedBackends()[backendIndex];
  123. SkQP::GMFactory gm = gSkQP.getGMs()[gmIndex];
  124. std::tie(outcome, except) = gSkQP.evaluateGM(backend, gm);
  125. }
  126. if (!except.empty()) {
  127. (void)env->ThrowNew(env->FindClass("org/skia/skqp/SkQPException"), except.c_str());
  128. }
  129. return (jlong)outcome.fTotalError;
  130. }
  131. jobjectArray Java_org_skia_skqp_SkQP_nExecuteUnitTest(JNIEnv* env,
  132. jobject object,
  133. jint index) {
  134. std::vector<std::string> errors;
  135. {
  136. jassert(env, index < (jint)gSkQP.getUnitTests().size(), nullptr);
  137. std::lock_guard<std::mutex> lock(gMutex);
  138. errors = gSkQP.executeTest(gSkQP.getUnitTests()[index]);
  139. }
  140. if (errors.size() == 0) {
  141. return nullptr;
  142. }
  143. jclass stringClass = env->FindClass("java/lang/String");
  144. jassert(env, stringClass, nullptr);
  145. jobjectArray array = env->NewObjectArray(errors.size(), stringClass, nullptr);
  146. for (unsigned i = 0; i < errors.size(); ++i) {
  147. set_string_array_element(env, array, errors[i].c_str(), i);
  148. }
  149. return (jobjectArray)env->NewGlobalRef(array);
  150. }
  151. void Java_org_skia_skqp_SkQP_nMakeReport(JNIEnv*, jobject) {
  152. std::lock_guard<std::mutex> lock(gMutex);
  153. gSkQP.makeReport();
  154. }
  155. ////////////////////////////////////////////////////////////////////////////////