android_view_ThreadedRenderer.cpp revision 51f2d606dcbfba3cc5b03dfea37c1304b91c232f
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_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
483        jint width, jint height, jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) {
484    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
485    proxy->setup(width, height, lightRadius, ambientShadowAlpha, spotShadowAlpha);
486}
487
488static void android_view_ThreadedRenderer_setLightCenter(JNIEnv* env, jobject clazz,
489        jlong proxyPtr, jfloat lightX, jfloat lightY, jfloat lightZ) {
490    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
491    proxy->setLightCenter((Vector3){lightX, lightY, lightZ});
492}
493
494static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
495        jlong proxyPtr, jboolean opaque) {
496    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
497    proxy->setOpaque(opaque);
498}
499
500static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
501        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
502    LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
503            "Mismatched size expectations, given %d expected %d",
504            frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
505    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
506    ScopedRemovedRenderNodeObserver observer(env);
507    env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
508    return proxy->syncAndDrawFrame(&observer);
509}
510
511static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
512        jlong proxyPtr, jlong rootNodePtr) {
513    ScopedRemovedRenderNodeObserver observer(env);
514    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
515    rootRenderNode->destroy();
516    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
517    proxy->destroy(&observer);
518}
519
520static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,
521        jlong rootNodePtr, jlong animatingNodePtr) {
522    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
523    RenderNode* animatingNode = reinterpret_cast<RenderNode*>(animatingNodePtr);
524    rootRenderNode->attachAnimatingNode(animatingNode);
525}
526
527static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
528        jlong functorPtr, jboolean waitForCompletion) {
529    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
530    RenderProxy::invokeFunctor(functor, waitForCompletion);
531}
532
533static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
534        jlong proxyPtr) {
535    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
536    DeferredLayerUpdater* layer = proxy->createTextureLayer();
537    return reinterpret_cast<jlong>(layer);
538}
539
540static void android_view_ThreadedRenderer_buildLayer(JNIEnv* env, jobject clazz,
541        jlong proxyPtr, jlong nodePtr) {
542    ScopedRemovedRenderNodeObserver observer(env);
543    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
544    RenderNode* node = reinterpret_cast<RenderNode*>(nodePtr);
545    proxy->buildLayer(node, &observer);
546}
547
548static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
549        jlong proxyPtr, jlong layerPtr, jobject jbitmap) {
550    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
551    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
552    SkBitmap bitmap;
553    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
554    return proxy->copyLayerInto(layer, bitmap);
555}
556
557static void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz,
558        jlong proxyPtr, jlong layerPtr) {
559    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
560    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
561    proxy->pushLayerUpdate(layer);
562}
563
564static void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz,
565        jlong proxyPtr, jlong layerPtr) {
566    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
567    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
568    proxy->cancelLayerUpdate(layer);
569}
570
571static void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobject clazz,
572        jlong proxyPtr, jlong layerPtr) {
573    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
574    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
575    proxy->detachSurfaceTexture(layer);
576}
577
578static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
579        jlong proxyPtr) {
580    ScopedRemovedRenderNodeObserver observer(env);
581    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
582    proxy->destroyHardwareResources(&observer);
583}
584
585static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
586        jint level) {
587    RenderProxy::trimMemory(level);
588}
589
590static void android_view_ThreadedRenderer_overrideProperty(JNIEnv* env, jobject clazz,
591        jstring name, jstring value) {
592    const char* nameCharArray = env->GetStringUTFChars(name, NULL);
593    const char* valueCharArray = env->GetStringUTFChars(value, NULL);
594    RenderProxy::overrideProperty(nameCharArray, valueCharArray);
595    env->ReleaseStringUTFChars(name, nameCharArray);
596    env->ReleaseStringUTFChars(name, valueCharArray);
597}
598
599static void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
600        jlong proxyPtr) {
601    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
602    proxy->fence();
603}
604
605static void android_view_ThreadedRenderer_stopDrawing(JNIEnv* env, jobject clazz,
606        jlong proxyPtr) {
607    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
608    proxy->stopDrawing();
609}
610
611static void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
612        jlong proxyPtr) {
613    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
614    proxy->notifyFramePending();
615}
616
617static void android_view_ThreadedRenderer_serializeDisplayListTree(JNIEnv* env, jobject clazz,
618        jlong proxyPtr) {
619    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
620    proxy->serializeDisplayListTree();
621}
622
623static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
624        jlong proxyPtr, jobject javaFileDescriptor, jint dumpFlags) {
625    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
626    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
627    proxy->dumpProfileInfo(fd, dumpFlags);
628}
629
630static void android_view_ThreadedRenderer_dumpProfileData(JNIEnv* env, jobject clazz,
631        jbyteArray jdata, jobject javaFileDescriptor) {
632    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
633    ScopedByteArrayRO buffer(env, jdata);
634    if (buffer.get()) {
635        JankTracker::dumpBuffer(buffer.get(), buffer.size(), fd);
636    }
637}
638
639static void android_view_ThreadedRenderer_addRenderNode(JNIEnv* env, jobject clazz,
640        jlong proxyPtr, jlong renderNodePtr, jboolean placeFront) {
641    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
642    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
643    proxy->addRenderNode(renderNode, placeFront);
644}
645
646static void android_view_ThreadedRenderer_removeRenderNode(JNIEnv* env, jobject clazz,
647        jlong proxyPtr, jlong renderNodePtr) {
648    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
649    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
650    proxy->removeRenderNode(renderNode);
651}
652
653static void android_view_ThreadedRendererd_drawRenderNode(JNIEnv* env, jobject clazz,
654        jlong proxyPtr, jlong renderNodePtr) {
655    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
656    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
657    proxy->drawRenderNode(renderNode);
658}
659
660static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env,
661        jobject clazz, jlong proxyPtr, jint left, jint top, jint right, jint bottom) {
662    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
663    proxy->setContentDrawBounds(left, top, right, bottom);
664}
665
666// ----------------------------------------------------------------------------
667// FrameMetricsObserver
668// ----------------------------------------------------------------------------
669
670static jlong android_view_ThreadedRenderer_addFrameMetricsObserver(JNIEnv* env,
671        jclass clazz, jlong proxyPtr, jobject fso) {
672    JavaVM* vm = nullptr;
673    if (env->GetJavaVM(&vm) != JNI_OK) {
674        LOG_ALWAYS_FATAL("Unable to get Java VM");
675        return 0;
676    }
677
678    renderthread::RenderProxy* renderProxy =
679            reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
680
681    FrameMetricsObserver* observer = new ObserverProxy(vm, fso);
682    renderProxy->addFrameMetricsObserver(observer);
683    return reinterpret_cast<jlong>(observer);
684}
685
686static void android_view_ThreadedRenderer_removeFrameMetricsObserver(JNIEnv* env, jclass clazz,
687        jlong proxyPtr, jlong observerPtr) {
688    FrameMetricsObserver* observer = reinterpret_cast<FrameMetricsObserver*>(observerPtr);
689    renderthread::RenderProxy* renderProxy =
690            reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
691
692    renderProxy->removeFrameMetricsObserver(observer);
693}
694
695// ----------------------------------------------------------------------------
696// Shaders
697// ----------------------------------------------------------------------------
698
699static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
700        jstring diskCachePath) {
701    const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
702    egl_cache_t::get()->setCacheFilename(cacheArray);
703    env->ReleaseStringUTFChars(diskCachePath, cacheArray);
704}
705
706// ----------------------------------------------------------------------------
707// Layers
708// ----------------------------------------------------------------------------
709
710static void android_view_ThreadedRenderer_setupVulkanLayerPath(JNIEnv* env, jobject clazz,
711        jstring layerPath) {
712
713    const char* layerArray = env->GetStringUTFChars(layerPath, NULL);
714    vulkan::LoaderData::GetInstance().layer_path = layerArray;
715    env->ReleaseStringUTFChars(layerPath, layerArray);
716}
717
718// ----------------------------------------------------------------------------
719// JNI Glue
720// ----------------------------------------------------------------------------
721
722const char* const kClassPathName = "android/view/ThreadedRenderer";
723
724static const JNINativeMethod gMethods[] = {
725    { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
726    { "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
727    { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
728    { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
729    { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
730    { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
731    { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
732    { "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize },
733    { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
734    { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
735    { "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
736    { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
737    { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
738    { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
739    { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
740    { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
741    { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
742    { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
743    { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
744    { "nCopyLayerInto", "(JJLandroid/graphics/Bitmap;)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
745    { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
746    { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
747    { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
748    { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources },
749    { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory },
750    { "nOverrideProperty", "(Ljava/lang/String;Ljava/lang/String;)V",  (void*) android_view_ThreadedRenderer_overrideProperty },
751    { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
752    { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
753    { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
754    { "nSerializeDisplayListTree", "(J)V", (void*) android_view_ThreadedRenderer_serializeDisplayListTree },
755    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
756    { "nDumpProfileData", "([BLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileData },
757    { "setupShadersDiskCache", "(Ljava/lang/String;)V",
758                (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
759    { "setupVulkanLayerPath", "(Ljava/lang/String;)V",
760                (void*) android_view_ThreadedRenderer_setupVulkanLayerPath },
761    { "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode},
762    { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
763    { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
764    { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
765    { "nAddFrameMetricsObserver",
766            "(JLandroid/view/FrameMetricsObserver;)J",
767            (void*)android_view_ThreadedRenderer_addFrameMetricsObserver },
768    { "nRemoveFrameMetricsObserver",
769            "(JJ)V",
770            (void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
771};
772
773int register_android_view_ThreadedRenderer(JNIEnv* env) {
774    jclass observerClass = FindClassOrDie(env, "android/view/FrameMetricsObserver");
775    gFrameMetricsObserverClassInfo.frameMetrics = GetFieldIDOrDie(
776            env, observerClass, "mFrameMetrics", "Landroid/view/FrameMetrics;");
777    gFrameMetricsObserverClassInfo.messageQueue = GetFieldIDOrDie(
778            env, observerClass, "mMessageQueue", "Landroid/os/MessageQueue;");
779    gFrameMetricsObserverClassInfo.callback = GetMethodIDOrDie(
780            env, observerClass, "notifyDataAvailable", "(I)V");
781
782    jclass metricsClass = FindClassOrDie(env, "android/view/FrameMetrics");
783    gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie(
784            env, metricsClass, "mTimingData", "[J");
785
786    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
787}
788
789}; // namespace android
790