<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【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 的源碼。

      img

      ? 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 透傳流程圖如下。

      img

      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 透傳流程圖如下。

      img

      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.hpprenderer.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 渲染流程

      ? 渲染流程圖如下。

      img

      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.hppartboard.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 啟動渲染流程

      ? 啟動渲染流程圖如下。

      img

      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 暫停渲染流程

      ? 暫停渲染流程圖如下。

      img

      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源碼分析

      posted @ 2025-10-04 12:02  little_fat_sheep  閱讀(89)  評論(0)    收藏  舉報
      主站蜘蛛池模板: japanese无码中文字幕| 色偷偷av一区二区三区| 久热这里只有精品12| 人妻少妇精品无码专区| 午夜免费福利小电影| 国产果冻豆传媒麻婆| 亚洲精品日韩久久精品| av在线播放国产一区| 国产精品丝袜一区二区三区| 精品日本免费一区二区三区| 亚洲精品第一区二区在线| 亚洲中文字幕第二十三页| 国产一区二区不卡在线| 国产国产人免费人成免费| 免费激情网址| 性动态图无遮挡试看30秒| 色综合天天综合网天天看片| 69精品丰满人妻无码视频a片| 中文字幕人妻中出制服诱惑| 亚洲欧洲日产国码AV天堂偷窥| 延吉市| 日本一区二区三区在线播放| 国产精品中文第一字幕| 欧美午夜精品久久久久久浪潮| 色诱视频在线观看| 天堂中文8资源在线8| 偷拍激情视频一区二区三区 | 少妇伦子伦精品无吗| 日韩精品亚洲专区在线观看| 东京热一精品无码av| 亚洲乱码国产乱码精品精大量| av无码久久久久不卡网站蜜桃 | 精品免费国产一区二区三区四区介绍| 国产精品麻豆成人av网| 依依成人精品视频在线观看| 免费无码av片在线观看中文| 日韩有码中文字幕一区二区 | 日韩精品无码免费专区午夜不卡 | 国产一区二区三区怡红院| 国产精品爽爽爽一区二区| 国产美女高潮流白浆视频|