blob: 7d641057a8e5b4db692abc4df22946e56a604938 [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 Lam6f15cc92012-01-22 15:26:27 -080018//#define LOG_NDEBUG 0
Jamie Gennisa85ca372012-02-23 19:27:23 -080019#define ATRACE_TAG ATRACE_TAG_GRAPHICS
Daniel Lam70e80aa2012-01-22 15:26:27 -080020
21#define GL_GLEXT_PROTOTYPES
22#define EGL_EGLEXT_PROTOTYPES
23
24#include <EGL/egl.h>
25#include <EGL/eglext.h>
26
27#include <gui/BufferQueue.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080028#include <gui/ISurfaceComposer.h>
Daniel Lam70e80aa2012-01-22 15:26:27 -080029#include <private/gui/ComposerService.h>
Daniel Lam70e80aa2012-01-22 15:26:27 -080030
31#include <utils/Log.h>
Daniel Lam6f15cc92012-01-22 15:26:27 -080032#include <gui/SurfaceTexture.h>
Jamie Gennisa85ca372012-02-23 19:27:23 -080033#include <utils/Trace.h>
Daniel Lam70e80aa2012-01-22 15:26:27 -080034
35// This compile option causes SurfaceTexture to return the buffer that is currently
36// attached to the GL texture from dequeueBuffer when no other buffers are
37// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
38// implicit cross-process synchronization to prevent the buffer from being
39// written to before the buffer has (a) been detached from the GL texture and
40// (b) all GL reads from the buffer have completed.
Daniel Lam6f15cc92012-01-22 15:26:27 -080041
42// During refactoring, do not support dequeuing the current buffer
43#undef ALLOW_DEQUEUE_CURRENT_BUFFER
44
Daniel Lam70e80aa2012-01-22 15:26:27 -080045#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
46#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true
47#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
48#else
49#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false
50#endif
51
52// Macros for including the BufferQueue name in log messages
Daniel Lam6f15cc92012-01-22 15:26:27 -080053#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
54#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
55#define ST_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
56#define ST_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
57#define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
Daniel Lam70e80aa2012-01-22 15:26:27 -080058
Mathias Agopiand1220b92012-03-01 22:11:25 -080059#define ATRACE_BUFFER_INDEX(index) \
60 char ___traceBuf[1024]; \
61 snprintf(___traceBuf, 1024, "%s: %d", mConsumerName.string(), (index)); \
62 android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);
63
Daniel Lam70e80aa2012-01-22 15:26:27 -080064namespace android {
65
66// Get an ID that's unique within this process.
67static int32_t createProcessUniqueId() {
68 static volatile int32_t globalCounter = 0;
69 return android_atomic_inc(&globalCounter);
70}
71
72BufferQueue::BufferQueue( bool allowSynchronousMode ) :
73 mDefaultWidth(1),
74 mDefaultHeight(1),
75 mPixelFormat(PIXEL_FORMAT_RGBA_8888),
76 mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
77 mClientBufferCount(0),
78 mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
Daniel Lam70e80aa2012-01-22 15:26:27 -080079 mNextTransform(0),
80 mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
81 mSynchronousMode(false),
82 mAllowSynchronousMode(allowSynchronousMode),
83 mConnectedApi(NO_CONNECTED_API),
84 mAbandoned(false),
Daniel Lam6f15cc92012-01-22 15:26:27 -080085 mFrameCounter(0),
86 mBufferHasBeenQueued(false)
Daniel Lam70e80aa2012-01-22 15:26:27 -080087{
88 // Choose a name using the PID and a process-unique ID.
Daniel Lam6f15cc92012-01-22 15:26:27 -080089 mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
Daniel Lam70e80aa2012-01-22 15:26:27 -080090
91 ST_LOGV("BufferQueue");
92 sp<ISurfaceComposer> composer(ComposerService::getComposerService());
93 mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
94 mNextCrop.makeInvalid();
95}
96
97BufferQueue::~BufferQueue() {
98 ST_LOGV("~BufferQueue");
99}
100
101status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
102 if (bufferCount > NUM_BUFFER_SLOTS)
103 return BAD_VALUE;
104
105 // special-case, nothing to do
106 if (bufferCount == mBufferCount)
107 return OK;
108
109 if (!mClientBufferCount &&
110 bufferCount >= mBufferCount) {
111 // easy, we just have more buffers
112 mBufferCount = bufferCount;
113 mServerBufferCount = bufferCount;
Mathias Agopian3e964c52012-03-06 18:26:54 -0800114 mDequeueCondition.broadcast();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800115 } else {
116 // we're here because we're either
117 // - reducing the number of available buffers
118 // - or there is a client-buffer-count in effect
119
120 // less than 2 buffers is never allowed
121 if (bufferCount < 2)
122 return BAD_VALUE;
123
124 // when there is non client-buffer-count in effect, the client is not
125 // allowed to dequeue more than one buffer at a time,
126 // so the next time they dequeue a buffer, we know that they don't
127 // own one. the actual resizing will happen during the next
128 // dequeueBuffer.
129
130 mServerBufferCount = bufferCount;
131 }
132 return OK;
133}
134
Daniel Lam6f15cc92012-01-22 15:26:27 -0800135bool BufferQueue::isSynchronousMode() const {
136 Mutex::Autolock lock(mMutex);
137 return mSynchronousMode;
138}
139
140void BufferQueue::setConsumerName(const String8& name) {
141 Mutex::Autolock lock(mMutex);
142 mConsumerName = name;
143}
144
145void BufferQueue::setFrameAvailableListener(
146 const sp<FrameAvailableListener>& listener) {
147 ST_LOGV("setFrameAvailableListener");
148 Mutex::Autolock lock(mMutex);
149 mFrameAvailableListener = listener;
150}
151
Daniel Lam70e80aa2012-01-22 15:26:27 -0800152status_t BufferQueue::setBufferCount(int bufferCount) {
153 ST_LOGV("setBufferCount: count=%d", bufferCount);
154 Mutex::Autolock lock(mMutex);
155
156 if (mAbandoned) {
157 ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
158 return NO_INIT;
159 }
160 if (bufferCount > NUM_BUFFER_SLOTS) {
161 ST_LOGE("setBufferCount: bufferCount larger than slots available");
162 return BAD_VALUE;
163 }
164
165 // Error out if the user has dequeued buffers
166 for (int i=0 ; i<mBufferCount ; i++) {
167 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
168 ST_LOGE("setBufferCount: client owns some buffers");
169 return -EINVAL;
170 }
171 }
172
173 const int minBufferSlots = mSynchronousMode ?
174 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
175 if (bufferCount == 0) {
176 mClientBufferCount = 0;
177 bufferCount = (mServerBufferCount >= minBufferSlots) ?
178 mServerBufferCount : minBufferSlots;
179 return setBufferCountServerLocked(bufferCount);
180 }
181
182 if (bufferCount < minBufferSlots) {
183 ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
184 "minimum (%d)", bufferCount, minBufferSlots);
185 return BAD_VALUE;
186 }
187
188 // here we're guaranteed that the client doesn't have dequeued buffers
189 // and will release all of its buffer references.
190 freeAllBuffersLocked();
191 mBufferCount = bufferCount;
192 mClientBufferCount = bufferCount;
Daniel Lam6f15cc92012-01-22 15:26:27 -0800193 mBufferHasBeenQueued = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800194 mQueue.clear();
Mathias Agopian3e964c52012-03-06 18:26:54 -0800195 mDequeueCondition.broadcast();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800196 return OK;
197}
198
Daniel Lamf7c761e2012-01-30 15:51:27 -0800199int BufferQueue::query(int what, int* outValue)
200{
Jamie Gennisa85ca372012-02-23 19:27:23 -0800201 ATRACE_CALL();
Daniel Lamf7c761e2012-01-30 15:51:27 -0800202 Mutex::Autolock lock(mMutex);
203
204 if (mAbandoned) {
205 ST_LOGE("query: SurfaceTexture has been abandoned!");
206 return NO_INIT;
207 }
208
209 int value;
210 switch (what) {
211 case NATIVE_WINDOW_WIDTH:
212 value = mDefaultWidth;
213 break;
214 case NATIVE_WINDOW_HEIGHT:
215 value = mDefaultHeight;
216 break;
217 case NATIVE_WINDOW_FORMAT:
218 value = mPixelFormat;
219 break;
220 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
221 value = mSynchronousMode ?
222 (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
223 break;
224 default:
225 return BAD_VALUE;
226 }
227 outValue[0] = value;
228 return NO_ERROR;
229}
230
Daniel Lam70e80aa2012-01-22 15:26:27 -0800231status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800232 ATRACE_CALL();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800233 ST_LOGV("requestBuffer: slot=%d", slot);
234 Mutex::Autolock lock(mMutex);
235 if (mAbandoned) {
236 ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
237 return NO_INIT;
238 }
239 if (slot < 0 || mBufferCount <= slot) {
240 ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
241 mBufferCount, slot);
242 return BAD_VALUE;
243 }
244 mSlots[slot].mRequestBufferCalled = true;
245 *buf = mSlots[slot].mGraphicBuffer;
246 return NO_ERROR;
247}
248
249status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
250 uint32_t format, uint32_t usage) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800251 ATRACE_CALL();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800252 ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
253
254 if ((w && !h) || (!w && h)) {
255 ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
256 return BAD_VALUE;
257 }
258
259 status_t returnFlags(OK);
260 EGLDisplay dpy = EGL_NO_DISPLAY;
261 EGLSyncKHR fence = EGL_NO_SYNC_KHR;
262
263 { // Scope for the lock
264 Mutex::Autolock lock(mMutex);
265
266 int found = -1;
267 int foundSync = -1;
268 int dequeuedCount = 0;
269 bool tryAgain = true;
270 while (tryAgain) {
271 if (mAbandoned) {
272 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
273 return NO_INIT;
274 }
275
276 // We need to wait for the FIFO to drain if the number of buffer
277 // needs to change.
278 //
279 // The condition "number of buffers needs to change" is true if
280 // - the client doesn't care about how many buffers there are
281 // - AND the actual number of buffer is different from what was
282 // set in the last setBufferCountServer()
283 // - OR -
284 // setBufferCountServer() was set to a value incompatible with
285 // the synchronization mode (for instance because the sync mode
286 // changed since)
287 //
288 // As long as this condition is true AND the FIFO is not empty, we
289 // wait on mDequeueCondition.
290
291 const int minBufferCountNeeded = mSynchronousMode ?
292 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
293
294 const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
295 ((mServerBufferCount != mBufferCount) ||
296 (mServerBufferCount < minBufferCountNeeded));
297
298 if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
299 // wait for the FIFO to drain
300 mDequeueCondition.wait(mMutex);
301 // NOTE: we continue here because we need to reevaluate our
302 // whole state (eg: we could be abandoned or disconnected)
303 continue;
304 }
305
306 if (numberOfBuffersNeedsToChange) {
307 // here we're guaranteed that mQueue is empty
308 freeAllBuffersLocked();
Mathias Agopian3e964c52012-03-06 18:26:54 -0800309 // XXX: signal?
Daniel Lam70e80aa2012-01-22 15:26:27 -0800310 mBufferCount = mServerBufferCount;
311 if (mBufferCount < minBufferCountNeeded)
312 mBufferCount = minBufferCountNeeded;
Daniel Lam6f15cc92012-01-22 15:26:27 -0800313 mBufferHasBeenQueued = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800314 returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
315 }
316
317 // look for a free buffer to give to the client
318 found = INVALID_BUFFER_SLOT;
319 foundSync = INVALID_BUFFER_SLOT;
320 dequeuedCount = 0;
321 for (int i = 0; i < mBufferCount; i++) {
322 const int state = mSlots[i].mBufferState;
323 if (state == BufferSlot::DEQUEUED) {
324 dequeuedCount++;
325 }
326
Daniel Lam6f15cc92012-01-22 15:26:27 -0800327 // this logic used to be if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER)
328 // but dequeuing the current buffer is disabled.
329 if (false) {
330 // This functionality has been temporarily removed so
331 // BufferQueue and SurfaceTexture can be refactored into
332 // separate objects
Daniel Lam70e80aa2012-01-22 15:26:27 -0800333 } else {
334 if (state == BufferSlot::FREE) {
335 /* We return the oldest of the free buffers to avoid
336 * stalling the producer if possible. This is because
337 * the consumer may still have pending reads of the
338 * buffers in flight.
339 */
340 bool isOlder = mSlots[i].mFrameNumber <
341 mSlots[found].mFrameNumber;
342 if (found < 0 || isOlder) {
343 foundSync = i;
344 found = i;
345 }
346 }
347 }
348 }
349
350 // clients are not allowed to dequeue more than one buffer
351 // if they didn't set a buffer count.
352 if (!mClientBufferCount && dequeuedCount) {
353 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
354 "setting the buffer count");
355 return -EINVAL;
356 }
357
358 // See whether a buffer has been queued since the last
359 // setBufferCount so we know whether to perform the
360 // MIN_UNDEQUEUED_BUFFERS check below.
Daniel Lam6f15cc92012-01-22 15:26:27 -0800361 if (mBufferHasBeenQueued) {
Daniel Lam70e80aa2012-01-22 15:26:27 -0800362 // make sure the client is not trying to dequeue more buffers
363 // than allowed.
364 const int avail = mBufferCount - (dequeuedCount+1);
365 if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
366 ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
367 "(dequeued=%d)",
368 MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
369 dequeuedCount);
370 return -EBUSY;
371 }
372 }
373
374 // we're in synchronous mode and didn't find a buffer, we need to
375 // wait for some buffers to be consumed
376 tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
377 if (tryAgain) {
378 mDequeueCondition.wait(mMutex);
379 }
380 }
381
382 if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
383 // foundSync guaranteed to be != INVALID_BUFFER_SLOT
384 found = foundSync;
385 }
386
387 if (found == INVALID_BUFFER_SLOT) {
388 // This should not happen.
389 ST_LOGE("dequeueBuffer: no available buffer slots");
390 return -EBUSY;
391 }
392
393 const int buf = found;
394 *outBuf = found;
395
Mathias Agopiand1220b92012-03-01 22:11:25 -0800396 ATRACE_BUFFER_INDEX(buf);
397
Daniel Lam70e80aa2012-01-22 15:26:27 -0800398 const bool useDefaultSize = !w && !h;
399 if (useDefaultSize) {
400 // use the default size
401 w = mDefaultWidth;
402 h = mDefaultHeight;
403 }
404
405 const bool updateFormat = (format != 0);
406 if (!updateFormat) {
407 // keep the current (or default) format
408 format = mPixelFormat;
409 }
410
411 // buffer is now in DEQUEUED (but can also be current at the same time,
412 // if we're in synchronous mode)
413 mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
414
415 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
416 if ((buffer == NULL) ||
417 (uint32_t(buffer->width) != w) ||
418 (uint32_t(buffer->height) != h) ||
419 (uint32_t(buffer->format) != format) ||
420 ((uint32_t(buffer->usage) & usage) != usage))
421 {
422 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
423 status_t error;
424 sp<GraphicBuffer> graphicBuffer(
425 mGraphicBufferAlloc->createGraphicBuffer(
426 w, h, format, usage, &error));
427 if (graphicBuffer == 0) {
428 ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
429 "failed");
430 return error;
431 }
432 if (updateFormat) {
433 mPixelFormat = format;
434 }
Daniel Lam6f15cc92012-01-22 15:26:27 -0800435
436 mSlots[buf].mAcquireCalled = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800437 mSlots[buf].mGraphicBuffer = graphicBuffer;
438 mSlots[buf].mRequestBufferCalled = false;
439 mSlots[buf].mFence = EGL_NO_SYNC_KHR;
Daniel Lam6f15cc92012-01-22 15:26:27 -0800440 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
441
442
443
444
Daniel Lam70e80aa2012-01-22 15:26:27 -0800445 returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
446 }
447
448 dpy = mSlots[buf].mEglDisplay;
449 fence = mSlots[buf].mFence;
450 mSlots[buf].mFence = EGL_NO_SYNC_KHR;
Daniel Lam6f15cc92012-01-22 15:26:27 -0800451 } // end lock scope
Daniel Lam70e80aa2012-01-22 15:26:27 -0800452
453 if (fence != EGL_NO_SYNC_KHR) {
454 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
455 // If something goes wrong, log the error, but return the buffer without
456 // synchronizing access to it. It's too late at this point to abort the
457 // dequeue operation.
458 if (result == EGL_FALSE) {
459 ALOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
460 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
461 ALOGE("dequeueBuffer: timeout waiting for fence");
462 }
463 eglDestroySyncKHR(dpy, fence);
Daniel Lam6f15cc92012-01-22 15:26:27 -0800464
Daniel Lam70e80aa2012-01-22 15:26:27 -0800465 }
466
467 ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
468 mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
469
470 return returnFlags;
471}
472
473status_t BufferQueue::setSynchronousMode(bool enabled) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800474 ATRACE_CALL();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800475 ST_LOGV("setSynchronousMode: enabled=%d", enabled);
476 Mutex::Autolock lock(mMutex);
477
478 if (mAbandoned) {
479 ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
480 return NO_INIT;
481 }
482
483 status_t err = OK;
484 if (!mAllowSynchronousMode && enabled)
485 return err;
486
487 if (!enabled) {
488 // going to asynchronous mode, drain the queue
489 err = drainQueueLocked();
490 if (err != NO_ERROR)
491 return err;
492 }
493
494 if (mSynchronousMode != enabled) {
495 // - if we're going to asynchronous mode, the queue is guaranteed to be
496 // empty here
497 // - if the client set the number of buffers, we're guaranteed that
498 // we have at least 3 (because we don't allow less)
499 mSynchronousMode = enabled;
Mathias Agopian3e964c52012-03-06 18:26:54 -0800500 mDequeueCondition.broadcast();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800501 }
502 return err;
503}
504
505status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
506 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800507 ATRACE_CALL();
Mathias Agopiand1220b92012-03-01 22:11:25 -0800508 ATRACE_BUFFER_INDEX(buf);
509
Daniel Lam70e80aa2012-01-22 15:26:27 -0800510 ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
511
512 sp<FrameAvailableListener> listener;
513
514 { // scope for the lock
515 Mutex::Autolock lock(mMutex);
516 if (mAbandoned) {
517 ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
518 return NO_INIT;
519 }
520 if (buf < 0 || buf >= mBufferCount) {
521 ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
522 mBufferCount, buf);
523 return -EINVAL;
524 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
525 ST_LOGE("queueBuffer: slot %d is not owned by the client "
526 "(state=%d)", buf, mSlots[buf].mBufferState);
527 return -EINVAL;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800528 } else if (!mSlots[buf].mRequestBufferCalled) {
529 ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
530 "buffer", buf);
531 return -EINVAL;
532 }
533
534 if (mSynchronousMode) {
535 // In synchronous mode we queue all buffers in a FIFO.
536 mQueue.push_back(buf);
537
538 // Synchronous mode always signals that an additional frame should
539 // be consumed.
540 listener = mFrameAvailableListener;
541 } else {
542 // In asynchronous mode we only keep the most recent buffer.
543 if (mQueue.empty()) {
544 mQueue.push_back(buf);
545
546 // Asynchronous mode only signals that a frame should be
547 // consumed if no previous frame was pending. If a frame were
548 // pending then the consumer would have already been notified.
549 listener = mFrameAvailableListener;
550 } else {
551 Fifo::iterator front(mQueue.begin());
552 // buffer currently queued is freed
553 mSlots[*front].mBufferState = BufferSlot::FREE;
554 // and we record the new buffer index in the queued list
555 *front = buf;
556 }
557 }
558
559 mSlots[buf].mBufferState = BufferSlot::QUEUED;
560 mSlots[buf].mCrop = mNextCrop;
561 mSlots[buf].mTransform = mNextTransform;
562 mSlots[buf].mScalingMode = mNextScalingMode;
563 mSlots[buf].mTimestamp = timestamp;
564 mFrameCounter++;
565 mSlots[buf].mFrameNumber = mFrameCounter;
566
Daniel Lam6f15cc92012-01-22 15:26:27 -0800567 mBufferHasBeenQueued = true;
Mathias Agopian3e964c52012-03-06 18:26:54 -0800568 mDequeueCondition.broadcast();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800569
570 *outWidth = mDefaultWidth;
571 *outHeight = mDefaultHeight;
572 *outTransform = 0;
Jamie Gennisa85ca372012-02-23 19:27:23 -0800573
574 ATRACE_INT(mConsumerName.string(), mQueue.size());
Daniel Lam70e80aa2012-01-22 15:26:27 -0800575 } // scope for the lock
576
577 // call back without lock held
578 if (listener != 0) {
579 listener->onFrameAvailable();
580 }
581 return OK;
582}
583
584void BufferQueue::cancelBuffer(int buf) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800585 ATRACE_CALL();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800586 ST_LOGV("cancelBuffer: slot=%d", buf);
587 Mutex::Autolock lock(mMutex);
588
589 if (mAbandoned) {
590 ST_LOGW("cancelBuffer: BufferQueue has been abandoned!");
591 return;
592 }
593
594 if (buf < 0 || buf >= mBufferCount) {
595 ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
596 mBufferCount, buf);
597 return;
598 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
599 ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
600 buf, mSlots[buf].mBufferState);
601 return;
602 }
603 mSlots[buf].mBufferState = BufferSlot::FREE;
604 mSlots[buf].mFrameNumber = 0;
Mathias Agopian3e964c52012-03-06 18:26:54 -0800605 mDequeueCondition.broadcast();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800606}
607
608status_t BufferQueue::setCrop(const Rect& crop) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800609 ATRACE_CALL();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800610 ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
611 crop.bottom);
612
613 Mutex::Autolock lock(mMutex);
614 if (mAbandoned) {
615 ST_LOGE("setCrop: BufferQueue has been abandoned!");
616 return NO_INIT;
617 }
618 mNextCrop = crop;
619 return OK;
620}
621
622status_t BufferQueue::setTransform(uint32_t transform) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800623 ATRACE_CALL();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800624 ST_LOGV("setTransform: xform=%#x", transform);
625 Mutex::Autolock lock(mMutex);
626 if (mAbandoned) {
627 ST_LOGE("setTransform: BufferQueue has been abandoned!");
628 return NO_INIT;
629 }
630 mNextTransform = transform;
631 return OK;
632}
633
634status_t BufferQueue::setScalingMode(int mode) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800635 ATRACE_CALL();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800636 ST_LOGV("setScalingMode: mode=%d", mode);
637
638 switch (mode) {
639 case NATIVE_WINDOW_SCALING_MODE_FREEZE:
640 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
641 break;
642 default:
643 ST_LOGE("unknown scaling mode: %d", mode);
644 return BAD_VALUE;
645 }
646
647 Mutex::Autolock lock(mMutex);
648 mNextScalingMode = mode;
649 return OK;
650}
651
652status_t BufferQueue::connect(int api,
653 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800654 ATRACE_CALL();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800655 ST_LOGV("connect: api=%d", api);
656 Mutex::Autolock lock(mMutex);
657
658 if (mAbandoned) {
659 ST_LOGE("connect: BufferQueue has been abandoned!");
660 return NO_INIT;
661 }
662
663 int err = NO_ERROR;
664 switch (api) {
665 case NATIVE_WINDOW_API_EGL:
666 case NATIVE_WINDOW_API_CPU:
667 case NATIVE_WINDOW_API_MEDIA:
668 case NATIVE_WINDOW_API_CAMERA:
669 if (mConnectedApi != NO_CONNECTED_API) {
670 ST_LOGE("connect: already connected (cur=%d, req=%d)",
671 mConnectedApi, api);
672 err = -EINVAL;
673 } else {
674 mConnectedApi = api;
675 *outWidth = mDefaultWidth;
676 *outHeight = mDefaultHeight;
677 *outTransform = 0;
678 }
679 break;
680 default:
681 err = -EINVAL;
682 break;
683 }
Daniel Lam6f15cc92012-01-22 15:26:27 -0800684
685 mBufferHasBeenQueued = false;
686
Daniel Lam70e80aa2012-01-22 15:26:27 -0800687 return err;
688}
689
690status_t BufferQueue::disconnect(int api) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800691 ATRACE_CALL();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800692 ST_LOGV("disconnect: api=%d", api);
693 Mutex::Autolock lock(mMutex);
694
695 if (mAbandoned) {
696 // it is not really an error to disconnect after the surface
697 // has been abandoned, it should just be a no-op.
698 return NO_ERROR;
699 }
700
701 int err = NO_ERROR;
702 switch (api) {
703 case NATIVE_WINDOW_API_EGL:
704 case NATIVE_WINDOW_API_CPU:
705 case NATIVE_WINDOW_API_MEDIA:
706 case NATIVE_WINDOW_API_CAMERA:
707 if (mConnectedApi == api) {
708 drainQueueAndFreeBuffersLocked();
709 mConnectedApi = NO_CONNECTED_API;
710 mNextCrop.makeInvalid();
711 mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
712 mNextTransform = 0;
Mathias Agopian3e964c52012-03-06 18:26:54 -0800713 mDequeueCondition.broadcast();
Daniel Lam70e80aa2012-01-22 15:26:27 -0800714 } else {
715 ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
716 mConnectedApi, api);
717 err = -EINVAL;
718 }
719 break;
720 default:
721 ST_LOGE("disconnect: unknown API %d", api);
722 err = -EINVAL;
723 break;
724 }
725 return err;
726}
727
Daniel Lam6f15cc92012-01-22 15:26:27 -0800728void BufferQueue::dump(String8& result) const
729{
730 char buffer[1024];
731 BufferQueue::dump(result, "", buffer, 1024);
732}
733
734void BufferQueue::dump(String8& result, const char* prefix,
735 char* buffer, size_t SIZE) const
736{
737 Mutex::Autolock _l(mMutex);
738 snprintf(buffer, SIZE,
739 "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x}\n"
740 ,prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right,
741 mNextCrop.bottom, mNextTransform
742 );
743 result.append(buffer);
744
745 String8 fifo;
746 int fifoSize = 0;
747 Fifo::const_iterator i(mQueue.begin());
748 while (i != mQueue.end()) {
749 snprintf(buffer, SIZE, "%02d ", *i++);
750 fifoSize++;
751 fifo.append(buffer);
752 }
753
754 snprintf(buffer, SIZE,
755 "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
756 "mPixelFormat=%d, FIFO(%d)={%s}\n",
757 prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
758 mDefaultHeight, mPixelFormat, fifoSize, fifo.string());
759 result.append(buffer);
760
761
762 struct {
763 const char * operator()(int state) const {
764 switch (state) {
765 case BufferSlot::DEQUEUED: return "DEQUEUED";
766 case BufferSlot::QUEUED: return "QUEUED";
767 case BufferSlot::FREE: return "FREE";
768 case BufferSlot::ACQUIRED: return "ACQUIRED";
769 default: return "Unknown";
770 }
771 }
772 } stateName;
773
774 for (int i=0 ; i<mBufferCount ; i++) {
775 const BufferSlot& slot(mSlots[i]);
776 snprintf(buffer, SIZE,
777 "%s%s[%02d] "
778 "state=%-8s, crop=[%d,%d,%d,%d], "
779 "transform=0x%02x, timestamp=%lld",
780 prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i,
781 stateName(slot.mBufferState),
782 slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
783 slot.mCrop.bottom, slot.mTransform, slot.mTimestamp
784 );
785 result.append(buffer);
786
787 const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
788 if (buf != NULL) {
789 snprintf(buffer, SIZE,
790 ", %p [%4ux%4u:%4u,%3X]",
791 buf->handle, buf->width, buf->height, buf->stride,
792 buf->format);
793 result.append(buffer);
794 }
795 result.append("\n");
796 }
797}
798
Daniel Lam70e80aa2012-01-22 15:26:27 -0800799void BufferQueue::freeBufferLocked(int i) {
800 mSlots[i].mGraphicBuffer = 0;
801 mSlots[i].mBufferState = BufferSlot::FREE;
802 mSlots[i].mFrameNumber = 0;
Daniel Lam6f15cc92012-01-22 15:26:27 -0800803 mSlots[i].mAcquireCalled = false;
804
805 // destroy fence as BufferQueue now takes ownership
806 if (mSlots[i].mFence != EGL_NO_SYNC_KHR) {
807 eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
808 mSlots[i].mFence = EGL_NO_SYNC_KHR;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800809 }
810}
811
812void BufferQueue::freeAllBuffersLocked() {
813 ALOGW_IF(!mQueue.isEmpty(),
814 "freeAllBuffersLocked called but mQueue is not empty");
Daniel Lam6f15cc92012-01-22 15:26:27 -0800815 mQueue.clear();
816 mBufferHasBeenQueued = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800817 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
818 freeBufferLocked(i);
819 }
820}
821
Daniel Lam6f15cc92012-01-22 15:26:27 -0800822status_t BufferQueue::acquire(BufferItem *buffer) {
Mathias Agopiand1220b92012-03-01 22:11:25 -0800823 ATRACE_CALL();
Daniel Lam6f15cc92012-01-22 15:26:27 -0800824 Mutex::Autolock _l(mMutex);
825 // check if queue is empty
826 // In asynchronous mode the list is guaranteed to be one buffer
827 // deep, while in synchronous mode we use the oldest buffer.
828 if (!mQueue.empty()) {
829 Fifo::iterator front(mQueue.begin());
830 int buf = *front;
831
Mathias Agopiand1220b92012-03-01 22:11:25 -0800832 ATRACE_BUFFER_INDEX(buf);
833
Daniel Lam6f15cc92012-01-22 15:26:27 -0800834 if (mSlots[buf].mAcquireCalled) {
835 buffer->mGraphicBuffer = NULL;
836 }
837 else {
838 buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
839 }
840 buffer->mCrop = mSlots[buf].mCrop;
841 buffer->mTransform = mSlots[buf].mTransform;
842 buffer->mScalingMode = mSlots[buf].mScalingMode;
843 buffer->mFrameNumber = mSlots[buf].mFrameNumber;
Daniel Lamd137cc72012-03-02 10:17:34 -0800844 buffer->mTimestamp = mSlots[buf].mTimestamp;
Daniel Lam6f15cc92012-01-22 15:26:27 -0800845 buffer->mBuf = buf;
846 mSlots[buf].mAcquireCalled = true;
847
848 mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
849 mQueue.erase(front);
Mathias Agopian3e964c52012-03-06 18:26:54 -0800850 mDequeueCondition.broadcast();
Jamie Gennisa85ca372012-02-23 19:27:23 -0800851
852 ATRACE_INT(mConsumerName.string(), mQueue.size());
Daniel Lam6f15cc92012-01-22 15:26:27 -0800853 }
854 else {
855 return -EINVAL; //should be a better return code
856 }
857
858 return OK;
859}
860
861status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
862 EGLSyncKHR fence) {
Mathias Agopiand1220b92012-03-01 22:11:25 -0800863 ATRACE_CALL();
864 ATRACE_BUFFER_INDEX(buf);
865
Daniel Lam6f15cc92012-01-22 15:26:27 -0800866 Mutex::Autolock _l(mMutex);
867
868 if (buf == INVALID_BUFFER_SLOT) {
869 return -EINVAL;
870 }
871
872 mSlots[buf].mEglDisplay = display;
873 mSlots[buf].mFence = fence;
874
875 // The current buffer becomes FREE if it was still in the queued
876 // state. If it has already been given to the client
877 // (synchronous mode), then it stays in DEQUEUED state.
878 if (mSlots[buf].mBufferState == BufferSlot::QUEUED
879 || mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
880 mSlots[buf].mBufferState = BufferSlot::FREE;
881 }
Mathias Agopian3e964c52012-03-06 18:26:54 -0800882
883 mDequeueCondition.broadcast();
Daniel Lam6f15cc92012-01-22 15:26:27 -0800884
885 return OK;
886}
887
888status_t BufferQueue::consumerDisconnect() {
889 Mutex::Autolock lock(mMutex);
890 // Once the SurfaceTexture disconnects, the BufferQueue
891 // is considered abandoned
892 mAbandoned = true;
893 freeAllBuffersLocked();
Mathias Agopian3e964c52012-03-06 18:26:54 -0800894 mDequeueCondition.broadcast();
Daniel Lam6f15cc92012-01-22 15:26:27 -0800895 return OK;
896}
897
898status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
899{
900 ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
901 if (!w || !h) {
902 ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
903 w, h);
904 return BAD_VALUE;
905 }
906
907 Mutex::Autolock lock(mMutex);
908 mDefaultWidth = w;
909 mDefaultHeight = h;
910 return OK;
911}
912
913status_t BufferQueue::setBufferCountServer(int bufferCount) {
Jamie Gennisa85ca372012-02-23 19:27:23 -0800914 ATRACE_CALL();
Daniel Lam6f15cc92012-01-22 15:26:27 -0800915 Mutex::Autolock lock(mMutex);
916 return setBufferCountServerLocked(bufferCount);
917}
918
Daniel Lam70e80aa2012-01-22 15:26:27 -0800919void BufferQueue::freeAllBuffersExceptHeadLocked() {
920 ALOGW_IF(!mQueue.isEmpty(),
921 "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
922 int head = -1;
923 if (!mQueue.empty()) {
924 Fifo::iterator front(mQueue.begin());
925 head = *front;
926 }
Daniel Lam6f15cc92012-01-22 15:26:27 -0800927 mBufferHasBeenQueued = false;
Daniel Lam70e80aa2012-01-22 15:26:27 -0800928 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
929 if (i != head) {
930 freeBufferLocked(i);
931 }
932 }
933}
934
935status_t BufferQueue::drainQueueLocked() {
936 while (mSynchronousMode && !mQueue.isEmpty()) {
937 mDequeueCondition.wait(mMutex);
938 if (mAbandoned) {
939 ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
940 return NO_INIT;
941 }
942 if (mConnectedApi == NO_CONNECTED_API) {
943 ST_LOGE("drainQueueLocked: BufferQueue is not connected!");
944 return NO_INIT;
945 }
946 }
947 return NO_ERROR;
948}
949
950status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
951 status_t err = drainQueueLocked();
952 if (err == NO_ERROR) {
953 if (mSynchronousMode) {
954 freeAllBuffersLocked();
955 } else {
956 freeAllBuffersExceptHeadLocked();
957 }
958 }
959 return err;
960}
961
962}; // namespace android