关于Surface请参考下面文章
SurfaceFlinger学习笔记(一)应用启动流程
SurfaceFlinger学习笔记(二)之Surface
SurfaceFlinger学习笔记(三)之SurfaceFlinger进程
SurfaceFlinger学习笔记(四)之HWC2
SurfaceFlinger学习笔记(五)之HWUI
SurfaceFlinger学习笔记(六)之View Layout Draw过程分析
渲染机制的更新,Android提出了硬件加速的机制,其作用就是将2D的绘图操纵,转换为对应的3D的绘图操纵,这个转换的过程,我们把它叫做录制。需要显示的时候,再用OpenGLES通过GPU去渲染。界面创建时,第一次全部录制,后续的过程中,界面如果只有部分区域的widget更新,只需要重新录制更新的widget。录制好的绘图操纵,保存在一个显示列表DisplayList中,需要真正显示到界面的时候,直接显示DisplayList中的绘图 操纵。这样,一方面利用GPU去渲染,比Skia要快;另一方面,采用DisplayList,值重新录制,有更新区域,最大程度利用上一帧的数据,效率自然就快很多。这就是硬件加速的来源
这个是Android原生的测试硬件绘制的应用
* frameworks/base/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java
public class HardwareCanvasSurfaceViewActivity extends Activity implements Callback {
private SurfaceView mSurfaceView;
private HardwareCanvasSurfaceViewActivity.RenderingThread mThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mSurfaceView = new SurfaceView(this);
mSurfaceView.getHolder().addCallback(this);
...
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mThread = new RenderingThread(holder);
mThread.start();
}
...
private static class RenderingThread extends Thread {
private final SurfaceHolder mSurface;
private volatile boolean mRunning = true;
private int mWidth, mHeight;
public RenderingThread(SurfaceHolder surface) {
mSurface = surface;
}
...
@Override
public void run() {
...
while (mRunning && !Thread.interrupted()) {
final Canvas canvas = mSurface.lockHardwareCanvas();
try {
canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
canvas.drawRect(x, y, x + 20.0f, y + 20.0f, paint);
} finally {
mSurface.unlockCanvasAndPost(canvas);
}
...
}
}
void stopRendering() {
interrupt();
mRunning = false;
}
}
}
应用这里拿到一个Surface,然后lock一个HardwareCanvas,用lock的HardwareCanvas进行绘制,我们绘制的就可以使用硬件GPU进行绘制
初始化流程
SurfaceView
SurfaceView::lockHardwareCanvas调用Surface::lockHardwareCanvas
在Surface::lockHardwareCanvas中创建mHwuiContext ,然后调用mHwuiContext.lockCanvas
SurfaceView中里面实现了SurfaceHolder,并通过回调到activity等类,维护了一个callback的list,在updateSurface时候调用surfaceCreated、surfaceChanged,并包含成员Surface、SurfaceControl、SurfaceSession,mSurfaceControl通过new SurfaceControl.Builder(SurfaceSession)获取
SurfaceSession:定义在frameworks/base/core/java/android/view/SurfaceSession.java
frameworks/base/core/jni/android_view_SurfaceSession.cpp
为SurfaceComposerClient的封装,java层保存了SurfaceComposerClient的指针,通过调用jni的nativeCreate、nativeDestroy、nativeKill方法,native层调用
SurfaceComposerClient client = reinterpret_cast(ptr);
client->decStrong((void*)nativeCreate);
Surface:定义在frameworks/base/core/java/android/view/Surface.java
作用:继承自Parcelable实现序列化,里面有个内部类 HwuiContext,在HwuiContext的构造函数中,创建了一个RenderNode和HwuiRenderer。HwuiRenderer为long,通过调用native方法nHwuiCreate。这里的HwuiContext,就是和HWUI打交道了
private final class HwuiContext {
...
HwuiContext(boolean isWideColorGamut) {
mRenderNode = RenderNode.create("HwuiCanvas", null);
mRenderNode.setClipToBounds(false);
mRenderNode.setForceDarkAllowed(false);
mIsWideColorGamut = isWideColorGamut;
mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject, isWideColorGamut);
}
Canvas lockCanvas(int width, int height) {
mCanvas = mRenderNode.beginRecording(width, height);
return mCanvas;
}
void unlockAndPost(Canvas canvas) {
...
mRenderNode.endRecording();
mCanvas = null;
nHwuiDraw(mHwuiRenderer);
}
void updateSurface() {
nHwuiSetSurface(mHwuiRenderer, mNativeObject);
}
...
}
RenderNode.create流程
用以录制绘图操纵的批处理,当绘制的时候,可以store和apply
其实RenderNode就对应前面我们所说的ViewGroup,有一个RootView,同样也有一个RootNode
在RenderNode.create时候new一个RenderNode,进而调用到nCreate,然后创建一个native层的RenderNode
* frameworks/base/graphics/java/android/graphics/RenderNode.java
private RenderNode(String name, AnimationHost animationHost) {
mNativeRenderNode = nCreate(name);
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
mAnimationHost = animationHost;
}
public static RenderNode create(String name, @Nullable AnimationHost animationHost) {
return new RenderNode(name, animationHost);
}
* frameworks/base/core/jni/android_view_RenderNode.cpp
static jlong android_view_RenderNode_create(JNIEnv* env, jobject, jstring name) {
RenderNode* renderNode = new RenderNode();
...
return reinterpret_cast<jlong>(renderNode);
}
创建nHwuiCreate流程: nHwuiCreate实现在android_view_Surface中的hwui::create,创建了一个RenderProxy,nHwuiCreate返回的是一个RenderProxy实例
RenderProxy
- RenderProxy是一个代理者,严格的单线程。所有的方法都必须在自己的线程中调用
- RenderThread,渲染线程,是一个单例,也就是说,一个进程中只有一个,所有的绘制操纵都必须在这个线程中完成。应用端很多操纵,都以RenderTask的形式post到RenderThread线程中完成
- CanvasContext,上下文,由于OpenGL是单线程的,所以,我们给到GPU的绘图命令都封装在各自的上下文中。这个和上层的HwuiRenderer是对应的
- DrawFrameTask,比较特殊的一个RenderTask。可重复使用的绘制Task,在Surface的draw中调用syncAndDrawFrame
- nHwuiCreate中在RenderProxy创建完成后,调用proxy->setSurface向RenderThread的WorkQueue队列中post一个东西,在process中执行CanvasContext::setSurface
* frameworks/base/core/jni/android_view_Surface.cpp
static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr, jboolean isWideColorGamut) {
RenderNode* rootNode = reinterpret_cast<RenderNode*>(rootNodePtr);
sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
ContextFactory factory;
RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
...
proxy->setSurface(surface);
...
return (jlong) proxy;
}
* frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) : mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
});
mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
}
void RenderProxy::setSurface(const sp<Surface>& surface) {
mRenderThread.queue().post(
[this, surf = surface]() mutable { mContext->setSurface(std::move(surf)); });
}
RenderThread
- RenderThread构造函数中调用PREVENT_COPY_AND_ASSIGN的目的是阻止拷贝构造函数和=重载
- 继承ThreadBase,ThreadBase继承Android的基本类Thread,在构造RenderThread时,调用start(“RenderThread”)就启动了RenderThread线程
- RenderThread起来后,就会执行RenderThread的threadLoop,threadLoop中执行while循环,不停处理请求。如果没有任务时,调用waitForWork等待
- RenderThread收到新消息后调用processQueue,然后通过threadLoop::processQueue调用到mQueue.process,从而进入到WorkQueue::process,最后调用到CanvasContext->setSurface
ThreadBase
- 继承Thread,包含成员mLooper、mQueue
- mQueue的实例化,C++的新特性。其实就是构造一个WorkQueue,第一个参数是一个函数,函数体执行的时候调用mLooper->wake()唤醒mLooper,线程开始工作
* frameworks/base/libs/hwui/renderthread/RenderThread.h
class RenderThread : private ThreadBase {
PREVENT_COPY_AND_ASSIGN(RenderThread);
}
bool RenderThread::threadLoop() {
setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
Looper::setForThread(mLooper);
if (gOnStartHook) {
gOnStartHook("RenderThread");
}
initThreadLocals();
while (true) {
waitForWork();
processQueue();
...
}
}
* frameworks/base/libs/hwui/thread/ThreadBase.h
ThreadBase() : Thread(false)
, mLooper(new Looper(false))
, mQueue([this]() { mLooper->wake(); }, mLock) {}
WorkQueue
- 包含一个结构体WorkItem ,其实就是前面RenderProxy::setSurface时候的匿名函数体mContext->setSurface
- post方法调用到WorkQueue::postAt方法中创建一个WorkItem 并调用WorkQueue::enqueue加入到消息队列,最后如果需要唤醒,就通过mWakeFunc函数
- mWakeFunc是ThreadBase中构建WorkQueue时,传下来的无名函数
* frameworks/base/libs/hwui/thread/WorkQueue.h
WorkQueue(std::function<void()>&& wakeFunc, std::mutex& lock)
: mWakeFunc(move(wakeFunc)), mLock(lock) {}
void enqueue(WorkItem&& item) {
bool needsWakeup;
{
std::unique_lock _lock{mLock};
auto insertAt = std::find_if(std::begin(mWorkQueue), std::end(mWorkQueue),
[time = item.runAt](WorkItem & item) { return item.runAt > time; });
needsWakeup = std::begin(mWorkQueue) == insertAt;
mWorkQueue.emplace(insertAt, std::move(item));
}
if (needsWakeup) {
mWakeFunc();
}
}
CanvasContext渲染的上下文
- 渲染Pipeline有几种类型,Pipeline由IRenderPipeline描述。创建CanvasContext时,会根据pipeline的类型,创建对应的Pipeline
- IRenderPipeline是统一的接口。默认的类型是OpenGLPipeline,用的是OpenGL实现。这可以可通过属性debug.hwui.renderer来设置
- SkiaOpenGLPipeline和SkiaVulkanPipeline,两者都用到skia进行Ops的渲染,也就是说,Ops的录制是用skia来完成的。后面的显示才用到OpenGL或Vulkan
* frameworks/base/libs/hwui/Properties.h
enum class RenderPipelineType { SkiaGL, SkiaVulkan, NotInitialized = 128 };
* frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,RenderNode* rootRenderNode, IContextFactory* contextFactory) {
auto renderType = Properties::getRenderPipelineType();
switch (renderType) {
case RenderPipelineType::SkiaGL:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
case RenderPipelineType::SkiaVulkan:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
default:
LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
return nullptr;
}
void CanvasContext::setSurface(sp<Surface>&& surface) {
if (surface) {
mNativeSurface = new ReliableSurface{std::move(surface)};
mNativeSurface->setDequeueTimeout(500_ms);
} else {
mNativeSurface = nullptr;
}
...
bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode, mRenderAheadCapacity);
}
* frameworks/base/libs/hwui/Properties.cpp
RenderPipelineType Properties::peekRenderPipelineType() {
...
property_get(PROPERTY_RENDERER, prop, useVulkan ? "skiavk" : "skiagl");
if (!strcmp(prop, "skiavk")) {
return RenderPipelineType::SkiaVulkan;
}
return RenderPipelineType::SkiaGL;
}
step3:
HwuiContext ::lockCanvas中调用mRenderNode.beginRecording->RecordingCanvas.obtain构造RecordingCanvas,RecordingCanvas构造时候主要是调用jni方法nCreateDisplayListCanvas
- RecordingCanvas继承DisplayListCanvas,而DisplayListCanvas继承BaseRecordingCanvas ,BaseRecordingCanvas 继承Canvas
- nCreateDisplayListCanvas实现在android_view_DisplayListCanvas中,调用Canvas::create_recording_canva
- hwui的Canvas里面封装了create_recording_canvas、 drawText、drawDoubleRoundRectXY等,其中create_recording_canvas调用new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width, height)
* frameworks/base/graphics/java/android/graphics/RecordingCanvas.java
protected RecordingCanvas(@NonNull RenderNode node, int width, int height) {
super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height));
mDensity = 0; // disable bitmap density scaling
}
static RecordingCanvas obtain(@NonNull RenderNode node, int width, int height) {
if (node == null) throw new IllegalArgumentException("node cannot be null");
RecordingCanvas canvas = sPool.acquire();
if (canvas == null) {
canvas = new RecordingCanvas(node, width, height);
} else {
nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode, width, height);
}
canvas.mNode = node;
canvas.mWidth = width;
canvas.mHeight = height;
return canvas;
}
* frameworks/base/core/jni/android_view_DisplayListCanvas.cpp
static jlong android_view_DisplayListCanvas_createDisplayListCanvas(jlong renderNodePtr,
jint width, jint height) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
return reinterpret_cast<jlong>(Canvas::create_recording_canvas(width, height, renderNode));
}
frameworks/base/libs/hwui/hwui/Canvas.cpp
Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::RenderNode* renderNode) {
return new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width, height);
}
SkiaRecordingCanvas
- 继承SkiaCanvas,SkiaCanvas又继承Canvas,里面有个成员变量RecordingCanvas::mRecorder,有些绘制操作直接调用RecordingCanvas
- 在构造时候调用SkiaRecordingCanvas::initDisplayList,这里调用RenderNode::detachAvailableList获取mAvailableDisplayList,否则创建了一个SkiaDisplayList,并调用SkiaDisplayList::attachRecorder,进而调用到RecordingCanvas::reset
- explicit 为C++特性,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生,声明为explicit的构造函数不能在隐式转换中使用
SkiaDisplayList
- 里面有个重要成员DisplayListData ,定义在RecordingCanvas中
SkiaCanvas
- SkiaCanvas又继承Canvas,里面有个成员变量RecordingCanvas::mRecorder和SkCanvas::mCanvas
mCanvas在SkiaCanvas::reset中赋值,即在SkiaRecordingCanvas::initDisplayList中把mRecorder赋值给mCanvas,则SkCanvas::mCanvas保存的是RecordingCanvas句柄
RecordingCanvas
继承SkCanvasVirtualEnforcer,SkCanvasVirtualEnforcer 为一个模块类,则继承SkNoDrawCanvas,进而继承skia::SkCanvas,这里的SkCanvas为Skia库中的
frameworks/base/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
explicit SkiaRecordingCanvas(uirenderer::RenderNode* renderNode, int width, int height) {
initDisplayList(renderNode, width, height);
}
void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width,
int height) {
mCurrentBarrier = nullptr;
SkASSERT(mDisplayList.get() == nullptr);
if (renderNode) {
mDisplayList = renderNode->detachAvailableList();
}
if (!mDisplayList) {
mDisplayList.reset(new SkiaDisplayList());
}
mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height));
SkiaCanvas::reset(&mRecorder);
}
* frameworks/base/libs/hwui/RenderNode.h
void attachAvailableList(skiapipeline::SkiaDisplayList* skiaDisplayList) {
mAvailableDisplayList.reset(skiaDisplayList);
}
* frameworks/base/libs/hwui/pipeline/skia/SkiaDisplayList.h
void attachRecorder(RecordingCanvas* recorder, const SkIRect& bounds) {
recorder->reset(&mDisplayList, bounds);
}
* frameworks/base/libs/hwui/RecordingCanvas.h
class RecordingCanvas final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> {
}
* external/skia/include/utils/SkNoDrawCanvas.h
class SK_API SkNoDrawCanvas : public SkCanvasVirtualEnforcer<SkCanvas> {
}
canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
canvas.drawRect(x, y, x + 20.0f, y + 20.0f, paint);
- HwuiContext ::lockCanvas中调用mRenderNode.beginRecording->RecordingCanvas.obtain构造RecordingCanvas,RecordingCanvas继承DisplayListCanvas ,DisplayListCanvas 继承BaseRecordingCanvas ,则BaseRecordingCanvas::drawColor,进而到jni的android_graphics_Canvas::drawColor
- mNativeCanvasWrapper,就是nCreateDisplayListCanvas时,创建的native对应的Canvas,即SkiaRecordingCanvas,后续JNI中都是通过mNativeCanvasWrapper去找到对应的native的Canvas的
- SkiaRecordingCanvas继承SkiaCanvas,则调用的SkiaCanvas::drawColor
- SkiaCanvas::drawColor调用mCanvas的drawColor,前文说到SkCanvas::mCanvas保存的是RecordingCanvas句柄,则调用到RecordingCanvas::drawColor
- 前文说到RecordingCanvas继承skia::SkCanvas,则这里调用到skia::SkCanvas::drawColor,进而调用到onDrawPaint,而drawRect则直接调用到onDrawRect,则进入到RecordingCanvas的onDrawPaint中
* frameworks/base/graphics/java/android/graphics/BaseRecordingCanvas.java
public final void drawColor(@ColorInt int color) {
nDrawColor(mNativeCanvasWrapper, color, BlendMode.SRC_OVER.getXfermode().porterDuffMode);
}
* frameworks/base/core/jni/android_graphics_Canvas.cpp
static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
get_canvas(canvasHandle)->drawColor(color, mode);
}
* frameworks/base/libs/hwui/SkiaCanvas.cpp
void SkiaCanvas::drawColor(int color, SkBlendMode mode) {
mCanvas->drawColor(color, mode);
}
* external/skia/src/core/SkCanvas.cpp
void SkCanvas::drawColor(SkColor c, SkBlendMode mode) {
SkPaint paint;
paint.setColor(c);
paint.setBlendMode(mode);
this->drawPaint(paint);
}
void SkCanvas::drawPaint(const SkPaint& paint) {
TRACE_EVENT0("skia", TRACE_FUNC);
this->onDrawPaint(paint);
}
void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
TRACE_EVENT0("skia", TRACE_FUNC);
// To avoid redundant logic in our culling code and various backends, we always sort rects
// before passing them along.
this->onDrawRect(r.makeSorted(), paint);
}
- RecordingCanvas::onDrawPaint中调用到fDL->drawPaint,进而调用到DisplayListData::drawPaint
这里的fDL为DisplayListData,在前文SkiaRecordingCanvas::initDisplayList时候调用SkiaDisplayList::attachRecorder时候调用RecordingCanvas::reset设置- DisplayListData::drawPaint,调用模板函数push方法,其实是new 了一个DrawPaint,并设置类型为Type::DrawPaint,保存在列表fBytes中,在draw时候,调用DisplayListData::map,进而调用到DrawPaint::draw方法
- std::move执行到右值的无条件转换,std::forward执行到右值的有条件转换,在参数都是右值时,二者就是等价的
* frameworks/base/libs/hwui/RecordingCanvas.cpp
void RecordingCanvas::reset(DisplayListData* dl, const SkIRect& bounds) {
this->resetCanvas(bounds.right(), bounds.bottom());
fDL = dl;
mClipMayBeComplex = false;
mSaveCount = mComplexSaveCount = 0;
}
void RecordingCanvas::onDrawPaint(const SkPaint& paint) {
fDL->drawPaint(paint);
}
void DisplayListData::drawPaint(const SkPaint& paint) {
this->push<DrawPaint>(0, paint);
}
template <typename T, typename... Args>
void* DisplayListData::push(size_t pod, Args&&... args) {
size_t skip = SkAlignPtr(sizeof(T) + pod);
SkASSERT(skip < (1 << 24));
if (fUsed + skip > fReserved) {//分配空间
static_assert(SkIsPow2(SKLITEDL_PAGE), "This math needs updating for non-pow2.");
// Next greater multiple of SKLITEDL_PAGE.
fReserved = (fUsed + skip + SKLITEDL_PAGE) & ~(SKLITEDL_PAGE - 1);
fBytes.realloc(fReserved);
}
SkASSERT(fUsed + skip <= fReserved);
auto op = (T*)(fBytes.get() + fUsed);//op指向fBytes的末尾
fUsed += skip;//fUsed增加对象的空间
//创建T,并传入参数,移动空间,这里new (op)T,是在op指向的位置上构造T
new (op) T{std::forward<Args>(args)...};
op->type = (uint32_t)T::kType;
op->skip = skip;
return op + 1;
}
Surface::unlockCanvasAndPost调用HwuiContext::unlockAndPost开始
先调用RenderNode::endRecording
- endRecording先通过RecordingCanvas::finishRecording调用native方法nFinishRecording,然后在jni中调用到SkiaRecordingCanvas::finishRecording,然后SkiaRecordingCanvas通过mRecorder调用到RecordingCanvas::restoreToCount这里其实调用的是external下skia库中的SkCanvas::restoreToCount,然后调用到SkCanvas::restore,进而调用到RecordingCanvas::willRestore
SkiaRecordingCanvas调用restoreToCount后,调用DisplayList::release返回DisplayList- 然后调用RenderNode::nSetDisplayList,然后调用到HWUI中的RenderNode.cpp的setStagingDisplayList
* frameworks/base/core/java/android/view/Surface.java
public void unlockCanvasAndPost(Canvas canvas) {
...
if (mHwuiContext != null) {
mHwuiContext.unlockAndPost(canvas);
} else {
unlockSwCanvasAndPost(canvas);
}
}
void unlockAndPost(Canvas canvas) {
mRenderNode.endRecording();
mCanvas = null;
nHwuiDraw(mHwuiRenderer);
}
* frameworks/base/graphics/java/android/graphics/RenderNode.java
public void endRecording() {
RecordingCanvas canvas = mCurrentRecordingCanvas;
mCurrentRecordingCanvas = null;
long displayList = canvas.finishRecording();
nSetDisplayList(mNativeRenderNode, displayList);
canvas.recycle();
}
* frameworks/base/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() {
// close any existing chunks if necessary
insertReorderBarrier(false);
mRecorder.restoreToCount(1);
return mDisplayList.release();
}
* frameworks/base/libs/hwui/RecordingCanvas.cpp
void RecordingCanvas::willRestore() {
mSaveCount--;
if (mSaveCount < mComplexSaveCount) {
mClipMayBeComplex = false;
mComplexSaveCount = 0;
}
fDL->restore();
}
* frameworks/base/libs/hwui/RenderNode.cpp
void RenderNode::setStagingDisplayList(DisplayList* displayList) {
mValid = (displayList != nullptr);
mNeedsDisplayListSync = true;
delete mStagingDisplayList;
mStagingDisplayList = displayList;
}
HwuiContext::unlockAndPost中然后调用jni方法nHwuiDraw,进而进入到android_view_Surface的draw方法,然后调用RenderProxy::syncAndDrawFrame,然后调用到DrawFrameTask::drawFrame,这里主要是通过调用DrawFrameTask::postAndWait
- drawFrame,也就通过RenderThread,post一个WorkItem到RenderThread的队列里面,在RenderThread线程中执行的,RenderThread处理Queue时,执行的确是这里的run函数
- DrawFrameTask::run先调用syncFrameState,同步一下Frame的状态,再通过CanvasContext的draw方法去绘制,主要的流程就到CanvasContext,在create时候SkiaOpenGLPipeline和SkiaVulkanPipeline
* frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
void DrawFrameTask::postAndWait() {
AutoMutex _lock(mLock);
mRenderThread->queue().post([this]() { run(); });
mSignal.wait(mLock);
}
void DrawFrameTask::run() {
...
TreeInfo info(TreeInfo::MODE_FULL, *mContext);
canUnblockUiThread = syncFrameState(info);
...
context->draw();
...
}
DrawFrameTask::syncFrameState
- makeCurrent,这个从早期的版本就有,早期只有Opengl pipeline时,Opengl只支持单线程。我们首先要通过makeCurrent,告诉GPU处理当前的上下文(context)。
- unpinImages,hwui为了提高速度,对各种object都做了cache,这里的unpin,就是让cache去做unpin,以前的都不要了。
- setContentDrawBounds,设置绘制的区域大小
- prepareTree,前面我们也说过,Android View是树型结构的,这就是在绘制之前,去准备这些Tree节点的绘图操作Ops。这个过程也是非常的复杂
* frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
...
bool canDraw = mContext->makeCurrent();
mContext->unpinImages();
...
mContext->setContentDrawBounds(mContentDrawBounds);
mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
...
}
前面其中就两个主要的流程:CanvasContext::PrepareTree和CanvasContext::Draw
CanvasContext::prepareTree
- RenderNode::prepareTree,Context可能会有多个RenderNode,每个RenderNode都进行Prepare
在RenderNode进行Prepare时,先对TreeInfo进行封,MarkAndSweepRemoved,主要是对可能的Node进行标记删除,能从tree上删除的就添加到mMarked中,在析构函数中,再对mMarked的mode进行删除
void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target) {
...
mAnimationContext->startFrame(info.mode);
mRenderPipeline->onPrepareTree();
//Context可能会有多个RenderNode,每个RenderNode都进行Prepare
for (const sp<RenderNode>& node : mRenderNodes) {
//只有Primary的node是 FULL,其他都是实时,这里为MODE_FULL
info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY);
node->prepareTree(info);
GL_CHECKPOINT(MODERATE);
}
...
mIsDirty = true;
// 如果,窗口已经没有Native Surface,这一帧就丢掉。
if (CC_UNLIKELY(!hasSurface())) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
info.out.canDrawThisFrame = false;
return;
}
...
}
* frameworks/base/libs/hwui/RenderNode.cpp
void RenderNode::prepareTree(TreeInfo& info) {
MarkAndSweepRemoved observer(&info);
const int before = info.disableForceDark;
prepareTreeImpl(observer, info, false);
}
* frameworks/base/libs/hwui/RenderNode.h
//能从tree上删除的就添加到mMarked中,在析构函数中,再对mMarked的mode进行删除
Class MarkAndSweepRemoved : public TreeObserver {
PREVENT_COPY_AND_ASSIGN(MarkAndSweepRemoved);
public:
explicit MarkAndSweepRemoved(TreeInfo* info) : mTreeInfo(info) {}
//emplace_back在容器尾部添加一个元素,这个元素原地构造,不需要触发拷贝构造和转移构造。而且调用形式更加简洁,直接根据参数初始化临时对象的成员
void onMaybeRemovedFromTree(RenderNode* node) override { mMarked.emplace_back(node); }
...
private:
FatVector<sp<RenderNode>, 10> mMarked;
TreeInfo* mTreeInfo;
};
RenderNode::prepareTreeImpl是RenderNode真正进行Prepare的地方,DisplayList的数据更新到了Context的mLayerUpdateQueue中
- damageAccumulator是从CanvasContext中传过来的,是CanvasContext的成员,damage的累乘器。主要是用来标记,屏幕的那些区域被破坏了,需要重新绘制,所有的RenderNode累加起来,就是总的
damage累加器中,每一个元素由DirtyStack描述,分两种类型:TransformMatrix4和TransformRenderNode。采用一个双向链表mHead进行管理- pushStagingPropertiesChanges,property是对RenderNode的描述,也就是对View的描述,比如大小,位置等。有两个状态,正在使用的syncProperties和待处理的mStagingProperties。syncProperties时,将mStagingProperties赋值给syncProperties。这里,很多状态都是这样同步的
- pushStagingDisplayListChanges,和前面的Property一样的流程,只是这里是syncDisplayList。这样,前面录制好Ops,就通过mStagingDisplayList传给mDisplayList,绘制的Ops都放在mDisplayList中,这边会去递归的调用每个RenderNode的prepareTreeImpl
- pushLayerUpdate,将要更新的RenderNode都加到TreeInfo的layerUpdateQueue中,还有其对应的damage大小
- 累加器的popTransform,就是将该Node的DirtyStack生效
void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) {
...
info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingPropertiesChanges(info);
}
...
prepareLayer(info, animatorDirtyMask);
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingDisplayListChanges(observer, info);
}
if (mDisplayList) {
info.out.hasFunctors |= mDisplayList->hasFunctor();
bool isDirty = mDisplayList->prepareListAndChildren(
observer, info, childFunctorsNeedLayer,
[](RenderNode* child, TreeObserver& observer, TreeInfo& info,
bool functorsNeedLayer) {
child->prepareTreeImpl(observer, info, functorsNeedLayer);
});
if (isDirty) {
damageSelf(info);
}
}
pushLayerUpdate(info);
if (!mProperties.getAllowForceDark()) {
info.disableForceDark--;
}
info.damageAccumulator->popTransform();
}
* frameworks/base/libs/hwui/DamageAccumulator.cpp
void DamageAccumulator::pushCommon() {
if (!mHead->next) {
DirtyStack* nextFrame = mAllocator.create_trivial<DirtyStack>();
nextFrame->next = nullptr;
nextFrame->prev = mHead;
mHead->next = nextFrame;
}
mHead = mHead->next;
mHead->pendingDirty.setEmpty();
}
void DamageAccumulator::pushTransform(const RenderNode* transform) {
pushCommon();
mHead->type = TransformRenderNode;
mHead->renderNode = transform;
}
CanvasContext::Draw
CanvasContext Prepare完后,绘制一帧的数据就准备好了。绘制是在各自的pipeline中进行的
这里为SkiaOpenGLPipeline
- CanvasContext::draw先调用SkiaOpenGLPipeline::getFrame,进而调用mEglManager.beginFrame
Frame是描述一帧数据信息的,主要是宽,高,ufferAge,和Surface这几个属性。绘制开始时,由EglManager根据Surface的属性构建- 然后调用SkiaOpenGLPipeline::draw
void CanvasContext::draw() {
...
Frame frame = mRenderPipeline->getFrame();
...
bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler()));
...
}
* frameworks/base/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
class SkiaOpenGLPipeline : public SkiaPipeline, public IGpuContextCallback {
}
* frameworks/base/libs/hwui/renderthread/EglManager.cpp
Frame EglManager::beginFrame(EGLSurface surface) {
LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE, "Tried to beginFrame on EGL_NO_SURFACE!");
makeCurrent(surface);
Frame frame;
frame.mSurface = surface;
eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, &frame.mWidth);
eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, &frame.mHeight);
frame.mBufferAge = queryBufferAge(surface);
eglBeginFrame(mEglDisplay, surface);
return frame;
}
SkiaOpenGLPipeline::draw
- 调用EglManager.damageFrame主要是部分更新参数的设置,前面我们也damage的区域就是前面Prepare时累加器累加出来的
- 通过FrameInfoVisualizer::draw调用SkiaProfileRenderer::drawRect,中保存SkCanvas::mCanvas成,draw时候调用SkCanvas对应的方法,进而调用到RecordingCanvas::onDrawRect
* frameworks/base/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
const LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
bool opaque, const LightInfo& lightInfo,
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler) {
mEglManager.damageFrame(frame, dirty);
...
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, SkMatrix::I());
layerUpdateQueue->clear();
if (CC_UNLIKELY(Properties::showDirtyRegions ||
ProfileType::None != Properties::getProfileType())) {
SkCanvas* profileCanvas = surface->getCanvas();
SkiaProfileRenderer profileRenderer(profileCanvas);
profiler->draw(profileRenderer);
profileCanvas->flush();
}
...
return true;
}
* frameworks/base/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
void SkiaProfileRenderer::drawRect(float left, float top, float right, float bottom,
const SkPaint& paint) {
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
mCanvas->drawRect(rect, paint);
}
* external/skia/src/core/SkCanvas.cpp
void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
...
this->onDrawRect(r.makeSorted(), paint);
}