该系列文章总纲链接:Android GUI系统之SurfaceFlinger 系列文章目录
本章节思维导图如上。主要讲述了DisplayDevice的概念,这里 主要DisplayDevice的创建流程和 两个关键方法makeCurrent 和swapBuffer。
在之前的分析中,我们知道 每个应用端对应一个SurfaceControl,每个SurfaceControl都对应多个Surface,即 应用端使用Surface来管理Buffer。实际上在SurfaceFlinger中 DisplayDevice也是通过Surface来管理Buffer。这里简单说明下两者的异同:
了解了这些后,我们开始从DisplayDevice创建流程开始分析。
1 DisplayDevice创建流程开始分析
DisplayDevice是在SurfaceFlinger的init中创建的,代码实现如下:
void SurfaceFlinger::init() {
//...
// initialize our non-virtual displays
for (size_t i=0 ; iisConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
// All non-virtual displays are currently considered secure.
bool isSecure = true;
createBuiltinDisplayLocked(type);
wp token = mBuiltinDisplays[i];
//BufferQueue相关
sp producer;
sp consumer;
BufferQueue::createBufferQueue(&producer, &consumer,
new GraphicBufferAlloc());
//关键点1:FramebufferSurface创建,定位为 消费者身份
sp fbs = new FramebufferSurface(*mHwc, i,
consumer);
int32_t hwcId = allocateHwcDisplayId(type);
//关键点2:DisplayDevice创建,定位为 生产者身份
sp hw = new DisplayDevice(this,
type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
fbs, producer,
mRenderEngine->getEGLConfig());
if (i > DisplayDevice::DISPLAY_PRIMARY) {
hw->setPowerMode(HWC_POWER_MODE_NORMAL);
}
mDisplays.add(token, hw);
}
}
//...
// start boot animation
startBootAnim();
}
1.1 FramebufferSurface创建流程分析
FramebufferSurface构造函数实现如下:
FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp,
const sp& consumer) :
ConsumerBase(consumer),
mDisplayType(disp),
mCurrentBufferSlot(-1),
mCurrentBuffer(0),
mHwc(hwc)
{
mName = "FramebufferSurface";
mConsumer->setConsumerName(mName);
/*这里设置了标志位GRALLOC_USAGE_HW_FB,借此参数分辨
向Ashmem申请->APP;向Framebuffer申请->DisplayDevice
*/
mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER);
mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
}
专注分析setConsumerUsageBits,属于BufferQueueConsumer类型,因此代码实现如下:
status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) {
ATRACE_CALL();
BQ_LOGV("setConsumerUsageBits: %#x", usage);
Mutex::Autolock lock(mCore->mMutex);
mCore->mConsumerUsageBits = usage;
return NO_ERROR;
}
这里将 参数usgae 传递给 mCore->mConsumerUsageBits。
1.2 DisplayDevice构造函数分析
DisplayDevice的构造函数实现如下:
DisplayDevice::DisplayDevice(
const sp& flinger,
DisplayType type,
//...各种初始化
{
//创建surface对象
mNativeWindow = new Surface(producer, false);
ANativeWindow* const window = mNativeWindow.get();
//创建OpenGLES 使用的surface对象
EGLSurface surface;
EGLint w, h;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (config == EGL_NO_CONFIG) {
config = RenderEngine::chooseEglConfig(display, format);
}
surface = eglCreateWindowSurface(display, config, window, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth);
eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);
if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
window->setSwapInterval(window, 0);//虚拟设备不支持 图像合成
mConfig = config;
mDisplay = display;
mSurface = surface;
mFormat = format;
mPageFlipCount = 0;
mViewport.makeInvalid();
mFrame.makeInvalid();
//虚拟设备的屏幕 默认不关闭
mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ?
HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
// Name the display. The name will be replaced shortly if the display
// was created with createDisplay().
switch (mType) {
case DISPLAY_PRIMARY:
mDisplayName = "Built-in Screen";
break;
case DISPLAY_EXTERNAL:
mDisplayName = "HDMI Screen";
break;
default:
mDisplayName = "Virtual Screen"; // e.g. Overlay #n
break;
}
// initialize the display orientation transform.
setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
}
该构造函数主要是 创建了Surface,也就是一个NativeWindow。
1.2.1 surface构造函数分析
这里看下 surface的构造函数,代码如下:
Surface::Surface(
const sp& bufferProducer,
bool controlledByApp)
: mGraphicBufferProducer(bufferProducer)
{
// 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;
//...
}
这里对其中的一个hook_queueBuffer进行分析,代码如下:
int Surface::hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer, int fenceFd) {
Surface* c = getSelf(window);
return c->queueBuffer(buffer, fenceFd);
}
最后是调用回了Surface的queueBuffer方法,其他几个hook方法也是类似的。即NativeWindow 和Surface访问的方法是一样的。
同时通过上面的分析得出Buffer的流程:Surface->BufferQueue->FramebufferSurface->HWComposer->Gralloc->显示设备Framebuffer
1.2.2 eglCreateWindowSurface分析
eglCreateWindowSurface的代码实现如下:
EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
NativeWindowType window,
const EGLint *attrib_list)
{
return createWindowSurface(dpy, config, window, attrib_list);
}
继续分析createWindowSurface,代码实现如下:
static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
NativeWindowType window, const EGLint* /*attrib_list*/)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
if (window == 0)
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
EGLint surfaceType;
if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
return EGL_FALSE;
if (!(surfaceType & EGL_WINDOW_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
if (static_cast(window)->common.magic !=
ANDROID_NATIVE_WINDOW_MAGIC) {
return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
}
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
int32_t depthFormat;
int32_t pixelFormat;
if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
}
egl_surface_t* surface;
//创建egl_window_surface_v2_t对象
surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
static_cast(window));
if (!surface->initCheck()) {
delete surface;
surface = 0;
}
return surface;
}
这里专注分析egl_window_surface_v2_t,构造函数代码实现如下:
egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
EGLConfig config,
int32_t depthFormat,
ANativeWindow* window)
: egl_surface_t(dpy, config, depthFormat),
nativeWindow(window), buffer(0), previousBuffer(0), module(0),
bits(NULL)
{
hw_module_t const* pModule;
hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
module = reinterpret_cast(pModule);
pixelFormatTable = gglGetPixelFormatTable();
// keep a reference on the window
nativeWindow->common.incRef(&nativeWindow->common);
nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
}
这里主要是一些初始化操作,从nativeWindow看出跟surface有关,从GRALLOC_HARDWARE_MODULE_ID来看也和 gralloc模块有关。会涉及 BufferQueue的一些操作。
2 DisplayDevice的两个关键方法
之所以分析这两个关键方法是因为 后面的章节 服务端分析4-handleMessageRefresh处理中 会有所涉及。
2.1 DisplayDevice的makeCurrent方法分析
makeCurrent代码实现如下:
EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const {
EGLBoolean result = EGL_TRUE;
EGLSurface sur = eglGetCurrentSurface(EGL_DRAW);
if (sur != mSurface) {
result = eglMakeCurrent(dpy, mSurface, mSurface, ctx);
//...
}
setViewportAndProjection();
return result;
}
这里关注eglMakeCurrent的实现,代码如下:
EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
EGLSurface read, EGLContext ctx)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (draw) {
egl_surface_t* s = (egl_surface_t*)draw;// 1
//...
}
//...
ogles_context_t* gl = (ogles_context_t*)ctx;
if (makeCurrent(gl) == 0) {
if (ctx) {
//...
if (d) {
if (d->connect() == EGL_FALSE) {
return EGL_FALSE;
}
d->ctx = ctx;
d->bindDrawSurface(gl);
}
//...
} else {
//...
}
return EGL_TRUE;
}
return setError(EGL_BAD_ACCESS, EGL_FALSE);
}
这里主要关注一个connect方法,这个所谓的d类型是 egl_window_surface_v2_t,是egl_surface_t的子类,对应的connect代码实现如下:
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(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
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
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;
}
这里会发现,调用了nativeWindow的dequeueBuffer操作,在之前的分析中我们知道这个dequeuBuffer实际上是Surface的dequeuBuffer方法(通过hook方式)。最后会进入到 BufferQueueproducer相关的操作。
2.2 DisplayDevice的swapbuffer方法分析
swapbuffer代码实现如下:
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
if (hwc.initCheck() != NO_ERROR ||
(hwc.hasGlesComposition(mHwcDisplayId) &&
(hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) {
EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
//...错误处理
}
status_t result = mDisplaySurface->advanceFrame();
//...错误处理
}
这里专注分析eglSwapBuffers,代码实现如下:
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
egl_surface_t* d = static_cast(draw);
if (!d->isValid())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (d->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
// post the surface
d->swapBuffers();
// if it's bound to a context, update the buffer
if (d->ctx != EGL_NO_CONTEXT) {
d->bindDrawSurface((ogles_context_t*)d->ctx);
egl_context_t* c = egl_context_t::context(d->ctx);
if (c->read == draw) {
d->bindReadSurface((ogles_context_t*)d->ctx);
}
}
return EGL_TRUE;
}
这里专注分析d->swapBuffers(),而这个d类型是 egl_window_surface_v2_t,是egl_surface_t的子类,对应的swapBuffers代码实现如下:
EGLBoolean egl_window_surface_v2_t::swapBuffers()
{
if (!buffer) {
return setError(EGL_BAD_ACCESS, EGL_FALSE);
}
if (!dirtyRegion.isEmpty()) {
dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
if (previousBuffer) {
// This was const Region copyBack, but that causes an
// internal compile error on simulator builds
/*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
if (!copyBack.isEmpty()) {
void* prevBits;
if (lock(previousBuffer,
GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
// copy from previousBuffer to buffer
copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
unlock(previousBuffer);
}
}
}
oldDirtyRegion = dirtyRegion;
}
if (previousBuffer) {
previousBuffer->common.decRef(&previousBuffer->common);
previousBuffer = 0;
}
unlock(buffer);
previousBuffer = buffer;
nativeWindow->queueBuffer(nativeWindow, buffer, -1);
buffer = 0;
// dequeue a new buffer
int fenceFd = -1;
if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) == NO_ERROR) {
sp fence(new Fence(fenceFd));
if (fence->wait(Fence::TIMEOUT_NEVER)) {
nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
return setError(EGL_BAD_ALLOC, EGL_FALSE);
}
// reallocate the depth-buffer if needed
if ((width != buffer->width) || (height != buffer->height)) {
// TODO: we probably should reset the swap rect here
// if the window size has changed
width = buffer->width;
height = buffer->height;
if (depth.data) {
free(depth.data);
depth.width = width;
depth.height = height;
depth.stride = buffer->stride;
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
setError(EGL_BAD_ALLOC, EGL_FALSE);
return EGL_FALSE;
}
}
}
// keep a reference on the buffer
buffer->common.incRef(&buffer->common);
// finally pin the buffer down
if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
ALOGE("eglSwapBuffers() 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
}
} else {
return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
}
return EGL_TRUE;
}
接下来主要对旧Buffer 和新Buffer 进行分析:
2.2.1 旧Buffer操作
这里对于旧Buffer,调用了nativeWindow的queueBuffer操作,在之前的分析中我们知道这个queuBuffer实际上是Surface的queueBuffer方法(通过hook方式),最后会进入到 BufferQueueProducer相关的操作。在执行了queueBuffer操作后,通过BufferQueue的接口最后会调用一个 onFrameAvailable的回调函数,代码如下:
void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
sp buf;
sp acquireFence;
status_t err = nextBuffer(buf, acquireFence);
//...错误处理
err = mHwc.fbPost(mDisplayType, acquireFence, buf);
//...错误处理
}
这里关注 nextBuffer 和后面fbPost方法。
@1 nextBuffer代码实现如下:
status_t FramebufferSurface::nextBuffer(sp& outBuffer, sp& outFence) {
Mutex::Autolock lock(mMutex);
BufferQueue::BufferItem item;
status_t err = acquireBufferLocked(&item, 0);
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
outBuffer = mCurrentBuffer;
return NO_ERROR;
}
//...
if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
item.mBuf != mCurrentBufferSlot) {
// Release the previous buffer.
err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
if (err < NO_ERROR) {
ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
return err;
}
}
mCurrentBufferSlot = item.mBuf;
mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
outFence = item.mFence;
outBuffer = mCurrentBuffer;
return NO_ERROR;
}
这里最主要的是 执行了Acquire操作,取出Buffer
@2 fbPost代码实现如下:
int HWComposer::fbPost(int32_t id,
const sp& acquireFence, const sp& buffer) {
if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
return setFramebufferTarget(id, acquireFence, buffer);
} else {
acquireFence->waitForever("HWComposer::fbPost");
return mFbDev->post(mFbDev, buffer->handle);
}
}
这里调用了mFbDev->post,和这个设备就是FrameBuffer的HAL层接口post方法(注册时被赋值为fb_post),因此最后会调用到FrameBuffer HAL层的方法fb_post,代码如下:
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
if (private_handle_t::validate(buffer) < 0)
return -EINVAL;
fb_context_t* ctx = (fb_context_t*)dev;
private_handle_t const* hnd = reinterpret_cast(buffer);
private_module_t* m = reinterpret_cast(
dev->common.module);
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
const size_t offset = hnd->base - m->framebuffer->base;
m->info.activate = FB_ACTIVATE_VBL;
m->info.yoffset = offset / m->finfo.line_length;
if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
ALOGE("FBIOPUT_VSCREENINFO failed");
m->base.unlock(&m->base, buffer);
return -errno;
}
m->currentBuffer = buffer;
} else {
// If we can't do the page_flip, just copy the buffer to the front
// FIXME: use copybit HAL instead of memcpy
void* fb_vaddr;
void* buffer_vaddr;
m->base.lock(&m->base, m->framebuffer,
GRALLOC_USAGE_SW_WRITE_RARELY,
0, 0, m->info.xres, m->info.yres,
&fb_vaddr);
m->base.lock(&m->base, buffer,
GRALLOC_USAGE_SW_READ_RARELY,
0, 0, m->info.xres, m->info.yres,
&buffer_vaddr);
memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
m->base.unlock(&m->base, buffer);
m->base.unlock(&m->base, m->framebuffer);
}
return 0;
}
这里最主要的是 消费Buffer,执行Post操作将Buffer推给Framebuffer来显示了。
2.2.2 新Buffer操作
对于新Buffer,又重现调用了dequeueBuffer的操作,进入下一次的 处理。
2.3 两个关键方法的总结