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