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