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