Home | History | Annotate | Download | only in device3
      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_TAG "Camera3-ZslStream"
     18 #define ATRACE_TAG ATRACE_TAG_CAMERA
     19 //#define LOG_NDEBUG 0
     20 
     21 #include <inttypes.h>
     22 
     23 #include <utils/Log.h>
     24 #include <utils/Trace.h>
     25 #include "Camera3ZslStream.h"
     26 
     27 typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
     28 
     29 namespace android {
     30 
     31 namespace camera3 {
     32 
     33 namespace {
     34 struct TimestampFinder : public RingBufferConsumer::RingBufferComparator {
     35     typedef RingBufferConsumer::BufferInfo BufferInfo;
     36 
     37     enum {
     38         SELECT_I1 = -1,
     39         SELECT_I2 = 1,
     40         SELECT_NEITHER = 0,
     41     };
     42 
     43     TimestampFinder(nsecs_t timestamp) : mTimestamp(timestamp) {}
     44     ~TimestampFinder() {}
     45 
     46     template <typename T>
     47     static void swap(T& a, T& b) {
     48         T tmp = a;
     49         a = b;
     50         b = tmp;
     51     }
     52 
     53     /**
     54      * Try to find the best candidate for a ZSL buffer.
     55      * Match priority from best to worst:
     56      *  1) Timestamps match.
     57      *  2) Timestamp is closest to the needle (and lower).
     58      *  3) Timestamp is closest to the needle (and higher).
     59      *
     60      */
     61     virtual int compare(const BufferInfo *i1,
     62                         const BufferInfo *i2) const {
     63         // Try to select non-null object first.
     64         if (i1 == NULL) {
     65             return SELECT_I2;
     66         } else if (i2 == NULL) {
     67             return SELECT_I1;
     68         }
     69 
     70         // Best result: timestamp is identical
     71         if (i1->mTimestamp == mTimestamp) {
     72             return SELECT_I1;
     73         } else if (i2->mTimestamp == mTimestamp) {
     74             return SELECT_I2;
     75         }
     76 
     77         const BufferInfo* infoPtrs[2] = {
     78             i1,
     79             i2
     80         };
     81         int infoSelectors[2] = {
     82             SELECT_I1,
     83             SELECT_I2
     84         };
     85 
     86         // Order i1,i2 so that always i1.timestamp < i2.timestamp
     87         if (i1->mTimestamp > i2->mTimestamp) {
     88             swap(infoPtrs[0], infoPtrs[1]);
     89             swap(infoSelectors[0], infoSelectors[1]);
     90         }
     91 
     92         // Second best: closest (lower) timestamp
     93         if (infoPtrs[1]->mTimestamp < mTimestamp) {
     94             return infoSelectors[1];
     95         } else if (infoPtrs[0]->mTimestamp < mTimestamp) {
     96             return infoSelectors[0];
     97         }
     98 
     99         // Worst: closest (higher) timestamp
    100         return infoSelectors[0];
    101 
    102         /**
    103          * The above cases should cover all the possibilities,
    104          * and we get an 'empty' result only if the ring buffer
    105          * was empty itself
    106          */
    107     }
    108 
    109     const nsecs_t mTimestamp;
    110 }; // struct TimestampFinder
    111 } // namespace anonymous
    112 
    113 Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height,
    114         int bufferCount) :
    115         Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
    116                             width, height,
    117                             HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
    118                             HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0) {
    119 
    120     sp<IGraphicBufferProducer> producer;
    121     sp<IGraphicBufferConsumer> consumer;
    122     BufferQueue::createBufferQueue(&producer, &consumer);
    123     mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL, bufferCount);
    124     mProducer->setName(String8("Camera2-ZslRingBufferConsumer"));
    125     mConsumer = new Surface(producer);
    126 }
    127 
    128 Camera3ZslStream::~Camera3ZslStream() {
    129 }
    130 
    131 status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) {
    132     ATRACE_CALL();
    133 
    134     status_t res;
    135 
    136     // TODO: potentially register from inputBufferLocked
    137     // this should be ok, registerBuffersLocked only calls getBuffer for now
    138     // register in output mode instead of input mode for ZSL streams.
    139     if (mState == STATE_IN_CONFIG || mState == STATE_IN_RECONFIG) {
    140         ALOGE("%s: Stream %d: Buffer registration for input streams"
    141               " not implemented (state %d)",
    142               __FUNCTION__, mId, mState);
    143         return INVALID_OPERATION;
    144     }
    145 
    146     if ((res = getBufferPreconditionCheckLocked()) != OK) {
    147         return res;
    148     }
    149 
    150     ANativeWindowBuffer* anb;
    151     int fenceFd;
    152 
    153     assert(mProducer != 0);
    154 
    155     sp<PinnedBufferItem> bufferItem;
    156     {
    157         List<sp<RingBufferConsumer::PinnedBufferItem> >::iterator it, end;
    158         it = mInputBufferQueue.begin();
    159         end = mInputBufferQueue.end();
    160 
    161         // Need to call enqueueInputBufferByTimestamp as a prerequisite
    162         if (it == end) {
    163             ALOGE("%s: Stream %d: No input buffer was queued",
    164                     __FUNCTION__, mId);
    165             return INVALID_OPERATION;
    166         }
    167         bufferItem = *it;
    168         mInputBufferQueue.erase(it);
    169     }
    170 
    171     anb = bufferItem->getBufferItem().mGraphicBuffer->getNativeBuffer();
    172     assert(anb != NULL);
    173     fenceFd = bufferItem->getBufferItem().mFence->dup();
    174 
    175     /**
    176      * FenceFD now owned by HAL except in case of error,
    177      * in which case we reassign it to acquire_fence
    178      */
    179     handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
    180                          /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false);
    181 
    182     mBuffersInFlight.push_back(bufferItem);
    183 
    184     return OK;
    185 }
    186 
    187 status_t Camera3ZslStream::returnBufferCheckedLocked(
    188             const camera3_stream_buffer &buffer,
    189             nsecs_t timestamp,
    190             bool output,
    191             /*out*/
    192             sp<Fence> *releaseFenceOut) {
    193 
    194     if (output) {
    195         // Output stream path
    196         return Camera3OutputStream::returnBufferCheckedLocked(buffer,
    197                                                               timestamp,
    198                                                               output,
    199                                                               releaseFenceOut);
    200     }
    201 
    202     /**
    203      * Input stream path
    204      */
    205     bool bufferFound = false;
    206     sp<PinnedBufferItem> bufferItem;
    207     {
    208         // Find the buffer we are returning
    209         Vector<sp<PinnedBufferItem> >::iterator it, end;
    210         for (it = mBuffersInFlight.begin(), end = mBuffersInFlight.end();
    211              it != end;
    212              ++it) {
    213 
    214             const sp<PinnedBufferItem>& tmp = *it;
    215             ANativeWindowBuffer *anb =
    216                     tmp->getBufferItem().mGraphicBuffer->getNativeBuffer();
    217             if (anb != NULL && &(anb->handle) == buffer.buffer) {
    218                 bufferFound = true;
    219                 bufferItem = tmp;
    220                 mBuffersInFlight.erase(it);
    221                 break;
    222             }
    223         }
    224     }
    225     if (!bufferFound) {
    226         ALOGE("%s: Stream %d: Can't return buffer that wasn't sent to HAL",
    227               __FUNCTION__, mId);
    228         return INVALID_OPERATION;
    229     }
    230 
    231     int releaseFenceFd = buffer.release_fence;
    232 
    233     if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
    234         if (buffer.release_fence != -1) {
    235             ALOGE("%s: Stream %d: HAL should not set release_fence(%d) when "
    236                   "there is an error", __FUNCTION__, mId, buffer.release_fence);
    237             close(buffer.release_fence);
    238         }
    239 
    240         /**
    241          * Reassign release fence as the acquire fence incase of error
    242          */
    243         releaseFenceFd = buffer.acquire_fence;
    244     }
    245 
    246     /**
    247      * Unconditionally return buffer to the buffer queue.
    248      * - Fwk takes over the release_fence ownership
    249      */
    250     sp<Fence> releaseFence = new Fence(releaseFenceFd);
    251     bufferItem->getBufferItem().mFence = releaseFence;
    252     bufferItem.clear(); // dropping last reference unpins buffer
    253 
    254     *releaseFenceOut = releaseFence;
    255 
    256     return OK;
    257 }
    258 
    259 status_t Camera3ZslStream::returnInputBufferLocked(
    260         const camera3_stream_buffer &buffer) {
    261     ATRACE_CALL();
    262 
    263     status_t res = returnAnyBufferLocked(buffer, /*timestamp*/0,
    264                                          /*output*/false);
    265 
    266     return res;
    267 }
    268 
    269 void Camera3ZslStream::dump(int fd, const Vector<String16> &args) const {
    270     (void) args;
    271 
    272     String8 lines;
    273     lines.appendFormat("    Stream[%d]: ZSL\n", mId);
    274     write(fd, lines.string(), lines.size());
    275 
    276     Camera3IOStreamBase::dump(fd, args);
    277 
    278     lines = String8();
    279     lines.appendFormat("      Input buffers pending: %zu, in flight %zu\n",
    280             mInputBufferQueue.size(), mBuffersInFlight.size());
    281     write(fd, lines.string(), lines.size());
    282 }
    283 
    284 status_t Camera3ZslStream::enqueueInputBufferByTimestamp(
    285         nsecs_t timestamp,
    286         nsecs_t* actualTimestamp) {
    287 
    288     Mutex::Autolock l(mLock);
    289 
    290     TimestampFinder timestampFinder = TimestampFinder(timestamp);
    291 
    292     sp<RingBufferConsumer::PinnedBufferItem> pinnedBuffer =
    293             mProducer->pinSelectedBuffer(timestampFinder,
    294                                         /*waitForFence*/false);
    295 
    296     if (pinnedBuffer == 0) {
    297         ALOGE("%s: No ZSL buffers were available yet", __FUNCTION__);
    298         return NO_BUFFER_AVAILABLE;
    299     }
    300 
    301     nsecs_t actual = pinnedBuffer->getBufferItem().mTimestamp;
    302 
    303     if (actual != timestamp) {
    304         // TODO: this is problematic, we'll end up with using wrong result for this pinned buffer.
    305         ALOGW("%s: ZSL buffer candidate search didn't find an exact match --"
    306               " requested timestamp = %" PRId64 ", actual timestamp = %" PRId64,
    307               __FUNCTION__, timestamp, actual);
    308     }
    309 
    310     mInputBufferQueue.push_back(pinnedBuffer);
    311 
    312     if (actualTimestamp != NULL) {
    313         *actualTimestamp = actual;
    314     }
    315 
    316     return OK;
    317 }
    318 
    319 status_t Camera3ZslStream::clearInputRingBuffer(nsecs_t* latestTimestamp) {
    320     Mutex::Autolock l(mLock);
    321 
    322     return clearInputRingBufferLocked(latestTimestamp);
    323 }
    324 
    325 status_t Camera3ZslStream::clearInputRingBufferLocked(nsecs_t* latestTimestamp) {
    326 
    327     if (latestTimestamp) {
    328         *latestTimestamp = mProducer->getLatestTimestamp();
    329     }
    330     mInputBufferQueue.clear();
    331 
    332     return mProducer->clear();
    333 }
    334 
    335 status_t Camera3ZslStream::disconnectLocked() {
    336     clearInputRingBufferLocked(NULL);
    337 
    338     return Camera3OutputStream::disconnectLocked();
    339 }
    340 
    341 status_t Camera3ZslStream::setTransform(int /*transform*/) {
    342     ALOGV("%s: Not implemented", __FUNCTION__);
    343     return INVALID_OPERATION;
    344 }
    345 
    346 }; // namespace camera3
    347 
    348 }; // namespace android
    349