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