Android9.0源碼分析
繪制入口
//frameworks/base/core/java/android/view/ViewRootImpl.java
private boolean draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
...
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
...
final FrameDrawingCallback callback = mNextRtFrameCallback;
mNextRtFrameCallback = null;
//硬件繪制
mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this, callback);
} else {
...
//軟件繪制
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
scalingRequired, dirty, surfaceInsets)) {
return false;
}
}
}
...
return useAsyncReport;
}
Android軟件渲染流程
canvas的創(chuàng)建
- 創(chuàng)建java層Canvas對(duì)象
//frameworks/base/core/java/android/view/Surface.java
private final Canvas mCanvas = new CompatibleCanvas();
//private final class CompatibleCanvas extends Canvas
- 非硬件加速情況下,通過nInitRaster()方法在native層創(chuàng)建對(duì)應(yīng)的Canvas對(duì)象
//frameworks/base/graphics/java/android/graphics/Canvas.java
public Canvas() {
if (!isHardwareAccelerated()) {
// 0 means no native bitmap
mNativeCanvasWrapper = nInitRaster(null);
mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
this, mNativeCanvasWrapper);
} else {
mFinalizer = null;
}
}
- 調(diào)用Canvas::create_canvas()方法創(chuàng)建canvas,Canvas為native層的封裝
//frameworks/base/libs/hwui/jni/android_graphics_Canvas.cpp
static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
SkBitmap bitmap;
if (jbitmap != NULL) {
GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
}
return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
}
- SkiaCanvs為Canvas子類,說明底層使用Skia引擎進(jìn)行渲染
//frameworks/base/libs/hwui/SkiaCanvas.cpp
Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
return new SkiaCanvas(bitmap);
}
SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
sk_sp<SkColorSpace> cs = bitmap.refColorSpace();
mCanvasOwned =
std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy));
if (cs.get() == nullptr || cs->isSRGB()) {
if (!uirenderer::Properties::isSkiaEnabled()) {
mCanvasWrapper =
SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB());
mCanvas = mCanvasWrapper.get();
} else {
mCanvas = mCanvasOwned.get();
}
} else {
mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), std::move(cs));
mCanvas = mCanvasWrapper.get();
}
}
- 最終創(chuàng)建了一個(gè)Skia的畫板,其中SkBitmapDevice表明后端渲染使用的是軟件渲染
//external/skia/src/core/SkCanvas.cpp
SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
, fProps(props)
{
inc_canvas();
//此處創(chuàng)建的SkBitmapDevice表明后端渲染使用的是軟件渲染
sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
this->init(device.get(), kDefault_InitFlags);
}
//frameworks/base/core/jni/android_view_Surface.cpp
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
...
ANativeWindow_Buffer outBuffer;
status_t err = surface->lock(&outBuffer, dirtyRectPtr);
...
SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
convertPixelFormat(outBuffer.format),
outBuffer.format == PIXEL_FORMAT_RGBX_8888
? kOpaque_SkAlphaType : kPremul_SkAlphaType,
GraphicsJNI::defaultColorSpace());
SkBitmap bitmap;
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
bitmap.setInfo(info, bpr);
if (outBuffer.width > 0 && outBuffer.height > 0) {
bitmap.setPixels(outBuffer.bits);
} else {
// be safe with an empty bitmap.
bitmap.setPixels(NULL);
}
Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
nativeCanvas->setBitmap(bitmap);
...
// Create another reference to the surface and return it. This reference
// should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,
// because the latter could be replaced while the surface is locked.
sp<Surface> lockedSurface(surface);
lockedSurface->incStrong(&sRefBaseOwner);
return (jlong) lockedSurface.get();
}
Android硬件渲染流程
- android系統(tǒng)默認(rèn)開啟硬件加速,開發(fā)者可以在應(yīng)用的Manifest文件中通過<application>以及<activity>標(biāo)簽的android:hardwareAccelerated屬性來關(guān)閉或開啟應(yīng)用或特定Activity的硬件加速(同時(shí)即使應(yīng)用級(jí)別的硬件加速被關(guān)閉,開發(fā)者仍然可以通過View.setLayerType()方法來為特定的視圖開啟硬件加速)。
1. 硬件加速開啟條件
從啟動(dòng)繪制代碼能看出只有mThreadRender非空并且可用的狀態(tài)下,才會(huì)使用硬件渲染,先看看mThreadRender的賦值條件。
//frameworks/base/core/java/android/view/ViewRootImpl.java
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
...
// Try to enable hardware acceleration if requested
final boolean hardwareAccelerated =
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
if (hardwareAccelerated) {
...
if (fakeHwAccelerated) {
...
} else if (!ThreadedRenderer.sRendererDisabled
|| (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
...
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
attrs.getTitle().toString());
...
}
}
}
上述enableHardwareAcceleration方法中attr參數(shù)由WindowManagerGlobal在創(chuàng)建ViewRootImpl時(shí)傳入,代碼如下。
//frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
...
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
//應(yīng)用未指定禁用硬件渲染,則attr.flags設(shè)置為使用硬件渲染
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
...
if (windowlessSession == null) {
root = new ViewRootImpl(view.getContext(), display);
} else {
root = new ViewRootImpl(view.getContext(), display,
windowlessSession, new WindowlessWindowLayout());
}
...
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
...
}
}
從代碼可以看出,此處硬件加速正好對(duì)應(yīng)上了應(yīng)用的配置。接下來看看硬件繪制的場(chǎng)景下,其繪制的基本流程。
- draw()
void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks,
FrameDrawingCallback frameDrawingCallback) {
attachInfo.mIgnoreDirtyState = true;
final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
choreographer.mFrameInfo.markDrawStart();
//更新繪制列表
updateRootDisplayList(view, callbacks);
...
final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
if (frameDrawingCallback != null) {
nSetFrameCallback(mNativeProxy, frameDrawingCallback);
}
//實(shí)際的繪制
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
...
}
- 更新根view繪制列表
//frameworks/base/core/java/android/view/ThreadedRenderer.java
private void updateRootDisplayList(View view, DrawCallbacks callbacks) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
//更新子view繪制列表
updateViewTreeDisplayList(view);
if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
try {
final int saveCount = canvas.save();
canvas.translate(mInsetLeft, mInsetTop);
callbacks.onPreDraw(canvas);
canvas.insertReorderBarrier();
canvas.drawRenderNode(view.updateDisplayListIfDirty());
canvas.insertInorderBarrier();
callbacks.onPostDraw(canvas);
canvas.restoreToCount(saveCount);
mRootNodeNeedsUpdate = false;
} finally {
mRootNode.end(canvas);
}
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
- 更新子view的繪制列表
//frameworks/base/core/java/android/view/ThreadedRenderer.java
private void updateViewTreeDisplayList(View view) {
...
view.updateDisplayListIfDirty();
view.mRecreateDisplayList = false;
}
//frameworks/base/core/java/android/view/View.java
public RenderNode updateDisplayListIfDirty() {
final RenderNode renderNode = mRenderNode;
...
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
|| !renderNode.isValid()
|| (mRecreateDisplayList)) {
...
dispatchGetDisplayList(); //分發(fā)子view生成繪制列表
return renderNode; // no work needed
}
// If we got here, we're recreating it. Mark it as such to ensure that
// we copy in child display lists into ours in drawChild()
mRecreateDisplayList = true;
...
final DisplayListCanvas canvas = renderNode.start(width, height);
try {
// 如果當(dāng)前view指定軟件渲染,則直接繪制到bitmap,用于后期合成
if (layerType == LAYER_TYPE_SOFTWARE) {
buildDrawingCache(true);
Bitmap cache = getDrawingCache(true);
if (cache != null) {
canvas.drawBitmap(cache, 0, 0, mLayerPaint);
}
} else {
computeScroll();
...
//繪制
draw(canvas);
}
} finally {
renderNode.end(canvas); //繪制結(jié)束
setDisplayListProperties(renderNode);
}
} else {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
}
return renderNode;
}
//frameworks/base/core/java/android/view/RenderNode.java
//繪制結(jié)束,記錄好繪制指令
public void end(DisplayListCanvas canvas) {
long displayList = canvas.finishRecording();
nSetDisplayList(mNativeRenderNode, displayList);
canvas.recycle();
}
- canvas的創(chuàng)建
//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) {
if (uirenderer::Properties::isSkiaEnabled()) {
return new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width, height);
}
return new uirenderer::RecordingCanvas(width, height);
}
- skiaRecordingCanvas
//frameworks/base/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
class SkiaRecordingCanvas : public SkiaCanvas {
public:
explicit SkiaRecordingCanvas(uirenderer::RenderNode* renderNode, int width, int height) {
initDisplayList(renderNode, width, height);
}
...
private:
SkLiteRecorder mRecorder; //繪制指令
std::unique_ptr<SkiaDisplayList> mDisplayList;
...
};
//
class SkLiteRecorder final : public SkNoDrawCanvas {
public:
void onDrawRect (const SkRect&, const SkPaint&) override;
void onDrawRegion(const SkRegion&, const SkPaint&) override;
...
private:
typedef SkNoDrawCanvas INHERITED;
SkLiteDL* fDL;
}
//external/skia/src/core/SkLiteRecorder.cpp
void SkLiteRecorder::onDrawPaint(const SkPaint& paint) {
fDL->drawPaint(paint);
}
其中SkLiteRecorder是SkCanvas子類,用于實(shí)現(xiàn)繪制指令的生成, 在java層對(duì)象View的onDraw(Canvas)方法后,整體的繪制指令已經(jīng)生成完畢。
- 繪制指令生成后,nSyncAndDrawFrame啟動(dòng)繪制,最終會(huì)調(diào)用到DrawFrameTask的run方法進(jìn)行繪制,其中DrawFrameTask中的CanvasContext在RenderProxy中創(chuàng)建
//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);
}
//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::OpenGL:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
std::make_unique<OpenGLPipeline>(thread));
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;
}
- 繼續(xù)來看下SkiaOpenGLPipeline的draw()方法, 其中renderFrame繼續(xù)進(jìn)行繪制操作,最終會(huì)調(diào)用到RenderNode的draw()方法
bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo,
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler) {
mEglManager.damageFrame(frame, dirty);
...
//繪制幀
renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
surface);
layerUpdateQueue->clear();
...
return true;
}
//frameworks/base/libs/hwui/pipeline/skia/SkiaPipeline.cpp
void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
bool wideColorGamut, const Rect& contentDrawBounds,
sk_sp<SkSurface> surface) {
...
// capture is enabled.
std::unique_ptr<SkPictureRecorder> recorder;
SkCanvas* canvas = tryCapture(surface.get());
renderFrameImpl(layers, clip, nodes, opaque, wideColorGamut, contentDrawBounds, canvas);
...
surface->getCanvas()->flush();
}
void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
bool wideColorGamut, const Rect& contentDrawBounds,
SkCanvas* canvas) {
if (1 == nodes.size()) {
if (!nodes[0]->nothingToDraw()) {
RenderNodeDrawable root(nodes[0].get(), canvas);
//繪制
root.draw(canvas);
}
}
}
- 繼續(xù)看RenderNodeDrawable的draw()方法, 最終會(huì)調(diào)用到drawContent()方法
//frameworks/base/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
RenderNode* renderNode = mRenderNode.get();
...
SkiaDisplayList* displayList = (SkiaDisplayList*)mRenderNode->getDisplayList();
...
//繪制
displayList->draw(canvas);
}
- SkiaDisplayList的draw()方法
//frameworks/base/libs/hwui/pipeline/skia/SkiaDisplayList.h
SkLiteDL mDisplayList;
void draw(SkCanvas* canvas) { mDisplayList.draw(canvas); }
draw(SkCanvas* canvas)方法中cancas由前面創(chuàng)建的skSurface中獲取,至此,skia硬件渲染正式開始。
Flutter源碼
engine倉庫
軟硬件渲染選擇
/Users/omegaxiao/MyCode/engine/shell/platform/android/platform_view_android.cc
std::unique_ptr<AndroidSurface> AndroidSurfaceFactoryImpl::CreateSurface() {
switch (android_context_->RenderingApi()) {
case AndroidRenderingAPI::kSoftware:
return std::make_unique<AndroidSurfaceSoftware>();
case AndroidRenderingAPI::kImpellerOpenGLES:
return std::make_unique<AndroidSurfaceGLImpeller>(
std::static_pointer_cast<AndroidContextGLImpeller>(android_context_));
case AndroidRenderingAPI::kSkiaOpenGLES:
return std::make_unique<AndroidSurfaceGLSkia>(
std::static_pointer_cast<AndroidContextGLSkia>(android_context_));
case AndroidRenderingAPI::kImpellerVulkan:
return std::make_unique<AndroidSurfaceVulkanImpeller>(
std::static_pointer_cast<AndroidContextVulkanImpeller>(
android_context_));
}
FML_UNREACHABLE();
}