Android:顯示系統(tǒng)總結(jié)

顯示系統(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ù)流是如何的?

image.png

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

BufferQueue是什么?

image.png

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虛擬化是什么?

參考https://windrunnerlihuan.com/2017/05/25/Android-SurfaceFlinger-%E5%AD%A6%E4%B9%A0%E4%B9%8B%E8%B7%AF-%E4%BA%94-VSync-%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86/

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開始繪制。


VSYNC-app跳變

Choreographer#doFrame 開始繪制


image.png

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


input,animate,travel

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);
}

RenderThread

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


image.png
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)系


image.png

參考 https://blog.csdn.net/jinzhuojun/article/details/54234354

繪制指令保存的chunk是什么東東?

chunk里面保存著繪制的指令,按照子view來區(qū)分,通過插入柵欄來隔開不同的chunk。
參考:https://www.kancloud.cn/alex_wsc/androids/473792

image.png

一個頁面繪制的起點(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

image.png

位置相關(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)。


image.png

window與view的區(qū)別

一個Activity就是一個window,這里window里面裝著decordview,decordview是根view。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容