前情提要
上一篇文章我們分析了 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() 的第五行
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
1.) 獲取 Display: eglGetDisplay
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)2.) 初始化: eglInitialize
獲取顯示器 (FrameBuffer), 參數一般使EGL_DEFAULT_DISPLAY 即可
eglGetDisplay 的 return 是一個 EGLDisplay
EGLBoolean eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);3.) 取得平台設置: EGLConfig
使用 EGLDisplay 之前, 必須經過初始化.
呼叫 eglInitialize 同時會回傳版本號, 這邊可以帶入 NULL 表示你不在意
EGLBoolean eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);4.) 取得 Render type: eglGetConfigAttrib
描述 EGL Surface 所用, 跟平台會有強相關性. (例如只支援 16-bit...etc)
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)6.) 建立 Surface: eglCreateWindowSurface
這裡的 attrib_list 表示版本號
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindow window, const EGLint *attrib_list)7.) 設置 Display 的當前 Surface: eglMakeCurrent
這個 window 是本地的 window, 會回傳一個 EGLSurface
EGLBoolean eglMakeCurrent(8.) 交換當前 Surface: eglSwapBuffers
EGLDisplay dpy, //dpy: display.
EGLSurface draw, //正在繪製的surface, 由eglCreateWindowSurface生成
EGLSurface read,
EGLContext ctx )
EGLBoolean eglSwapBuffers(EGLDisplay display, EGLSurface surface);有了這些基本知識, 我們回頭看一下 BootAnimation 做的事情:
Process 使用 OpenGL API 繪製完成後, 藉由 eglSwapBuffers 將繪製好的圖形顯示出來
大多時候你的 EGLSurface 會是雙緩衝的,
back-surface 用於儲存 rendor 後的結果,
front-surface 則連結到 NativeWindow, NativeWindow 負責顯示到設備上.
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
就從下一篇再開始描述吧 ⧸⎩⎠⎞͏(・∀・)⎛͏⎝⎭⧹
沒有留言:
張貼留言