1 前言
本文基于 rive-android 10.1.0 进行源码分析,主要介绍 Rive 的渲染类型、RendererType 透传流程、Surface 透传流程、渲染流程、启动渲染流程、暂停渲染流程等内容。
rive-android 类图框架如下。图中,蓝色的类表示 rive-android 中 Kotlin 代码,绿色的类表示 rive-android 中 C++ 代码,橙色的类表示 rive-runtime 中代码(下同)。本文只解读 rive-android 的源码,不解读 rive-runtime 的源码。
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- enum class RendererType(val value: Int) {
- Rive(0),
- Canvas(1);
- companion object {
- fun fromIndex(index: Int): RendererType {
- val maxIndex = entries.size
- ...
- return entries[index]
- }
- }
- }
复制代码 3 RendererType 透传流程
本节将介绍 RendererType 如何一步一步透传下去,直到最终创建 DrawableThreadState 对象。本节中,读者需要重点关注 RendererType 是如何在各个类之间传递的。RendererType 透传流程图如下。
3.1 设置 RendererType 的源头
用户在初始化 Rive 环境时,可以指定 RenderType,如下。- Rive.init(applicationContext, defaultRenderer = RendererType.Rive)
复制代码
也可以在布局文件中指定 RenderType(如果想使用 Winscope 或 Perfetto 查看 Trace,可以配置 riveTraceAnimations 参数),如下。- [/code] 无论是哪种方式,在 RiveAnimationView 对象被创建时,渲染类型会保存在 rendererAttributes 对象的 rendererType 属性中(rendererAttributes 是 RendererAttributes 类型)。
- [size=5]3.2 创建 RiveArtboardRenderer[/size]
- RiveAnimationView 继承了 RiveTextureView,RiveTextureView 继承了 TextureView,并重写了其 onAttachedToWindow 函数,如下。
- app.rive.runtime.kotlin.RiveTextureView.kt
- [code]@CallSuper
- override fun onAttachedToWindow() {
- super.onAttachedToWindow()
- surfaceTextureListener = this
- isOpaque = false
- renderer = createRenderer().apply { make() }
- }
复制代码 在 RiveAnimationView 中重写了 createRenderer 函数,如下。
app.rive.runtime.kotlin.RiveAnimationView.kt- override fun createRenderer(): Renderer {
- return RiveArtboardRenderer(
- trace = rendererAttributes.riveTraceAnimations,
- controller = controller,
- rendererType = rendererAttributes.rendererType,
- )
- }
复制代码 RiveArtboardRenderer 只有主构造函数,没有次要构造函数,如下。关于主构造函数和次要构造函数的介绍详见 → 类和对象。
app.rive.runtime.kotlin.renderers.RiveArtboardRenderer.kt- open class RiveArtboardRenderer(
- trace: Boolean = false,
- rendererType: RendererType = Rive.defaultRendererType,
- private var controller: RiveFileController,
- ) : Renderer(rendererType, trace)
复制代码 Renderer 的也只有主构造函数,没有次要构造函数,如下。
app.rive.runtime.kotlin.renderers.Renderer.kt- abstract class Renderer(
- @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- var type: RendererType = Rive.defaultRendererType,
- val trace: Boolean = false
- ) : 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- @CallSuper
- open fun make() {
- if (!hasCppObject) {
- cppPointer = constructor(trace, type.value)
- refs.incrementAndGet()
- }
- }
- /** Instantiates JNIRenderer in C++ */
- private external fun constructor(trace: Boolean, type: Int): Long
复制代码 全局搜索 "Renderer_constructor",找到 JNI 中的 constructor 函数的实现如下。
bindings/bindings_renderer.cpp- JNIEXPORT jlong JNICALL
- Java_app_rive_runtime_kotlin_renderers_Renderer_constructor(JNIEnv* env, jobject ktRenderer,
- jboolean trace, jint type)
- {
- RendererType rendererType = static_cast<RendererType>(type);
- JNIRenderer* renderer = new JNIRenderer(ktRenderer, trace, rendererType);
- ...
- return (jlong)renderer;
- }
复制代码 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- JNIRenderer::JNIRenderer(jobject ktRenderer, bool trace, const RendererType rendererType) :
- m_worker(RefWorker::CurrentOrFallback(rendererType)),
- m_ktRenderer(GetJNIEnv()->NewGlobalRef(ktRenderer)),
- m_tracer(getTracer(trace))
- {}
复制代码 3.4 创建 RefWorker
RefWorker::CurrentOrFallback 的源码如下。
helpers/work_ref.cpp- rcp<RefWorker> RefWorker::CurrentOrFallback(RendererType rendererType)
- {
- rcp<RefWorker> currentOrFallback;
- switch (rendererType)
- {
- case RendererType::None:
- assert(false);
- break;
- case RendererType::Rive:
- currentOrFallback = RiveWorker();
- break;
- case RendererType::Canvas:
- currentOrFallback = CanvasWorker();
- break;
- }
- if (currentOrFallback == nullptr)
- {
- currentOrFallback = CanvasWorker();
- }
- return currentOrFallback;
- }
复制代码 RiveWorker 和 CanvasWorker 函数实现如下。
helpers/work_ref.cpp- rcp<RefWorker> RefWorker::RiveWorker()
- {
- static enum class RiveRendererSupport { unknown, no, yes } s_isSupported;
- static std::unique_ptr<RefWorker> s_riveWorker;
- ...
- if (s_isSupported == RiveRendererSupport::unknown)
- {
- std::unique_ptr<RefWorker> candidateWorker(new RefWorker(RendererType::Rive));
- candidateWorker->runAndWait(
- [](rive_android::DrawableThreadState* threadState) {
- PLSThreadState* plsThreadState = static_cast<PLSThreadState*>(threadState);
- s_isSupported = plsThreadState->renderContext() != nullptr ? RiveRendererSupport::yes : RiveRendererSupport::no;
- });
- if (s_isSupported == RiveRendererSupport::yes)
- {
- s_riveWorker = std::move(candidateWorker);
- }
- ...
- }
- if (s_riveWorker != nullptr)
- {
- ++s_riveWorker->m_externalRefCount;
- }
- return rcp(s_riveWorker.get());
- }
- rcp<RefWorker> RefWorker::CanvasWorker()
- {
- if (s_canvasWorker == nullptr)
- {
- s_canvasWorker = std::unique_ptr<RefWorker>(new RefWorker(RendererType::Canvas));
- }
- ++s_canvasWorker->m_externalRefCount;
- return rcp(s_canvasWorker.get());
- }
复制代码 RefWorker 继承 WorkerThread,如下。
helpers/work_ref.hpp- explicit RefWorker(const RendererType rendererType) :
- WorkerThread(RendererName(rendererType), Affinity::None, rendererType)
- {}
复制代码 3.5 创建 WorkThread
WorkThread 的构造函数如下,可以看到这里创建了一个线程,用于处理渲染任务。
helpers/worker_thread.hpp- WorkerThread(const char* name, Affinity affinity, const RendererType rendererType) :
- m_RendererType(rendererType),
- mName(name),
- mAffinity(affinity),
- mWorkMutex{}
- {
- mThread = std::thread([this]() { threadMain(); });
- }
复制代码 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- void threadMain()
- {
- setAffinity(mAffinity);
- ...
- m_threadState = MakeThreadState(m_RendererType);
- std::unique_lock lock(mWorkMutex);
- for (;;)
- {
- while (mWorkQueue.empty())
- {
- m_workPushedCondition.wait(mWorkMutex);
- }
- Work work = mWorkQueue.front();
- mWorkQueue.pop();
- if (!work)
- {
- // A null function is a special token that tells the thread to terminate.
- break;
- }
- lock.unlock();
- work(m_threadState.get());
- lock.lock();
- ++m_lastCompletedWorkID;
- m_workedCompletedCondition.notify_all();
- }
- m_threadState.reset();
- DetachThread();
- }
复制代码 4.5 WorkerImpl::Make
models/worker_impl.cpp- std::unique_ptr<DrawableThreadState> WorkerThread::MakeThreadState(const RendererType type)
- {
- switch (type)
- {
- case RendererType::Canvas:
- return std::make_unique<CanvasThreadState>();
- default:
- case RendererType::Rive:
- return std::make_unique<PLSThreadState>();
- }
- }
复制代码 4.6 创建 WorkerImpl
PLSWorkerImpl 继承 EGLWorkerImpl,EGLWorkerImpl 和 CanvasWorkerImpl 继承 WorkerImpl。
4.6.1 WorkerImpl 接口定义
models/worker_impl.hpp- class DrawableThreadState
- {
- public:
- virtual ~DrawableThreadState(){};
- virtual void swapBuffers() = 0;
- };
- class EGLThreadState : public DrawableThreadState
- {
- public:
- EGLThreadState();
- virtual ~EGLThreadState() = 0;
- EGLSurface createEGLSurface(ANativeWindow*);
- virtual void destroySurface(EGLSurface) = 0;
- virtual void makeCurrent(EGLSurface) = 0;
- void swapBuffers() override;
- protected:
- EGLSurface m_currentSurface = EGL_NO_SURFACE;
- EGLDisplay m_display = EGL_NO_DISPLAY;
- EGLContext m_context = EGL_NO_CONTEXT;
- EGLConfig m_config = static_cast<EGLConfig>(0);
- };
- class CanvasThreadState : public DrawableThreadState
- {
- public:
- void swapBuffers() override {}
- };
复制代码 4.6.2 创建 EGLWorkerImpl
EGLWorkerImpl 的构造函数如下。
models/worker_impl.hpp- EGLThreadState::EGLThreadState()
- {
- // 创建 EGLDisplay
- m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- ...
- if (!eglInitialize(m_display, 0, 0))
- {
- ...
- return;
- }
- // 创建 EGLConfig
- const EGLint configAttributes[] = {...};
- ...
- eglChooseConfig(m_display, configAttributes, supportedConfigs.data(), num_configs, &num_configs);
- ...
- // 创建 EGLContext
- m_context = eglCreateContext(m_display, m_config, nullptr, contextAttributes);
- ...
- }
复制代码 EGLThreadState::createEGLSurface 函数源码如下。eglCreateWindowSurface 用于创建一个与屏幕窗口相关的 EGL 表面,这个表面通常与设备的窗口系统交互,使得 OpenGL ES 渲染的内容能够显示在屏幕上(补充:eglCreatePbufferSurface 用于创建一个离屏渲染的 EGL 表面)。
helpers/thread_state_egl.cpp- PLSThreadState::PLSThreadState()
- {
- // 创建 EGLSurface
- const EGLint PbufferAttrs[] = {...};
- m_backgroundSurface = eglCreatePbufferSurface(m_display, m_config, PbufferAttrs);
- ...
- // 绑定 EGLSurface 和 EGLContext 到显示设备 (EGLDisplay)
- eglMakeCurrent(m_display, m_backgroundSurface, m_backgroundSurface, m_context);
- m_currentSurface = m_backgroundSurface;
- m_renderContext = rive::gpu::RenderContextGLImpl::MakeContext();
- }
复制代码 4.6.3 创建 PLSWorkerImpl
PLSWorkerImpl 的构造函数如下,最终创建了 rive::RiveRenderer 对象,其源码不在 rive-android 代码库中,在 rive-runtime 代码库中,详见 → rive_renderer.cpp。
models/worker_impl.cpp- @CallSuper
- override fun onSurfaceTextureAvailable(
- surfaceTexture: SurfaceTexture, width: Int, height: Int) {
- if (this::viewSurface.isInitialized) {
- viewSurface.release()
- }
- viewSurface = Surface(surfaceTexture)
- renderer?.apply {
- stop()
- setSurface(viewSurface)
- }
- }
复制代码 PLSThreadState::makeCurrent 函数的实现如下,eglMakeCurrent 是 EGL 环境创建的最后一步,作用是绑定 EGLSurface 和 EGLContext 到显示设备(EGLDisplay)。
helpers/thread_state_pls.cpp- fun setSurface(surface: Surface) {
- cppSetSurface(surface, cppPointer)
- isAttached = true
- start()
- }
复制代码 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- JNIEXPORT void JNICALL
- Java_app_rive_runtime_kotlin_renderers_Renderer_cppSetSurface(JNIEnv* env, jobject,
- jobject surface, jlong rendererRef)
- {
- JNIRenderer* renderer = reinterpret_cast<JNIRenderer*>(rendererRef);
- if (renderer->rendererType() != RendererType::Canvas)
- {
- ANativeWindow* surfaceWindow = ANativeWindow_fromSurface(env, surface);
- reinterpret_cast<JNIRenderer*>(rendererRef) ->setSurface(surfaceWindow);
- if (surfaceWindow)
- {
- ANativeWindow_release(surfaceWindow);
- }
- }
- else
- {
- renderer->setSurface(surface);
- }
- }
复制代码 5 渲染流程
渲染流程图如下。
5.1 Renderer.doFrame
Renderer 实现了 Choreographer.FrameCallback 接口,重写了其 doFrame 方法,其 doFrame 和 scheduleFrame 方法源码如下。
app.rive.runtime.kotlin.renderers.Renderer.kt- void JNIRenderer::setSurface(SurfaceVariant surface)
- {
- SurfaceVariant oldSurface = m_surface;
- acquireSurface(surface);
- m_worker->run([this, oldSurface](DrawableThreadState* threadState) mutable {
- m_workerThreadID = std::this_thread::get_id();
- ...
- if (m_surface.index() > 0)
- {
- m_workerImpl = WorkerImpl::Make(m_surface, threadState, m_worker->rendererType());
- }
- });
- }
复制代码 5.2 JNI cppDoFrame
全局搜索 "Renderer_cppDoFrame",找到 JNI 中的 cppDoFrame 函数的实现如下。
bindings/bindings_renderer.cpp- std::unique_ptr<WorkerImpl> WorkerImpl::Make(SurfaceVariant surface,
- DrawableThreadState* threadState, const RendererType type)
- {
- ...
- bool success = false;
- std::unique_ptr<WorkerImpl> impl;
- switch (type)
- {
- case RendererType::Rive:
- {
- ANativeWindow* window = std::get(surface);
- impl = std::make_unique<PLSWorkerImpl>(window, threadState, &success);
- break;
- }
- case RendererType::Canvas:
- {
- jobject ktSurface = std::get<jobject>(surface);
- impl = std::make_unique<CanvasWorkerImpl>(ktSurface, &success);
- }
- default:
- break;
- }
- ...
- return impl;
- }
复制代码 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- class WorkerImpl
- {
- public:
- static std::unique_ptr<WorkerImpl> Make(SurfaceVariant, DrawableThreadState*, const RendererType);
- void start(jobject ktRenderer, std::chrono::high_resolution_clock::time_point);
- void stop();
- void doFrame(ITracer*, DrawableThreadState*, jobject ktRenderer, std::chrono::high_resolution_clock::time_point);
- virtual void prepareForDraw(DrawableThreadState*) const = 0;
- virtual void destroy(DrawableThreadState*) = 0;
- virtual void flush(DrawableThreadState*) const = 0;
- virtual rive::Renderer* renderer() const = 0;
- protected:
- jclass m_ktRendererClass = nullptr;
- jmethodID m_ktDrawCallback = nullptr;
- jmethodID m_ktAdvanceCallback = nullptr;
- std::chrono::high_resolution_clock::time_point m_lastFrameTime;
- bool m_isStarted = false;
- };
复制代码 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- class EGLWorkerImpl : public WorkerImpl
- {
- ...
- protected:
- EGLWorkerImpl(struct ANativeWindow* window, DrawableThreadState* threadState, bool* success)
- {
- *success = false;
- auto eglThreadState = static_cast<EGLThreadState*>(threadState);
- m_eglSurface = eglThreadState->createEGLSurface(window);
- if (m_eglSurface == EGL_NO_SURFACE)
- return;
- *success = true;
- }
- ...
- };
复制代码 接下来,分别介绍 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- EGLSurface EGLThreadState::createEGLSurface(ANativeWindow* window)
- {
- if (!window)
- {
- return EGL_NO_SURFACE;
- }
- ...
- // 创建一个与屏幕窗口相关的 EGL 表面, 这个表面通常与设备的窗口系统交, 使得 OpenGL ES 渲染的内容能够显示在屏幕上
- auto res = eglCreateWindowSurface(m_display, m_config, window, nullptr);
- ...
- return res;
- }
复制代码 2)CanvasWorkerImpl::prepareForDraw
CanvasWorkerImpl 的 prepareForDraw 函数源码如下。其作用是通过 surface.lockCanvas 方法拿到 Canvas 对象。
models/worker_impl.cpp- PLSWorkerImpl::PLSWorkerImpl(struct ANativeWindow* window, DrawableThreadState* threadState, bool* success) :
- EGLWorkerImpl(window, threadState, success)
- {
- if (!success)
- {
- return;
- }
- auto eglThreadState = static_cast<EGLThreadState*>(threadState);
- eglThreadState->makeCurrent(m_eglSurface);
- rive::gpu::RenderContext* renderContext = PLSWorkerImpl::PlsThreadState(eglThreadState)->renderContext();
- if (renderContext == nullptr)
- {
- return; // PLS was not supported.
- }
- int width = ANativeWindow_getWidth(window); // 获取窗口宽度
- int height = ANativeWindow_getHeight(window); // 获取窗口高度
- GLint sampleCount; // 多重采样数
- glBindFramebuffer(GL_FRAMEBUFFER, 0); // 绑定默认帧缓冲区
- glGetIntegerv(GL_SAMPLES, &sampleCount); // 查询当前的多重采样数
- // 创建一个基于 GLES 的帧缓冲区渲染目标,用于离屏渲染
- m_renderTarget = rive::make_rcp<rive::gpu::FramebufferRenderTargetGL>(width, height, 0, sampleCount);
- // 初始化 Rive 的 PLS 渲染器
- m_plsRenderer = std::make_unique<rive::RiveRenderer>(renderContext);
- *success = true;
- }
复制代码 bindCanvas 函数源码如下,m_ktCanvas 是通过 surface.lockCanvas 函数获取的 Canvas 对象。
models/canvas_renderer.hpp- void PLSThreadState::makeCurrent(EGLSurface eglSurface)
- {
- if (eglSurface == m_currentSurface)
- {
- return;
- }
- ...
- // 绑定 EGLSurface 和 EGLContext 到显示设备 (EGLDisplay)
- eglMakeCurrent(m_display, eglSurface, eglSurface, m_context);
- m_currentSurface = eglSurface;
- ...
- }
复制代码 GetSurfaceLockCanvasMethodId 用于获取 surface.lockCanvas 的方法 id,具体实现如下。这里没有调用 surface.lockHardwareCanvas 方法,说明 Canvas 渲染方式是软渲染(即 CPU 渲染,而不是 GPU 渲染)。
models/jni_refs.cpp- class CanvasWorkerImpl : public WorkerImpl
- {
- public:
- CanvasWorkerImpl(jobject ktSurface, bool* success) :
- m_canvasRenderer{std::make_unique<CanvasRenderer>()}
- {
- m_ktSurface = GetJNIEnv()->NewGlobalRef(ktSurface);
- *success = true;
- }
- private:
- std::unique_ptr<CanvasRenderer> m_canvasRenderer;
- jobject m_ktSurface = nullptr;
- };
复制代码 5.4.3 flush
1)PLSWorkerImpl::flush
PLSWorkerImpl 的 flush 函数如下。renderContext->flush 函数的源码不在 rive-android 代码库中,在 rive-runtime 代码库中,详见 → render_context.cpp。
models/worker_impl.cpp- @CallSuper
- override fun doFrame(frameTimeNanos: Long) {
- if (isPlaying) {
- cppDoFrame(cppPointer)
- scheduleFrame()
- }
- }
- open fun scheduleFrame() {
- Handler(Looper.getMainLooper()).post {
- Choreographer.getInstance().postFrameCallback(this@Renderer)
- }
- }
复制代码 2)CanvasWorkerImpl::flush
CanvasWorkerImpl 的 flush 函数如下,最终会调用 surface.unlockCanvasAndPost 函数。
models/worker_impl.cpp- JNIEXPORT void JNICALL
- Java_app_rive_runtime_kotlin_renderers_Renderer_cppDoFrame(JNIEnv*, jobject, jlong rendererRef)
- {
- reinterpret_cast<JNIRenderer*>(rendererRef)->doFrame();
- }
复制代码 models/canvas_renderer.hpp- void JNIRenderer::doFrame()
- {
- if (m_numScheduledFrames >= kMaxScheduledFrames)
- {
- return;
- }
- m_worker->run([this](DrawableThreadState* threadState) {
- if (!m_workerImpl)
- return;
- auto now = std::chrono::high_resolution_clock::now();
- m_workerImpl->doFrame(m_tracer, threadState, m_ktRenderer, now);
- m_numScheduledFrames--;
- calculateFps(now);
- });
- m_numScheduledFrames++;
- }
复制代码 GetSurfaceUnlockCanvasAndPostMethodId 函数调用了 surface.unlockCanvasAndPost 函数,具体实现如下。
models/jni_refs.cpp- void WorkerImpl::doFrame(ITracer* tracer, DrawableThreadState* threadState, jobject ktRenderer,
- std::chrono::high_resolution_clock::time_point frameTime)
- {
- if (!m_isStarted)
- {
- return;
- }
- float fElapsedMs = std::chrono::duration<float>(frameTime - m_lastFrameTime).count();
- m_lastFrameTime = frameTime;
- auto env = GetJNIEnv();
- // m_ktAdvanceCallback 在 start 函数中定义, 指向 kotlin 中 Renderer.advance 函数
- JNIExceptionHandler::CallVoidMethod(env, ktRenderer, m_ktAdvanceCallback, fElapsedMs);
- tracer->beginSection("draw()");
- // 准备渲染状态, 调用 eglMakeCurrent 函数, 或 surface.lockCanvas 函数
- prepareForDraw(threadState);
- // m_ktDrawCallback 在 start 函数中定义, 指向 kotlin 中 Renderer.draw 函数
- JNIExceptionHandler::CallVoidMethod(env, ktRenderer, m_ktDrawCallback);
- tracer->beginSection("flush()");
- flush(threadState); // 提交渲染指令
- tracer->endSection(); // flush
- tracer->beginSection("swapBuffers()");
- threadState->swapBuffers(); // 交换缓冲区
- tracer->endSection(); // swapBuffers
- tracer->endSection(); // draw()
- }
复制代码 5.4.4 EGLThreadState::swapBuffers
DrawableThreadState 的子类中,只有 EGLThreadState 重写了 swapBuffers 函数,如下。eglSwapBuffers 函数用于交换缓冲区。
helpers/thread_state_egl.cpp- virtual void prepareForDraw(DrawableThreadState* threadState) const override
- {
- auto eglThreadState = static_cast<EGLThreadState*>(threadState);
- // 里面调用了 eglMakeCurrent, 用于绑定 EGLSurface 和 EGLContext 到显示设备 (EGLDisplay)
- eglThreadState->makeCurrent(m_eglSurface);
- clear(threadState);
- }
复制代码 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- void CanvasWorkerImpl::prepareForDraw(DrawableThreadState*) const
- {
- m_canvasRenderer->bindCanvas(m_ktSurface);
- }
复制代码 5.6 Artboard.draw
app.rive.runtime.kotlin.core.Artboard.kt- void bindCanvas(jobject ktSurface)
- {
- ...
- JNIEnv* env = GetJNIEnv();
- // 通过 surface.lockCanvas 函数获取 Canvas 对象
- m_ktCanvas = env->NewGlobalRef(GetCanvas(ktSurface));
- // 通过 canvas.getWidth 函数获取 Canvas 的宽度
- m_width = JNIExceptionHandler::CallIntMethod(env, m_ktCanvas, GetCanvasWidthMethodId());
- // 通过 canvas.getHeight 函数获取 Canvas 的高度
- m_height = JNIExceptionHandler::CallIntMethod(env, m_ktCanvas, GetCanvasHeightMethodId());
- Clear(m_ktCanvas);
- }
- static jobject GetCanvas(jobject ktSurface)
- {
- return GetJNIEnv()->CallObjectMethod(ktSurface, GetSurfaceLockCanvasMethodId(), nullptr);
- }
复制代码 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- jmethodID GetSurfaceLockCanvasMethodId()
- {
- return GetMethodId(GetAndroidSurfaceClass(), "lockCanvas", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;");
- }
- jmethodID GetMethodId(jclass clazz, const char* name, const char* sig)
- {
- JNIEnv* env = GetJNIEnv();
- jmethodID output = env->GetMethodID(clazz, name, sig);
- env->DeleteLocalRef(clazz);
- return output;
- }
- jclass GetAndroidSurfaceClass() { return GetClass("android/view/Surface"); }
复制代码 6 启动渲染流程
启动渲染流程图如下。
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- abstract class Renderer(
- @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- var type: RendererType = Rive.defaultRendererType,
- val trace: Boolean = false
- ) : 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- void CanvasWorkerImpl::flush(DrawableThreadState*) const
- {
- m_canvasRenderer->unlockAndPost(m_ktSurface);
- }
复制代码 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- void unlockAndPost(jobject ktSurface)
- {
- JNIEnv* env = GetJNIEnv();
- JNIExceptionHandler::CallVoidMethod(env, ktSurface, GetSurfaceUnlockCanvasAndPostMethodId(), m_ktCanvas);
- m_width = -1;
- m_height = -1;
- env->DeleteGlobalRef(m_ktCanvas);
- m_ktCanvas = nullptr;
- }
复制代码 6.5 WorkerImpl::start
WorkerImpl::start 函数源码如下。这里主要初始化 m_ktRendererClass 、m_ktDrawCallback、m_ktAdvanceCallback,并启动 Rive 引擎。
models/worker_impl.cpp- jmethodID GetSurfaceUnlockCanvasAndPostMethodId()
- {
- return GetMethodId(GetAndroidSurfaceClass(), "unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V");
- }
- jmethodID GetMethodId(jclass clazz, const char* name, const char* sig)
- {
- JNIEnv* env = GetJNIEnv();
- jmethodID output = env->GetMethodID(clazz, name, sig);
- env->DeleteLocalRef(clazz);
- return output;
- }
- jclass GetAndroidSurfaceClass() { return GetClass("android/view/Surface"); }
复制代码 7 暂停渲染流程
暂停渲染流程图如下。
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- abstract class Renderer(
- @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- var type: RendererType = Rive.defaultRendererType,
- val trace: Boolean = false
- ) : 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- @WorkerThread
- override fun draw() {
- synchronized(controller.file?.lock ?: this) {
- ...
- controller.activeArtboard?.draw(cppPointer, fit, alignment, scaleFactor = scaleFactor)
- }
- }
复制代码 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- @WorkerThread
- fun draw(rendererAddress: Long, fit: Fit, alignment: Alignment, scaleFactor: Float = 1.0f) {
- synchronized(lock) {
- cppDrawAligned(cppPointer, rendererAddress, fit, alignment, scaleFactor)
- }
- }
复制代码 7.5 WorkerImpl::stop
WorkerImpl::stop 函数源码如下。这里主要暂停 Rive 引擎,并将 m_ktRendererClass 、m_ktDrawCallback、m_ktAdvanceCallback 设置为空。
models/worker_impl.cpp- JNIEXPORT void JNICALL
- Java_app_rive_runtime_kotlin_core_Artboard_cppDrawAligned(JNIEnv* env, jobject, jlong artboardRef,
- jlong rendererRef, jobject ktFit, jobject ktAlignment, jfloat scaleFactor)
- {
- auto artboard = reinterpret_cast<rive::ArtboardInstance*>(artboardRef); // 获取 ArtboardInstance 对象(未开放源码)
- auto jniWrapper = reinterpret_cast<JNIRenderer*>(rendererRef); // 获取 JNIRenderer 对象
- // 获取 rive::RiveRenderer 对象或 CanvasRenderer 对象
- rive::Renderer* renderer = jniWrapper->getRendererOnWorkerThread();
- rive::Fit fit = GetFit(env, ktFit);
- rive::Alignment alignment = GetAlignment(env, ktAlignment);
- renderer->save(); // 如果 renderer 是 CanvasRenderer, 将调用 canvas.save 函数
- renderer->align(fit, alignment,
- rive::AABB(0, 0, jniWrapper->width(), jniWrapper->height()),
- artboard->bounds(),scaleFactor);
- artboard->draw(renderer);
- renderer->restore(); // 如果 renderer 是 CanvasRenderer, 将调用 canvas.restore 函数
- }
复制代码 声明:本文转自【Rive】rive-android源码分析。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |