BufferQueue介绍

我们从下面几个文件开始分析Surface相关知识

  1. frameworks/native/libs/gui/tests/
  2. frameworks/native/opengl/tests/EGLTest/
  3. frameworks/native/libs/nativedisplay/surfacetexture/

一. 基本知识

先看下继承关系:

74  class Surface
75      : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
76  {

Surface继承ANativeWindow和RefBase
再看下构造函数:

99      explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false,
100                       const sp<IBinder>& surfaceControlHandle = nullptr);

可以看到new Surface的时候就会指定producer是谁。一般都是通过下面方式传入的:

148      sp<IGraphicBufferProducer> producer;
149      sp<IGraphicBufferConsumer> consumer;
150      BufferQueue::createBufferQueue(&producer, &consumer);
152      sp<Surface> mSTC = new Surface(producer);

1.先看下BufferQueue的创建

101  void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
102          sp<IGraphicBufferConsumer>* outConsumer,
103          bool consumerIsSurfaceFlinger) {  //默认false
109      sp<BufferQueueCore> core(new BufferQueueCore());
 
113      sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));

117      sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));

121      *outProducer = producer;
122      *outConsumer = consumer;
123  }

三个对象:BufferQueueCore、BufferQueueProducer、BufferQueueConsumer

1)BufferQueueCore

构造的时候几个关键的变量
️mConsumerName:
String8::format("unnamed-%d-%d", getpid(),
63 android_atomic_inc(&counter));
当然后期也可以通过函数接口重新设置:

719  status_t BufferQueueConsumer::setConsumerName(const String8& name) {
720      ATRACE_CALL();
721      BQ_LOGV("setConsumerName: '%s'", name.string());
722      std::lock_guard<std::mutex> lock(mCore->mMutex);
723      mCore->mConsumerName = name;
724      mConsumerName = name;
725      return NO_ERROR;
726  }

️mFreeSlots

134      int numStartingBuffers = getMaxBufferCountLocked();
135      for (int s = 0; s < numStartingBuffers; s++) {
136          mFreeSlots.insert(s);
137      }

可以看到初始化时mFreeSlots数量由getMaxBufferCountLocked函数决定。

246  int BufferQueueCore::getMaxBufferCountLocked() const {
247      int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
248              ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0);
249  
250      // limit maxBufferCount by mMaxBufferCount always
251      maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);
252  
253      return maxBufferCount;
254  }

由于mMaxBufferCount基本等于BufferQueueDefs::NUM_BUFFER_SLOTS,当然也可以调用consumer的BufferQueueConsumer::setMaxBufferCount函数重新设置,因此可以看出getMaxBufferCountLocked由mMaxAcquiredBufferCount和mMaxDequeuedBufferCount以及+1(mAsyncMode/mDequeueBufferCannotBlock)决定。
mMaxAcquiredBufferCount在BufferQueueCore初始化为1,也可以通过BufferQueueConsumer::setMaxAcquiredBufferCount函数重新设置。
mMaxDequeuedBufferCount在BufferQueueCore初始化为1,也可以通过 BufferQueueProducer::setMaxDequeuedBufferCount函数重新设置。
通过mMaxDequeuedBufferCount名字上可以看出由producer设置,而mMaxBufferCount/mMaxAcquiredBufferCount 是由consumer设置。
而mAsyncMode默认是false,也可以由producer端的BufferQueueProducer::setAsyncMode函数进行设置。
mDequeueBufferCannotBlock默认也是false,这个变量容易出问题会使得总buffer数量+1,值得注意下!在producer端connect时:mDequeueBufferCannotBlock默认是false,但是如果producer和consumer端由app控制的话那么下面判断会进入:

1311      if (mCore->mConsumerControlledByApp && producerControlledByApp) {
1312          mCore->mDequeueBufferCannotBlock = mDequeueTimeout < 0;
1313          mCore->mQueueBufferCanDrop = mDequeueTimeout <= 0;
1314      }

会根据mDequeueTimeout变量(默认为-1)决定mDequeueBufferCannotBlock的值,如果是surfaceTexture,那么该判断会进入,但是如果没有调用BufferQueueProducer::setDequeueTimeout,那么mDequeueTimeout为-1,mDequeueBufferCannotBlock值会为true。因此,如果发现buffer多了一个,看下dump信息,是不是这个变量为true了。

️mUnusedSlots
mUnusedSlots表示目前没有使用的buffer,也就是用64-当前buffer数量

138      for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
139              s++) {
140          mUnusedSlots.push_front(s);
141      }

️mDefaultWidth/mDefaultHeight
默认为1,可以通过下面的consumer端重新设置,记得和producer端的函数有区是分的哦。Surface.cpp中也有同样的变量,是从当前BufferQueueCore中取的。

595  status_t BufferQueueConsumer::setDefaultBufferSize(uint32_t width,
596          uint32_t height) {
597      ATRACE_CALL();
608      mCore->mDefaultWidth = width;
609      mCore->mDefaultHeight = height;
610      return NO_ERROR;
611  }

对应其他模块调用:mConsumer->setDefaultBufferSize(w, h)
如:frameworks/native/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp

️ mConsumerControlledByApp
既有producer端的也有consumer端的,共同决定前面说的mDequeueBufferCannotBlock变量。
如:SurfaceTexture设置过程如下:

frameworks/base/core/jni/android_graphics_SurfaceTexture.cpp
234  static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
235          jint texName, jboolean singleBufferMode, jobject weakThiz)
236  {
237      sp<IGraphicBufferProducer> producer;
238      sp<IGraphicBufferConsumer> consumer;
239      BufferQueue::createBufferQueue(&producer, &consumer);
245      sp<SurfaceTexture> surfaceTexture;
246      if (isDetached) {
247          surfaceTexture = new SurfaceTexture(consumer, GL_TEXTURE_EXTERNAL_OES,  //根据singleBuffer确认mConsumerControlledByApp
248                  true, !singleBufferMode);
249      } else {
250          surfaceTexture = new SurfaceTexture(consumer, texName,
251                  GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode); //根据singleBuffer确认mConsumerControlledByApp
252      }

frameworks/native/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
36  SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
37                                 uint32_t texTarget, bool useFenceSync, bool isControlledByApp)
38        : ConsumerBase(bq, isControlledByApp),

frameworks/native/libs/gui/ConsumerBase.cpp
58  ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) {
72      status_t err = mConsumer->consumerConnect(proxy, controlledByApp);

frameworks/native/libs/gui/include/gui/BufferQueueConsumer.h
165      virtual status_t consumerConnect(const sp<IConsumerListener>& consumer,
166              bool controlledByApp) {
167          return connect(consumer, controlledByApp);
168      }

frameworks/native/libs/gui/BufferQueueConsumer.cpp
511  status_t BufferQueueConsumer::connect(
512          const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
513      ATRACE_CALL();
531      mCore->mConsumerControlledByApp = controlledByApp;
532  
533      return NO_ERROR;
534  }

2)BufferQueueProducer

️ mSlots
取的是BufferQueueCore中的mSlots
mSlots(core->mSlots)

3)BufferQueueConsumer

️ mSlots
取的是BufferQueueCore中的mSlots
mSlots(core->mSlots)

2. 回到主线上去看Surface中的成员变量

️mGraphicBufferProducer
指向BufferQueueProducer

️ mProducerControlledByApp
在new Surface的时候传入,这个值会被设置到BufferQueueProducer用于判断上面说的mDequeueBufferCannotBlock值。需要注意哦!
mProducerControlledByApp = controlledByApp
如:
TextureView:

frameworks/base/core/jni/android_view_TextureView.cpp
sp<ANativeWindow> window = new Surface(producer, true);

SurfaceTexture:

frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp
301      sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(_env, native_window));
302      window = new Surface(producer, true);
frameworks/base/core/jni/android_view_Surface.cpp
android_view_Surface_createFromIGraphicBufferProducer
135      sp<Surface> surface(new Surface(bufferProducer, true));
nativeCreateFromSurfaceTexture
156      sp<Surface> surface(new Surface(producer, true));

️mReqWidth/mReqHeight

2079  int Surface::setBuffersDimensions(uint32_t width, uint32_t height)
2080  {
2081      ATRACE_CALL();        //有trace标签
2082      ALOGV("Surface::setBuffersDimensions");  //有log
2091      mReqWidth = width;
2092      mReqHeight = height;
2093      return NO_ERROR;
2094  }

对应其他模块调用:native_window_set_buffers_dimensions

️ mUserWidth/mUserHeight
Surface::setBuffersUserDimensions
对应其他模块调用:native_window_set_buffers_user_dimensions
可以看到和req的有点类似,使用时二者选1,首选req的:

157 uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; // in allocateBuffers()
554 dequeueInput->height = mReqHeight ? mReqHeight : mUserHeight; //in getDequeueBufferInputLocked()

query时查询方式:

1234              case NATIVE_WINDOW_DEFAULT_WIDTH:
1235                  *value = static_cast<int>(
1236                          mUserWidth ? mUserWidth : mDefaultWidth);
1237                  return NO_ERROR;
1238              case NATIVE_WINDOW_DEFAULT_HEIGHT:
1239                  *value = static_cast<int>(
1240                          mUserHeight ? mUserHeight : mDefaultHeight);
1241                  return NO_ERROR;

一般user的很少设置,目前没有碰到过这类问题。

️mDefaultWidth/mDefaultHeight
来源于BufferQueue中queueBuffer,取自BufferQueueCore。
1029 output->width = mCore->mDefaultWidth;
1030 output->height = mCore->mDefaultHeight;

️mReqFormat
Surface::setBuffersFormat(PixelFormat format)
对应其他模块调用:native_window_set_buffers_format

️mReqUsage
Surface::setUsage(uint64_t reqUsage)
对应其他模块调用:native_window_set_usage

二.BLASTBufferQueue

147  BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame) {
155      createBufferQueue(&mProducer, &mConsumer);  //保存起来
156      // since the adapter is in the client process, set dequeue timeout
157      // explicitly so that dequeueBuffer will block
158      mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());//那么mDequeueBufferCannotBlock就不会true了
159  
160      // safe default, most producers are expected to override this
161      mProducer->setMaxDequeuedBufferCount(2);     //设置dequeuecount=2
162      mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
163                                                        GraphicBuffer::USAGE_HW_COMPOSER |
164                                                                GraphicBuffer::USAGE_HW_TEXTURE,
165                                                        1, false, this);  //有usage哦!
166      static std::atomic<uint32_t> nextId = 0;
167      mProducerId = nextId++;
168      mName = name + "#" + std::to_string(mProducerId);
169      auto consumerName = mName + "(BLAST Consumer)" + std::to_string(mProducerId);
170      mQueuedBufferTrace = "QueuedBuffer - " + mName + "BLAST#" + std::to_string(mProducerId);//perfetto名字
171      mBufferItemConsumer->setName(String8(consumerName.c_str()));  //设置consumerName
172      mBufferItemConsumer->setFrameAvailableListener(this);
173  
174      ComposerServiceAIDL::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);//高刷一般2个,低刷1个
175      mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);  //设置acquirecount
176      mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;

1133  void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
1134                                           sp<IGraphicBufferConsumer>* outConsumer) {
1138      sp<BufferQueueCore> core(new BufferQueueCore());
1141      sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core, this));
1145      sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
1146      consumer->setAllowExtraAcquire(true);
1150      *outProducer = producer;
1151      *outConsumer = consumer;
1152  }

可以看出,和普通BufferQueue的区别是producer换成了BBQBufferQueueProducer,多调用了setAllowExtraAcquire函数。
看下继承关系就一目了然了:

1081  class BBQBufferQueueProducer : public BufferQueueProducer {
1082  public:
1083      BBQBufferQueueProducer(const sp<BufferQueueCore>& core, wp<BLASTBufferQueue> bbq)
1084            : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/),  //可以看到此处为false
1085              mBLASTBufferQueue(std::move(bbq)) {}

为什么consumerIsSurfaceFlinger为false呢?
我们知道从BLASTBufferQueue出现后buffer的dequeue/queue动作都发生在APP进程了,之前都是发生在SF进程,所以可想而知,此变量就应该是false的。目前代码中好像没有看到有设置true的地方。

再回到BLASTBufferQueue 中看下BLASTBufferItemConsumer

38  class BLASTBufferItemConsumer : public BufferItemConsumer {
39  public:
40      BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
41                              int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
42            : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
43              mBLASTBufferQueue(std::move(bbq)),

class BufferItemConsumer: public ConsumerBase
35  BufferItemConsumer::BufferItemConsumer(
36          const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
37          int bufferCount, bool controlledByApp) :
38      ConsumerBase(consumer, controlledByApp) //构建consumerBase
39  {
40      status_t err = mConsumer->setConsumerUsageBits(consumerUsage);//设置BufferQueueConsumer的usage
43      if (bufferCount != DEFAULT_MAX_BUFFERS) {
44          err = mConsumer->setMaxAcquiredBufferCount(bufferCount);//设置acquireBufferCount,后面会被覆盖重写
47      }
48  }

58  ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
59          mAbandoned(false),
60          mConsumer(bufferQueue),
61          mPrevFinalReleaseFence(Fence::NO_FENCE) {
62      // Choose a name using the PID and a process-unique ID.
63      mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
64  
69      wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
70      sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
71  
72      status_t err = mConsumer->consumerConnect(proxy, controlledByApp);  //connect,设置consumerControlByApp为false
73      if (err != NO_ERROR) {
74          CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
75                  strerror(-err), err);
76      } else {
77          mConsumer->setConsumerName(mName);  //setName,后面会被重写
78      }
79  }

以上mConsumer均为BufferQueueConsumer对象!!!!;
usage为GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_HW_TEXTURE;bufferCount为1;controlledByApp为false。

再回到BLASTBufferQueue中可以看到后面又重新调用
setName、setMaxAcquiredBufferCount,覆盖了之前new BLASTBufferItemConsumer阶段覆的值,但是usage没有重新赋值。

再看看对应的Surface:

953  sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
954      std::lock_guard _lock{mMutex};
955      sp<IBinder> scHandle = nullptr;
956      if (includeSurfaceControlHandle && mSurfaceControl) {
957          scHandle = mSurfaceControl->getHandle();
958      }
959      return new BBQSurface(mProducer, true, scHandle, this);//记住此处mProducerControlledByApp为true哦。
960  }

873  class BBQSurface : public Surface {
880      BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
881                 const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
882            : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}

884      void allocateBuffers() override {
885          uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;
886          uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;
887          auto gbp = getIGraphicBufferProducer();
888          std::thread ([reqWidth, reqHeight, gbp=getIGraphicBufferProducer(),
889                        reqFormat=mReqFormat, reqUsage=mReqUsage] () {
890              gbp->allocateBuffers(reqWidth, reqHeight,
891                                   reqFormat, reqUsage);  //起单独线程做
892  
893          }).detach();
894      }

80      sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
81          return mProducer;  //拿BBQBufferQueueProducer
82      }

可以看出来通过拿到BBQSurface来进行buffer申请,而且是启用单独的线程做分配buffer的动作,从perfetto中可以看出来哦。
allocateBuffers在APP冷启动的时候调用,如果后面width/height/usage/format等变化会重新dequeueBuffer,如:旋转。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容