1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "ThreadedRenderer"
18
19#include <algorithm>
20
21#include "jni.h"
22#include <nativehelper/JNIHelp.h>
23#include <android_runtime/AndroidRuntime.h>
24
25#include <EGL/egl.h>
26#include <EGL/eglext.h>
27#include <EGL/egl_cache.h>
28
29#include <utils/StrongPointer.h>
30#include <android_runtime/android_view_Surface.h>
31#include <system/window.h>
32
33#include "android_view_GraphicBuffer.h"
34
35#include <Animator.h>
36#include <AnimationContext.h>
37#include <IContextFactory.h>
38#include <RenderNode.h>
39#include <renderthread/CanvasContext.h>
40#include <renderthread/RenderProxy.h>
41#include <renderthread/RenderTask.h>
42#include <renderthread/RenderThread.h>
43#include <Vector.h>
44
45namespace android {
46
47#ifdef USE_OPENGL_RENDERER
48
49using namespace android::uirenderer;
50using namespace android::uirenderer::renderthread;
51
52static JNIEnv* getenv(JavaVM* vm) {
53    JNIEnv* env;
54    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
55        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
56    }
57    return env;
58}
59
60class OnFinishedEvent {
61public:
62    OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
63            : animator(animator), listener(listener) {}
64    sp<BaseRenderNodeAnimator> animator;
65    sp<AnimationListener> listener;
66};
67
68class InvokeAnimationListeners : public MessageHandler {
69public:
70    InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) {
71        mOnFinishedEvents.swap(events);
72    }
73
74    static void callOnFinished(OnFinishedEvent& event) {
75        event.listener->onAnimationFinished(event.animator.get());
76    }
77
78    virtual void handleMessage(const Message& message) {
79        std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished);
80        mOnFinishedEvents.clear();
81    }
82
83private:
84    std::vector<OnFinishedEvent> mOnFinishedEvents;
85};
86
87class RenderingException : public MessageHandler {
88public:
89    RenderingException(JavaVM* vm, const std::string& message)
90            : mVm(vm)
91            , mMessage(message) {
92    }
93
94    virtual void handleMessage(const Message&) {
95        throwException(mVm, mMessage);
96    }
97
98    static void throwException(JavaVM* vm, const std::string& message) {
99        JNIEnv* env = getenv(vm);
100        jniThrowException(env, "java/lang/IllegalStateException", message.c_str());
101    }
102
103private:
104    JavaVM* mVm;
105    std::string mMessage;
106};
107
108class RootRenderNode : public RenderNode, ErrorHandler {
109public:
110    RootRenderNode(JNIEnv* env) : RenderNode() {
111        mLooper = Looper::getForThread();
112        LOG_ALWAYS_FATAL_IF(!mLooper.get(),
113                "Must create RootRenderNode on a thread with a looper!");
114        env->GetJavaVM(&mVm);
115    }
116
117    virtual ~RootRenderNode() {}
118
119    virtual void onError(const std::string& message) {
120        mLooper->sendMessage(new RenderingException(mVm, message), 0);
121    }
122
123    virtual void prepareTree(TreeInfo& info) {
124        info.errorHandler = this;
125        RenderNode::prepareTree(info);
126        info.errorHandler = NULL;
127    }
128
129    void sendMessage(const sp<MessageHandler>& handler) {
130        mLooper->sendMessage(handler, 0);
131    }
132
133    void attachAnimatingNode(RenderNode* animatingNode) {
134        mPendingAnimatingRenderNodes.push_back(animatingNode);
135    }
136
137    void doAttachAnimatingNodes(AnimationContext* context) {
138        for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) {
139            RenderNode* node = mPendingAnimatingRenderNodes[i].get();
140            context->addAnimatingRenderNode(*node);
141        }
142        mPendingAnimatingRenderNodes.clear();
143    }
144
145private:
146    sp<Looper> mLooper;
147    JavaVM* mVm;
148    std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
149};
150
151class AnimationContextBridge : public AnimationContext {
152public:
153    AnimationContextBridge(renderthread::TimeLord& clock, RootRenderNode* rootNode)
154            : AnimationContext(clock), mRootNode(rootNode) {
155    }
156
157    virtual ~AnimationContextBridge() {}
158
159    // Marks the start of a frame, which will update the frame time and move all
160    // next frame animations into the current frame
161    virtual void startFrame(TreeInfo::TraversalMode mode) {
162        if (mode == TreeInfo::MODE_FULL) {
163            mRootNode->doAttachAnimatingNodes(this);
164        }
165        AnimationContext::startFrame(mode);
166    }
167
168    // Runs any animations still left in mCurrentFrameAnimations
169    virtual void runRemainingAnimations(TreeInfo& info) {
170        AnimationContext::runRemainingAnimations(info);
171        postOnFinishedEvents();
172    }
173
174    virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
175        OnFinishedEvent event(animator, listener);
176        mOnFinishedEvents.push_back(event);
177    }
178
179    virtual void destroy() {
180        AnimationContext::destroy();
181        postOnFinishedEvents();
182    }
183
184private:
185    sp<RootRenderNode> mRootNode;
186    std::vector<OnFinishedEvent> mOnFinishedEvents;
187
188    void postOnFinishedEvents() {
189        if (mOnFinishedEvents.size()) {
190            sp<InvokeAnimationListeners> message
191                    = new InvokeAnimationListeners(mOnFinishedEvents);
192            mRootNode->sendMessage(message);
193        }
194    }
195};
196
197class ContextFactoryImpl : public IContextFactory {
198public:
199    ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {}
200
201    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
202        return new AnimationContextBridge(clock, mRootNode);
203    }
204
205private:
206    RootRenderNode* mRootNode;
207};
208
209static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
210        jlong proxyPtr, jobject graphicBuffer, jlongArray atlasMapArray) {
211    sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
212    jsize len = env->GetArrayLength(atlasMapArray);
213    if (len <= 0) {
214        ALOGW("Failed to initialize atlas, invalid map length: %d", len);
215        return;
216    }
217    int64_t* map = new int64_t[len];
218    env->GetLongArrayRegion(atlasMapArray, 0, len, map);
219
220    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
221    proxy->setTextureAtlas(buffer, map, len);
222}
223
224static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
225    RootRenderNode* node = new RootRenderNode(env);
226    node->incStrong(0);
227    node->setName("RootRenderNode");
228    return reinterpret_cast<jlong>(node);
229}
230
231static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
232        jboolean translucent, jlong rootRenderNodePtr) {
233    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
234    ContextFactoryImpl factory(rootRenderNode);
235    return (jlong) new RenderProxy(translucent, rootRenderNode, &factory);
236}
237
238static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
239        jlong proxyPtr) {
240    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
241    delete proxy;
242}
243
244static void android_view_ThreadedRenderer_setFrameInterval(JNIEnv* env, jobject clazz,
245        jlong proxyPtr, jlong frameIntervalNanos) {
246    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
247    proxy->setFrameInterval(frameIntervalNanos);
248}
249
250static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
251        jlong proxyPtr) {
252    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
253    return proxy->loadSystemProperties();
254}
255
256static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
257        jlong proxyPtr, jobject jsurface) {
258    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
259    sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
260    return proxy->initialize(window);
261}
262
263static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
264        jlong proxyPtr, jobject jsurface) {
265    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
266    sp<ANativeWindow> window;
267    if (jsurface) {
268        window = android_view_Surface_getNativeWindow(env, jsurface);
269    }
270    proxy->updateSurface(window);
271}
272
273static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
274        jlong proxyPtr, jobject jsurface) {
275    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
276    sp<ANativeWindow> window;
277    if (jsurface) {
278        window = android_view_Surface_getNativeWindow(env, jsurface);
279    }
280    return proxy->pauseSurface(window);
281}
282
283static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
284        jint width, jint height,
285        jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius,
286        jint ambientShadowAlpha, jint spotShadowAlpha) {
287    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
288    proxy->setup(width, height, (Vector3){lightX, lightY, lightZ}, lightRadius,
289            ambientShadowAlpha, spotShadowAlpha);
290}
291
292static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
293        jlong proxyPtr, jboolean opaque) {
294    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
295    proxy->setOpaque(opaque);
296}
297
298static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
299        jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) {
300    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
301    return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density);
302}
303
304static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
305        jlong proxyPtr) {
306    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
307    proxy->destroy();
308}
309
310static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,
311        jlong rootNodePtr, jlong animatingNodePtr) {
312    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
313    RenderNode* animatingNode = reinterpret_cast<RenderNode*>(animatingNodePtr);
314    rootRenderNode->attachAnimatingNode(animatingNode);
315}
316
317static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
318        jlong functorPtr, jboolean waitForCompletion) {
319    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
320    RenderProxy::invokeFunctor(functor, waitForCompletion);
321}
322
323static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
324        jlong proxyPtr) {
325    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
326    DeferredLayerUpdater* layer = proxy->createTextureLayer();
327    return reinterpret_cast<jlong>(layer);
328}
329
330static void android_view_ThreadedRenderer_buildLayer(JNIEnv* env, jobject clazz,
331        jlong proxyPtr, jlong nodePtr) {
332    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
333    RenderNode* node = reinterpret_cast<RenderNode*>(nodePtr);
334    proxy->buildLayer(node);
335}
336
337static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
338        jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
339    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
340    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
341    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
342    return proxy->copyLayerInto(layer, bitmap);
343}
344
345static void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz,
346        jlong proxyPtr, jlong layerPtr) {
347    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
348    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
349    proxy->pushLayerUpdate(layer);
350}
351
352static void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz,
353        jlong proxyPtr, jlong layerPtr) {
354    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
355    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
356    proxy->cancelLayerUpdate(layer);
357}
358
359static void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobject clazz,
360        jlong proxyPtr, jlong layerPtr) {
361    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
362    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
363    proxy->detachSurfaceTexture(layer);
364}
365
366static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
367        jlong proxyPtr) {
368    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
369    proxy->destroyHardwareResources();
370}
371
372static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
373        jint level) {
374    RenderProxy::trimMemory(level);
375}
376
377static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
378        jlong proxyPtr) {
379    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
380    proxy->fence();
381}
382
383static void android_view_ThreadedRenderer_stopDrawing(JNIEnv* env, jobject clazz,
384        jlong proxyPtr) {
385    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
386    proxy->stopDrawing();
387}
388
389static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
390        jlong proxyPtr) {
391    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
392    proxy->notifyFramePending();
393}
394
395static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
396        jlong proxyPtr, jobject javaFileDescriptor) {
397    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
398    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
399    proxy->dumpProfileInfo(fd);
400}
401
402#endif
403
404// ----------------------------------------------------------------------------
405// Shaders
406// ----------------------------------------------------------------------------
407
408static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
409        jstring diskCachePath) {
410
411    const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
412    egl_cache_t::get()->setCacheFilename(cacheArray);
413    env->ReleaseStringUTFChars(diskCachePath, cacheArray);
414}
415
416// ----------------------------------------------------------------------------
417// JNI Glue
418// ----------------------------------------------------------------------------
419
420const char* const kClassPathName = "android/view/ThreadedRenderer";
421
422static JNINativeMethod gMethods[] = {
423#ifdef USE_OPENGL_RENDERER
424    { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
425    { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
426    { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
427    { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
428    { "nSetFrameInterval", "(JJ)V", (void*) android_view_ThreadedRenderer_setFrameInterval },
429    { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
430    { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
431    { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
432    { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
433    { "nSetup", "(JIIFFFFII)V", (void*) android_view_ThreadedRenderer_setup },
434    { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
435    { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
436    { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
437    { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
438    { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
439    { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
440    { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
441    { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
442    { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
443    { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
444    { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
445    { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources },
446    { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory },
447    { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
448    { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
449    { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
450    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
451#endif
452    { "setupShadersDiskCache", "(Ljava/lang/String;)V",
453                (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
454};
455
456int register_android_view_ThreadedRenderer(JNIEnv* env) {
457    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
458}
459
460}; // namespace android
461