measure OnMeasure setMeasuredDimension
resultSize = size resultMode
MeasureSpec.makeMasureSpec
resultSize resultMode
mMeasuredWidth mMeasuredHeight
mPrivateFlags
DecorView FrameLayout ViewGroup view
参数measureSpec的值其实是由两部分内容来组成的,最高2位表示一个测量规范,而低30位表示一个宽度值或者高度值。测量规范有三种,分别是0、1和2,使用常量MeasureSpec.UNSPECIFIED、MeasureSpec.EXACTLY和MeasureSpec.AT_MOST来表示。
当参数measureSpec描述的规范是MeasureSpec.UNSPECIFIED时,就表示当前视图没有指定它的大小测量模式,这时候就使用参数size的值;当参数measureSpec描述的规范是MeasureSpec.AT_MOST时,就表示当前视图的大小等于参数size和参数measureSpec所指定的值中的较小值;当参数measureSpec描述的规范是MeasureSpec.EXACTLY时,就表示当前视图的大小等于参数measureSpec中所指定的值。
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
......
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
mPrivateFlags |= MEASURED_DIMENSION_SET;
}
......
}
childHeightMeasureSpec childWidthMeasureSpec
DecorView getChildMeasureSpec child.measure
接下来,我们就继续分析View类的成员函数setFrame和onLayout的实现,以便可以了解当前视图及其子视图是如何执行布局操作的。
layout setFrame invalidate invalidateChild onLayout
请求绘制当前视图的UI是通过调用View类的成员变量mParent所描述的一个ViewParent接口的成员函数invalidateChild来实现的。前面我们假设当前视图是应用程序窗口的顶层视图,即它是一个类型为DecoreView的视图,它的成员变量mParent指向的是与其所关联的一个ViewRoot对象。因此,绘制当前视图的UI的操作实际上是通过调用ViewRoot类的成员函数invalidateChild来实现的。
注意,在调用ViewRoot类的成员函数invalidateChild的成员函数invalidateChild来绘制当前视图的UI之前,会将当前视图即将要绘制的区域记录在View类的成员变量mAttachInfo所描述的一个AttachInfo对象的成员变量mTmpInvalRect中。
接下来,我们就继续分析ViewRoot类的成员函数invalidateChild的实现。
Step 4. ViewRoot.invalidateChild
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
......
int mPrivateFlags;
......
public final void layout(int l, int t, int r, int b) {
boolean changed = setFrame(l, t, r, b);
if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
......
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~LAYOUT_REQUIRED;
}
mPrivateFlags &= ~FORCE_LAYOUT;
}
......
}
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
......
protected ViewParent mParent;
......
int mPrivateFlags;
......
public void invalidate() {
......
if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS)) {
mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
final ViewParent p = mParent;
final AttachInfo ai = mAttachInfo;
if (p != null && ai != null) {
final Rect r = ai.mTmpInvalRect;
r.set(0, 0, mRight - mLeft, mBottom - mTop);
// Don't call invalidate -- we don't want to internally scroll
// our own bounds
p.invalidateChild(this, r);
}
}
}
......
}
请求绘制当前视图的UI是通过调用View类的成员变量mParent所描述的一个ViewParent接口的成员函数invalidateChild来实现的。前面我们假设当前视图是应用程序窗口的顶层视图,即它是一个类型为DecoreView的视图,它的成员变量mParent指向的是与其所关联的一个ViewRoot对象。因此,绘制当前视图的UI的操作实际上是通过调用ViewRoot类的成员函数invalidateChild来实现的。
DecorView mParent = ViewRoot ViewRootImpl
mDecor = mWindow.getDecorView();
PhoneWindow
mDecor = generateDecor();
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
final ViewParent p = mParent;
p.invalidateChild(this, r);
@Override
public void invalidateChild(View child, Rect dirty) {
invalidateChildInParent(null, dirty);
}
void invalidate() {
mDirty.set(0, 0, mWidth, mHeight);
if (!mWillDrawSoon) {
scheduleTraversals();
}
}
设置好当前正在处理的应用程序窗口下一次所要重新绘制的总区域之后,ViewRoot类的成员函数invalidateChild最后就检查成员变量mWillDrawSoon的值是否不等于true。如果ViewRoot类的成员mWillDrawSoon的值等于true的话,那么就说明UI线程的消息队列中已经有一个DO_TRAVERSAL消息在等待执行了,这时候就不需要调用ViewRoot类的成员函数scheduleTraversals来向UI线程的消息队列发送一个DO_TRAVERSAL消息了,否则的话,就需要调用ViewRoot类的成员函数scheduleTraversals来向UI线程的消息队列发送一个DO_TRAVERSAL消息。
DO_TRAVERSAL
scheduleTraversals
private DecorView mDecor;
layout setFrame invalidate onLayout
p.invalidateChild
事实上,DecorView类是通过FrameLayout类来间接继承View类的,并且它的成员函数onLayout是从FrameLayout类继承下来的,因此,接下来我们实际上要分析的是FrameLayout类的成员函数onLayout的实现。
DecorView FrameLayout
public class FrameLayout extends ViewGroup {
......
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
final int count = getChildCount();
final int parentLeft = mPaddingLeft + mForegroundPaddingLeft;
final int parentRight = right - left - mPaddingRight - mForegroundPaddingRight;
final int parentTop = mPaddingTop + mForegroundPaddingTop;
final int parentBottom = bottom - top - mPaddingBottom - mForegroundPaddingBottom;
mForegroundBoundsChanged = true;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
int childLeft = parentLeft;
int childTop = parentTop;
final int gravity = lp.gravity;
if (gravity != -1) {
final int horizontalGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (horizontalGravity) {
case Gravity.LEFT:
childLeft = parentLeft + lp.leftMargin;
break;
case Gravity.CENTER_HORIZONTAL:
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = parentRight - width - lp.rightMargin;
break;
default:
childLeft = parentLeft + lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.TOP:
childTop = parentTop + lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = parentBottom - height - lp.bottomMargin;
break;
default:
childTop = parentTop + lp.topMargin;
}
}
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
}
......
}
Gravity.LEFT
parentLeft + (parentRight - width) / 2 +
lp.leftMargin
parentTop + parentBottom - parentTop - height
Gravity.BOTTOM
child.layout(childLeft, childTop, childLeft + width, childTop + height);
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
......
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
......
int yoff;
final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();
if (scrolling) {
yoff = mScroller.getCurrY();
} else {
yoff = mScrollY;
}
if (mCurScrollY != yoff) {
mCurScrollY = yoff;
fullRedrawNeeded = true;
}
float appScale = mAttachInfo.mApplicationScale;
boolean scalingRequired = mAttachInfo.mScalingRequired;
Rect dirty = mDirty;
......
if (mUseGL) {
if (!dirty.isEmpty()) {
Canvas canvas = mGlCanvas;
if (mGL != null && canvas != null) {
......
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try {
canvas.translate(0, -yoff);
if (mTranslator != null) {
mTranslator.translateCanvas(canvas);
}
canvas.setScreenDensity(scalingRequired
? DisplayMetrics.DENSITY_DEVICE : 0);
mView.draw(canvas);
......
} finally {
canvas.restoreToCount(saveCount);
}
......
}
}
if (scrolling) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
return;
}
if (fullRedrawNeeded) {
......
dirty.union(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
}
......
if (!dirty.isEmpty() || mIsAnimating) {
Canvas canvas;
try {
......
canvas = surface.lockCanvas(dirty);
......
} catch (Surface.OutOfResourcesException e) {
......
return;
} catch (IllegalArgumentException e) {
......
return;
}
try {
if (!dirty.isEmpty() || mIsAnimating) {
.....
mView.mPrivateFlags |= View.DRAWN;
......
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try {
canvas.translate(0, -yoff);
if (mTranslator != null) {
mTranslator.translateCanvas(canvas);
}
canvas.setScreenDensity(scalingRequired
? DisplayMetrics.DENSITY_DEVICE : 0);
mView.draw(canvas);
} finally {
......
canvas.restoreToCount(saveCount);
}
......
}
} finally {
surface.unlockCanvasAndPost(canvas);
}
}
......
if (scrolling) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
}
......
}
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas = surface.lockCanvas(dirty);
canvas.restoreToCount
surface.unlockCanvasAndPost
ViewRootImpl
void scheduleTraversals() {
doTraversal();
performTraversals();
final View host = mView =DecorView
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
int relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingConfiguration, mSurface);
final class Session extends IWindowSession.Stub
Session
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outStableInsets, outConfig, outSurface);
SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
SurfaceFlinger
SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
public class Surface implements Parcelable {
......
public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException, IllegalArgumentException
{
/* the dirty rectangle may be expanded to the surface's size, if
* for instance it has been resized or if the bits were lost, since
* the last call.
*/
return lockCanvasNative(dirty);
}
private native Canvas lockCanvasNative(Rect dirty);
......
}
从前面Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析一文还可以知道,每一个Java层的Surface对象内部都有一块画布,这块画布是通过它的成员变量mCanvas所指向的一个Java层的CompatibleCanvas对象来描述的。so是一个类型为so_t的结构体,它的成员变量canvas描述的是Java层的Surface类的成员变量mCanva在类中的偏移量,因此,通过这个偏移量就可以获得参数clazz所指向的一个Java层的Surface对象的内部的一块类型为CompatibleCanvas的画布canvas。
画布canvas的类型为Java层的CompatibleCanvas,它是从Canvas类继承下来的。Canvas类有一个成员变量mNativeCanvas,它指向的是一个C++层的SkCanvas对象,这个C++层的SkCanvas对象描述的就是Skia图形库绘制应用程序窗口UI时所需要的画布。no是一个类型为no_t的结构体,它的成员变量native_canvas描述的是Java层的Canvas类的成员变量mNativeCanvas在类中的偏移量,因此,通过这个偏移量就可以获得变量canvas所指向的一个Java层的CompatibleCanvas对象的内部的一块类型为SkCanvas的画布nativeCanvas。
Surface
public class Surface implements Parcelable {
public Surface(SurfaceTexture surfaceTexture) {
checkHeadless();
if (DEBUG_RELEASE) {
mCreationStack = new Exception();
}
mCanvas = new CompatibleCanvas();
initFromSurfaceTexture(surfaceTexture);
}
private Canvas mCanvas;
native private static void nativeClassInit();
static { nativeClassInit(); }
Surface
private class CompatibleCanvas extends Canvas {
// A temp matrix to remember what an application obtained via {@link getMatrix}
private Matrix mOrigMatrix = null;
@Override
public int getWidth() {
android_view_Surface.cpp
struct so_t {
jfieldID surfaceControl;
jfieldID surfaceGenerationId;
jfieldID surface;
jfieldID saveCount;
jfieldID canvas;
};
画布canvas的类型为Java层的CompatibleCanvas,它是从Canvas类继承下来的。Canvas类有一个成员变量mNativeCanvas,它指向的是一个C++层的SkCanvas对象,这个C++层的SkCanvas对象描述的就是Skia图形库绘制应用程序窗口UI时所需要的画布。no是一个类型为no_t的结构体,它的成员变量native_canvas描述的是Java层的Canvas类的成员变量mNativeCanvas在类中的偏移量,因此,通过这个偏移量就可以获得变量canvas所指向的一个Java层的CompatibleCanvas对象的内部的一块类型为SkCanvas的画布nativeCanvas。
Canvas
public class Canvas {
// assigned in constructors, freed in finalizer
final int mNativeCanvas;
public Canvas() {
// 0 means no native bitmap
mNativeCanvas = initRaster(0);
mFinalizer = new CanvasFinalizer(mNativeCanvas);
}
private static native int initRaster(int nativeBitmapOrZero);
// Associate a SkCanvas object to this surface
jobject canvas = env->GetObjectField(clazz, so.canvas);
......
SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
//从c++ canvas 对应的Java类Canvas中拿到mNativeCanvas赋值给c++的no.native_canvas 并转换为SKCanvas
truct no_t {
jfieldID native_canvas;
jfieldID native_region;
jfieldID native_parcel;
};
static no_t no;
获得了Skia图形库所需要的画布nativeCanvas之后,函数就可以将前面所获得的图形缓冲区的地址,即SurfaceInfo对象info的成员变量bits封装到它内部去了,这是通过调用它的成员函数setPixels来实现的。
jfieldID和jmethodID
在JNI中用jfieldID和jmethodID来代表Java类中的成员变量和方法,可以通过JNIEnv的下面两个方法来分别得到:
jfieldID GetFieldID(jclass clazz,const char *name,const char *sig);
jmethodID GetFieldID(jclass clazz,const char *name,const char *sig);
其中,jclass代表Java类,name代表成员方法或者成员变量的名字,sig为这个方法和变量的签名。
static void
android_media_MediaRecorder_native_init(JNIEnv *env)
{
jclass clazz;
clazz = env->FindClass("android/media/MediaRecorder");//1
if (clazz == NULL) {
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "J");//2
if (fields.context == NULL) {
return;
}
fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");//3
if (fields.surface == NULL) {
return;
}
jclass surface = env->FindClass("android/view/Surface");
if (surface == NULL) {
return;
}
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");//4
if (fields.post_event == NULL) {
return;
}
}
注释1处,通过FindClass来找到Java层的MediaRecorder的Class对象,并赋值给jclass类型的变量clazz,因此,clazz就是Java层的MediaRecorder在JNI层的代表。注释2和注释3处的代码用来找到Java层的MediaRecorder中名为mNativeContext和mSurface的成员变量,并分别赋值给context和surface。注释4出获取Java层的MediaRecorder中名为postEventFromNative的静态方法,并赋值给post_event。其中fields的定义为:
struct fields_t {
jfieldID context;
jfieldID surface;
jmethodID post_event;
};
static fields_t fields;
将这些成员变量和方法赋值给jfieldID和jmethodID类型的变量主要是为了效率考虑,如果每次调用相关方法时都要进行查询方法和变量,显然会效率很低,因此在MediaRecorder框架JNI层的初始化方法android_media_MediaRecorder_native_init中将这些jfieldID和jmethodID类型的变量保存起来,以供后续使用。
frameworks/base/media/jni/android_media_MediaRecorder.cpp
static void
android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
{
ALOGV("prepare");
sp
jobject surface = env->GetObjectField(thiz, fields.surface);//1
if (surface != NULL) {
const sp
...
}
process_media_recorder_call(env, mr->prepare(), "java/io/IOException", "prepare failed.");
在注释1处调用了JNIEnv的GetObjectField函数,参数中的fields.surface用来保存Java层MediaRecorde中的成员变量mSurface,mSurface的类型为Surface,这样通过GetObjectField函数就得到了mSurface在JNI层中对应的jobject类型变量surface 。
struct fields_t {
jfieldID context;
jfieldID surface;
jmethodID post_event;
};
static fields_t fields;
#include "video1_TestNative.h"
#include
using namespace std;
JNIEXPORT void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, jobject obj){
cout<<"Hello Native Test !"<
//否则就传入一个jclass对象表示native()方法所在的类
jclass native_clazz = env->GetObjectClass(obj);
//得到jfieldID
jfieldID fieldID_name = env->GetFieldID(native_clazz,"name","Ljava/lang/String;");
jfieldID fieldID_num = env->GetFieldID(native_clazz,"number","I");
//得到jmethodID
jmethodID methodID_func=env->GetMethodID(native_clazz,"signTest","(ILjava/util/Date;[I)I");
//调用signTest方法
env->CallIntMethod(obj,methodID_func,1L,NULL,NULL);
//得到name属性
jobject name = env->GetObjectField(obj,fieldID_name);
//得到number属性
jint number= env->GetIntField(obj,fieldID_num);
cout<
env->SetIntField(obj,fieldID_num,18880L);
number= env->GetIntField(obj,fieldID_num);
cout<
// Associate a SkCanvas object to this surface
jobject canvas = env->GetObjectField(clazz, so.canvas);
//拿到Java的 Canvas类
函数接下来就调用前面所获得的C++层的Surface对象surface的成员函数lock来获得一个图形缓冲区,这个图形缓冲区使用一个SurfaceInfo对象info来描述,其中,图形缓冲区的地址就保存在它的成员变量bits中。
env->SetIntField(canvas, co.surfaceFormat, info.format);
//给Java Canvas类里面的mSurfaceFormat变量赋值为info.format
android_view_Surface.cpp
void nativeClassInit(JNIEnv* env, jclass clazz)
{
no.native_canvas = env->GetFieldID(canvas, "mNativeCanvas", "I");
co.surfaceFormat = env->GetFieldID(canvas, "mSurfaceFormat", "I");
Canvas
public class Canvas {
// assigned in constructors, freed in finalizer
final int mNativeCanvas;
// Used by native code
@SuppressWarnings({"UnusedDeclaration"})
private int mSurfaceFormat;
SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
//拿到Java Canvas类里面 mNativeCanvas 转换为C++类里面的SkCanvas对象
bitmap.setPixels(info.bits);
设置好SkRegion的对象clipReg所包含的区域之后,函数就可以调用前面得到的SkCanvas画布nativeCanvas的成员函数clipRegion来将它设置为自己的裁剪区域了,接下来函数还会将该裁剪区域所围成的一个矩形区域的位置和大小设置到参数dirtyRect所描述的一个Java层的Rect对象中去,以便调用者可以知道现在正在创建的画布的大小。
if (dirtyRect) {
const Rect& bounds(dirtyRegion.getBounds());
env->SetIntField(dirtyRect, ro.l, bounds.left);
env->SetIntField(dirtyRect, ro.t, bounds.top);
env->SetIntField(dirtyRect, ro.r, bounds.right);
env->SetIntField(dirtyRect, ro.b, bounds.bottom);
}
struct ro_t {
jfieldID l;
jfieldID t;
jfieldID r;
jfieldID b;
};
static ro_t ro;
jclass rect = env->FindClass("android/graphics/Rect");
ro.l = env->GetFieldID(rect, "left", "I");
ro.t = env->GetFieldID(rect, "top", "I");
ro.r = env->GetFieldID(rect, "right", "I");
ro.b = env->GetFieldID(rect, "bottom", "I");
函数在将与C++层的SkCanvas画布nativeCanvas所关联的一个Java层的CompatibleCanvas画布canvas返回给调用者之前,还会将画布的当前堆栈状态保存下来,以便在绘制完成应用程序窗口的UI之后,可以恢复回来,这是通过调用C++层的SkCanvas画布nativeCanvas的成员函数save来实现的。画布的当前堆栈状态是通过一个整数来描述的,这个整数即为C++层的SkCanvas画布nativeCanvas的成员函数save的返回值saveCount,它会被保存在参数clazz所描述的一个Java层的Surface对象的成员变量mSaveCount中,等到应用程序窗口的UI绘制完成之后,就可以通过这个整数来恢复画布的堆栈状态了。
int saveCount = nativeCanvas->save();
env->SetIntField(clazz, so.saveCount, saveCount);
会被保存在参数clazz所描述的一个Java层的Surface对象的成员变量mSaveCount中
接下来,我们继续分析C++层的Surface类的成员函数lock的实现,以便可以了解用来创建绘制应用程序窗口UI所需要的画布的图形缓冲区是如何获得的。
Step 3. Surface.lock
{"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas },
status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
{
......
if (mApiLock.tryLock() != NO_ERROR) {//tryLock 上
......
return WOULD_BLOCK;
}
Surface类的成员变量mApiLock是一个类型为Mutex的互斥锁,它是用来保证Surface类的成员函数lock是线程安全的。如果调用Surface类的成员变量mApiLock所描述的一个Mutex对象的成员函数tryLock的返回值不等于NO_ERROR,那么就说明这个Mutex对象已经被另外一个线程获得了,因此,这时候函数就直接返回一个错误码WOULD_BLOCK给调用者了。
Mutex = mApiLock
/* Here we're holding mApiLock */
if (mLockedBuffer != 0) {
......
mApiLock.unlock();
return INVALID_OPERATION;
}
// we're intending to do software rendering from this point
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
android_native_buffer_t* out;
status_t err = dequeueBuffer(&out);
......
Surface类的成员函数lock接下来就调用另外一个成员函数dequeueBuffer来获得一个新的图形缓冲区了,这个新的图形缓冲区使用一个android_native_buffer_t对象out来描述的。在前面Android应用程序请求SurfaceFlinger服务渲染Surface的过程分析一文中,我们已经分析过Surface类的成员函数dequeueBuffer的实现了,它主要就是请求SurfaceFlinger服务来分配一个图形缓冲区。
android_native_buffer_t*
if (err == NO_ERROR) {
sp
err = lockBuffer(backBuffer.get());
前面获得的android_native_buffer_t对象out接下来又会被封装成一个GraphicBuffer对象backBuffer,这样,Surface类的成员函数lock接下来就会通过GraphicBuffer对象backBuffer来访问前面所获得的图形缓冲区。
......
if (err == NO_ERROR) {
const Rect bounds(backBuffer->width, backBuffer->height);
const Region boundsRegion(bounds);
Region scratch(boundsRegion);
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
newDirtyRegion &= boundsRegion;
// figure out if we can copy the frontbuffer back
const sp
const bool canCopyBack = (frontBuffer != 0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format &&
!(mFlags & ISurfaceComposer::eDestroyBackbuffer));
......
if (canCopyBack) {
// copy the area that is invalid and not repainted this round
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty())
copyBlt(backBuffer, frontBuffer, copyback);
} else {
// if we can't copy-back anything, modify the user's dirty
// region to make sure they redraw the whole buffer
newDirtyRegion = boundsRegion;
}
......
void* vaddr;
status_t res = backBuffer->lock(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr);
......
mLockedBuffer = backBuffer;
other->w = backBuffer->width;
other->h = backBuffer->height;
other->s = backBuffer->stride;
other->usage = backBuffer->usage;
other->format = backBuffer->format;
other->bits = vaddr;
}
}
mApiLock.unlock();
return err;
}
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include
#include
#include
#include
#include
#include
#include
using namespace android;
int main(int argc, char** argv)
{
// set up the thread-pool
sp
ProcessState::self()->startThreadPool();
// create a client to surfaceflinger
sp
sp
0, 160, 240, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::openGlobalTransaction();
surfaceControl->setLayer(100000);
SurfaceComposerClient::closeGlobalTransaction();
// pretend it went cross-process
Parcel parcel;
SurfaceControl::writeSurfaceToParcel(surfaceControl, &parcel);
parcel.setDataPosition(0);
sp
ANativeWindow* window = surface.get();
printf("window=%p\n", window);
int err = native_window_set_buffer_count(window, 8);
ANativeWindowBuffer* buffer;
for (int i=0 ; i<8 ; i++) {
window->dequeueBuffer(window, &buffer);
printf("buffer %d: %p\n", i, buffer);
}
printf("test complete. CTRL+C to finish.\n");
IPCThreadState::self()->joinThreadPool();
return 0;
}
Surface ProcessState SurfaceComposerClient SurfaceControl
ANativeWindow*
const sp
status_t err = surface->lock(&info, &dirtyRegion);
Surface类是使用一种称为双缓冲的技术来渲染应用程序窗口的UI的。这种双缓冲技术需要两个图形缓冲区,其中一个称为前端缓冲区,另外一个称为后端缓冲区。前端缓冲区是正在渲染的图形缓冲区,而后端缓冲区是接下来要渲染的图形缓冲区,它们分别通过Surface类的成员变量mPostedBuffer和mLockedBuffer所指向的两个GraphicBuffer对象来描述。前面所获得的图形缓冲区backBuffer是作为后端缓冲区来使用的,即接下来它所指向的图形缓冲区也需要保存在Surface类的成员变量mLockedBuffer中。
在将图形缓冲区backBuffer返回给调用者之前,Surface类的成员函数lock还需要对它进行进一步的处理,即判断是否需要前端缓冲区mPostedBuffer的内容拷贝回它里面去,以便可以支持部分更新应用程序窗口UI的功能。在满足以下三个条件下,Surface类的成员函数lock可以将前端缓冲区的内容拷贝到后端缓冲区中去:
1. 前端缓冲区的内容拷贝到后端缓冲区所描述的区域的宽度和高度相同。
2. 前端缓冲区和后端缓冲区的像素格式相同。
3. 应用程序窗口绘图表面的属性值mFlags的ISurfaceComposer::eDestroyBackbuffer位等于0,即在渲染了应用程序窗口的UI之后,应该保留正在渲染的图形缓冲区的内容。
如果能将前端缓冲区的内容拷贝到后端缓冲区中去,那么就不用重新绘制应用程序窗口的所有区域,而只需要绘制那些脏的区域,即Region对象newDirtyRegion所描述的区域。注意,参数dirtyIn所描述的区域是原先指定的脏区域,但是在分配了新的后端缓冲区backBuffer之后,我们需要将新的图形缓冲区backBuffer所描述的区域boundsRegion与原先指定的脏区域作一个与操作,得到才是最后需要重绘的脏区域newDirtyRegion。由于在这种情况下,我们只在后端缓冲区backBuffer绘制中绘制应用程序窗口的脏区域,因此,就需要将那些干净的区域从前端缓冲区frontBuffer拷贝到图形缓冲区backBuffer的对应位置去,这是通过调用函数copyBlt来实现的。应用程序窗口的干净区域使用Region对象copyback来描述,它是从应用程序窗口上一次所重绘的区域减去接下来需要重绘的脏区域newDirtyRegion得到的,而应用程序窗口上一次所重绘的区域是保存在Surface类的成员变量mOldDirtyRegion中的。
如果不能将前端缓冲区的内容拷贝到后端缓冲区中去,那么接下来就需要重新绘制应用程序窗口的所有区域了,这时候应用程序窗口的脏区域newDirtyRegion就会被修改为后端缓冲区backBuffer所描述的区域boundsRegion。
Surface类的成员函数lock处理完成前后端缓冲区的拷贝问题之后,接下来就会调用后端缓冲区backBuffer所指向的一个GraphicBuffer对象的成员函数lock来获得它的地址vaddr,以便接下来保存在参数other所描述的一个SurfaceInfo对象的成员变量bits中,这样调用者就获得后端缓冲区backBuffer的地址值了。注意,同时保存在SurfaceInfo对象中的信息还包括后端缓冲区backBuffer的宽度width、高度height、每行像素点stride、用途usage和像素格式format。
Surface类的成员函数lock还会将接下来要重绘的脏缓冲区newDirtyRegion保存在Surface类的成员变量mOldDirtyRegion中,以便再下一次为应用程序窗口分配图形缓冲区时,可以知道应用程序窗口的上一次重绘区域,即上一次干净区域。
此外,Surface类的成员函数lock还会将后端缓冲区backBuffer保存在Surface类的成员变量mLockedBuffer,这样就可以知道应用程序窗口当前正在使用的图形缓冲区,即下一次要请求SurfaceFlinger服务渲染的图形缓冲区。
最后,Surface类的成员函数lock首先调用成员变量mApiLock所指向的一个Mutex对象的成员函数unlock,以便中可以释放前面所获得的锁,然后再返回到上一步去。
接下来,我们继续分析GraphicBuffer类的成员函数lock的实现,以便可以了解一个图形缓冲区的地址是如何获得的。
class Region
{
public:
Region();
Region(const Region& rhs);
explicit Region(const Rect& rhs);
explicit Region(const void* buffer);
~Region();
Region& operator = (const Region& rhs);
inline bool isEmpty() const { return mBounds.isEmpty(); }
inline bool isRect() const { return mStorage.isEmpty(); }
inline Rect getBounds() const { return mBounds; }
inline Rect bounds() const { return getBounds(); }
// the region becomes its bounds
Region& makeBoundsSelf();
void clear();
void set(const Rect& r);
void set(uint32_t w, uint32_t h);
Region& orSelf(const Rect& rhs);
Region& xorSelf(const Rect& rhs);
Region& andSelf(const Rect& rhs);
Region& subtractSelf(const Rect& rhs);
// boolean operators, applied on this
Region& orSelf(const Region& rhs);
Region& xorSelf(const Region& rhs);
Region& andSelf(const Region& rhs);
Region& subtractSelf(const Region& rhs);
// boolean operators
const Region merge(const Rect& rhs) const;
const Region mergeExclusive(const Rect& rhs) const;
const Region intersect(const Rect& rhs) const;
const Region subtract(const Rect& rhs) const;
// boolean operators
const Region merge(const Region& rhs) const;
const Region mergeExclusive(const Region& rhs) const;
const Region intersect(const Region& rhs) const;
const Region subtract(const Region& rhs) const;
// these translate rhs first
Region& translateSelf(int dx, int dy);
Region& orSelf(const Region& rhs, int dx, int dy);
Region& xorSelf(const Region& rhs, int dx, int dy);
Region& andSelf(const Region& rhs, int dx, int dy);
Region& subtractSelf(const Region& rhs, int dx, int dy);
// these translate rhs first
const Region translate(int dx, int dy) const;
const Region merge(const Region& rhs, int dx, int dy) const;
const Region mergeExclusive(const Region& rhs, int dx, int dy) const;
const Region intersect(const Region& rhs, int dx, int dy) const;
const Region subtract(const Region& rhs, int dx, int dy) const;
// convenience operators overloads
inline const Region operator | (const Region& rhs) const;
inline const Region operator ^ (const Region& rhs) const;
inline const Region operator & (const Region& rhs) const;
inline const Region operator - (const Region& rhs) const;
inline const Region operator + (const Point& pt) const;
inline Region& operator |= (const Region& rhs);
inline Region& operator ^= (const Region& rhs);
inline Region& operator &= (const Region& rhs);
inline Region& operator -= (const Region& rhs);
inline Region& operator += (const Point& pt);
/* various ways to access the rectangle list */
typedef Rect const* const_iterator;
const_iterator begin() const;
const_iterator end() const;
/* no user serviceable parts here... */
size_t getRects(Vector
Rect const* getArray(size_t* count) const;
// add a rectangle to the internal list. This rectangle must
// be sorted in Y and X and must not make the region invalid.
void addRectUnchecked(int l, int t, int r, int b);
// flatten/unflatten a region to/from a raw buffer
ssize_t write(void* buffer, size_t size) const;
static ssize_t writeEmpty(void* buffer, size_t size);
ssize_t read(const void* buffer);
static bool isEmpty(void* buffer);
void dump(String8& out, const char* what, uint32_t flags=0) const;
void dump(const char* what, uint32_t flags=0) const;
private:
class rasterizer;
friend class rasterizer;
Region& operationSelf(const Rect& r, int op);
Region& operationSelf(const Region& r, int op);
Region& operationSelf(const Region& r, int dx, int dy, int op);
const Region operation(const Rect& rhs, int op) const;
const Region operation(const Region& rhs, int op) const;
const Region operation(const Region& rhs, int dx, int dy, int op) const;
static void boolean_operation(int op, Region& dst,
const Region& lhs, const Region& rhs, int dx, int dy);
static void boolean_operation(int op, Region& dst,
const Region& lhs, const Rect& rhs, int dx, int dy);
static void boolean_operation(int op, Region& dst,
const Region& lhs, const Region& rhs);
static void boolean_operation(int op, Region& dst,
const Region& lhs, const Rect& rhs);
static void translate(Region& reg, int dx, int dy);
static void translate(Region& dst, const Region& reg, int dx, int dy);
static bool validate(const Region& reg, const char* name);
Rect mBounds;
Vector
};
const Region Region::operator | (const Region& rhs) const {
return merge(rhs);
}
const Region Region::operator ^ (const Region& rhs) const {
return mergeExclusive(rhs);
}
const Region Region::operator & (const Region& rhs) const {
return intersect(rhs);
}
const Region Region::operator - (const Region& rhs) const {
return subtract(rhs);
}
const Region Region::operator + (const Point& pt) const {
return translate(pt.x, pt.y);
}
Region& Region::operator |= (const Region& rhs) {
return orSelf(rhs);
}
Region& Region::operator ^= (const Region& rhs) {
return xorSelf(rhs);
}
Region& Region::operator &= (const Region& rhs) {
return andSelf(rhs);
}
Region& Region::operator -= (const Region& rhs) {
return subtractSelf(rhs);
}
Region& Region::operator += (const Point& pt) {
return translateSelf(pt.x, pt.y);
}
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_UI_REGION_H
Region& Region::andSelf(const Region& rhs, int dx, int dy) {
return operationSelf(rhs, dx, dy, op_and);
}
Region& Region::andSelf(const Region& rhs) {
return operationSelf(rhs, op_and);
}
二、Region的Boolean操作
Region的Boolean操作总体主要分主要有如下几种:
enum {
op_nand = region_operator
op_and = region_operator
op_or = region_operator
op_xor = region_operator
};
下面我们主要以op_or操作为情景,分析Region如何执行这些boolean操作的。显然,Region可以与Region或Rect之间进行上述的boolean操作。当然,执行这些操作后,Region可能会变得不合法了,需要进行调整使新的Region变为合法的,整个过程就会伴随着怎样将Region从不合法的状态调整成合法的状态,这个过程会涉及到Rect的合并或分解。
下面我们将分析boolean_operation(...)函数的执行过程,因为所有的这些boolean操作都是基于此函数实现的。我们直接进入关键代码段:
size_t lhs_count;
Rect const * const lhs_rects = lhs.getArray(&lhs_count);
region_operator
region_operator
region_operator
{ // scope for rasterizer (dtor has side effects)
rasterizer r(dst);
operation(r);
}
我们将上述分为三步:
1. region_operator
这一步是初始化,为第二步做准备。传递了两个信息:Region进行的什么操作,以及操作的两个Region对象,这两个Region对象的引用被传递给了Spanner对象。region_operator这个类定义两个Region之间的boolean操作的步骤,其中定义的内部类region_rasterizer主要作用就是将一个Rect加入到当前的Region中,其中会涉及到Span与Rect之间的合并。
class region_rasterizer {
friend class region_operator;
virtual void operator()(const RECT& rect) = 0;
public:
virtual ~region_rasterizer() { };
};
2. rasterizer r(dst);
类rasterrizer是Region类中内部类,它继承自上面提到的region_rasterizer类。主要实现了其中的operator()(const RECT& rect)虚函数。它对Region进行了一些初始化,该Region将是执行boolean操作后的结果Region。
rasterizer(Region& reg)
: bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
storage.clear();
}
3. operation(r);
这步进入了实际的操作过程,将执行如下的函数:
void operator()(region_rasterizer& rasterizer) {
RECT current;
do {
SpannerInner spannerInner(spanner.lhs, spanner.rhs);
int inside = spanner.next(current.top, current.bottom);
spannerInner.prepare(inside);
do {
TYPE left, right;
int inside = spannerInner.next(current.left, current.right);
if ((op_mask >> inside) & 1) {
if (current.left < current.right &&
current.top < current.bottom) {
rasterizer(current);
}
}
} while(!spannerInner.isDone());
} while(!spanner.isDone());
}
Region& Region::operationSelf(const Region& rhs, int op) {
Region lhs(*this);
boolean_operation(op, *this, lhs, rhs);
return *this;
}
//int op, Region& dst,
const Region& lhs, const Rect& rhs,
void Region::boolean_operation(int op, Region& dst,
const Region& lhs,
const Region& rhs, int dx, int dy)
{
#if VALIDATE_REGIONS
validate(lhs, "boolean_operation (before): lhs");
validate(rhs, "boolean_operation (before): rhs");
validate(dst, "boolean_operation (before): dst");
#endif
size_t lhs_count;
Rect const * const lhs_rects = lhs.getArray(&lhs_count);
size_t rhs_count;
Rect const * const rhs_rects = rhs.getArray(&rhs_count);
region_operator
region_operator
region_operator
{ // scope for rasterizer (dtor has side effects)
rasterizer r(dst);
operation(r);
}
#if VALIDATE_REGIONS
validate(lhs, "boolean_operation: lhs");
validate(rhs, "boolean_operation: rhs");
validate(dst, "boolean_operation: dst");
#endif
#if VALIDATE_WITH_CORECG
SkRegion sk_lhs;
SkRegion sk_rhs;
SkRegion sk_dst;
for (size_t i=0 ; i
lhs_rects[i].left + dx,
lhs_rects[i].top + dy,
lhs_rects[i].right + dx,
lhs_rects[i].bottom + dy,
SkRegion::kUnion_Op);
for (size_t i=0 ; i
rhs_rects[i].left + dx,
rhs_rects[i].top + dy,
rhs_rects[i].right + dx,
rhs_rects[i].bottom + dy,
SkRegion::kUnion_Op);
const char* name = "---";
SkRegion::Op sk_op;
switch (op) {
case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
}
sk_dst.op(sk_lhs, sk_rhs, sk_op);
if (sk_dst.isEmpty() && dst.isEmpty())
return;
bool same = true;
Region::const_iterator head = dst.begin();
Region::const_iterator const tail = dst.end();
SkRegion::Iterator it(sk_dst);
while (!it.done()) {
if (head != tail) {
if (
head->left != it.rect().fLeft ||
head->top != it.rect().fTop ||
head->right != it.rect().fRight ||
head->bottom != it.rect().fBottom
) {
same = false;
break;
}
} else {
same = false;
break;
}
head++;
it.next();
}
if (head != tail) {
same = false;
}
if(!same) {
ALOGD("---\nregion boolean %s failed", name);
lhs.dump("lhs");
rhs.dump("rhs");
dst.dump("dst");
ALOGD("should be");
SkRegion::Iterator it(sk_dst);
while (!it.done()) {
ALOGD(" [%3d, %3d, %3d, %3d]",
it.rect().fLeft,
it.rect().fTop,
it.rect().fRight,
it.rect().fBottom);
it.next();
}
}
#endif
}
void Region::boolean_operation(int op, Region& dst,
const Region& lhs,
const Rect& rhs, int dx, int dy)
{
if (!rhs.isValid()) {
ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
op, rhs.left, rhs.top, rhs.right, rhs.bottom);
return;
}
#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
#else
size_t lhs_count;
Rect const * const lhs_rects = lhs.getArray(&lhs_count);
region_operator
region_operator
region_operator
{ // scope for rasterizer (dtor has side effects)
rasterizer r(dst);
operation(r);
}
#endif
}
void Region::boolean_operation(int op, Region& dst,
const Region& lhs, const Region& rhs)
{
boolean_operation(op, dst, lhs, rhs, 0, 0);
}
void Region::boolean_operation(int op, Region& dst,
const Region& lhs, const Rect& rhs)
{
boolean_operation(op, dst, lhs, rhs, 0, 0);
}
Region.h
class Region : public LightFlattenable
{
inline bool isFixedSize() const { return false; }
size_t getFlattenedSize() const;
private:
class rasterizer;
friend class rasterizer;
Vector
Region.cpp
class Region::rasterizer : public region_operator
class Region::rasterizer : public region_operator
{
Rect bounds;
Vector
Rect* head;
Rect* tail;
Vector
Rect* cur;
public:
rasterizer(Region& reg)
: bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
storage.clear();
}
RegionHelper.h
template
class region_operator
{
public:
typedef typename RECT::value_type TYPE;
static const TYPE max_value = 0x7FFFFFF;
}
if (cur->isValid() == false) {
ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
result = false;
}
if (cur->right > region_operator
ALOGE_IF(!silent, "%s: rect->right > max_value", name);
result = false;
}
if (cur->bottom > region_operator
ALOGE_IF(!silent, "%s: rect->right > max_value", name);
result = false;
}
二、Region的Boolean操作
Region的Boolean操作总体主要分主要有如下几种:
Region.cpp
enum {
op_nand = region_operator
op_and = region_operator
op_or = region_operator
op_xor = region_operator
};
RegionHelper.h
enum {
op_nand = LHS & ~RHS,
op_and = LHS & RHS,
op_or = LHS | RHS,
op_xor = LHS ^ RHS
};
Region.cpp
void Region::boolean_operation(int op, Region& dst,
const Region& lhs,
const Region& rhs, int dx, int dy)
{
region_operator
region_operator
region_operator
struct region {
RECT const* rects;
size_t count;
TYPE dx;
TYPE dy;
inline region(const region& rhs)
: rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
inline region(RECT const* r, size_t c)
: rects(r), count(c), dx(), dy() { }
inline region(RECT const* r, size_t c, TYPE dx, TYPE dy)
: rects(r), count(c), dx(dx), dy(dy) { }
};
Rect const* Region::getArray(size_t* count) const {
const_iterator const b(begin());
const_iterator const e(end());
if (count) *count = e-b;
return b;
}
Region::const_iterator Region::begin() const {
return mStorage.array();
}
Region.h
typedef Rect const* const_iterator;
const_iterator begin() const;
const_iterator end() const;
Region.cpp
Region::const_iterator Region::end() const {
size_t numRects = isRect() ? 1 : mStorage.size() - 1;
return mStorage.array() + numRects;
}
size_t lhs_count;
Rect const * const lhs_rects = lhs.getArray(&lhs_count);
RegionHelper.h
inline region_operator(int op, const region& lhs, const region& rhs)
: op_mask(op), spanner(lhs, rhs)
{
}
RegionHelper.h
private:
uint32_t op_mask;
Spanner spanner;
class Spanner : protected SpannerBase
{
friend class region_operator;
region lhs;
region rhs;
public:
inline Spanner(const region& lhs, const region& rhs)
region_rasterizer
class region_rasterizer {
friend class region_operator;
virtual void operator()(const RECT& rect) = 0;
public:
virtual ~region_rasterizer() { };
};
根据C++虚函数的多态性,这个调用实际会执行到Region::rasterizer类的 operator()(const Rect& rect) 方法,来看下它的具体实现过程:
rasterizer
virtual void operator()(const Rect& rect) {
//ALOGD(">>> %3d, %3d, %3d, %3d",
// rect.left, rect.top, rect.right, rect.bottom);
if (span.size()) {
if (cur->top != rect.top) {
flushSpan();
} else if (cur->right == rect.left) {
cur->right = rect.right;
return;
}
}
span.add(rect);
cur = span.editArray() + (span.size() - 1);
}