Androidのビュー描画はGUIシステムの中核であり、描画ビューにはバッファ、つまりキャンバスが必要なので、このバッファの割り当て処理を理解する必要があり、この記事ではこのバッファの割り当てについて説明します。
アクティビティ構造解析
Acitivtyは実際にはWMS側では単なるWindowで、WindowStateに記述され、AMS側ではActivityRecordで、その中のActivityではmWindowを保持し、それは実際にはPhoneWindowインスタンスで、PhoneWindowでは、ビューツリーであるDecorViewを保持し、このPhoneWindowインスタンスはWindowManagerImplによって管理されます。PhoneWindowの内部では、ビューツリーであるDecorViewを保持し、このPhoneWindowインスタンスはWindowManagerImplによって管理されます。WindowManagerImplは、WMSのローカルプロキシを保持するWindowManagerGlobalシングルトンをWindowManagaerImplの内部に保持します。IWindowManagerとそれによってオープンされたIWindowSessionはWMSとのセッションを担当し、一方でアプリケーション全体のウィンドウビューの管理、つまりDecorViewとViewRootImplの管理を担当します。新しく追加された各ウィンドウは、最終的にWMSのWidowStateの形で存在します。WMSはウィンドウのViewツリーの内容は気にせず、ウィンドウのサイズやスタイル、Zオーダーなどを気にするだけで、描画の処理はアプリケーションによって実行され、実際にはViewRootImpによって描画されます。そして、キャンバスの描画のためにキャンバスを必要とする前のビューツリーの描画で対応するViewRootImplはSurfaceです。次はSurfaceの周辺に話題を広げていきます。
次に、キャンバスの割り当てです。
Surface オブジェクトは、ViewRootImpl の作成時に作成されます。
private final Surface mSurface = new Surface();
次に、このSurfaceが内部で何をするのかを見てみましょう。
public class Surface implements Parcelable {
^
int mNativeObject; // package scope only for SurfaceControl access
private int mLockedObject;
private int mGenerationId; // incremented each time mNativeObject changes
private final Canvas mCanvas = new CompatibleCanvas();
public Surface() {
}
}
Surface コンストラクタは単なる空の実装で、mCanvas が本当のキャンバスである可能性があります。
public class Canvas {
/** @hide */
public int mNativeCanvas;
// may be null
private Bitmap mBitmap;
// optional field set by the caller
private DrawFilter mDrawFilter;
public Canvas() {
if (!isHardwareAccelerated()) {
// 0 means no native bitmap
mNativeCanvas = initRaster(0);
mFinalizer = new CanvasFinalizer(mNativeCanvas);
} else {
mFinalizer = null;
}
}
}
Canavaのコンストラクタにバッファ割り当てアクションがないので、新しいSurfaceは本当にバッファが割り当てられていませんが、単に空のシェルです。それを理解することができますについて考えると、タイミングを割り当てViewRootImplを知っている時間の割り当てのビューを介してWindowManagerGlobal addViewツリーは、この時間は、WMSは、ウィンドウの存在を知らないし、ビューのツリーのバッファの割り当てが確かに早すぎます。だから、いつそれを割り当てるための適切なタイミングですか?もちろん、それはあなたがformTraversalで行われ、ビューツリーを描画する準備ができたときです。
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;//viewRootマネージド・ビュー・ツリー decorView
boolean windowShouldResize = layoutRequested && windowSizeMayChange
&& ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
|| (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.width() < desiredWindowWidth && frame.width() != mWidth)
|| (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.height() < desiredWindowHeight && frame.height() != mHeight));
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null || mConfigurationChanged) {
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
}
performMeasure();
performLayout();
performDraw();
}
formTraversals関数は、比較的長いですが、私はこの記事の内容でここだけを取ると、formTraversalsの3つの主要な描画処理formMeasure、formLayoutとformDrawだけでなく、実際には、これらの3つのプロセスで、または多くのことを行う、私は単に簡単にお話しします:
ウィンドウにステータスバーがある場合は、ステータスバーの部分の幅と高さをサイズから削除します。そうでない場合は、画面全体のサイズになります。
ウィンドウのサイズが変更された場合は、同様にログに記録する必要があります。
ウィンドウのコンテンツ領域の境界が変化するかどうかを計算します。
可視性が変更された場合、同様にログに記録する必要があり、ビューツリーのサブビューに可視性が変更されたことを通知する必要があります。
条件に基づいて relayoutWindow が必要かどうかを判断し、ウィンドウサイズは relayoutWindow で再計算されます。満たす必要のある条件は、少なくとも以下のいずれかです:
<1>. Activityつまり、ViewRootクラスのメンバ変数mFirstの値はtrueに等しい。 <2>. 先に取得した変数windowShouldResizeの値はtrueに等しい、つまりアクティビティ・ウィンドウのサイズは変化する。 <3>. 先に得た変数insetsChangedの値はtrueに等しい、つまりアクティビティ・ウィンドウのコンテンツ・エリアのサイド・ライニングが変更された。 <4>. Activityウィンドウの可視性が変更され、変数viewVisibilityChangedの値がtrueに等しくなる。 <5>. Activityウィンドウのプロパティが変更され、変数paramsがWindowManagerを指すようになった。.LayoutParams
6.別セクションで説明する描画プロセスを実行します。
ウィンドウのサイズは relayoutWindow で計算され、バッファもここで割り当てられます。
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
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,
mPendingConfiguration, mSurface);
return relayoutResult;
}
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags,
int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outConfig, outSurface);//WMSのrelayoutWindowを呼び出す
return res;
}
セッションのリレーアウトは、WMS の relayoutWindow を通して行われます。
public int relayoutWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return 0;
}
WindowStateAnimator winAnimator = win.mWinAnimator;
try {
if (!win.mHasSurface) {
surfaceChanged = true;
}
//SurfaceControlの作成 キャンバスを準備する
SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
if (surfaceControl != null) {
outSurface.copyFrom(surfaceControl);
} else {
// For some reason there isn't a surface. Clear the
// caller's object so they see the same state.
outSurface.release();
}
}
}
}
frameworks/base/services/java/com/android/server/wm/WindowStateAnimator.java
SurfaceControl createSurfaceLocked() {
if (mSurfaceControl == null) {
mSurfaceControl = new SurfaceControl(
mSession.mSurfaceSession,
attrs.getTitle().toString(),
w, h, format, flags);
}
return mSurfaceControl;
}
mSurfaceControlは、WindowStateAnimatorで一度だけ作成されます。 ここでのmSessionは、実際にはアプリケーションがWMSと持つセッション、つまりIWindowSessionであり、作成時にバッファサイズ、フォーマット、マーカーを指定します。では、mSurfaceSessionとは何で、どこで作成されるのでしょうか?続きを読む
frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
//クライアント用のセッションを作成し、クライアントはこのセッションを使ってWMSと通信する。
@Override
public IWindowSession openSession(IInputMethodClient client,
IInputContext inputContext) {
Session session = new Session(this, client, inputContext);
return session;
}
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, InputChannel outInputChannel) {
win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
win.attach()
}
frameworks/base/services/java/com/android/server/wm/WindowState.java
void attach() {
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Attaching " + this + " token=" + mToken
+ ", list=" + mToken.windows);
mSession.windowAddedLocked();
}
frameworks/base/services/java/com/android/server/wm/Session.java
void windowAddedLocked() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
mService.mSessions.add(this);
}
mNumWindow++;
}
アプリケーションがセッションを開くためのWMSでは、mSurfaceSessionの作成直後ではなく、attachメソッドで作成されたWindowStateの作成後にWMSに追加されたWindowにあります。また、1つのセッションに対して1つしか作成されないため、アプリケーションは1つのSurfaceSessionしか持たないことになります。
public final class SurfaceSession {
// Note: This field is accessed by native code.
private int mNativeClient; // SurfaceComposerClient*
private static native int nativeCreate();
private static native void nativeDestroy(int ptr);
private static native void nativeKill(int ptr);
/** Create a new connection with the surface flinger. */
public SurfaceSession() {
mNativeClient = nativeCreate();
}
}
SurfaceSessionの実装は、ネイティブレイヤーですべての作業を行うのでシンプルです。
frameworks/base/core/jni/android_view_SurfaceSession.cpp
static jint nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient();//SurfaceComposerClientこれは
client->incStrong((void*)nativeCreate);
return reinterpret_cast<jint>(client);
}
実際にはSurfaceComposerClientオブジェクトを作成し、mNativeClientに配置します。このオブジェクトはSurfaceFlingerを扱うために使用されますが、SurfaceFlingerのローカルプロキシではありません。SurfaceFlingerはバッファを含むインターフェイスレイヤーの合成を担当するので、バッファの割り当てはSurfaceFlingerが行う必要があります。
public class SurfaceControl {
int mNativeObject;
public SurfaceControl(SurfaceSession session,
String name, int w, int h, int format, int flags)
throws OutOfResourcesException {
mName = name;
mNativeObject = nativeCreate(session, name, w, h, format, flags);//ネイティブレイヤーでSurfaceControlを作成する
}
}
繰り返しますが、ネイティブレイヤーで機能します。
frameworks/base/core/jni/android_view_SurfaceControl.cpp
static jint nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
jstring nameStr, jint w, jint h, jint format, jint flags) {
ScopedUtfChars name(env, nameStr);
sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
sp<SurfaceControl> surface = client->createSurface(
String8(name.c_str()), w, h, format, flags);//SurfaceHolderの作成
if (surface == NULL) {
jniThrowException(env, OutOfResourcesException, NULL);
return 0;
}
surface->incStrong((void *)nativeCreate);
return int(surface.get());//ここで、作成したSurfaceControlに戻る。
}
frameworks/base/core/jni/android_view_SurfaceSession.cpp
sp<SurfaceComposerClient> android_view_SurfaceSession_getClient(
JNIEnv* env, jobject surfaceSessionObj) {
return reinterpret_cast<SurfaceComposerClient*>(
env->GetIntField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
}
/frameworks/native/libs/gui/SurfaceComposerClient.cpp
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sm(ComposerService::getComposerService());
if (sm != 0) {
sp<ISurfaceComposerClient> conn = sm->createConnection();//サーフェスフリンガーとの接続を確立する
if (conn != 0) {
mClient = conn;//mClientサーバー側のクライアントに対応する
mStatus = NO_ERROR;
}
}
}
sp<ISurfaceComposer> ComposerService::getComposerService() {
ComposerService& instance = ComposerService::getInstance();//この例では
Mutex::Autolock _l(instance.mLock);
if (instance.mComposerService == NULL) {
ComposerService::getInstance().connectLocked();
assert(instance.mComposerService != NULL);
ALOGD("ComposerService reconnected");
}
return instance.mComposerService;
}
void ComposerService::connectLocked() {
const String16 name("SurfaceFlinger");
while (getService(name, &mComposerService) != NO_ERROR) {//サーフェスフリンガー・サービスの取得
usleep();
}
}
sp<SurfaceControl> SurfaceComposerClient::createSurface(
const String8& name,
uint32_t w,
uint32_t h,
PixelFormat format,
uint32_t flags)
{
sp<SurfaceControl> sur;
if (mStatus == NO_ERROR) {
sp<IBinder> handle;
sp<IGraphicBufferProducer> gbp;
status_t err = mClient->createSurface(name, w, h, format, flags,
&handle, &gbp);//クライアント側で対応するレイヤーを作る。
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
sur = new SurfaceControl(this, handle, gbp);//SurfaceControlを作成すると同時に、このgbpが対応するLayer BufferQueueになる。
}
}
return sur;
}
frameworks/native/services/surfaceflinger/Client.cpp
//アプリケーションはサーフェス
status_t Client::createSurface(
const String8& name,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp)
{
class MessageCreateLayer : public MessageBase {
SurfaceFlinger* flinger;
Client* client;
sp<IBinder>* handle;
sp<IGraphicBufferProducer>* gbp;
status_t result;
const String8& name;
uint32_t w, h;
PixelFormat format;
uint32_t flags;
public:
MessageCreateLayer(SurfaceFlinger* flinger,
const String8& name, Client* client,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp)
: flinger(flinger), client(client),
handle(handle), gbp(gbp),
name(name), w(w), h(h), format(format), flags(flags) {
}
status_t getResult() const { return result; }
//message最終的な処理は、このハンドラーを通して行われる
virtual bool handler() {
result = flinger->createLayer(name, client, w, h, format, flags,
handle, gbp);//作成プロセスはsfのcreateLayerで完了する。クライアントはサーフェスを作成し、これはsfのレイヤーの作成に対応する。
return true;
}
};
sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
name, this, w, h, format, flags, handle, gbp);
mFlinger->postMessageSync(msg);//リクエストはメッセージ・キューによって処理される。これは主に、sfが複数のアプリケーションに対応しており、この方法で複数のリクエストを処理するのが簡単だからである。
return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}
void MessageBase::handleMessage(const Message&) {
this->handler();//ハンドラー・メソッドを呼び出す
barrier.open();
};
status_t SurfaceFlinger::createLayer(
const String8& name,
const sp<Client>& client,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)//クライアント用のレイヤーを作成する
{
sp<Layer> layer;
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {//ノーマルとディムの2種類のレイヤーをサポートする。
case ISurfaceComposerClient::eFXSurfaceNormal:
result = createNormalLayer(client,
name, w, h, flags, format,
handle, gbp, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceDim:
result = createDimLayer(client,
name, w, h, flags,
handle, gbp, &layer);
break;
default:
result = BAD_VALUE;
break;
}
if (result == NO_ERROR) {
addClientLayer(client, *handle, *gbp, layer);//作成されたレイヤーをユーザーのキューに追加する。
setTransactionFlags(eTransactionNeeded);
}
return result;
}
status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)//ノーマルレイヤーの作成
{
// initialize the surfaces
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
case PIXEL_FORMAT_TRANSLUCENT:
format = PIXEL_FORMAT_RGBA_8888;
break;
case PIXEL_FORMAT_OPAQUE:
#ifdef NO_RGBX_8888
format = PIXEL_FORMAT_RGB_565;
#else
format = PIXEL_FORMAT_RGBX_8888;
#endif
break;
}
#ifdef NO_RGBX_8888
if (format == PIXEL_FORMAT_RGBX_8888)
format = PIXEL_FORMAT_RGBA_8888;
#endif
*outLayer = new Layer(this, client, name, w, h, flags);//Layouerの作成 BufferQueueとConsumerはLayerが最初に参照されたときに作成される。
status_t err = (*outLayer)->setBuffers(w, h, format, flags);//レイヤーのサイズとフォーマットを設定する
if (err == NO_ERROR) {
*handle = (*outLayer)->getHandle();
*gbp = (*outLayer)->getBufferQueue();//レイヤーに対応するBufferQueueを取得する
}
return err;
}
Layerのインスタンスを生成した後、Binder ServerであるgetBufferQueueを通してLayerの内部BufferQueueを取得することができます。これはレイヤーのonFirstRefで生成され、SurfaceFligner側でバッファの割り当てが行われます。同時にバッファのコンシューマでもありプロデューサでもあります。アプリケーション側はデータを埋める側なのでプロデューサの役割を果たし、SurfaceFligner側はレイヤの合成や表示用のバッファの取り出しなどを行うのでコンシューマの役割を果たします。
void Layer::onFirstRef() {//最初の参照でバッファキューを作成する
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
mBufferQueue = new SurfaceTextureLayer(mFlinger);//レイヤーのグラフィック・バッファを管理するためにBufferQueueを作る。
}
class SurfaceTextureLayer : public BufferQueue {//親クラスはBufferQueueだ。
sp<SurfaceFlinger> flinger;
public:
SurfaceTextureLayer(const sp<SurfaceFlinger>& flinger);
virtual ~SurfaceTextureLayer();
};
ここでのSurfaceTextureLayerは実際にはBufferQueueです。
sp<SurfaceControl> SurfaceComposerClient::createSurface(
const String8& name,
uint32_t w,
uint32_t h,
PixelFormat format,
uint32_t flags)
{
sp<SurfaceControl> sur;
if (mStatus == NO_ERROR) {
sp<IBinder> handle;
sp<IGraphicBufferProducer> gbp;
status_t err = mClient->createSurface(name, w, h, format, flags,
&handle, &gbp);//クライアント側で対応するレイヤーを作成する。
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
sur = new SurfaceControl(this, handle, gbp);//SurfaceControlを作成すると同時に、このgbpが対応するLayer BufferQueueになる。
}
}
return sur;
}
レイヤーが作成された後、getBufferQueueを通してIGraphicBufferProducerとして返されます。これは、このBufferQueueがクライアントのプロデューサーとして使用されることを意味します。ローカルでSurfaceControlを作成した直後は、gbdがアプリケーションプロセスに入っており、BufferQueueのローカルプロキシバインダオブジェクトになっていることに注意する必要があります。SurfaceControlは、このプロキシオブジェクトを通して作成されます。
SurfaceControl::SurfaceControl(
const sp<SurfaceComposerClient>& client,
const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbp)
: mClient(client), mHandle(handle), mGraphicBufferProducer(gbp)
{
}
ここでは、ローカルのSurfaceControlを作成し、javaレイヤーのSurfaceControlのmNativeObjectに保存しています。しかし、この時点ではバッファを割り当てているようには見えないので、上のレイヤのためにこのSurfaceControlを作成する意味はあるのでしょうか?そうです、これはバッファを割り当てるために使用されます。なぜなら、レイヤーのBufferQueueプロキシバインダであるIGraphicBufferProducerを内部に持っているからです。
public class Surface implements Parcelable {
public void copyFrom(SurfaceControl other) {
if (other == null) {
throw new IllegalArgumentException("other must not be null");
}
int surfaceControlPtr = other.mNativeObject;//ローカル・オブジェクト・ポインターをSurfaceControlにフェッチする。
if (surfaceControlPtr == 0) {
throw new NullPointerException(
"SurfaceControl native object is null. Are you using a released SurfaceControl?");
}
int newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);//SurfaceControlを使って新しいSurfaceを作成する
synchronized (mLock) {
if (mNativeObject != 0) {
nativeRelease(mNativeObject);
}
setNativeObjectLocked(newNativeObject);
}
}
}
static jint nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
jint surfaceControlNativeObj) {
sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
sp<Surface> surface(ctrl->getSurface());//surfacecontrolが管理するサーフェスを返す。
if (surface != NULL) {
surface->incStrong(&sRefBaseOwner);
}
return reinterpret_cast<jint>(surface.get());
}
sp<Surface> SurfaceControl::getSurface() const//内部で保持されているサーフェスを取得する
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == 0) {//最初は空の状態で作成される
// This surface is always consumed by SurfaceFlinger, so the
// producerControlledByApp value doesn't matter; using false.
mSurfaceData = new Surface(mGraphicBufferProducer, false);//このサーフェスはsfで消費される。
}
return mSurfaceData;
}
private void setNativeObjectLocked(int ptr) {
if (mNativeObject != ptr) {
if (mNativeObject == 0 && ptr != 0) {
mCloseGuard.open("release");
} else if (mNativeObject != 0 && ptr == 0) {
mCloseGuard.close();
}
mNativeObject = ptr;
mGenerationId += 1;
}
}
第三に、Surface
Surfaceからのバッファの取得
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
boolean scalingRequired, Rect dirty) {
Canvas canvas;
canvas = mSurface.lockCanvas(dirty);
try {
mView.draw(canvas);
} finally {
try {
surface.unlockCanvasAndPost(canvas);
}
}
return true;
}
Surfaceはまず、lockCanvasによってCanvasオブジェクトを取得します。
public Canvas lockCanvas(Rect inOutDirty)
throws Surface.OutOfResourcesException, IllegalArgumentException {
synchronized (mLock) {
mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
return mCanvas;
}
}
//jniレイヤーのサーフェスロックキャンバス呼び出し
static jint nativeLockCanvas(JNIEnv* env, jclass clazz,
jint nativeObject, jobject canvasObj, jobject dirtyRectObj) {
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));//このサーフェスはsurfaceControlによって作成される。
if (!isSurfaceValid(surface)) {
doThrowIAE(env);
return 0;
}
Rect dirtyRect;
Rect* dirtyRectPtr = NULL;
if (dirtyRectObj) {
dirtyRect.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
dirtyRect.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
dirtyRect.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
dirtyRectPtr = &dirtyRect;
}
ANativeWindow_Buffer outBuffer;//ANativeWindow_Bufferネイティブの_window.h
status_t err = surface->lock(&outBuffer, dirtyRectPtr);
if (err < 0) {
const char* const exception = (err == NO_MEMORY) ?
OutOfResourcesException :
"java/lang/IllegalArgumentException";
jniThrowException(env, exception, NULL);
return 0;
}
// Associate a SkCanvas object to this surface
env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format);//skCanvasはサーフェスに関連付けられている。
SkBitmap bitmap;//キャンバスを準備する
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr);//キャンバスのサイズとフォーマットを設定する
if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
bitmap.setAlphaType(kOpaque_SkAlphaType);
}
if (outBuffer.width > 0 && outBuffer.height > 0) {
bitmap.setPixels(outBuffer.bits);//キャンバスのバッファを設定する
} else {
// be safe with an empty bitmap.
bitmap.setPixels(NULL);
}
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));//キャンバスをネイティブのキャンバスとして上のレイヤーに戻す。
swapCanvasPtr(env, canvasObj, nativeCanvas);
if (dirtyRectPtr) {
nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
}
if (dirtyRectObj) {
env->SetIntField(dirtyRectObj, gRectClassInfo.left, dirtyRect.left);
env->SetIntField(dirtyRectObj, gRectClassInfo.top, dirtyRect.top);
env->SetIntField(dirtyRectObj, gRectClassInfo.right, dirtyRect.right);
env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
}
sp<Surface> lockedSurface(surface);
lockedSurface->incStrong(&sRefBaseOwner);
return (int) lockedSurface.get();
}
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
ANativeWindowBuffer* out;// ウィンドウで定義.h
int fenceFd = -1;
status_t err = dequeueBuffer(&out, &fenceFd);//バッファの割り当て
}
//グラフィックス・バッファを要求する
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
ATRACE_CALL();
Mutex::Autolock lock(mMutex);
int buf = -1;
int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight;
sp<Fence> fence;
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
reqW, reqH, mReqFormat, mReqUsage);
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {//未割り当てまたは再マップが必要
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);//Surfaceグラフィックス・バッファは、requestBufferを呼び出すことでSurfaceプロセスにマッピングされる。
if (result != NO_ERROR) {
ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
return result;
}
}
*buffer = gbuf.get();//バッファを取得する
return OK;
}
バッファはまずmGraphicBufferProducerを介してdequeueBufferで割り当てられ、実際にはBufferQueueで行われます。バッファを作成し、そのバッファをSurfaceが存在するプロセスにマッピングします。これでアプリケーションを使用できるようになります。
引き出されたバッファーの提出
public void unlockCanvasAndPost(Canvas canvas) {
synchronized (mLock) {
nativeUnlockCanvasAndPost(mLockedObject, canvas);
nativeRelease(mLockedObject);
mLockedObject = 0;
}
}
同様に、アプリケーション層はバッファのロックを解除し、描画後にバッファを BufferQueue に送信する必要があります。
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
jint nativeObject, jobject canvasObj) {
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
if (!isSurfaceValid(surface)) {
return;
}
// detach the canvas from the surface
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
swapCanvasPtr(env, canvasObj, nativeCanvas);//キャンバスとサーフェスを分離する
// unlock surface
status_t err = surface->unlockAndPost();//結果を提出する
if (err < 0) {
doThrowIAE(env);
}
}
status_t Surface::unlockAndPost()//ロックされたバッファを提出する
{
if (mLockedBuffer == 0) {
ALOGE("Surface::unlockAndPost failed, no locked buffer");
return INVALID_OPERATION;
}
status_t err = mLockedBuffer->unlock();
err = queueBuffer(mLockedBuffer.get(), -1);//このバッファ・キューを設定する
mPostedBuffer = mLockedBuffer;//lockedレイヤーのバッファは
return err;
}
SurfaeのunlockAndPostはqueueBufferメソッドを呼び出し、バッファのコミットを完了させます。
int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {//buffer queue消費
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);//GBPの
return err;
}
mGraphicBufferProducerを通してこのバッファをキューに入れ、この時点でプロデューサのタスクは完了し、SurfaceFlingerであるConsumerのレイヤ側はこの効果的なバッファを聞き、表示レイヤを合成する準備ができ、最終的に図面が画面に表示されます。




