enum BufferState {
FREE = 0,//空闲
DEQUEUED = 1,//生产状态,被生产者拥有
QUEUED = 2,//保存数据状态,被BufferQueue拥有
ACQUIRED = 3//消费状态,被消费者拥有
BufferQueueProducer的dequeueBuffer函数用来向BufferQueueCore申请一个空闲的slot,这个slot可能已经有缓冲区,也可能没有,如果没有缓冲区,dequeueBuffer函数会分配一块新的缓冲区。得到空闲的slot后,还需要调用requestBuffer函数来取得一块缓冲区。得到缓冲区,如果不需要了,可以使用cancelBuffer函数来释放这个slot。调用dequeueBuffer函数之后,缓冲区的拥有者是生产者,缓冲区处于DEQUEUED状态。一旦缓冲区复制数据完成,通过queueBuffer函数把缓冲区的控制权交还给BufferQueueCore,这时候缓冲区将处于QUEUED状态。
1.2 消费者和core的联系
下面是IGraphicBufferComsumer接口的几个主要函数:
virtual status_t acquireBuffer(BufferItem* outBuffer,
nsecs_t expectedPresent, uint64_t maxFrameNumber = 0) override;
......
virtual status_t releaseBuffer(int slot, uint64_t frameNumber,
const sp<Fence>& releaseFence, EGLDisplay display,
EGLSyncKHR fence);
virtual status_t connect(const sp<IConsumerListener>& consumerListener,
bool controlledByApp);
virtual status_t disconnect();
BufferQueueConsumer类是接口IGraphicBufferComsumer的实现,在使用它之前,先要调用connect函数建立联系,这里传递的参数是IConsumerListener对象,是一个回调接口,如果BufferQueue中有数据准备好了就会调用它的onFrameAvailable函数来通知消费者取走数据。
取走数据的时候,需要调用acquireBuffer函数,将缓冲区状态变成ACQUIRED,使用完之后调用releaseBuffer函数可以吧缓冲区数据归还给BufferQueueCore,这样缓冲区就变成FREE。
1.3 三者联系
对象BufferQueueProducer和BufferQueueConsumer好像没有直接联系,其实都是通过共同的BufferQueueCore对象连接在一起的,很多操作时直接使用BufferQueueCore对象的成员变量而不是函数来完成的。
二、GraphicBuffer对象的创建
对Surface而言,图像缓冲区是一个重要的数据结构,它是用户进程和图像显示器之间的纽带,下面我们来看看Surface的图像缓冲区是如何创建的。
2.1 内存缓冲区的创建
前面介绍了过dequeueBuffer函数,图像缓冲区GraphicBuffer就是在这个函数中创建的,当从BufferQueueCore中获取到空间的slot时,如果这个slot没有缓冲区就要新建一个。
下面是dequeueBuffer函数的部分代码,在从BufferQueueCore中获取到slot的时候,如果需要重新分配图像缓冲区就会调用mCore->mAllocator->createGraphicBuffer函数来重新创建一个图像缓冲区。
......
*outSlot = found;//found复制到outslot
ATRACE_BUFFER_INDEX(found);
attachedByConsumer = mSlots[found].mAttachedByConsumer;
mSlots[found].mBufferState = BufferSlot::DEQUEUED;//slot的状态修改变成生产状态
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if ((buffer == NULL) ||//为空,或者需要重新分配
buffer->needsReallocation(width, height, format, usage))
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = NULL;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->mBufferAge = 0;
returnFlags |= BUFFER_NEEDS_REALLOCATION;//需要重启分配缓冲区
} else {
// We add 1 because that will be the frame number when this buffer
// is queued
mCore->mBufferAge =
mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
mCore->mBufferAge);
if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
"slot=%d w=%d h=%d format=%u",
found, buffer->width, buffer->height, buffer->format);
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
*outFence = mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->validateConsistencyLocked();
} // Autolock scope
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {//如果需要重启分配图像缓冲区
status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(//创建图像缓冲区
width, height, format, usage, &error));
if (graphicBuffer == NULL) {
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
return error;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
} // Autolock scope
......
mAllocator的类型是IGraphicBufferAlloc,也是一个Binder对象,它是在BufferQueueCore的构造函数中得到的,这个时候allocator为空的,具体要从Layer的构造函数中调用BufferQueue::createBufferQueue函数是,那个时候allocator参数就为空。然后通过getComposerService来调用createGraphicBufferAlloc函数来创建这个mAllocator对象。
之前的博客分析过getComposerService返回的是和SurfaceFlinger进程的Binder对象,因此最后是到SurfaceFlinger的createGraphicBufferAlloc函数中去了(但是这里有点搞不明白明明是在一个进程中为什么要用Binder呢?)。
......
if (allocator == NULL) {
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mAllocator = composer->createGraphicBufferAlloc();
if (mAllocator == NULL) {
BQ_LOGE("createGraphicBufferAlloc failed");
......
下面我们来看SurfaceFlinger的createGraphicBufferAlloc函数。
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
return gba;
因此最后BufferQueueProducer中的dequeueBuffer函数中调用mCore->mAllocator的createGraphicBuffer函数就是调用了GraphicBufferAlloc的createGraphicBufferAlloc函数。
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
uint32_t height, PixelFormat format, uint32_t usage, status_t* error) {
sp<GraphicBuffer> graphicBuffer(
new GraphicBuffer(width, height, format, usage));
status_t err = graphicBuffer->initCheck();
*error = err;
......//错误处理
return graphicBuffer;
我们来看下GraphicBuffer对象的构造函数中调用了initSize函数。
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage)
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mId(getUniqueId())
......
mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage);
在initSize函数中调用GraphicBufferAllocator的alloc来分配内存。
status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage)
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
uint32_t outStride = 0;
status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage,
&handle, &outStride);
if (err == NO_ERROR) {
width = static_cast<int>(inWidth);
height = static_cast<int>(inHeight);
format = inFormat;
usage = static_cast<int>(inUsage);
stride = static_cast<int>(outStride);
return err;
}
alloc又调用了成员变量mAllocDev的alloc函数。
status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage, buffer_handle_t* handle,
uint32_t* stride)
......
err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
static_cast<int>(height), format, static_cast<int>(usage), handle,
&outStride);
在GraphicBufferAllocator的构造函数中装载了Gralloc模块,因此mAllocDev指向了Gralloc模块。这个会在后面的博客中分析
GraphicBufferAllocator::GraphicBufferAllocator()
: mAllocDev(0)
hw_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
if (err == 0) {
gralloc_open(module, &mAllocDev);
这里调用alloc分配了一块共享的内存缓冲区,alloc函数将返回共享区的fd和缓冲区的指针。既然GraphicBuffer中的缓冲区是共享内存,我们知道使用共享内存需要传递共享内存的句柄fd。下面我们看看是如何传到客户进程的。
2.2 内存缓冲区的fd传递到客户进程
GraphicBuffer类从模板类Flattenable派生,这个派生类可以通过Parcel传递,通常派生类需要重载flatten和unflatten方法,用于对象的序列化和反序列化。
class GraphicBuffer
: public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >,
public Flattenable<GraphicBuffer>
我们先来看下flatten函数,fds参数用来传递文件句柄,函数把handle中的句柄复制到fds中,因此这些句柄就能通过binder传递到目标进程中去。
status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
if (size < sizeNeeded) return NO_MEMORY;
size_t fdCountNeeded = GraphicBuffer::getFdCount();
if (count < fdCountNeeded) return NO_MEMORY;
int32_t* buf = static_cast<int32_t*>(buffer);
buf[0] = 'GBFR';
buf[1] = width;
buf[2] = height;
buf[3] = stride;
buf[4] = format;
buf[5] = usage;
buf[6] = static_cast<int32_t>(mId >> 32);
buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull);
buf[8] = static_cast<int32_t>(mGenerationNumber);
buf[9] = 0;
buf[10] = 0;
if (handle) {
buf[9] = handle->numFds;
buf[10] = handle->numInts;
memcpy(fds, handle->data,//把handle中的中复制到fds中
static_cast<size_t>(handle->numFds) * sizeof(int));
memcpy(&buf[11], handle->data + handle->numFds,
static_cast<size_t>(handle->numInts) * sizeof(int));
buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
size -= sizeNeeded;
if (handle) {
fds += handle->numFds;
count -= static_cast<size_t>(handle->numFds);
return NO_ERROR;
}
再来看unflatten函数,调用这个函数时,共享区的文件句柄已经准备好了,但是内存还没有进行映射,调用了mBufferMapper.registerBuffer函数来进行内存映射。
status_t GraphicBuffer::unflatten(
void const*& buffer, size_t& size, int const*& fds, size_t& count) {
......
if (handle != 0) {
status_t err = mBufferMapper.registerBuffer(handle);
......
buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded);
size -= sizeNeeded;
fds += numFds;
count -= numFds;
return NO_ERROR;
}
我们看下GraphicBufferMapper::registerBuffer函数,调用了mAllocMod的registerBuffer函数,mAllocMod同样是指向了Gralloc模块的指针,在GraphicBufferMapper的构造函数中创建,因此实际是调用了Gralloc模块的gralloc_register_buffer函数。这个函数就是调用了mmap来进行共享内存的映射。在后续的博客我们再详细分析。
status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
ATRACE_CALL();
status_t err;
err = mAllocMod->registerBuffer(mAllocMod, handle);
ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
handle, err, strerror(-err));
return err;
在硬件设备支持Framebuffer缓冲区的情况下,Surface中绘制图形的缓冲区就是Framebuffer的缓冲区,绘制完成后,如果不需要进行图像合成,只需要flip操作就能完成图像的输出,中间完全不用复制的过程,很高效。
接着前面的BootAnimation的启动过程,可以看到内部会涉及很多OpenGLES的相关操作,OpenGLES通过之前创建的具备有SurfaceTexture等的Surface类,来操作远端的SF来完成相关的图像渲染。这里主要涉及到ANativeWindow的2个核心回调函数,OpenGLES在应用层的eglSwapBuffers就是调用了QueueBuffer和DequeueBuffer两个函数来完成的。在介绍上面两个函数的实现时,有必要把BufferQueue这个类再提出来。他是由应用程序在客户端通过和服务端的Client交互,提交消息给SurfaceFlinger处理时创建的Laye
上一篇文章分析了生产者-消费者模型,构成此模型最重要的三个类就是生产者BufferQueueProducer,消费者BufferQueueConsumer,buffer队列BufferQueue,而buffer队列的核心就是BufferQueueCore。
本篇文章来分析一下dequeueBuffer这个函数,这个函数的作用是应用程序一端请求绘制图像时,向BufferQueue中申请一块可用的GraphicBuffer,有了这个buffer就可以绘制图像数据了。
在分析这个函数之前先来看看BufferQue
之前分析了显示系统的大致流程,其中有几个地方不是很清楚,这里我专门写几篇专题。
这篇先来看GraphicBuffer分配内存,我们在之前的博客中分析到用户进程创建一个Surface,最后返回的参数gbp是sp类型的,过程之前都分析过了,我们就不分析了,这个gbp是在Layer的onFirstRef中创建的。
在BufferQueue的createBufferQueue中创建了producer和
一.先从Serialize说起
我们都知道JAVA中的Serialize机制,译成串行化、序列化……,其作用是能将数据对象存入字节流当中,在需要时重新生成对象。主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等。
二.Android中的新的序列化机制
在Android系统中,定位为针对内存受限的设备,因此对性能要求更高,另外系统中采用了新的IPC(进程间通信)机制,必然要...
之前在这篇博客中http://blog.csdn.net/kc58236582/article/details/52437855我们分析过应用在ViewRootImpl的drawSoftware函数中完成绘制
下面我们来看下这个函数,它先调用了Surface的lockCanvas获取一个Canvas,然后再调用surface.unlockCanvasAndPost来表示绘制结束。
3.2 绘图表面相关(Surface& Layer & BufferQueue)
App和SurfaceFlinger连接后,接下去就可以调用mClient->createSurface创建Surface, 然后SurfaceFlinger会对应的创建Layer,然后Layer内部会创建BufferQueueProducer和
BufferQueueConsumer,一个负责生产graphic
使用TextureView进行两个网络视频同时播放;
快速连续点击屏幕或在屏幕上拖动,会导致视频开始掉帧卡顿,概率导致屏幕卡死,无法操作,但程序正常运行;
视频码率越高,卡顿越严重,单个视频卡死的现象越容易出现;
CPU没有占满(5%~20%),可能是TextureView底层与屏幕共用了资源,互相排挤;
使用小...
1. Linux内核提供了统一的framebuffer显示驱动,设备节点/dev/graphics/fb*或者/dev/fb*,以fb0表示第一个显示屏,当前实现中只用到了一个显示屏。
2. Android的HAL层提供了Gralloc,分为fb和gralloc两个设备。设备fb负责打开内核中的framebuffer以及提供post、setSwapInterval等操作,设备gralloc则负责
http://windrunnerlihuan.com/2017/06/22/Android-SurfaceFlinger-%E5%AD%A6%E4%B9%A0%E4%B9%8B%E8%B7%AF-%E4%B8%83-%E5%88%9B%E5%BB%BA%E5%9B%BE%E5%BD%A2%E7%BC%93%E5%86%B2%E5%8C%BAGraphicBuffer/