1
2 /*
3 * Copyright 2018 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkStream.h"
14 #include "include/core/SkSurface.h"
15 #include "include/core/SkTime.h"
16 #include "modules/skresources/include/SkResources.h"
17 #include <jni.h>
18 #include <math.h>
19 #include <string>
20 #include <utility>
21
22 #include "include/gpu/GrBackendSurface.h"
23 #include "include/gpu/GrContextOptions.h"
24 #include "include/gpu/GrDirectContext.h"
25 #include "include/gpu/gl/GrGLInterface.h"
26 #include "include/gpu/gl/GrGLTypes.h"
27
28 #include "modules/skottie/include/Skottie.h"
29 #include "modules/sksg/include/SkSGInvalidationController.h"
30
31 #include <GLES2/gl2.h>
32 #include <GLES2/gl2ext.h>
33
34 #include <GLES3/gl3.h>
35
36 #define STENCIL_BUFFER_SIZE 8
37
38 /*#define ATRACE_NAME(name) ScopedTrace ___tracer(name)
39
40 // ATRACE_CALL is an ATRACE_NAME that uses the current function name.
41 #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
42 namespace {
43 class ScopedTrace {
44 public:
45 inline ScopedTrace(const char *name) {
46 ATrace_beginSection(name);
47 }
48
49 inline ~ScopedTrace() {
50 ATrace_endSection();
51 }
52 };
53
54 }*/
55
56 //disable atrace
57 #define ATRACE_NAME(name)
58 #define ATRACE_CALL()
59
60 struct SkottieRunner {
61 sk_sp<GrDirectContext> mDContext;
62 };
63
64 static JavaVM* sJVM = nullptr;
65
release_global_jni_ref(const void *,void * context)66 static void release_global_jni_ref(const void* /*data*/, void* context) {
67 JNIEnv* env;
68 if (sJVM->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
69 SK_ABORT("Attempting to release a JNI ref on a thread without a JVM attached.");
70 }
71 jobject obj = reinterpret_cast<jobject>(context);
72 env->DeleteGlobalRef(obj);
73 }
74
75 extern "C" JNIEXPORT jlong
76 JNICALL
Java_org_skia_skottie_SkottieRunner_nCreateProxy(JNIEnv * env,jclass clazz)77 Java_org_skia_skottie_SkottieRunner_nCreateProxy(JNIEnv *env, jclass clazz) {
78 sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
79 if (!glInterface.get()) {
80 return 0;
81 }
82
83 GrContextOptions options;
84 options.fDisableDistanceFieldPaths = true;
85 sk_sp<GrDirectContext> dContext = GrDirectContext::MakeGL(std::move(glInterface), options);
86 if (!dContext.get()) {
87 return 0;
88 }
89
90 SkottieRunner* skottie = new SkottieRunner();
91 skottie->mDContext = std::move(dContext);
92
93 return (jlong) skottie;
94 }
95
96 extern "C" JNIEXPORT void
97 JNICALL
Java_org_skia_skottie_SkottieRunner_nDeleteProxy(JNIEnv * env,jclass clazz,jlong nativeProxy)98 Java_org_skia_skottie_SkottieRunner_nDeleteProxy(JNIEnv *env, jclass clazz, jlong nativeProxy) {
99 if (!nativeProxy) {
100 return;
101 }
102 SkottieRunner* skottie = reinterpret_cast<SkottieRunner*>(nativeProxy);
103 if (skottie->mDContext) {
104 skottie->mDContext->releaseResourcesAndAbandonContext();
105 skottie->mDContext.reset();
106 }
107 delete skottie;
108 }
109
110
111 extern "C" JNIEXPORT void
112 JNICALL
Java_org_skia_skottie_SkottieRunner_nSetMaxCacheSize(JNIEnv * env,jclass clazz,jint maxCacheSize,jlong nativeProxy)113 Java_org_skia_skottie_SkottieRunner_nSetMaxCacheSize(JNIEnv *env, jclass clazz, jint maxCacheSize,
114 jlong nativeProxy) {
115 if (!nativeProxy) {
116 return;
117 }
118 SkottieRunner* skottie = reinterpret_cast<SkottieRunner*>(nativeProxy);
119 if (skottie->mDContext) {
120 skottie->mDContext->setResourceCacheLimit(maxCacheSize);
121 }
122 }
123
124 struct SkottieAnimation {
125 SkottieRunner *mRunner;
126 std::unique_ptr<SkStream> mStream;
127 sk_sp<skottie::Animation> mAnimation;
128 long mTimeBase;
129 float mDuration; //in milliseconds
130 };
131
132 extern "C" JNIEXPORT jlong
133 JNICALL
Java_org_skia_skottie_SkottieAnimation_nCreateProxy(JNIEnv * env,jobject clazz,jlong runner,jobject bufferObj)134 Java_org_skia_skottie_SkottieAnimation_nCreateProxy(JNIEnv *env,
135 jobject clazz,
136 jlong runner,
137 jobject bufferObj) {
138
139 if (!runner) {
140 return 0;
141 }
142 SkottieRunner *skottieRunner = reinterpret_cast<SkottieRunner*>(runner);
143
144 const void* buffer = env->GetDirectBufferAddress(bufferObj);
145 jlong bufferSize = env->GetDirectBufferCapacity(bufferObj);
146 if (buffer == nullptr || bufferSize <= 0) {
147 return 0;
148 }
149
150 env->GetJavaVM(&sJVM);
151 jobject bufferRef = env->NewGlobalRef(bufferObj);
152 if (bufferRef == nullptr) {
153 return 0;
154 }
155
156 sk_sp<SkData> data(SkData::MakeWithProc(buffer, bufferSize, release_global_jni_ref,
157 reinterpret_cast<void*>(bufferRef)));
158 std::unique_ptr<SkStream> stream = SkMemoryStream::Make(data);
159 if (!stream.get()) {
160 // Cannot create a stream
161 return 0;
162 }
163
164 SkottieAnimation* skottieAnimation = new SkottieAnimation();
165 skottieAnimation->mRunner = skottieRunner;
166 skottieAnimation->mStream = std::move(stream);
167
168 skottieAnimation->mAnimation = skottie::Animation::Builder()
169 .setResourceProvider(skresources::DataURIResourceProviderProxy::Make(nullptr))
170 .make(skottieAnimation->mStream.get());
171 skottieAnimation->mTimeBase = 0.0f; // force a time reset
172 skottieAnimation->mDuration = 1000 * skottieAnimation->mAnimation->duration();
173
174 if (!skottieAnimation->mAnimation) {
175 //failed to load Bodymovin animation
176 delete skottieAnimation;
177 return 0;
178 }
179
180 return (jlong) skottieAnimation;
181 }
182
183 extern "C" JNIEXPORT void
184 JNICALL
Java_org_skia_skottie_SkottieAnimation_nDeleteProxy(JNIEnv * env,jclass clazz,jlong nativeProxy)185 Java_org_skia_skottie_SkottieAnimation_nDeleteProxy(JNIEnv *env, jclass clazz,
186 jlong nativeProxy) {
187 if (!nativeProxy) {
188 return;
189 }
190 SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy);
191 delete skottieAnimation;
192 }
193
194 extern "C" JNIEXPORT bool
195 JNICALL
Java_org_skia_skottie_SkottieAnimation_nDrawFrame(JNIEnv * env,jclass clazz,jlong nativeProxy,jint width,jint height,jboolean wideColorGamut,jfloat progress,jint backgroundColor,jboolean forceDraw)196 Java_org_skia_skottie_SkottieAnimation_nDrawFrame(JNIEnv *env, jclass clazz,
197 jlong nativeProxy, jint width,
198 jint height,
199 jboolean wideColorGamut,
200 jfloat progress,
201 jint backgroundColor,
202 jboolean forceDraw) {
203 ATRACE_NAME("SkottieDrawFrame");
204 if (!nativeProxy) {
205 return false;
206 }
207 SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy);
208
209 auto dContext = skottieAnimation->mRunner->mDContext.get();
210
211 if (!dContext) {
212 return false;
213 }
214
215 sksg::InvalidationController ic;
216
217 if (skottieAnimation->mAnimation) {
218 skottieAnimation->mAnimation->seek(progress, &ic);
219 if (!forceDraw && ic.bounds().isEmpty()) {
220 return false;
221 }
222 }
223
224 SkColorType colorType;
225 // setup surface for fbo0
226 GrGLFramebufferInfo fboInfo;
227 fboInfo.fFBOID = 0;
228 if (wideColorGamut) {
229 fboInfo.fFormat = GL_RGBA16F;
230 colorType = kRGBA_F16_SkColorType;
231 } else {
232 fboInfo.fFormat = GL_RGBA8;
233 colorType = kN32_SkColorType;
234 }
235 GrBackendRenderTarget backendRT(width, height, 0, STENCIL_BUFFER_SIZE, fboInfo);
236
237 SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
238
239 sk_sp<SkSurface> renderTarget(SkSurface::MakeFromBackendRenderTarget(
240 dContext, backendRT, kBottomLeft_GrSurfaceOrigin, colorType,
241 nullptr, &props));
242
243 auto canvas = renderTarget->getCanvas();
244 canvas->clear(backgroundColor);
245
246 SkAutoCanvasRestore acr(canvas, true);
247 SkRect bounds = SkRect::MakeWH(width, height);
248 skottieAnimation->mAnimation->render(canvas, &bounds);
249
250 canvas->flush();
251 return true;
252 }
253
254 extern "C" JNIEXPORT jlong
255 JNICALL
Java_org_skia_skottie_SkottieAnimation_nGetDuration(JNIEnv * env,jclass clazz,jlong nativeProxy)256 Java_org_skia_skottie_SkottieAnimation_nGetDuration(JNIEnv *env,
257 jclass clazz,
258 jlong nativeProxy) {
259 if (!nativeProxy) {
260 return 0;
261 }
262 SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy);
263 return (jlong) skottieAnimation->mDuration;
264 }
265