|
1 /* |
|
2 * Copyright (C) 2012 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 "GonkBufferQueue" |
|
19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS |
|
20 #define LOG_NDEBUG 0 |
|
21 |
|
22 #define GL_GLEXT_PROTOTYPES |
|
23 #define EGL_EGLEXT_PROTOTYPES |
|
24 |
|
25 #include <utils/Log.h> |
|
26 #include <utils/Trace.h> |
|
27 #include <utils/CallStack.h> |
|
28 #include <cutils/compiler.h> |
|
29 |
|
30 #include "mozilla/layers/GrallocTextureClient.h" |
|
31 #include "mozilla/layers/ImageBridgeChild.h" |
|
32 #include "GonkBufferQueueKK.h" |
|
33 |
|
34 // Macros for including the GonkBufferQueue name in log messages |
|
35 #define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) |
|
36 #define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) |
|
37 #define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) |
|
38 #define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) |
|
39 #define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) |
|
40 |
|
41 #define ATRACE_BUFFER_INDEX(index) |
|
42 |
|
43 using namespace mozilla; |
|
44 using namespace mozilla::gfx; |
|
45 using namespace mozilla::layers; |
|
46 |
|
47 namespace android { |
|
48 |
|
49 // Get an ID that's unique within this process. |
|
50 static int32_t createProcessUniqueId() { |
|
51 static volatile int32_t globalCounter = 0; |
|
52 return android_atomic_inc(&globalCounter); |
|
53 } |
|
54 |
|
55 static const char* scalingModeName(int scalingMode) { |
|
56 switch (scalingMode) { |
|
57 case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; |
|
58 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; |
|
59 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; |
|
60 default: return "Unknown"; |
|
61 } |
|
62 } |
|
63 |
|
64 class nsProxyReleaseTask : public Task |
|
65 { |
|
66 public: |
|
67 nsProxyReleaseTask(TextureClient* aClient) |
|
68 : mTextureClient(aClient) { |
|
69 } |
|
70 |
|
71 virtual void Run() MOZ_OVERRIDE |
|
72 { |
|
73 mTextureClient = nullptr; |
|
74 } |
|
75 |
|
76 private: |
|
77 mozilla::RefPtr<TextureClient> mTextureClient; |
|
78 }; |
|
79 |
|
80 GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode, |
|
81 const sp<IGraphicBufferAlloc>& allocator) : |
|
82 mDefaultWidth(1), |
|
83 mDefaultHeight(1), |
|
84 mMaxAcquiredBufferCount(1), |
|
85 mDefaultMaxBufferCount(2), |
|
86 mOverrideMaxBufferCount(0), |
|
87 // mSynchronousMode(true), // GonkBufferQueue always works in sync mode. |
|
88 mConsumerControlledByApp(false), |
|
89 mDequeueBufferCannotBlock(false), |
|
90 mUseAsyncBuffer(true), |
|
91 mConnectedApi(NO_CONNECTED_API), |
|
92 mAbandoned(false), |
|
93 mFrameCounter(0), |
|
94 mBufferHasBeenQueued(false), |
|
95 mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), |
|
96 mConsumerUsageBits(0), |
|
97 mTransformHint(0) |
|
98 { |
|
99 // Choose a name using the PID and a process-unique ID. |
|
100 mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); |
|
101 |
|
102 ST_LOGV("GonkBufferQueue"); |
|
103 } |
|
104 |
|
105 GonkBufferQueue::~GonkBufferQueue() { |
|
106 ST_LOGV("~GonkBufferQueue"); |
|
107 } |
|
108 |
|
109 status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) { |
|
110 if (count < 2 || count > NUM_BUFFER_SLOTS) |
|
111 return BAD_VALUE; |
|
112 |
|
113 mDefaultMaxBufferCount = count; |
|
114 mDequeueCondition.broadcast(); |
|
115 |
|
116 return NO_ERROR; |
|
117 } |
|
118 |
|
119 void GonkBufferQueue::setConsumerName(const String8& name) { |
|
120 Mutex::Autolock lock(mMutex); |
|
121 mConsumerName = name; |
|
122 } |
|
123 |
|
124 status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) { |
|
125 Mutex::Autolock lock(mMutex); |
|
126 mDefaultBufferFormat = defaultFormat; |
|
127 return NO_ERROR; |
|
128 } |
|
129 |
|
130 status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) { |
|
131 Mutex::Autolock lock(mMutex); |
|
132 mConsumerUsageBits = usage; |
|
133 return NO_ERROR; |
|
134 } |
|
135 |
|
136 status_t GonkBufferQueue::setTransformHint(uint32_t hint) { |
|
137 ST_LOGV("setTransformHint: %02x", hint); |
|
138 Mutex::Autolock lock(mMutex); |
|
139 mTransformHint = hint; |
|
140 return NO_ERROR; |
|
141 } |
|
142 |
|
143 TemporaryRef<TextureClient> |
|
144 GonkBufferQueue::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) |
|
145 { |
|
146 Mutex::Autolock _l(mMutex); |
|
147 if (buffer == NULL) { |
|
148 ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); |
|
149 return nullptr; |
|
150 } |
|
151 |
|
152 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
153 if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { |
|
154 return mSlots[i].mTextureClient; |
|
155 } |
|
156 } |
|
157 ST_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); |
|
158 return nullptr; |
|
159 } |
|
160 |
|
161 int GonkBufferQueue::getSlotFromTextureClientLocked( |
|
162 TextureClient* client) const |
|
163 { |
|
164 if (client == NULL) { |
|
165 ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); |
|
166 return BAD_VALUE; |
|
167 } |
|
168 |
|
169 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
170 if (mSlots[i].mTextureClient == client) { |
|
171 return i; |
|
172 } |
|
173 } |
|
174 ST_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); |
|
175 return BAD_VALUE; |
|
176 } |
|
177 |
|
178 status_t GonkBufferQueue::setBufferCount(int bufferCount) { |
|
179 ST_LOGV("setBufferCount: count=%d", bufferCount); |
|
180 |
|
181 sp<IConsumerListener> listener; |
|
182 { |
|
183 Mutex::Autolock lock(mMutex); |
|
184 |
|
185 if (mAbandoned) { |
|
186 ST_LOGE("setBufferCount: GonkBufferQueue has been abandoned!"); |
|
187 return NO_INIT; |
|
188 } |
|
189 if (bufferCount > NUM_BUFFER_SLOTS) { |
|
190 ST_LOGE("setBufferCount: bufferCount too large (max %d)", |
|
191 NUM_BUFFER_SLOTS); |
|
192 return BAD_VALUE; |
|
193 } |
|
194 |
|
195 // Error out if the user has dequeued buffers |
|
196 for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) { |
|
197 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { |
|
198 ST_LOGE("setBufferCount: client owns some buffers"); |
|
199 return -EINVAL; |
|
200 } |
|
201 } |
|
202 |
|
203 if (bufferCount == 0) { |
|
204 mOverrideMaxBufferCount = 0; |
|
205 mDequeueCondition.broadcast(); |
|
206 return NO_ERROR; |
|
207 } |
|
208 |
|
209 // fine to assume async to false before we're setting the buffer count |
|
210 const int minBufferSlots = getMinMaxBufferCountLocked(false); |
|
211 if (bufferCount < minBufferSlots) { |
|
212 ST_LOGE("setBufferCount: requested buffer count (%d) is less than " |
|
213 "minimum (%d)", bufferCount, minBufferSlots); |
|
214 return BAD_VALUE; |
|
215 } |
|
216 |
|
217 // here we're guaranteed that the client doesn't have dequeued buffers |
|
218 // and will release all of its buffer references. We don't clear the |
|
219 // queue, however, so currently queued buffers still get displayed. |
|
220 // XXX: Should this use drainQueueAndFreeBuffersLocked instead? |
|
221 freeAllBuffersLocked(); |
|
222 mOverrideMaxBufferCount = bufferCount; |
|
223 mDequeueCondition.broadcast(); |
|
224 listener = mConsumerListener; |
|
225 } // scope for lock |
|
226 |
|
227 if (listener != NULL) { |
|
228 listener->onBuffersReleased(); |
|
229 } |
|
230 |
|
231 return NO_ERROR; |
|
232 } |
|
233 |
|
234 int GonkBufferQueue::query(int what, int* outValue) |
|
235 { |
|
236 ATRACE_CALL(); |
|
237 Mutex::Autolock lock(mMutex); |
|
238 |
|
239 if (mAbandoned) { |
|
240 ST_LOGE("query: GonkBufferQueue has been abandoned!"); |
|
241 return NO_INIT; |
|
242 } |
|
243 |
|
244 int value; |
|
245 switch (what) { |
|
246 case NATIVE_WINDOW_WIDTH: |
|
247 value = mDefaultWidth; |
|
248 break; |
|
249 case NATIVE_WINDOW_HEIGHT: |
|
250 value = mDefaultHeight; |
|
251 break; |
|
252 case NATIVE_WINDOW_FORMAT: |
|
253 value = mDefaultBufferFormat; |
|
254 break; |
|
255 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: |
|
256 value = getMinUndequeuedBufferCount(false); |
|
257 break; |
|
258 case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: |
|
259 value = (mQueue.size() >= 2); |
|
260 break; |
|
261 case NATIVE_WINDOW_CONSUMER_USAGE_BITS: |
|
262 value = mConsumerUsageBits; |
|
263 break; |
|
264 default: |
|
265 return BAD_VALUE; |
|
266 } |
|
267 outValue[0] = value; |
|
268 return NO_ERROR; |
|
269 } |
|
270 |
|
271 status_t GonkBufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { |
|
272 ATRACE_CALL(); |
|
273 ST_LOGV("requestBuffer: slot=%d", slot); |
|
274 Mutex::Autolock lock(mMutex); |
|
275 if (mAbandoned) { |
|
276 ST_LOGE("requestBuffer: GonkBufferQueue has been abandoned!"); |
|
277 return NO_INIT; |
|
278 } |
|
279 if (slot < 0 || slot >= NUM_BUFFER_SLOTS) { |
|
280 ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", |
|
281 NUM_BUFFER_SLOTS, slot); |
|
282 return BAD_VALUE; |
|
283 } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { |
|
284 ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)", |
|
285 slot, mSlots[slot].mBufferState); |
|
286 return BAD_VALUE; |
|
287 } |
|
288 mSlots[slot].mRequestBufferCalled = true; |
|
289 *buf = mSlots[slot].mGraphicBuffer; |
|
290 return NO_ERROR; |
|
291 } |
|
292 |
|
293 status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async, |
|
294 uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { |
|
295 ATRACE_CALL(); |
|
296 ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); |
|
297 |
|
298 if ((w && !h) || (!w && h)) { |
|
299 ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); |
|
300 return BAD_VALUE; |
|
301 } |
|
302 |
|
303 status_t returnFlags(OK); |
|
304 int buf = INVALID_BUFFER_SLOT; |
|
305 |
|
306 { // Scope for the lock |
|
307 Mutex::Autolock lock(mMutex); |
|
308 |
|
309 if (format == 0) { |
|
310 format = mDefaultBufferFormat; |
|
311 } |
|
312 // turn on usage bits the consumer requested |
|
313 usage |= mConsumerUsageBits; |
|
314 |
|
315 int found = -1; |
|
316 bool tryAgain = true; |
|
317 while (tryAgain) { |
|
318 if (mAbandoned) { |
|
319 ST_LOGE("dequeueBuffer: GonkBufferQueue has been abandoned!"); |
|
320 return NO_INIT; |
|
321 } |
|
322 |
|
323 const int maxBufferCount = getMaxBufferCountLocked(async); |
|
324 if (async && mOverrideMaxBufferCount) { |
|
325 // FIXME: some drivers are manually setting the buffer-count (which they |
|
326 // shouldn't), so we do this extra test here to handle that case. |
|
327 // This is TEMPORARY, until we get this fixed. |
|
328 if (mOverrideMaxBufferCount < maxBufferCount) { |
|
329 ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override"); |
|
330 return BAD_VALUE; |
|
331 } |
|
332 } |
|
333 |
|
334 // Free up any buffers that are in slots beyond the max buffer |
|
335 // count. |
|
336 //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { |
|
337 // assert(mSlots[i].mBufferState == BufferSlot::FREE); |
|
338 // if (mSlots[i].mGraphicBuffer != NULL) { |
|
339 // freeBufferLocked(i); |
|
340 // returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS; |
|
341 // } |
|
342 //} |
|
343 |
|
344 // look for a free buffer to give to the client |
|
345 found = INVALID_BUFFER_SLOT; |
|
346 int dequeuedCount = 0; |
|
347 int acquiredCount = 0; |
|
348 for (int i = 0; i < maxBufferCount; i++) { |
|
349 const int state = mSlots[i].mBufferState; |
|
350 switch (state) { |
|
351 case BufferSlot::DEQUEUED: |
|
352 dequeuedCount++; |
|
353 break; |
|
354 case BufferSlot::ACQUIRED: |
|
355 acquiredCount++; |
|
356 break; |
|
357 case BufferSlot::FREE: |
|
358 /* We return the oldest of the free buffers to avoid |
|
359 * stalling the producer if possible. This is because |
|
360 * the consumer may still have pending reads of the |
|
361 * buffers in flight. |
|
362 */ |
|
363 if ((found < 0) || |
|
364 mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { |
|
365 found = i; |
|
366 } |
|
367 break; |
|
368 } |
|
369 } |
|
370 |
|
371 // clients are not allowed to dequeue more than one buffer |
|
372 // if they didn't set a buffer count. |
|
373 if (!mOverrideMaxBufferCount && dequeuedCount) { |
|
374 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " |
|
375 "setting the buffer count"); |
|
376 return -EINVAL; |
|
377 } |
|
378 |
|
379 // See whether a buffer has been queued since the last |
|
380 // setBufferCount so we know whether to perform the min undequeued |
|
381 // buffers check below. |
|
382 if (mBufferHasBeenQueued) { |
|
383 // make sure the client is not trying to dequeue more buffers |
|
384 // than allowed. |
|
385 const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); |
|
386 const int minUndequeuedCount = getMinUndequeuedBufferCount(async); |
|
387 if (newUndequeuedCount < minUndequeuedCount) { |
|
388 ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " |
|
389 "exceeded (dequeued=%d undequeudCount=%d)", |
|
390 minUndequeuedCount, dequeuedCount, |
|
391 newUndequeuedCount); |
|
392 return -EBUSY; |
|
393 } |
|
394 } |
|
395 |
|
396 // If no buffer is found, wait for a buffer to be released or for |
|
397 // the max buffer count to change. |
|
398 tryAgain = found == INVALID_BUFFER_SLOT; |
|
399 if (tryAgain) { |
|
400 // return an error if we're in "cannot block" mode (producer and consumer |
|
401 // are controlled by the application) -- however, the consumer is allowed |
|
402 // to acquire briefly an extra buffer (which could cause us to have to wait here) |
|
403 // and that's okay because we know the wait will be brief (it happens |
|
404 // if we dequeue a buffer while the consumer has acquired one but not released |
|
405 // the old one yet -- for e.g.: see GLConsumer::updateTexImage()). |
|
406 if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) { |
|
407 ST_LOGE("dequeueBuffer: would block! returning an error instead."); |
|
408 return WOULD_BLOCK; |
|
409 } |
|
410 mDequeueCondition.wait(mMutex); |
|
411 } |
|
412 } |
|
413 |
|
414 |
|
415 if (found == INVALID_BUFFER_SLOT) { |
|
416 // This should not happen. |
|
417 ST_LOGE("dequeueBuffer: no available buffer slots"); |
|
418 return -EBUSY; |
|
419 } |
|
420 |
|
421 buf = found; |
|
422 *outBuf = found; |
|
423 |
|
424 const bool useDefaultSize = !w && !h; |
|
425 if (useDefaultSize) { |
|
426 // use the default size |
|
427 w = mDefaultWidth; |
|
428 h = mDefaultHeight; |
|
429 } |
|
430 |
|
431 mSlots[buf].mBufferState = BufferSlot::DEQUEUED; |
|
432 |
|
433 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); |
|
434 if ((buffer == NULL) || |
|
435 (uint32_t(buffer->width) != w) || |
|
436 (uint32_t(buffer->height) != h) || |
|
437 (uint32_t(buffer->format) != format) || |
|
438 ((uint32_t(buffer->usage) & usage) != usage)) |
|
439 { |
|
440 mSlots[buf].mAcquireCalled = false; |
|
441 mSlots[buf].mGraphicBuffer = NULL; |
|
442 mSlots[buf].mRequestBufferCalled = false; |
|
443 mSlots[buf].mFence = Fence::NO_FENCE; |
|
444 if (mSlots[buf].mTextureClient) { |
|
445 mSlots[buf].mTextureClient->ClearRecycleCallback(); |
|
446 // release TextureClient in ImageBridge thread |
|
447 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient); |
|
448 mSlots[buf].mTextureClient = NULL; |
|
449 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); |
|
450 } |
|
451 returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION; |
|
452 } |
|
453 |
|
454 |
|
455 if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) { |
|
456 ST_LOGE("dequeueBuffer: about to return a NULL fence from mSlot. " |
|
457 "buf=%d, w=%d, h=%d, format=%d", |
|
458 buf, buffer->width, buffer->height, buffer->format); |
|
459 } |
|
460 *outFence = mSlots[buf].mFence; |
|
461 mSlots[buf].mFence = Fence::NO_FENCE; |
|
462 } // end lock scope |
|
463 |
|
464 sp<GraphicBuffer> graphicBuffer; |
|
465 if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { |
|
466 RefPtr<GrallocTextureClientOGL> textureClient = |
|
467 new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(), |
|
468 gfx::SurfaceFormat::UNKNOWN, |
|
469 gfx::BackendType::NONE, |
|
470 TEXTURE_DEALLOCATE_CLIENT); |
|
471 usage |= GraphicBuffer::USAGE_HW_TEXTURE; |
|
472 bool result = textureClient->AllocateGralloc(IntSize(w, h), format, usage); |
|
473 sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer(); |
|
474 if (!result || !graphicBuffer.get()) { |
|
475 ST_LOGE("dequeueBuffer: failed to alloc gralloc buffer"); |
|
476 return -ENOMEM; |
|
477 } |
|
478 |
|
479 { // Scope for the lock |
|
480 Mutex::Autolock lock(mMutex); |
|
481 |
|
482 if (mAbandoned) { |
|
483 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); |
|
484 return NO_INIT; |
|
485 } |
|
486 |
|
487 mSlots[buf].mGraphicBuffer = graphicBuffer; |
|
488 mSlots[buf].mTextureClient = textureClient; |
|
489 ST_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, |
|
490 mSlots[buf].mGraphicBuffer->handle); |
|
491 |
|
492 } |
|
493 |
|
494 } |
|
495 |
|
496 ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf, |
|
497 mSlots[*outBuf].mFrameNumber, |
|
498 mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); |
|
499 |
|
500 return returnFlags; |
|
501 } |
|
502 |
|
503 status_t GonkBufferQueue::queueBuffer(int buf, |
|
504 const QueueBufferInput& input, QueueBufferOutput* output) { |
|
505 ATRACE_CALL(); |
|
506 |
|
507 Rect crop; |
|
508 uint32_t transform; |
|
509 int scalingMode; |
|
510 int64_t timestamp; |
|
511 bool isAutoTimestamp; |
|
512 bool async; |
|
513 sp<Fence> fence; |
|
514 |
|
515 input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, |
|
516 &async, &fence); |
|
517 |
|
518 if (fence == NULL) { |
|
519 ST_LOGE("queueBuffer: fence is NULL"); |
|
520 return BAD_VALUE; |
|
521 } |
|
522 |
|
523 ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " |
|
524 "scale=%s", |
|
525 buf, timestamp, crop.left, crop.top, crop.right, crop.bottom, |
|
526 transform, scalingModeName(scalingMode)); |
|
527 |
|
528 switch (scalingMode) { |
|
529 case NATIVE_WINDOW_SCALING_MODE_FREEZE: |
|
530 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: |
|
531 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: |
|
532 case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: |
|
533 break; |
|
534 default: |
|
535 ST_LOGE("unknown scaling mode: %d", scalingMode); |
|
536 return -EINVAL; |
|
537 } |
|
538 |
|
539 sp<IConsumerListener> listener; |
|
540 |
|
541 { // scope for the lock |
|
542 Mutex::Autolock lock(mMutex); |
|
543 |
|
544 if (mAbandoned) { |
|
545 ST_LOGE("queueBuffer: GonkBufferQueue has been abandoned!"); |
|
546 return NO_INIT; |
|
547 } |
|
548 |
|
549 const int maxBufferCount = getMaxBufferCountLocked(async); |
|
550 if (async && mOverrideMaxBufferCount) { |
|
551 // FIXME: some drivers are manually setting the buffer-count (which they |
|
552 // shouldn't), so we do this extra test here to handle that case. |
|
553 // This is TEMPORARY, until we get this fixed. |
|
554 if (mOverrideMaxBufferCount < maxBufferCount) { |
|
555 ST_LOGE("queueBuffer: async mode is invalid with buffercount override"); |
|
556 return BAD_VALUE; |
|
557 } |
|
558 } |
|
559 if (buf < 0 || buf >= maxBufferCount) { |
|
560 ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", |
|
561 maxBufferCount, buf); |
|
562 return -EINVAL; |
|
563 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { |
|
564 ST_LOGE("queueBuffer: slot %d is not owned by the client " |
|
565 "(state=%d)", buf, mSlots[buf].mBufferState); |
|
566 return -EINVAL; |
|
567 } else if (!mSlots[buf].mRequestBufferCalled) { |
|
568 ST_LOGE("queueBuffer: slot %d was enqueued without requesting a " |
|
569 "buffer", buf); |
|
570 return -EINVAL; |
|
571 } |
|
572 |
|
573 ST_LOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] " |
|
574 "tr=%#x scale=%s", |
|
575 buf, mFrameCounter + 1, timestamp, |
|
576 crop.left, crop.top, crop.right, crop.bottom, |
|
577 transform, scalingModeName(scalingMode)); |
|
578 |
|
579 const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer); |
|
580 Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); |
|
581 Rect croppedCrop; |
|
582 crop.intersect(bufferRect, &croppedCrop); |
|
583 if (croppedCrop != crop) { |
|
584 ST_LOGE("queueBuffer: crop rect is not contained within the " |
|
585 "buffer in slot %d", buf); |
|
586 return -EINVAL; |
|
587 } |
|
588 |
|
589 mSlots[buf].mFence = fence; |
|
590 mSlots[buf].mBufferState = BufferSlot::QUEUED; |
|
591 mFrameCounter++; |
|
592 mSlots[buf].mFrameNumber = mFrameCounter; |
|
593 |
|
594 BufferItem item; |
|
595 item.mAcquireCalled = mSlots[buf].mAcquireCalled; |
|
596 item.mGraphicBuffer = mSlots[buf].mGraphicBuffer; |
|
597 item.mCrop = crop; |
|
598 item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; |
|
599 item.mTransformToDisplayInverse = bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); |
|
600 item.mScalingMode = scalingMode; |
|
601 item.mTimestamp = timestamp; |
|
602 item.mIsAutoTimestamp = isAutoTimestamp; |
|
603 item.mFrameNumber = mFrameCounter; |
|
604 item.mBuf = buf; |
|
605 item.mFence = fence; |
|
606 item.mIsDroppable = mDequeueBufferCannotBlock || async; |
|
607 |
|
608 if (mQueue.empty()) { |
|
609 // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and |
|
610 // simply queue this buffer. |
|
611 mQueue.push_back(item); |
|
612 listener = mConsumerListener; |
|
613 } else { |
|
614 // when the queue is not empty, we need to look at the front buffer |
|
615 // state and see if we need to replace it. |
|
616 Fifo::iterator front(mQueue.begin()); |
|
617 if (front->mIsDroppable) { |
|
618 // buffer slot currently queued is marked free if still tracked |
|
619 if (stillTracking(front)) { |
|
620 mSlots[front->mBuf].mBufferState = BufferSlot::FREE; |
|
621 // reset the frame number of the freed buffer so that it is the first in |
|
622 // line to be dequeued again. |
|
623 mSlots[front->mBuf].mFrameNumber = 0; |
|
624 } |
|
625 // and we record the new buffer in the queued list |
|
626 *front = item; |
|
627 } else { |
|
628 mQueue.push_back(item); |
|
629 listener = mConsumerListener; |
|
630 } |
|
631 } |
|
632 |
|
633 mBufferHasBeenQueued = true; |
|
634 mDequeueCondition.broadcast(); |
|
635 |
|
636 output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, |
|
637 mQueue.size()); |
|
638 |
|
639 } // scope for the lock |
|
640 |
|
641 // call back without lock held |
|
642 if (listener != 0) { |
|
643 listener->onFrameAvailable(); |
|
644 } |
|
645 return NO_ERROR; |
|
646 } |
|
647 |
|
648 void GonkBufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) { |
|
649 ATRACE_CALL(); |
|
650 ST_LOGV("cancelBuffer: slot=%d", buf); |
|
651 Mutex::Autolock lock(mMutex); |
|
652 |
|
653 if (mAbandoned) { |
|
654 ST_LOGW("cancelBuffer: GonkBufferQueue has been abandoned!"); |
|
655 return; |
|
656 } |
|
657 |
|
658 if (buf < 0 || buf >= NUM_BUFFER_SLOTS) { |
|
659 ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", |
|
660 NUM_BUFFER_SLOTS, buf); |
|
661 return; |
|
662 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { |
|
663 ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", |
|
664 buf, mSlots[buf].mBufferState); |
|
665 return; |
|
666 } else if (fence == NULL) { |
|
667 ST_LOGE("cancelBuffer: fence is NULL"); |
|
668 return; |
|
669 } |
|
670 mSlots[buf].mBufferState = BufferSlot::FREE; |
|
671 mSlots[buf].mFrameNumber = 0; |
|
672 mSlots[buf].mFence = fence; |
|
673 mDequeueCondition.broadcast(); |
|
674 } |
|
675 |
|
676 |
|
677 status_t GonkBufferQueue::connect(const sp<IBinder>& token, |
|
678 int api, bool producerControlledByApp, QueueBufferOutput* output) { |
|
679 ATRACE_CALL(); |
|
680 ST_LOGV("connect: api=%d producerControlledByApp=%s", api, |
|
681 producerControlledByApp ? "true" : "false"); |
|
682 Mutex::Autolock lock(mMutex); |
|
683 |
|
684 retry: |
|
685 if (mAbandoned) { |
|
686 ST_LOGE("connect: GonkBufferQueue has been abandoned!"); |
|
687 return NO_INIT; |
|
688 } |
|
689 |
|
690 if (mConsumerListener == NULL) { |
|
691 ST_LOGE("connect: GonkBufferQueue has no consumer!"); |
|
692 return NO_INIT; |
|
693 } |
|
694 |
|
695 if (mConnectedApi != NO_CONNECTED_API) { |
|
696 ST_LOGE("connect: already connected (cur=%d, req=%d)", |
|
697 mConnectedApi, api); |
|
698 return -EINVAL; |
|
699 } |
|
700 |
|
701 // If we disconnect and reconnect quickly, we can be in a state where our slots are |
|
702 // empty but we have many buffers in the queue. This can cause us to run out of |
|
703 // memory if we outrun the consumer. Wait here if it looks like we have too many |
|
704 // buffers queued up. |
|
705 int maxBufferCount = getMaxBufferCountLocked(false); // worst-case, i.e. largest value |
|
706 if (mQueue.size() > (size_t) maxBufferCount) { |
|
707 // TODO: make this bound tighter? |
|
708 ST_LOGV("queue size is %d, waiting", mQueue.size()); |
|
709 mDequeueCondition.wait(mMutex); |
|
710 goto retry; |
|
711 } |
|
712 |
|
713 int err = NO_ERROR; |
|
714 switch (api) { |
|
715 case NATIVE_WINDOW_API_EGL: |
|
716 case NATIVE_WINDOW_API_CPU: |
|
717 case NATIVE_WINDOW_API_MEDIA: |
|
718 case NATIVE_WINDOW_API_CAMERA: |
|
719 mConnectedApi = api; |
|
720 output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size()); |
|
721 |
|
722 // set-up a death notification so that we can disconnect |
|
723 // automatically when/if the remote producer dies. |
|
724 if (token != NULL && token->remoteBinder() != NULL) { |
|
725 status_t err = token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); |
|
726 if (err == NO_ERROR) { |
|
727 mConnectedProducerToken = token; |
|
728 } else { |
|
729 ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err); |
|
730 } |
|
731 } |
|
732 break; |
|
733 default: |
|
734 err = -EINVAL; |
|
735 break; |
|
736 } |
|
737 |
|
738 mBufferHasBeenQueued = false; |
|
739 mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; |
|
740 |
|
741 return err; |
|
742 } |
|
743 |
|
744 void GonkBufferQueue::binderDied(const wp<IBinder>& who) { |
|
745 // If we're here, it means that a producer we were connected to died. |
|
746 // We're GUARANTEED that we still are connected to it because it has no other way |
|
747 // to get disconnected -- or -- we wouldn't be here because we're removing this |
|
748 // callback upon disconnect. Therefore, it's okay to read mConnectedApi without |
|
749 // synchronization here. |
|
750 int api = mConnectedApi; |
|
751 this->disconnect(api); |
|
752 } |
|
753 |
|
754 status_t GonkBufferQueue::disconnect(int api) { |
|
755 ATRACE_CALL(); |
|
756 ST_LOGV("disconnect: api=%d", api); |
|
757 |
|
758 int err = NO_ERROR; |
|
759 sp<IConsumerListener> listener; |
|
760 |
|
761 { // Scope for the lock |
|
762 Mutex::Autolock lock(mMutex); |
|
763 |
|
764 if (mAbandoned) { |
|
765 // it is not really an error to disconnect after the surface |
|
766 // has been abandoned, it should just be a no-op. |
|
767 return NO_ERROR; |
|
768 } |
|
769 |
|
770 switch (api) { |
|
771 case NATIVE_WINDOW_API_EGL: |
|
772 case NATIVE_WINDOW_API_CPU: |
|
773 case NATIVE_WINDOW_API_MEDIA: |
|
774 case NATIVE_WINDOW_API_CAMERA: |
|
775 if (mConnectedApi == api) { |
|
776 freeAllBuffersLocked(); |
|
777 mConnectedApi = NO_CONNECTED_API; |
|
778 mDequeueCondition.broadcast(); |
|
779 listener = mConsumerListener; |
|
780 } else { |
|
781 ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)", |
|
782 mConnectedApi, api); |
|
783 err = -EINVAL; |
|
784 } |
|
785 break; |
|
786 default: |
|
787 ST_LOGE("disconnect: unknown API %d", api); |
|
788 err = -EINVAL; |
|
789 break; |
|
790 } |
|
791 } |
|
792 |
|
793 if (listener != NULL) { |
|
794 listener->onBuffersReleased(); |
|
795 } |
|
796 |
|
797 return err; |
|
798 } |
|
799 |
|
800 void GonkBufferQueue::dump(String8& result, const char* prefix) const { |
|
801 Mutex::Autolock _l(mMutex); |
|
802 |
|
803 String8 fifo; |
|
804 int fifoSize = 0; |
|
805 Fifo::const_iterator i(mQueue.begin()); |
|
806 while (i != mQueue.end()) { |
|
807 fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " |
|
808 "xform=0x%02x, time=%#llx, scale=%s\n", |
|
809 i->mBuf, i->mGraphicBuffer.get(), |
|
810 i->mCrop.left, i->mCrop.top, i->mCrop.right, |
|
811 i->mCrop.bottom, i->mTransform, i->mTimestamp, |
|
812 scalingModeName(i->mScalingMode) |
|
813 ); |
|
814 i++; |
|
815 fifoSize++; |
|
816 } |
|
817 |
|
818 |
|
819 result.appendFormat( |
|
820 "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " |
|
821 "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", |
|
822 prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, |
|
823 mDefaultHeight, mDefaultBufferFormat, mTransformHint, |
|
824 fifoSize, fifo.string()); |
|
825 |
|
826 struct { |
|
827 const char * operator()(int state) const { |
|
828 switch (state) { |
|
829 case BufferSlot::DEQUEUED: return "DEQUEUED"; |
|
830 case BufferSlot::QUEUED: return "QUEUED"; |
|
831 case BufferSlot::FREE: return "FREE"; |
|
832 case BufferSlot::ACQUIRED: return "ACQUIRED"; |
|
833 default: return "Unknown"; |
|
834 } |
|
835 } |
|
836 } stateName; |
|
837 |
|
838 // just trim the free buffers to not spam the dump |
|
839 int maxBufferCount = 0; |
|
840 for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) { |
|
841 const BufferSlot& slot(mSlots[i]); |
|
842 if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) { |
|
843 maxBufferCount = i+1; |
|
844 break; |
|
845 } |
|
846 } |
|
847 |
|
848 for (int i=0 ; i<maxBufferCount ; i++) { |
|
849 const BufferSlot& slot(mSlots[i]); |
|
850 const sp<GraphicBuffer>& buf(slot.mGraphicBuffer); |
|
851 result.appendFormat( |
|
852 "%s%s[%02d:%p] state=%-8s", |
|
853 prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(), |
|
854 stateName(slot.mBufferState) |
|
855 ); |
|
856 |
|
857 if (buf != NULL) { |
|
858 result.appendFormat( |
|
859 ", %p [%4ux%4u:%4u,%3X]", |
|
860 buf->handle, buf->width, buf->height, buf->stride, |
|
861 buf->format); |
|
862 } |
|
863 result.append("\n"); |
|
864 } |
|
865 } |
|
866 |
|
867 void GonkBufferQueue::freeAllBuffersLocked() |
|
868 { |
|
869 ALOGW_IF(!mQueue.isEmpty(), |
|
870 "freeAllBuffersLocked called but mQueue is not empty"); |
|
871 mQueue.clear(); |
|
872 mBufferHasBeenQueued = false; |
|
873 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
874 mSlots[i].mGraphicBuffer = 0; |
|
875 if (mSlots[i].mTextureClient) { |
|
876 mSlots[i].mTextureClient->ClearRecycleCallback(); |
|
877 // release TextureClient in ImageBridge thread |
|
878 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient); |
|
879 mSlots[i].mTextureClient = NULL; |
|
880 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task); |
|
881 } |
|
882 if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { |
|
883 mSlots[i].mNeedsCleanupOnRelease = true; |
|
884 } |
|
885 mSlots[i].mBufferState = BufferSlot::FREE; |
|
886 mSlots[i].mFrameNumber = 0; |
|
887 mSlots[i].mAcquireCalled = false; |
|
888 // destroy fence as GonkBufferQueue now takes ownership |
|
889 mSlots[i].mFence = Fence::NO_FENCE; |
|
890 } |
|
891 } |
|
892 |
|
893 status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) { |
|
894 ATRACE_CALL(); |
|
895 Mutex::Autolock _l(mMutex); |
|
896 |
|
897 // Check that the consumer doesn't currently have the maximum number of |
|
898 // buffers acquired. We allow the max buffer count to be exceeded by one |
|
899 // buffer, so that the consumer can successfully set up the newly acquired |
|
900 // buffer before releasing the old one. |
|
901 int numAcquiredBuffers = 0; |
|
902 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
903 if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { |
|
904 numAcquiredBuffers++; |
|
905 } |
|
906 } |
|
907 if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) { |
|
908 ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)", |
|
909 numAcquiredBuffers, mMaxAcquiredBufferCount); |
|
910 return INVALID_OPERATION; |
|
911 } |
|
912 |
|
913 // check if queue is empty |
|
914 // In asynchronous mode the list is guaranteed to be one buffer |
|
915 // deep, while in synchronous mode we use the oldest buffer. |
|
916 if (mQueue.empty()) { |
|
917 return NO_BUFFER_AVAILABLE; |
|
918 } |
|
919 |
|
920 Fifo::iterator front(mQueue.begin()); |
|
921 |
|
922 // If expectedPresent is specified, we may not want to return a buffer yet. |
|
923 // If it's specified and there's more than one buffer queued, we may |
|
924 // want to drop a buffer. |
|
925 if (expectedPresent != 0) { |
|
926 const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second |
|
927 |
|
928 // The "expectedPresent" argument indicates when the buffer is expected |
|
929 // to be presented on-screen. If the buffer's desired-present time |
|
930 // is earlier (less) than expectedPresent, meaning it'll be displayed |
|
931 // on time or possibly late if we show it ASAP, we acquire and return |
|
932 // it. If we don't want to display it until after the expectedPresent |
|
933 // time, we return PRESENT_LATER without acquiring it. |
|
934 // |
|
935 // To be safe, we don't defer acquisition if expectedPresent is |
|
936 // more than one second in the future beyond the desired present time |
|
937 // (i.e. we'd be holding the buffer for a long time). |
|
938 // |
|
939 // NOTE: code assumes monotonic time values from the system clock are |
|
940 // positive. |
|
941 |
|
942 // Start by checking to see if we can drop frames. We skip this check |
|
943 // if the timestamps are being auto-generated by Surface -- if the |
|
944 // app isn't generating timestamps explicitly, they probably don't |
|
945 // want frames to be discarded based on them. |
|
946 while (mQueue.size() > 1 && !mQueue[0].mIsAutoTimestamp) { |
|
947 // If entry[1] is timely, drop entry[0] (and repeat). We apply |
|
948 // an additional criteria here: we only drop the earlier buffer if |
|
949 // our desiredPresent falls within +/- 1 second of the expected |
|
950 // present. Otherwise, bogus desiredPresent times (e.g. 0 or |
|
951 // a small relative timestamp), which normally mean "ignore the |
|
952 // timestamp and acquire immediately", would cause us to drop |
|
953 // frames. |
|
954 // |
|
955 // We may want to add an additional criteria: don't drop the |
|
956 // earlier buffer if entry[1]'s fence hasn't signaled yet. |
|
957 // |
|
958 // (Vector front is [0], back is [size()-1]) |
|
959 const BufferItem& bi(mQueue[1]); |
|
960 nsecs_t desiredPresent = bi.mTimestamp; |
|
961 if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || |
|
962 desiredPresent > expectedPresent) { |
|
963 // This buffer is set to display in the near future, or |
|
964 // desiredPresent is garbage. Either way we don't want to |
|
965 // drop the previous buffer just to get this on screen sooner. |
|
966 ST_LOGV("pts nodrop: des=%lld expect=%lld (%lld) now=%lld", |
|
967 desiredPresent, expectedPresent, desiredPresent - expectedPresent, |
|
968 systemTime(CLOCK_MONOTONIC)); |
|
969 break; |
|
970 } |
|
971 ST_LOGV("pts drop: queue1des=%lld expect=%lld size=%d", |
|
972 desiredPresent, expectedPresent, mQueue.size()); |
|
973 if (stillTracking(front)) { |
|
974 // front buffer is still in mSlots, so mark the slot as free |
|
975 mSlots[front->mBuf].mBufferState = BufferSlot::FREE; |
|
976 } |
|
977 mQueue.erase(front); |
|
978 front = mQueue.begin(); |
|
979 } |
|
980 |
|
981 // See if the front buffer is due. |
|
982 nsecs_t desiredPresent = front->mTimestamp; |
|
983 if (desiredPresent > expectedPresent && |
|
984 desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { |
|
985 ST_LOGV("pts defer: des=%lld expect=%lld (%lld) now=%lld", |
|
986 desiredPresent, expectedPresent, desiredPresent - expectedPresent, |
|
987 systemTime(CLOCK_MONOTONIC)); |
|
988 return PRESENT_LATER; |
|
989 } |
|
990 |
|
991 ST_LOGV("pts accept: des=%lld expect=%lld (%lld) now=%lld", |
|
992 desiredPresent, expectedPresent, desiredPresent - expectedPresent, |
|
993 systemTime(CLOCK_MONOTONIC)); |
|
994 } |
|
995 |
|
996 int buf = front->mBuf; |
|
997 buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; |
|
998 buffer->mFrameNumber = mSlots[buf].mFrameNumber; |
|
999 buffer->mBuf = buf; |
|
1000 buffer->mFence = mSlots[buf].mFence; |
|
1001 ATRACE_BUFFER_INDEX(buf); |
|
1002 |
|
1003 ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }", |
|
1004 front->mBuf, front->mFrameNumber, |
|
1005 front->mGraphicBuffer->handle); |
|
1006 // if front buffer still being tracked update slot state |
|
1007 if (stillTracking(front)) { |
|
1008 mSlots[buf].mAcquireCalled = true; |
|
1009 mSlots[buf].mNeedsCleanupOnRelease = false; |
|
1010 mSlots[buf].mBufferState = BufferSlot::ACQUIRED; |
|
1011 mSlots[buf].mFence = Fence::NO_FENCE; |
|
1012 } |
|
1013 |
|
1014 // If the buffer has previously been acquired by the consumer, set |
|
1015 // mGraphicBuffer to NULL to avoid unnecessarily remapping this |
|
1016 // buffer on the consumer side. |
|
1017 //if (buffer->mAcquireCalled) { |
|
1018 // buffer->mGraphicBuffer = NULL; |
|
1019 //} |
|
1020 |
|
1021 mQueue.erase(front); |
|
1022 mDequeueCondition.broadcast(); |
|
1023 |
|
1024 return NO_ERROR; |
|
1025 } |
|
1026 |
|
1027 status_t GonkBufferQueue::releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& fence) { |
|
1028 ATRACE_CALL(); |
|
1029 |
|
1030 if (buf == INVALID_BUFFER_SLOT || fence == NULL) { |
|
1031 return BAD_VALUE; |
|
1032 } |
|
1033 |
|
1034 Mutex::Autolock _l(mMutex); |
|
1035 |
|
1036 // If the frame number has changed because buffer has been reallocated, |
|
1037 // we can ignore this releaseBuffer for the old buffer. |
|
1038 //if (frameNumber != mSlots[buf].mFrameNumber) { |
|
1039 // return STALE_BUFFER_SLOT; |
|
1040 //} |
|
1041 |
|
1042 |
|
1043 // Internal state consistency checks: |
|
1044 // Make sure this buffers hasn't been queued while we were owning it (acquired) |
|
1045 Fifo::iterator front(mQueue.begin()); |
|
1046 Fifo::const_iterator const end(mQueue.end()); |
|
1047 while (front != end) { |
|
1048 if (front->mBuf == buf) { |
|
1049 LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been " |
|
1050 "acquired", mConsumerName.string(), frameNumber, buf); |
|
1051 break; // never reached |
|
1052 } |
|
1053 front++; |
|
1054 } |
|
1055 |
|
1056 // The buffer can now only be released if its in the acquired state |
|
1057 if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { |
|
1058 mSlots[buf].mFence = fence; |
|
1059 mSlots[buf].mBufferState = BufferSlot::FREE; |
|
1060 } else if (mSlots[buf].mNeedsCleanupOnRelease) { |
|
1061 ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState); |
|
1062 mSlots[buf].mNeedsCleanupOnRelease = false; |
|
1063 return STALE_BUFFER_SLOT; |
|
1064 } else { |
|
1065 ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState); |
|
1066 return -EINVAL; |
|
1067 } |
|
1068 |
|
1069 mDequeueCondition.broadcast(); |
|
1070 return NO_ERROR; |
|
1071 } |
|
1072 |
|
1073 status_t GonkBufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener, |
|
1074 bool controlledByApp) { |
|
1075 ST_LOGV("consumerConnect controlledByApp=%s", |
|
1076 controlledByApp ? "true" : "false"); |
|
1077 Mutex::Autolock lock(mMutex); |
|
1078 |
|
1079 if (mAbandoned) { |
|
1080 ST_LOGE("consumerConnect: GonkBufferQueue has been abandoned!"); |
|
1081 return NO_INIT; |
|
1082 } |
|
1083 if (consumerListener == NULL) { |
|
1084 ST_LOGE("consumerConnect: consumerListener may not be NULL"); |
|
1085 return BAD_VALUE; |
|
1086 } |
|
1087 |
|
1088 mConsumerListener = consumerListener; |
|
1089 mConsumerControlledByApp = controlledByApp; |
|
1090 |
|
1091 return NO_ERROR; |
|
1092 } |
|
1093 |
|
1094 status_t GonkBufferQueue::consumerDisconnect() { |
|
1095 ST_LOGV("consumerDisconnect"); |
|
1096 Mutex::Autolock lock(mMutex); |
|
1097 |
|
1098 if (mConsumerListener == NULL) { |
|
1099 ST_LOGE("consumerDisconnect: No consumer is connected!"); |
|
1100 return -EINVAL; |
|
1101 } |
|
1102 |
|
1103 mAbandoned = true; |
|
1104 mConsumerListener = NULL; |
|
1105 mQueue.clear(); |
|
1106 freeAllBuffersLocked(); |
|
1107 mDequeueCondition.broadcast(); |
|
1108 return NO_ERROR; |
|
1109 } |
|
1110 |
|
1111 status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) { |
|
1112 ST_LOGV("getReleasedBuffers"); |
|
1113 Mutex::Autolock lock(mMutex); |
|
1114 |
|
1115 if (mAbandoned) { |
|
1116 ST_LOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!"); |
|
1117 return NO_INIT; |
|
1118 } |
|
1119 |
|
1120 uint32_t mask = 0; |
|
1121 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { |
|
1122 if (!mSlots[i].mAcquireCalled) { |
|
1123 mask |= 1 << i; |
|
1124 } |
|
1125 } |
|
1126 |
|
1127 // Remove buffers in flight (on the queue) from the mask where acquire has |
|
1128 // been called, as the consumer will not receive the buffer address, so |
|
1129 // it should not free these slots. |
|
1130 Fifo::iterator front(mQueue.begin()); |
|
1131 while (front != mQueue.end()) { |
|
1132 if (front->mAcquireCalled) |
|
1133 mask &= ~(1 << front->mBuf); |
|
1134 front++; |
|
1135 } |
|
1136 |
|
1137 *slotMask = mask; |
|
1138 |
|
1139 ST_LOGV("getReleasedBuffers: returning mask %#x", mask); |
|
1140 return NO_ERROR; |
|
1141 } |
|
1142 |
|
1143 status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) { |
|
1144 ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); |
|
1145 if (!w || !h) { |
|
1146 ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", |
|
1147 w, h); |
|
1148 return BAD_VALUE; |
|
1149 } |
|
1150 |
|
1151 Mutex::Autolock lock(mMutex); |
|
1152 mDefaultWidth = w; |
|
1153 mDefaultHeight = h; |
|
1154 return NO_ERROR; |
|
1155 } |
|
1156 |
|
1157 status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) { |
|
1158 ATRACE_CALL(); |
|
1159 Mutex::Autolock lock(mMutex); |
|
1160 return setDefaultMaxBufferCountLocked(bufferCount); |
|
1161 } |
|
1162 |
|
1163 status_t GonkBufferQueue::disableAsyncBuffer() { |
|
1164 ATRACE_CALL(); |
|
1165 Mutex::Autolock lock(mMutex); |
|
1166 if (mConsumerListener != NULL) { |
|
1167 ST_LOGE("disableAsyncBuffer: consumer already connected!"); |
|
1168 return INVALID_OPERATION; |
|
1169 } |
|
1170 mUseAsyncBuffer = false; |
|
1171 return NO_ERROR; |
|
1172 } |
|
1173 |
|
1174 status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { |
|
1175 ATRACE_CALL(); |
|
1176 Mutex::Autolock lock(mMutex); |
|
1177 if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) { |
|
1178 ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d", |
|
1179 maxAcquiredBuffers); |
|
1180 return BAD_VALUE; |
|
1181 } |
|
1182 if (mConnectedApi != NO_CONNECTED_API) { |
|
1183 return INVALID_OPERATION; |
|
1184 } |
|
1185 mMaxAcquiredBufferCount = maxAcquiredBuffers; |
|
1186 return NO_ERROR; |
|
1187 } |
|
1188 |
|
1189 int GonkBufferQueue::getMinUndequeuedBufferCount(bool async) const { |
|
1190 // if dequeueBuffer is allowed to error out, we don't have to |
|
1191 // add an extra buffer. |
|
1192 if (!mUseAsyncBuffer) |
|
1193 return mMaxAcquiredBufferCount; |
|
1194 |
|
1195 // we're in async mode, or we want to prevent the app to |
|
1196 // deadlock itself, we throw-in an extra buffer to guarantee it. |
|
1197 if (mDequeueBufferCannotBlock || async) |
|
1198 return mMaxAcquiredBufferCount + 1; |
|
1199 |
|
1200 return mMaxAcquiredBufferCount; |
|
1201 } |
|
1202 |
|
1203 int GonkBufferQueue::getMinMaxBufferCountLocked(bool async) const { |
|
1204 return getMinUndequeuedBufferCount(async) + 1; |
|
1205 } |
|
1206 |
|
1207 int GonkBufferQueue::getMaxBufferCountLocked(bool async) const { |
|
1208 int minMaxBufferCount = getMinMaxBufferCountLocked(async); |
|
1209 |
|
1210 int maxBufferCount = mDefaultMaxBufferCount; |
|
1211 if (maxBufferCount < minMaxBufferCount) { |
|
1212 maxBufferCount = minMaxBufferCount; |
|
1213 } |
|
1214 if (mOverrideMaxBufferCount != 0) { |
|
1215 assert(mOverrideMaxBufferCount >= minMaxBufferCount); |
|
1216 maxBufferCount = mOverrideMaxBufferCount; |
|
1217 } |
|
1218 |
|
1219 // Any buffers that are dequeued by the producer or sitting in the queue |
|
1220 // waiting to be consumed need to have their slots preserved. Such |
|
1221 // buffers will temporarily keep the max buffer count up until the slots |
|
1222 // no longer need to be preserved. |
|
1223 for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { |
|
1224 BufferSlot::BufferState state = mSlots[i].mBufferState; |
|
1225 if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) { |
|
1226 maxBufferCount = i + 1; |
|
1227 } |
|
1228 } |
|
1229 |
|
1230 return maxBufferCount; |
|
1231 } |
|
1232 |
|
1233 bool GonkBufferQueue::stillTracking(const BufferItem *item) const { |
|
1234 const BufferSlot &slot = mSlots[item->mBuf]; |
|
1235 |
|
1236 ST_LOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, " |
|
1237 "slot: { slot=%d/%llu, buffer=%p }", |
|
1238 item->mBuf, item->mFrameNumber, |
|
1239 (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0), |
|
1240 item->mBuf, slot.mFrameNumber, |
|
1241 (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0)); |
|
1242 |
|
1243 // Compare item with its original buffer slot. We can check the slot |
|
1244 // as the buffer would not be moved to a different slot by the producer. |
|
1245 return (slot.mGraphicBuffer != NULL && |
|
1246 item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle); |
|
1247 } |
|
1248 |
|
1249 GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener( |
|
1250 const wp<ConsumerListener>& consumerListener): |
|
1251 mConsumerListener(consumerListener) {} |
|
1252 |
|
1253 GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} |
|
1254 |
|
1255 void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() { |
|
1256 sp<ConsumerListener> listener(mConsumerListener.promote()); |
|
1257 if (listener != NULL) { |
|
1258 listener->onFrameAvailable(); |
|
1259 } |
|
1260 } |
|
1261 |
|
1262 void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() { |
|
1263 sp<ConsumerListener> listener(mConsumerListener.promote()); |
|
1264 if (listener != NULL) { |
|
1265 listener->onBuffersReleased(); |
|
1266 } |
|
1267 } |
|
1268 |
|
1269 }; // namespace android |