android_view_ThreadedRenderer.cpp revision e4267ea4f20740c37c01bfb6aefcf61fddc4566a
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 <RenderNode.h>
37#include <renderthread/CanvasContext.h>
38#include <renderthread/RenderProxy.h>
39#include <renderthread/RenderTask.h>
40#include <renderthread/RenderThread.h>
41#include <Vector.h>
42
43namespace android {
44
45#ifdef USE_OPENGL_RENDERER
46
47using namespace android::uirenderer;
48using namespace android::uirenderer::renderthread;
49
50static jmethodID gRunnableMethod;
51
52class JavaTask : public RenderTask {
53public:
54    JavaTask(JNIEnv* env, jobject jrunnable) {
55        env->GetJavaVM(&mVm);
56        mRunnable = env->NewGlobalRef(jrunnable);
57    }
58
59    virtual void run() {
60        env()->CallVoidMethod(mRunnable, gRunnableMethod);
61        env()->DeleteGlobalRef(mRunnable);
62        delete this;
63    };
64
65private:
66    JNIEnv* env() {
67        JNIEnv* env;
68        if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
69            return 0;
70        }
71        return env;
72    }
73
74    JavaVM* mVm;
75    jobject mRunnable;
76};
77
78class SetAtlasTask : public RenderTask {
79public:
80    SetAtlasTask(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size)
81            : mBuffer(buffer)
82            , mMap(map)
83            , mMapSize(size) {
84    }
85
86    virtual void run() {
87        CanvasContext::setTextureAtlas(mBuffer, mMap, mMapSize);
88        mMap = 0;
89        delete this;
90    }
91
92private:
93    sp<GraphicBuffer> mBuffer;
94    int64_t* mMap;
95    size_t mMapSize;
96};
97
98class OnFinishedEvent {
99public:
100    OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
101            : animator(animator), listener(listener) {}
102    sp<BaseRenderNodeAnimator> animator;
103    sp<AnimationListener> listener;
104};
105
106class InvokeAnimationListeners : public MessageHandler {
107public:
108    InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) {
109        mOnFinishedEvents.swap(events);
110    }
111
112    static void callOnFinished(OnFinishedEvent& event) {
113        event.listener->onAnimationFinished(event.animator.get());
114    }
115
116    virtual void handleMessage(const Message& message) {
117        std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished);
118        mOnFinishedEvents.clear();
119    }
120
121private:
122    std::vector<OnFinishedEvent> mOnFinishedEvents;
123};
124
125class RootRenderNode : public RenderNode, public AnimationHook {
126public:
127    RootRenderNode() : RenderNode() {
128        mLooper = Looper::getForThread();
129        LOG_ALWAYS_FATAL_IF(!mLooper.get(),
130                "Must create RootRenderNode on a thread with a looper!");
131    }
132
133    virtual ~RootRenderNode() {}
134
135    virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
136        OnFinishedEvent event(animator, listener);
137        mOnFinishedEvents.push_back(event);
138    }
139
140    virtual void prepareTree(TreeInfo& info) {
141        info.animationHook = this;
142        RenderNode::prepareTree(info);
143        info.animationHook = NULL;
144
145        // post all the finished stuff
146        if (mOnFinishedEvents.size()) {
147            sp<InvokeAnimationListeners> message
148                    = new InvokeAnimationListeners(mOnFinishedEvents);
149            mLooper->sendMessage(message, 0);
150        }
151    }
152
153protected:
154    virtual void damageSelf(TreeInfo& info) {
155        // Intentionally a no-op. As RootRenderNode gets a new DisplayListData
156        // every frame this would result in every draw push being a full inval,
157        // which is wrong. Only RootRenderNode has this issue.
158    }
159
160private:
161    sp<Looper> mLooper;
162    std::vector<OnFinishedEvent> mOnFinishedEvents;
163};
164
165static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
166        jobject graphicBuffer, jlongArray atlasMapArray) {
167    sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
168    jsize len = env->GetArrayLength(atlasMapArray);
169    if (len <= 0) {
170        ALOGW("Failed to initialize atlas, invalid map length: %d", len);
171        return;
172    }
173    int64_t* map = new int64_t[len];
174    env->GetLongArrayRegion(atlasMapArray, 0, len, map);
175
176    SetAtlasTask* task = new SetAtlasTask(buffer, map, len);
177    RenderThread::getInstance().queue(task);
178}
179
180static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
181    RootRenderNode* node = new RootRenderNode();
182    node->incStrong(0);
183    node->setName("RootRenderNode");
184    return reinterpret_cast<jlong>(node);
185}
186
187static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
188        jboolean translucent, jlong rootRenderNodePtr) {
189    RenderNode* rootRenderNode = reinterpret_cast<RenderNode*>(rootRenderNodePtr);
190    return (jlong) new RenderProxy(translucent, rootRenderNode);
191}
192
193static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
194        jlong proxyPtr) {
195    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
196    delete proxy;
197}
198
199static void android_view_ThreadedRenderer_setFrameInterval(JNIEnv* env, jobject clazz,
200        jlong proxyPtr, jlong frameIntervalNanos) {
201    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
202    proxy->setFrameInterval(frameIntervalNanos);
203}
204
205static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
206        jlong proxyPtr) {
207    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
208    return proxy->loadSystemProperties();
209}
210
211static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
212        jlong proxyPtr, jobject jsurface) {
213    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
214    sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
215    return proxy->initialize(window);
216}
217
218static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
219        jlong proxyPtr, jobject jsurface) {
220    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
221    sp<ANativeWindow> window;
222    if (jsurface) {
223        window = android_view_Surface_getNativeWindow(env, jsurface);
224    }
225    proxy->updateSurface(window);
226}
227
228static void android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
229        jlong proxyPtr, jobject jsurface) {
230    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
231    sp<ANativeWindow> window;
232    if (jsurface) {
233        window = android_view_Surface_getNativeWindow(env, jsurface);
234    }
235    proxy->pauseSurface(window);
236}
237
238static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
239        jint width, jint height,
240        jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius) {
241    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
242    proxy->setup(width, height, Vector3(lightX, lightY, lightZ), lightRadius);
243}
244
245static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
246        jlong proxyPtr, jboolean opaque) {
247    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
248    proxy->setOpaque(opaque);
249}
250
251static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
252        jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) {
253    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
254    return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density);
255}
256
257static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
258        jlong proxyPtr) {
259    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
260    proxy->destroyCanvasAndSurface();
261}
262
263static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
264        jlong proxyPtr, jlong functorPtr, jboolean waitForCompletion) {
265    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
266    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
267    proxy->invokeFunctor(functor, waitForCompletion);
268}
269
270static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz,
271        jlong proxyPtr, jobject jrunnable) {
272    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
273    RenderTask* task = new JavaTask(env, jrunnable);
274    proxy->runWithGlContext(task);
275}
276
277static jlong android_view_ThreadedRenderer_createDisplayListLayer(JNIEnv* env, jobject clazz,
278        jlong proxyPtr, jint width, jint height) {
279    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
280    DeferredLayerUpdater* layer = proxy->createDisplayListLayer(width, height);
281    return reinterpret_cast<jlong>(layer);
282}
283
284static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
285        jlong proxyPtr) {
286    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
287    DeferredLayerUpdater* layer = proxy->createTextureLayer();
288    return reinterpret_cast<jlong>(layer);
289}
290
291static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
292        jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
293    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
294    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
295    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
296    return proxy->copyLayerInto(layer, bitmap);
297}
298
299static void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz,
300        jlong proxyPtr, jlong layerPtr) {
301    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
302    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
303    proxy->pushLayerUpdate(layer);
304}
305
306static void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz,
307        jlong proxyPtr, jlong layerPtr) {
308    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
309    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
310    proxy->cancelLayerUpdate(layer);
311}
312
313static void android_view_ThreadedRenderer_flushCaches(JNIEnv* env, jobject clazz,
314        jlong proxyPtr, jint flushMode) {
315    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
316    proxy->flushCaches(static_cast<Caches::FlushMode>(flushMode));
317}
318
319static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
320        jlong proxyPtr) {
321    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
322    proxy->fence();
323}
324
325static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
326        jlong proxyPtr) {
327    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
328    proxy->notifyFramePending();
329}
330
331static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
332        jlong proxyPtr, jobject javaFileDescriptor) {
333    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
334    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
335    proxy->dumpProfileInfo(fd);
336}
337
338#endif
339
340// ----------------------------------------------------------------------------
341// Shaders
342// ----------------------------------------------------------------------------
343
344static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
345        jstring diskCachePath) {
346
347    const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
348    egl_cache_t::get()->setCacheFilename(cacheArray);
349    env->ReleaseStringUTFChars(diskCachePath, cacheArray);
350}
351
352// ----------------------------------------------------------------------------
353// JNI Glue
354// ----------------------------------------------------------------------------
355
356const char* const kClassPathName = "android/view/ThreadedRenderer";
357
358static JNINativeMethod gMethods[] = {
359#ifdef USE_OPENGL_RENDERER
360    { "nSetAtlas", "(Landroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
361    { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
362    { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
363    { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
364    { "nSetFrameInterval", "(JJ)V", (void*) android_view_ThreadedRenderer_setFrameInterval },
365    { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
366    { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
367    { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
368    { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
369    { "nSetup", "(JIIFFFF)V", (void*) android_view_ThreadedRenderer_setup },
370    { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
371    { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
372    { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
373    { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
374    { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
375    { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
376    { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
377    { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
378    { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
379    { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
380    { "nFlushCaches", "(JI)V", (void*) android_view_ThreadedRenderer_flushCaches },
381    { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
382    { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
383    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
384#endif
385    { "setupShadersDiskCache", "(Ljava/lang/String;)V",
386                (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
387};
388
389int register_android_view_ThreadedRenderer(JNIEnv* env) {
390#ifdef USE_OPENGL_RENDERER
391    jclass cls = env->FindClass("java/lang/Runnable");
392    gRunnableMethod = env->GetMethodID(cls, "run", "()V");
393    env->DeleteLocalRef(cls);
394#endif
395    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
396}
397
398}; // namespace android
399