深入剖析android新特性 笔记
9.2 图形系统组件
图形系统的实现涉及比较多的模块,代码在:
frameworks/base/core/jni/
frameworks/native/libs/ui/
frameworks/native/libs/gui/
frameworks/native/service/.surfaceflinger/.
hardware/libhardware/
9.2.1 Acitivt与Surface
Android系统的四大组件中,只有Activity包含界面
接下来以Activity为起点,来了解它与整个图形系统的关系
在Android系统中,每个Activity包含一个描述窗口的Window对象,
Window对象的根元素是一个名称为DocorView的试图。
DocorView包含了一个类型为ViewRootImpl的元素,如这个元素名称所示,它是所有视图的根元素,
为了能在显示屏显示,ViewRootImpl会包含一个Surface对象,而Surface正是图形系统的重要组件。
这几个类的关系:
Activity
| getWindow()
Window
| getDecorView()
DecorView
| getViewRootImpl()
ViewRootImpl
| mSurface
Surface
上面提到的结构都是java层的类,
而在surface的实现中会通过JNI调用native层的代码,关系:
ViewRootImpl.java => Surface.java => android_view_Surface.cpp => Surface.cpp
Surface很多逻辑都是在C++层实现的,
所以Surface.java里面包含了一系列native方法,
下面这个方法最重要,负责Surface分配缓冲:
private static native void nativeAllocateBuffers(long nativeObject);
这个native方法对应的JNI方法位于android_view_Surface.cpp,代码:
static void nativeAllocateBuffers(JNIEnv* /* env */, jclass /*clazz */, jlong nativeObject)
{
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
if(!isSurfaceValid(surface)){ return; }
surface->allocateBuffers();
}
很显然,这里真正的实现在C++层的Surface::allocateBuffers方法中,代码:
/Surface.cpp
void Surface::allocateBuffers()
{
mGraphicBufferProducer->allocateBuffers(reqWidth, reqHeight, mReqForemat, mReqUsage);
}
这里通过缓冲区的生产者进行buffer的分配,
目前感觉不好理解正常,这一节会详细讲解最重要的部件
9.2.2 Gralloc
Gralloc,graphics memory allocator是最底层的组件,如其名字,负责图形内存的分配,
AOSP中,系统为Gralloc模块拟定了接口,在
hardware/libhardware/include/hardware/gralloc.h
Gralloc模块是与硬件紧密相关的,因此,它的实现不是AOSP的一部分,而是硬件设备厂商完成的,
厂商实现一个动态链接库so,在运行时被加载和使用,系统仅仅定义了头文件,
gralloc.h包含了gralloc_module_t和alloca_device_t两个结构体,定义:
typedef struct grallolc_module_t {
struct hw_module_t common;
int (*registerBuffer)(struct gralloc_module_t const* module, buffer_hdnle_t handle);
int (lock)(struct gralloc_module_t const* module, buffer_handle_t handle, int usage, int l/t/w/h, void** vaddr);
int (*perform);
int (*lockAsync);
.....
}gralloc_module_t;
typedef struct alloc_device_t {
struct hw_device_t common;
int (*alloc)(struct alloc_device_t *dev, int w/h/format/usage, buffer_hanlde_t* handle, int* stride);
int (*free);
int (*dump);
}alloc_device_t;
API说明:
alloc_deivce_t alloc,分配一个图形缓冲,通过buffer_handle_t返回
alloc_device_t free
alloc_device_t dump
gralloc_module_t registerBuffer,从alloc_device_t::alloc返回的buffer_handle_t必须经过这个调用才可以使用,
gralloc_module_t lock,特定使用场景前调用,标识调用者只会修改指定区域内的内容
gralloc_module_t perform,保留接口,以后扩展使用
gralloc_module_t lock_ycbcr,类似lock,但它使用缓冲布局的描述填充ycbcr,
gralloc_module_t lockAsync,类似lock,但是异步的,缓冲的同步栅栏对象被传递到锁里面,而不是让调用者等待。
gralloc_module_t unlockAsync,返回缓冲区同步栅栏对象
注意,由于图形缓冲区通常是很大的数据,如果在进程间传递,性能会很差。
所以这里的操作都是通过buffer_handle_t来对图形缓冲进程标识,这是一个轻量的文件描述符结构的句柄,这个句柄可以轻松的在进程间传递。
9.2.3,bufferQueue
BufferQueues是android图形组件的粘合剂,
它是将缓冲池与队列相结合的数据结构,使用BinderIPC在生产者和消费者进程之间传递缓冲区。
在实现中:
缓冲区通过GraphicsBuffer描述,
BufferQueues的生产者使用IGraphicBufferProducer描述,
BufferQueues的生产者使用IgraphicsBufferConsumer描述,
图像生产者的一些例子是由相机HAL或者OGLES游戏制作的相机预览,但最常见的生产者是activity,
图像消费者的一些示例是SurfaceFlinger,或者另一个显示OGLES流的AP,如显示相机取景器的相机AP。
一旦Acitivty生产者提交了buffer,SF消费者就将其合成并且显示在显示器上:
queue acquire
PRODUCER BUFFER QUEUE CONSUMER
dequeue release
BufferQueue可以在三种模块运行:
同步模式,
默认BufferQueue以同步模式运行,从生产者产生的每个缓冲区都通过消费者消费掉,
此模式下不会丢弃任何缓冲区。
如果生产者太快,请创建缓冲区比他们消耗的速度快,它将阻塞并且等待可用的缓冲区。
非阻塞模式,
BufferQueue也可以在非阻塞模式运行。这时他会产生错误而不是等待缓冲区,
这种模式下不会丢弃缓冲区,
这对于避免可能不了解图形框架的复杂依赖性的AP中欧冠潜在死锁很有用,
丢弃模式,
BufferQUeue的状态
生产者和消费者使用BufferQueue的方法:
1,生产者通过dequeueBuffer()请求一个空闲的buffer,并且指定相关的参数,如w,h,format像素格式
2,生产者填充buffer内容后会通过queueBuffer()将其放入队列中,
3,之后,消费者会通过acquireBuffer()使用Buffer的内容
4,消费者用完,releaseBuffer()归还给队列。
FREE --> IGraphicBufferProducer::dequeueBuffer() -->
DEQUEUED --> IGraphicBufferProducer::queueBuffer() -->
QUEUED --> IGraphicBufferConsumer::acquireBuffer() -->
ACQUIED --> IGraphicBufferConsumer::releaseBuffer()-->
屏幕上内容的更新,就是通过对BufferQUeue的缓冲区不断的进出队列实现的,
GraphicBufferAllocator,
GraphicBufferAllocator负责缓冲的份额皮,这个类的结构简单,主要提供了allocate方法分配缓冲,还有free,
GraphicBufferAllocator最终要依赖于Gralloc模块完成缓冲的分配和释放,因此其接口也通过buffer_handle_t标识缓冲区。
9.2.4 Surface
前面提到过Surface组件,Surface是Android从API Level 1就公开的API。
Surface是BufferQueue的生产者一端,而SurfaceFlinger通常是消费者一端
当渲染Surface时,结果将通过BufferQueue传递给消费者。
Surface的BufferQueue通常配置为三重缓冲(见下节Project Butter),
但缓冲是按需分配的。
所以如果生产者缓慢的生成buffer--也许是在60fps的显示器上以30fps的速度动画,则队列可能只有两个分配的buffer,
这样有助于最小化内存消耗。
通过adb shell dumpsys SurfaceFlinger输出图形系统的详细信息
以前的Android版本,所有渲染都是软件完成的,虽然现在也可以这样做。底层实现由Skia图形库提供。
如果要绘制一个矩形,则进程库调用,并在buffer中适当设置内容,
为确保两个客户端不会同时更新buffer,或者在显示时写入buffer,必须先锁定buffer才可以访问。
lockCanvas()用来lock buffer并返回Canvas用于绘图,unlockCanvasAndPost()用来unlock buffer并发送到合成器。
后来,具有通用3D引擎的设备出现了,Android重新定位在OpenGLES上,
而重要的是保持旧的API适用于APP和APP框架代码,所以系统通过硬件加速Canvas API。
Canvas提供给View的onDraw()方法可能会被硬件加速,
但是当APP直接使用lockCanvas()锁定Surface时获得的Canvas一定不会使用硬件加速,
为了访问Canvas而锁定Surface时,“CPU渲染器”连接到BufferQueue的生产者端,直到Surface被销毁时才断开连接。
多数其他生产者(如GLES)可以断开连接并且重新连接到Surface,但是基于Canvas的“GPU渲染器”是不行的。
这意味着,如果已经将其锁定在画布上,则无法使用GLES绘制曲面或者从视频解码器发送帧
生产者首次从BufferQueue请求缓冲区时,将被分配并init为0,。
init是必要的,来避免无意间在进程之间共享数据。
而在重新使用buffer时,以前的内容仍然在。
若反复调用lockCanvas()和unlockCanvasAndPost(),而不绘制内容,则会在先前渲染的帧之间循环。
Surface 锁定/解锁代码保留对先前渲染的缓冲区的引用。
如果在锁定Surface时指定了脏区域,那么它将从前一个缓冲区复制非脏像素。
buffer可能由SF或者HWC处理,但由于我们只需要读,所以不用等待独占访问。
软件绘制的实现
ViewRootImpl中的drawSoftware负责软件绘制的逻辑,
//ViewRootImpl.java
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty){
final Canvas canvas;
try {
final int left = dirty.left;
final int top = dirty.top;
final int right .....
canvas = mSurface.lockCanvas(ditry); ①
...
}
try {
...
if(!canvas.isOpaque() || yoff != 0 || xoff != 0) {
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
}
...
try {
canvas.translate(-xoff, -yoff);
if(mTranslator != null) mTranslator.translateCanvas(canvas);
}
....
mView.draw(canvas); ②
drawAccessibilityFocusedDrawableIfNeeded(canvas);
} finally {
...
}
} finally {
try {
surface.unlockCanvasAndPost(canvas); ③
} catch(IllegalArgumentException e) {
}
...
}
}
这段代码的主要逻辑:
1,lock界面中要绘制的部分
2,将View的内容画到Canvas上
3,post绘制的结果
Surface.unlockCanvasAndPost方法中提交结果的方式就是向BufferQueue传递缓冲,逻辑:
ViewRootImpl.drawSoftware JAVA层
Surface.unlockCanvasAndPost
Surface.unlockSwCanvasAndPost
Surface.nativeUnlockCanvasAndPost JNI层
Surface::unlockAndPost C++层
Surface::queueBuffer
IGraphicBufferProducer::queueBuffer
这样ViewRootImpl中相关区域的内容便进行了更新
本节内容总结:
Acitivity
Surface SurfaceFlinger
IGraphicBufferProducer <-> BufferQUeue <-> IGraphicBufferConsumer
GraphicBufferAllocator
Gralloc
http://elinux.org/images/2/2b/Android_graphics_path-chis_simmonds.pdf
http://www.cnblogs.com/samchen2009/p/3367496.html
http://lindt.blog.51cto.com/9699125/1864591