文档章节

Android4.2.2 SurfaceFlinger之图形缓存区申请与分配dequeueBuffer

RoyceInWh
 RoyceInWh
发布于 2016/06/20 16:04
字数 5543
阅读 15
收藏 0

本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。

欢迎和大家交流。qq:1037701636 email:gzzaigcn2012@gmail.com

Android源码版本Version:4.2.2; 硬件平台 全志A31

 

接着前面的BootAnimation的启动过程,可以看到内部会涉及很多OpenGL ES的相关操作,OpenGL ES通过之前创建的具备有SurfaceTexture等的Surface类,来操作远端的SF来完成相关的图像渲染。

这里主要涉及到ANativeWindow的2个核心回调函数,OpenGL ES在应用层的eglSwapBuffers就是调用了QueueBuffer和DequeueBuffer两个函数来完成的。

在介绍上面两个函数的实现时,有必要把BufferQueue这个类再提出来。他是由应用程序在客户端通过和服务端的Client交互,提交消息给SurfaceFlinger处理时创建的Layer对象时在SurfaceTextureLayer类构造中创建的:

BufferQueue中有一个成员变量BufferSlot mSlots[NUM_BUFFER_SLOTS];即一个BufferQueue实际上最大可以有32个Buffer,即一个应用程序申请的Surface在SF端的Layer可以有32个图像缓存区。而这32个图形缓存区都有上面的mSlots维护着,每个Buffer有以下几种可变的状态,由BufferState mBufferState维护:

分别是FREE,DEQUEUED,QUEUE,ACQUIRED这4个状态,分别是空闲,出列被填充数据,入列代表有了数据,最终将入列后有了图形数据的缓冲区进行渲染。

 

step1:先来看dequeueBuffer函数,可以理解为生产者,会用来申请Buffer并进行应用程序端的图像绘制。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer,  
  2.         int* fenceFd) {  
  3.     ATRACE_CALL();  
  4.     ALOGV("SurfaceTextureClient::dequeueBuffer");  
  5.     Mutex::Autolock lock(mMutex);  
  6.     int buf = -1;  
  7.     int reqW = mReqWidth ? mReqWidth : mUserWidth;  
  8.     int reqH = mReqHeight ? mReqHeight : mUserHeight;  
  9.     sp<Fence> fence;  
  10.     status_t result = mSurfaceTexture->dequeueBuffer(&buf, fence, reqW, reqH,  
  11.             mReqFormat, mReqUsage);//调用远程的BnSurfaceTexture来完成BufferQueue的操作  
  12.     if (result < 0) {  
  13.         ALOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"  
  14.              "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,  
  15.              result);  
  16.         return result;  
  17.     }  
  18.     sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);//对应到客户端的mSlots中,buf为SF侧分配到的id  
  19.     if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) {  
  20.         freeAllBuffers();  
  21.     }  
  22.   
  23.     if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {  
  24.         result = mSurfaceTexture->requestBuffer(buf, &gbuf);//返回的result是在重新分配后找到对应的缓冲区信息,需要进行request  
  25.         if (result != NO_ERROR) {  
  26.             ALOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",  
  27.                     result);  
  28.             return result;  
  29.         }  
  30.     }  
  31.   
  32.     if (fence.get()) {  
  33.         *fenceFd = fence->dup();  
  34.         if (*fenceFd == -1) {  
  35.             ALOGE("dequeueBuffer: error duping fence: %d", errno);  
  36.             // dup() should never fail; something is badly wrong. Soldier on  
  37.             // and hope for the best; the worst that should happen is some  
  38.             // visible corruption that lasts until the next frame.  
  39.         }  
  40.     } else {  
  41.         *fenceFd = -1;  
  42.     }  
  43.   
  44.     *buffer = gbuf.get();//GraphicBuffer  
  45.     return OK;  
  46. }  

上面函数的核心在于status_t result = mSurfaceTexture->dequeueBuffer(&buf, fence, reqW, reqH,mReqFormat, mReqUsage);那么这个应用层即所谓的客户端侧的mSurfaceTexture是什么呢?这个其实就是应用程序侧在创建了SurfaceControl后获得的,即所谓的BufferQueue的Binder匿名代理(继承了BnSurfaceTexture而已)BpSurfaceTexture。从而这样建立起来的Binder通信机制,使得在ANativeWindow将最终的Buffer处理都扔回给了之前由SurfaceFlinger创建的Layer,SurfaceTexture对象中去了。

 

step2:现在回到BufferQueue去吧,看看是如何做调用的。

 通过BpSurfaceTexture来到BnSurfaceTexture,如下:

因为BufferQueue继承了BnSurfaceTexture后,故调用BufferQueue的成员函数queueBuffer,其实也就是SurfaceFlinger再操纵着这些个Buffer。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.         case DEQUEUE_BUFFER: {//图像缓冲区申请  
  2.             CHECK_INTERFACE(ISurfaceTexture, data, reply);  
  3.             uint32_t w      = data.readInt32();  
  4.             uint32_t h      = data.readInt32();  
  5.             uint32_t format = data.readInt32();  
  6.             uint32_t usage  = data.readInt32();  
  7.             int buf;  
  8.             sp<Fence> fence;  
  9.             int result = dequeueBuffer(&buf, fence, w, h, format, usage);  
  10.             bool hasFence = fence.get() && fence->isValid();  
  11.             reply->writeInt32(buf);  
  12.             reply->writeInt32(hasFence);  
  13.             if (hasFence) {  
  14.                 reply->write(*fence.get());  
  15.             }  
  16.             reply->writeInt32(result);  
  17.             return NO_ERROR;  
  18.         } break;<span style="font-family:Courier New;background-color: rgb(240, 240, 240);">  
  19. </span>  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,  
  2.         uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {  
  3. {  
  4.   ......  
  5.     { // Scope for the lock  
  6.         Mutex::Autolock lock(mMutex);  
  7.   
  8.         if (format == 0) {  
  9.             format = mDefaultBufferFormat;  
  10.         }  
  11.         // turn on usage bits the consumer requested  
  12.         usage |= mConsumerUsageBits;  
  13.   
  14.         int found = -1;  
  15.         int dequeuedCount = 0;  
  16.         bool tryAgain = true;  
  17.         while (tryAgain) {  
  18.             if (mAbandoned) {  
  19.                 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");  
  20.                 return NO_INIT;  
  21.             }  
  22.             const int maxBufferCount = getMaxBufferCountLocked();  
  23.   
  24.             // Free up any buffers that are in slots beyond the max buffer  
  25.             // count.  
  26.             for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {//寻找所有的slots  
  27.                 assert(mSlots[i].mBufferState == BufferSlot::FREE);  
  28.                 if (mSlots[i].mGraphicBuffer != NULL) {  
  29.                     freeBufferLocked(i);  
  30.                     returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;  
  31.                 }  
  32.             }  
  33.   
  34.             // look for a free buffer to give to the client  
  35.             found = INVALID_BUFFER_SLOT;  
  36.             dequeuedCount = 0;  
  37.             for (int i = 0; i < maxBufferCount; i++) {  
  38.                 const int state = mSlots[i].mBufferState;  
  39.                 if (state == BufferSlot::DEQUEUED) {  
  40.                     dequeuedCount++;//统计已经出列的buffer个数  
  41.                 }  
  42.   
  43.                 if (state == BufferSlot::FREE) {  
  44.                     /* We return the oldest of the free buffers to avoid 
  45.                      * stalling the producer if possible.  This is because 
  46.                      * the consumer may still have pending reads of the 
  47.                      * buffers in flight. 
  48.                      */  
  49.                     if ((found < 0) ||  
  50.                             mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {  
  51.                         found = i;//寻址free里面帧号最小的位置Slot  
  52.                     }  
  53.                 }  
  54.             }  
  55.             // clients are not allowed to dequeue more than one buffer  
  56.             // if they didn't set a buffer count.  
  57.             if (!mOverrideMaxBufferCount && dequeuedCount) {  
  58.                 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "  
  59.                         "setting the buffer count");  
  60.                 return -EINVAL;  
  61.             }  
  62.   
  63.             // See whether a buffer has been queued since the last  
  64.             // setBufferCount so we know whether to perform the min undequeued  
  65.             // buffers check below.  
  66.             if (mBufferHasBeenQueued) {  
  67.                 // make sure the client is not trying to dequeue more buffers  
  68.                 // than allowed.  
  69.                 const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);  
  70.                 const int minUndequeuedCount = getMinUndequeuedBufferCountLocked();  
  71.                 if (newUndequeuedCount < minUndequeuedCount) {  
  72.                     ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "  
  73.                             "exceeded (dequeued=%d undequeudCount=%d)",  
  74.                             minUndequeuedCount, dequeuedCount,  
  75.                             newUndequeuedCount);  
  76.                     return -EBUSY;  
  77.                 }  
  78.             }  
  79.   
  80.             // If no buffer is found, wait for a buffer to be released or for  
  81.             // the max buffer count to change.  
  82.             tryAgain = found == INVALID_BUFFER_SLOT;  
  83.             if (tryAgain) {  
  84.                 for (int i = 0; i < maxBufferCount; i++) {  
  85.                     BQ_LOGD("#dequeueBuffer tryAgain buf:%d state:%d", i, mSlots[i].mBufferState);  
  86.                 }  
  87.                 mDequeueCondition.wait(mMutex);//等待有buffer的释放  
  88.             }  
  89.         }  
  90.   
  91.   
  92.         if (found == INVALID_BUFFER_SLOT) {  
  93.             // This should not happen.  
  94.             ST_LOGE("dequeueBuffer: no available buffer slots");  
  95.             return -EBUSY;  
  96.         }  
  97.   
  98.         const int buf = found;  
  99.         *outBuf = found;//找到可以使用的buffer,记录到outBuf里面  
  100.   
  101.         ATRACE_BUFFER_INDEX(buf);  
  102.   
  103.         const bool useDefaultSize = !w && !h;  
  104.         if (useDefaultSize) {  
  105.             // use the default size  
  106.             w = mDefaultWidth;  
  107.             h = mDefaultHeight;  
  108.         }  
  109.   
  110.         // buffer is now in DEQUEUED (but can also be current at the same time,  
  111.         // if we're in synchronous mode)  
  112.         mSlots[buf].mBufferState = BufferSlot::DEQUEUED;  
  113.   
  114.         const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);  
  115.         if ((buffer == NULL) ||  
  116.             (uint32_t(buffer->width)  != w) ||  
  117.             (uint32_t(buffer->height) != h) ||  
  118.             (uint32_t(buffer->format) != format) ||  
  119.             ((uint32_t(buffer->usage) & usage) != usage))//当前找到的slots中的buffer没有缓冲区或者相关属性不匹配则从新申请  
  120.         {  
  121.             mSlots[buf].mAcquireCalled = false;  
  122.             mSlots[buf].mGraphicBuffer = NULL;  
  123.             mSlots[buf].mRequestBufferCalled = false;  
  124.             mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;  
  125.             mSlots[buf].mFence.clear();  
  126.             mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;  
  127.   
  128.             returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;//重新申请  
  129.         }  
  130.   
  131.         dpy = mSlots[buf].mEglDisplay;  
  132.         eglFence = mSlots[buf].mEglFence;  
  133.         outFence = mSlots[buf].mFence;  
  134.         mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;  
  135.         mSlots[buf].mFence.clear();  
  136.     }  // end lock scope  
  137.     if (returnFlags & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) {  
  138.         status_t error;  
  139.         mGraphicBufferAlloc->acquireBufferReferenceSlot(*outBuf);  
  140.         sp<GraphicBuffer> graphicBuffer(  
  141.                 mGraphicBufferAlloc->createGraphicBuffer(  
  142.                         w, h, format, usage, &error));//重新请求SF端申请一个buffer  
  143.         if (graphicBuffer == 0) {  
  144.             ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "  
  145.                     "failed");  
  146.             return error;  
  147.         }  
  148.   
  149.         { // Scope for the lock  
  150.             Mutex::Autolock lock(mMutex);  
  151.   
  152.             if (mAbandoned) {  
  153.                 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");  
  154.                 return NO_INIT;  
  155.             }  
  156.   
  157.             mSlots[*outBuf].mGraphicBuffer = graphicBuffer;//申请的buffer加入到当前的mSlots的成员mGraphicBuffer中  
  158.         }  
  159.     }  
  160.   
  161.     if (eglFence != EGL_NO_SYNC_KHR) {  
  162.           
  163.         EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000);  
  164.         // If something goes wrong, log the error, but return the buffer without  
  165.         // synchronizing access to it.  It's too late at this point to abort the  
  166.         // dequeue operation.  
  167.         if (result == EGL_FALSE) {  
  168.             ST_LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());  
  169.         } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {  
  170.             ST_LOGE("dequeueBuffer: timeout waiting for fence");  
  171.         }  
  172.         eglDestroySyncKHR(dpy, eglFence);  
  173.     }  
  174.   
  175.     BQ_LOGD("#dequeueBuffer: returning slot=%d buf=%p flags=%#x %p", *outBuf,  
  176.             mSlots[*outBuf].mGraphicBuffer->handle, returnFlags, this);  
  177.   
  178.     return returnFlags;  
  179. }  

DeQueueuffer的内容比较多,我们分以下几个Step来进行分析。

 

step1:清空超过最大需求的Buffer

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // Free up any buffers that are in slots beyond the max buffer  
  2.  // count.  
  3.  for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {//寻找所有的slots  
  4.      assert(mSlots[i].mBufferState == BufferSlot::FREE);  
  5.      if (mSlots[i].mGraphicBuffer != NULL) {  
  6.          freeBufferLocked(i);  
  7.          returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;  
  8.      }  
  9.  }  

这里假设maxBufferCount = 2,对其余的Buffer进行图形缓存区的清除。

 

step2:查找一个合格的Free了的Buffer

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. found = INVALID_BUFFER_SLOT;  
  2. dequeuedCount = 0;  
  3. for (int i = 0; i < maxBufferCount; i++) {  
  4.     const int state = mSlots[i].mBufferState;  
  5.     if (state == BufferSlot::DEQUEUED) {  
  6.         dequeuedCount++;//统计已经出列的buffer个数  
  7.     }  
  8.   
  9.     if (state == BufferSlot::FREE) {  
  10.         /* We return the oldest of the free buffers to avoid 
  11.          * stalling the producer if possible.  This is because 
  12.          * the consumer may still have pending reads of the 
  13.          * buffers in flight. 
  14.          */  
  15.         if ((found < 0) ||  
  16.                 mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {  
  17.             found = i;//寻址free里面帧号最小的位置Slot  
  18.         }  
  19.     }  
  20. }  

这里可以看到只执行2次循环,因为只需要2个图形缓存区而已。这里找到FREE的BufferSlot后,还需要查看当前的buffer所属于的帧号,这里found最终被定义为帧号小的BufferSlot.

 

step3:找到对应的BufferSlot的索index后,赋值给返回的outbuf参数,并切换当前状态从FREE到DEQUEUED。

 

step4: 实际图形缓存区的分配和申请,是实际DEqueuebuffer的重点所在

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.     mSlots[buf].mBufferState = BufferSlot::DEQUEUED;  
  2.   
  3.     const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);  
  4.     if ((buffer == NULL) ||  
  5.         (uint32_t(buffer->width)  != w) ||  
  6.         (uint32_t(buffer->height) != h) ||  
  7.         (uint32_t(buffer->format) != format) ||  
  8.         ((uint32_t(buffer->usage) & usage) != usage))//当前找到的slots中的buffer没有缓冲区或者相关属性不匹配则从新申请  
  9.     {  
  10.         mSlots[buf].mAcquireCalled = false;  
  11.         mSlots[buf].mGraphicBuffer = NULL;  
  12.         mSlots[buf].mRequestBufferCalled = false;  
  13.         mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;  
  14.         mSlots[buf].mFence.clear();  
  15.         mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;  
  16.   
  17.         returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;//重新申请  
  18.     }  
  19.   
  20.     dpy = mSlots[buf].mEglDisplay;  
  21.     eglFence = mSlots[buf].mEglFence;  
  22.     outFence = mSlots[buf].mFence;  
  23.     mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;  
  24.     mSlots[buf].mFence.clear();  
  25. }  // end lock scope  
  26. if (returnFlags & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) {  
  27.     status_t error;  
  28.     mGraphicBufferAlloc->acquireBufferReferenceSlot(*outBuf);  
  29.     sp<GraphicBuffer> graphicBuffer(  
  30.             mGraphicBufferAlloc->createGraphicBuffer(  
  31.                     w, h, format, usage, &error));//重新请求SF端申请一个buffer  
  32.     if (graphicBuffer == 0) {  
  33.         ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "  
  34.                 "failed");  
  35.         return error;  
  36.     }  
  37.   
  38.     { // Scope for the lock  
  39.         Mutex::Autolock lock(mMutex);  
  40.   
  41.         if (mAbandoned) {  
  42.             ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");  
  43.             return NO_INIT;  
  44.         }  
  45.   
  46.         mSlots[*outBuf].mGraphicBuffer = graphicBuffer;//申请的buffer加入到当前的mSlots的成员mGraphicBuffer中  
  47.     }  
  48. }  

这里都是在对查找到的BufferSlot进行初始化操作,可以看到只要buffer(sp<GraphicBuffer> mGraphicBuffer;是一个图形缓存类),或者需要的图形缓存的大小、格式、使用形式等与当前的BufferSlot不一样就有必要重新分配图形缓存了。

 

step6:图形缓存申请的实现mGraphicBufferAlloc->createGraphicBuffer()

那么这个函数是如何实现的呢?回来看看BufferQueue当初创建的时候把,在BufferQueue的构造函数里面,有一个图形缓存区分配的成员对象,他最终是由SurfaceFlinger来实现的。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. sp<ISurfaceComposer> composer(ComposerService::getComposerService());  
  2. mGraphicBufferAlloc = composer->createGraphicBufferAlloc();//创建GraphicBuffer  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.     virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()  
  2.     {  
  3.         uint32_t n;  
  4.         Parcel data, reply;  
  5.         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());  
  6.         remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply);//  
  7.         return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder());//BpGraphicBufferAlloc  
  8.     }  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t BnSurfaceComposer::onTransact(//内部函数由继承类SF来完成  
  2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  3. {        case CREATE_GRAPHIC_BUFFER_ALLOC: {  
  4.             CHECK_INTERFACE(ISurfaceComposer, data, reply);  
  5.             sp<IBinder> b = createGraphicBufferAlloc()->asBinder();//创建图像缓存  
  6.             reply->writeStrongBinder(b);  
  7.         } break;  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()  
  2. {  
  3.     sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());//图形缓存的申请  
  4.     return gba;  
  5. }  

在上述典型的Binder交互完成后,SF在服务端侧新建了一个图形缓存分配类对象后,将新建的gba写入Binder驱动,返回到客户端益BpBinder的形式存在
实际返回的是BpGraphicBufferAlloc的Binder代理,而

 

因此这里通过这个匿名的Binder代理,去请求BnGraphicBufferAlloc来完成

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t BnGraphicBufferAlloc::onTransact(  
  2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  3. {  
  4.         case CREATE_GRAPHIC_BUFFER: {  
  5.             CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);  
  6.             uint32_t w = data.readInt32();  
  7.             uint32_t h = data.readInt32();  
  8.             PixelFormat format = data.readInt32();  
  9.             uint32_t usage = data.readInt32();  
  10.             status_t error;  
  11.             sp<GraphicBuffer> result =  
  12.                     createGraphicBuffer(w, h, format, usage, &error);  
  13.             reply->writeInt32(error);  
  14.             if (result != 0) {  
  15.                 reply->write(*result);  
  16.                 // We add a BufferReference to this parcel to make sure the  
  17.                 // buffer stays alive until the GraphicBuffer object on  
  18.                 // the other side has been created.  
  19.                 // This is needed so that the buffer handle can be  
  20.                 // registered before the buffer is destroyed on implementations  
  21.                 // that do not use file-descriptors to track their buffers.  
  22.                 reply->writeStrongBinder( new BufferReference(result) );  
  23.             }  
  24.             return NO_ERROR;  
  25.         } break;  
  26. ....  
  27. }  

而之前存入的匿名binder对就是上述SF新建的GraphicBufferAlloc gba;而该类也正好继承了BpGraphicBufferAlloc这个对象,故有GraphicBufferAlloc::createGraphicBuffer来实现:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,  
  2.         PixelFormat format, uint32_t usage, status_t* error) {  
  3.     sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));  
  4.     status_t err = graphicBuffer->initCheck();  
  5.     *error = err;  
  6.     if (err != 0 || graphicBuffer->handle == 0) {  
  7.         if (err == NO_MEMORY) {  
  8.             GraphicBuffer::dumpAllocationsToSystemLog();  
  9.         }  
  10.         ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "  
  11.              "failed (%s), handle=%p",  
  12.                 w, h, strerror(-err), graphicBuffer->handle);  
  13.         return 0;  
  14.     }  
  15.     return graphicBuffer;  
  16. }  

这里看到了一个图像缓存类GraphicBuffer,在这里所谓的图像缓存创建就是构造了这个对象

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class GraphicBuffer  
  2.     : public ANativeObjectBase<  
  3.         ANativeWindowBuffer,  
  4.         GraphicBuffer,   
  5.         LightRefBase<GraphicBuffer> >, public Flattenable  
  6. {  

该类继承了本地窗口缓存ANativeWindowBuffer;

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,   
  2.         PixelFormat reqFormat, uint32_t reqUsage)  
  3.     : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),  
  4.       mInitCheck(NO_ERROR), mIndex(-1)  
  5. {  
  6.     width  =   
  7.     height =   
  8.     stride =   
  9.     format =   
  10.     usage  = 0;  
  11.     handle = NULL;  
  12.     mInitCheck = initSize(w, h, reqFormat, reqUsage);//内部实现缓存的申请  
  13. }  

GraphicBuffer有一个mBufferMapper对象,缓存的映射,看看他的初始化:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class GraphicBufferMapper : public Singleton<GraphicBufferMapper>  
  2. {  
  3. public:  
  4.     static inline GraphicBufferMapper& get() { return getInstance(); }  
  5.   
  6.     status_t registerBuffer(buffer_handle_t handle);  
  7.   
  8.     status_t unregisterBuffer(buffer_handle_t handle);  
  9.       
  10.     status_t lock(buffer_handle_t handle,  
  11.             int usage, const Rect& bounds, void** vaddr);  
  12.   
  13.     status_t unlock(buffer_handle_t handle);  
  14.       
  15.     // dumps information about the mapping of this handle  
  16.     void dump(buffer_handle_t handle);  
  17.   
  18.     status_t get_phy_addess(buffer_handle_t handle, void** vaddr);  
  19.   
  20. private:  
  21.     friend class Singleton<GraphicBufferMapper>;  
  22.     GraphicBufferMapper();  
  23.     gralloc_module_t const *mAllocMod;  
  24. };  

这个的get()返回的是一个GraphicBufferMapper对象,且为单列模式。

 

step7: 该对象将来完成图形缓存的映射,也就是图形缓存区内存映射到应用程序。看她的构造函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. GraphicBufferMapper::GraphicBufferMapper()  
  2.     : mAllocMod(0)  
  3. {  
  4.     hw_module_t const* module;  
  5.     int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);  
  6.     ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);  
  7.     if (err == 0) {  
  8.         mAllocMod = (gralloc_module_t const *)module;  
  9.     }  
  10. }  

很清楚这个是获取FrameBuffer的HAL模块gralloc的handle到module中,重点来看构造函数里的initSize函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format,  
  2.         uint32_t reqUsage)  
  3. {  
  4.     GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();  
  5.     status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);//图像缓冲区的分配  
  6.     if (err == NO_ERROR) {  
  7.         this->width  = w;  
  8.         this->height = h;  
  9.         this->format = format;  
  10.         this->usage  = reqUsage;  
  11.     }  
  12.     return err;  
  13. }  

这里又出现了一个图形缓存分配器的类,类似于GraphicBufferMapper函数,来看他的构造过程:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. GraphicBufferAllocator::GraphicBufferAllocator()  
  2.     : mAllocDev(0)  
  3. {  
  4.     hw_module_t const* module;  
  5.     int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);//调用HAL层  
  6.     ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);  
  7.     if (err == 0) {  
  8.         gralloc_open(module, &mAllocDev);//获得buffer分配模块mAllocDev,使用的是GPU这个模块ID  
  9.     }  
  10. }  

这里是打开了HAL层的gralloc模块到mAllocDev中,调用alloc函数,看看他完成了什么?

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,  
  2.         int usage, buffer_handle_t* handle, int32_t* stride)  
  3. {  
  4. ......  
  5.     BufferLiberatorThread::maybeWaitForLiberation();  
  6.   
  7.     err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);  
  8.   
  9.     if (err != NO_ERROR) {  
  10.         ALOGW("WOW! gralloc alloc failed, waiting for pending frees!");  
  11.         BufferLiberatorThread::waitForLiberation();  
  12.         err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);  
  13.     }  
  14.   
  15.     ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",  
  16.             w, h, format, usage, err, strerror(-err));  
  17.   
  18.     if (err == NO_ERROR) {  
  19.         Mutex::Autolock _l(sLock);  
  20.         KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);  
  21.         int bpp = bytesPerPixel(format);  
  22.         if (bpp < 0) {  
  23.             // probably a HAL custom format. in any case, we don't know  
  24.             // what its pixel size is.  
  25.             bpp = 0;  
  26.         }  
  27.         alloc_rec_t rec;  
  28.         rec.w = w;  
  29.         rec.h = h;  
  30.         rec.s = *stride;  
  31.         rec.format = format;  
  32.         rec.usage = usage;  
  33.         rec.size = h * stride[0] * bpp;  
  34.         list.add(*handle, rec);  
  35.     }  
  36.   
  37.     return err;  
  38. }  

这里是调用了Gralloc模块的alloc回调函数来完成对内存图形缓存区的申请。

 

step8:回到HAL层看看gralloc模块做了什么?

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static int gralloc_alloc(alloc_device_t* dev,  
  2.         int w, int h, int format, int usage,  
  3.         buffer_handle_t* pHandle, int* pStride)  
  4. {  
  5.     if (!pHandle || !pStride)  
  6.         return -EINVAL;  
  7.   
  8.     size_t size, stride;  
  9.   
  10.     int align = 4;  
  11.     int bpp = 0;  
  12.     switch (format) {  
  13.         case HAL_PIXEL_FORMAT_RGBA_8888:  
  14.         case HAL_PIXEL_FORMAT_RGBX_8888:  
  15.         case HAL_PIXEL_FORMAT_BGRA_8888:  
  16.             bpp = 4;  
  17.             break;  
  18.         case HAL_PIXEL_FORMAT_RGB_888:  
  19.             bpp = 3;  
  20.             break;  
  21.         case HAL_PIXEL_FORMAT_RGB_565:  
  22.         case HAL_PIXEL_FORMAT_RGBA_5551:  
  23.         case HAL_PIXEL_FORMAT_RGBA_4444:  
  24.         case HAL_PIXEL_FORMAT_RAW_SENSOR:  
  25.             bpp = 2;  
  26.             break;  
  27.         default:  
  28.             return -EINVAL;  
  29.     }  
  30.     size_t bpr = (w*bpp + (align-1)) & ~(align-1);  
  31.     size = bpr * h;  
  32.     stride = bpr / bpp;  
  33.   
  34.     int err;  
  35.     if (usage & GRALLOC_USAGE_HW_FB) {  
  36.         err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);//分配系统缓存帧  
  37.     } else {  
  38.         err = gralloc_alloc_buffer(dev, size, usage, pHandle);//分配的是内存缓存  
  39.     }  
  40.   
  41.     if (err < 0) {  
  42.         return err;  
  43.     }  
  44.   
  45.     *pStride = stride;  
  46.     return 0;  
  47. }  

这里看到usage有一种是硬件帧缓存,另一个是开辟单独的匿名内存块。当然数据直接写入FramerBuffer是最快的,但往往一个帧缓存是远远不够的,故而这里将还会创建匿名的pmem来作为图像缓冲区,但帧缓存只有一个。这里的buffer_handle_t *pHandle最终可以理解为是图形缓存在当前应用程序mmap后的用户空间地址。使得后续的图像渲染等直接对用户空间操作即可。

 

到这里我们返回到了SurfaceTextureClient::dequeueBuffer函数中去,完成mSurfaceTexture->dequeueBuffer函数返回后,可以看到如果当前的在服务端从新分配了图像缓存后ISurfaceTexture::BUFFER_NEEDS_REALLOCATION,将调用requestBuffer函数,来看看为何还要这么处理?

依旧是BpSurfaceTexture来处理

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {  
  2.     Parcel data, reply;  
  3.     data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());  
  4.     data.writeInt32(bufferIdx);  
  5.     status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);  
  6.     if (result != NO_ERROR) {  
  7.         return result;  
  8.     }  
  9.     bool nonNull = reply.readInt32();  
  10.     if (nonNull) {  
  11.         *buf = new GraphicBuffer();//应用程序侧也新建一个图形缓存  
  12.         reply.read(**buf);//buf生成  
  13.     }  
  14.     result = reply.readInt32();  
  15.     return result;  
  16. }  

对应在BnSurfaceTexture侧的响应如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t BnSurfaceTexture::onTransact(  
  2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  3. {  
  4.     switch(code) {  
  5.         case REQUEST_BUFFER: {  
  6.             CHECK_INTERFACE(ISurfaceTexture, data, reply);  
  7.             int bufferIdx   = data.readInt32();  
  8.             sp<GraphicBuffer> buffer;  
  9.             int result = requestBuffer(bufferIdx, &buffer);  
  10.             reply->writeInt32(buffer != 0);  
  11.             if (buffer != 0) {  
  12.                 reply->write(*buffer);  
  13.             }  
  14.             reply->writeInt32(result);  
  15.             return NO_ERROR;  
  16.         } break;  

通过客户端传递过来的数据,即一个buffer的索引id,在BufferQueue里调用requestBuffer函数

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {  
  2.     int maxBufferCount = getMaxBufferCountLocked();  
  3.     if (slot < 0 || maxBufferCount <= slot) {  
  4.         ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",  
  5.                 maxBufferCount, slot);  
  6.         return BAD_VALUE;  
  7.     } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {  
  8.         // XXX: I vaguely recall there was some reason this can be valid, but  
  9.         // for the life of me I can't recall under what circumstances that's  
  10.         // the case.  
  11.         ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",  
  12.                 slot, mSlots[slot].mBufferState);  
  13.         return BAD_VALUE;  
  14.     }  
  15.     mSlots[slot].mRequestBufferCalled = true;  
  16.     *buf = mSlots[slot].mGraphicBuffer;  
  17.     return NO_ERROR;  
  18. }  

上述函数通过这个buffer的索引值,找到对应的BufferSlot后,返回的是这个他维护着的服务端的sp<GraphicBuffer> mGraphicBuffer成员,这里有必要看下最终的                reply->write(*buffer);写入过程,他的实现如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t Parcel::write(const Flattenable& val)  
  2. {    err = val.flatten(buf, len, fds, fd_count);//对buffer进行写入调用,GraphicBuffer::flatten  
  3. .............  
  4. }  

之所以哪呢过将这个buffer写入在于GraphicBuffer的特殊性,该类继承了一个Flattenable类,最终调用下面的函数

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t GraphicBuffer::flatten(void* buffer, size_t size,//发送端打包  
  2.         int fds[], size_t count) const  
  3. {  
  4.     size_t sizeNeeded = GraphicBuffer::getFlattenedSize();  
  5.     if (size < sizeNeeded) return NO_MEMORY;  
  6.   
  7.     size_t fdCountNeeded = GraphicBuffer::getFdCount();  
  8.     if (count < fdCountNeeded) return NO_MEMORY;  
  9.   
  10.     int* buf = static_cast<int*>(buffer);  
  11.     buf[0] = 'GBFR';  
  12.     buf[1] = width;  
  13.     buf[2] = height;  
  14.     buf[3] = stride;  
  15.     buf[4] = format;  
  16.     buf[5] = usage;  
  17.     buf[6] = 0;  
  18.     buf[7] = 0;  
  19.   
  20.     if (handle) {  
  21.         buf[6] = handle->numFds;  
  22.         buf[7] = handle->numInts;  
  23.         native_handle_t constconst h = handle;  
  24.         memcpy(fds,     h->data,             h->numFds*sizeof(int));  
  25.         memcpy(&buf[8], h->data + h->numFds, h->numInts*sizeof(int));  
  26.     }  
  27.   
  28.     return NO_ERROR;  
  29. }  

上述函数将GraphicBuffer的信息初始化到buf数组里面,最终数据都写入到reply中返回。

而同样在requestbuffer的客户端处,是对接收到的数据的解析,解析使用下面的过程实现:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. BpSurfaceTexture(const sp<IBinder>& impl)  
  2.     : BpInterface<ISurfaceTexture>(impl)  
  3. {  
  4. }  
  5.   
  6. virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {  
  7.     Parcel data, reply;  
  8.     data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());  
  9.     data.writeInt32(bufferIdx);  
  10.     status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);  
  11.     if (result != NO_ERROR) {  
  12.         return result;  
  13.     }  
  14.     bool nonNull = reply.readInt32();  
  15.     if (nonNull) {  
  16.         *buf = new GraphicBuffer();//应用程序侧也新建一个图形缓存  
  17.         reply.read(**buf);//buf生成  
  18.     }  
  19.     result = reply.readInt32();  
  20.     return result;  
  21. }  

首先是新建一个应用程序客户端侧的一个GraphicBuffer对象,然后利用服务端返回的reply信息填充并初始化GraphicBuffer

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t Parcel::read(Flattenable& val) const  
  2. {  
  3.     // size  
  4.     if (err == NO_ERROR) {  
  5.         err = val.unflatten(buf, len, fds, fd_count);//解析出信息到buffer  
  6.     }  
  7. ...  
  8. }  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t GraphicBuffer::unflatten(void const* buffer, size_t size,  
  2.         int fds[], size_t count)//接收端解析  
  3. {  
  4.     if (size < 8*sizeof(int)) return NO_MEMORY;  
  5.   
  6.     int const* buf = static_cast<int const*>(buffer);  
  7.     if (buf[0] != 'GBFR'return BAD_TYPE;  
  8.   
  9.     const size_t numFds  = buf[6];  
  10.     const size_t numInts = buf[7];  
  11.   
  12.     const size_t sizeNeeded = (8 + numInts) * sizeof(int);  
  13.     if (size < sizeNeeded) return NO_MEMORY;  
  14.   
  15.     size_t fdCountNeeded = 0;  
  16.     if (count < fdCountNeeded) return NO_MEMORY;  
  17.   
  18.     if (handle) {  
  19.         // free previous handle if any  
  20.         free_handle();  
  21.     }  
  22.   
  23.     if (numFds || numInts) {  
  24.         width  = buf[1];  
  25.         height = buf[2];  
  26.         stride = buf[3];  
  27.         format = buf[4];  
  28.         usage  = buf[5];  
  29.         native_handle* h = native_handle_create(numFds, numInts);//创建本地的图像缓存buffer  
  30.         memcpy(h->data,          fds,     numFds*sizeof(int));//文件描述符  
  31.         memcpy(h->data + numFds, &buf[8], numInts*sizeof(int));//数据  
  32.         handle = h;  
  33.     } else {  
  34.         width = height = stride = format = usage = 0;  
  35.         handle = NULL;  
  36.     }  
  37.   
  38.     mOwner = ownHandle;  
  39.   
  40.     if (handle != 0) {  
  41.         status_t err = mBufferMapper.registerBuffer(handle);//buffer注册,即将这个图像缓存mmap映射到当前的用户进程  
  42.         if (err != NO_ERROR) {  
  43.             ALOGE("unflatten: registerBuffer failed: %s (%d)",  
  44.                     strerror(-err), err);  
  45.             return err;  
  46.         }  
  47.     }  
  48.   
  49.     return NO_ERROR;  
  50. }  

在flatten和unflatten函数其实就是为了满足Binder数据的通信协议Parcel而设计的(用于传输对象变量),在unflatten函数中完成了对数据的解析后获得了一个handle,利用这个handle进行了registerBuffer的操作。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)  
  2. {  
  3.     ATRACE_CALL();  
  4.     status_t err;  
  5.   
  6.     err = mAllocMod->registerBuffer(mAllocMod, handle);//Client端可以将指定的内存区域映射到自己的进程空间  
  7.   
  8.     ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)",  
  9.             handle, err, strerror(-err));  
  10.     return err;  
  11. }  

这里又回到了客户端侧的,的确这里很好奇的是在服务端侧也有过GraphicBuffer的存在,而客户端侧却还要创建一个GraphicBuffer,这个原因是什么呢?

来看看Gralloc模块对registerBuffer的实现吧:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int gralloc_register_buffer(gralloc_module_t const* module,  
  2.         buffer_handle_t handle)  
  3. {  
  4.     if (private_handle_t::validate(handle) < 0)  
  5.         return -EINVAL;  
  6.   
  7.     // if this handle was created in this process, then we keep it as is.  
  8.     int err = 0;  
  9.     private_handle_t* hnd = (private_handle_t*)handle;  
  10.     if (hnd->pid != getpid()) {  
  11.         void *vaddr;  
  12.         err = gralloc_map(module, handle, &vaddr);  
  13.     }  
  14.     return err;  
  15. }  

调用gralloc模块中的gralloc_map完成mmap的相关操作:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static int gralloc_map(gralloc_module_t const* module,  
  2.         buffer_handle_t handle,  
  3.         void** vaddr)  
  4. {  
  5.     private_handle_t* hnd = (private_handle_t*)handle;  
  6.     if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {  
  7.         size_t size = hnd->size;  
  8.         void* mappedAddress = mmap(0, size,  
  9.                 PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);//将匿名共享内存mmap到用户空间  
  10.         if (mappedAddress == MAP_FAILED) {  
  11.             ALOGE("Could not mmap %s", strerror(errno));  
  12.             return -errno;  
  13.         }  
  14.         hnd->base = intptr_t(mappedAddress) + hnd->offset;  
  15.         //ALOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",  
  16.         //        hnd->fd, hnd->offset, hnd->size, mappedAddress);  
  17.     }  
  18.     *vaddr = (void*)hnd->base;  
  19.     return 0;  
  20. }  

这里的逻辑应该是handle维护着映射到用户空间的虚拟地址,hnd->base就包含了这个信息,而hnd->fd应该是一个内存设备的描述符。最终这里就通过这个handle将服务端申请并分配的图形内存缓冲区(无论是帧缓存还是匿名的ashmem)共享到客户端,两者都以GrallocBuffer对象的形式存在。

 

到此为止分析基于OpenGL ES的ANativeWindow和ANativeWindowBuffer的dequeueBuffer的分析基本完成了,下面以2个简易的流程图来进行总结,方便自己理解,图1是OpenGL ES所需要的在应用层的Surface创建的一个过程,如果图片看不清,可以下载地址SurfaceFlinger应用端创建surface的过程图



 

  


 

图2: 图形缓存GraphicBuffer的申请与分配图
 

 

这里继续补充在应用程序侧和服务侧的GraphicBuffer,这两个图形缓存区的区别与联系:

1.在BufferQueue的构造函数中有mGraphicBufferAlloc = composer->createGraphicBufferAlloc(),显然是由SF进程来完成这个对象的创建的,故SF维护着mGraphicBufferAlloc这个匿名的本地Binder服务,并传递给BufferQueue维护。

2.BufferQueue中请求createGraphicBuffer时,还是有SF来完成,故缓存的实际创建还是有SF进程来完成的,由createGraphicBuffer里的new GraphicBuffer();在SF侧创建实际的图形缓存。

3.交给GraphicBufferAllocator来完成gralloc的图形缓存的申请并完成映射。分为gralloc_alloc_framebuffer和gralloc_alloc_buffer两种,前者是直接在帧缓存中分配出图像缓存,后者是直接申请一个匿名共享内存来做为图形缓存区。最终申请并完成映射到SF处的图像缓存以buffer_handle_t的类型维护着。

4.在服务端SF那里有了图像缓存后,应用端势必也需要有服务端图像缓冲区的信息,将实际的图像内存维护到应用侧的用户空间。这个过程是在requestBuffer来完成的:

实际是有GraphicBuffer来完成,其中GraphicBufferMapper来维护Gralloc模块的打开,以及gralloc_module_t回调registerBuffer。gralloc的registerBuffer实际就是用来用户空间注册缓存,而注册实际只是一个mmap的过程,映射到用户空间。

 

这样在内核中开辟的一个内存空间,在服务端被映射,在应用端也完成映射,故使得最终的操作都是同一块内存图形区域,建立了紧密的联系。

 


 

 

本文转载自:http://blog.csdn.net/jingxia2008/article/details/49249899

RoyceInWh

RoyceInWh

粉丝 5
博文 240
码字总数 1282
作品 0
武汉
程序员
私信 提问
Android窗口管理分析(4):Android View绘制内存的分配、传递、使用

前文Android匿名共享内存(Ashmem)原理分析了匿名共享内存,它最主要的作用就是View视图绘制,Android视图是按照一帧一帧显示到屏幕的,而每一帧都会占用一定的存储空间,通过Ashmem机制APP...

看书的小蜗牛
2017/10/20
0
0
Android 中的framebuffer和SurFaceFlinger的关系

FrameBuffer 在Android中并不像在其它GUI那样直观,抽象的层次比较多,加上GUI的更新是通过OpenGLES来做的。所以让人很难搞清GUI更新的整个流程,最近要准备一个讲稿,所以花了一些去研究,这...

天王盖地虎626
06/06
20
0
「Android」SurfaceFlinger分析

本篇针对surfaceFlinger模块进行分析,目录如下: 1、SurfaceFlinger功能   1.1、BufferQueue原理(native/libs/gui模块)   1.2 layer显示内存分配(native/libs/ui模块)   1.3、sur...

sunwengang
2018/10/18
0
0
Android硬件加速(二)-RenderThread与OpenGL GPU渲染

Android4.0之后,系统默认开启硬件加速来渲染视图,之前,理解Android硬件加速的小白文简单的讲述了硬件加速的简单模型,不过主要针对前半阶段,并没怎么说是如何使用OpenGL、GPU处理数据的,...

看书的小蜗牛
2018/08/07
0
0
Android BufferQueue与Open GLES杂记

Android官方整体结构: 在Android的framework的surfaceflinger中创建Surface时会创建OpenGL的纹理 具体代码实现是在Layer类中,代码如下: 最后将纹理保存到SurfaceFlingerConsumer中 Buffer...

DB_Terrill
2018/06/28
1
1

没有更多内容

加载失败,请刷新页面

加载更多

maven 环境隔离

解决问题 即 在 resource 文件夹下面 ,新增对应的资源配置文件夹,对应 开发,测试,生产的不同的配置内容 <resources> <resource> <directory>src/main/resources.${deplo......

之渊
今天
8
0
Linux创建yum仓库

第一步、搞定自己的光盘 #创建文件夹 mkdir -p /media/cdrom #挂载光盘 mount /dev/cdrom /media/cdrom #编辑配置文件使其永久生效 vim /etc/fstab 第二步,编辑yun源 vim /ect yum.repos.d...

究极小怪兽zzz
今天
6
0
jar 更新部分文件

C:\Program Files (x86)\Java\jdk1.8.0_102\bin>jar -hIllegal option: hUsage: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...Options: -c c......

圣洁之子
今天
9
0
OSChina 周六乱弹 —— 感谢女装红薯开办了这个网站

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @胖达panda:分享歌词: 我有一只小毛驴我从来也不骑,有一天我心血来潮骑着去赶集,我手里拿着小皮鞭我心里正得意,不知怎么哗啦啦,我摔了一...

小小编辑
今天
2.6K
13
DDD(四)

1,引言 软件开发者大多趋向于将关注点放在数据上,而不是领域上。这对于刚入门的DDD的新手而言也是如此。以我目前的思考方式,数据库依然占据主要的地位。开发一个功能,首先我就会考虑我会...

MrYuZixian
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部