“Layer”模式是常見的一種Layer,在創(chuàng)建Surface時,會為每個Surface分配兩個緩沖:前端緩沖(Front Buffer)和后端緩沖(Back Buffer)。不論前端緩沖還是后端緩沖,其本質(zhì)上均為GraphicBuffer對象。根據(jù)渲染方式的不同,GraphicBuffer的用法可以分為多種,在“Layer”模式的Layer中,系統(tǒng)會根據(jù)緩沖的使用情況設置渲染方式是軟件渲染、硬件渲染、硬件組合等。
前端緩沖和后端緩沖是根據(jù)緩沖所處的位置來區(qū)別的,當緩沖在后端時,系統(tǒng)在該緩沖上進行渲染,當完成渲染后,該緩沖轉(zhuǎn)變?yōu)榍岸司彌_和其他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)); //獲取渲染區(qū)域
mPostedDirtyRegion=dirty.intersect( newFrontBuffer->getBounds() ); //獲取重疊區(qū)域
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;
//重新計算可視區(qū)域
recomputeVisibleRegions=true;
}
mFreezeLock.clear();
}
if (lcblk->getQueuedCount()) { //計算前端緩沖的數(shù)量
// signal an event if we have more buffers waiting
mFlinger->signalEvent();
}
if (!mPostedDirtyRegion.isEmpty()) { //如果有重疊區(qū)域,為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();
}
}
當后端緩沖切換為前端緩沖時,系統(tǒng)需要判斷該緩沖要顯示的區(qū)域是否和其他Surface的Layer有重疊,如果發(fā)生重疊,就計算出重疊的區(qū)域,然后對重疊的區(qū)域進行Layer紋理重載。Layer重載紋理的過程如下:
代碼:Layer重載紋理的過程
void Layer::reloadTexture(const Region& dirty)
{
Mutex::Autolock _l(mLock);
spbuffer(getFrontBufferLocked());
if (buffer==NULL) {
return;
}
const int index=mFrontBufferIndex;
//如果需要,創(chuàng)建新的紋理名
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();
}
}
}