“Layer”模式是常见的一种Layer,在创建Surface时,会为每个Surface分配两个缓冲:前端缓冲(Front Buffer)和后端缓冲(Back Buffer)。不论前端缓冲还是后端缓冲,其本质上均为GraphicBuffer对象。根据渲染方式的不同,GraphicBuffer的用法可以分为多种,在“Layer”模式的Layer中,系统会根据缓冲的使用情况设置渲染方式是软件渲染、硬件渲染、硬件组合等。
前端缓冲和后端缓冲是根据缓冲所处的位置来区别的,当缓冲在后端时,系统在该缓冲上进行渲染,当完成渲染后,该缓冲转变为前端缓冲和其他Surface中的Layer重载纹理并显示在屏幕上。
后端缓冲切换为前段缓冲并向屏幕上渲染的过程如下:
代码:后端缓冲切换为前端缓冲并渲染的过程
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
ssize_t buf=lcblk->retireAndLock(); //利用共享缓冲服务对缓冲加锁
if (buf < NO_ERROR) {
return;
}
mFrontBufferIndex=buf; //缓冲由后端缓冲切换为前端缓冲
sp< GraphicBuffer> newFrontBuffer(getBuffer(buf));
const Region dirty(lcblk->getDirtyRegion(buf)); //获取渲染区域
mPostedDirtyRegion=dirty.intersect( newFrontBuffer->getBounds() ); //获取重叠区域
const Layer::State& front(drawingState());
if (newFrontBuffer->getWidth()==front.requested_w &&
newFrontBuffer->getHeight()==front.requested_h)
{
if ((front.w !=front.requested_w) ||
(front.h !=front.requested_h))
{
Layer::State& editDraw(mDrawingState);
editDraw.w=editDraw.requested_w;
editDraw.h=editDraw.requested_h;
Layer::State& editTemp(currentState());
editTemp.w=editDraw.w;
editTemp.h=editDraw.h;
//重新计算可视区域
recomputeVisibleRegions=true;
}
mFreezeLock.clear();
}
if (lcblk->getQueuedCount()) { //计算前端缓冲的数量
// signal an event if we have more buffers waiting
mFlinger->signalEvent();
}
if (!mPostedDirtyRegion.isEmpty()) { //如果有重叠区域,为Layer重载纹理
reloadTexture( mPostedDirtyRegion );
}
}
void Layer::unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion)
{
Region dirtyRegion(mPostedDirtyRegion);
if (!dirtyRegion.isEmpty()) {
mPostedDirtyRegion.clear();
const Layer::State& s(drawingState());
const Transform tr(planeTransform * s.transform);
dirtyRegion=tr.transform(dirtyRegion);
dirtyRegion.andSelf(visibleRegionScreen);
outDirtyRegion.orSelf(dirtyRegion);
}
if (visibleRegionScreen.isEmpty()) {
mFreezeLock.clear();
}
}
当后端缓冲切换为前端缓冲时,系统需要判断该缓冲要显示的区域是否和其他Surface的Layer有重叠,如果发生重叠,就计算出重叠的区域,然后对重叠的区域进行Layer纹理重载。Layer重载纹理的过程如下:
代码:Layer重载纹理的过程
void Layer::reloadTexture(const Region& dirty)
{
Mutex::Autolock _l(mLock);
spbuffer(getFrontBufferLocked());
if (buffer==NULL) {
return;
}
const int index=mFrontBufferIndex;
//如果需要,创建新的纹理名
if (UNLIKELY(mTextures[index].name==-1U)) {
mTextures[index].name=createTexture();
mTextures[index].width=0;
mTextures[index].height=0;
}
#ifdef EGL_ANDROID_image_native_buffer
if (mFlags & DisplayHardware::DIRECT_TEXTURE) { //直接渲染
if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) {//判断是否硬件组合
if (mTextures[index].dirty) {
initializeEglImage(buffer, &mTextures[index]); //组合为EglImage
}
} else { //通过mHybridBuffer去渲染
if (mHybridBuffer==0 || (mHybridBuffer->width !=buffer->width ||
mHybridBuffer->height !=buffer->height)) {
mHybridBuffer.clear();
mHybridBuffer=new GraphicBuffer(
buffer->width, buffer->height, buffer->format,
GraphicBuffer::USAGE_SW_WRITE_OFTEN |
GraphicBuffer::USAGE_HW_TEXTURE);
initializeEglImage(mHybridBuffer, &mTextures[0]);
}
GGLSurface t;
status_t res=buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
LOGE_IF(res, "error %d (%s) locking buffer %p",
res, strerror(res), buffer.get());
if (res==NO_ERROR) {
Texture* const texture(&mTextures[0]);
glBindTexture(GL_TEXTURE_2D, texture->name);
sp< GraphicBuffer> buf(mHybridBuffer);
void* vaddr;
res=buf->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &vaddr);
if (res==NO_ERROR) {
int bpp=0;
switch (t.format) {
case GGL_PIXEL_FORMAT_RGB_565:
case GGL_PIXEL_FORMAT_RGBA_4444:
bpp=2;
break;
case GGL_PIXEL_FORMAT_RGBA_8888:
case GGL_PIXEL_FORMAT_RGBX_8888:
bpp=4;
break;
case GGL_PIXEL_FORMAT_YCbCr_422_SP:
case GGL_PIXEL_FORMAT_YCbCr_420_SP:
bpp=1;
break;
default:
LOGE("layer %p, texture=%d, using format %d, which is not ""supported by the GL", this, texture->name, t.format);
}
if (bpp) {
const Rect bounds(dirty.getBounds());
size_t src_stride=t.stride;
size_t dst_stride=buf->stride;
if (src_stride==dst_stride &&
bounds.width()==t.width &&
bounds.height()==t.height)
{
memcpy(vaddr, t.data, t.height * t.stride * bpp);
} else {
GLubyte const * src=t.data+(bounds.left+bounds.top * src_stride) * bpp;
GLubyte * dst=(GLubyte *)vaddr+(bounds.left+bounds.top * dst_stride) * bpp;
const size_t length=bounds.width() * bpp;
size_t h=bounds.height();
src_stride *=bpp;
dst_stride *=bpp;
while (h--) {
memcpy(dst, src, length);
dst +=dst_stride;
src +=src_stride;
}
}
}
buf->unlock();
}
buffer->unlock();
}
}
} else
#endif
{
for (size_t i=0 ; i< NUM_BUFFERS ; i++) {
mTextures[i].image=EGL_NO_IMAGE_KHR;
}
GGLSurface t;
status_t res=buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
LOGE_IF(res, "error %d (%s) locking buffer %p",res, strerror(res), buffer.get());
if (res==NO_ERROR) {
loadTexture(&mTextures[0], dirty, t); //加载纹理
buffer->unlock();
}
}
}