Android绘制系统(1): Surface - clarkehe/Android GitHub Wiki
Android绘制系统比较复杂,核心是surfaceFlinger(很多有经验的开发人员不认识这个独立服务进程),还有很多的概念(类)。从去年就开始断断续续看了一些源码与别人写的博客文章,有了一个大概的了解。但不太全面,有细节也不够深入。只能边了解一点,边记录一点,后面再慢慢的串起来。先从Surface讲起吧。
Surface在Android的绘制系统是一个承上启下的类。上向View提供画布Canvas,下向surfaceFlinger提供可显示的缓存。在surfaceFlinger眼中是没有View这些概念的,它只关心图像缓存。View树绘制出来的图像通过Surface提交给了surfaceFlinger进行合成显示。
在Java层(Surface.java),Surface有两个核心的接口:lockCanvas和unlockCanvasAndPost。lockCanvas返回一个Canvas供View进行绘制,unlockCanvasAndPost则提交绘制的结果。
再看看Native层的Surface(Surface.h、Surface.cpp)。
Native层的Surface是ANativeWindow(window.h)的一个实现。ANativeWindow是Android针对OpenGL ES的窗口实现。ANativeWindow联接了OpenGL与Surface。Surface通过ANativeWindow为OpenGL提供要栅格化时需要的缓存(硬件绘制的时候,将命令转化为像素位图)。
class Surface
: public ANativeObjectBase<ANativeWindow, Surface, RefBase>
{
public:
...
Surface对外提供了获取可用缓存的接口,Surface是可以无视ANativeWindow独立存在的(个人理解),比如Skia 2D软绘制的时候。ANativeWindow的实现接口最终都转为对Surface的接口的调用,类似一种接口转换模式。OpenGL在栅格化时,找ANativeWindow要缓存,ANativeWindow自己没有缓存,将请求转给了Surface,由Surface来提供缓存。
ViewRootImpl.java中软绘制时,Surface的使用。这也是软件绘制的入口及基本流程。
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {
// Draw with software renderer.
final Canvas canvas;
try {
canvas = mSurface.lockCanvas(dirty);
}
...
try {
...
try {
...
mView.draw(canvas);
}
....
} finally {
try {
surface.unlockCanvasAndPost(canvas);
}
...
}
return true;
}
这样Surface在绘制时,有两种使用途径。一种是软绘制的时候,直接使用其lockCanvas与unlockCanvasAndPost接口;另一种是硬件绘制的时候,通过ANativeWindow向OpenGL提供缓存。本质都一样的,都是缓存的获取,数据填充,缓存提交。
Java层Surface对象的创建主要有三种方式。
一是JAVA反射方法创建(android_view_Surface.cpp),这种方式用的地方很多,ImageReader的Surface就是这处方式创建。
/* called from android_view_Surface_createFromIGraphicBufferProducer() */
private Surface(long nativeObject) {
synchronized (mLock) {
setNativeObjectLocked(nativeObject);
}
}
jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
const sp<IGraphicBufferProducer>& bufferProducer) {
if (bufferProducer == NULL) {
return NULL;
}
//Native层Surface的创建,构造参数有一个非常关键的:bufferProducer
sp<Surface> surface(new Surface(bufferProducer, true));
if (surface == NULL) {
return NULL;
}
//调用JAVA层Surface的构造方法,Java层的Surface只是一个壳,通过一个long型值引用Native层的Surface
jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz,
gSurfaceClassInfo.ctor, (jlong)surface.get());
if (surfaceObj == NULL) {
if (env->ExceptionCheck()) {
ALOGE("Could not create instance of Surface from IGraphicBufferProducer.");
LOGE_EX(env);
env->ExceptionClear();
}
return NULL;
}
surface->incStrong(&sRefBaseOwner);
return surfaceObj;
}
二是复制创建([Surface.java] (http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/view/Surface.java#311)),Activity背后的Surface就是这种方式创建的。
/**
* Copy another surface to this one. This surface now holds a reference
* to the same data as the original surface, and is -not- the owner.
* This is for use by the window manager when returning a window surface
* back from a client, converting it from the representation being managed
* by the window manager to the representation the client uses to draw
* in to it.
* @hide
*/
public void copyFrom(SurfaceControl other) {
if (other == null) {
throw new IllegalArgumentException("other must not be null");
}
long surfaceControlPtr = other.mNativeObject;
if (surfaceControlPtr == 0) {
throw new NullPointerException(
"SurfaceControl native object is null. Are you using a released SurfaceControl?");
}
long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
synchronized (mLock) {
if (mNativeObject != 0) {
nativeRelease(mNativeObject);
}
setNativeObjectLocked(newNativeObject);
}
}
第三种是通过SurfaceTexture来创建([Surface.java] (http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/view/Surface.java#133)),这种方式不太常见。 使用这种方式,就需要先创建一个SurfaceTexture,而创建SurfaceTexture则需求一个texture id。后面再专门讲SurfaceTexture及其创建。
public Surface(SurfaceTexture surfaceTexture) {
if (surfaceTexture == null) {
throw new IllegalArgumentException("surfaceTexture must not be null");
}
synchronized (mLock) {
mName = surfaceTexture.toString();
setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
}
}
/**
* Construct a new SurfaceTexture to stream images to a given OpenGL texture.
*
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
*
* @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(int texName) {
this(texName, false);
}
Native层的Surface(Surface.cpp)创建就一种方法,构造函数中传入一个IGraphicBufferProducer参数。
Surface::Surface(
const sp<IGraphicBufferProducer>& bufferProducer,
bool controlledByApp)
: mGraphicBufferProducer(bufferProducer)
{
// Initialize the ANativeWindow function pointers.
...
}
前面说过,Surface主要对外提供绘制所需要的缓存,其实真正提供缓存的是mGraphicBufferProducer。mGraphicBufferProducer指向一个缓存队列,在需要缓存空间时,会在缓存队列中找到一个空闲的缓存块。空闲缓存块获取后,先锁定,填充绘制的图像数据,再提交。
因此,与mGraphicBufferProducer相对应的,还有一个mGraphicBufferConsumer。缓存在提交后,要被使用,缓存的使用(消费)者(如surfaceFlinger)会保存一个mGraphicBufferConsumer的引用。当mGraphicBufferProducer提交(通知)数据时,通过mGraphicBufferConsumer获取到提交的缓存数据,进行使用(合成、显示)。
这就是一个典型的生产-消费者模式。缓存数据的生产者通过Surface(也是通过mGraphicBufferProducer)提交数据,缓存的消费者通过mGraphicBufferConsumer获取数据进行消费。
ImagerReader(android_media_ImageReader.cpp)使用Surface。
static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz,
jint width, jint height, jint format, jint maxImages)
{
....
//创建缓存队列,一个队列,一个生产者,一个消费者
sp<IGraphicBufferProducer> gbProducer;
sp<IGraphicBufferConsumer> gbConsumer;
BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
//消费者
sp<CpuConsumer> consumer = new CpuConsumer(gbConsumer, maxImages,
/*controlledByApp*/true);
...
//ImageReader的消费者
ctx->setCpuConsumer(consumer);
//ImageReader的生产者,gbProducer会用来创建Surface
ctx->setProducer(gbProducer);
....
}
//使用gbProducer来创建Surface
static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
{
ALOGV("%s: ", __FUNCTION__);
IGraphicBufferProducer* gbp = ImageReader_getProducer(env, thiz);
if (gbp == NULL) {
jniThrowRuntimeException(env, "CpuConsumer is uninitialized");
return NULL;
}
// Wrap the IGBP in a Java-language Surface.
return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
}
mGraphicBufferConsumer与mGraphicBufferConsumer的实现,另外再专门分析下。