|
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 "GonkConsumerBaseJB.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) : |
|
48 mAbandoned(false), |
|
49 mBufferQueue(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<GonkBufferQueue::ConsumerListener> listener; |
|
58 sp<GonkBufferQueue::ConsumerListener> proxy; |
|
59 listener = static_cast<GonkBufferQueue::ConsumerListener*>(this); |
|
60 proxy = new GonkBufferQueue::ProxyConsumerListener(listener); |
|
61 |
|
62 status_t err = mBufferQueue->consumerConnect(proxy); |
|
63 if (err != NO_ERROR) { |
|
64 CB_LOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", |
|
65 strerror(-err), err); |
|
66 } else { |
|
67 mBufferQueue->setConsumerName(mName); |
|
68 } |
|
69 } |
|
70 |
|
71 GonkConsumerBase::~GonkConsumerBase() { |
|
72 CB_LOGV("~GonkConsumerBase"); |
|
73 Mutex::Autolock lock(mMutex); |
|
74 |
|
75 // Verify that abandon() has been called before we get here. This should |
|
76 // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a |
|
77 // derived class to override that method and not call |
|
78 // GonkConsumerBase::onLastStrongRef(). |
|
79 LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " |
|
80 "consumer is not abandoned!", mName.string()); |
|
81 } |
|
82 |
|
83 void GonkConsumerBase::onLastStrongRef(const void* id) { |
|
84 abandon(); |
|
85 } |
|
86 |
|
87 void GonkConsumerBase::freeBufferLocked(int slotIndex) { |
|
88 CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); |
|
89 mSlots[slotIndex].mGraphicBuffer = 0; |
|
90 mSlots[slotIndex].mFence = Fence::NO_FENCE; |
|
91 } |
|
92 |
|
93 // Used for refactoring, should not be in final interface |
|
94 sp<GonkBufferQueue> GonkConsumerBase::getBufferQueue() const { |
|
95 Mutex::Autolock lock(mMutex); |
|
96 return mBufferQueue; |
|
97 } |
|
98 |
|
99 void GonkConsumerBase::onFrameAvailable() { |
|
100 CB_LOGV("onFrameAvailable"); |
|
101 |
|
102 sp<FrameAvailableListener> listener; |
|
103 { // scope for the lock |
|
104 Mutex::Autolock lock(mMutex); |
|
105 #if ANDROID_VERSION == 17 |
|
106 listener = mFrameAvailableListener; |
|
107 #else |
|
108 listener = mFrameAvailableListener.promote(); |
|
109 #endif |
|
110 } |
|
111 |
|
112 if (listener != NULL) { |
|
113 CB_LOGV("actually calling onFrameAvailable"); |
|
114 listener->onFrameAvailable(); |
|
115 } |
|
116 } |
|
117 |
|
118 void GonkConsumerBase::onBuffersReleased() { |
|
119 Mutex::Autolock lock(mMutex); |
|
120 |
|
121 CB_LOGV("onBuffersReleased"); |
|
122 |
|
123 if (mAbandoned) { |
|
124 // Nothing to do if we're already abandoned. |
|
125 return; |
|
126 } |
|
127 |
|
128 uint32_t mask = 0; |
|
129 mBufferQueue->getReleasedBuffers(&mask); |
|
130 for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { |
|
131 if (mask & (1 << i)) { |
|
132 freeBufferLocked(i); |
|
133 } |
|
134 } |
|
135 } |
|
136 |
|
137 void GonkConsumerBase::abandon() { |
|
138 CB_LOGV("abandon"); |
|
139 Mutex::Autolock lock(mMutex); |
|
140 |
|
141 if (!mAbandoned) { |
|
142 abandonLocked(); |
|
143 mAbandoned = true; |
|
144 } |
|
145 } |
|
146 |
|
147 void GonkConsumerBase::abandonLocked() { |
|
148 CB_LOGV("abandonLocked"); |
|
149 for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { |
|
150 freeBufferLocked(i); |
|
151 } |
|
152 // disconnect from the GonkBufferQueue |
|
153 mBufferQueue->consumerDisconnect(); |
|
154 mBufferQueue.clear(); |
|
155 } |
|
156 |
|
157 void GonkConsumerBase::setFrameAvailableListener( |
|
158 #if ANDROID_VERSION == 17 |
|
159 const sp<FrameAvailableListener>& listener) { |
|
160 #else |
|
161 const wp<FrameAvailableListener>& listener) { |
|
162 #endif |
|
163 CB_LOGV("setFrameAvailableListener"); |
|
164 Mutex::Autolock lock(mMutex); |
|
165 mFrameAvailableListener = listener; |
|
166 } |
|
167 |
|
168 void GonkConsumerBase::dump(String8& result) const { |
|
169 char buffer[1024]; |
|
170 dump(result, "", buffer, 1024); |
|
171 } |
|
172 |
|
173 void GonkConsumerBase::dump(String8& result, const char* prefix, |
|
174 char* buffer, size_t size) const { |
|
175 Mutex::Autolock _l(mMutex); |
|
176 dumpLocked(result, prefix, buffer, size); |
|
177 } |
|
178 |
|
179 void GonkConsumerBase::dumpLocked(String8& result, const char* prefix, |
|
180 char* buffer, size_t SIZE) const { |
|
181 snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned)); |
|
182 result.append(buffer); |
|
183 |
|
184 if (!mAbandoned) { |
|
185 mBufferQueue->dump(result, prefix, buffer, SIZE); |
|
186 } |
|
187 } |
|
188 |
|
189 status_t GonkConsumerBase::acquireBufferLocked(GonkBufferQueue::BufferItem *item) { |
|
190 status_t err = mBufferQueue->acquireBuffer(item); |
|
191 if (err != NO_ERROR) { |
|
192 return err; |
|
193 } |
|
194 |
|
195 if (item->mGraphicBuffer != NULL) { |
|
196 mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; |
|
197 } |
|
198 |
|
199 mSlots[item->mBuf].mFence = item->mFence; |
|
200 |
|
201 CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf); |
|
202 |
|
203 return OK; |
|
204 } |
|
205 |
|
206 status_t GonkConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) { |
|
207 Mutex::Autolock lock(mMutex); |
|
208 return addReleaseFenceLocked(slot, fence); |
|
209 } |
|
210 |
|
211 status_t GonkConsumerBase::addReleaseFenceLocked(int slot, const sp<Fence>& fence) { |
|
212 CB_LOGV("addReleaseFenceLocked: slot=%d", slot); |
|
213 |
|
214 if (!mSlots[slot].mFence.get()) { |
|
215 mSlots[slot].mFence = fence; |
|
216 } else { |
|
217 sp<Fence> mergedFence = Fence::merge( |
|
218 String8::format("%.28s:%d", mName.string(), slot), |
|
219 mSlots[slot].mFence, fence); |
|
220 if (!mergedFence.get()) { |
|
221 CB_LOGE("failed to merge release fences"); |
|
222 // synchronization is broken, the best we can do is hope fences |
|
223 // signal in order so the new fence will act like a union |
|
224 mSlots[slot].mFence = fence; |
|
225 return BAD_VALUE; |
|
226 } |
|
227 mSlots[slot].mFence = mergedFence; |
|
228 } |
|
229 |
|
230 return OK; |
|
231 } |
|
232 |
|
233 status_t GonkConsumerBase::releaseBufferLocked(int slot) { |
|
234 CB_LOGV("releaseBufferLocked: slot=%d", slot); |
|
235 status_t err = mBufferQueue->releaseBuffer(slot, mSlots[slot].mFence); |
|
236 if (err == GonkBufferQueue::STALE_BUFFER_SLOT) { |
|
237 freeBufferLocked(slot); |
|
238 } |
|
239 |
|
240 mSlots[slot].mFence = Fence::NO_FENCE; |
|
241 |
|
242 return err; |
|
243 } |
|
244 |
|
245 } // namespace android |