已知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:
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。
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都要经历的。
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加速的。
通过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