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