水煮肉片的家常做法,浅显易懂Android BufferQueue,一剪梅简谱

频道:趣闻中心 日期: 浏览:271

1. 布景

对事务开发来说,无法接触到BufferQueue,乃至不知道BufferQueue是什么东西。对体系来说,BufferQueue是很重要的传递数据的组件,Android显现体系依赖于BufferQueue,只需显现内容到“屏幕”(此处指笼统的屏幕,有时分还能够包括编码器),就必定需求用到BufferQueue,能够说在显现/播放器相关的领会中,BufferQueue无处不在。即便直接调用Opengl ES来制作,底层仍然需求BufferQueue才干显现到屏幕上。

弄理解BufferQueue,不只能够增强对Android体系的了解,还能够弄理解/排查相关的问题,如为什么Mediacodec调用dequeueBuffer老是回来-1?为什么一般V秦梦瑶和范军是啥联系iew的draw办法直接制作内容即可,SurfaceView在draw结束后还需求unlockCanvasAndPost?

注:本文剖析的代码来自于Android6.0.1。

2. BufferQueue内部运作办法

BufferQueue是Android显现体系的中心,它的规划哲学是出产者-顾客模型,只需往BufferQueue中填充数据,则认为是出产者,只需从BufferQueue中获取数据,则认为是顾客。有时分同一个类,在不同的场景下既或许是出产者也有或许是顾客。如SurfaceFlinger,在组成并显现UI内容时,UI元素作为出产者出产内容,SurfaceFlinger水煮肉片的家常做法,深入浅出Android BufferQueue,一剪梅简谱作为顾客消费这些内容。而在截屏时,SurfaceFlinger又作为出产者将当时组成显现的UI内容填充到另一个BufferQueue,截屏运用此刻作为顾客从BufferQueue中获取数据并出产截图。

以下是Android官网对其的介绍:

以下是常见的BufferQueue运用进程:

当然图形数据的出产者能够不必等候BufferQueue的回调再出产数据,而是一向出产数据然后入队到BufferQueue,直到BufferQueue满停止。图形数据的李金羽和陈蓉结婚照顾客也能够不必等BufferQueue的回调告诉,每次都从BufferQueue中测验获取数据,获取失利则测验,仅仅这样功率比较低,需求不断的轮训BufferQueue(由于BufferQueue有同步堵塞和非同步堵塞两种机种,在非同步堵塞机制下获取数据失利不会堵塞该线程直到有数据才唤醒该线程,而是直接回来-1)。

一起运用BufferQueue的出产者和顾客往往处在不同的进程,BufferQueue内部运用同享内存和Binder在不同的进程传递数据,削减数据复制进步功率。

和BufferQueue有关的几个类分别是:

BufferQueue顶用BufferSlot来存储GraphicBuffer,运用数组来存储一系列BufferSlot,数组默许巨细为64。

GraphicBuffer用BufferState来表明其状况,有以下状况:

为什么需求这些状况呢? 假定不需求这些状况,完结一个简略的BufferQueue,假定是如下完结:

BufferQueue{ vector<GraphicBuffer> slots; void push(GraphicBuffer slot){ slots.push(slot); } GraphicBuffer pull(){ return slots.pull(); }}

出产者出产完数据后,经过调用BufferQueue水煮肉片的家常做法,深入浅出Android BufferQueue,一剪梅简谱的push函数将数据刺进到vector中。顾客调用BufferQueue的pull函数出队一个Buffer数据。

上述完结的问题在于,出产者每次都需求自行创立GraphicBuffer,而顾客每次消费完数据后的GraphicBuffer就被开释了,GraphicBuffer没有得到循环运用。而在Android中,由于BufferQueue的出产者-顾客往往处于不同的进程,GraphicBuffer内部是需求经过同享内存来衔接生成者-顾客进程的,每次创立GraphicBuffer,即意味着需求创立同享内存,功率较低。

而BufferQueue顶用BufferState来表明GraphicBuffer的状况则处理了这个问题。每个GraphicBuffer都有当时的状况,经过保护GraphicBuffer的状况,完结GraphicBuffer的复用。

由于BufferQueue内部完结是BufferQueueCore,下文均用BufferQueueCore替代BufferQueue。先介绍下BufferQueueCore内部相应的数据结构,再介绍BufferQueue的状况改变进程和出产-消费进程。

以下是Buffer的入队/出队操作和BufferState的状况改变的进程,这儿只介绍非同步堵塞形式。

2.1 BufferQueueCore内部数据结构

中心数据结构如下:

BufferQueueDefs::SlotsType mSlots:用数组寄存的Slot,数组默许巨细为BufferQueueDefs::NUM_BUFFER_SLOTS,详细是64,代表一切的Slotstd::set<int> mFreeSlots:当时一切的状况为FREE的Slot,这些Slot没有相关上详细的GraphicBuffer,后续用的时分还需求相关上GraphicBufferstd::list&le商赢t;int> mFreeBuffers:当时一切的状况为FREE的Slot,这些Slot现已相关上详细的GraphicBuffer,能够直接运用Fifo mQueue:一个先进先出行列,保存了出产者出产的数据

在BufferQueueCore初始化时,由于此刻行列中没有入队任何数据,依照上面的介绍,此刻mFreeSlots应该包括一切的Slot,元素巨细和mSlots共同,初始化代码如下:

for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { mFreeSlots.insert(slot); }

2.2 出产者dequeueBuffer

当出产者能够出产图形数据时,首先向BufferQueue中请求一块GraphicBuffer。调用函数是BufferQueueProducer.dequeueBuffer,假如当时BufferQueue中有可用的GraphicBuffer,则回来其对用的索引,假如不存在,则回来-1,代码在BufferQueueProducer,流程如下:

status_t BufferQueueProducer::dequeueBuffer(int *outSlot, sp<android::Fence> *outFence, bool async, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { //1. 寻觅可用的Slot,可用指Buffer状况为FREE status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, &found, &returnFlags); if (status != NO_ERROR) { return status; }

//2.找到可用的Slot,将Buffer状况设置为DEQUEUED,由于进程1找到的Slot状况为FREE,因而这一步完结了FREE到DEQUEUED的状况切换 *outSlot = found; ATRACE_BUFFER_INDEX(found); attachedByConsumer = mSlots[found].mAttachedByConsumer; mSlots[found].mBufferState = BufferSlot::DEQUEUED;

//3. 找到的Slot假如需求请求GraphicBuffer,则请求GraphicBuffer,这儿采用了懒加载机制,假如内存没有请求,请求内寄存在出产者来处理 if (returnFlags & BUFFER_NEEDS_REALLOCATION) { status_t error; sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(width, height, format, usage, &error)); graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; }}

要害韦小宝之娇妻成群在于寻觅可用Slot,waitForFreeSlotThenRelock的流程如下:

sta水煮肉片的家常做法,深入浅出Android BufferQueue,一剪梅简谱tus_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, bool async, int* found, status_t* returnFlags) const { //1. mQueue 是否太多 bool tooManyBuffers = mCore->mQueue.size()> static_cast<size_t>(maxBufferCount); if (tooManyBuffers) { } else {

// 2. 先查找mFreeBuffers中是否有可用的,由2.1介绍可知,mFreeBuffers中的元素相关了GraphicBuffer,直接可用 if (!mCore->mFreeBuffers.empty()) { auto slot = mCore->mFreeBuffers.begin(); *found = *slot; mCore->mFreeBuffers.erase(slot); } else if (mCore->mAllowAllocation && !mCore->mFreeSlots.empty()) {

// 3. 再查找mFreeSlots中是否有可用的,由2.1可知,初始化时会填充溢这个列表,因而第一次调用必定不会为空。一起用这个列表中的元素需求相关上GraphicBuffer才干够直接运用,相关的进程由外层函数来完结 auto slot = mCore->mFreeSlots.begin(); // Only return free slots up to the max buffer count if (*slot < maxBufferCount) { *found = *slot; mCore->mFreeSlots.erase(slot); } } } tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || tooMa水煮肉片的家常做法,深入浅出Android BufferQueue,一剪梅简谱nyBuffers; //4. 假如找不到可用的Slot或许Buffer太多(同步堵塞形式下),则或许需求等 if (tryAgain) { if (mCore->mDequeueBufferCannotBlock && (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { return WOULD_BLOCK; } mCore->mDequeueCondition.wait(mCore->mMutex); }}waitForFreeSlotThenRelock函数会测验寻觅一个可用的Slot,可用的Slot状况必定是FREE(由于是从两个FREE状况的列表中获取的),然后dequeueBuffer将状况改变为DEQUEUED,即完结了状况的改变。

waitForFreeSlotThenRelock回来可用的Slot分为两种:

小结dequeueBuffer:测验找到一个Slot,并完结Slot与GraphicBuffer的相关(假如需求),然后将Slot的状况由FREE改变成DEQUEUED。回来Slot在BufferQueueCore中mSlots对应的索引。

2.3 出产者requestBuffer

dequeueBuffer函数获取到了可用Slot的索引后,经过requestBuffer获取到对应的GraphicBuffer。流程如下:

status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { // 1. 判别slot参数是否合法 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { BQ_LOGE("requestBuffer: slot index %d out of range [0, %d)", slot, BufferQueueDefs::NUM_BUFFER_SLOTS); return BAD_VALUE; } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { BQ_LOGE("requestBuffer: slot %d is not owned by the producer " "(state = %d)", slot, mSlots[slot].mBufferState); return BAD_VALUE; } //2. 将mRequestBufferCalled置为true mSlots[slot].mRequestBufferCalled = true; *buf = mSlots[slot].mGraphicBuffer; return NO_ERROR;}

这一步不是有必要的。事务层能够直接经过Slot的索引获取到对应的GraphicBuffer。

2.4 出产者queueBuffer

上文dequeueBuffer获取到一个Slot后,就能够在Slot对应的GraphicBuffer上完结图画数据的出产了,能够是View的主线程Draw进程,也能够是SurfaceView的子线程制作进程d2565,乃至能够是MediaCodec的解码进程。

填充完图画数据后,需求将Slot入队BufferQueueCore(数据写完了,能够传给出产者-顾客行列,让顾客来消费了),入队调用queueBuffer函数。queueBuffer的流程如下:

status_t BufferQueueProducer::queueBuffer(int slot, const QueueBufferInput &input, QueueBufferOutput *output) { // 1. 先判别传入的Slot是否合法 if (slot < 0 || slot >= maxBufferCount) { BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)", slot, maxBufferCount); return BAD_VALUE; }

//2. 将Buffer状况改变成QUEUED,此步完结了Buffer的状况由DEQUEUED到QUEUED的进程 mSlots[slot].mFence = fence; mSlots[slot].mBufferState = BufferSlot::QUEUED; ++mCore->mFrameCounter; mSlots[slot].mFrameNumber = mCore->mFrameCounter;

//3. 入队mQueue if (mCore->mQueue.empty()) { mCore->mQueue.push_back(item); frameAvailableListener = mCore->mConsumerListener; }

// 4. 回调frameAvailableListener,奉告顾客有数据入队了 if (frameAvailableListener != NULL) { frameAvailableListener->onFrameAvailable(item); } else if (frameReplacedListener != NULL) { frameReplacedListener->onFrameReplaced(item); }}

从上面的注释能够看到,queueBuffer的首要进程如下:

小结queueBuffer:将Slot的状况改变成QUEUED,并添加到mQueue中,终究告诉顾客有数据入队

2.5 顾客acquireBuffer

在顾客接收到onFrameAvailable回调时或许顾客自动想要消费数据,调用acquireBuffer测验向BufferQueueCore获取一个数据以供消费。顾客的代码在BufferQueueConsumer中,acquireBuffer流程如下:

status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, nsecs_t expectedPresent, uint64_t maxFrameNumber) { //1. 假如行列为空,则直接回来 if (mCore->mQueue.empty()) { return NO_BUFFER_AVAILABLE; }

//2. 取出mQueue行列的第一个元素,并从行列中移除 BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); int slot = front->mSlot; *outBuffer = *front; mCore->mQueue.erase(front);

//3. 处理expectedPresent的状况,这种状况或许会接连丢几个Slot的“显现”时刻小于expectedPresent的状况,这种状况下这些Slot现已是“过期”的,直接走下文的releaseBuffer消费流程,代码比较长,疏忽了 //4. 更新Slot的状况为ACQUIRED if (mCore->stillTracking(front)) { mSlots[slot].mAcquireCalled = true; mSlots[slot].mNeedsCleanupOnRelease = false; mSlots[slot].mBufferState = BufferSlot::ACQUIRED; mSlots[slot].mFence = Fence::NO_FENCE; }

//5. 假如进程3有直接releaseBuffer的进程,则回调出产者,有数据被消费了 if (listener != NULL) { for (int i = 0; i < numDroppedBuffers; ++i) { listener->onBufferReleased(); } }}

从上面的注释能够看到,acquireBuffer的首要进程如下:

小结acquireBuffer:将Slot的状况改变成ACQUIRED,并从mQueue中移除,终究告诉出产者有数据出队。

2.6 顾客releaseBuffer

顾客获取到Slot后开端消费数据(典型的消费如SurfaceFlinger的UI组成),消费结束后,需求奉告BufferQueueCore这个Slot被顾客消费结束了,能够给出产者从头出产数据,releaseBuffer流程如下:

status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, const sp<Fence>& releaseFence, EGLDisplay eglDisplay,EGLSyncKHR eglFence) { //1. 查看Slot是否合法 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SL德鲁瓦斯OTS || return BAD_VALUE; }

//2. 容错处理:假如要处理的Slot存在于mQueue中,那么阐明这个Slot的来历不合法,并不是从2.5的acquireBuffer获取的Slot,回绝处理 BufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); while (current != mCore->mQueue.end()) { if (current->mSlot == slot) { return BAD_VALUE; } ++current; }

// 3. 将Slot的状况改变为FREE,之前是ACQUIRED,并将该Slot添加到BufferQueueCore的mFreeBuffers列表中(mFreeBuffers的界说参阅2.1的介绍) if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) { mSlots[slot].mEglDisplay = eglDisplay; mSlots[slot].mEglFence = eglFence; mSlots[slot].mFence = releaseFence; mSlots[slot].mBufferState = BufferSlot::FREE; mCore->mFreeBuffers.push_back(slot); listener = mCore->mCon王若林nectedProducerListener; BQ_LOGV("releaseBuffer: releasing slot %d", slot); }

// 4. 回调出产者,有数据被消费了 if (listener != NULL) { listener->onBufferReleased(); }}

从上面的注释能够看到,releaseBuffer的首要进程如下:

小结releaseBuff鬼域乡大冒险er:将Slot的状况改变成FREE,并添加到BufferQueueCore mFreeBuffers行列中,终究告诉出产者有数据出队。

总结下状况改变的进程:

上面首要介绍了BufferQueue的规划思维和内部完结。

下面将持续介绍BufferQueue,侧重介绍Android中关于BufferQueue的常用封装,以及Su水煮肉片的家常做法,深入浅出Android BufferQueue,一剪梅简谱rfaceView中运用BufferQueue的详细完结。

3.Bu袁东操影视论坛fferQueue常用封装类

在实践运用中,除了直接运用BuferQueue外,更多的是运用Surface/SurfaceTexture,其对BufferQueue做了包装,便利事务更便利的运用BufferQueue。Surface作为BufferQueue的出产者,SurfaceTexture作为BufferQueue的顾客。

3.1 Surface

Surface的结构函数如下:

Surface::Surface(

const sp<IGraphicBufferProducer>& bufferProducer,

bool controlledByApp)

: mGraphicBufferProducer(bufferProducer),

mGenerationNumber(0)

结构函数需求传入一个出产者的引证,和BufferQueue的交互均有这个出产者的引证来完结。dequeueBuffer的流程如下:

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { // 1. 调用mGraphicBufferProducer的dequeueBuffer办法,测验获取一个Slot索引 int buf = -1; sp<Fence> fence; status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero, reqWidth, reqHeight, reqFormat, reqUsage); if (result < 0) { ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)" "failed: %d", swapIntervalZero, reqWidth, reqHeight, reqFormat, reqUsage, result); return result; }

// 2. 调用mGraphicBufferProducer的requestBuffer办法,测验获取Slot sp<GraphicBuffer>& gbuf(mSlots[buf].buffer); if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); if (result != NO_ERROR) { ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result); mGraphicBufferProducer->cancelBuffer(buf, fence); return result; } }

// 3. 回来GraphicBuffer *buffer = gbuf.get();}

queueBuffer也是如下,流程如下:

int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, mDataSpace, crop, m木灵仙道ScalingMode, mTransform ^ mStickyTransform, mSwapIntervalZero, fence, mStickyTransform); // 1. 直接调用mGraphicBufferProducer的queueBuffer办法即可 status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); }}

Surface还供给了lock函数,用来支撑双缓冲,内部也是调用dequeueBuffer办法获取最新的Buffer:

status_t Surface::lock( ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBoun水煮肉片的家常做法,深入浅出Android BufferQueue,一剪梅简谱ds){ ANativeWindowBuffer* out; int fenceFd = -1; //1. 获取实践Buffer status_t err = dequeueBuffer(&out, &fenceFd);

//2. 处理双缓冲 if (canCopyBack) { // copy the area that is invalid and not repainted this round const Region copyback(可怕的科学在线阅览mDirtyRegion.subtract(newDirtyRegion)); if (!copyback.isEmpty()) copyBlt(backBuffer, frontBuffer, copyback); }}

Surface也供给了unlockAndPost办法,将数据给到BufferQueue:

status_t Surface::unlockAndPost(){ if (mLockedBuffer == 0) { ALOGE("Surface::unlockAndPost failed, no locked buffer"); return INVALID_OPERATION; } int fd = -1; status_t err = mLockedBuffer->unlockAsync(&fd); ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle); //1. 将出产好的数据给到BufferQueue err = queueBuffer(mLockedBuffer.get(), fd); ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)", mLockedBuffer->handle, strerror(-err)); mPostedBuffer = mLockedBuffer; mLockedBuffer = 0; return err;}

3.2 SurfaceTexture

SurfaceTexture作为BufferQueue的顾客,其初始化代码如下:

static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached, jint texName, jboolean singleBufferMode, jobject weakThiz){ sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; //1. 创立一个BufferQueue BufferQueue::createBufferQueue(&producer, &consumer); if (singleBufferMode) { consumer->disableAsyncBuffer(); consumer->setDefaultMaxBufferCount(1); }

//2. 创立一个顾客实例surfaceTexture sp<GLConsumer> surfaceTexture; if (isDetached) { surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES, true, true); } else { surfaceTexture = new GLConsumer(consumer, texName, GL_TEXTURE_EXTERNAL_OES, true, true); } //3. 将顾客实例和该BufferQueue对应的出产者保存到java层,这样Surface结构时,就能够获取到该BufferQueue对应的出产者了 SurfaceTexture_setSurfaceTexture(env, thi水煮肉片的家常做法,深入浅出Android BufferQueue,一剪梅简谱z, surfaceTexture); SurfaceTexture_setProducer(env, thiz, producer);}

消费的办法是updateTexImage,流程如下:

static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz){ // 1. 先获取到初始化时结构的顾客 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));

// 2. 调用顾客的updateTexImage办法 status_t err = surfaceTexture->updateTexImage办法(); if (err == INVALID_OPERATION) { jniThrowException(env, IllegalStateException, "Unable to update texture contents (see " "logcat for details)"); } else if (err < 0) { jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)"); }}

GLConsumer的updateTextImage完结如下:

status_t GLConsumer::updateTexImage() { BufferItem item; //1. 调用本身的acquireBufferLocked办法 err = acquireBufferLocked(&item, 0);:updateTexImage() { //僵尸夜总会 Release the previous buffer. err = updateAndReleaseLocked(item); if (err != NO_ERROR) {河谷镇砸冰 glBindTexture(mTexTarget, mTexName); return err; }

}

acquireBufferLocked办法,终究走到了ConsumerBase的acquireBufferLocked办法。

status_t ConsumerBase::acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, uint64_t maxFrameNumber) { //1. 终究仍是走到了顾客的acquasiamonstrireBuffer办法,顾客对应上面的BufferQueueConsumer status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber); if (err != NO_ERROR) { return err; } return OK;}

同理,顾客消费数据的办法是releaseTexImage,终究也会走到BufferQueueConsumer的releaseBufferLocked办法,这儿不再描绘了。

4.BufferQueue的实例

上述介绍了BufferQueue的内部完结,以及常用的封装类。接下来将介绍一个详细的实例。

Android中,SurfaceView作为体系供给的组件,由于能够在子线程中制作进步功能,SurfaceView具有本身的Surface,不需求和Activity的Surface同享,在SurfaceFlinger中,Activity的Surface和SurfaceView的Surface是平级且相互独立的,能够独立的进行组成。那咱们来看一下SurfaceView是怎样运用BufferQue博翱公棚ue的。

4.1 数据的出产进程

SurfaceView的Surface创立进程,这儿不重视,有爱好的能够参阅 android SurfaceView制作完结原理解析 这篇文章,咱们首要重视其间与BufferQueue相关的制作和显现进程。

运用SuerfaceView制作伪码如下:

Canvas canvas = null;

try {

canvas = holder.lockCanvas(null);

//实践的draw

}catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}finally {

if(canvas != null) {

holder.unlockCanvasAndPost(canvas);

}

需求调用lockCanvas和unlockCanvasAndPost办法,这两个办法的效果是什么呢?

先看下lockCanvas,调用流程是:

nativeLockCanvas完结如下:

static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) { sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); ANativeWindow_Buffer outBuffer; //1. 经过Surface::lock办法,获取一个适宜的Buffer status_t err = surface->lock(&outBuffer, dirtyRectPtr);

//2. 结构一个Bitmap,地址指向进程1获取的Buffer的地址,这样在这个Bitmap上制作的内容,直接制作到了GraphicBuffer,假如GraphicBuffer的内存是SurfaceFlinger经过同享定北侯是谁内存请求的,那么SurfaceFlinger就能直接看到制作的图形数据 SkImageInfo info = SkImageInfo::Make(outBuffer.wid李老汉th, outBuffer.height, convertPixelFormat(outBuffer.format), kPremul_SkAlphaType); SkBitmap bitmap; ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); bitmap.setInfo(info, bpr); if (outBuffer.width > 0 && outBuffer.height > 0) { bitmap.setPixels(outBuffer.bits); } else { // be safe with an empty bitmap. bitmap.setPixels(NULL); }

// 3. 将创立的Bitmap设置给Canvas,作为画布 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj); nativeCanvas->setBitmap(bitmap);}

从这儿能够看到,nativeLockCanvas的进程首要如下:

在制作图形完结后,调用unlockCanvasAndPost办法,调用流程是:

nativeUnlockCanvasAndPost 的完结如下:

static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,

jlong nativeObject, jobject canvasObj) {

sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));

if (!isSurfaceValid(surface)) {

return;

}

// detach the canvas from the surface

Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);

nativeCanvas->setBitmap(SkBitmap());

// 直接调用Surface的unlockAndPost办法,有上文可知unlockAndPost内部终究也会调用到qeueBuffer办法

status_t err = surface->unlockAnd壮妇杀羊Post办法,有上文可知unlockAndPost内部终究也会调用到qeueBuffer办法();

if (err < 0) {

doThrowIAE(env);

}

}

从注释能够看到,这个办法,终究会调用到Surface的unlockAndPost办法办法,而该办法内部终究也会调用到BufferQueueProducer的queueBuffer办法。即完结了数据的出产和入队。

4.2 数据的消费进程

SurfaceView制作的数据,传递过BufferQueue后,终究由SurfaceFlinger进行组成消费。SurfaceFlinger的消费由SurfaceFlingerConsumer完结,流程如下:

status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, uint64_t maxFrameNumber){ BufferItem item; // 1. 调用acquireBufferLocked获取一个Slot err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber); if (err != NO_ERROR) { return err; }

//2. 消费结束,开释Slot err = updateAndReleaseLocked(item); if (err != NO_ERROR) { return err; }}

acquireBufferLocked的完结如下:

status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, uint64_t maxFrameNumber) { //1. 调用 GLConsumer::acquireBufferLocked,终究会调用到BufferQueueConsumer的acquireBuffer办法 status_t result = GLConsumer::acquireBufferLocked(item, presentWhen, maxFrameNumber); if (result == NO_ERROR) { mTransformToDisplayInverse = item->mTransformToDisplayInverse; mSurfaceDamage = item->mSurfaceDamage; } return result;}

而updateAndReleaseLocked办法的流程如下:

5. 总结

本文对BufferQueue的内部完结做了介绍,结合入队/出对说死神的圣约明晰BufferQueue内部Slot的状况改变进程,并介绍了常用的BufferQueue封装类,终究介绍了一个根据BufferQueue的比如。

声明:该文观念仅代表作者自己,搜狐号系信息发布渠道,搜狐仅供给信息存储空间效劳。