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