前情提要
上一篇文章我們分析了 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
就從下一篇再開始描述吧 ⧸⎩⎠⎞͏(・∀・)⎛͏⎝⎭⧹