硬件渲染器初始化从 ViewRootImpl 类 setView(…) 方法中调用 enableHardwareAcceleration(…) 开始。
HardwareRenderer 是一个抽象类,代表使用硬件加速渲染视图层次结构的接口。
首先找到 mHardwareRenderer 赋值的位置,我们才能确认它具体是什么子类。这在 ViewRootImpl 类 setView 方法中调用 enableHardwareAcceleration(…) 方法启用硬件加速开始。
frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
......
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
......
// 如果应用程序拥有 Surface,不要启用硬件加速
if (mSurfaceHolder == null) {
enableHardwareAcceleration(attrs);
}
......
}
......
}
......
}
......
}
- 创建硬件渲染器类实例
- 给硬件渲染器设置名称
frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
......
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
// 当应用程序处于兼容模式时,不要启用硬件加速
if (mTranslator != null) return;
// 如果需要,尝试启用硬件加速
final boolean hardwareAccelerated =
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
if (hardwareAccelerated) {
if (!HardwareRenderer.isAvailable()) {
return;
}
// 持久性进程(包括系统)不应在低端设备上进行加速渲染。
// 在这种情况下,将设置 sRendererDisabled。
// 此外,系统进程本身绝不应进行加速渲染。
// 在这种情况下,将同时设置 sRendererDisabled 和 sSystemRendererDisabled。
// 设置 sSystemRendererDisabled 时,
// 系统进程中的代码可以使用 PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED 启用硬件加速绘图。
//(这基本上是用于锁定屏幕的)
final boolean fakeHwAccelerated = (attrs.privateFlags &
WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
final boolean forceHwAccelerated = (attrs.privateFlags &
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
if (fakeHwAccelerated) {
// 这仅用于窗口管理器显示的用于启动应用程序的预览窗口,
// 因此它们看起来更像是正在启动的应用程序。
mAttachInfo.mHardwareAccelerationRequested = true;
} else if (!HardwareRenderer.sRendererDisabled
|| (HardwareRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.destroy();
}
final Rect insets = attrs.surfaceInsets;
final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
|| insets.top != 0 || insets.bottom != 0;
final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
// 1. 创建硬件渲染器类实例
mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);
if (mAttachInfo.mHardwareRenderer != null) {
// 2. 给硬件渲染器设置名称
mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
mAttachInfo.mHardwareAccelerated =
mAttachInfo.mHardwareAccelerationRequested = true;
}
}
}
}
......
}
使用 OpenGL 创建一个硬件渲染器。HardwareRenderer 实际为 ThreadedRenderer 类。
frameworks/base/core/java/android/view/HardwareRenderer.java
public abstract class HardwareRenderer {
......
/**
* @param translucent True 如果 Surface 是半透明的为 true,否则为 false
* @return 一个由OpenGL支持的硬件渲染器。
*/
static HardwareRenderer create(Context context, boolean translucent) {
HardwareRenderer renderer = null;
if (DisplayListCanvas.isAvailable()) {
renderer = new ThreadedRenderer(context, translucent);
}
return renderer;
}
......
}
硬件渲染器,它将渲染代理给渲染线程。大多数调用目前是同步的。UI 线程可以在渲染线程上阻塞,但是渲染线程绝对不能在 UI 线程上阻塞。ThreadedRenderer 创建一个 RenderProxy 实例。RenderProxy 反过来在 RenderThread 上创建和管理 CanvasContext。 CanvasContext 由 RenderProxy 的生命周期完全管理。
请注意,虽然目前 EGL 上下文和 Surface 是由渲染线程创建和管理的,但目标是将其移动到一个共享结构中,可以由两个线程管理。EGLSurface 的创建和删除应该在 UI 线程上完成,而不是在渲染线程上完成,以避免 Surface 缓冲区分配造成渲染线程的阻塞。
ThreadedRenderer 构造函数主要完成了以下工作:
- 获取由主题指定的光影属性
- 调用 nCreateRootRenderNode 创建 RenderNode
- 调用 nCreateProxy 创建 RenderProxy
frameworks/base/core/java/android/view/ThreadedRenderer.java
public class ThreadedRenderer extends HardwareRenderer {
......
// 由主题指定的光影属性
private final float mLightY;
private final float mLightZ;
private final float mLightRadius;
private final int mAmbientShadowAlpha;
private final int mSpotShadowAlpha;
......
private long mNativeProxy;
......
private RenderNode mRootNode;
......
ThreadedRenderer(Context context, boolean translucent) {
final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
mAmbientShadowAlpha =
(int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
a.recycle();
long rootNodePtr = nCreateRootRenderNode();
// 采用现有的本地渲染节点。
mRootNode = RenderNode.adopt(rootNodePtr);
// 设置渲染节点是否应该将自身剪切到其边界。该属性由视图的父视图控制。
mRootNode.setClipToBounds(false);
mNativeProxy = nCreateProxy(translucent, rootNodePtr);
ProcessInitializer.sInstance.init(context, mNativeProxy);
loadSystemProperties();
}
......
}
nCreateRootRenderNode 是一个 jni 方法,Native 对应实现为 android_view_ThreadedRenderer_createRootRenderNode(…) 方法。
frameworks/base/core/java/android/view/ThreadedRenderer.java
public class ThreadedRenderer extends HardwareRenderer {
......
private static native long nCreateRootRenderNode();
......
}
new 出来 Native RootRenderNode 对象,然后设置名称为 “RootRenderNode”,最后将 RootRenderNode 对象指针强转为 jlong 返回到 Java 层。
frameworks/base/core/jni/android_view_ThreadedRenderer.cpp
namespace android {
......
static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
RootRenderNode* node = new RootRenderNode(env);
node->incStrong(0);
node->setName("RootRenderNode");
return reinterpret_cast<jlong>(node);
}
......
const char* const kClassPathName = "android/view/ThreadedRenderer";
static JNINativeMethod gMethods[] = {
......
{ "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
......
};
int register_android_view_ThreadedRenderer(JNIEnv* env) {
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
};
渲染节点是个什么?用于存储已记录的画布命令以及每个 View/ViewGroup 显示属性。画布命令的记录与 SkPicture 有点类似,除了画布记录功能在 DisplayListCanvas(用于管理记录),DisplayListData(用于保存实际数据)和 DisplayList(用于保存属性并在渲染器上执行回放)之间划分。请注意,当刷新视图记录的画布操作流时,DisplayListData 从单个 DisplayList 的下面换出。DisplayList(及其属性)保持 attach 状态。
再来分析 nCreateProxy(…) 方法。它是一个 jni 函数,对应 Native 实现为 android_view_ThreadedRenderer_createProxy(…) 方法。
frameworks/base/core/java/android/view/ThreadedRenderer.java
public class ThreadedRenderer extends HardwareRenderer {
......
private static native long nCreateProxy(boolean translucent, long rootRenderNode);
......
}
- 将 rootRenderNodePtr jlong 强转回 RootRenderNode* 指针
- 创建 ContextFactoryImpl 对象,其内部持有 RootRenderNode
- 创建 RenderProxy 渲染代理对象
frameworks/base/core/jni/android_view_ThreadedRenderer.cpp
namespace android {
......
static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
jboolean translucent, jlong rootRenderNodePtr) {
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
ContextFactoryImpl factory(rootRenderNode);
return (jlong) new RenderProxy(translucent, rootRenderNode, &factory);
}
......
const char* const kClassPathName = "android/view/ThreadedRenderer";
static JNINativeMethod gMethods[] = {
......
{ "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
......
};
int register_android_view_ThreadedRenderer(JNIEnv* env) {
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
};
RenderProxy 是严格的单线程化。所有方法都必须在所属线程上调用。
- 调用 RenderThread 类 getInstance() 获取 RenderThread 渲染线程单例,赋值给 RenderProxy 成员变量 mRenderThread
- 展开 SETUP_TASK 宏定义,得到指向 createContextArgs 结构体的指针 args,createContextArgs 结构体是在编译期间 CREATE_BRIDGE4 宏定义展开后定义的,其中还实现了函数 Bridge_createContext,return 语句就是其函数体。这个函数在展开 SETUP_TASK 宏定义时作为入参传入 MethodInvokeRenderTask 构造函数
- 给 createContextArgs 结构体成员 translucent、rootRenderNode、thread 和 contextFactory 赋值
- mContext 是指向 CanvasContext* 的指针成员,调用 postAndWait(…) 函数传入实参 MethodInvokeRenderTask 对象,返回值赋给 mContext,实际就是指向 CREATE_BRIDGE4 宏最后 new 出来的 CanvasContext 对象。此函数将渲染任务添加到了渲染线程
- mDrawFrameTask 是一个 DrawFrameTask 成员,代表绘制帧任务,调用其 setContext(…) 方法设置上下文,入参为 RenderThread 和 CanvasContext*。
frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
namespace android {
namespace uirenderer {
namespace renderthread {
......
#define ARGS(method) method ## Args
......
#define CREATE_BRIDGE4(name, a1, a2, a3, a4) CREATE_BRIDGE(name, a1,a2,a3,a4,,,,)
......
#define CREATE_BRIDGE(name, a1, a2, a3, a4, a5, a6, a7, a8) \
typedef struct { \
a1; a2; a3; a4; a5; a6; a7; a8; \
} ARGS(name); \
static void* Bridge_ ## name(ARGS(name)* args)
#define SETUP_TASK(method) \
LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \
"METHOD_INVOKE_PAYLOAD_SIZE %zu is smaller than sizeof(" #method "Args) %zu", \
METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \
MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
ARGS(method) *args = (ARGS(method) *) task->payload()
......
CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,
RenderNode* rootRenderNode, IContextFactory* contextFactory) {
return new CanvasContext(*args->thread, args->translucent,
args->rootRenderNode, args->contextFactory);
}
......
RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory)
: mRenderThread(RenderThread::getInstance())
, mContext(nullptr) {
SETUP_TASK(createContext);
args->translucent = translucent;
args->rootRenderNode = rootRenderNode;
args->thread = &mRenderThread;
args->contextFactory = contextFactory;
mContext = (CanvasContext*) postAndWait(task);
mDrawFrameTask.setContext(&mRenderThread, mContext);
}
......
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
调用 RenderThread 类 getInstance() 方法可获得单例 RenderThread 对象。getInstance() 方法定义在 Singleton.h 中,Singleton 类是一个模板单例类,getInstance() 方法会返回对应的 TYPE* 指针。RenderThread 类继承自 Singleton 因此就可以返回 RenderThread* 指针。
system/core/include/utils/Singleton.h
template <typename TYPE>
class ANDROID_API Singleton
{
public:
static TYPE& getInstance() {
Mutex::Autolock _l(sLock);
TYPE* instance = sInstance;
if (instance == 0) {
instance = new TYPE();
sInstance = instance;
}
return *instance;
}
static bool hasInstance() {
Mutex::Autolock _l(sLock);
return sInstance != 0;
}
protected:
~Singleton() { };
Singleton() { };
private:
Singleton(const Singleton&);
Singleton& operator = (const Singleton&);
static Mutex sLock;
static TYPE* sInstance;
};
getInstance() 会调用 RenderThread 类无参构造函数。
- 初始化了一系列成员变量
- mFrameCallbackTask 赋值为 DispatchFrameCallbacks 对象
- mLooper 赋值为 Looper 对象
- 启动 RenderThread 线程
frameworks/base/libs/hwui/renderthread/RenderThread.cpp
RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
, mNextWakeup(LLONG_MAX)
, mDisplayEventReceiver(nullptr)
, mVsyncRequested(false)
, mFrameCallbackTaskPending(false)
, mFrameCallbackTask(nullptr)
, mRenderState(nullptr)
, mEglManager(nullptr) {
Properties::load();
mFrameCallbackTask = new DispatchFrameCallbacks(this);
mLooper = new Looper(false);
run("RenderThread");
}
启动线程之后,重点需要关注 threadLoop() 函数返回值。
Thread 对象有两种使用方法:
loop:如果 threadLoop() 返回 true,则在 requestExit() 未被调用时再次调用。
once:如果 threadLoop() 返回 false,则该线程将在返回时退出。
这里配置为 false,代表只运行一次,但 threadLoop() 函数体内部存在一个“无限” for 循环,结合 Looper 一起使用。这里处理了所有 RenderTask(渲染任务)。
frameworks/base/libs/hwui/renderthread/RenderThread.cpp
bool RenderThread::threadLoop() {
setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
initThreadLocals();
int timeoutMillis = -1;
for (;;) {
int result = mLooper->pollOnce(timeoutMillis);
LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
"RenderThread Looper POLL_ERROR!");
nsecs_t nextWakeup;
// 如果我们有任务的话,处理我们的队列
while (RenderTask* task = nextTask(&nextWakeup)) {
// 调用 task run() 方法
task->run();
// 任务本身可能已经删除,不要再引用它
}
if (nextWakeup == LLONG_MAX) {
timeoutMillis = -1;
} else {
// 计算下一次唤醒时间
nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);
if (timeoutMillis < 0) {
timeoutMillis = 0;
}
}
// 处理帧回调注册
if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
drainDisplayEventQueue();
mFrameCallbacks.insert(
mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
mPendingRegistrationFrameCallbacks.clear();
// 请求 vsync 信号
requestVsync();
}
if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
// TODO: Clean this up. This is working around an issue where a combination
// of bad timing and slow drawing can result in dropping a stale vsync
// on the floor (correct!) but fails to schedule to listen for the
// next vsync (oops), so none of the callbacks are run.
// 请求 vsync 信号
requestVsync();
}
}
return false;
}
最后总结一下它们的类图关系。