• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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