找回密码
 立即注册
首页 业界区 业界 【Rive】rive-android源码分析

【Rive】rive-android源码分析

聱嘹 6 天前
1 前言

​    本文基于 rive-android 10.1.0 进行源码分析,主要介绍 Rive 的渲染类型、RendererType 透传流程、Surface 透传流程、渲染流程、启动渲染流程、暂停渲染流程等内容。
​    rive-android 类图框架如下。图中,蓝色的类表示 rive-android 中 Kotlin 代码,绿色的类表示 rive-android 中 C++ 代码,橙色的类表示 rive-runtime 中代码(下同)。本文只解读 rive-android 的源码,不解读 rive-runtime 的源码。
1.png

​    Rive 相关应用参考以下内容。

  • Rive在Android上的简单应用
  • 动画
  • 混合动画
  • Android与Rive交互
  • 事件
  • 波动文字
  • 骨骼动画
  • 眼睛互动动画
2 渲染类型

​    rive-android 10.0.0 之前的版本,有三种渲染类型,分别是:Skia、Rive、Canvas,默认是 Skia 类型。10.0.0 版本开始舍弃了 Skia 渲染类型,默认是 Rive 类型。Skia 和 Rive 渲染类型底层都是基于 EGL 环境进行离屏渲染。
​    RenderType 类源码如下。
​    app.rive.runtime.kotlin.core.RendererType.kt
  1. enum class RendererType(val value: Int) {
  2.     Rive(0),
  3.     Canvas(1);
  4.     companion object {
  5.         fun fromIndex(index: Int): RendererType {
  6.             val maxIndex = entries.size
  7.             ...
  8.             return entries[index]
  9.         }
  10.     }
  11. }
复制代码
3 RendererType 透传流程

​    本节将介绍 RendererType 如何一步一步透传下去,直到最终创建 DrawableThreadState 对象。本节中,读者需要重点关注 RendererType 是如何在各个类之间传递的。RendererType 透传流程图如下。
2.png

3.1 设置 RendererType 的源头

​    用户在初始化 Rive 环境时,可以指定 RenderType,如下。
  1. Rive.init(applicationContext, defaultRenderer = RendererType.Rive)
复制代码
3.gif

​    也可以在布局文件中指定 RenderType(如果想使用 Winscope 或 Perfetto 查看 Trace,可以配置 riveTraceAnimations 参数),如下。
  1. [/code]​    无论是哪种方式,在 RiveAnimationView 对象被创建时,渲染类型会保存在 rendererAttributes 对象的 rendererType 属性中(rendererAttributes 是 RendererAttributes 类型)。
  2. [size=5]3.2 创建 RiveArtboardRenderer[/size]
  3. ​    RiveAnimationView 继承了 RiveTextureView,RiveTextureView 继承了 TextureView,并重写了其 onAttachedToWindow 函数,如下。
  4. ​    app.rive.runtime.kotlin.RiveTextureView.kt
  5. [code]@CallSuper
  6. override fun onAttachedToWindow() {
  7.         super.onAttachedToWindow()
  8.         surfaceTextureListener = this
  9.         isOpaque = false
  10.         renderer = createRenderer().apply { make() }
  11. }
复制代码
​    在 RiveAnimationView 中重写了 createRenderer 函数,如下。
​    app.rive.runtime.kotlin.RiveAnimationView.kt
  1. override fun createRenderer(): Renderer {
  2.         return RiveArtboardRenderer(
  3.                 trace = rendererAttributes.riveTraceAnimations,
  4.                 controller = controller,
  5.                 rendererType = rendererAttributes.rendererType,
  6.         )
  7. }
复制代码
​    RiveArtboardRenderer 只有主构造函数,没有次要构造函数,如下。关于主构造函数和次要构造函数的介绍详见 → 类和对象。
​    app.rive.runtime.kotlin.renderers.RiveArtboardRenderer.kt
  1. open class RiveArtboardRenderer(
  2.     trace: Boolean = false,
  3.     rendererType: RendererType = Rive.defaultRendererType,
  4.     private var controller: RiveFileController,
  5. ) : Renderer(rendererType, trace)
复制代码
​    Renderer 的也只有主构造函数,没有次要构造函数,如下。
​     app.rive.runtime.kotlin.renderers.Renderer.kt
  1. abstract class Renderer(
  2.     @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
  3.     var type: RendererType = Rive.defaultRendererType,
  4.     val trace: Boolean = false
  5. ) : NativeObject(NULL_POINTER), Choreographer.FrameCallback
复制代码
3.3 创建 JNIRenderer

​    我们再回到 RiveTextureView 的 onAttachedToWindow 函数中,在 createRenderer 之后,调用了 Renderer 的 make 函数。make 函数的源码如下。cppPointer 是在 NativeObject 中定义的 Long 类型变量,对应 C++ 中的指针变量,指向的是 JNI 中 JNIRenderer 对象。在 make 函数中又调用了 constructor 函数,它在 JNI 中有实现。(注意:这里的 constructor 不是 Renderer 的构造函数,因为其前面加了 fun,构造函数前面不能加 fun)
​    app.rive.runtime.kotlin.renderers.Renderer.kt
  1. @CallSuper
  2. open fun make() {
  3.         if (!hasCppObject) {
  4.                 cppPointer = constructor(trace, type.value)
  5.                 refs.incrementAndGet()
  6.         }
  7. }
  8. /** Instantiates JNIRenderer in C++ */
  9. private external fun constructor(trace: Boolean, type: Int): Long
复制代码
​    全局搜索 "Renderer_constructor",找到 JNI 中的 constructor 函数的实现如下。
​    bindings/bindings_renderer.cpp
  1. JNIEXPORT jlong JNICALL
  2. Java_app_rive_runtime_kotlin_renderers_Renderer_constructor(JNIEnv* env, jobject ktRenderer,
  3.         jboolean trace, jint type)
  4. {
  5.         RendererType rendererType = static_cast<RendererType>(type);
  6.         JNIRenderer* renderer = new JNIRenderer(ktRenderer, trace, rendererType);
  7.         ...
  8.         return (jlong)renderer;
  9. }
复制代码
​    JNIRenderer 的构造函数如下,这里会创建 RefWorker 对象保存在 m_worker 中,创建 ITracer 对象保存在 m_tracer 中。如果 trace 为 false,将创建 NoopTracer 对象,其 beginSection、endSection 函数都是空实现;如果 trace 为 true,将创建 Tracer 对象,其 beginSection 函数将调用 ATrace_beginSection,endSection 函数将调用 ATrace_endSection(详见 aosp 中的 frameworks/base/native/android/trace.cpp),这时用户就可以使用 Winscope 或 Perfetto 查看 Trace 了。
​    models/jni_renderer.cpp
  1. JNIRenderer::JNIRenderer(jobject ktRenderer, bool trace, const RendererType rendererType) :
  2.     m_worker(RefWorker::CurrentOrFallback(rendererType)),
  3.     m_ktRenderer(GetJNIEnv()->NewGlobalRef(ktRenderer)),
  4.     m_tracer(getTracer(trace))
  5. {}
复制代码
3.4 创建 RefWorker

​    RefWorker::CurrentOrFallback 的源码如下。
​    helpers/work_ref.cpp
  1. rcp<RefWorker> RefWorker::CurrentOrFallback(RendererType rendererType)
  2. {
  3.     rcp<RefWorker> currentOrFallback;
  4.     switch (rendererType)
  5.     {
  6.         case RendererType::None:
  7.             assert(false);
  8.             break;
  9.         case RendererType::Rive:
  10.             currentOrFallback = RiveWorker();
  11.             break;
  12.         case RendererType::Canvas:
  13.             currentOrFallback = CanvasWorker();
  14.             break;
  15.     }
  16.     if (currentOrFallback == nullptr)
  17.     {
  18.         currentOrFallback = CanvasWorker();
  19.     }
  20.     return currentOrFallback;
  21. }
复制代码
​    RiveWorker 和 CanvasWorker 函数实现如下。
​    helpers/work_ref.cpp
  1. rcp<RefWorker> RefWorker::RiveWorker()
  2. {
  3.     static enum class RiveRendererSupport { unknown, no, yes } s_isSupported;
  4.     static std::unique_ptr<RefWorker> s_riveWorker;
  5.     ...
  6.     if (s_isSupported == RiveRendererSupport::unknown)
  7.     {
  8.         std::unique_ptr<RefWorker> candidateWorker(new RefWorker(RendererType::Rive));
  9.         candidateWorker->runAndWait(
  10.             [](rive_android::DrawableThreadState* threadState) {
  11.                 PLSThreadState* plsThreadState = static_cast<PLSThreadState*>(threadState);
  12.                 s_isSupported = plsThreadState->renderContext() != nullptr ? RiveRendererSupport::yes : RiveRendererSupport::no;
  13.             });
  14.         if (s_isSupported == RiveRendererSupport::yes)
  15.         {
  16.             s_riveWorker = std::move(candidateWorker);
  17.         }
  18.         ...
  19.     }
  20.     if (s_riveWorker != nullptr)
  21.     {
  22.         ++s_riveWorker->m_externalRefCount;
  23.     }
  24.     return rcp(s_riveWorker.get());
  25. }
  26. rcp<RefWorker> RefWorker::CanvasWorker()
  27. {
  28.     if (s_canvasWorker == nullptr)
  29.     {
  30.         s_canvasWorker = std::unique_ptr<RefWorker>(new RefWorker(RendererType::Canvas));
  31.     }
  32.     ++s_canvasWorker->m_externalRefCount;
  33.     return rcp(s_canvasWorker.get());
  34. }
复制代码
​    RefWorker 继承 WorkerThread,如下。
​    helpers/work_ref.hpp
  1. explicit RefWorker(const RendererType rendererType) :
  2.         WorkerThread(RendererName(rendererType), Affinity::None, rendererType)
  3. {}
复制代码
3.5 创建 WorkThread

​    WorkThread 的构造函数如下,可以看到这里创建了一个线程,用于处理渲染任务。
​    helpers/worker_thread.hpp
  1. WorkerThread(const char* name, Affinity affinity, const RendererType rendererType) :
  2.         m_RendererType(rendererType),
  3.         mName(name),
  4.         mAffinity(affinity),
  5.         mWorkMutex{}
  6. {
  7.         mThread = std::thread([this]() { threadMain(); });
  8. }
复制代码
​    threadMain 函数的实现如下。首先通过 MakeThreadState 函数创建 DrawableThreadState 对象;接着进入 for 无限循环体中,如果 mWorkQueue 为空(mWorkQueue 中的元素是 functionrendererType() != RendererType::Canvas)        {                ANativeWindow* surfaceWindow = ANativeWindow_fromSurface(env, surface);                reinterpret_cast(rendererRef) ->setSurface(surfaceWindow);                if (surfaceWindow)                {                        ANativeWindow_release(surfaceWindow);                }        }        else        {                renderer->setSurface(surface);        }}[/code]4.4 JNIRenderer::setSurface

​    JNIRenderer::setSurface 的源码如下。m_worker 是 RefWorker 类的实例,RefWorker 继承 WorkThread,WorkThread 中创建了工作线程(见 3.5 节),并且有个 run 函数,m_worker->run 表示把任务提交到 WorkThread 中的工作线程中执行。
​    models/jni_renderer.cpp
  1. void threadMain()
  2. {
  3.         setAffinity(mAffinity);
  4.         ...
  5.         m_threadState = MakeThreadState(m_RendererType);
  6.         std::unique_lock lock(mWorkMutex);
  7.         for (;;)
  8.         {
  9.                 while (mWorkQueue.empty())
  10.                 {
  11.                         m_workPushedCondition.wait(mWorkMutex);
  12.                 }
  13.                 Work work = mWorkQueue.front();
  14.                 mWorkQueue.pop();
  15.                 if (!work)
  16.                 {
  17.                         // A null function is a special token that tells the thread to terminate.
  18.                         break;
  19.                 }
  20.                 lock.unlock();
  21.                 work(m_threadState.get());
  22.                 lock.lock();
  23.                 ++m_lastCompletedWorkID;
  24.                 m_workedCompletedCondition.notify_all();
  25.         }
  26.         m_threadState.reset();
  27.         DetachThread();
  28. }
复制代码
4.5 WorkerImpl::Make

​    models/worker_impl.cpp
  1. std::unique_ptr<DrawableThreadState> WorkerThread::MakeThreadState(const RendererType type)
  2. {
  3.     switch (type)
  4.     {
  5.         case RendererType::Canvas:
  6.             return std::make_unique<CanvasThreadState>();
  7.         default:
  8.         case RendererType::Rive:
  9.             return std::make_unique<PLSThreadState>();
  10.     }
  11. }
复制代码
4.6 创建 WorkerImpl

​    PLSWorkerImpl 继承 EGLWorkerImpl,EGLWorkerImpl 和 CanvasWorkerImpl 继承 WorkerImpl。
4.6.1 WorkerImpl 接口定义

​    models/worker_impl.hpp
  1. class DrawableThreadState
  2. {
  3. public:
  4.     virtual ~DrawableThreadState(){};
  5.     virtual void swapBuffers() = 0;
  6. };
  7. class EGLThreadState : public DrawableThreadState
  8. {
  9. public:
  10.     EGLThreadState();
  11.     virtual ~EGLThreadState() = 0;
  12.     EGLSurface createEGLSurface(ANativeWindow*);
  13.     virtual void destroySurface(EGLSurface) = 0;
  14.     virtual void makeCurrent(EGLSurface) = 0;
  15.     void swapBuffers() override;
  16. protected:
  17.     EGLSurface m_currentSurface = EGL_NO_SURFACE;
  18.     EGLDisplay m_display = EGL_NO_DISPLAY;
  19.     EGLContext m_context = EGL_NO_CONTEXT;
  20.     EGLConfig m_config = static_cast<EGLConfig>(0);
  21. };
  22. class CanvasThreadState : public DrawableThreadState
  23. {
  24. public:
  25.     void swapBuffers() override {}
  26. };
复制代码
4.6.2 创建 EGLWorkerImpl

​    EGLWorkerImpl 的构造函数如下。
​    models/worker_impl.hpp
  1. EGLThreadState::EGLThreadState()
  2. {
  3.     // 创建 EGLDisplay
  4.     m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  5.     ...
  6.     if (!eglInitialize(m_display, 0, 0))
  7.     {
  8.         ...
  9.         return;
  10.     }
  11.     // 创建 EGLConfig
  12.     const EGLint configAttributes[] = {...};
  13.     ...
  14.     eglChooseConfig(m_display, configAttributes, supportedConfigs.data(), num_configs, &num_configs);
  15.     ...
  16.         // 创建 EGLContext
  17.     m_context = eglCreateContext(m_display, m_config, nullptr, contextAttributes);
  18.     ...
  19. }
复制代码
​    EGLThreadState::createEGLSurface 函数源码如下。eglCreateWindowSurface 用于创建一个与屏幕窗口相关的 EGL 表面,这个表面通常与设备的窗口系统交互,使得 OpenGL ES 渲染的内容能够显示在屏幕上(补充:eglCreatePbufferSurface 用于创建一个离屏渲染的 EGL 表面)。
​    helpers/thread_state_egl.cpp
  1. PLSThreadState::PLSThreadState()
  2. {
  3.     // 创建 EGLSurface
  4.     const EGLint PbufferAttrs[] = {...};
  5.     m_backgroundSurface = eglCreatePbufferSurface(m_display, m_config, PbufferAttrs);
  6.     ...
  7.     // 绑定 EGLSurface 和 EGLContext 到显示设备 (EGLDisplay)
  8.     eglMakeCurrent(m_display, m_backgroundSurface, m_backgroundSurface, m_context);
  9.     m_currentSurface = m_backgroundSurface;
  10.     m_renderContext = rive::gpu::RenderContextGLImpl::MakeContext();
  11. }
复制代码
4.6.3 创建 PLSWorkerImpl

​    PLSWorkerImpl 的构造函数如下,最终创建了 rive::RiveRenderer 对象,其源码不在 rive-android 代码库中,在 rive-runtime 代码库中,详见 → rive_renderer.cpp。
​    models/worker_impl.cpp
  1. @CallSuper
  2. override fun onSurfaceTextureAvailable(
  3.         surfaceTexture: SurfaceTexture, width: Int, height: Int) {
  4.         if (this::viewSurface.isInitialized) {
  5.                 viewSurface.release()
  6.         }
  7.         viewSurface = Surface(surfaceTexture)
  8.         renderer?.apply {
  9.                 stop()
  10.                 setSurface(viewSurface)
  11.         }
  12. }
复制代码
​    PLSThreadState::makeCurrent 函数的实现如下,eglMakeCurrent 是 EGL 环境创建的最后一步,作用是绑定 EGLSurface 和 EGLContext 到显示设备(EGLDisplay)。
​    helpers/thread_state_pls.cpp
  1. fun setSurface(surface: Surface) {
  2.         cppSetSurface(surface, cppPointer)
  3.         isAttached = true
  4.         start()
  5. }
复制代码
4.6.4 创建 CanvasWorkerImpl

​    CanvasWorkerImpl 的构造函数如下。这里主要创建了 CanvasRenderer 对象,保存在 m_canvasRenderer 中,CanvasRenderer 继承 rive::Renderer,其源码不在 rive-android 代码库中,在 rive-runtime 代码库中,详见 → renderer.hpp、renderer.cpp;接着通过 NewGlobalRef(ktSurface) 将传入的局部引用 ktSurface 转换为全局引用,并存储在 m_ktSurface 中(全局引用会阻止 Java 垃圾回收器回收该对象,直到显式释放)。
​    models/worker_impl.hpp
  1. JNIEXPORT void JNICALL
  2. Java_app_rive_runtime_kotlin_renderers_Renderer_cppSetSurface(JNIEnv* env, jobject,
  3.         jobject surface, jlong rendererRef)
  4. {
  5.         JNIRenderer* renderer = reinterpret_cast<JNIRenderer*>(rendererRef);
  6.         if (renderer->rendererType() != RendererType::Canvas)
  7.         {
  8.                 ANativeWindow* surfaceWindow = ANativeWindow_fromSurface(env, surface);
  9.                 reinterpret_cast<JNIRenderer*>(rendererRef) ->setSurface(surfaceWindow);
  10.                 if (surfaceWindow)
  11.                 {
  12.                         ANativeWindow_release(surfaceWindow);
  13.                 }
  14.         }
  15.         else
  16.         {
  17.                 renderer->setSurface(surface);
  18.         }
  19. }
复制代码
5 渲染流程

​    渲染流程图如下。
4.png

5.1 Renderer.doFrame

​    Renderer 实现了 Choreographer.FrameCallback 接口,重写了其 doFrame 方法,其 doFrame 和 scheduleFrame 方法源码如下。
​    app.rive.runtime.kotlin.renderers.Renderer.kt
  1. void JNIRenderer::setSurface(SurfaceVariant surface)
  2. {
  3.     SurfaceVariant oldSurface = m_surface;
  4.     acquireSurface(surface);
  5.     m_worker->run([this, oldSurface](DrawableThreadState* threadState) mutable {
  6.         m_workerThreadID = std::this_thread::get_id();
  7.         ...
  8.         if (m_surface.index() > 0)
  9.         {
  10.             m_workerImpl = WorkerImpl::Make(m_surface, threadState, m_worker->rendererType());
  11.         }
  12.     });
  13. }
复制代码
5.2 JNI cppDoFrame

​    全局搜索 "Renderer_cppDoFrame",找到 JNI 中的 cppDoFrame 函数的实现如下。
​    bindings/bindings_renderer.cpp
  1. std::unique_ptr<WorkerImpl> WorkerImpl::Make(SurfaceVariant surface,
  2.     DrawableThreadState* threadState, const RendererType type)
  3. {
  4.     ...
  5.     bool success = false;
  6.     std::unique_ptr<WorkerImpl> impl;
  7.     switch (type)
  8.     {
  9.         case RendererType::Rive:
  10.         {
  11.             ANativeWindow* window = std::get(surface);
  12.             impl = std::make_unique<PLSWorkerImpl>(window, threadState, &success);
  13.             break;
  14.         }
  15.         case RendererType::Canvas:
  16.         {
  17.             jobject ktSurface = std::get<jobject>(surface);
  18.             impl = std::make_unique<CanvasWorkerImpl>(ktSurface, &success);
  19.         }
  20.         default:
  21.             break;
  22.     }
  23.     ...
  24.     return impl;
  25. }
复制代码
5.3 JNIRenderer::doFrame

​    JNIRenderer::doFrame 的源码如下。m_worker 是 RefWorker 类的实例,RefWorker 继承 WorkThread,WorkThread 中创建了工作线程(见 3.5 节),并且有个 run 函数,m_worker->run 表示把任务提交到 WorkThread 中的工作线程中执行。m_workerImpl 是 4.6 节创建的 WorkerImpl 对象(可能是 PLSWorkerImpl 或 CanavsWorkerImpl)。
​    models/jni_renderer.cpp
  1. class WorkerImpl
  2. {
  3. public:
  4.     static std::unique_ptr<WorkerImpl> Make(SurfaceVariant, DrawableThreadState*, const RendererType);
  5.     void start(jobject ktRenderer, std::chrono::high_resolution_clock::time_point);
  6.     void stop();
  7.     void doFrame(ITracer*, DrawableThreadState*, jobject ktRenderer, std::chrono::high_resolution_clock::time_point);
  8.     virtual void prepareForDraw(DrawableThreadState*) const = 0;
  9.     virtual void destroy(DrawableThreadState*) = 0;
  10.     virtual void flush(DrawableThreadState*) const = 0;
  11.     virtual rive::Renderer* renderer() const = 0;
  12. protected:
  13.     jclass m_ktRendererClass = nullptr;
  14.     jmethodID m_ktDrawCallback = nullptr;
  15.     jmethodID m_ktAdvanceCallback = nullptr;
  16.     std::chrono::high_resolution_clock::time_point m_lastFrameTime;
  17.     bool m_isStarted = false;
  18. };
复制代码
5.4 WorkerImpl::doFrame

5.4.1 doFrame

​    WorkerImpl::doFrame 的源码如下。tracer 是性能追踪器,用于测量各阶段耗时,它在 JNIRenderer 中创建(见 3.3 节),这里有 3 个追踪标签,分别是 "draw()"、"flush()"、"swapBuffers()"。m_ktAdvanceCallback 在 start 函数中定义,指向 kotlin 中 Renderer.advance 函数;m_ktDrawCallback 在 start 函数中定义,指向 kotlin 中 Renderer.draw 函数。
​    models/worker_impl.cpp
  1. class EGLWorkerImpl : public WorkerImpl
  2. {
  3. ...
  4. protected:
  5.     EGLWorkerImpl(struct ANativeWindow* window, DrawableThreadState* threadState, bool* success)
  6.     {
  7.         *success = false;
  8.         auto eglThreadState = static_cast<EGLThreadState*>(threadState);
  9.         m_eglSurface = eglThreadState->createEGLSurface(window);
  10.         if (m_eglSurface == EGL_NO_SURFACE)
  11.             return;
  12.         *success = true;
  13.     }
  14. ...
  15. };
复制代码
​     接下来,分别介绍 prepareForDraw、flush、swapBuffers。
5.4.2 prepareForDraw

​    1)EGLWorkerImpl::prepareForDraw
​    EGLWorkerImpl 的 prepareForDraw 函数源码如下。PLSThreadState 中实现了 makeCurrent 函数(见 2.6.3 节),eglThreadState->makeCurrent 中 调用了 eglMakeCurrent 函数,eglMakeCurrent 是 EGL 环境创建的最后一步,作用是绑定 EGLSurface 和 EGLContext 到显示设备(EGLDisplay)。
​    models/worker_impl.hpp
  1. EGLSurface EGLThreadState::createEGLSurface(ANativeWindow* window)
  2. {
  3.     if (!window)
  4.     {
  5.         return EGL_NO_SURFACE;
  6.     }
  7.     ...
  8.     // 创建一个与屏幕窗口相关的 EGL 表面, 这个表面通常与设备的窗口系统交, 使得 OpenGL ES 渲染的内容能够显示在屏幕上
  9.     auto res = eglCreateWindowSurface(m_display, m_config, window, nullptr);
  10.     ...
  11.     return res;
  12. }
复制代码
​    2)CanvasWorkerImpl::prepareForDraw
​    CanvasWorkerImpl 的 prepareForDraw 函数源码如下。其作用是通过 surface.lockCanvas 方法拿到 Canvas 对象。
​    models/worker_impl.cpp
  1. PLSWorkerImpl::PLSWorkerImpl(struct ANativeWindow* window, DrawableThreadState* threadState, bool* success) :
  2.     EGLWorkerImpl(window, threadState, success)
  3. {
  4.     if (!success)
  5.     {
  6.         return;
  7.     }
  8.     auto eglThreadState = static_cast<EGLThreadState*>(threadState);
  9.     eglThreadState->makeCurrent(m_eglSurface);
  10.     rive::gpu::RenderContext* renderContext = PLSWorkerImpl::PlsThreadState(eglThreadState)->renderContext();
  11.     if (renderContext == nullptr)
  12.     {
  13.         return; // PLS was not supported.
  14.     }
  15.     int width = ANativeWindow_getWidth(window); // 获取窗口宽度
  16.     int height = ANativeWindow_getHeight(window); // 获取窗口高度
  17.     GLint sampleCount; // 多重采样数
  18.     glBindFramebuffer(GL_FRAMEBUFFER, 0); // 绑定默认帧缓冲区
  19.     glGetIntegerv(GL_SAMPLES, &sampleCount); // 查询当前的多重采样数
  20.     // 创建一个基于 GLES 的帧缓冲区渲染目标,用于离屏渲染
  21.     m_renderTarget = rive::make_rcp<rive::gpu::FramebufferRenderTargetGL>(width, height, 0, sampleCount);
  22.     // 初始化 Rive 的 PLS 渲染器
  23.     m_plsRenderer = std::make_unique<rive::RiveRenderer>(renderContext);
  24.     *success = true;
  25. }
复制代码
​    bindCanvas 函数源码如下,m_ktCanvas 是通过 surface.lockCanvas 函数获取的 Canvas 对象。
​    models/canvas_renderer.hpp
  1. void PLSThreadState::makeCurrent(EGLSurface eglSurface)
  2. {
  3.     if (eglSurface == m_currentSurface)
  4.     {
  5.         return;
  6.     }
  7.         ...
  8.     // 绑定 EGLSurface 和 EGLContext 到显示设备 (EGLDisplay)
  9.     eglMakeCurrent(m_display, eglSurface, eglSurface, m_context);
  10.     m_currentSurface = eglSurface;
  11.         ...
  12. }
复制代码
​    GetSurfaceLockCanvasMethodId 用于获取 surface.lockCanvas 的方法 id,具体实现如下。这里没有调用 surface.lockHardwareCanvas 方法,说明 Canvas 渲染方式是软渲染(即 CPU 渲染,而不是 GPU 渲染)。
​    models/jni_refs.cpp
  1. class CanvasWorkerImpl : public WorkerImpl
  2. {
  3. public:
  4.     CanvasWorkerImpl(jobject ktSurface, bool* success) :
  5.         m_canvasRenderer{std::make_unique<CanvasRenderer>()}
  6.     {
  7.         m_ktSurface = GetJNIEnv()->NewGlobalRef(ktSurface);
  8.         *success = true;
  9.     }
  10. private:
  11.     std::unique_ptr<CanvasRenderer> m_canvasRenderer;
  12.     jobject m_ktSurface = nullptr;
  13. };
复制代码
5.4.3 flush

​    1)PLSWorkerImpl::flush
​    PLSWorkerImpl 的 flush 函数如下。renderContext->flush 函数的源码不在 rive-android 代码库中,在 rive-runtime 代码库中,详见 → render_context.cpp。
​    models/worker_impl.cpp
  1. @CallSuper
  2. override fun doFrame(frameTimeNanos: Long) {
  3.         if (isPlaying) {
  4.                 cppDoFrame(cppPointer)
  5.                 scheduleFrame()
  6.         }
  7. }
  8. open fun scheduleFrame() {
  9.         Handler(Looper.getMainLooper()).post {
  10.                 Choreographer.getInstance().postFrameCallback(this@Renderer)
  11.         }
  12. }
复制代码
​    2)CanvasWorkerImpl::flush
​    CanvasWorkerImpl 的 flush 函数如下,最终会调用 surface.unlockCanvasAndPost 函数。
​    models/worker_impl.cpp
  1. JNIEXPORT void JNICALL
  2. Java_app_rive_runtime_kotlin_renderers_Renderer_cppDoFrame(JNIEnv*, jobject, jlong rendererRef)
  3. {
  4.         reinterpret_cast<JNIRenderer*>(rendererRef)->doFrame();
  5. }
复制代码
​    models/canvas_renderer.hpp
  1. void JNIRenderer::doFrame()
  2. {
  3.     if (m_numScheduledFrames >= kMaxScheduledFrames)
  4.     {
  5.         return;
  6.     }
  7.     m_worker->run([this](DrawableThreadState* threadState) {
  8.         if (!m_workerImpl)
  9.             return;
  10.         auto now = std::chrono::high_resolution_clock::now();
  11.         m_workerImpl->doFrame(m_tracer, threadState, m_ktRenderer, now);
  12.         m_numScheduledFrames--;
  13.         calculateFps(now);
  14.     });
  15.     m_numScheduledFrames++;
  16. }
复制代码
​    GetSurfaceUnlockCanvasAndPostMethodId 函数调用了 surface.unlockCanvasAndPost 函数,具体实现如下。
​    models/jni_refs.cpp
  1. void WorkerImpl::doFrame(ITracer* tracer, DrawableThreadState* threadState, jobject ktRenderer,
  2.     std::chrono::high_resolution_clock::time_point frameTime)
  3. {
  4.     if (!m_isStarted)
  5.     {
  6.         return;
  7.     }
  8.     float fElapsedMs = std::chrono::duration<float>(frameTime - m_lastFrameTime).count();
  9.     m_lastFrameTime = frameTime;
  10.     auto env = GetJNIEnv();
  11.     // m_ktAdvanceCallback 在 start 函数中定义, 指向 kotlin 中 Renderer.advance 函数
  12.     JNIExceptionHandler::CallVoidMethod(env, ktRenderer, m_ktAdvanceCallback, fElapsedMs);
  13.     tracer->beginSection("draw()");
  14.     // 准备渲染状态, 调用 eglMakeCurrent 函数, 或 surface.lockCanvas 函数
  15.     prepareForDraw(threadState);
  16.     // m_ktDrawCallback 在 start 函数中定义, 指向 kotlin 中 Renderer.draw 函数
  17.     JNIExceptionHandler::CallVoidMethod(env, ktRenderer, m_ktDrawCallback);
  18.     tracer->beginSection("flush()");
  19.     flush(threadState); // 提交渲染指令
  20.     tracer->endSection(); // flush
  21.     tracer->beginSection("swapBuffers()");
  22.     threadState->swapBuffers(); // 交换缓冲区
  23.     tracer->endSection(); // swapBuffers
  24.     tracer->endSection(); // draw()
  25. }
复制代码
5.4.4 EGLThreadState::swapBuffers

​    DrawableThreadState 的子类中,只有 EGLThreadState 重写了 swapBuffers 函数,如下。eglSwapBuffers 函数用于交换缓冲区。
​    helpers/thread_state_egl.cpp
  1. virtual void prepareForDraw(DrawableThreadState* threadState) const override
  2. {
  3.         auto eglThreadState = static_cast<EGLThreadState*>(threadState);
  4.         // 里面调用了 eglMakeCurrent, 用于绑定 EGLSurface 和 EGLContext 到显示设备 (EGLDisplay)
  5.         eglThreadState->makeCurrent(m_eglSurface);
  6.         clear(threadState);
  7. }
复制代码
5.5 RiveArtboardRenderer.draw

​    5.4.1 节 WorkerImpl::doFrame 函数中,在 prepareForDraw 之后,调用了 m_ktDrawCallback,它指向的是 kotlin 中 Renderer.draw 函数,它是个抽象函数,RiveArtboardRenderer 中实现了该函数,如下。controller 是 RiveFileController 对象,它在 RiveAnimationView 的 init 代码块中创建,在 createRenderer 函数中传递给 RiveArtboardRenderer。activeArtboard 是 Artboard 对象,
​    app.rive.runtime.kotlin.renderers.RiveArtboardRenderer.kt
  1. void CanvasWorkerImpl::prepareForDraw(DrawableThreadState*) const
  2. {
  3.     m_canvasRenderer->bindCanvas(m_ktSurface);
  4. }
复制代码
5.6 Artboard.draw

​    app.rive.runtime.kotlin.core.Artboard.kt
  1. void bindCanvas(jobject ktSurface)
  2. {
  3.         ...
  4.         JNIEnv* env = GetJNIEnv();
  5.     // 通过 surface.lockCanvas 函数获取 Canvas 对象
  6.         m_ktCanvas = env->NewGlobalRef(GetCanvas(ktSurface));
  7.     // 通过 canvas.getWidth 函数获取 Canvas 的宽度
  8.         m_width = JNIExceptionHandler::CallIntMethod(env, m_ktCanvas, GetCanvasWidthMethodId());
  9.     // 通过 canvas.getHeight 函数获取 Canvas 的高度
  10.         m_height = JNIExceptionHandler::CallIntMethod(env, m_ktCanvas, GetCanvasHeightMethodId());
  11.         Clear(m_ktCanvas);
  12. }
  13. static jobject GetCanvas(jobject ktSurface)
  14. {
  15.         return GetJNIEnv()->CallObjectMethod(ktSurface, GetSurfaceLockCanvasMethodId(), nullptr);
  16. }
复制代码
5.7 JNI cppDrawAligned

​    全局搜索 "Artboard_cppDrawAligned",找到 JNI 中的 cppDrawAligned 函数的实现如下。首先获取 rive::ArtboardInstance 对象,接着通过 getRendererOnWorkerThread 函数获取 rive::RiveRenderer 或 CanavsRenderer 对象,最后调用 artboard->draw(renderer) 函数渲染一帧画面。rive::ArtboardInstance 的源码不在 rive-android 代码库中,在 rive-runtime 代码库中,详见 → artboard.hpp、artboard.cpp。
​    bindings/bindings_artboard.cpp
  1. jmethodID GetSurfaceLockCanvasMethodId()
  2. {
  3.     return GetMethodId(GetAndroidSurfaceClass(), "lockCanvas", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;");
  4. }
  5. jmethodID GetMethodId(jclass clazz, const char* name, const char* sig)
  6. {
  7.     JNIEnv* env = GetJNIEnv();
  8.     jmethodID output = env->GetMethodID(clazz, name, sig);
  9.     env->DeleteLocalRef(clazz);
  10.     return output;
  11. }
  12. jclass GetAndroidSurfaceClass() { return GetClass("android/view/Surface"); }
复制代码
6 启动渲染流程

​    启动渲染流程图如下。
5.png

6.1 启动渲染的源头

​    在 Rive 的 kotlin 源码中,通过调用 Renderer.start 函数启动渲染,但是,用户无法直接调用该函数,调用该函数的地方非常多,分成以下几类。
​    1)直接调用
​    以下函数中会直接调用 Renderer.start 函数启动渲染。

  • RiveAnimationView.onAttachedToWindow
  • RiveTextureView.onVisibilityChanged
  • Renderer.setSurface
​    2)RiveFileController.onStart
​    RiveFileController.onStart 也指向了 Renderer.start 函数,在 RiveFileController 的 fit、alignment、layoutScaleFactor、layoutScaleFactorAutomatic 等属性变化、以及 autoplay 属性变为 true 时,会调用 onStart.invoke 启动渲染。
​    3)间接调用
​    在 RiveAnimationView 的以下函数中,经过多步调用,最终会调用到 Renderer.start 函数启动渲染。

  • play
  • reset
  • fireState
  • setBooleanState
  • setNumberState
  • setTextRunValue
  • onTouchEvent
6.2 Renderer.start

​    Renderer 的 start 函数如下,通过 Choreographer.getInstance().postFrameCallback 函数让 doFrame 函数每帧调用一次,通过 cppStart 函数启动 Rive 引擎(rive::AudioEngine::RuntimeEngine)。
​    app.rive.runtime.kotlin.renderers.Renderer.kt
  1. abstract class Renderer(
  2.     @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
  3.     var type: RendererType = Rive.defaultRendererType,
  4.     val trace: Boolean = false
  5. ) : NativeObject(NULL_POINTER), Choreographer.FrameCallback    fun start() {        if (isPlaying) return        if (!isAttached) return        if (!hasCppObject) return        isPlaying = true        cppStart(cppPointer)        scheduleFrame()    }        open fun scheduleFrame() {        Handler(Looper.getMainLooper()).post {            Choreographer.getInstance().postFrameCallback(this@Renderer)        }    }        @CallSuper    override fun doFrame(frameTimeNanos: Long) {        if (isPlaying) {            cppDoFrame(cppPointer)            scheduleFrame()        }    }}
复制代码
6.3 JNI cppStart

​    全局搜索 "Renderer_cppStart",找到 JNI 中的 cppStart 函数的实现如下。
​    bindings/bindings_renderers.cpp
  1. void CanvasWorkerImpl::flush(DrawableThreadState*) const
  2. {
  3.     m_canvasRenderer->unlockAndPost(m_ktSurface);
  4. }
复制代码
6.4 JNIRenderer::start

​    JNIRenderer::start 的源码如下。m_worker 是 RefWorker 类的实例,RefWorker 继承 WorkThread,WorkThread 中创建了工作线程(见 3.5 节),并且有个 run 函数,m_worker->run 表示把任务提交到 WorkThread 中的工作线程中执行。m_workerImpl 是 4.6 节创建的 WorkerImpl 对象(可能是 PLSWorkerImpl 或 CanavsWorkerImpl)。
​    models/jni_renderer.cpp
  1. void unlockAndPost(jobject ktSurface)
  2. {
  3.         JNIEnv* env = GetJNIEnv();
  4.         JNIExceptionHandler::CallVoidMethod(env, ktSurface, GetSurfaceUnlockCanvasAndPostMethodId(), m_ktCanvas);
  5.         m_width = -1;
  6.         m_height = -1;
  7.         env->DeleteGlobalRef(m_ktCanvas);
  8.         m_ktCanvas = nullptr;
  9. }
复制代码
6.5 WorkerImpl::start

​    WorkerImpl::start 函数源码如下。这里主要初始化 m_ktRendererClass 、m_ktDrawCallback、m_ktAdvanceCallback,并启动 Rive 引擎。
​    models/worker_impl.cpp
  1. jmethodID GetSurfaceUnlockCanvasAndPostMethodId()
  2. {
  3.     return GetMethodId(GetAndroidSurfaceClass(), "unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V");
  4. }
  5. jmethodID GetMethodId(jclass clazz, const char* name, const char* sig)
  6. {
  7.     JNIEnv* env = GetJNIEnv();
  8.     jmethodID output = env->GetMethodID(clazz, name, sig);
  9.     env->DeleteLocalRef(clazz);
  10.     return output;
  11. }
  12. jclass GetAndroidSurfaceClass() { return GetClass("android/view/Surface"); }
复制代码
7 暂停渲染流程

​    暂停渲染流程图如下。
6.png

7.1 暂停渲染的源头

​    在 Rive 的 kotlin 源码中,通过调用 Renderer.stop 函数暂停渲染,但是,用户无法直接调用该函数,调用该函数的地方非常多,主要有以下几处。

  • RiveAnimationView.pause
  • RiveAnimationView.onDetachedFromWindow
  • RiveTextureView.onVisibilityChanged
7.2 Renderer.stop

​    Renderer 的 stop 函数如下,通过 cppStop 函数暂停 Rive 引擎(rive::AudioEngine::RuntimeEngine),通过 Choreographer.getInstance().removeFrameCallback 函数移除 doFrame 回调。
​    app.rive.runtime.kotlin.renderers.Renderer.kt
  1. abstract class Renderer(
  2.     @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
  3.     var type: RendererType = Rive.defaultRendererType,
  4.     val trace: Boolean = false
  5. ) : NativeObject(NULL_POINTER), Choreographer.FrameCallback    @CallSuper    fun stop() {        stopThread()        Handler(Looper.getMainLooper()).post { // postFrameCallback must be called from the main looper            Choreographer.getInstance().removeFrameCallback(this@Renderer)        }    }    @CallSuper    internal fun stopThread() {        if (!isPlaying) return        if (!hasCppObject) return        isPlaying = false        cppStop(cppPointer)    }        open fun scheduleFrame() {        Handler(Looper.getMainLooper()).post {            Choreographer.getInstance().postFrameCallback(this@Renderer)        }    }        @CallSuper    override fun doFrame(frameTimeNanos: Long) {        if (isPlaying) {            cppDoFrame(cppPointer)            scheduleFrame()        }    }}
复制代码
7.3 JNI cppStop

​    全局搜索 "Renderer_cppStop",找到 JNI 中的 cppStop 函数的实现如下。
​    bindings/bindings_renderers.cpp
  1. @WorkerThread
  2. override fun draw() {
  3.         synchronized(controller.file?.lock ?: this) {
  4.                 ...
  5.                 controller.activeArtboard?.draw(cppPointer, fit, alignment, scaleFactor = scaleFactor)
  6.         }
  7. }
复制代码
7.4 JNIRenderer::stop

​    JNIRenderer::stop 的源码如下。m_worker 是 RefWorker 类的实例,RefWorker 继承 WorkThread,WorkThread 中创建了工作线程(见 3.5 节),并且有个 run 函数,m_worker->run 表示把任务提交到 WorkThread 中的工作线程中执行。m_workerImpl 是 4.6 节创建的 WorkerImpl 对象(可能是 PLSWorkerImpl 或 CanavsWorkerImpl)。
​    models/jni_renderer.cpp
  1. @WorkerThread
  2. fun draw(rendererAddress: Long, fit: Fit, alignment: Alignment, scaleFactor: Float = 1.0f) {
  3.         synchronized(lock) {
  4.                 cppDrawAligned(cppPointer, rendererAddress, fit, alignment, scaleFactor)
  5.         }
  6. }
复制代码
7.5 WorkerImpl::stop

​    WorkerImpl::stop 函数源码如下。这里主要暂停 Rive 引擎,并将 m_ktRendererClass 、m_ktDrawCallback、m_ktAdvanceCallback 设置为空。
​    models/worker_impl.cpp
  1. JNIEXPORT void JNICALL
  2. Java_app_rive_runtime_kotlin_core_Artboard_cppDrawAligned(JNIEnv* env, jobject, jlong artboardRef,
  3.         jlong rendererRef, jobject ktFit, jobject ktAlignment, jfloat scaleFactor)
  4. {
  5.         auto artboard = reinterpret_cast<rive::ArtboardInstance*>(artboardRef); // 获取 ArtboardInstance 对象(未开放源码)
  6.         auto jniWrapper = reinterpret_cast<JNIRenderer*>(rendererRef); // 获取 JNIRenderer 对象
  7.     // 获取 rive::RiveRenderer 对象或 CanvasRenderer 对象
  8.         rive::Renderer* renderer = jniWrapper->getRendererOnWorkerThread();
  9.         rive::Fit fit = GetFit(env, ktFit);
  10.         rive::Alignment alignment = GetAlignment(env, ktAlignment);
  11.         renderer->save(); // 如果 renderer 是 CanvasRenderer, 将调用 canvas.save 函数
  12.         renderer->align(fit, alignment,
  13.                 rive::AABB(0, 0, jniWrapper->width(), jniWrapper->height()),
  14.                 artboard->bounds(),scaleFactor);
  15.         artboard->draw(renderer);
  16.         renderer->restore(); // 如果 renderer 是 CanvasRenderer, 将调用 canvas.restore 函数
  17. }
复制代码
声明:本文转自【Rive】rive-android源码分析。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册