已知Surface对应着SurfaceFlinger管理的一个Layer,而LayerBuffer在C++和java空间中分别对应着ISurfaceComposer.h中的ePushBuffers与Surface.java中的PUSH_BUFFERS类型的Surface。创建LayerBuffer时,会先看是否支持硬件copybit加速:
int err = module->perform(module, GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER, buffers.heap->heapID(), bufferSize, offset, buffers.heap->base(), &src.img.handle);
// we can fail here is the passed buffer is purely software
mSupportsCopybit = (err == NO_ERROR);
当开始把视频帧渲染到SurfaceFlinger时需要resize到mTexture上面。系统如果支持硬件copybit加速,在对视频帧做resize的时候就使用硬件copybit:
/frameworks/base/services/surfaceflinger/LayerBuffer.cpp
if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
copybit_open(module, &mLayer.mBlitEngine);
}
copybit_device_t* copybit = mLayer.mBlitEngine;
... ...
err = initTempBuffer();
const NativeBuffer& dst(mTempBuffer);
region_iterator clip(Region(Rect(dst.crop.r, dst.crop.b)));
copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
err = copybit->stretch(copybit, &dst.img, &src.img, &dst.crop, &src.crop, &clip);
否则,就使用mTextureManager.loadTexture(&mTexture, dirty, t)通过glTexSubImage2D或glTexImage2D操作把数据渲染到mTexture贴图上面去的。也就是由OpenGL来做resize。
/frameworks/base/services/surfaceflinger/LayerBuffer.cpp
GGLSurface t;
t.version = sizeof(GGLSurface);
t.width = src.crop.r;
t.height = src.crop.b;
t.stride = src.img.w;
t.vstride = src.img.h;
t.format = src.img.format;
t.data = (GGLubyte*) src.img.base;
const Region dirty(Rect(t.width, t.height));
mTextureManager.loadTexture(&mTexture, dirty, t);
resize操作完成以后,mTexture会被绘制到SurfaceFlinger的共享显存上面,SurfaceFlinger把各个Layer的mTexture进行Compose,然后交给GPU或FrameBuffer。后面的这几步操作是各个Layer都要经历的。
有一个地方还需要注意一下,上面有这么一句:we can fail here is the passed buffer is purely software。
需要看一下/frameworks/base/media/libstagefright/colorconversion/SoftwareRenderer.cpp中的代码段:
mMemoryHeap = new MemoryHeapBase("/dev/pmem_adsp", 2 * mFrameSize);
if (mMemoryHeap->heapID() < 0) {
LOGI("Creating physical memory heap failed, reverting to regular heap.");
mMemoryHeap = new MemoryHeapBase(2 * mFrameSize);
} else {
sp<MemoryHeapPmem> pmemHeap = new MemoryHeapPmem(mMemoryHeap);
pmemHeap->slap();
mMemoryHeap = pmemHeap;
}
可以看到,系统会先尝试使用pmem分配,失败的话,就会在regular heap(常规内存)中分配。如果存放视频帧原始数据(已经在被ColorConversion由decode过的YUV数据转化成RGB55)的内存是在regular heap中分配的话,在LayerBuffer中进行resize时是不会进行硬件copybit加速的。
综上,如果要实现resize的硬件加速的话,需要做这么几点:
1、保证内存由pmem分配。
2、实现gralloc的perform操作。可以参照msm7k的gralloc实现。
3、硬件copybit加速除了GPU和FB以外再增加对PMEM内存的支持。
通过1和2让系统知道可以使用硬件加速,3是硬件加速的具体实现。
补充于2011.8.5
关于pmem
要使用pmem的话,先确定有驱动支持,然后把SoftwareRenderer.cpp中mMemoryHeap = new MemoryHeapBase("/dev/pmem_adsp", 2 * mFrameSize)里面的pmem_adsp改成pmem就行了。进行mmap时,驱动就会主动分配内存。实现pmem分配内存后,还要实现gralloc的perform函数,为pmem添加native_handle_t信息。更详细的,参考下面几篇文章。
Android PMEM驱动研究(2)——在应用程序中使用PMEM
http://hi.baidu.com/aokikyon/blog/item/a1f060fb6bbed51a6d22eb94.html
普通应用使用Surface的方法
http://blog.csdn.net/eustoma/article/details/6554108
android pmem 和ashmem 介绍及实例分析
http://www.ophonesdn.com.cn/forum/viewthread.jsp?action=printable&tid=6260
Android平台上PMEM的使用及Platform设备注册(一)
http://blog.csdn.net/wxzking/article/details/6420070