2018年1月10日 星期三

從 BootAnimation 探索 SurfaceFlinger (三) 野生的四天王.現身

前情提要

上一篇文章我們分析了 Layer class 裡面的 BufferQueue 相關構造,
但是還沒有看到 Layer 究竟會做哪些工作.

Layer 生成了 mProducer 跟 mSurfaceFlingerConsumer,
因為 Layer 本身繼承了 SurfaceFlingerConsumer::ContentsChangedListener,
它會通知 SurfaceFlinger 說已經有新的資料來到了.
另一方面, 這個 mProducer 應該要有人負責去輸入資料,
我們接著看看是誰來接走了 mProducer 的功能.

回到 createNormalLayer:
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;
}

透過 setBuffer 設置 mSurfaceFlingerConsumer 的屬性,
然後把 handle 跟 gbp 設置好, 準備返回給 SurfaceComposerClient
(忘記的人可以點開第一篇來回顧一下)
sp<IBinder> Layer::getHandle() {
    Mutex::Autolock _l(mLock);

    LOG_ALWAYS_FATAL_IF(mHasSurface,
            "Layer::getHandle() has already been called");

    mHasSurface = true;

    /*
     * The layer handle is just a BBinder object passed to the client
     * (remote process) -- we don't keep any reference on our side such that
     * the dtor is called when the remote side let go of its reference.
     *
     * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
     * this layer when the handle is destroyed.
     */

    class Handle : public BBinder, public LayerCleaner {
        wp<const Layer> mOwner;
    public:
        Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
            : LayerCleaner(flinger, layer), mOwner(layer) {
        }
    };

    return new Handle(mFlinger, this);
}

sp<IGraphicBufferProducer> Layer::getProducer() const {
    return mProducer;
}

Handle 的功能是將這個 new 出來的 Layer 轉交給 SurfaceComposerClient,
而不是將 Layer 的指針保存在 SurfaceFlinger 裡面
而 mProducer 就是 MonitoredProducer, 可以透過它存取 BufferQueueProducer

再度回到 SurfaceComposerClient (中間還有一層 Binder 的 IPC, 這裡就不特別論述)
sp<SurfaceControl> SurfaceComposerClient::createSurface(
        const String8& name,
        uint32_t w,
        uint32_t h,
        PixelFormat format,
        uint32_t flags)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags,
                &handle, &gbp);
        ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);
        }
    }
    return sur;
}

handle 跟 gbp 又被轉交給了 SurfaceControl 對象
SurfaceControl::SurfaceControl(
        const sp<SurfaceComposerClient>& client,
        const sp<IBinder>& handle,
        const sp<IGraphicBufferProducer>& gbp)
    : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp)
{
}

好的, 終於要回到 BootAnimation 了
可怕的是...我們還在 readyToRun() 的第五行
跟 Inception 一樣每下一層的時間都是上一層的 20 倍
status_t BootAnimation::readyToRun() {
    mAssets.addDefaultAssets();

    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
            ISurfaceComposer::eDisplayIdMain));
    DisplayInfo dinfo;
    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
    if (status)
        return -1;

    // create the native surface
    sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);

    SurfaceComposerClient::openGlobalTransaction();
    control->setLayer(0x40000000);
    SurfaceComposerClient::closeGlobalTransaction();

    sp<Surface> s = control->getSurface();

這裡的 openGlobalTransaction() ~ closeGlobalTransaction() 會在多執行序時讓希望通知 SurfaceFlinger的人可以進行一次通知
它會使用變量 mTransactionNestCount 來判斷是否還有其他人也想同時操作
假設有多個用戶在呼叫 (此例是 SurfaceControl 呼叫 SurfaceComposerClient::setLayer())
每個人在 openGlobalTransaction() 時會增加 mTransactionNestCount
並在 closeGlobalTransaction() 時去減掉 mTransactionNestCount
只有當 mTransactionNestCount 為 0 的時候才會去呼叫 SurfaceFlinger, 如下:
void Composer::openGlobalTransactionImpl() {
    { // scope for the lock
        Mutex::Autolock _l(mLock);
        mTransactionNestCount += 1;
    }
}

void Composer::closeGlobalTransactionImpl(bool synchronous) {
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());

    Vector<ComposerState> transaction;
    Vector<DisplayState> displayTransaction;
    uint32_t flags = 0;

    { // scope for the lock
        Mutex::Autolock _l(mLock);
        mForceSynchronous |= synchronous;
        if (!mTransactionNestCount) {
            ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior "
                    "call to openGlobalTransaction().");
        } else if (--mTransactionNestCount) {
            return;
        }

        transaction = mComposerStates;
        mComposerStates.clear();

        displayTransaction = mDisplayStates;
        mDisplayStates.clear();

        if (mForceSynchronous) {
            flags |= ISurfaceComposer::eSynchronous;
        }
        if (mAnimation) {
            flags |= ISurfaceComposer::eAnimation;
        }

        mForceSynchronous = false;
        mAnimation = false;
    }

   sm->setTransactionState(transaction, displayTransaction, flags);
}

這裡呼叫的設定是 SurfaceControl->setLayer(0x40000000)
我們過一下這整個 code flow:
// SurfaceControl.cpp
status_t SurfaceControl::setLayer(uint32_t layer) {
    status_t err = validate();
    if (err < 0) return err;
    return mClient->setLayer(mHandle, layer);
}   

// SurfaceComposerClient.cpp
status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, uint32_t z) {
    return getComposer().setLayer(this, id, z);
}

status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
        const sp<IBinder>& id, uint32_t z) {
    Mutex::Autolock _l(mLock);
    layer_state_t* s = getLayerStateLocked(client, id);
    if (!s)
        return BAD_INDEX;
    s->what |= layer_state_t::eLayerChanged;
    s->z = z;
    return NO_ERROR;
}

layer_state_t* Composer::getLayerStateLocked(
        const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) {
    
    ComposerState s; 
    s.client = client->mClient;
    s.state.surface = id;
    
    ssize_t index = mComposerStates.indexOf(s);
    if (index < 0) {
        // we don't have it, add an initialized layer_state to our list
        index = mComposerStates.add(s);
    }

    ComposerState* const out = mComposerStates.editArray();
    return &(out[index].state);
}

// LayerState.h
struct ComposerState {
    sp<ISurfaceComposerClient> client;
    layer_state_t state;
    status_t    write(Parcel& output) const;
    status_t    read(const Parcel& input);
};

// LayerState.cpp
struct layer_state_t {
    layer_state_t()
        :   what(0),
            x(0), y(0), z(0), w(0), h(0), layerStack(0),
            alpha(0), flags(0), mask(0),
            reserved(0)
    {
        matrix.dsdx = matrix.dtdy = 1.0f;
        matrix.dsdy = matrix.dtdx = 0.0f;
        crop.makeInvalid();
    }

    status_t    write(Parcel& output) const;
    status_t    read(const Parcel& input);

    struct matrix22_t {
        float   dsdx;
        float   dtdx;
        float   dsdy;
        float   dtdy;
    };
    sp<IBinder>     surface;
    uint32_t        what;
    float           x;
    float           y;
    uint32_t        z;
    uint32_t        w;
    uint32_t        h;
    uint32_t        layerStack;
    float           alpha;
    uint8_t         flags;
    uint8_t         mask;
    uint8_t         reserved;
    matrix22_t      matrix;
    Rect            crop;
    // non POD must be last. see write/read
    Region          transparentRegion;
};

第一次呼叫時, 應該會把一個新的 ComposerState 加入 mComposerStates 這個 SortedVector 裡面
接著對 ComposerState 裡面的 layer_state_t 設定其 z 值
這個 z 值其實是拿來計算不同 layer 的上下關係, 如果被覆蓋住的區塊就不會特別去繪製了
後面在繪圖的部分會再看到這部分的計算.

接下來再回到 BootAnimation, 接下來要呼叫的是
sp<Surface> s = control->getSurface();
sp<Surface> SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        // This surface is always consumed by SurfaceFlinger, so the
        // producerControlledByApp value doesn't matter; using false.
        mSurfaceData = new Surface(mGraphicBufferProducer, false);
    }
    return mSurfaceData;
}

這個 Surface 對象會跟 openGL 的 API 接軌
我們看一下他的建構子:
Surface::Surface(
        const sp<IGraphicBufferProducer>& bufferProducer,
        bool controlledByApp)
    : mGraphicBufferProducer(bufferProducer),
      mGenerationNumber(0)
{
    // Initialize the ANativeWindow function pointers.
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
    ANativeWindow::queueBuffer      = hook_queueBuffer;
    ANativeWindow::query            = hook_query;
    ANativeWindow::perform          = hook_perform;

    ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
    ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;
    ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;
    ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;

    const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;

    mReqWidth = 0;
    mReqHeight = 0;
    mReqFormat = 0;
    mReqUsage = 0;
    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
    mDataSpace = HAL_DATASPACE_UNKNOWN;
    mCrop.clear();
    mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
    mTransform = 0;
    mStickyTransform = 0;
    mDefaultWidth = 0;
    mDefaultHeight = 0;
    mUserWidth = 0;
    mUserHeight = 0;
    mTransformHint = 0;
    mConsumerRunningBehind = false;
    mConnectedToCpu = false;
    mProducerControlledByApp = controlledByApp;
    mSwapIntervalZero = false;
}

可以看到一開始生成的 mGraphicBufferProducer 被帶進來了
之後它會在呼叫 Surface::dequeueBuffer() 時使用到, 我們晚點再一起談論.

接下來是一連串 openGL / EGL 的操作

關於 EGL 跟 OpenGL 的關係, 可以參考這篇文章
簡單摘錄一下重點:
OpenGL 會負責操作 GPU 進行圖形的渲染等工作
但因為 OpenGL 需要跟平台的視窗系統進行溝通, EGL 因此被設計出來擔任這兩者的橋樑
EGL 提供的 API 主要負責下列幾點功能:

  • 幫 OpenGL 創建 Context (OpenGL 的狀態會儲存在 EGL 管理的 Context 之中)
  • 繪製目標 Surface
  • 配置 FrameBuffer 屬性
  • Swap 提交繪製結果
順帶一提, 雖然我們可以不用去管 OpenGL 實際上做了甚麼.
不過 Android 有為了 Emulator 製作了一份 libagl, 用來 cover 沒有 GPU 的狀況.
可以查看 EGL 的 Loader (frameworks/native/opengl/libs/EGL/Loader.cpp)
我會在後面的文章補充 EGL initial 的流程

這邊先列出整個 EGL 操作的流程:

1.) 獲取 Display: eglGetDisplay
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
獲取顯示器 (FrameBuffer), 參數一般使EGL_DEFAULT_DISPLAY 即可
eglGetDisplay 的 return 是一個 EGLDisplay
 2.) 初始化: eglInitialize
EGLBoolean eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
使用 EGLDisplay 之前, 必須經過初始化.
呼叫 eglInitialize 同時會回傳版本號, 這邊可以帶入 NULL 表示你不在意
 3.) 取得平台設置: EGLConfig
EGLBoolean eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
描述 EGL Surface 所用, 跟平台會有強相關性. (例如只支援 16-bit...etc)
 4.) 取得 Render type: eglGetConfigAttrib
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) 
 5.) 建立 Context: eglCreateContext
EGLContext APIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
這裡的 attrib_list 表示版本號
 6.) 建立 Surface: eglCreateWindowSurface
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindow window, const EGLint *attrib_list)
這個 window 是本地的 window, 會回傳一個 EGLSurface
 7.) 設置 Display 的當前 Surface: eglMakeCurrent
EGLBoolean eglMakeCurrent(
 EGLDisplay dpy,   //dpy: display.
 EGLSurface draw,  //正在繪製的surface, 由eglCreateWindowSurface生成
 EGLSurface read,
 EGLContext ctx )
 8.) 交換當前 Surface: eglSwapBuffers
EGLBoolean eglSwapBuffers(EGLDisplay display, EGLSurface surface);
Process 使用 OpenGL API 繪製完成後, 藉由 eglSwapBuffers 將繪製好的圖形顯示出來
大多時候你的 EGLSurface 會是雙緩衝的,
back-surface 用於儲存 rendor 後的結果,
front-surface 則連結到 NativeWindow, NativeWindow 負責顯示到設備上.
有了這些基本知識, 我們回頭看一下 BootAnimation 做的事情:
status_t BootAnimation::readyToRun() {
    ...
    // initialize opengl and egl
    const EGLint attribs[] = {
            EGL_RED_SIZE,   8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE,  8,
            EGL_DEPTH_SIZE, 0,
            EGL_NONE
    };
    EGLint w, h;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;
        
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(display, 0, 0);
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
    surface = eglCreateWindowSurface(display, config, s.get(), NULL);
    context = eglCreateContext(display, config, NULL, NULL);
    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
        return NO_INIT;
    ...
}

其實就是把 (1) ~ (7) 的事情都做過一次
注意在 eglCreateWindowSurface 裡面我們帶入了 s.get(),
s 是藉由 SurfaceControl 建立的 Surface 對象,
還記得上面它提供了很多 ANativeWindow 的 function pointer 嗎?
就是要提供給 EGL 呼叫所使用的
關於 ANativeWindow 的結構, 可以查看 /system/core/include/system/window.h
struct ANativeWindow
{
    struct android_native_base_t common;
    const uint32_t flags;
    const int   minSwapInterval;
    const float xdpi, ydpi;
    
    int (*queueBuffer)(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer, int fenceFd);
    int (*dequeueBuffer)(struct ANativeWindow* window, struct ANativeWindowBuffer** buffer, int* fenceFd);
    int (*perform)(struct ANativeWindow* window, int operation, ... );
}

由於每一種系統的視窗系統都不同,
EGL 作為跨平台的接口, 自然要處理這個轉換
// frameworks/native/opengl/include/EGL/eglplatform.h
#if defined(_WIN32) || defined(__VC32__) && 
   ...
#elif defined(__WINSCW__) || 
   ...
#elif defined(__ANDROID__) || defined(ANDROID)

struct ANativeWindow;
struct egl_native_pixmap_t;

typedef struct ANativeWindow*           EGLNativeWindowType;
typedef struct egl_native_pixmap_t*     EGLNativePixmapType;
typedef void*                           EGLNativeDisplayType;

#elif defined(__unix__)
   ...
#else
#error "Platform not recognized"
#endif

這裡可以看到 EGLNativeWindowType 實際上被定為了 ANativeWindow

我們試著展開 eglCreateWindowSurface看看:
// frameworks/native/opengl/libs/EGL/eglApi.cpp
EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
                                    NativeWindowType window,
                                    const EGLint *attrib_list)
{
    egl_connection_t* cnx = NULL;
    egl_display_ptr dp = validate_display_connection(dpy, cnx);
    if (dp) {
        EGLDisplay iDpy = dp->disp.dpy;

        int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);

        // 一些 format 的制定, 跳過
        ...

        if (format != 0) {
            int err = native_window_set_buffers_format(window, format);
            if (err != 0) {
                ALOGE("error setting native window pixel format: %s (%d)",
                        strerror(-err), err);
                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
            }
        }

        if (dataSpace != 0) {
            int err = native_window_set_buffers_data_space(window, dataSpace);
            if (err != 0) {
                ALOGE("error setting native window pixel dataSpace: %s (%d)",
                        strerror(-err), err);
                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
            }
        }

        // the EGL spec requires that a new EGLSurface default to swap interval
        // 1, so explicitly set that on the window here.
        ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
        anw->setSwapInterval(anw, 1);

        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
                iDpy, config, window, attrib_list);
        if (surface != EGL_NO_SURFACE) {
            egl_surface_t* s = new egl_surface_t(dp.get(), config, window,
                    surface, cnx);
            return s;
        }

        // EGLSurface creation failed
        native_window_set_buffers_format(window, 0);
        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
    }
    return EGL_NO_SURFACE;
}

呼叫了 native_window_api_connect,
可以在window.h (/system/core/include/system/window.h) 找到
/*
 * native_window_api_connect(..., int api)
 * connects an API to this window. only one API can be connected at a time.
 * Returns -EINVAL if for some reason the window cannot be connected, which
 * can happen if it's connected to some other API.
 */
static inline int native_window_api_connect(
        struct ANativeWindow* window, int api)
{
    return window->perform(window, NATIVE_WINDOW_API_CONNECT, api);
}

呼叫了 window->perform(window, NATIVE_WINDOW_API_CONNECT, api);
從前面我們可以知道現在的 window 就是 s.get(), 也就是 Surface 結構.
接下來把它全部展開:
int Surface::hook_perform(ANativeWindow* window, int operation, ...) {
    va_list args;
    va_start(args, operation);
    Surface* c = getSelf(window);
    return c->perform(operation, args);
}

int Surface::perform(int operation, va_list args)
{
    int res = NO_ERROR;
    switch (operation) {
    ...
    case NATIVE_WINDOW_API_CONNECT:
        res = dispatchConnect(args);
        break;
    ...
    default:
        res = NAME_NOT_FOUND;
        break;
    }
    return res;
}

int Surface::dispatchConnect(va_list args) {
    int api = va_arg(args, int);
    return connect(api);
}

int Surface::connect(int api) {
    static sp<IProducerListener> listener = new DummyProducerListener();
    return connect(api, listener);
}

int Surface::connect(int api, const sp<IProducerListener>& listener) {
    ATRACE_CALL();
    ALOGV("Surface::connect");
    Mutex::Autolock lock(mMutex);
    IGraphicBufferProducer::QueueBufferOutput output;
    int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
    if (err == NO_ERROR) {
        uint32_t numPendingBuffers = 0;
        uint32_t hint = 0;
        output.deflate(&mDefaultWidth, &mDefaultHeight, &hint,
                &numPendingBuffers);

        // Disable transform hint if sticky transform is set.
        if (mStickyTransform == 0) {
            mTransformHint = hint;
        }

        mConsumerRunningBehind = (numPendingBuffers >= 2);
    }
    if (!err && api == NATIVE_WINDOW_API_CPU) {
        mConnectedToCpu = true;
        // Clear the dirty region in case we're switching from a non-CPU API
        mDirtyRegion.clear();
    } else if (!err) {
        // Initialize the dirty region for tracking surface damage
        mDirtyRegion = Region::INVALID_REGION;
    }

    return err;
}

status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
        int api, bool producerControlledByApp, QueueBufferOutput *output) {
    ATRACE_CALL();
    Mutex::Autolock lock(mCore->mMutex);
    mConsumerName = mCore->mConsumerName;

    int status = NO_ERROR;
    switch (api) {
        case NATIVE_WINDOW_API_EGL:
        case NATIVE_WINDOW_API_CPU:
        case NATIVE_WINDOW_API_MEDIA:
        case NATIVE_WINDOW_API_CAMERA:
            mCore->mConnectedApi = api;
            output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
                    mCore->mTransformHint,
                    static_cast<uint32_t>(mCore->mQueue.size()));

            // Set up a death notification so that we can disconnect
            // automatically if the remote producer dies
            if (listener != NULL &&
                    IInterface::asBinder(listener)->remoteBinder() != NULL) {
                status = IInterface::asBinder(listener)->linkToDeath(
                        static_cast<IBinder::DeathRecipient*>(this));
                if (status != NO_ERROR) {
                    BQ_LOGE("connect(P): linkToDeath failed: %s (%d)",
                            strerror(-status), status);
                }
            }
            mCore->mConnectedProducerListener = listener;
            break;
        default:
            BQ_LOGE("connect(P): unknown API %d", api);
            status = BAD_VALUE;
            break;
    }

    mCore->mBufferHasBeenQueued = false;
    mCore->mDequeueBufferCannotBlock =
            mCore->mConsumerControlledByApp && producerControlledByApp;
    mCore->mAllowAllocation = true;

    return status;
}

沒有特別做甚麼事情, 只是將 mCore->mConnectedApi 設置為 api;
下面幾個 native_window_xxx 的 API 的 flow 同樣是走這個 flow.

我們回到 eglCreateWindowSurface, 最下面會去生成 EGLSurface
EGLSurface surface = cnx->egl.eglCreateWindowSurface(
        iDpy, config, window, attrib_list);

這個 cnx 是一個 function pointer, 它會透過 EGL interface 去控制 OpenGL,
根據你的 Loader 所讀取到不同的 dynamic library 而定.
當然, 你可以看看 Google Emulator 的 EGL 實作
(frameworks/native/opengl/libagl/egl.cpp)
static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
        NativeWindowType window, const EGLint* /*attrib_list*/)
{
    ...
    egl_surface_t* surface;
    surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
            static_cast<ANativeWindow*>(window));
    ...
    return surface;
}

這邊生成了一個 egl_window_surface_v2_t 的結構,
並把我們的 Surface 作為 nativeWindow 變數儲存起來

接下來看看

EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
                            EGLSurface read, EGLContext ctx)
{
    ...
    EGLBoolean result = dp->makeCurrent(c, cur_c,
            draw, read, ctx,
            impl_draw, impl_read, impl_ctx);
   ...
}

EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
        EGLSurface draw, EGLSurface read, EGLContext /*ctx*/,
        EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
{
    EGLBoolean result;

    { // scope for the lock
        Mutex::Autolock _l(lock);
        if (c) {
            result = c->cnx->egl.eglMakeCurrent(
                    disp.dpy, impl_draw, impl_read, impl_ctx);
            if (result == EGL_TRUE) {
                c->onMakeCurrent(draw, read);
                if (!cur_c) {
                    mHibernation.incWakeCount(HibernationMachine::STRONG);
                }
            }
        } else {
            result = cur_c->cnx->egl.eglMakeCurrent(
                    disp.dpy, impl_draw, impl_read, impl_ctx);
            if (result == EGL_TRUE) {
                cur_c->onLooseCurrent();
                mHibernation.decWakeCount(HibernationMachine::STRONG);
            }
        }
    }

    return result;
}

EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
                            EGLSurface read, EGLContext ctx)
{
    ...
    ogles_context_t* gl = (ogles_context_t*)ctx;
    if (makeCurrent(gl) == 0) {
        if (ctx) {
            egl_context_t* c = egl_context_t::context(ctx);
            egl_surface_t* d = (egl_surface_t*)draw;
            egl_surface_t* r = (egl_surface_t*)read;

            if (c->draw) {
                egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
                s->disconnect();
                s->ctx = EGL_NO_CONTEXT;
                if (s->zombie)
                    delete s;
            }
            if (c->read) {
                // FIXME: unlock/disconnect the read surface too 
            }

            c->draw = draw;
            c->read = read;

            if (c->flags & egl_context_t::NEVER_CURRENT) {
                c->flags &= ~egl_context_t::NEVER_CURRENT;
                GLint w = 0;
                GLint h = 0;
                if (draw) {
                    w = d->getWidth();
                    h = d->getHeight();
                }
                ogles_surfaceport(gl, 0, 0);
                ogles_viewport(gl, 0, 0, w, h);
                ogles_scissor(gl, 0, 0, w, h);
            }
            if (d) {
                if (d->connect() == EGL_FALSE) {
                    return EGL_FALSE;
                }
                d->ctx = ctx;
                d->bindDrawSurface(gl);
            }
            if (r) {
                // FIXME: lock/connect the read surface too 
                r->ctx = ctx;
                r->bindReadSurface(gl);
            }
        return EGL_TRUE;
    }
    ...
    return setError(EGL_BAD_ACCESS, EGL_FALSE);
}

還有印象 d 就是 egl_window_surface_v2_t 嗎?
我們查看它的 connect function, 又見到了熟悉的好朋友 nativeWindow
(<ゝω・) Surface☆

EGLBoolean egl_window_surface_v2_t::connect()
{
    // we're intending to do software rendering
    native_window_set_usage(nativeWindow,
            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);

    // dequeue a buffer
    int fenceFd = -1;
    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer,
            &fenceFd) != NO_ERROR) {
        return setError(EGL_BAD_ALLOC, EGL_FALSE);
    }

    // wait for the buffer
    sp<Fence> fence(new Fence(fenceFd));
    if (fence->wait(Fence::TIMEOUT_NEVER) != NO_ERROR) {
        nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
        return setError(EGL_BAD_ALLOC, EGL_FALSE);
    }

    // allocate a corresponding depth-buffer
    width = buffer->width;
    height = buffer->height;
    if (depth.format) {
        depth.width   = width;
        depth.height  = height;
        depth.stride  = depth.width; // use the width here
        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
                static_cast<uint64_t>(depth.height) * 2;
        if (depth.stride < 0 || depth.height > INT_MAX ||
                allocSize > UINT32_MAX) {
            return setError(EGL_BAD_ALLOC, EGL_FALSE);
        }
        depth.data    = (GGLubyte*)malloc(allocSize);
        if (depth.data == 0) {
            return setError(EGL_BAD_ALLOC, EGL_FALSE);
        }
    }
    // keep a reference on the buffer
    buffer->common.incRef(&buffer->common);

    // pin the buffer down
    if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
            GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
        ALOGE("connect() failed to lock buffer %p (%ux%u)",
                buffer, buffer->width, buffer->height);
        return setError(EGL_BAD_ACCESS, EGL_FALSE);
        // FIXME: we should make sure we're not accessing the buffer anymore
    }
    return EGL_TRUE;
}

再度展開 Surface::dequeueBuffer

int Surface::hook_dequeueBuffer(ANativeWindow* window,
        ANativeWindowBuffer** buffer, int* fenceFd) {
    Surface* c = getSelf(window);
    return c->dequeueBuffer(buffer, fenceFd);
}

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
    ATRACE_CALL();
    ALOGV("Surface::dequeueBuffer");

    uint32_t reqWidth;
    uint32_t reqHeight;
    bool swapIntervalZero;
    PixelFormat reqFormat;
    uint32_t reqUsage;

    {
        Mutex::Autolock lock(mMutex);

        reqWidth = mReqWidth ? mReqWidth : mUserWidth;
        reqHeight = mReqHeight ? mReqHeight : mUserHeight;

        swapIntervalZero = mSwapIntervalZero;
        reqFormat = mReqFormat;
        reqUsage = mReqUsage;
    } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffer

    int buf = -1;
    sp<Fence> fence;
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,
            reqWidth, reqHeight, reqFormat, reqUsage);

    if (result < 0) {
        ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)"
             "failed: %d", swapIntervalZero, reqWidth, reqHeight, reqFormat,
             reqUsage, result);
        return result;
    }

    Mutex::Autolock lock(mMutex);
    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);

    // this should never happen
    ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);

    if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
        freeAllBuffers();
    }

    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
        if (result != NO_ERROR) {
            ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
            mGraphicBufferProducer->cancelBuffer(buf, fence);
            return result;
        }
    }

    if (fence->isValid()) {
        *fenceFd = fence->dup();
        if (*fenceFd == -1) {
            ALOGE("dequeueBuffer: error duping fence: %d", errno);
            // dup() should never fail; something is badly wrong. Soldier on
            // and hope for the best; the worst that should happen is some
            // visible corruption that lasts until the next frame.
        }
    } else {
        *fenceFd = -1;
    }

    *buffer = gbuf.get();
    return OK;
}

* mGraphicBufferProducer 就是 BufferQueueProducer

整個調用流程如下
eglMakeCurrent (EGL API)
  -> makeCurrent (egl_display)
    -> eglMakeCurrent (OEM EGL library)
      -> connect (EGL Surface)
        -> hook_dequeueBuffer (native_window = Surface)
          -> dequeueBuffer (Surface)
            -> dequeueBuffer (MonitoredProducer)
              -> dequeueBuffer (BufferQueueProducer)

這整個流程是 BufferQueueProducer 要開始運作的前哨站,
dequeueBuffer 函數將會承接到前面提過的 BufferQueue 裡面的各種 Slots

就從下一篇再開始描述吧 ⧸⎩⎠⎞͏(・∀・)⎛͏⎝⎭⧹

沒有留言:

張貼留言

不定參數印 log

From the UNIXProcess_md.c #ifdef DEBUG_PROCESS   /* Debugging process code is difficult; where to write debug output? */ static void deb...