|
1 /* |
|
2 * Copyright (C) 2010 The Android Open Source Project |
|
3 * Copyright (C) 2013 Mozilla Foundation |
|
4 * |
|
5 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 * you may not use this file except in compliance with the License. |
|
7 * You may obtain a copy of the License at |
|
8 * |
|
9 * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 * |
|
11 * Unless required by applicable law or agreed to in writing, software |
|
12 * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 * See the License for the specific language governing permissions and |
|
15 * limitations under the License. |
|
16 */ |
|
17 |
|
18 #define LOG_TAG "GonkConsumerBase" |
|
19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS |
|
20 //#define LOG_NDEBUG 0 |
|
21 |
|
22 #define EGL_EGLEXT_PROTOTYPES |
|
23 |
|
24 #include <hardware/hardware.h> |
|
25 |
|
26 #include <gui/IGraphicBufferAlloc.h> |
|
27 #include <utils/Log.h> |
|
28 #include <utils/String8.h> |
|
29 |
|
30 #include "GonkConsumerBaseKK.h" |
|
31 |
|
32 // Macros for including the GonkConsumerBase name in log messages |
|
33 #define CB_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) |
|
34 #define CB_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) |
|
35 #define CB_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) |
|
36 #define CB_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) |
|
37 #define CB_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) |
|
38 |
|
39 namespace android { |
|
40 |
|
41 // Get an ID that's unique within this process. |
|
42 static int32_t createProcessUniqueId() { |
|
43 static volatile int32_t globalCounter = 0; |
|
44 return android_atomic_inc(&globalCounter); |
|
45 } |
|
46 |
|
47 GonkConsumerBase::GonkConsumerBase(const sp<GonkBufferQueue>& bufferQueue, bool controlledByApp) : |
|
48 mAbandoned(false), |
|
49 mConsumer(bufferQueue) { |
|
50 // Choose a name using the PID and a process-unique ID. |
|
51 mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); |
|
52 |
|
53 // Note that we can't create an sp<...>(this) in a ctor that will not keep a |
|
54 // reference once the ctor ends, as that would cause the refcount of 'this' |
|
55 // dropping to 0 at the end of the ctor. Since all we need is a wp<...> |
|
56 // that's what we create. |
|
57 wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this); |
|
58 sp<IConsumerListener> proxy = new GonkBufferQueue::ProxyConsumerListener(listener); |
|
59 |
|
60 status_t err = mConsumer->consumerConnect(proxy, controlledByApp); |
|
61 if (err != NO_ERROR) { |
|
62 CB_LOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", |
|
63 strerror(-err), err); |
|
64 } else { |
|
65 mConsumer->setConsumerName(mName); |
|
66 } |
|
67 } |
|
68 |
|
69 GonkConsumerBase::~GonkConsumerBase() { |
|
70 CB_LOGV("~GonkConsumerBase"); |
|
71 Mutex::Autolock lock(mMutex); |
|
72 |
|
73 // Verify that abandon() has been called before we get here. This should |
|
74 // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a |
|
75 // derived class to override that method and not call |
|
76 // GonkConsumerBase::onLastStrongRef(). |
|
77 LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " |
|
78 "consumer is not abandoned!", mName.string()); |
|
79 } |
|
80 |
|
81 void GonkConsumerBase::onLastStrongRef(const void* id) { |
|
82 abandon(); |
|
83 } |
|
84 |
|
85 void GonkConsumerBase::freeBufferLocked(int slotIndex) { |
|
86 CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); |
|
87 mSlots[slotIndex].mGraphicBuffer = 0; |
|
88 mSlots[slotIndex].mFence = Fence::NO_FENCE; |
|
89 mSlots[slotIndex].mFrameNumber = 0; |
|
90 } |
|
91 |
|
92 // Used for refactoring, should not be in final interface |
|
93 sp<GonkBufferQueue> GonkConsumerBase::getBufferQueue() const { |
|
94 Mutex::Autolock lock(mMutex); |
|
95 return mConsumer; |
|
96 } |
|
97 |
|
98 void GonkConsumerBase::onFrameAvailable() { |
|
99 CB_LOGV("onFrameAvailable"); |
|
100 |
|
101 sp<FrameAvailableListener> listener; |
|
102 { // scope for the lock |
|
103 Mutex::Autolock lock(mMutex); |
|
104 listener = mFrameAvailableListener.promote(); |
|
105 } |
|
106 |
|
107 if (listener != NULL) { |
|
108 CB_LOGV("actually calling onFrameAvailable"); |
|
109 listener->onFrameAvailable(); |
|
110 } |
|
111 } |
|
112 |
|
113 void GonkConsumerBase::onBuffersReleased() { |
|
114 Mutex::Autolock lock(mMutex); |
|
115 |
|
116 CB_LOGV("onBuffersReleased"); |
|
117 |
|
118 if (mAbandoned) { |
|
119 // Nothing to do if we're already abandoned. |
|
120 return; |
|
121 } |
|
122 |
|
123 uint32_t mask = 0; |
|
124 mConsumer->getReleasedBuffers(&mask); |
|
125 for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { |
|
126 if (mask & (1 << i)) { |
|
127 freeBufferLocked(i); |
|
128 } |
|
129 } |
|
130 } |
|
131 |
|
132 void GonkConsumerBase::abandon() { |
|
133 CB_LOGV("abandon"); |
|
134 Mutex::Autolock lock(mMutex); |
|
135 |
|
136 if (!mAbandoned) { |
|
137 abandonLocked(); |
|
138 mAbandoned = true; |
|
139 } |
|
140 } |
|
141 |
|
142 void GonkConsumerBase::abandonLocked() { |
|
143 CB_LOGV("abandonLocked"); |
|
144 for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { |
|
145 freeBufferLocked(i); |
|
146 } |
|
147 // disconnect from the BufferQueue |
|
148 mConsumer->consumerDisconnect(); |
|
149 mConsumer.clear(); |
|
150 } |
|
151 |
|
152 void GonkConsumerBase::setFrameAvailableListener( |
|
153 const wp<FrameAvailableListener>& listener) { |
|
154 CB_LOGV("setFrameAvailableListener"); |
|
155 Mutex::Autolock lock(mMutex); |
|
156 mFrameAvailableListener = listener; |
|
157 } |
|
158 |
|
159 void GonkConsumerBase::dump(String8& result) const { |
|
160 dump(result, ""); |
|
161 } |
|
162 |
|
163 void GonkConsumerBase::dump(String8& result, const char* prefix) const { |
|
164 Mutex::Autolock _l(mMutex); |
|
165 dumpLocked(result, prefix); |
|
166 } |
|
167 |
|
168 void GonkConsumerBase::dumpLocked(String8& result, const char* prefix) const { |
|
169 result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); |
|
170 |
|
171 if (!mAbandoned) { |
|
172 mConsumer->dump(result, prefix); |
|
173 } |
|
174 } |
|
175 |
|
176 status_t GonkConsumerBase::acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item, |
|
177 nsecs_t presentWhen) { |
|
178 status_t err = mConsumer->acquireBuffer(item, presentWhen); |
|
179 if (err != NO_ERROR) { |
|
180 return err; |
|
181 } |
|
182 |
|
183 if (item->mGraphicBuffer != NULL) { |
|
184 mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; |
|
185 } |
|
186 |
|
187 mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; |
|
188 mSlots[item->mBuf].mFence = item->mFence; |
|
189 |
|
190 CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf); |
|
191 |
|
192 return OK; |
|
193 } |
|
194 |
|
195 status_t GonkConsumerBase::addReleaseFence(int slot, |
|
196 const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { |
|
197 Mutex::Autolock lock(mMutex); |
|
198 return addReleaseFenceLocked(slot, graphicBuffer, fence); |
|
199 } |
|
200 |
|
201 status_t GonkConsumerBase::addReleaseFenceLocked(int slot, |
|
202 const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { |
|
203 CB_LOGV("addReleaseFenceLocked: slot=%d", slot); |
|
204 |
|
205 // If consumer no longer tracks this graphicBuffer, we can safely |
|
206 // drop this fence, as it will never be received by the producer. |
|
207 if (!stillTracking(slot, graphicBuffer)) { |
|
208 return OK; |
|
209 } |
|
210 |
|
211 if (!mSlots[slot].mFence.get()) { |
|
212 mSlots[slot].mFence = fence; |
|
213 } else { |
|
214 sp<Fence> mergedFence = Fence::merge( |
|
215 String8::format("%.28s:%d", mName.string(), slot), |
|
216 mSlots[slot].mFence, fence); |
|
217 if (!mergedFence.get()) { |
|
218 CB_LOGE("failed to merge release fences"); |
|
219 // synchronization is broken, the best we can do is hope fences |
|
220 // signal in order so the new fence will act like a union |
|
221 mSlots[slot].mFence = fence; |
|
222 return BAD_VALUE; |
|
223 } |
|
224 mSlots[slot].mFence = mergedFence; |
|
225 } |
|
226 |
|
227 return OK; |
|
228 } |
|
229 |
|
230 status_t GonkConsumerBase::releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer) { |
|
231 // If consumer no longer tracks this graphicBuffer (we received a new |
|
232 // buffer on the same slot), the buffer producer is definitely no longer |
|
233 // tracking it. |
|
234 if (!stillTracking(slot, graphicBuffer)) { |
|
235 return OK; |
|
236 } |
|
237 |
|
238 CB_LOGV("releaseBufferLocked: slot=%d/%llu", |
|
239 slot, mSlots[slot].mFrameNumber); |
|
240 status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, mSlots[slot].mFence); |
|
241 if (err == GonkBufferQueue::STALE_BUFFER_SLOT) { |
|
242 freeBufferLocked(slot); |
|
243 } |
|
244 |
|
245 mSlots[slot].mFence = Fence::NO_FENCE; |
|
246 |
|
247 return err; |
|
248 } |
|
249 |
|
250 bool GonkConsumerBase::stillTracking(int slot, |
|
251 const sp<GraphicBuffer> graphicBuffer) { |
|
252 if (slot < 0 || slot >= GonkBufferQueue::NUM_BUFFER_SLOTS) { |
|
253 return false; |
|
254 } |
|
255 return (mSlots[slot].mGraphicBuffer != NULL && |
|
256 mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); |
|
257 } |
|
258 |
|
259 } // namespace android |