【Rive】rive-android源碼分析
1 前言
? 本文基于 rive-android 10.1.0 進行源碼分析,主要介紹 Rive 的渲染類型、RendererType 透傳流程、Surface 透傳流程、渲染流程、啟動渲染流程、暫停渲染流程等內容。
? rive-android 類圖框架如下。圖中,藍色的類表示 rive-android 中 Kotlin 代碼,綠色的類表示 rive-android 中 C++ 代碼,橙色的類表示 rive-runtime 中代碼(下同)。本文只解讀 rive-android 的源碼,不解讀 rive-runtime 的源碼。

? 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 參數),如下。
<app.rive.runtime.kotlin.RiveAnimationView
app:riveRenderer="Rive"
app:riveTraceAnimations="true"
… />
? 無論是哪種方式,在 RiveAnimationView 對象被創建時,渲染類型會保存在 rendererAttributes 對象的 rendererType 屬性中(rendererAttributes 是 RendererAttributes 類型)。
3.2 創建 RiveArtboardRenderer
? RiveAnimationView 繼承了 RiveTextureView,RiveTextureView 繼承了 TextureView,并重寫了其 onAttachedToWindow 函數,如下。
? app.rive.runtime.kotlin.RiveTextureView.kt
@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 中的元素是 function<void(DrawableThreadState*) 類型的函數指針),線程將處于 wait 狀態,否則從工作隊列中取出函數指針元素,并執行函數;如果從工作隊列中取出的函數指針為空,將結束線程。
? helpers/worker_thread.hpp
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();
}
3.6 創建 DrawableThreadState
? MakeThreadState 函數的實現如下。
? helpers/worker_thread.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>();
}
}
? CanvasThreadState 繼承 DrawableThreadState,PLSThreadState 繼承 EGLThreadState,EGLThreadState 繼承 DrawableThreadState(在 rive-android 10.0.0 之前的版本,還有 SkiaThreadState 也繼承 EGLThreadState,它對應的 RenderType 是 Skia)。
3.6.1 DrawableThreadState、EGLThreadState、CanvasThreadState 接口定義
? DrawableThreadState、EGLThreadState、CanvasThreadState 的接口定義如下。
? helpers/thread_state_egl.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 {}
};
3.6.2 創建 EGLThreadState
? EGLThreadState 的構造函數源碼如下,它實現了 EGL 環境創建 5 步中的前 3步,剩下 2 步在 PLSThreadState 的構造函數中實現。EGL 環境創建詳見 → EGL+FBO離屏渲染。
? helpers/thread_state_egl.cpp
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);
...
}
3.6.3 創建 PLSThreadState
? PLSThreadState 的構造函數源碼如下,它實現了 EGL 環境創建 5 步中的后 2步。eglCreatePbufferSurface 用于創建一個離屏渲染的 EGL 表面,Pbuffer 表面是一個虛擬的離屏緩沖區,可以在其中進行渲染操作,而不直接與屏幕交互。rive::gpu::RenderContextGLImpl::MakeContext 的源碼不在 rive-android 代碼庫中,在 rive-runtime 代碼庫中,詳見 → render_context_gl_impl.cpp。
? helpers/thread_state_psl.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 Surface 透傳流程
? 本節將介紹 Surface 如何一步一步透傳下去,直到最終創建 rive::RiveRenderer 對象或 CanvasRenderer 對象。本節中,讀者需要重點關注 Surface 是如何在各個類之間傳遞的。Surface 透傳流程圖如下。

4.1 Surface 創建的源頭
? 在 RiveTextureView 的 onSurfaceTextureAvailable 方法中,創建了 Surface 如下。
? app.rive.runtime.kotlin.RiveTextureView.kt
@CallSuper
override fun onSurfaceTextureAvailable(
surfaceTexture: SurfaceTexture, width: Int, height: Int) {
if (this::viewSurface.isInitialized) {
viewSurface.release()
}
viewSurface = Surface(surfaceTexture)
renderer?.apply {
stop()
setSurface(viewSurface)
}
}
4.2 Renderer.setSurface
? Renderer 的 setSurface 函數源碼如下。cppPointer 是在 NativeObject 中定義的 Long 類型變量,對應 C++ 中的指針變量,指向的是 JNI 中 JNIRenderer 對象。
? app.rive.runtime.kotlin.renderers.Renderer.kt
fun setSurface(surface: Surface) {
cppSetSurface(surface, cppPointer)
isAttached = true
start()
}
4.3 JNI cppSetSurface
? 全局搜索 Renderer_cppSetSurface,找到 JNI 層 cppSetSurface 函數的實現如下。對于 Rive 渲染類型,將創建一個 ANativeWindow 指針(ANativeWindow_fromSurface 函數詳見 aosp 中的 frameworks/base/native/android/native_window_jni.cpp),并將 ANativeWindow 指針傳遞到 JNIRenderer 中;對于 Canvas 渲染類型,直接將 Surface 傳遞到 JNIRenderer 中。
? bindings/bindings_renderer.cpp
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);
}
}
4.4 JNIRenderer::setSurface
? JNIRenderer::setSurface 的源碼如下。m_worker 是 RefWorker 類的實例,RefWorker 繼承 WorkThread,WorkThread 中創建了工作線程(見 3.5 節),并且有個 run 函數,m_worker->run 表示把任務提交到 WorkThread 中的工作線程中執行。
? models/jni_renderer.cpp
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());
}
});
}
4.5 WorkerImpl::Make
? models/worker_impl.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<ANativeWindow*>(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;
}
4.6 創建 WorkerImpl
? PLSWorkerImpl 繼承 EGLWorkerImpl,EGLWorkerImpl 和 CanvasWorkerImpl 繼承 WorkerImpl。
4.6.1 WorkerImpl 接口定義
? models/worker_impl.hpp
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;
};
4.6.2 創建 EGLWorkerImpl
? EGLWorkerImpl 的構造函數如下。
? models/worker_impl.hpp
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;
}
...
};
? EGLThreadState::createEGLSurface 函數源碼如下。eglCreateWindowSurface 用于創建一個與屏幕窗口相關的 EGL 表面,這個表面通常與設備的窗口系統交互,使得 OpenGL ES 渲染的內容能夠顯示在屏幕上(補充:eglCreatePbufferSurface 用于創建一個離屏渲染的 EGL 表面)。
? helpers/thread_state_egl.cpp
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;
}
4.6.3 創建 PLSWorkerImpl
? PLSWorkerImpl 的構造函數如下,最終創建了 rive::RiveRenderer 對象,其源碼不在 rive-android 代碼庫中,在 rive-runtime 代碼庫中,詳見 → rive_renderer.cpp。
? 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;
}
? PLSThreadState::makeCurrent 函數的實現如下,eglMakeCurrent 是 EGL 環境創建的最后一步,作用是綁定 EGLSurface 和 EGLContext 到顯示設備(EGLDisplay)。
? helpers/thread_state_pls.cpp
void PLSThreadState::makeCurrent(EGLSurface eglSurface)
{
if (eglSurface == m_currentSurface)
{
return;
}
...
// 綁定 EGLSurface 和 EGLContext 到顯示設備 (EGLDisplay)
eglMakeCurrent(m_display, eglSurface, eglSurface, m_context);
m_currentSurface = eglSurface;
...
}
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
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 渲染流程
? 渲染流程圖如下。

5.1 Renderer.doFrame
? Renderer 實現了 Choreographer.FrameCallback 接口,重寫了其 doFrame 方法,其 doFrame 和 scheduleFrame 方法源碼如下。
? app.rive.runtime.kotlin.renderers.Renderer.kt
@CallSuper
override fun doFrame(frameTimeNanos: Long) {
if (isPlaying) {
cppDoFrame(cppPointer)
scheduleFrame()
}
}
open fun scheduleFrame() {
Handler(Looper.getMainLooper()).post {
Choreographer.getInstance().postFrameCallback(this@Renderer)
}
}
5.2 JNI cppDoFrame
? 全局搜索 "Renderer_cppDoFrame",找到 JNI 中的 cppDoFrame 函數的實現如下。
? bindings/bindings_renderer.cpp
JNIEXPORT void JNICALL
Java_app_rive_runtime_kotlin_renderers_Renderer_cppDoFrame(JNIEnv*, jobject, jlong rendererRef)
{
reinterpret_cast<JNIRenderer*>(rendererRef)->doFrame();
}
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
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++;
}
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
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()
}
? 接下來,分別介紹 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
virtual void prepareForDraw(DrawableThreadState* threadState) const override
{
auto eglThreadState = static_cast<EGLThreadState*>(threadState);
// 里面調用了 eglMakeCurrent, 用于綁定 EGLSurface 和 EGLContext 到顯示設備 (EGLDisplay)
eglThreadState->makeCurrent(m_eglSurface);
clear(threadState);
}
? 2)CanvasWorkerImpl::prepareForDraw
? CanvasWorkerImpl 的 prepareForDraw 函數源碼如下。其作用是通過 surface.lockCanvas 方法拿到 Canvas 對象。
? models/worker_impl.cpp
void CanvasWorkerImpl::prepareForDraw(DrawableThreadState*) const
{
m_canvasRenderer->bindCanvas(m_ktSurface);
}
? bindCanvas 函數源碼如下,m_ktCanvas 是通過 surface.lockCanvas 函數獲取的 Canvas 對象。
? models/canvas_renderer.hpp
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);
}
? GetSurfaceLockCanvasMethodId 用于獲取 surface.lockCanvas 的方法 id,具體實現如下。這里沒有調用 surface.lockHardwareCanvas 方法,說明 Canvas 渲染方式是軟渲染(即 CPU 渲染,而不是 GPU 渲染)。
? models/jni_refs.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"); }
5.4.3 flush
? 1)PLSWorkerImpl::flush
? PLSWorkerImpl 的 flush 函數如下。renderContext->flush 函數的源碼不在 rive-android 代碼庫中,在 rive-runtime 代碼庫中,詳見 → render_context.cpp。
? models/worker_impl.cpp
void PLSWorkerImpl::flush(DrawableThreadState* threadState) const
{
PLSThreadState* plsThreadState = PLSWorkerImpl::PlsThreadState(threadState);
rive::gpu::RenderContext* renderContext = plsThreadState->renderContext();
renderContext->flush({.renderTarget = m_renderTarget.get()});
}
? 2)CanvasWorkerImpl::flush
? CanvasWorkerImpl 的 flush 函數如下,最終會調用 surface.unlockCanvasAndPost 函數。
? models/worker_impl.cpp
void CanvasWorkerImpl::flush(DrawableThreadState*) const
{
m_canvasRenderer->unlockAndPost(m_ktSurface);
}
? models/canvas_renderer.hpp
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;
}
? GetSurfaceUnlockCanvasAndPostMethodId 函數調用了 surface.unlockCanvasAndPost 函數,具體實現如下。
? models/jni_refs.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"); }
5.4.4 EGLThreadState::swapBuffers
? DrawableThreadState 的子類中,只有 EGLThreadState 重寫了 swapBuffers 函數,如下。eglSwapBuffers 函數用于交換緩沖區。
? helpers/thread_state_egl.cpp
void EGLThreadState::swapBuffers()
{
eglSwapBuffers(m_display, m_currentSurface); // 交換緩沖區
EGL_ERR_CHECK();
}
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
@WorkerThread
override fun draw() {
synchronized(controller.file?.lock ?: this) {
...
controller.activeArtboard?.draw(cppPointer, fit, alignment, scaleFactor = scaleFactor)
}
}
5.6 Artboard.draw
? app.rive.runtime.kotlin.core.Artboard.kt
@WorkerThread
fun draw(rendererAddress: Long, fit: Fit, alignment: Alignment, scaleFactor: Float = 1.0f) {
synchronized(lock) {
cppDrawAligned(cppPointer, rendererAddress, fit, alignment, scaleFactor)
}
}
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
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 函數
}
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
JNIEXPORT void JNICALL
Java_app_rive_runtime_kotlin_renderers_Renderer_cppStart(JNIEnv*, jobject, jlong rendererRef)
{
reinterpret_cast<JNIRenderer*>(rendererRef)->start();
}
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 JNIRenderer::start()
{
m_worker->run([this](DrawableThreadState* threadState) {
if (!m_workerImpl)
return;
auto now = std::chrono::steady_clock::now();
m_fpsLastFrameTime = now;
m_workerImpl->start(m_ktRenderer, now);
});
}
6.5 WorkerImpl::start
? WorkerImpl::start 函數源碼如下。這里主要初始化 m_ktRendererClass 、m_ktDrawCallback、m_ktAdvanceCallback,并啟動 Rive 引擎。
? models/worker_impl.cpp
void WorkerImpl::start(jobject ktRenderer, std::chrono::high_resolution_clock::time_point frameTime)
{
auto env = GetJNIEnv();
jclass ktClass = env->GetObjectClass(ktRenderer);
m_ktRendererClass = reinterpret_cast<jclass>(env->NewWeakGlobalRef(ktClass)); // 獲取 kotlin 中 Renderer 對象
m_ktDrawCallback = env->GetMethodID(m_ktRendererClass, "draw", "()V"); // 指向 Renderer.draw 方法
m_ktAdvanceCallback = env->GetMethodID(m_ktRendererClass, "advance", "(F)V"); // 指向 Renderer.advance 方法
m_lastFrameTime = frameTime;
m_isStarted = true;
if (auto engine = rive::AudioEngine::RuntimeEngine(false))
{
engine->start(); // 啟動 Rive 引擎
}
}
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
JNIEXPORT void JNICALL
Java_app_rive_runtime_kotlin_renderers_Renderer_cppStop(JNIEnv*, jobject, jlong rendererRef)
{
reinterpret_cast<JNIRenderer*>(rendererRef)->stop();
}
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
void JNIRenderer::stop()
{
m_worker->run([this](DrawableThreadState* threadState) {
if (!m_workerImpl)
return;
m_workerImpl->stop();
});
}
7.5 WorkerImpl::stop
? WorkerImpl::stop 函數源碼如下。這里主要暫停 Rive 引擎,并將 m_ktRendererClass 、m_ktDrawCallback、m_ktAdvanceCallback 設置為空。
? models/worker_impl.cpp
void WorkerImpl::stop()
{
if (auto engine = rive::AudioEngine::RuntimeEngine(false))
{
engine->stop(); // 暫停 Rive 引擎
}
auto env = GetJNIEnv();
if (m_ktRendererClass != nullptr)
{
env->DeleteWeakGlobalRef(m_ktRendererClass);
}
m_ktRendererClass = nullptr;
m_ktDrawCallback = nullptr;
m_ktAdvanceCallback = nullptr;
m_isStarted = false;
}
聲明:本文轉自【Rive】rive-android源碼分析。

浙公網安備 33010602011771號