blob: 20c4e3a28ec49ac2e3b5c25fccb7d84b935ce018 [file] [log] [blame]
Daniel Lam70e80aa2012-01-22 15:26:27 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "BufferQueue"
Daniel Lama6313992012-01-22 15:26:27 -080018//#define LOG_NDEBUG 0
Daniel Lam70e80aa2012-01-22 15:26:27 -080019
20#define GL_GLEXT_PROTOTYPES
21#define EGL_EGLEXT_PROTOTYPES
22
23#include <EGL/egl.h>
24#include <EGL/eglext.h>
25
26#include <gui/BufferQueue.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080027#include <gui/ISurfaceComposer.h>
Daniel Lam70e80aa2012-01-22 15:26:27 -080028#include <private/gui/ComposerService.h>
Daniel Lam70e80aa2012-01-22 15:26:27 -080029
30#include <utils/Log.h>
Daniel Lama6313992012-01-22 15:26:27 -080031#include <gui/SurfaceTexture.h>
Daniel Lam70e80aa2012-01-22 15:26:27 -080032
33// This compile option causes SurfaceTexture to return the buffer that is currently
34// attached to the GL texture from dequeueBuffer when no other buffers are
35// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
36// implicit cross-process synchronization to prevent the buffer from being
37// written to before the buffer has (a) been detached from the GL texture and
38// (b) all GL reads from the buffer have completed.
39#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
40#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true
41#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
42#else
43#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false
44#endif
45
46// Macros for including the BufferQueue name in log messages
Daniel Lama6313992012-01-22 15:26:27 -080047#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
48#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
49#define ST_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
50#define ST_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
51#define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
Daniel Lam70e80aa2012-01-22 15:26:27 -080052
53namespace android {
54
55// Get an ID that's unique within this process.
56static int32_t createProcessUniqueId() {
57 static volatile int32_t globalCounter = 0;
58 return android_atomic_inc(&globalCounter);
59}
60
61BufferQueue::BufferQueue( bool allowSynchronousMode ) :
62 mDefaultWidth(1),
63 mDefaultHeight(1),
64 mPixelFormat(PIXEL_FORMAT_RGBA_8888),
65 mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
66 mClientBufferCount(0),
67 mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
Daniel Lam70e80aa2012-01-22 15:26:27 -080068 mNextTransform(0),
69 mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
70 mSynchronousMode(false),
71 mAllowSynchronousMode(allowSynchronousMode),
72 mConnectedApi(NO_CONNECTED_API),
73 mAbandoned(false),
Daniel Lama6313992012-01-22 15:26:27 -080074 mFrameCounter(0),
75 mBufferHasBeenQueued(false)
Daniel Lam70e80aa2012-01-22 15:26:27 -080076{
77 // Choose a name using the PID and a process-unique ID.
Daniel Lama6313992012-01-22 15:26:27 -080078 mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
Daniel Lam70e80aa2012-01-22 15:26:27 -080079
80 ST_LOGV("BufferQueue");
81 sp<ISurfaceComposer> composer(ComposerService::getComposerService());
82 mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
83 mNextCrop.makeInvalid();
84}
85
86BufferQueue::~BufferQueue() {
87 ST_LOGV("~BufferQueue");
88}
89
90status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
91 if (bufferCount > NUM_BUFFER_SLOTS)
92 return BAD_VALUE;
93
94 // special-case, nothing to do
95 if (bufferCount == mBufferCount)
96 return OK;
97
98 if (!mClientBufferCount &&
99 bufferCount >= mBufferCount) {
100 // easy, we just have more buffers
101 mBufferCount = bufferCount;
102 mServerBufferCount = bufferCount;
103 mDequeueCondition.signal();
104 } else {
105 // we're here because we're either
106 // - reducing the number of available buffers
107 // - or there is a client-buffer-count in effect
108
109 // less than 2 buffers is never allowed
110 if (bufferCount < 2)
111 return BAD_VALUE;
112
113 // when there is non client-buffer-count in effect, the client is not
114 // allowed to dequeue more than one buffer at a time,
115 // so the next time they dequeue a buffer, we know that they don't
116 // own one. the actual resizing will happen during the next
117 // dequeueBuffer.
118
119 mServerBufferCount = bufferCount;
120 }
121 return OK;
122}
123
Daniel Lama6313992012-01-22 15:26:27 -0800124bool BufferQueue::isSynchronousMode() const {
125 Mutex::Autolock lock(mMutex);
126 return mSynchronousMode;
127}
128
129void BufferQueue::setConsumerName(const String8& name) {
130 Mutex::Autolock lock(mMutex);
131 mConsumerName = name;
132}
133
134void BufferQueue::setFrameAvailableListener(
135 const sp<FrameAvailableListener>& listener) {
136 ST_LOGV("setFrameAvailableListener");
137 Mutex::Autolock lock(mMutex);
138 mFrameAvailableListener = listener;
139}
140
Daniel Lam70e80aa2012-01-22 15:26:27 -0800141status_t BufferQueue::setBufferCount(int bufferCount) {
142 ST_LOGV("setBufferCount: count=%d", bufferCount);
143 Mutex::Autolock lock(mMutex);
144
145 if (mAbandoned) {
146 ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
147 return NO_INIT;
148 }
149 if (bufferCount > NUM_BUFFER_SLOTS) {
150 ST_LOGE("setBufferCount: bufferCount larger than slots available");
151 return BAD_VALUE;
152 }
153
154 // Error out if the user has dequeued buffers
155 for (int i=0 ; i<mBufferCount ; i++) {
156 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
157 ST_LOGE("setBufferCount: client owns some buffers");
158 return -EINVAL;
159 }
160 }
161
162 const int minBufferSlots = mSynchronousMode ?
163 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
164 if (bufferCount == 0) {
165 mClientBufferCount = 0;
166 bufferCount = (mServerBufferCount >= minBufferSlots) ?
167 mServerBufferCount : minBufferSlots;
168 return setBufferCountServerLocked(bufferCount);
169 }
170
171 if (bufferCount < minBufferSlots) {
172 ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
173 "minimum (%d)", bufferCount, minBufferSlots);
174 return BAD_VALUE;
175 }
176
177 // here we're guaranteed that the client doesn't have dequeued buffers
178 // and will release all of its buffer references.
179 freeAllBuffersLocked();
180 mBufferCount = bufferCount;
181 mClientBufferCount = bufferCount;
Daniel Lama6313992012-01-22 15:26:27 -0800182 mBufferHasBeenQueued = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800183 mQueue.clear();
184 mDequeueCondition.signal();
185 return OK;
186}
187
Daniel Lamf7c761e2012-01-30 15:51:27 -0800188int BufferQueue::query(int what, int* outValue)
189{
190 Mutex::Autolock lock(mMutex);
191
192 if (mAbandoned) {
193 ST_LOGE("query: SurfaceTexture has been abandoned!");
194 return NO_INIT;
195 }
196
197 int value;
198 switch (what) {
199 case NATIVE_WINDOW_WIDTH:
200 value = mDefaultWidth;
201 break;
202 case NATIVE_WINDOW_HEIGHT:
203 value = mDefaultHeight;
204 break;
205 case NATIVE_WINDOW_FORMAT:
206 value = mPixelFormat;
207 break;
208 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
209 value = mSynchronousMode ?
210 (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
211 break;
212 default:
213 return BAD_VALUE;
214 }
215 outValue[0] = value;
216 return NO_ERROR;
217}
218
Daniel Lam70e80aa2012-01-22 15:26:27 -0800219status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
220 ST_LOGV("requestBuffer: slot=%d", slot);
221 Mutex::Autolock lock(mMutex);
222 if (mAbandoned) {
223 ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
224 return NO_INIT;
225 }
226 if (slot < 0 || mBufferCount <= slot) {
227 ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
228 mBufferCount, slot);
229 return BAD_VALUE;
230 }
231 mSlots[slot].mRequestBufferCalled = true;
232 *buf = mSlots[slot].mGraphicBuffer;
233 return NO_ERROR;
234}
235
236status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
237 uint32_t format, uint32_t usage) {
238 ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
239
240 if ((w && !h) || (!w && h)) {
241 ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
242 return BAD_VALUE;
243 }
244
245 status_t returnFlags(OK);
246 EGLDisplay dpy = EGL_NO_DISPLAY;
247 EGLSyncKHR fence = EGL_NO_SYNC_KHR;
248
249 { // Scope for the lock
250 Mutex::Autolock lock(mMutex);
251
252 int found = -1;
253 int foundSync = -1;
254 int dequeuedCount = 0;
255 bool tryAgain = true;
256 while (tryAgain) {
257 if (mAbandoned) {
258 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
259 return NO_INIT;
260 }
261
262 // We need to wait for the FIFO to drain if the number of buffer
263 // needs to change.
264 //
265 // The condition "number of buffers needs to change" is true if
266 // - the client doesn't care about how many buffers there are
267 // - AND the actual number of buffer is different from what was
268 // set in the last setBufferCountServer()
269 // - OR -
270 // setBufferCountServer() was set to a value incompatible with
271 // the synchronization mode (for instance because the sync mode
272 // changed since)
273 //
274 // As long as this condition is true AND the FIFO is not empty, we
275 // wait on mDequeueCondition.
276
277 const int minBufferCountNeeded = mSynchronousMode ?
278 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
279
280 const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
281 ((mServerBufferCount != mBufferCount) ||
282 (mServerBufferCount < minBufferCountNeeded));
283
284 if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
285 // wait for the FIFO to drain
286 mDequeueCondition.wait(mMutex);
287 // NOTE: we continue here because we need to reevaluate our
288 // whole state (eg: we could be abandoned or disconnected)
289 continue;
290 }
291
292 if (numberOfBuffersNeedsToChange) {
293 // here we're guaranteed that mQueue is empty
294 freeAllBuffersLocked();
295 mBufferCount = mServerBufferCount;
296 if (mBufferCount < minBufferCountNeeded)
297 mBufferCount = minBufferCountNeeded;
Daniel Lama6313992012-01-22 15:26:27 -0800298 mBufferHasBeenQueued = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800299 returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
300 }
301
302 // look for a free buffer to give to the client
303 found = INVALID_BUFFER_SLOT;
304 foundSync = INVALID_BUFFER_SLOT;
305 dequeuedCount = 0;
306 for (int i = 0; i < mBufferCount; i++) {
307 const int state = mSlots[i].mBufferState;
308 if (state == BufferSlot::DEQUEUED) {
309 dequeuedCount++;
310 }
311
Daniel Lam70e80aa2012-01-22 15:26:27 -0800312 if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
Daniel Lama6313992012-01-22 15:26:27 -0800313 // This functionality has been temporarily removed so
314 // BufferQueue and SurfaceTexture can be refactored into
315 // separate objects
Daniel Lam70e80aa2012-01-22 15:26:27 -0800316 } else {
317 if (state == BufferSlot::FREE) {
318 /* We return the oldest of the free buffers to avoid
319 * stalling the producer if possible. This is because
320 * the consumer may still have pending reads of the
321 * buffers in flight.
322 */
323 bool isOlder = mSlots[i].mFrameNumber <
324 mSlots[found].mFrameNumber;
325 if (found < 0 || isOlder) {
326 foundSync = i;
327 found = i;
328 }
329 }
330 }
331 }
332
333 // clients are not allowed to dequeue more than one buffer
334 // if they didn't set a buffer count.
335 if (!mClientBufferCount && dequeuedCount) {
336 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
337 "setting the buffer count");
338 return -EINVAL;
339 }
340
341 // See whether a buffer has been queued since the last
342 // setBufferCount so we know whether to perform the
343 // MIN_UNDEQUEUED_BUFFERS check below.
Daniel Lama6313992012-01-22 15:26:27 -0800344 if (mBufferHasBeenQueued) {
Daniel Lam70e80aa2012-01-22 15:26:27 -0800345 // make sure the client is not trying to dequeue more buffers
346 // than allowed.
347 const int avail = mBufferCount - (dequeuedCount+1);
348 if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
349 ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
350 "(dequeued=%d)",
351 MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
352 dequeuedCount);
353 return -EBUSY;
354 }
355 }
356
357 // we're in synchronous mode and didn't find a buffer, we need to
358 // wait for some buffers to be consumed
359 tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
360 if (tryAgain) {
361 mDequeueCondition.wait(mMutex);
362 }
363 }
364
365 if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
366 // foundSync guaranteed to be != INVALID_BUFFER_SLOT
367 found = foundSync;
368 }
369
370 if (found == INVALID_BUFFER_SLOT) {
371 // This should not happen.
372 ST_LOGE("dequeueBuffer: no available buffer slots");
373 return -EBUSY;
374 }
375
376 const int buf = found;
377 *outBuf = found;
378
379 const bool useDefaultSize = !w && !h;
380 if (useDefaultSize) {
381 // use the default size
382 w = mDefaultWidth;
383 h = mDefaultHeight;
384 }
385
386 const bool updateFormat = (format != 0);
387 if (!updateFormat) {
388 // keep the current (or default) format
389 format = mPixelFormat;
390 }
391
392 // buffer is now in DEQUEUED (but can also be current at the same time,
393 // if we're in synchronous mode)
394 mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
395
396 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
397 if ((buffer == NULL) ||
398 (uint32_t(buffer->width) != w) ||
399 (uint32_t(buffer->height) != h) ||
400 (uint32_t(buffer->format) != format) ||
401 ((uint32_t(buffer->usage) & usage) != usage))
402 {
403 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
404 status_t error;
405 sp<GraphicBuffer> graphicBuffer(
406 mGraphicBufferAlloc->createGraphicBuffer(
407 w, h, format, usage, &error));
408 if (graphicBuffer == 0) {
409 ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
410 "failed");
411 return error;
412 }
413 if (updateFormat) {
414 mPixelFormat = format;
415 }
Daniel Lama6313992012-01-22 15:26:27 -0800416
417 mSlots[buf].mAcquireCalled = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800418 mSlots[buf].mGraphicBuffer = graphicBuffer;
419 mSlots[buf].mRequestBufferCalled = false;
420 mSlots[buf].mFence = EGL_NO_SYNC_KHR;
Daniel Lama6313992012-01-22 15:26:27 -0800421 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
422
423
424
425
Daniel Lam70e80aa2012-01-22 15:26:27 -0800426 returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
427 }
428
429 dpy = mSlots[buf].mEglDisplay;
430 fence = mSlots[buf].mFence;
431 mSlots[buf].mFence = EGL_NO_SYNC_KHR;
Daniel Lama6313992012-01-22 15:26:27 -0800432 } // end lock scope
Daniel Lam70e80aa2012-01-22 15:26:27 -0800433
434 if (fence != EGL_NO_SYNC_KHR) {
435 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
436 // If something goes wrong, log the error, but return the buffer without
437 // synchronizing access to it. It's too late at this point to abort the
438 // dequeue operation.
439 if (result == EGL_FALSE) {
440 ALOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
441 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
442 ALOGE("dequeueBuffer: timeout waiting for fence");
443 }
444 eglDestroySyncKHR(dpy, fence);
Daniel Lama6313992012-01-22 15:26:27 -0800445
Daniel Lam70e80aa2012-01-22 15:26:27 -0800446 }
447
448 ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
449 mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
450
451 return returnFlags;
452}
453
454status_t BufferQueue::setSynchronousMode(bool enabled) {
455 ST_LOGV("setSynchronousMode: enabled=%d", enabled);
456 Mutex::Autolock lock(mMutex);
457
458 if (mAbandoned) {
459 ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
460 return NO_INIT;
461 }
462
463 status_t err = OK;
464 if (!mAllowSynchronousMode && enabled)
465 return err;
466
467 if (!enabled) {
468 // going to asynchronous mode, drain the queue
469 err = drainQueueLocked();
470 if (err != NO_ERROR)
471 return err;
472 }
473
474 if (mSynchronousMode != enabled) {
475 // - if we're going to asynchronous mode, the queue is guaranteed to be
476 // empty here
477 // - if the client set the number of buffers, we're guaranteed that
478 // we have at least 3 (because we don't allow less)
479 mSynchronousMode = enabled;
480 mDequeueCondition.signal();
481 }
482 return err;
483}
484
485status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
486 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
487 ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
488
489 sp<FrameAvailableListener> listener;
490
491 { // scope for the lock
492 Mutex::Autolock lock(mMutex);
493 if (mAbandoned) {
494 ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
495 return NO_INIT;
496 }
497 if (buf < 0 || buf >= mBufferCount) {
498 ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
499 mBufferCount, buf);
500 return -EINVAL;
501 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
502 ST_LOGE("queueBuffer: slot %d is not owned by the client "
503 "(state=%d)", buf, mSlots[buf].mBufferState);
504 return -EINVAL;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800505 } else if (!mSlots[buf].mRequestBufferCalled) {
506 ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
507 "buffer", buf);
508 return -EINVAL;
509 }
510
511 if (mSynchronousMode) {
512 // In synchronous mode we queue all buffers in a FIFO.
513 mQueue.push_back(buf);
514
515 // Synchronous mode always signals that an additional frame should
516 // be consumed.
517 listener = mFrameAvailableListener;
518 } else {
519 // In asynchronous mode we only keep the most recent buffer.
520 if (mQueue.empty()) {
521 mQueue.push_back(buf);
522
523 // Asynchronous mode only signals that a frame should be
524 // consumed if no previous frame was pending. If a frame were
525 // pending then the consumer would have already been notified.
526 listener = mFrameAvailableListener;
527 } else {
528 Fifo::iterator front(mQueue.begin());
529 // buffer currently queued is freed
530 mSlots[*front].mBufferState = BufferSlot::FREE;
531 // and we record the new buffer index in the queued list
532 *front = buf;
533 }
534 }
535
536 mSlots[buf].mBufferState = BufferSlot::QUEUED;
537 mSlots[buf].mCrop = mNextCrop;
538 mSlots[buf].mTransform = mNextTransform;
539 mSlots[buf].mScalingMode = mNextScalingMode;
540 mSlots[buf].mTimestamp = timestamp;
541 mFrameCounter++;
542 mSlots[buf].mFrameNumber = mFrameCounter;
543
Daniel Lama6313992012-01-22 15:26:27 -0800544 mBufferHasBeenQueued = true;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800545 mDequeueCondition.signal();
546
547 *outWidth = mDefaultWidth;
548 *outHeight = mDefaultHeight;
549 *outTransform = 0;
550 } // scope for the lock
551
552 // call back without lock held
553 if (listener != 0) {
554 listener->onFrameAvailable();
555 }
556 return OK;
557}
558
559void BufferQueue::cancelBuffer(int buf) {
560 ST_LOGV("cancelBuffer: slot=%d", buf);
561 Mutex::Autolock lock(mMutex);
562
563 if (mAbandoned) {
564 ST_LOGW("cancelBuffer: BufferQueue has been abandoned!");
565 return;
566 }
567
568 if (buf < 0 || buf >= mBufferCount) {
569 ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
570 mBufferCount, buf);
571 return;
572 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
573 ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
574 buf, mSlots[buf].mBufferState);
575 return;
576 }
577 mSlots[buf].mBufferState = BufferSlot::FREE;
578 mSlots[buf].mFrameNumber = 0;
579 mDequeueCondition.signal();
580}
581
582status_t BufferQueue::setCrop(const Rect& crop) {
583 ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
584 crop.bottom);
585
586 Mutex::Autolock lock(mMutex);
587 if (mAbandoned) {
588 ST_LOGE("setCrop: BufferQueue has been abandoned!");
589 return NO_INIT;
590 }
591 mNextCrop = crop;
592 return OK;
593}
594
595status_t BufferQueue::setTransform(uint32_t transform) {
596 ST_LOGV("setTransform: xform=%#x", transform);
597 Mutex::Autolock lock(mMutex);
598 if (mAbandoned) {
599 ST_LOGE("setTransform: BufferQueue has been abandoned!");
600 return NO_INIT;
601 }
602 mNextTransform = transform;
603 return OK;
604}
605
606status_t BufferQueue::setScalingMode(int mode) {
607 ST_LOGV("setScalingMode: mode=%d", mode);
608
609 switch (mode) {
610 case NATIVE_WINDOW_SCALING_MODE_FREEZE:
611 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
612 break;
613 default:
614 ST_LOGE("unknown scaling mode: %d", mode);
615 return BAD_VALUE;
616 }
617
618 Mutex::Autolock lock(mMutex);
619 mNextScalingMode = mode;
620 return OK;
621}
622
623status_t BufferQueue::connect(int api,
624 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
625 ST_LOGV("connect: api=%d", api);
626 Mutex::Autolock lock(mMutex);
627
628 if (mAbandoned) {
629 ST_LOGE("connect: BufferQueue has been abandoned!");
630 return NO_INIT;
631 }
632
633 int err = NO_ERROR;
634 switch (api) {
635 case NATIVE_WINDOW_API_EGL:
636 case NATIVE_WINDOW_API_CPU:
637 case NATIVE_WINDOW_API_MEDIA:
638 case NATIVE_WINDOW_API_CAMERA:
639 if (mConnectedApi != NO_CONNECTED_API) {
640 ST_LOGE("connect: already connected (cur=%d, req=%d)",
641 mConnectedApi, api);
642 err = -EINVAL;
643 } else {
644 mConnectedApi = api;
645 *outWidth = mDefaultWidth;
646 *outHeight = mDefaultHeight;
647 *outTransform = 0;
648 }
649 break;
650 default:
651 err = -EINVAL;
652 break;
653 }
Daniel Lama6313992012-01-22 15:26:27 -0800654
655 mBufferHasBeenQueued = false;
656
Daniel Lam70e80aa2012-01-22 15:26:27 -0800657 return err;
658}
659
660status_t BufferQueue::disconnect(int api) {
661 ST_LOGV("disconnect: api=%d", api);
662 Mutex::Autolock lock(mMutex);
663
664 if (mAbandoned) {
665 // it is not really an error to disconnect after the surface
666 // has been abandoned, it should just be a no-op.
667 return NO_ERROR;
668 }
669
670 int err = NO_ERROR;
671 switch (api) {
672 case NATIVE_WINDOW_API_EGL:
673 case NATIVE_WINDOW_API_CPU:
674 case NATIVE_WINDOW_API_MEDIA:
675 case NATIVE_WINDOW_API_CAMERA:
676 if (mConnectedApi == api) {
677 drainQueueAndFreeBuffersLocked();
678 mConnectedApi = NO_CONNECTED_API;
679 mNextCrop.makeInvalid();
680 mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
681 mNextTransform = 0;
682 mDequeueCondition.signal();
683 } else {
684 ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
685 mConnectedApi, api);
686 err = -EINVAL;
687 }
688 break;
689 default:
690 ST_LOGE("disconnect: unknown API %d", api);
691 err = -EINVAL;
692 break;
693 }
694 return err;
695}
696
Daniel Lama6313992012-01-22 15:26:27 -0800697void BufferQueue::dump(String8& result) const
698{
699 char buffer[1024];
700 BufferQueue::dump(result, "", buffer, 1024);
701}
702
703void BufferQueue::dump(String8& result, const char* prefix,
704 char* buffer, size_t SIZE) const
705{
706 Mutex::Autolock _l(mMutex);
707 snprintf(buffer, SIZE,
708 "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x}\n"
709 ,prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right,
710 mNextCrop.bottom, mNextTransform
711 );
712 result.append(buffer);
713
714 String8 fifo;
715 int fifoSize = 0;
716 Fifo::const_iterator i(mQueue.begin());
717 while (i != mQueue.end()) {
718 snprintf(buffer, SIZE, "%02d ", *i++);
719 fifoSize++;
720 fifo.append(buffer);
721 }
722
723 snprintf(buffer, SIZE,
724 "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
725 "mPixelFormat=%d, FIFO(%d)={%s}\n",
726 prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
727 mDefaultHeight, mPixelFormat, fifoSize, fifo.string());
728 result.append(buffer);
729
730
731 struct {
732 const char * operator()(int state) const {
733 switch (state) {
734 case BufferSlot::DEQUEUED: return "DEQUEUED";
735 case BufferSlot::QUEUED: return "QUEUED";
736 case BufferSlot::FREE: return "FREE";
737 case BufferSlot::ACQUIRED: return "ACQUIRED";
738 default: return "Unknown";
739 }
740 }
741 } stateName;
742
743 for (int i=0 ; i<mBufferCount ; i++) {
744 const BufferSlot& slot(mSlots[i]);
745 snprintf(buffer, SIZE,
746 "%s%s[%02d] "
747 "state=%-8s, crop=[%d,%d,%d,%d], "
748 "transform=0x%02x, timestamp=%lld",
749 prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i,
750 stateName(slot.mBufferState),
751 slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
752 slot.mCrop.bottom, slot.mTransform, slot.mTimestamp
753 );
754 result.append(buffer);
755
756 const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
757 if (buf != NULL) {
758 snprintf(buffer, SIZE,
759 ", %p [%4ux%4u:%4u,%3X]",
760 buf->handle, buf->width, buf->height, buf->stride,
761 buf->format);
762 result.append(buffer);
763 }
764 result.append("\n");
765 }
766}
767
Daniel Lam70e80aa2012-01-22 15:26:27 -0800768void BufferQueue::freeBufferLocked(int i) {
769 mSlots[i].mGraphicBuffer = 0;
770 mSlots[i].mBufferState = BufferSlot::FREE;
771 mSlots[i].mFrameNumber = 0;
Daniel Lama6313992012-01-22 15:26:27 -0800772 mSlots[i].mAcquireCalled = false;
773
774 // destroy fence as BufferQueue now takes ownership
775 if (mSlots[i].mFence != EGL_NO_SYNC_KHR) {
776 eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
777 mSlots[i].mFence = EGL_NO_SYNC_KHR;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800778 }
779}
780
781void BufferQueue::freeAllBuffersLocked() {
782 ALOGW_IF(!mQueue.isEmpty(),
783 "freeAllBuffersLocked called but mQueue is not empty");
Daniel Lama6313992012-01-22 15:26:27 -0800784 mQueue.clear();
785 mBufferHasBeenQueued = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800786 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
787 freeBufferLocked(i);
788 }
789}
790
Daniel Lama6313992012-01-22 15:26:27 -0800791status_t BufferQueue::acquire(BufferItem *buffer) {
792 Mutex::Autolock _l(mMutex);
793 // check if queue is empty
794 // In asynchronous mode the list is guaranteed to be one buffer
795 // deep, while in synchronous mode we use the oldest buffer.
796 if (!mQueue.empty()) {
797 Fifo::iterator front(mQueue.begin());
798 int buf = *front;
799
800 if (mSlots[buf].mAcquireCalled) {
801 buffer->mGraphicBuffer = NULL;
802 }
803 else {
804 buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
805 }
806 buffer->mCrop = mSlots[buf].mCrop;
807 buffer->mTransform = mSlots[buf].mTransform;
808 buffer->mScalingMode = mSlots[buf].mScalingMode;
809 buffer->mFrameNumber = mSlots[buf].mFrameNumber;
810 buffer->mBuf = buf;
811 mSlots[buf].mAcquireCalled = true;
812
813 mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
814 mQueue.erase(front);
815 }
816 else {
817 return -EINVAL; //should be a better return code
818 }
819
820 return OK;
821}
822
823status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
824 EGLSyncKHR fence) {
825 Mutex::Autolock _l(mMutex);
826
827 if (buf == INVALID_BUFFER_SLOT) {
828 return -EINVAL;
829 }
830
831 mSlots[buf].mEglDisplay = display;
832 mSlots[buf].mFence = fence;
833
834 // The current buffer becomes FREE if it was still in the queued
835 // state. If it has already been given to the client
836 // (synchronous mode), then it stays in DEQUEUED state.
837 if (mSlots[buf].mBufferState == BufferSlot::QUEUED
838 || mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
839 mSlots[buf].mBufferState = BufferSlot::FREE;
840 }
841 mDequeueCondition.signal();
842
843 return OK;
844}
845
846status_t BufferQueue::consumerDisconnect() {
847 Mutex::Autolock lock(mMutex);
848 // Once the SurfaceTexture disconnects, the BufferQueue
849 // is considered abandoned
850 mAbandoned = true;
851 freeAllBuffersLocked();
852 mDequeueCondition.signal();
853 return OK;
854}
855
856status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
857{
858 ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
859 if (!w || !h) {
860 ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
861 w, h);
862 return BAD_VALUE;
863 }
864
865 Mutex::Autolock lock(mMutex);
866 mDefaultWidth = w;
867 mDefaultHeight = h;
868 return OK;
869}
870
871status_t BufferQueue::setBufferCountServer(int bufferCount) {
872 Mutex::Autolock lock(mMutex);
873 return setBufferCountServerLocked(bufferCount);
874}
875
Daniel Lam70e80aa2012-01-22 15:26:27 -0800876void BufferQueue::freeAllBuffersExceptHeadLocked() {
877 ALOGW_IF(!mQueue.isEmpty(),
878 "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
879 int head = -1;
880 if (!mQueue.empty()) {
881 Fifo::iterator front(mQueue.begin());
882 head = *front;
883 }
Daniel Lama6313992012-01-22 15:26:27 -0800884 mBufferHasBeenQueued = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800885 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
886 if (i != head) {
887 freeBufferLocked(i);
888 }
889 }
890}
891
892status_t BufferQueue::drainQueueLocked() {
893 while (mSynchronousMode && !mQueue.isEmpty()) {
894 mDequeueCondition.wait(mMutex);
895 if (mAbandoned) {
896 ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
897 return NO_INIT;
898 }
899 if (mConnectedApi == NO_CONNECTED_API) {
900 ST_LOGE("drainQueueLocked: BufferQueue is not connected!");
901 return NO_INIT;
902 }
903 }
904 return NO_ERROR;
905}
906
907status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
908 status_t err = drainQueueLocked();
909 if (err == NO_ERROR) {
910 if (mSynchronousMode) {
911 freeAllBuffersLocked();
912 } else {
913 freeAllBuffersExceptHeadLocked();
914 }
915 }
916 return err;
917}
918
919}; // namespace android