android_view_ThreadedRenderer.cpp revision 8afcc76920499d0a384dba1470c5a377f80ed768
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#include <atomic>
21
22#include "jni.h"
23#include <nativehelper/JNIHelp.h>
24#include "core_jni_helpers.h"
25#include <GraphicsJNI.h>
26#include <ScopedPrimitiveArray.h>
27
28#include <EGL/egl.h>
29#include <EGL/eglext.h>
30#include <EGL/egl_cache.h>
31#include <vulkan/vulkan_loader_data.h>
32
33#include <utils/Looper.h>
34#include <utils/RefBase.h>
35#include <utils/StrongPointer.h>
36#include <android_runtime/android_view_Surface.h>
37#include <system/window.h>
38
39#include "android_view_GraphicBuffer.h"
40#include "android_os_MessageQueue.h"
41
42#include <Animator.h>
43#include <AnimationContext.h>
44#include <FrameInfo.h>
45#include <FrameMetricsObserver.h>
46#include <IContextFactory.h>
47#include <JankTracker.h>
48#include <RenderNode.h>
49#include <renderthread/CanvasContext.h>
50#include <renderthread/RenderProxy.h>
51#include <renderthread/RenderTask.h>
52#include <renderthread/RenderThread.h>
53#include <Vector.h>
54
55namespace android {
56
57using namespace android::uirenderer;
58using namespace android::uirenderer::renderthread;
59
60struct {
61    jfieldID frameMetrics;
62    jfieldID timingDataBuffer;
63    jfieldID messageQueue;
64    jmethodID callback;
65} gFrameMetricsObserverClassInfo;
66
67static JNIEnv* getenv(JavaVM* vm) {
68    JNIEnv* env;
69    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
70        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
71    }
72    return env;
73}
74
75// TODO: Clean this up, it's a bit odd to need to call over to
76// rendernode's jni layer. Probably means RootRenderNode should be pulled
77// into HWUI with appropriate callbacks for the various JNI hooks so
78// that RenderNode's JNI layer can handle its own thing
79void onRenderNodeRemoved(JNIEnv* env, RenderNode* node);
80
81class ScopedRemovedRenderNodeObserver : public TreeObserver {
82public:
83    ScopedRemovedRenderNodeObserver(JNIEnv* env) : mEnv(env) {}
84    ~ScopedRemovedRenderNodeObserver() {
85        for (auto& node : mMaybeRemovedNodes) {
86            if (node->hasParents()) continue;
87            onRenderNodeRemoved(mEnv, node.get());
88        }
89    }
90
91    virtual void onMaybeRemovedFromTree(RenderNode* node) override {
92        mMaybeRemovedNodes.insert(sp<RenderNode>(node));
93    }
94
95private:
96    JNIEnv* mEnv;
97    std::set< sp<RenderNode> > mMaybeRemovedNodes;
98};
99
100class OnFinishedEvent {
101public:
102    OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
103            : animator(animator), listener(listener) {}
104    sp<BaseRenderNodeAnimator> animator;
105    sp<AnimationListener> listener;
106};
107
108class InvokeAnimationListeners : public MessageHandler {
109public:
110    InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) {
111        mOnFinishedEvents.swap(events);
112    }
113
114    static void callOnFinished(OnFinishedEvent& event) {
115        event.listener->onAnimationFinished(event.animator.get());
116    }
117
118    virtual void handleMessage(const Message& message) {
119        std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished);
120        mOnFinishedEvents.clear();
121    }
122
123private:
124    std::vector<OnFinishedEvent> mOnFinishedEvents;
125};
126
127class RenderingException : public MessageHandler {
128public:
129    RenderingException(JavaVM* vm, const std::string& message)
130            : mVm(vm)
131            , mMessage(message) {
132    }
133
134    virtual void handleMessage(const Message&) {
135        throwException(mVm, mMessage);
136    }
137
138    static void throwException(JavaVM* vm, const std::string& message) {
139        JNIEnv* env = getenv(vm);
140        jniThrowException(env, "java/lang/IllegalStateException", message.c_str());
141    }
142
143private:
144    JavaVM* mVm;
145    std::string mMessage;
146};
147
148class RootRenderNode : public RenderNode, ErrorHandler {
149public:
150    RootRenderNode(JNIEnv* env) : RenderNode() {
151        mLooper = Looper::getForThread();
152        LOG_ALWAYS_FATAL_IF(!mLooper.get(),
153                "Must create RootRenderNode on a thread with a looper!");
154        env->GetJavaVM(&mVm);
155    }
156
157    virtual ~RootRenderNode() {}
158
159    virtual void onError(const std::string& message) override {
160        mLooper->sendMessage(new RenderingException(mVm, message), 0);
161    }
162
163    virtual void prepareTree(TreeInfo& info) override {
164        info.errorHandler = this;
165        // TODO: This is hacky
166        info.windowInsetLeft = -stagingProperties().getLeft();
167        info.windowInsetTop = -stagingProperties().getTop();
168        info.updateWindowPositions = true;
169        RenderNode::prepareTree(info);
170        info.updateWindowPositions = false;
171        info.windowInsetLeft = 0;
172        info.windowInsetTop = 0;
173        info.errorHandler = nullptr;
174    }
175
176    void sendMessage(const sp<MessageHandler>& handler) {
177        mLooper->sendMessage(handler, 0);
178    }
179
180    void attachAnimatingNode(RenderNode* animatingNode) {
181        mPendingAnimatingRenderNodes.push_back(animatingNode);
182    }
183
184    void doAttachAnimatingNodes(AnimationContext* context) {
185        for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) {
186            RenderNode* node = mPendingAnimatingRenderNodes[i].get();
187            context->addAnimatingRenderNode(*node);
188        }
189        mPendingAnimatingRenderNodes.clear();
190    }
191
192    void destroy() {
193        for (auto& renderNode : mPendingAnimatingRenderNodes) {
194            renderNode->animators().endAllStagingAnimators();
195        }
196        mPendingAnimatingRenderNodes.clear();
197    }
198
199private:
200    sp<Looper> mLooper;
201    JavaVM* mVm;
202    std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
203};
204
205class AnimationContextBridge : public AnimationContext {
206public:
207    AnimationContextBridge(renderthread::TimeLord& clock, RootRenderNode* rootNode)
208            : AnimationContext(clock), mRootNode(rootNode) {
209    }
210
211    virtual ~AnimationContextBridge() {}
212
213    // Marks the start of a frame, which will update the frame time and move all
214    // next frame animations into the current frame
215    virtual void startFrame(TreeInfo::TraversalMode mode) {
216        if (mode == TreeInfo::MODE_FULL) {
217            mRootNode->doAttachAnimatingNodes(this);
218        }
219        AnimationContext::startFrame(mode);
220    }
221
222    // Runs any animations still left in mCurrentFrameAnimations
223    virtual void runRemainingAnimations(TreeInfo& info) {
224        AnimationContext::runRemainingAnimations(info);
225        postOnFinishedEvents();
226    }
227
228    virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
229        OnFinishedEvent event(animator, listener);
230        mOnFinishedEvents.push_back(event);
231    }
232
233    virtual void destroy() {
234        AnimationContext::destroy();
235        postOnFinishedEvents();
236    }
237
238private:
239    sp<RootRenderNode> mRootNode;
240    std::vector<OnFinishedEvent> mOnFinishedEvents;
241
242    void postOnFinishedEvents() {
243        if (mOnFinishedEvents.size()) {
244            sp<InvokeAnimationListeners> message
245                    = new InvokeAnimationListeners(mOnFinishedEvents);
246            mRootNode->sendMessage(message);
247        }
248    }
249};
250
251class ContextFactoryImpl : public IContextFactory {
252public:
253    ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {}
254
255    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
256        return new AnimationContextBridge(clock, mRootNode);
257    }
258
259private:
260    RootRenderNode* mRootNode;
261};
262
263class ObserverProxy;
264
265class NotifyHandler : public MessageHandler {
266public:
267    NotifyHandler(JavaVM* vm, ObserverProxy* observer) : mVm(vm), mObserver(observer) {}
268
269    virtual void handleMessage(const Message& message);
270
271private:
272    JavaVM* const mVm;
273    ObserverProxy* const mObserver;
274};
275
276static jlongArray get_metrics_buffer(JNIEnv* env, jobject observer) {
277    jobject frameMetrics = env->GetObjectField(
278            observer, gFrameMetricsObserverClassInfo.frameMetrics);
279    LOG_ALWAYS_FATAL_IF(frameMetrics == nullptr, "unable to retrieve data sink object");
280    jobject buffer = env->GetObjectField(
281            frameMetrics, gFrameMetricsObserverClassInfo.timingDataBuffer);
282    LOG_ALWAYS_FATAL_IF(buffer == nullptr, "unable to retrieve data sink buffer");
283    return reinterpret_cast<jlongArray>(buffer);
284}
285
286/*
287 * Implements JNI layer for hwui frame metrics reporting.
288 */
289class ObserverProxy : public FrameMetricsObserver {
290public:
291    ObserverProxy(JavaVM *vm, jobject observer) : mVm(vm) {
292        JNIEnv* env = getenv(mVm);
293
294        mObserverWeak = env->NewWeakGlobalRef(observer);
295        LOG_ALWAYS_FATAL_IF(mObserverWeak == nullptr,
296                "unable to create frame stats observer reference");
297
298        jlongArray buffer = get_metrics_buffer(env, observer);
299        jsize bufferSize = env->GetArrayLength(reinterpret_cast<jarray>(buffer));
300        LOG_ALWAYS_FATAL_IF(bufferSize != kBufferSize,
301                "Mismatched Java/Native FrameMetrics data format.");
302
303        jobject messageQueueLocal = env->GetObjectField(
304                observer, gFrameMetricsObserverClassInfo.messageQueue);
305        mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal);
306        LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available");
307
308        mMessageHandler = new NotifyHandler(mVm, this);
309        LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr,
310                "OOM: unable to allocate NotifyHandler");
311    }
312
313    ~ObserverProxy() {
314        JNIEnv* env = getenv(mVm);
315        env->DeleteWeakGlobalRef(mObserverWeak);
316    }
317
318    jweak getObserverReference() {
319        return mObserverWeak;
320    }
321
322    bool getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) {
323        FrameMetricsNotification& elem = mRingBuffer[mNextInQueue];
324
325        if (elem.hasData.load()) {
326            env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer);
327            *dropCount = elem.dropCount;
328            mNextInQueue = (mNextInQueue + 1) % kRingSize;
329            elem.hasData = false;
330            return true;
331        }
332
333        return false;
334    }
335
336    virtual void notify(const int64_t* stats) {
337        FrameMetricsNotification& elem = mRingBuffer[mNextFree];
338
339        if (!elem.hasData.load()) {
340            memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0]));
341
342            elem.dropCount = mDroppedReports;
343            mDroppedReports = 0;
344
345            incStrong(nullptr);
346            mNextFree = (mNextFree + 1) % kRingSize;
347            elem.hasData = true;
348
349            mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage);
350        } else {
351            mDroppedReports++;
352        }
353    }
354
355private:
356    static const int kBufferSize = static_cast<int>(FrameInfoIndex::NumIndexes);
357    static constexpr int kRingSize = 3;
358
359    class FrameMetricsNotification {
360    public:
361        FrameMetricsNotification() : hasData(false) {}
362
363        std::atomic_bool hasData;
364        int64_t buffer[kBufferSize];
365        int dropCount = 0;
366    };
367
368    JavaVM* const mVm;
369    jweak mObserverWeak;
370    jobject mJavaBufferGlobal;
371
372    sp<MessageQueue> mMessageQueue;
373    sp<NotifyHandler> mMessageHandler;
374    Message mMessage;
375
376    int mNextFree = 0;
377    int mNextInQueue = 0;
378    FrameMetricsNotification mRingBuffer[kRingSize];
379
380    int mDroppedReports = 0;
381};
382
383void NotifyHandler::handleMessage(const Message& message) {
384    JNIEnv* env = getenv(mVm);
385
386    jobject target = env->NewLocalRef(mObserver->getObserverReference());
387
388    if (target != nullptr) {
389        jlongArray javaBuffer = get_metrics_buffer(env, target);
390        int dropCount = 0;
391        while (mObserver->getNextBuffer(env, javaBuffer, &dropCount)) {
392            env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback, dropCount);
393        }
394        env->DeleteLocalRef(target);
395    }
396
397    mObserver->decStrong(nullptr);
398}
399
400static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
401        jlong proxyPtr, jobject graphicBuffer, jlongArray atlasMapArray) {
402    sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
403    jsize len = env->GetArrayLength(atlasMapArray);
404    if (len <= 0) {
405        ALOGW("Failed to initialize atlas, invalid map length: %d", len);
406        return;
407    }
408    int64_t* map = new int64_t[len];
409    env->GetLongArrayRegion(atlasMapArray, 0, len, map);
410
411    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
412    proxy->setTextureAtlas(buffer, map, len);
413}
414
415static void android_view_ThreadedRenderer_setProcessStatsBuffer(JNIEnv* env, jobject clazz,
416        jlong proxyPtr, jint fd) {
417    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
418    proxy->setProcessStatsBuffer(fd);
419}
420
421static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
422    RootRenderNode* node = new RootRenderNode(env);
423    node->incStrong(0);
424    node->setName("RootRenderNode");
425    return reinterpret_cast<jlong>(node);
426}
427
428static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
429        jboolean translucent, jlong rootRenderNodePtr) {
430    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
431    ContextFactoryImpl factory(rootRenderNode);
432    return (jlong) new RenderProxy(translucent, rootRenderNode, &factory);
433}
434
435static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
436        jlong proxyPtr) {
437    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
438    delete proxy;
439}
440
441static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
442        jlong proxyPtr) {
443    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
444    return proxy->loadSystemProperties();
445}
446
447static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz,
448        jlong proxyPtr, jstring jname) {
449    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
450    const char* name = env->GetStringUTFChars(jname, NULL);
451    proxy->setName(name);
452    env->ReleaseStringUTFChars(jname, name);
453}
454
455static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
456        jlong proxyPtr, jobject jsurface) {
457    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
458    sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
459    proxy->initialize(surface);
460}
461
462static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
463        jlong proxyPtr, jobject jsurface) {
464    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
465    sp<Surface> surface;
466    if (jsurface) {
467        surface = android_view_Surface_getSurface(env, jsurface);
468    }
469    proxy->updateSurface(surface);
470}
471
472static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
473        jlong proxyPtr, jobject jsurface) {
474    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
475    sp<Surface> surface;
476    if (jsurface) {
477        surface = android_view_Surface_getSurface(env, jsurface);
478    }
479    return proxy->pauseSurface(surface);
480}
481
482static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz,
483        jlong proxyPtr, jboolean stopped) {
484    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
485    proxy->setStopped(stopped);
486}
487
488static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
489        jint width, jint height, jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) {
490    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
491    proxy->setup(width, height, lightRadius, ambientShadowAlpha, spotShadowAlpha);
492}
493
494static void android_view_ThreadedRenderer_setLightCenter(JNIEnv* env, jobject clazz,
495        jlong proxyPtr, jfloat lightX, jfloat lightY, jfloat lightZ) {
496    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
497    proxy->setLightCenter((Vector3){lightX, lightY, lightZ});
498}
499
500static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
501        jlong proxyPtr, jboolean opaque) {
502    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
503    proxy->setOpaque(opaque);
504}
505
506static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
507        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
508    LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
509            "Mismatched size expectations, given %d expected %d",
510            frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
511    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
512    ScopedRemovedRenderNodeObserver observer(env);
513    env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
514    return proxy->syncAndDrawFrame(&observer);
515}
516
517static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
518        jlong proxyPtr, jlong rootNodePtr) {
519    ScopedRemovedRenderNodeObserver observer(env);
520    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
521    rootRenderNode->destroy();
522    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
523    proxy->destroy(&observer);
524}
525
526static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,
527        jlong rootNodePtr, jlong animatingNodePtr) {
528    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
529    RenderNode* animatingNode = reinterpret_cast<RenderNode*>(animatingNodePtr);
530    rootRenderNode->attachAnimatingNode(animatingNode);
531}
532
533static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
534        jlong functorPtr, jboolean waitForCompletion) {
535    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
536    RenderProxy::invokeFunctor(functor, waitForCompletion);
537}
538
539static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
540        jlong proxyPtr) {
541    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
542    DeferredLayerUpdater* layer = proxy->createTextureLayer();
543    return reinterpret_cast<jlong>(layer);
544}
545
546static void android_view_ThreadedRenderer_buildLayer(JNIEnv* env, jobject clazz,
547        jlong proxyPtr, jlong nodePtr) {
548    ScopedRemovedRenderNodeObserver observer(env);
549    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
550    RenderNode* node = reinterpret_cast<RenderNode*>(nodePtr);
551    proxy->buildLayer(node, &observer);
552}
553
554static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
555        jlong proxyPtr, jlong layerPtr, jobject jbitmap) {
556    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
557    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
558    SkBitmap bitmap;
559    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
560    return proxy->copyLayerInto(layer, bitmap);
561}
562
563static void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz,
564        jlong proxyPtr, jlong layerPtr) {
565    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
566    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
567    proxy->pushLayerUpdate(layer);
568}
569
570static void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz,
571        jlong proxyPtr, jlong layerPtr) {
572    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
573    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
574    proxy->cancelLayerUpdate(layer);
575}
576
577static void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobject clazz,
578        jlong proxyPtr, jlong layerPtr) {
579    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
580    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
581    proxy->detachSurfaceTexture(layer);
582}
583
584static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
585        jlong proxyPtr) {
586    ScopedRemovedRenderNodeObserver observer(env);
587    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
588    proxy->destroyHardwareResources(&observer);
589}
590
591static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
592        jint level) {
593    RenderProxy::trimMemory(level);
594}
595
596static void android_view_ThreadedRenderer_overrideProperty(JNIEnv* env, jobject clazz,
597        jstring name, jstring value) {
598    const char* nameCharArray = env->GetStringUTFChars(name, NULL);
599    const char* valueCharArray = env->GetStringUTFChars(value, NULL);
600    RenderProxy::overrideProperty(nameCharArray, valueCharArray);
601    env->ReleaseStringUTFChars(name, nameCharArray);
602    env->ReleaseStringUTFChars(name, valueCharArray);
603}
604
605static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
606        jlong proxyPtr) {
607    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
608    proxy->fence();
609}
610
611static void android_view_ThreadedRenderer_stopDrawing(JNIEnv* env, jobject clazz,
612        jlong proxyPtr) {
613    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
614    proxy->stopDrawing();
615}
616
617static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
618        jlong proxyPtr) {
619    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
620    proxy->notifyFramePending();
621}
622
623static void android_view_ThreadedRenderer_serializeDisplayListTree(JNIEnv* env, jobject clazz,
624        jlong proxyPtr) {
625    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
626    proxy->serializeDisplayListTree();
627}
628
629static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
630        jlong proxyPtr, jobject javaFileDescriptor, jint dumpFlags) {
631    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
632    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
633    proxy->dumpProfileInfo(fd, dumpFlags);
634}
635
636static void android_view_ThreadedRenderer_dumpProfileData(JNIEnv* env, jobject clazz,
637        jbyteArray jdata, jobject javaFileDescriptor) {
638    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
639    ScopedByteArrayRO buffer(env, jdata);
640    if (buffer.get()) {
641        JankTracker::dumpBuffer(buffer.get(), buffer.size(), fd);
642    }
643}
644
645static void android_view_ThreadedRenderer_addRenderNode(JNIEnv* env, jobject clazz,
646        jlong proxyPtr, jlong renderNodePtr, jboolean placeFront) {
647    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
648    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
649    proxy->addRenderNode(renderNode, placeFront);
650}
651
652static void android_view_ThreadedRenderer_removeRenderNode(JNIEnv* env, jobject clazz,
653        jlong proxyPtr, jlong renderNodePtr) {
654    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
655    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
656    proxy->removeRenderNode(renderNode);
657}
658
659static void android_view_ThreadedRendererd_drawRenderNode(JNIEnv* env, jobject clazz,
660        jlong proxyPtr, jlong renderNodePtr) {
661    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
662    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
663    proxy->drawRenderNode(renderNode);
664}
665
666static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env,
667        jobject clazz, jlong proxyPtr, jint left, jint top, jint right, jint bottom) {
668    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
669    proxy->setContentDrawBounds(left, top, right, bottom);
670}
671
672static jboolean android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
673        jobject clazz, jobject jsurface, jobject jbitmap) {
674    SkBitmap bitmap;
675    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
676    sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
677    return RenderProxy::copySurfaceInto(surface, &bitmap);
678}
679
680// ----------------------------------------------------------------------------
681// FrameMetricsObserver
682// ----------------------------------------------------------------------------
683
684static jlong android_view_ThreadedRenderer_addFrameMetricsObserver(JNIEnv* env,
685        jclass clazz, jlong proxyPtr, jobject fso) {
686    JavaVM* vm = nullptr;
687    if (env->GetJavaVM(&vm) != JNI_OK) {
688        LOG_ALWAYS_FATAL("Unable to get Java VM");
689        return 0;
690    }
691
692    renderthread::RenderProxy* renderProxy =
693            reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
694
695    FrameMetricsObserver* observer = new ObserverProxy(vm, fso);
696    renderProxy->addFrameMetricsObserver(observer);
697    return reinterpret_cast<jlong>(observer);
698}
699
700static void android_view_ThreadedRenderer_removeFrameMetricsObserver(JNIEnv* env, jclass clazz,
701        jlong proxyPtr, jlong observerPtr) {
702    FrameMetricsObserver* observer = reinterpret_cast<FrameMetricsObserver*>(observerPtr);
703    renderthread::RenderProxy* renderProxy =
704            reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
705
706    renderProxy->removeFrameMetricsObserver(observer);
707}
708
709// ----------------------------------------------------------------------------
710// Shaders
711// ----------------------------------------------------------------------------
712
713static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
714        jstring diskCachePath) {
715    const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
716    egl_cache_t::get()->setCacheFilename(cacheArray);
717    env->ReleaseStringUTFChars(diskCachePath, cacheArray);
718}
719
720// ----------------------------------------------------------------------------
721// Layers
722// ----------------------------------------------------------------------------
723
724static void android_view_ThreadedRenderer_setupVulkanLayerPath(JNIEnv* env, jobject clazz,
725        jstring layerPath) {
726
727    const char* layerArray = env->GetStringUTFChars(layerPath, NULL);
728    vulkan::LoaderData::GetInstance().layer_path = layerArray;
729    env->ReleaseStringUTFChars(layerPath, layerArray);
730}
731
732// ----------------------------------------------------------------------------
733// JNI Glue
734// ----------------------------------------------------------------------------
735
736const char* const kClassPathName = "android/view/ThreadedRenderer";
737
738static const JNINativeMethod gMethods[] = {
739    { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
740    { "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
741    { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
742    { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
743    { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
744    { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
745    { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
746    { "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize },
747    { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
748    { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
749    { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped },
750    { "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
751    { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
752    { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
753    { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
754    { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
755    { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
756    { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
757    { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
758    { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
759    { "nCopyLayerInto", "(JJLandroid/graphics/Bitmap;)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
760    { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
761    { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
762    { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
763    { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources },
764    { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory },
765    { "nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V",  (void*) android_view_ThreadedRenderer_overrideProperty },
766    { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
767    { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
768    { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
769    { "nSerializeDisplayListTree", "(J)V", (void*) android_view_ThreadedRenderer_serializeDisplayListTree },
770    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
771    { "nDumpProfileData", "([BLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileData },
772    { "setupShadersDiskCache", "(Ljava/lang/String;)V",
773                (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
774    { "setupVulkanLayerPath", "(Ljava/lang/String;)V",
775                (void*) android_view_ThreadedRenderer_setupVulkanLayerPath },
776    { "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode},
777    { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
778    { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
779    { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
780    { "nAddFrameMetricsObserver",
781            "(JLandroid/view/FrameMetricsObserver;)J",
782            (void*)android_view_ThreadedRenderer_addFrameMetricsObserver },
783    { "nRemoveFrameMetricsObserver",
784            "(JJ)V",
785            (void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
786    { "nCopySurfaceInto", "(Landroid/view/Surface;Landroid/graphics/Bitmap;)Z",
787                (void*)android_view_ThreadedRenderer_copySurfaceInto },
788};
789
790int register_android_view_ThreadedRenderer(JNIEnv* env) {
791    jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver");
792    gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie(
793            env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;");
794    gFrameMetricsObserverClassInfo.messageQueue = GetFieldIDOrDie(
795            env, observerClass, "mMessageQueue", "Landroid/os/MessageQueue;");
796    gFrameMetricsObserverClassInfo.callback = GetMethodIDOrDie(
797            env, observerClass, "notifyDataAvailable", "(I)V");
798
799    jclass metricsClass = FindClassOrDie(env, "android/view/FrameMetrics");
800    gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie(
801            env, metricsClass, "mTimingData", "[J");
802
803    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
804}
805
806}; // namespace android
807