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