Igor Murashkin | 4060274 | 2013-04-29 10:31:06 -0700 | [diff] [blame^] | 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 | #ifndef ANDROID_GUI_RINGBUFFERCONSUMER_H |
| 18 | #define ANDROID_GUI_RINGBUFFERCONSUMER_H |
| 19 | |
| 20 | #include <gui/ConsumerBase.h> |
| 21 | |
| 22 | #include <ui/GraphicBuffer.h> |
| 23 | |
| 24 | #include <utils/String8.h> |
| 25 | #include <utils/Vector.h> |
| 26 | #include <utils/threads.h> |
| 27 | #include <utils/List.h> |
| 28 | |
| 29 | #define ANDROID_GRAPHICS_RINGBUFFERCONSUMER_JNI_ID "mRingBufferConsumer" |
| 30 | |
| 31 | namespace android { |
| 32 | |
| 33 | /** |
| 34 | * The RingBufferConsumer maintains a ring buffer of BufferItem objects, |
| 35 | * (which are 'acquired' as long as they are part of the ring buffer, and |
| 36 | * 'released' when they leave the ring buffer). |
| 37 | * |
| 38 | * When new buffers are produced, the oldest non-pinned buffer item is immediately |
| 39 | * dropped from the ring buffer, and overridden with the newest buffer. |
| 40 | * |
| 41 | * Users can only access a buffer item after pinning it (which also guarantees |
| 42 | * that during its duration it will not be released back into the BufferQueue). |
| 43 | * |
| 44 | * Note that the 'oldest' buffer is the one with the smallest timestamp. |
| 45 | * |
| 46 | * Edge cases: |
| 47 | * - If ringbuffer is not full, no drops occur when a buffer is produced. |
| 48 | * - If all the buffers get filled or pinned then there will be no empty |
| 49 | * buffers left, so the producer will block on dequeue. |
| 50 | */ |
| 51 | class RingBufferConsumer : public ConsumerBase, |
| 52 | public ConsumerBase::FrameAvailableListener |
| 53 | { |
| 54 | public: |
| 55 | typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; |
| 56 | |
| 57 | typedef BufferQueue::BufferItem BufferItem; |
| 58 | |
| 59 | enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT }; |
| 60 | enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; |
| 61 | |
| 62 | // Create a new ring buffer consumer. The consumerUsage parameter determines |
| 63 | // the consumer usage flags passed to the graphics allocator. The |
| 64 | // bufferCount parameter specifies how many buffers can be pinned for user |
| 65 | // access at the same time. |
| 66 | RingBufferConsumer(uint32_t consumerUsage, |
| 67 | int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS); |
| 68 | |
| 69 | virtual ~RingBufferConsumer(); |
| 70 | |
| 71 | // set the name of the RingBufferConsumer that will be used to identify it in |
| 72 | // log messages. |
| 73 | void setName(const String8& name); |
| 74 | |
| 75 | sp<IGraphicBufferProducer> getProducerInterface() const { return getBufferQueue(); } |
| 76 | |
| 77 | // setDefaultBufferSize is used to set the size of buffers returned by |
| 78 | // requestBuffers when a with and height of zero is requested. |
| 79 | status_t setDefaultBufferSize(uint32_t w, uint32_t h); |
| 80 | |
| 81 | // setDefaultBufferFormat allows the BufferQueue to create |
| 82 | // GraphicBuffers of a defaultFormat if no format is specified |
| 83 | // by the producer endpoint. |
| 84 | status_t setDefaultBufferFormat(uint32_t defaultFormat); |
| 85 | |
| 86 | // setConsumerUsage allows the BufferQueue consumer usage to be |
| 87 | // set at a later time after construction. |
| 88 | status_t setConsumerUsage(uint32_t usage); |
| 89 | |
| 90 | // Buffer info, minus the graphics buffer/slot itself. |
| 91 | struct BufferInfo { |
| 92 | // mCrop is the current crop rectangle for this buffer slot. |
| 93 | Rect mCrop; |
| 94 | |
| 95 | // mTransform is the current transform flags for this buffer slot. |
| 96 | uint32_t mTransform; |
| 97 | |
| 98 | // mScalingMode is the current scaling mode for this buffer slot. |
| 99 | uint32_t mScalingMode; |
| 100 | |
| 101 | // mTimestamp is the current timestamp for this buffer slot. This gets |
| 102 | // to set by queueBuffer each time this slot is queued. |
| 103 | int64_t mTimestamp; |
| 104 | |
| 105 | // mFrameNumber is the number of the queued frame for this slot. |
| 106 | uint64_t mFrameNumber; |
| 107 | |
| 108 | // mPinned is whether or not the buffer has been pinned already. |
| 109 | bool mPinned; |
| 110 | }; |
| 111 | |
| 112 | struct RingBufferComparator { |
| 113 | // Return < 0 to select i1, > 0 to select i2, 0 for neither |
| 114 | // i1 or i2 can be NULL. |
| 115 | // |
| 116 | // The comparator has to implement a total ordering. Otherwise |
| 117 | // a linear scan won't find the most preferred buffer. |
| 118 | virtual int compare(const BufferInfo* i1, |
| 119 | const BufferInfo* i2) const = 0; |
| 120 | |
| 121 | virtual ~RingBufferComparator() {} |
| 122 | }; |
| 123 | |
| 124 | struct PinnedBufferItem : public LightRefBase<PinnedBufferItem> { |
| 125 | PinnedBufferItem(wp<RingBufferConsumer> consumer, |
| 126 | const BufferItem& item) : |
| 127 | mConsumer(consumer), |
| 128 | mBufferItem(item) { |
| 129 | } |
| 130 | |
| 131 | ~PinnedBufferItem() { |
| 132 | sp<RingBufferConsumer> consumer = mConsumer.promote(); |
| 133 | if (consumer != NULL) { |
| 134 | consumer->unpinBuffer(mBufferItem); |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | bool isEmpty() { |
| 139 | return mBufferItem.mBuf == BufferQueue::INVALID_BUFFER_SLOT; |
| 140 | } |
| 141 | |
| 142 | BufferItem& getBufferItem() { return mBufferItem; } |
| 143 | const BufferItem& getBufferItem() const { return mBufferItem; } |
| 144 | |
| 145 | private: |
| 146 | wp<RingBufferConsumer> mConsumer; |
| 147 | BufferItem mBufferItem; |
| 148 | }; |
| 149 | |
| 150 | // Find a buffer using the filter, then pin it before returning it. |
| 151 | // |
| 152 | // The filter will be invoked on each buffer item in the ring buffer, |
| 153 | // passing the item that was selected from each previous iteration, |
| 154 | // as well as the current iteration's item. |
| 155 | // |
| 156 | // Pinning will ensure that the buffer will not be dropped when a new |
| 157 | // frame is available. |
| 158 | sp<PinnedBufferItem> pinSelectedBuffer(const RingBufferComparator& filter, |
| 159 | bool waitForFence = true); |
| 160 | |
| 161 | // Release all the non-pinned buffers in the ring buffer |
| 162 | status_t clear(); |
| 163 | |
| 164 | private: |
| 165 | |
| 166 | // Override ConsumerBase::onFrameAvailable |
| 167 | virtual void onFrameAvailable(); |
| 168 | |
| 169 | void pinBufferLocked(const BufferItem& item); |
| 170 | void unpinBuffer(const BufferItem& item); |
| 171 | |
| 172 | // Releases oldest buffer. Returns NO_BUFFER_AVAILABLE |
| 173 | // if all the buffers were pinned. |
| 174 | // Returns NOT_ENOUGH_DATA if list was empty. |
| 175 | status_t releaseOldestBufferLocked(size_t* pinnedFrames); |
| 176 | |
| 177 | struct RingBufferItem : public BufferItem { |
| 178 | RingBufferItem() : BufferItem(), mPinCount(0) {} |
| 179 | int mPinCount; |
| 180 | }; |
| 181 | |
| 182 | // List of acquired buffers in our ring buffer |
| 183 | List<RingBufferItem> mBufferItemList; |
| 184 | const int mBufferCount; |
| 185 | }; |
| 186 | |
| 187 | } // namespace android |
| 188 | |
| 189 | #endif // ANDROID_GUI_CPUCONSUMER_H |