顯示系統(tǒng)
Hardware Composer是什么?
硬件圖層混合器,把不同的view layer混合起來。
參考:https://blog.csdn.net/zhjali123/article/details/81455060
SurfaceFlinger是什么?
是一個數(shù)據(jù)緩存區(qū)的管理者,用于接收來自于多個源。管理的數(shù)據(jù)緩存區(qū)叫做layer。
大多數(shù)應(yīng)用于任何時間在屏幕上具有三個 layers:屏幕頂部的狀態(tài)欄,底部或側(cè)面的導(dǎo)航欄,以及應(yīng)用程序 UI。
SurfaceFlinger與windowManager是什么關(guān)系?
WM將手機(jī)的window元數(shù)據(jù)(包括屏幕,z-order等)信息發(fā)送給SurfaceFlinger,因此SurfaceFlinger 能使用這些信息來合成surfaces,并輸出到顯示設(shè)備.
參考:http://gityuan.com/2017/02/05/graphic_arch/
SurfaceFlinger,windowManager,Hardware Compose是什么關(guān)系
windowManager請求SurfaceFlinger,SurfaceFlinger請求Hardware Compose。
應(yīng)用開發(fā)者如何構(gòu)造圖形
可以使用Canvas 或 OpenGL的api。
參考:https://source.android.com/devices/graphics/index.html
Surface是什么?
在 Android 平臺上創(chuàng)建的每個窗口都由 Surface 提供支持。
Surface什么時候創(chuàng)建?
在ViewRootImpl的relayoutWindow的時候創(chuàng)建。
https://zhuanlan.zhihu.com/p/30535788
從應(yīng)用到GPU整個數(shù)據(jù)流是如何的?

左側(cè)的對象是生成圖形緩沖區(qū)的渲染器,如主屏幕、狀態(tài)欄和系統(tǒng)界面。SurfaceFlinger 是合成器,而硬件混合渲染器是制作器。
參考:https://source.android.com/devices/graphics/index.html
BufferQueue是什么?

BufferQueue 包含將圖像流生產(chǎn)方與圖像流消耗方結(jié)合在一起的邏輯。包含三種同步,非同步,舍棄三種工作模式。
應(yīng)用如何和SurfaceFlinger建立連接?
通過SurfaceComposerClient類來連接。進(jìn)行Binder通信。
注意,不是直接使用SurfaceFlinger的Binder。
mSession = new SurfaceComposerClient();
sp<SurfaceControl> control = session()->createSurface(
String8("BootAnimation"), dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
應(yīng)用端new一個SurfaceComposerClient,然后使用這個類去創(chuàng)建一個SurfaceControl去操作Surface。
下面是SurfaceComposerClient的初始化函數(shù)。
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sm(ComposerService::getComposerService());
if (sm != 0) {
auto rootProducer = mParent.promote();
sp<ISurfaceComposerClient> conn;
conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) :
sm->createConnection();
if (conn != 0) {
mClient = conn;
mStatus = NO_ERROR;
}
}
}
ISurfaceComposer實(shí)際是SurfaceFlinger在本地的代理。
/SDM670_Master_8_1/android/frameworks/native/libs/gui/include/gui/ISurfaceComposer.h
class BnSurfaceComposer: public BnInterface<ISurfaceComposer> 服務(wù)端的類,一般叫BnXXX,繼承于BnInterface
/SDM670_Master_8_1/android/frameworks/native/libs/gui/ISurfaceComposer.cpp
class BpSurfaceComposer : public BpInterface<ISurfaceComposer> 客戶端代理的類,一般叫BpXXX,繼承于BpInterface
ISurfaceComposerClient也是遠(yuǎn)端的一個代理,應(yīng)用的操作都是通過ISurfaceComposerClient來操作的。
SurfaceControl類是干什么的?
java上層操控Surface的一個類。
應(yīng)用是怎么申請緩沖區(qū)的?
app與surfaceflinger間如何共享內(nèi)存
通過GraphicBufferMapper,通過序列化的方式構(gòu)造。
通過mmap同一個文件來實(shí)現(xiàn)內(nèi)存共享。
參考:https://www.cnblogs.com/gdk-0078/p/5165242.html
http://www.360doc.com/content/14/0911/15/10366845_408677796.shtml
Gralloc模塊干什么的?
Android系統(tǒng)在硬件抽象層中提供了一個Gralloc模塊,封裝了對幀緩沖區(qū)的所有訪問操作。
SharedBufferStack過時了嗎?
過時了?。?/p>
open gl es在android的窗口較什么名字?
FramebufferNativeWindow
https://blog.csdn.net/STN_LCD/article/details/52680679
layer的消費(fèi)者和生產(chǎn)者是怎么來的?
在layer的構(gòu)造方法中
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer, true); //創(chuàng)建了一個buffer queue
mProducer = new MonitoredProducer(producer, mFlinger, this);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
if (mFlinger->isLayerTripleBufferingDisabled()) {
mProducer->setMaxDequeuedBufferCount(2);
}
const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
updateTransformHint(hw);
}
layer 是什么時候創(chuàng)建的?
在SurfaceFlinger.cpp
的createNormalLayer方法中創(chuàng)建了一個layer
status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
// initialize the surfaces
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
case PIXEL_FORMAT_TRANSLUCENT:
format = PIXEL_FORMAT_RGBA_8888;
break;
case PIXEL_FORMAT_OPAQUE:
format = PIXEL_FORMAT_RGBX_8888;
break;
}
*outLayer = new Layer(this, client, name, w, h, flags);
status_t err = (*outLayer)->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
*handle = (*outLayer)->getHandle();
*gbp = (*outLayer)->getProducer();
}
ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
return err;
}
Layer創(chuàng)建流程是怎樣的?
從客戶端binder通信SurfaceFlinger,讓SurfaceFlinger幫忙建一個surface。
SurfaceComposerClient::createSurface ->
Client::createSurface ->
flinger->createLayer ->
outLayer = new Layer(this, client, name, w, h, flags)
Surface的創(chuàng)建流程是怎樣的?
在創(chuàng)建Surface的過程中,會在SurfaceFlinger端創(chuàng)建一個Layer。
流程是
WindowManagerService.relayoutWindow ->
WindowManagerService.createSurfaceControl ->
winAnimator.createSurfaceLocked ->
surfaceController.getSurface(outSurface) ->
outSurface.copyFrom(mSurfaceControl) ->
Surface.nativeGetFromSurfaceControl(surfaceControlPtr) ->
ctrl->getSurface() ->
new Surface(mGraphicBufferProducer, false);
這個Surface是在wms中的,那應(yīng)用的呢??應(yīng)用是這樣binder調(diào)用
int relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame,
mPendingMergedConfiguration, mSurface);
參考http://www.itdecent.cn/p/64e5c866b4ae
是通過parcel的方式,在應(yīng)用端自己new了一個。
在android_view_Surface.cpp函數(shù)中,通過binder返回的graphicBufferProducer構(gòu)建一個Surface。
if (surfaceShim.graphicBufferProducer != nullptr) {
// we have a new IGraphicBufferProducer, create a new Surface for it
sur = new Surface(surfaceShim.graphicBufferProducer, true);
// and keep a reference before passing to java
sur->incStrong(&sRefBaseOwner);
}
獲取buffer的流程是怎樣的?
RenderThread::initThreadLocals -> EglManager::createSurface -> egl.cpp.eglCreateWindowSurface -> egl.cpp.createWindowSurface
surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
static_cast<ANativeWindow*>(window));
egl_window_surface_v2_t 的connect()函數(shù)會dequeuebuffer
RenderThread什么時候啟動??
在viewrootimpl中的開啟硬件加速時,會創(chuàng)建ThreadRenderer,進(jìn)而創(chuàng)建RenderProxy代理,該代理會獲取RenderThread的單例,創(chuàng)建單例的時候就會啟動這個渲染線程。
應(yīng)用是如何addview的?
WindowManager wm = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
para.type = WindowManager.LayoutParams.TYPE_PHONE;
...
(6.0以上需要動態(tài)檢查是否被授予了SYSTEM_ALERT_WINDOW權(quán)限)
...
wm.addView(view, para);
可以看到
SystemServiceRegistry.java
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx);
}});
所有是使用WindowManagerImpl來addview的。
參考:https://blog.csdn.net/maximus_chan/article/details/40784367
那么Activity第一個view是從哪里來的?
在ActivityThread中的handleResumeActivity函數(shù)中,將decor add進(jìn)去了。
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
那應(yīng)用如何開啟一次繪制了?
addview,添加一個decorview-> viewrootimple.travlasl -> relayout獲取一個surface->performdraw調(diào)用RenderThread去繪制。
繼續(xù)查看ThreadedRenderer.draw函數(shù)。這個是屬于硬件加速的東西。
最終是構(gòu)建一個display list。
繪制一個display list會調(diào)用Surface的debuffer申請內(nèi)存,然后內(nèi)存在應(yīng)用和surfaceflinger共享。
參考,https://blog.csdn.net/luoshengyang/article/details/46281499
http://www.itdecent.cn/p/ccd5da85cf9e
光柵化是什么?
屏幕是一個個光柵組成的。畫圖就是確定哪些光柵要填充內(nèi)容。這個有g(shù)pu完成。
VSYNC虛擬化是什么?
app如何申請vsync,流程是怎樣的?
ViewRootImpl.java
mChoreographer = Choreographer.getInstance();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
Choreographer.java
Choreographer.scheduleVsyncLocked
mDisplayEventReceiver.scheduleVsync
DisplayEventDispatcher.cpp
mReceiver.requestNextVsync
DisplayEventReceiver.cpp
requestNextVsync()
mEventConnection->requestNextVsync();
EventThread.cpp
EventThread::Connection::requestNextVsync
mFlinger.resyncWithRateLimit();
enableVSyncLocked
mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));
mVSyncSource->setVSyncEnabled(true);
SurfaceFlinger.cpp
mDispSync->addEventListener
DispSyncSource.onDispSyncEvent 被回調(diào)
vsync的相位差是如何計算的?
參考:http://www.itdecent.cn/p/d3e4b1805c92
addView會觸發(fā)一次繪制嗎?
會的,addView會觸發(fā)。
frameworks\base\core\java\android\app\ActivityThread.java#handleResumeActivity()
frameworks\base\core\java\android\view\WindowManagerImpl.java#addView()
frameworks\base\core\java\android\view\ViewRoot#setView()
frameworks\base\core\java\android\view\ViewRoot#requestLayout()
frameworks\base\core\java\android\view\ViewRoot#scheduleTraversals()
參考:https://blog.csdn.net/user11223344abc/article/details/81168087
Vsync與動畫的關(guān)系
需要繪制完一幀之后,再次申請vsync??!
參考:https://blog.csdn.net/jiangnan2222/article/details/82619796
多重緩沖技術(shù)
多重緩沖是什么技術(shù)呢?我們先來說雙重緩沖。在Linux上,通常使用FrameBuffer來做顯示輸出。雙重緩沖會創(chuàng)建一個FrontBuffer和一個BackBuffer,顧名思義,F(xiàn)rontBuffer是當(dāng)前顯示的頁面,BackBuffer是下一個要顯示的畫面。
參考:https://www.cnblogs.com/frrj/archive/2018/07/30/brief-info-of-android-display.html
詳細(xì)請看源碼
Layer.cpp
Fence機(jī)制是什么?
Fence是一種同步機(jī)制,在[Android](javascript:void())里主要用于圖形系統(tǒng)中GraphicBuffer的同步。那它和已有同步機(jī)制相比有什么特點(diǎn)呢?它主要被用來處理跨硬件的情況,尤其是CPU,GPU和HWC之間的同步,另外它還可以用于多個時間點(diǎn)之間的同步。
參考:http://www.voidcn.com/article/p-beszdqzb-u.html
可以用system trace來描述整個繪制過程嗎?
首先VSYNC-app跳變,app開始繪制。

Choreographer#doFrame 開始繪制

分別處理input ,animation ,traversal事件,分別對應(yīng)Choreographer.doCallbacks不同類型,這份trace的traversal事件最耗時,draw對應(yīng)ViewRootImpl.performDraw(),Record View#draw()對應(yīng)ThreadedRenderer.updateRootDisplayList,更新根的DisplayList。

ThreadedRenderer.updateRootDisplayList會喚醒沉睡的RenderThread。ThreadedRenderer.nSyncAndDrawFrame 會調(diào)用native方法,通過RenderProxy跟RenderThread打交道。
創(chuàng)建一個DrawFrameTask,丟到RenderThread的任務(wù)列表中。
void DrawFrameTask::postAndWait() {
AutoMutex _lock(mLock);
mRenderThread->queue(this);
mSignal.wait(mLock);
}

SurfaceFlinger在vsync消息來時會處理三個主要的步驟handleMessageTransaction,handleMessageInvalidate,handleMessageRefresh

void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
bool frameMissed = !mHadClientComposition &&
mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getSignalTime() ==
Fence::SIGNAL_TIME_PENDING);
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
if (mPropagateBackpressure && frameMissed) {
signalLayerUpdate();
break;
}
// Now that we're going to make it to the handleMessageTransaction()
// call below it's safe to call updateVrFlinger(), which will
// potentially trigger a display handoff.
updateVrFlinger();
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
// repaint
signalRefresh();
}
break;
}
case MessageQueue::REFRESH: {
handleMessageRefresh();
break;
}
}
}
SurfaceControl的show方法是如何和應(yīng)用啟動顯示的Surface相關(guān)聯(lián)的?
其實(shí)是通過動畫的方式,會調(diào)用到show方法。
"android.display@6431" prio=5 runnable
java.lang.Thread.State: RUNNABLE
at android.view.SurfaceControl.show(SurfaceControl.java:387)
at com.android.server.wm.WindowStateAnimator.showSurfaceRobustlyLocked(WindowStateAnimator.java:1784)
at com.android.server.wm.WindowStateAnimator.prepareSurfaceLocked(WindowStateAnimator.java:1522)
at com.android.server.wm.WindowAnimator.animateLocked(WindowAnimator.java:684)
at com.android.server.wm.WindowAnimator.-wrap0(WindowAnimator.java:-1)
at com.android.server.wm.WindowAnimator$1.doFrame(WindowAnimator.java:123)
- locked <0x19e0> (a java.util.HashMap)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:856)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
WMS是通過什么來操作Surface的呢?
WMS中每一個窗口對應(yīng)一個windowstate,每個windowstate有一個windowstateanimator,里面有surfacecontrol,來操作surface。
LayerStack是什么?Layer的Z軸如何確定??
Layer放置在LayerStack。
Z軸通過SurfaceFlinger的變量layersSortedByZ來確定。
參考https://blog.csdn.net/scpcaicai/article/details/51338411
SurfaceControl的show是做了什么操作?
實(shí)際是需要搭配openSurfaceTransaction和closeSurfaceTransaction,這個會進(jìn)行一個binder通信,通知到SurfaceFlinger。
mService.openSurfaceTransaction();
try {
mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, false);
mSurfaceController.setLayerStackInTransaction(getLayerStack());
mSurfaceController.setLayer(mAnimLayer);
} finally {
mService.closeSurfaceTransaction();
}
流程大概是:
SurfaceControl::setFlags -》SurfaceComposerClient::setFlags -》Composer:setFlags
注意composer是單例的。
最終設(shè)置了一個mComposerStates狀態(tài),binder通信把這個狀態(tài)傳到SurfaceFlinger。
void Composer::closeGlobalTransactionImpl(bool synchronous) {
sp<ISurfaceComposer> sm(ComposerService::getComposerService());
…….
transaction = mComposerStates;
mComposerStates.clear();
…...
sm->setTransactionState(transaction, displayTransaction, flags);
}
這個過程會申請一次vsync嗎??看看會不會調(diào)用requestNextVsync
QueueBuffer后會請求一次Vsync嗎?
會。
流程如下
BufferQueueProducer::queueBuffer
IConsumerListener.h
frameAvailableListener->onFrameAvailable(item)
Layer::onFrameAvailable
SurfaceFlinger::signalLayerUpdate
MessageQueue::invalidate
DisplayEventConnection::requestNextVsync
QueueBuffer是怎么調(diào)用的?
軟件繪制:
ViewRootImpl.drawSoftware方法會lockcanvas和unlockcanvasandpost,分別對應(yīng)dequeuebuffer和queuebuffer
硬件加速:
硬件渲染者的實(shí)例是 ThreadedRenderer
HardwareRenderer.java
static HardwareRenderer create(Context context, boolean translucent) {
HardwareRenderer renderer = null;
if (DisplayListCanvas.isAvailable()) {
renderer = new ThreadedRenderer(context, translucent);
}
return renderer;
}
在ViewRootImpl的draw方法中調(diào)用 ThreadedRenderer的draw方法進(jìn)行硬件繪制。下面是調(diào)用順序。
mAttachInfo.mHardwareRenderer.draw
android_view_ThreadedRenderer.nSyncAndDrawFrame
RenderProxy.syncAndDrawFrame
DrawFrameTask.drawFrame
CanvasContext::draw
EglManager.eglSwapBuffers
egl_window_surface_v2_t::swapBuffers
nativeWindow->queueBuffer
默認(rèn)構(gòu)造函數(shù)的對象實(shí)例方法
參考http://www.cnblogs.com/gklovexixi/p/5814626.html
硬件加速的環(huán)境CanvasContext是怎么創(chuàng)建的?
在RenderProxy的構(gòu)造函數(shù)中:
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, rootRenderNode);
}
SETUP_TASK是什么東西呢?
看看下面的宏定義
#define ARGS(method) method ## Args
#define CREATE_BRIDGE0(name) CREATE_BRIDGE(name,,,,,,,,)
#define CREATE_BRIDGE1(name, a1) CREATE_BRIDGE(name, a1,,,,,,,)
#define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,)
#define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
#define CREATE_BRIDGE4(name, a1, a2, a3, a4) CREATE_BRIDGE(name, a1,a2,a3,a4,,,,)
#define CREATE_BRIDGE5(name, a1, a2, a3, a4, a5) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,,,)
#define CREATE_BRIDGE6(name, a1, a2, a3, a4, a5, a6) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,,)
#define CREATE_BRIDGE7(name, a1, a2, a3, a4, a5, a6, a7) CREATE_BRIDGE(name, a1,a2,a3,a4,a5,a6,a7,)
#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_assert(std::is_trivially_destructible<ARGS(name)>::value, \
"Error, ARGS must be trivially destructible!"); \
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 CanvasContext::create(*args->thread, args->translucent,
args->rootRenderNode, args->contextFactory);
}
將CREATE_BRIDGE4翻譯過來就是
第一步:
CREATE_BRIDGE(createContext, thread,translucent,rootRenderNode,contextFactory,,,,)
第二步
typedef struct { \
createContext, thread,translucent,rootRenderNode,contextFactory,,,,
} createContextArgs; \
static void* Bridge_createContext(createContextArgs* args)
將SETUP_TASK翻譯過來就是,##是連接的意思
MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_createContext);
createContextArgs *args = (createContextArgs *) task->payload()
task->payload返回args,新建了一個task,然后在構(gòu)造函數(shù)賦值args,運(yùn)行這個task。
Layer的名字是從哪里來的?
在relayoutwindow的時候會創(chuàng)建一個WindowSurfaceController,Title就是layer的名字了。
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
attrs.getTitle().toString(),
width, height, format, flags, this, windowType, ownerUid);
Layer的Layer::doTransaction做了什么??
參考http://www.360doc.com/content/14/0329/22/10366845_364800019.shtml
多少個周期才顯示畫面
https://blog.csdn.net/prike/article/details/52175191
繪制的Pipline是什么?
參考:https://segmentfault.com/a/1190000017099186?utm_source=tag-newest
指使用的繪制api,包括skiagl,opengl等
RenderPipelineType Properties::getRenderPipelineType() {
if (sRenderPipelineType != RenderPipelineType::NotInitialized) {
return sRenderPipelineType;
}
char prop[PROPERTY_VALUE_MAX];
property_get(PROPERTY_RENDERER, prop, "skiagl");
if (!strcmp(prop, "skiagl")) {
ALOGD("Skia GL Pipeline");
sRenderPipelineType = RenderPipelineType::SkiaGL;
} else if (!strcmp(prop, "skiavk")) {
ALOGD("Skia Vulkan Pipeline");
sRenderPipelineType = RenderPipelineType::SkiaVulkan;
} else { //"opengl"
ALOGD("HWUI GL Pipeline");
sRenderPipelineType = RenderPipelineType::OpenGL;
}
#ifdef VENDOR_EDIT
//Xiaori.Yuan@MM.Display.Service.Feature, 2018/12/17, Add for douyin power
String8 processName("");
getProcessName(getpid(), processName);
if(needChangeToOpenGL(processName)){
ALOGD("%s: HWUI GL Pipeline",processName.string());
sRenderPipelineType = RenderPipelineType::OpenGL;
}
#endif /* VENDOR_EDIT */
return sRenderPipelineType;
}
如何導(dǎo)出一個應(yīng)用的繪制信息?
dumpsys gfxinfo com.opera.browser
Applications Graphics Acceleration Info:
Uptime: 11571274 Realtime: 18973286
** Graphics info for pid 14773 [com.opera.browser] **
Stats since: 11541453130610ns
Total frames rendered: 536
Janky frames: 85 (15.86%)
50th percentile: 5ms
90th percentile: 23ms
95th percentile: 61ms
99th percentile: 150ms
Number Missed Vsync: 33
Number High input latency: 280
Number Slow UI thread: 28
Number Slow bitmap uploads: 1
Number Slow issue draw commands: 11
Number Frame deadline missed: 43
HISTOGRAM: 5ms=328 6ms=15 7ms=11 8ms=13 9ms=12 10ms=15 11ms=9 12ms=11 13ms=10 14ms=10 15ms=11 16ms=11 17ms=5 18ms=5 19ms=8 20ms=3 21ms=4 22ms=1 23ms=4 24ms=0 25ms=1 26ms=1 27ms=0 28ms=0 29ms=1 30ms=1 31ms=1 32ms=3 34ms=1 36ms=2 38ms=3 40ms=0 42ms=3 44ms=1 46ms=0 48ms=1 53ms=2 57ms=2 61ms=3 65ms=2 69ms=1 73ms=0 77ms=1 81ms=2 85ms=2 89ms=0 93ms=0 97ms=0 101ms=1 105ms=0 109ms=0 113ms=0 117ms=1 121ms=0 125ms=1 129ms=0 133ms=1 150ms=8 200ms=1 250ms=1 300ms=0 350ms=0 400ms=0 450ms=0 500ms=0 550ms=0 600ms=0 650ms=1 700ms=0 750ms=0 800ms=0 850ms=0 900ms=0 950ms=0 1000ms=1 1050ms=0 1100ms=0 1150ms=0 1200ms=0 1250ms=0 1300ms=0 1350ms=0 1400ms=0 1450ms=0 1500ms=0 1550ms=0 1600ms=0 1650ms=0 1700ms=0 1750ms=0 1800ms=0 1850ms=0 1900ms=0 1950ms=0 2000ms=0 2050ms=0 2100ms=0 2150ms=0 2200ms=0 2250ms=0 2300ms=0 2350ms=0 2400ms=0 2450ms=0 2500ms=0 2550ms=0 2600ms=0 2650ms=0 2700ms=0 2750ms=0 2800ms=0 2850ms=0 2900ms=0 2950ms=0 3000ms=0 3050ms=0 3100ms=0 3150ms=0 3200ms=0 3250ms=0 3300ms=0 3350ms=0 3400ms=0 3450ms=0 3500ms=0 3550ms=0 3600ms=0 3650ms=0 3700ms=0 3750ms=0 3800ms=0 3850ms=0 3900ms=0 3950ms=0 4000ms=0 4050ms=0 4100ms=0 4150ms=0 4200ms=0 4250ms=0 4300ms=0 4350ms=0 4400ms=0 4450ms=0 4500ms=0 4550ms=0 4600ms=0 4650ms=0 4700ms=0 4750ms=0 4800ms=0 4850ms=0 4900ms=0 4950ms=0
Font Cache (CPU):
Size: 504.68 kB
Glyph Count: 43
CPU Caches:
GPU Caches:
Other:
Buffer Object: 99.00 KB (3 entries)
Image:
Surface: 2.21 MB (31 entries)
Scratch:
Buffer Object: 64.00 KB (2 entries)
Surface: 71.11 MB (39 entries)
Other Caches:
Current / Maximum
VectorDrawableAtlas 0.00 kB / 0.00 KB (entries = 0)
Layers Total 0.00 KB (numLayers = 0)
Total GPU memory usage:
77053016 bytes, 73.48 MB (23.22 MB is purgeable)
Pipeline=Skia (Vulkan)
Layout Cache Info:
Usage: 413/5000 entries
Hit ratio: 5161/5574 (0.925906)
Profile data in ms:
com.opera.browser/com.opera.android.BrowserActivity/android.view.ViewRootImpl@40f3c9e (visibility=0)
View hierarchy:
com.opera.browser/com.opera.android.BrowserActivity/android.view.ViewRootImpl@40f3c9e
224 views, 201.06 kB of display lists
Total ViewRootImpl: 1
Total Views: 224
Total DisplayList: 201.06 kB
android如何調(diào)用skia的api的??
繪制是通過類SKCanvas.cpp來實(shí)現(xiàn)的。
生成的庫是libskia
view的構(gòu)造函數(shù)會新建一個RenderNode,RenderNode會新建一個DisplaylistCanvas,Canvas的繪制就是要用到skia的接口?。。?/p>
參考:https://blog.csdn.net/jxt1234and2010/article/details/42572559
https://blog.csdn.net/wind_hzx/article/details/20307093
https://blog.csdn.net/kc58236582/article/details/52879698
如何將displaylist轉(zhuǎn)換為opengl的命令?
android o之前通過方法:
DeferredDisplayList::flush
android O之后參考
http://www.itdecent.cn/p/abfaea892611
繪制的指令的記錄在哪里的?
繪制的指令記錄在RecordingCanvas中,這個東西是在創(chuàng)建DisplayListCanvas的過程中創(chuàng)建的。
具體是android_view_DisplayListCanvas.cpp的android_view_DisplayListCanvas_createDisplayListCanvas函數(shù)中。
CanvasState用來記錄繪制的狀態(tài)。
CanvasState的變量mSnapshot 表示當(dāng)前的快照,用來記錄當(dāng)前繪制的坐標(biāo)系

參考 https://blog.csdn.net/jinzhuojun/article/details/54234354
繪制指令保存的chunk是什么東東?
chunk里面保存著繪制的指令,按照子view來區(qū)分,通過插入柵欄來隔開不同的chunk。
參考:https://www.kancloud.cn/alex_wsc/androids/473792

一個頁面繪制的起點(diǎn)是什么?
是Root Render Node,這個相當(dāng)與一個樹的起點(diǎn),從這個起點(diǎn)可以變量整棵樹,進(jìn)而繪制了一個完整的畫面。
Root Render Node在ThreadRender的構(gòu)造函數(shù)中創(chuàng)建。對于一個Actvity,這個Root RenderNode就是decord view啦。
從RootRenderNode的角度看,繪制流程是怎樣的?
流程如下:
ViewRootImpl.java
mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
ThreadedRenderer.java
draw()
updateRootDisplayList()
canvas.drawRenderNode(view.updateDisplayListIfDirty());
EGLSurface和Surface有什么關(guān)系?
Surface是android端的東西,EGLSurface是Egl系統(tǒng)的一個頁面。
對應(yīng)EGLSurface,有EGLContext,代表EGL繪制的上下文。
這個上下文在RenderProxy的構(gòu)造函數(shù)中創(chuàng)建
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, rootRenderNode);
}
可以看到這個上下文指定了渲染的線程RenderThread和渲染的根結(jié)點(diǎn)RootRenderNode。
并且在他的init函數(shù)會綁定android的Surface
CREATE_BRIDGE2(initialize, CanvasContext* context, Surface* surface) {
args->context->initialize(args->surface);
return nullptr;
}
參考https://blog.csdn.net/happy19850920/article/details/50773875
https://blog.csdn.net/luoshengyang/article/details/45769759
https://blog.csdn.net/c_z_w/article/details/86527847
GlSurfaceView的流程是怎樣的?
參考frameworks/native/opengl/tests/lighting1709/src/com/android/lightingtest/ClearActivity.java
可以將GlsurfaceView直接用過setContentview來設(shè)置進(jìn)去。
GlSurfaceView里面只需要設(shè)置一個Render渲染器就可以。
class ClearGLSurfaceView extends GLSurfaceView {
public ClearGLSurfaceView(Context context) {
super(context);
mRenderer = new ClearRenderer();
setRenderer(mRenderer);
}
ClearRenderer mRenderer;
}
而所有的繪制的回調(diào)函數(shù)都在Render中實(shí)現(xiàn)。例如
public interface Renderer {
void onSurfaceCreated(GL10 gl, EGLConfig config);
void onSurfaceChanged(GL10 gl, int width, int height);
void onDrawFrame(GL10 gl);
}
那如何觸發(fā)開始渲染的呢?
我們知道Surface是獨(dú)立渲染的,渲染的入口就是setRenderer方法。這個方法會啟動一個GlThread渲染線程開始渲染。
渲染的流程:
1.獲取顯示設(shè)備
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
2.選擇config
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
3.創(chuàng)建EglContext
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
4.創(chuàng)建EglSurface
mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
mEglDisplay, mEglConfig, view.getHolder());
5.設(shè)置渲染環(huán)境到當(dāng)前線程
mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
6.開始渲染
TextureView
在UI重繪函數(shù)performTranversals()中,作為View hierachy的一分子,TextureView的draw()函數(shù)被調(diào)用,其中便會相繼調(diào)用applyUpdate()和HardwareLayer的updateSurfaceTexture()函數(shù)
參考https://blog.csdn.net/m475664483/article/details/52998445
http://www.itdecent.cn/p/a14955e52216
http://www.itdecent.cn/p/4e2916889f27
Android View系統(tǒng)的位置信息是如何的?
protected int mLeft; view左邊界距離父View左邊的距離
protected int mRight; view右邊界距離父View左邊的距離
protected int mTop;view上邊界距離父View上邊的距離
protected int mBottom;view下邊界距離父View上邊的距離
protected int mScrollX;
protected int mScrollY;
見下圖,參考https://blog.csdn.net/hehe26/article/details/53286027

位置相關(guān)函數(shù): 參考:https://blog.csdn.net/cadi2011/article/details/71440491
getLocationInWindow
一個控件在其父窗口中的坐標(biāo)位置,源碼如下,原理就是不斷地獲取父view的mLeft,然后疊加在一起,就是最后一個控件在其父窗口中的左坐標(biāo)位置。右左標(biāo)同理。
public void getLocationInWindow(@Size(2) int[] outLocation) {
if (outLocation == null || outLocation.length < 2) {
throw new IllegalArgumentException("outLocation must be an array of two integers");
}
outLocation[0] = 0;
outLocation[1] = 0;
transformFromViewToWindowSpace(outLocation);
}
/** @hide */
public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) {
if (inOutLocation == null || inOutLocation.length < 2) {
throw new IllegalArgumentException("inOutLocation must be an array of two integers");
}
if (mAttachInfo == null) {
// When the view is not attached to a window, this method does not make sense
inOutLocation[0] = inOutLocation[1] = 0;
return;
}
float position[] = mAttachInfo.mTmpTransformLocation;
position[0] = inOutLocation[0];
position[1] = inOutLocation[1];
if (!hasIdentityMatrix()) {
getMatrix().mapPoints(position);
}
position[0] += mLeft;
position[1] += mTop;
ViewParent viewParent = mParent;
while (viewParent instanceof View) { //關(guān)鍵點(diǎn),遍歷父view
final View view = (View) viewParent;
position[0] -= view.mScrollX;
position[1] -= view.mScrollY;
if (!view.hasIdentityMatrix()) {
view.getMatrix().mapPoints(position);
}
position[0] += view.mLeft;
position[1] += view.mTop;
viewParent = view.mParent;
}
if (viewParent instanceof ViewRootImpl) {
// *cough*
final ViewRootImpl vr = (ViewRootImpl) viewParent;
position[1] -= vr.mCurScrollY;
}
inOutLocation[0] = Math.round(position[0]);
inOutLocation[1] = Math.round(position[1]);
}
getLocationOnScreen
一個控件在其整個屏幕上的坐標(biāo)位置,源碼如下,意思是靠mAttachInfo來獲取
public int[] getLocationOnScreen() {
int[] location = new int[2];
getLocationOnScreen(location);
return location;
}
/**
* <p>Computes the coordinates of this view on the screen. The argument
* must be an array of two integers. After the method returns, the array
* contains the x and y location in that order.</p>
*
* @param outLocation an array of two integers in which to hold the coordinates
*/
public void getLocationOnScreen(@Size(2) int[] outLocation) {
getLocationInWindow(outLocation);
final AttachInfo info = mAttachInfo;
if (info != null) {
outLocation[0] += info.mWindowLeft;
outLocation[1] += info.mWindowTop;
}
}
getLocationInWindow是以B為原點(diǎn)的C的坐標(biāo),而getLocationOnScreen以A為原點(diǎn)。

window與view的區(qū)別
一個Activity就是一個window,這里window里面裝著decordview,decordview是根view。