Home | History | Annotate | Download | only in gui
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "RingBufferConsumer"
     19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
     20 
     21 #include <inttypes.h>
     22 
     23 #include <utils/Log.h>
     24 
     25 #include <gui/RingBufferConsumer.h>
     26 
     27 #define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
     28 #define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
     29 #define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
     30 #define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
     31 #define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
     32 
     33 #undef assert
     34 #define assert(x) ALOG_ASSERT((x), #x)
     35 
     36 typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
     37 
     38 namespace android {
     39 
     40 RingBufferConsumer::RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer,
     41         uint32_t consumerUsage,
     42         int bufferCount) :
     43     ConsumerBase(consumer),
     44     mBufferCount(bufferCount),
     45     mLatestTimestamp(0)
     46 {
     47     mConsumer->setConsumerUsageBits(consumerUsage);
     48     mConsumer->setMaxAcquiredBufferCount(bufferCount);
     49 
     50     assert(bufferCount > 0);
     51 }
     52 
     53 RingBufferConsumer::~RingBufferConsumer() {
     54 }
     55 
     56 void RingBufferConsumer::setName(const String8& name) {
     57     Mutex::Autolock _l(mMutex);
     58     mName = name;
     59     mConsumer->setConsumerName(name);
     60 }
     61 
     62 sp<PinnedBufferItem> RingBufferConsumer::pinSelectedBuffer(
     63         const RingBufferComparator& filter,
     64         bool waitForFence) {
     65 
     66     sp<PinnedBufferItem> pinnedBuffer;
     67 
     68     {
     69         List<RingBufferItem>::iterator it, end, accIt;
     70         BufferInfo acc, cur;
     71         BufferInfo* accPtr = NULL;
     72 
     73         Mutex::Autolock _l(mMutex);
     74 
     75         for (it = mBufferItemList.begin(), end = mBufferItemList.end();
     76              it != end;
     77              ++it) {
     78 
     79             const RingBufferItem& item = *it;
     80 
     81             cur.mCrop = item.mCrop;
     82             cur.mTransform = item.mTransform;
     83             cur.mScalingMode = item.mScalingMode;
     84             cur.mTimestamp = item.mTimestamp;
     85             cur.mFrameNumber = item.mFrameNumber;
     86             cur.mPinned = item.mPinCount > 0;
     87 
     88             int ret = filter.compare(accPtr, &cur);
     89 
     90             if (ret == 0) {
     91                 accPtr = NULL;
     92             } else if (ret > 0) {
     93                 acc = cur;
     94                 accPtr = &acc;
     95                 accIt = it;
     96             } // else acc = acc
     97         }
     98 
     99         if (!accPtr) {
    100             return NULL;
    101         }
    102 
    103         pinnedBuffer = new PinnedBufferItem(this, *accIt);
    104         pinBufferLocked(pinnedBuffer->getBufferItem());
    105 
    106     } // end scope of mMutex autolock
    107 
    108     if (waitForFence) {
    109         status_t err = pinnedBuffer->getBufferItem().mFence->waitForever(
    110                 "RingBufferConsumer::pinSelectedBuffer");
    111         if (err != OK) {
    112             BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
    113                     strerror(-err), err);
    114         }
    115     }
    116 
    117     return pinnedBuffer;
    118 }
    119 
    120 status_t RingBufferConsumer::clear() {
    121 
    122     status_t err;
    123     Mutex::Autolock _l(mMutex);
    124 
    125     BI_LOGV("%s", __FUNCTION__);
    126 
    127     // Avoid annoying log warnings by returning early
    128     if (mBufferItemList.size() == 0) {
    129         return OK;
    130     }
    131 
    132     do {
    133         size_t pinnedFrames = 0;
    134         err = releaseOldestBufferLocked(&pinnedFrames);
    135 
    136         if (err == NO_BUFFER_AVAILABLE) {
    137             assert(pinnedFrames == mBufferItemList.size());
    138             break;
    139         }
    140 
    141         if (err == NOT_ENOUGH_DATA) {
    142             // Fine. Empty buffer item list.
    143             break;
    144         }
    145 
    146         if (err != OK) {
    147             BI_LOGE("Clear failed, could not release buffer");
    148             return err;
    149         }
    150 
    151     } while(true);
    152 
    153     return OK;
    154 }
    155 
    156 nsecs_t RingBufferConsumer::getLatestTimestamp() {
    157     Mutex::Autolock _l(mMutex);
    158     if (mBufferItemList.size() == 0) {
    159         return 0;
    160     }
    161     return mLatestTimestamp;
    162 }
    163 
    164 void RingBufferConsumer::pinBufferLocked(const BufferItem& item) {
    165     List<RingBufferItem>::iterator it, end;
    166 
    167     for (it = mBufferItemList.begin(), end = mBufferItemList.end();
    168          it != end;
    169          ++it) {
    170 
    171         RingBufferItem& find = *it;
    172         if (item.mGraphicBuffer == find.mGraphicBuffer) {
    173             find.mPinCount++;
    174             break;
    175         }
    176     }
    177 
    178     if (it == end) {
    179         BI_LOGE("Failed to pin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
    180                  item.mTimestamp, item.mFrameNumber);
    181     } else {
    182         BI_LOGV("Pinned buffer (frame %" PRIu64 ", timestamp %" PRId64 ")",
    183                 item.mFrameNumber, item.mTimestamp);
    184     }
    185 }
    186 
    187 status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) {
    188     status_t err = OK;
    189 
    190     List<RingBufferItem>::iterator it, end, accIt;
    191 
    192     it = mBufferItemList.begin();
    193     end = mBufferItemList.end();
    194     accIt = end;
    195 
    196     if (it == end) {
    197         /**
    198          * This is fine. We really care about being able to acquire a buffer
    199          * successfully after this function completes, not about it releasing
    200          * some buffer.
    201          */
    202         BI_LOGV("%s: No buffers yet acquired, can't release anything",
    203               __FUNCTION__);
    204         return NOT_ENOUGH_DATA;
    205     }
    206 
    207     for (; it != end; ++it) {
    208         RingBufferItem& find = *it;
    209 
    210         if (find.mPinCount > 0) {
    211             if (pinnedFrames != NULL) {
    212                 ++(*pinnedFrames);
    213             }
    214             // Filter out pinned frame when searching for buffer to release
    215             continue;
    216         }
    217 
    218         if (find.mTimestamp < accIt->mTimestamp || accIt == end) {
    219             accIt = it;
    220         }
    221     }
    222 
    223     if (accIt != end) {
    224         RingBufferItem& item = *accIt;
    225 
    226         // In case the object was never pinned, pass the acquire fence
    227         // back to the release fence. If the fence was already waited on,
    228         // it'll just be a no-op to wait on it again.
    229 
    230         // item.mGraphicBuffer was populated with the proper graphic-buffer
    231         // at acquire even if it was previously acquired
    232         err = addReleaseFenceLocked(item.mBuf,
    233                 item.mGraphicBuffer, item.mFence);
    234 
    235         if (err != OK) {
    236             BI_LOGE("Failed to add release fence to buffer "
    237                     "(timestamp %" PRId64 ", framenumber %" PRIu64,
    238                     item.mTimestamp, item.mFrameNumber);
    239             return err;
    240         }
    241 
    242         BI_LOGV("Attempting to release buffer timestamp %" PRId64 ", frame %" PRIu64,
    243                 item.mTimestamp, item.mFrameNumber);
    244 
    245         // item.mGraphicBuffer was populated with the proper graphic-buffer
    246         // at acquire even if it was previously acquired
    247         err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer,
    248                                   EGL_NO_DISPLAY,
    249                                   EGL_NO_SYNC_KHR);
    250         if (err != OK) {
    251             BI_LOGE("Failed to release buffer: %s (%d)",
    252                     strerror(-err), err);
    253             return err;
    254         }
    255 
    256         BI_LOGV("Buffer timestamp %" PRId64 ", frame %" PRIu64 " evicted",
    257                 item.mTimestamp, item.mFrameNumber);
    258 
    259         size_t currentSize = mBufferItemList.size();
    260         mBufferItemList.erase(accIt);
    261         assert(mBufferItemList.size() == currentSize - 1);
    262     } else {
    263         BI_LOGW("All buffers pinned, could not find any to release");
    264         return NO_BUFFER_AVAILABLE;
    265 
    266     }
    267 
    268     return OK;
    269 }
    270 
    271 void RingBufferConsumer::onFrameAvailable(const BufferItem& item) {
    272     status_t err;
    273 
    274     {
    275         Mutex::Autolock _l(mMutex);
    276 
    277         /**
    278          * Release oldest frame
    279          */
    280         if (mBufferItemList.size() >= (size_t)mBufferCount) {
    281             err = releaseOldestBufferLocked(/*pinnedFrames*/NULL);
    282             assert(err != NOT_ENOUGH_DATA);
    283 
    284             // TODO: implement the case for NO_BUFFER_AVAILABLE
    285             assert(err != NO_BUFFER_AVAILABLE);
    286             if (err != OK) {
    287                 return;
    288             }
    289             // TODO: in unpinBuffer rerun this routine if we had buffers
    290             // we could've locked but didn't because there was no space
    291         }
    292 
    293         RingBufferItem& item = *mBufferItemList.insert(mBufferItemList.end(),
    294                                                        RingBufferItem());
    295 
    296         /**
    297          * Acquire new frame
    298          */
    299         err = acquireBufferLocked(&item, 0);
    300         if (err != OK) {
    301             if (err != NO_BUFFER_AVAILABLE) {
    302                 BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
    303             }
    304 
    305             mBufferItemList.erase(--mBufferItemList.end());
    306             return;
    307         }
    308 
    309         BI_LOGV("New buffer acquired (timestamp %" PRId64 "), "
    310                 "buffer items %zu out of %d",
    311                 item.mTimestamp,
    312                 mBufferItemList.size(), mBufferCount);
    313 
    314         if (item.mTimestamp < mLatestTimestamp) {
    315             BI_LOGE("Timestamp  decreases from %" PRId64 " to %" PRId64,
    316                     mLatestTimestamp, item.mTimestamp);
    317         }
    318 
    319         mLatestTimestamp = item.mTimestamp;
    320 
    321         item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer;
    322     } // end of mMutex lock
    323 
    324     ConsumerBase::onFrameAvailable(item);
    325 }
    326 
    327 void RingBufferConsumer::unpinBuffer(const BufferItem& item) {
    328     Mutex::Autolock _l(mMutex);
    329 
    330     List<RingBufferItem>::iterator it, end, accIt;
    331 
    332     for (it = mBufferItemList.begin(), end = mBufferItemList.end();
    333          it != end;
    334          ++it) {
    335 
    336         RingBufferItem& find = *it;
    337         if (item.mGraphicBuffer == find.mGraphicBuffer) {
    338             status_t res = addReleaseFenceLocked(item.mBuf,
    339                     item.mGraphicBuffer, item.mFence);
    340 
    341             if (res != OK) {
    342                 BI_LOGE("Failed to add release fence to buffer "
    343                         "(timestamp %" PRId64 ", framenumber %" PRIu64,
    344                         item.mTimestamp, item.mFrameNumber);
    345                 return;
    346             }
    347 
    348             find.mPinCount--;
    349             break;
    350         }
    351     }
    352 
    353     if (it == end) {
    354         // This should never happen. If it happens, we have a bug.
    355         BI_LOGE("Failed to unpin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
    356                  item.mTimestamp, item.mFrameNumber);
    357     } else {
    358         BI_LOGV("Unpinned buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
    359                  item.mTimestamp, item.mFrameNumber);
    360     }
    361 }
    362 
    363 status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
    364     Mutex::Autolock _l(mMutex);
    365     return mConsumer->setDefaultBufferSize(w, h);
    366 }
    367 
    368 status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
    369     Mutex::Autolock _l(mMutex);
    370     return mConsumer->setDefaultBufferFormat(defaultFormat);
    371 }
    372 
    373 status_t RingBufferConsumer::setConsumerUsage(uint32_t usage) {
    374     Mutex::Autolock _l(mMutex);
    375     return mConsumer->setConsumerUsageBits(usage);
    376 }
    377 
    378 } // namespace android
    379