| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2010 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 "ConsumerBase" | 
|  | 18 | #define ATRACE_TAG ATRACE_TAG_GRAPHICS | 
|  | 19 | //#define LOG_NDEBUG 0 | 
|  | 20 |  | 
|  | 21 | #define GL_GLEXT_PROTOTYPES | 
|  | 22 | #define EGL_EGLEXT_PROTOTYPES | 
|  | 23 |  | 
|  | 24 | #include <EGL/egl.h> | 
|  | 25 | #include <EGL/eglext.h> | 
|  | 26 |  | 
|  | 27 | #include <hardware/hardware.h> | 
|  | 28 |  | 
|  | 29 | #include <gui/IGraphicBufferAlloc.h> | 
|  | 30 | #include <gui/ISurfaceComposer.h> | 
|  | 31 | #include <gui/SurfaceComposerClient.h> | 
|  | 32 | #include <gui/ConsumerBase.h> | 
|  | 33 |  | 
|  | 34 | #include <private/gui/ComposerService.h> | 
|  | 35 |  | 
|  | 36 | #include <utils/Log.h> | 
|  | 37 | #include <utils/String8.h> | 
|  | 38 | #include <utils/Trace.h> | 
|  | 39 |  | 
|  | 40 | // Macros for including the ConsumerBase name in log messages | 
|  | 41 | #define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) | 
|  | 42 | #define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) | 
|  | 43 | #define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) | 
|  | 44 | #define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) | 
|  | 45 | #define CB_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) | 
|  | 46 |  | 
|  | 47 | namespace android { | 
|  | 48 |  | 
|  | 49 | // Get an ID that's unique within this process. | 
|  | 50 | static int32_t createProcessUniqueId() { | 
|  | 51 | static volatile int32_t globalCounter = 0; | 
|  | 52 | return android_atomic_inc(&globalCounter); | 
|  | 53 | } | 
|  | 54 |  | 
|  | 55 | ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) : | 
| Jamie Gennis | 9fea342 | 2012-08-07 18:03:04 -0700 | [diff] [blame] | 56 | mAbandoned(false), | 
|  | 57 | mBufferQueue(bufferQueue) { | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 58 | // Choose a name using the PID and a process-unique ID. | 
|  | 59 | mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); | 
|  | 60 |  | 
|  | 61 | // Note that we can't create an sp<...>(this) in a ctor that will not keep a | 
|  | 62 | // reference once the ctor ends, as that would cause the refcount of 'this' | 
|  | 63 | // dropping to 0 at the end of the ctor.  Since all we need is a wp<...> | 
|  | 64 | // that's what we create. | 
|  | 65 | wp<BufferQueue::ConsumerListener> listener; | 
|  | 66 | sp<BufferQueue::ConsumerListener> proxy; | 
|  | 67 | listener = static_cast<BufferQueue::ConsumerListener*>(this); | 
|  | 68 | proxy = new BufferQueue::ProxyConsumerListener(listener); | 
|  | 69 |  | 
|  | 70 | status_t err = mBufferQueue->consumerConnect(proxy); | 
|  | 71 | if (err != NO_ERROR) { | 
| Andy McFadden | 2adaf04 | 2012-12-18 09:49:45 -0800 | [diff] [blame] | 72 | CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 73 | strerror(-err), err); | 
|  | 74 | } else { | 
|  | 75 | mBufferQueue->setConsumerName(mName); | 
|  | 76 | } | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | ConsumerBase::~ConsumerBase() { | 
|  | 80 | CB_LOGV("~ConsumerBase"); | 
|  | 81 | abandon(); | 
|  | 82 | } | 
|  | 83 |  | 
|  | 84 | void ConsumerBase::freeBufferLocked(int slotIndex) { | 
|  | 85 | CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); | 
|  | 86 | mSlots[slotIndex].mGraphicBuffer = 0; | 
| Jamie Gennis | 1df8c34 | 2012-12-20 14:05:45 -0800 | [diff] [blame] | 87 | mSlots[slotIndex].mFence = Fence::NO_FENCE; | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 88 | } | 
|  | 89 |  | 
|  | 90 | // Used for refactoring, should not be in final interface | 
|  | 91 | sp<BufferQueue> ConsumerBase::getBufferQueue() const { | 
|  | 92 | Mutex::Autolock lock(mMutex); | 
|  | 93 | return mBufferQueue; | 
|  | 94 | } | 
|  | 95 |  | 
|  | 96 | void ConsumerBase::onFrameAvailable() { | 
|  | 97 | CB_LOGV("onFrameAvailable"); | 
|  | 98 |  | 
|  | 99 | sp<FrameAvailableListener> listener; | 
|  | 100 | { // scope for the lock | 
|  | 101 | Mutex::Autolock lock(mMutex); | 
| Igor Murashkin | a4a3149 | 2012-10-29 13:36:11 -0700 | [diff] [blame] | 102 | listener = mFrameAvailableListener.promote(); | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 103 | } | 
|  | 104 |  | 
|  | 105 | if (listener != NULL) { | 
|  | 106 | CB_LOGV("actually calling onFrameAvailable"); | 
|  | 107 | listener->onFrameAvailable(); | 
|  | 108 | } | 
|  | 109 | } | 
|  | 110 |  | 
|  | 111 | void ConsumerBase::onBuffersReleased() { | 
| Jamie Gennis | 72c3f7d | 2012-12-07 00:41:56 -0800 | [diff] [blame] | 112 | Mutex::Autolock lock(mMutex); | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 113 |  | 
| Jamie Gennis | 72c3f7d | 2012-12-07 00:41:56 -0800 | [diff] [blame] | 114 | CB_LOGV("onBuffersReleased"); | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 115 |  | 
| Jamie Gennis | 72c3f7d | 2012-12-07 00:41:56 -0800 | [diff] [blame] | 116 | if (mAbandoned) { | 
|  | 117 | // Nothing to do if we're already abandoned. | 
|  | 118 | return; | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 119 | } | 
|  | 120 |  | 
| Jamie Gennis | 72c3f7d | 2012-12-07 00:41:56 -0800 | [diff] [blame] | 121 | uint32_t mask = 0; | 
|  | 122 | mBufferQueue->getReleasedBuffers(&mask); | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 123 | for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { | 
| Jamie Gennis | 72c3f7d | 2012-12-07 00:41:56 -0800 | [diff] [blame] | 124 | if (mask & (1 << i)) { | 
|  | 125 | freeBufferLocked(i); | 
|  | 126 | } | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 127 | } | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | void ConsumerBase::abandon() { | 
|  | 131 | CB_LOGV("abandon"); | 
|  | 132 | Mutex::Autolock lock(mMutex); | 
|  | 133 |  | 
|  | 134 | if (!mAbandoned) { | 
|  | 135 | abandonLocked(); | 
|  | 136 | mAbandoned = true; | 
|  | 137 | } | 
|  | 138 | } | 
|  | 139 |  | 
|  | 140 | void ConsumerBase::abandonLocked() { | 
|  | 141 | CB_LOGV("abandonLocked"); | 
|  | 142 | for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { | 
|  | 143 | freeBufferLocked(i); | 
|  | 144 | } | 
|  | 145 | // disconnect from the BufferQueue | 
|  | 146 | mBufferQueue->consumerDisconnect(); | 
|  | 147 | mBufferQueue.clear(); | 
|  | 148 | } | 
|  | 149 |  | 
|  | 150 | void ConsumerBase::setFrameAvailableListener( | 
| Igor Murashkin | a4a3149 | 2012-10-29 13:36:11 -0700 | [diff] [blame] | 151 | const wp<FrameAvailableListener>& listener) { | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 152 | CB_LOGV("setFrameAvailableListener"); | 
|  | 153 | Mutex::Autolock lock(mMutex); | 
|  | 154 | mFrameAvailableListener = listener; | 
|  | 155 | } | 
|  | 156 |  | 
|  | 157 | void ConsumerBase::dump(String8& result) const { | 
|  | 158 | char buffer[1024]; | 
|  | 159 | dump(result, "", buffer, 1024); | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | void ConsumerBase::dump(String8& result, const char* prefix, | 
|  | 163 | char* buffer, size_t size) const { | 
|  | 164 | Mutex::Autolock _l(mMutex); | 
|  | 165 | dumpLocked(result, prefix, buffer, size); | 
|  | 166 | } | 
|  | 167 |  | 
|  | 168 | void ConsumerBase::dumpLocked(String8& result, const char* prefix, | 
|  | 169 | char* buffer, size_t SIZE) const { | 
|  | 170 | snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned)); | 
|  | 171 | result.append(buffer); | 
|  | 172 |  | 
|  | 173 | if (!mAbandoned) { | 
|  | 174 | mBufferQueue->dump(result, prefix, buffer, SIZE); | 
|  | 175 | } | 
|  | 176 | } | 
|  | 177 |  | 
|  | 178 | status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) { | 
|  | 179 | status_t err = mBufferQueue->acquireBuffer(item); | 
|  | 180 | if (err != NO_ERROR) { | 
|  | 181 | return err; | 
|  | 182 | } | 
|  | 183 |  | 
|  | 184 | if (item->mGraphicBuffer != NULL) { | 
|  | 185 | mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; | 
|  | 186 | } | 
|  | 187 |  | 
| Jamie Gennis | b272541 | 2012-09-05 20:09:05 -0700 | [diff] [blame] | 188 | mSlots[item->mBuf].mFence = item->mFence; | 
|  | 189 |  | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 190 | CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf); | 
|  | 191 |  | 
|  | 192 | return OK; | 
|  | 193 | } | 
|  | 194 |  | 
| Jamie Gennis | b272541 | 2012-09-05 20:09:05 -0700 | [diff] [blame] | 195 | status_t ConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) { | 
| Jesse Hall | 9504eb9 | 2012-10-05 14:34:21 -0700 | [diff] [blame] | 196 | Mutex::Autolock lock(mMutex); | 
|  | 197 | return addReleaseFenceLocked(slot, fence); | 
|  | 198 | } | 
|  | 199 |  | 
|  | 200 | status_t ConsumerBase::addReleaseFenceLocked(int slot, const sp<Fence>& fence) { | 
|  | 201 | CB_LOGV("addReleaseFenceLocked: slot=%d", slot); | 
| Jamie Gennis | b272541 | 2012-09-05 20:09:05 -0700 | [diff] [blame] | 202 |  | 
|  | 203 | if (!mSlots[slot].mFence.get()) { | 
|  | 204 | mSlots[slot].mFence = fence; | 
|  | 205 | } else { | 
|  | 206 | sp<Fence> mergedFence = Fence::merge( | 
| Jamie Gennis | 7aff4a5 | 2012-09-24 12:25:15 -0700 | [diff] [blame] | 207 | String8::format("%.28s:%d", mName.string(), slot), | 
| Jamie Gennis | b272541 | 2012-09-05 20:09:05 -0700 | [diff] [blame] | 208 | mSlots[slot].mFence, fence); | 
|  | 209 | if (!mergedFence.get()) { | 
|  | 210 | CB_LOGE("failed to merge release fences"); | 
|  | 211 | // synchronization is broken, the best we can do is hope fences | 
|  | 212 | // signal in order so the new fence will act like a union | 
|  | 213 | mSlots[slot].mFence = fence; | 
|  | 214 | return BAD_VALUE; | 
|  | 215 | } | 
|  | 216 | mSlots[slot].mFence = mergedFence; | 
|  | 217 | } | 
|  | 218 |  | 
|  | 219 | return OK; | 
|  | 220 | } | 
|  | 221 |  | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 222 | status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display, | 
| Jamie Gennis | b272541 | 2012-09-05 20:09:05 -0700 | [diff] [blame] | 223 | EGLSyncKHR eglFence) { | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 224 | CB_LOGV("releaseBufferLocked: slot=%d", slot); | 
| Jamie Gennis | b272541 | 2012-09-05 20:09:05 -0700 | [diff] [blame] | 225 | status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, | 
|  | 226 | mSlots[slot].mFence); | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 227 | if (err == BufferQueue::STALE_BUFFER_SLOT) { | 
|  | 228 | freeBufferLocked(slot); | 
|  | 229 | } | 
|  | 230 |  | 
| Jamie Gennis | 1df8c34 | 2012-12-20 14:05:45 -0800 | [diff] [blame] | 231 | mSlots[slot].mFence = Fence::NO_FENCE; | 
| Jamie Gennis | 1a4d883 | 2012-08-02 20:11:05 -0700 | [diff] [blame] | 232 |  | 
|  | 233 | return err; | 
|  | 234 | } | 
|  | 235 |  | 
| Andy McFadden | 2adaf04 | 2012-12-18 09:49:45 -0800 | [diff] [blame] | 236 | } // namespace android |