1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gonk/nativewindow/GonkConsumerBaseKK.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,259 @@ 1.4 +/* 1.5 + * Copyright (C) 2010 The Android Open Source Project 1.6 + * Copyright (C) 2013 Mozilla Foundation 1.7 + * 1.8 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.9 + * you may not use this file except in compliance with the License. 1.10 + * You may obtain a copy of the License at 1.11 + * 1.12 + * http://www.apache.org/licenses/LICENSE-2.0 1.13 + * 1.14 + * Unless required by applicable law or agreed to in writing, software 1.15 + * distributed under the License is distributed on an "AS IS" BASIS, 1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.17 + * See the License for the specific language governing permissions and 1.18 + * limitations under the License. 1.19 + */ 1.20 + 1.21 +#define LOG_TAG "GonkConsumerBase" 1.22 +#define ATRACE_TAG ATRACE_TAG_GRAPHICS 1.23 +//#define LOG_NDEBUG 0 1.24 + 1.25 +#define EGL_EGLEXT_PROTOTYPES 1.26 + 1.27 +#include <hardware/hardware.h> 1.28 + 1.29 +#include <gui/IGraphicBufferAlloc.h> 1.30 +#include <utils/Log.h> 1.31 +#include <utils/String8.h> 1.32 + 1.33 +#include "GonkConsumerBaseKK.h" 1.34 + 1.35 +// Macros for including the GonkConsumerBase name in log messages 1.36 +#define CB_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) 1.37 +#define CB_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) 1.38 +#define CB_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) 1.39 +#define CB_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) 1.40 +#define CB_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) 1.41 + 1.42 +namespace android { 1.43 + 1.44 +// Get an ID that's unique within this process. 1.45 +static int32_t createProcessUniqueId() { 1.46 + static volatile int32_t globalCounter = 0; 1.47 + return android_atomic_inc(&globalCounter); 1.48 +} 1.49 + 1.50 +GonkConsumerBase::GonkConsumerBase(const sp<GonkBufferQueue>& bufferQueue, bool controlledByApp) : 1.51 + mAbandoned(false), 1.52 + mConsumer(bufferQueue) { 1.53 + // Choose a name using the PID and a process-unique ID. 1.54 + mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); 1.55 + 1.56 + // Note that we can't create an sp<...>(this) in a ctor that will not keep a 1.57 + // reference once the ctor ends, as that would cause the refcount of 'this' 1.58 + // dropping to 0 at the end of the ctor. Since all we need is a wp<...> 1.59 + // that's what we create. 1.60 + wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this); 1.61 + sp<IConsumerListener> proxy = new GonkBufferQueue::ProxyConsumerListener(listener); 1.62 + 1.63 + status_t err = mConsumer->consumerConnect(proxy, controlledByApp); 1.64 + if (err != NO_ERROR) { 1.65 + CB_LOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", 1.66 + strerror(-err), err); 1.67 + } else { 1.68 + mConsumer->setConsumerName(mName); 1.69 + } 1.70 +} 1.71 + 1.72 +GonkConsumerBase::~GonkConsumerBase() { 1.73 + CB_LOGV("~GonkConsumerBase"); 1.74 + Mutex::Autolock lock(mMutex); 1.75 + 1.76 + // Verify that abandon() has been called before we get here. This should 1.77 + // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a 1.78 + // derived class to override that method and not call 1.79 + // GonkConsumerBase::onLastStrongRef(). 1.80 + LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " 1.81 + "consumer is not abandoned!", mName.string()); 1.82 +} 1.83 + 1.84 +void GonkConsumerBase::onLastStrongRef(const void* id) { 1.85 + abandon(); 1.86 +} 1.87 + 1.88 +void GonkConsumerBase::freeBufferLocked(int slotIndex) { 1.89 + CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); 1.90 + mSlots[slotIndex].mGraphicBuffer = 0; 1.91 + mSlots[slotIndex].mFence = Fence::NO_FENCE; 1.92 + mSlots[slotIndex].mFrameNumber = 0; 1.93 +} 1.94 + 1.95 +// Used for refactoring, should not be in final interface 1.96 +sp<GonkBufferQueue> GonkConsumerBase::getBufferQueue() const { 1.97 + Mutex::Autolock lock(mMutex); 1.98 + return mConsumer; 1.99 +} 1.100 + 1.101 +void GonkConsumerBase::onFrameAvailable() { 1.102 + CB_LOGV("onFrameAvailable"); 1.103 + 1.104 + sp<FrameAvailableListener> listener; 1.105 + { // scope for the lock 1.106 + Mutex::Autolock lock(mMutex); 1.107 + listener = mFrameAvailableListener.promote(); 1.108 + } 1.109 + 1.110 + if (listener != NULL) { 1.111 + CB_LOGV("actually calling onFrameAvailable"); 1.112 + listener->onFrameAvailable(); 1.113 + } 1.114 +} 1.115 + 1.116 +void GonkConsumerBase::onBuffersReleased() { 1.117 + Mutex::Autolock lock(mMutex); 1.118 + 1.119 + CB_LOGV("onBuffersReleased"); 1.120 + 1.121 + if (mAbandoned) { 1.122 + // Nothing to do if we're already abandoned. 1.123 + return; 1.124 + } 1.125 + 1.126 + uint32_t mask = 0; 1.127 + mConsumer->getReleasedBuffers(&mask); 1.128 + for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { 1.129 + if (mask & (1 << i)) { 1.130 + freeBufferLocked(i); 1.131 + } 1.132 + } 1.133 +} 1.134 + 1.135 +void GonkConsumerBase::abandon() { 1.136 + CB_LOGV("abandon"); 1.137 + Mutex::Autolock lock(mMutex); 1.138 + 1.139 + if (!mAbandoned) { 1.140 + abandonLocked(); 1.141 + mAbandoned = true; 1.142 + } 1.143 +} 1.144 + 1.145 +void GonkConsumerBase::abandonLocked() { 1.146 + CB_LOGV("abandonLocked"); 1.147 + for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { 1.148 + freeBufferLocked(i); 1.149 + } 1.150 + // disconnect from the BufferQueue 1.151 + mConsumer->consumerDisconnect(); 1.152 + mConsumer.clear(); 1.153 +} 1.154 + 1.155 +void GonkConsumerBase::setFrameAvailableListener( 1.156 + const wp<FrameAvailableListener>& listener) { 1.157 + CB_LOGV("setFrameAvailableListener"); 1.158 + Mutex::Autolock lock(mMutex); 1.159 + mFrameAvailableListener = listener; 1.160 +} 1.161 + 1.162 +void GonkConsumerBase::dump(String8& result) const { 1.163 + dump(result, ""); 1.164 +} 1.165 + 1.166 +void GonkConsumerBase::dump(String8& result, const char* prefix) const { 1.167 + Mutex::Autolock _l(mMutex); 1.168 + dumpLocked(result, prefix); 1.169 +} 1.170 + 1.171 +void GonkConsumerBase::dumpLocked(String8& result, const char* prefix) const { 1.172 + result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); 1.173 + 1.174 + if (!mAbandoned) { 1.175 + mConsumer->dump(result, prefix); 1.176 + } 1.177 +} 1.178 + 1.179 +status_t GonkConsumerBase::acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item, 1.180 + nsecs_t presentWhen) { 1.181 + status_t err = mConsumer->acquireBuffer(item, presentWhen); 1.182 + if (err != NO_ERROR) { 1.183 + return err; 1.184 + } 1.185 + 1.186 + if (item->mGraphicBuffer != NULL) { 1.187 + mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; 1.188 + } 1.189 + 1.190 + mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; 1.191 + mSlots[item->mBuf].mFence = item->mFence; 1.192 + 1.193 + CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf); 1.194 + 1.195 + return OK; 1.196 +} 1.197 + 1.198 +status_t GonkConsumerBase::addReleaseFence(int slot, 1.199 + const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { 1.200 + Mutex::Autolock lock(mMutex); 1.201 + return addReleaseFenceLocked(slot, graphicBuffer, fence); 1.202 +} 1.203 + 1.204 +status_t GonkConsumerBase::addReleaseFenceLocked(int slot, 1.205 + const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { 1.206 + CB_LOGV("addReleaseFenceLocked: slot=%d", slot); 1.207 + 1.208 + // If consumer no longer tracks this graphicBuffer, we can safely 1.209 + // drop this fence, as it will never be received by the producer. 1.210 + if (!stillTracking(slot, graphicBuffer)) { 1.211 + return OK; 1.212 + } 1.213 + 1.214 + if (!mSlots[slot].mFence.get()) { 1.215 + mSlots[slot].mFence = fence; 1.216 + } else { 1.217 + sp<Fence> mergedFence = Fence::merge( 1.218 + String8::format("%.28s:%d", mName.string(), slot), 1.219 + mSlots[slot].mFence, fence); 1.220 + if (!mergedFence.get()) { 1.221 + CB_LOGE("failed to merge release fences"); 1.222 + // synchronization is broken, the best we can do is hope fences 1.223 + // signal in order so the new fence will act like a union 1.224 + mSlots[slot].mFence = fence; 1.225 + return BAD_VALUE; 1.226 + } 1.227 + mSlots[slot].mFence = mergedFence; 1.228 + } 1.229 + 1.230 + return OK; 1.231 +} 1.232 + 1.233 +status_t GonkConsumerBase::releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer) { 1.234 + // If consumer no longer tracks this graphicBuffer (we received a new 1.235 + // buffer on the same slot), the buffer producer is definitely no longer 1.236 + // tracking it. 1.237 + if (!stillTracking(slot, graphicBuffer)) { 1.238 + return OK; 1.239 + } 1.240 + 1.241 + CB_LOGV("releaseBufferLocked: slot=%d/%llu", 1.242 + slot, mSlots[slot].mFrameNumber); 1.243 + status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, mSlots[slot].mFence); 1.244 + if (err == GonkBufferQueue::STALE_BUFFER_SLOT) { 1.245 + freeBufferLocked(slot); 1.246 + } 1.247 + 1.248 + mSlots[slot].mFence = Fence::NO_FENCE; 1.249 + 1.250 + return err; 1.251 +} 1.252 + 1.253 +bool GonkConsumerBase::stillTracking(int slot, 1.254 + const sp<GraphicBuffer> graphicBuffer) { 1.255 + if (slot < 0 || slot >= GonkBufferQueue::NUM_BUFFER_SLOTS) { 1.256 + return false; 1.257 + } 1.258 + return (mSlots[slot].mGraphicBuffer != NULL && 1.259 + mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); 1.260 +} 1.261 + 1.262 +} // namespace android