android graphic (8) - surface 신청 GraphicBuffer 과정
48778 단어 android-graphic
surface 의 dequeue Buffer 함수
Surface 호출 hookdequeueBuffer () 는 그래 픽 버퍼 를 신청 합 니 다.
int Surface::hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer, int* fenceFd) {
Surface* c = getSelf(window);
return c->dequeueBuffer(buffer, fenceFd);
}
그 중
typedef struct android_native_base_t
{
/* a magic value defined by the actual EGL native type */
int magic;
/* the sizeof() of the actual EGL native type */
int version;
void* reserved[4];
/* reference-counting interface */
void (*incRef)(struct android_native_base_t* base);
void (*decRef)(struct android_native_base_t* base);
} android_native_base_t;
typedef struct native_handle
{
int version; /* sizeof(native_handle_t) */
int numFds; /* number of file-descriptors at &data[0] */
int numInts; /* number of ints at &data[numFds] */
int data[0]; /* numFds + numInts ints */
} native_handle_t;
typedef const native_handle_t* buffer_handle_t;
typedef struct ANativeWindowBuffer
{
struct android_native_base_t common;
int width;
int height;
int stride;
int format;
int usage;
void* reserved[2];
//
buffer_handle_t handle;
void* reserved_proc[8];
} ANativeWindowBuffer_t;
도형 의 buffer 는 사실 핵심 은
buffer_handle_t handle;
이 handle 입 니 다. 지난 절 에 분석 한 바 와 같이 mmap 를 통 해 돌아 온 fd, size, map 에서 프로 세 스 메모리 의 시작 주소 입 니 다.int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
ATRACE_CALL();
ALOGV("Surface::dequeueBuffer");
Mutex::Autolock lock(mMutex);
int buf = -1;
int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight;
sp fence;
//① buffer
// mGraphicBufferProducer BufferQueue Bp
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
reqW, reqH, mReqFormat, mReqUsage);
if (result < 0) {
ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
"failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
result);
return result;
}
sp& gbuf(mSlots[buf].buffer);
// this should never happen
ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
freeAllBuffers();
}
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
//②
// surfaceflinger ,BufferQueue
// binder ,Surface
// requestBuffer Surface
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
if (result != NO_ERROR) {
ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
return result;
}
}
if (fence->isValid()) {
*fenceFd = fence->dup();
if (*fenceFd == -1) {
ALOGE("dequeueBuffer: error duping fence: %d", errno);
// dup() should never fail; something is badly wrong. Soldier on
// and hope for the best; the worst that should happen is some
// visible corruption that lasts until the next frame.
}
} else {
*fenceFd = -1;
}
//sp<> get
*buffer = gbuf.get();
return OK;
}
위의 dequeue Buffer () 는 주로 2 부분 을 포함한다. 1. Buffer Queue 에 버퍼 를 신청 합 니 다.2. Buffer Queue 와 Surface 가 같은 프로 세 스 에 있 지 않 기 때문에 request Buffer 로 Buffer Queue 프로 세 스 의 그래 픽 버퍼 를 surface 가 있 는 프로 세 스 (익명 공유 메모리) 에 동시에 표시 해 야 합 니 다.
Buffer Queue 에 메모리 신청
Surface 클래스 에는 32 개의 Buffer Slot 가 있 는 mSlots 배열 이 있 습 니 다.
//NUM_BUFFER_SLOTS 32
BufferSlot mSlots[NUM_BUFFER_SLOTS];
BufferSlot 구 조 는 다음 과 같 습 니 다. 신청 한 그래 픽 버퍼 를 저장 합 니 다.
struct BufferSlot {
//
sp buffer;
Region dirtyRegion;
};
//int buf = -1;
// buf int , mSlots
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
reqW, reqH, mReqFormat, mReqUsage);
mGraphicBufferProducer->dequeueBuffer
더 나 아가 BpGraphicBufferProducer
의 dequeueBuffer
함 수 를 호출 합 니 다.class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
{
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(async);
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
data.writeInt32(usage);
// BpBinder buffer data, BBinder
status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
}
//BBinder BpBinder int, , handle
*buf = reply.readInt32();
bool nonNull = reply.readInt32();
if (nonNull) {
*fence = new Fence();
reply.read(**fence);
}
result = reply.readInt32();
return result;
}
}
client 측, 즉 BpGraphic Buffer Producer 측 을 통 해 DEQUEUEBUFFER 이후 핵심 은 하나
*buf = reply.readInt32();
만 되 돌 아 왔 다.보아하니 BufferQueue 에 도 mSlots 와 대응 하 는 배열 이 있 을 것 입 니 다. 32 개 입 니 다. 일일이 대응 하고 server 측, 즉 Bn 측 을 계속 분석 하 겠 습 니 다.status_t BnGraphicBufferProducer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
case DEQUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool async = data.readInt32();
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
uint32_t format = data.readInt32();
uint32_t usage = data.readInt32();
int buf;
sp<Fence> fence;
// BufferQueue dequeueBuffer
// int buf
int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage);
// buf fence parcel, binder client
reply->writeInt32(buf);
reply->writeInt32(fence != NULL);
if (fence != NULL) {
reply->write(*fence);
}
reply->writeInt32(result);
return NO_ERROR;
}
Buffer Queue 에 도 역시 mSlots 배열 이 있 습 니 다. 32 개의 Buffer Slot 가 있 습 니 다.
BufferSlot mSlots[NUM_BUFFER_SLOTS];
그러나 BufferSlot 구 조 는 Surface 와 다 릅 니 다. BufferQueue 의 핵심 직책 은 그래 픽 버퍼 를 관리 하 는 것 이기 때문에 모든 버퍼 의 상태 (FREE, DEQUEUED, QUEUED, ACQUIRED) 등 을 기록 해 야 합 니 다. 생산자 소비자 에 대해 서 는 자세히 설명 하지 않 습 니 다.
struct BufferSlot {
BufferSlot()
: mEglDisplay(EGL_NO_DISPLAY),
mBufferState(BufferSlot::FREE),
mRequestBufferCalled(false),
mFrameNumber(0),
mEglFence(EGL_NO_SYNC_KHR),
mAcquireCalled(false),
mNeedsCleanupOnRelease(false) {
}
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
// if no buffer has been allocated.
sp mGraphicBuffer;
// mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects.
EGLDisplay mEglDisplay;
// BufferState represents the different states in which a buffer slot
// can be. All slots are initially FREE.
enum BufferState {
// FREE indicates that the buffer is available to be dequeued
// by the producer. The buffer may be in use by the consumer for
// a finite time, so the buffer must not be modified until the
// associated fence is signaled.
//
// The slot is "owned" by BufferQueue. It transitions to DEQUEUED
// when dequeueBuffer is called.
FREE = 0,
// DEQUEUED indicates that the buffer has been dequeued by the
// producer, but has not yet been queued or canceled. The
// producer may modify the buffer's contents as soon as the
// associated ready fence is signaled.
//
// The slot is "owned" by the producer. It can transition to
// QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
DEQUEUED = 1,
// QUEUED indicates that the buffer has been filled by the
// producer and queued for use by the consumer. The buffer
// contents may continue to be modified for a finite time, so
// the contents must not be accessed until the associated fence
// is signaled.
//
// The slot is "owned" by BufferQueue. It can transition to
// ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
// queued in asynchronous mode).
QUEUED = 2,
// ACQUIRED indicates that the buffer has been acquired by the
// consumer. As with QUEUED, the contents must not be accessed
// by the consumer until the fence is signaled.
//
// The slot is "owned" by the consumer. It transitions to FREE
// when releaseBuffer is called.
ACQUIRED = 3
};
// mBufferState is the current state of this buffer slot.
BufferState mBufferState;
// mRequestBufferCalled is used for validating that the producer did
// call requestBuffer() when told to do so. Technically this is not
// needed but useful for debugging and catching producer bugs.
bool mRequestBufferCalled;
// mFrameNumber is the number of the queued frame for this slot. This
// is used to dequeue buffers in LRU order (useful because buffers
// may be released before their release fence is signaled).
uint64_t mFrameNumber;
// mEglFence is the EGL sync object that must signal before the buffer
// associated with this buffer slot may be dequeued. It is initialized
// to EGL_NO_SYNC_KHR when the buffer is created and may be set to a
// new sync object in releaseBuffer. (This is deprecated in favor of
// mFence, below.)
EGLSyncKHR mEglFence;
// mFence is a fence which will signal when work initiated by the
// previous owner of the buffer is finished. When the buffer is FREE,
// the fence indicates when the consumer has finished reading
// from the buffer, or when the producer has finished writing if it
// called cancelBuffer after queueing some writes. When the buffer is
// QUEUED, it indicates when the producer has finished filling the
// buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
// passed to the consumer or producer along with ownership of the
// buffer, and mFence is set to NO_FENCE.
sp mFence;
// Indicates whether this buffer has been seen by a consumer yet
bool mAcquireCalled;
// Indicates whether this buffer needs to be cleaned up by the
// consumer. This is set when a buffer in ACQUIRED state is freed.
// It causes releaseBuffer to return STALE_BUFFER_SLOT.
bool mNeedsCleanupOnRelease;
};
Buffer Queue 의 dequeue Buffer 함수,
status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
ATRACE_CALL();
ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
status_t returnFlags(OK);
EGLDisplay dpy = EGL_NO_DISPLAY;
EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
{ // Scope for the lock
Mutex::Autolock lock(mMutex);
if (format == 0) {
format = mDefaultBufferFormat;
}
// turn on usage bits the consumer requested
usage |= mConsumerUsageBits;
int found = -1;
bool tryAgain = true;
while (tryAgain) {
if (mAbandoned) {
ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
const int maxBufferCount = getMaxBufferCountLocked(async);
if (async && mOverrideMaxBufferCount) {
// FIXME: some drivers are manually setting the buffer-count (which they
// shouldn't), so we do this extra test here to handle that case.
// This is TEMPORARY, until we get this fixed.
if (mOverrideMaxBufferCount < maxBufferCount) {
ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override");
return BAD_VALUE;
}
}
// Free up any buffers that are in slots beyond the max buffer
// count.
for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
assert(mSlots[i].mBufferState == BufferSlot::FREE);
if (mSlots[i].mGraphicBuffer != NULL) {
freeBufferLocked(i);
returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
}
}
// look for a free buffer to give to the client
found = INVALID_BUFFER_SLOT;
int dequeuedCount = 0;
int acquiredCount = 0;
//① mSlots FREE , mFrameNumber
for (int i = 0; i < maxBufferCount; i++) {
const int state = mSlots[i].mBufferState;
switch (state) {
case BufferSlot::DEQUEUED:
dequeuedCount++;
break;
case BufferSlot::ACQUIRED:
acquiredCount++;
break;
case BufferSlot::FREE:
/* We return the oldest of the free buffers to avoid
* stalling the producer if possible. This is because
* the consumer may still have pending reads of the
* buffers in flight.
*/
if ((found < 0) ||
mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
found = i;
}
break;
}
}
// clients are not allowed to dequeue more than one buffer
// if they didn't set a buffer count.
if (!mOverrideMaxBufferCount && dequeuedCount) {
ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
"setting the buffer count");
return -EINVAL;
}
// See whether a buffer has been queued since the last
// setBufferCount so we know whether to perform the min undequeued
// buffers check below.
if (mBufferHasBeenQueued) {
// make sure the client is not trying to dequeue more buffers
// than allowed.
const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
const int minUndequeuedCount = getMinUndequeuedBufferCount(async);
if (newUndequeuedCount < minUndequeuedCount) {
ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
"exceeded (dequeued=%d undequeudCount=%d)",
minUndequeuedCount, dequeuedCount,
newUndequeuedCount);
return -EBUSY;
}
}
// If no buffer is found, wait for a buffer to be released or for
// the max buffer count to change.
tryAgain = found == INVALID_BUFFER_SLOT;
//② buffer free ,
if (tryAgain) {
// return an error if we're in "cannot block" mode (producer and consumer
// are controlled by the application) -- however, the consumer is allowed
// to acquire briefly an extra buffer (which could cause us to have to wait here)
// and that's okay because we know the wait will be brief (it happens
// if we dequeue a buffer while the consumer has acquired one but not released
// the old one yet -- for e.g.: see GLConsumer::updateTexImage()).
if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) {
ST_LOGE("dequeueBuffer: would block! returning an error instead.");
return WOULD_BLOCK;
}
mDequeueCondition.wait(mMutex);
}
}
if (found == INVALID_BUFFER_SLOT) {
// This should not happen.
ST_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY;
}
const int buf = found;
*outBuf = found;
ATRACE_BUFFER_INDEX(buf);
const bool useDefaultSize = !w && !h;
if (useDefaultSize) {
// use the default size
w = mDefaultWidth;
h = mDefaultHeight;
}
//③ buf DEQUEUED
mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
const sp& buffer(mSlots[buf].mGraphicBuffer);
//④ buffer , , buffer ,
// returnFlags BUFFER_NEEDS_REALLOCATION
if ((buffer == NULL) ||
(uint32_t(buffer->width) != w) ||
(uint32_t(buffer->height) != h) ||
(uint32_t(buffer->format) != format) ||
((uint32_t(buffer->usage) & usage) != usage))
{
mSlots[buf].mAcquireCalled = false;
mSlots[buf].mGraphicBuffer = NULL;
mSlots[buf].mRequestBufferCalled = false;
mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
mSlots[buf].mFence = Fence::NO_FENCE;
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
}
if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) {
ST_LOGE("dequeueBuffer: about to return a NULL fence from mSlot. "
"buf=%d, w=%d, h=%d, format=%d",
buf, buffer->width, buffer->height, buffer->format);
}
dpy = mSlots[buf].mEglDisplay;
eglFence = mSlots[buf].mEglFence;
*outFence = mSlots[buf].mFence;
mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
mSlots[buf].mFence = Fence::NO_FENCE;
} // end lock scope
//⑤ buffer , mGraphicBufferAlloc buffer
if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
status_t error;
sp graphicBuffer(
mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage, &error));
if (graphicBuffer == 0) {
ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed");
return error;
}
{ // Scope for the lock
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
mSlots[*outBuf].mFrameNumber = ~0;
mSlots[*outBuf].mGraphicBuffer = graphicBuffer;
}
}
if (eglFence != EGL_NO_SYNC_KHR) {
EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000);
// If something goes wrong, log the error, but return the buffer without
// synchronizing access to it. It's too late at this point to abort the
// dequeue operation.
if (result == EGL_FALSE) {
ST_LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
ST_LOGE("dequeueBuffer: timeout waiting for fence");
}
eglDestroySyncKHR(dpy, eglFence);
}
ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf,
mSlots[*outBuf].mFrameNumber,
mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
return returnFlags;
}
위의 함 수 는 주로 5 부분 을 포함한다. 1. 먼저 남 은 buffer 를 찾 아야 한다. mSlots 에서 상 태 는 FREE 이 고 mFrameNumber 값 이 가장 작은 것 을 선택해 야 한다.2. 모든 buffer 가 free 가 아니라면 기다린다.3. 찾 은 buf 에 대응 하 는 상 태 를 DEQUEUED 로 변경 합 니 다.4.
const sp& buffer(mSlots[buf].mGraphicBuffer)
찾 은 buf 의 mGraphic Buffer 를 가 져 옵 니 다. buffer 가 비어 있 거나 비어 있 지 않 지만 buffer 의 크기 가 변 하면 returnFlags 에 BUFFER 를 추가 합 니 다.NEEDS_REALLCATION 재 신청 표지;5. buffer 가 다시 신청 해 야 한다 면 mGraphicBufferAlloc 를 호출 하여 buffer 를 만 듭 니 다. mGraphicBufferAlloc 의 생 성 은 앞의 에 소개 되 어 있 습 니 다. mGraphicBufferAlloc 가 버퍼 를 만 드 는 과정 을 계속 분석 합 니 다. sp graphicBuffer(
mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage, &error));
BpGraphicBufferAlloc ,
class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
{
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage, status_t* error) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
data.writeInt32(usage);
remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply);
sp<GraphicBuffer> graphicBuffer;
status_t result = reply.readInt32();
if (result == NO_ERROR) {
//client replay surfaceflinger GraphicBuffer
graphicBuffer = new GraphicBuffer();
result = reply.read(*graphicBuffer);
// reply.readStrongBinder();
// here we don't even have to read the BufferReference from
// the parcel, it'll die with the parcel.
}
*error = result;
return graphicBuffer;
}
}
BnGraphicBufferAlloc,
status_t BnGraphicBufferAlloc::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
case CREATE_GRAPHIC_BUFFER: {
CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
PixelFormat format = data.readInt32();
uint32_t usage = data.readInt32();
status_t error;
// GraphicBufferAlloc createGraphicBuffer ,
sp<GraphicBuffer> result =
createGraphicBuffer(w, h, format, usage, &error);
reply->writeInt32(error);
if (result != 0) {
//GraphicBuffer , client
reply->write(*result);
// We add a BufferReference to this parcel to make sure the
// buffer stays alive until the GraphicBuffer object on
// the other side has been created.
// This is needed so that the buffer handle can be
// registered before the buffer is destroyed on implementations
// that do not use file-descriptors to track their buffers.
reply->writeStrongBinder( new BufferReference(result) );
}
return NO_ERROR;
} break;
}
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage, status_t* error) {
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
status_t err = graphicBuffer->initCheck();
*error = err;
if (err != 0 || graphicBuffer->handle == 0) {
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
"failed (%s), handle=%p",
w, h, strerror(-err), graphicBuffer->handle);
return 0;
}
return graphicBuffer;
}
GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
PixelFormat reqFormat, uint32_t reqUsage)
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR)
{
width =
height =
stride =
format =
usage = 0;
handle = NULL;
mInitCheck = initSize(w, h, reqFormat, reqUsage);
}
위의 함 수 는 주로 Graphic Buffer Alloc 를 이용 하여 그래 픽 버퍼 를 분배 하 는 과정 입 니 다. 중간 에 gralloc 모듈 과 Graphic Buffer 의 직렬 화 와 반 직렬 화, 반 직렬 화 unflatten () 을 사용 할 때 gralloc 를 사용 하여 Buffer Queue 가 있 는 프로 세 스 를 surfaceflinger 에서 신청 한 메모리 map 에 등록 합 니 다 (익명 공유 메모리).여기 서 BufferQueue 에 메모리 가 신청 되 었 습 니 다. Surface 에 int 배열 아래 표 시 를 되 돌려 주 었 습 니 다. 이때 Surface 는 도형 버퍼 와 관련 된 것 을 얻 지 못 한 것 같 습 니 다.신청 한 메모 리 는 BufferQueue 가 있 는 프로 세 스 이기 때문에 다음 에 request Buffer 를 호출 하여 buffer 를 Surface 가 있 는 프로 세 스 에 표시 해 야 합 니 다.
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
Surface RequestBuffer
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
..........
sp& gbuf(mSlots[buf].buffer);
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
// , BufferQueue GraphicBuffer
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
if (result != NO_ERROR) {
ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
return result;
}
}
......
}
위 에서 호출
mGraphicBufferProducer->requestBuffer(buf, &gbuf)
, BpGraphic Buffer Producer,class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
{
virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(bufferIdx);
//
status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
}
bool nonNull = reply.readInt32();
if (nonNull) {
//GraphicBuffer , Surface map
*buf = new GraphicBuffer();
reply.read(**buf);
}
result = reply.readInt32();
return result;
}
}
위의 코드 를 통 해 알 수 있 듯 이 requestBuffer 의 핵심 은 Surface 가 하나의 배열 아래 표 시 를 전달 한 다음 에 BufferQueue 에 대응 하 는 배열 아래 표 시 된 Graphic Buffer 대상 을 Surface 에 투사 한 다음 에 해당 하 는 배열 에 저장 하 는 것 입 니 다. 이 두 배열 은 일일이 대응 합 니 다.다시 말 하면 진정 으로 그래 픽 버퍼 를 신청 하 는 것 은 surface flinger 프로 세 스 입 니 다. Graphic BufferAlloc 대상 은 surface flinger 에서 new 로 나 온 다음 에 BufferQueue 와 Surface 의 그래 픽 버퍼 는 모두 Graphic Buffer 의 직렬 화 와 반 직렬 화 를 통 해 새로 매 핑 되 었 기 때 문 입 니 다.