BufferQueue.cpp revision 333023884112259f145bb23c41a05211198d9792
1/*
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"
18//#define LOG_NDEBUG 0
19
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>
27#include <private/gui/ComposerService.h>
28#include <surfaceflinger/ISurfaceComposer.h>
29
30#include <utils/Log.h>
31#include <gui/SurfaceTexture.h>
32
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
47#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__)
52
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),
68    mNextTransform(0),
69    mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
70    mSynchronousMode(false),
71    mAllowSynchronousMode(allowSynchronousMode),
72    mConnectedApi(NO_CONNECTED_API),
73    mAbandoned(false),
74    mFrameCounter(0),
75    mBufferHasBeenQueued(false)
76{
77    // Choose a name using the PID and a process-unique ID.
78    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
79
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
124bool 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
141status_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;
182    mBufferHasBeenQueued = false;
183    mQueue.clear();
184    mDequeueCondition.signal();
185    return OK;
186}
187
188int 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
219status_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;
298                mBufferHasBeenQueued = false;
299                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
312                if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
313                    // This functionality has been temporarily removed so
314                    // BufferQueue and SurfaceTexture can be refactored into
315                    // separate objects
316                } 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.
344            if (mBufferHasBeenQueued) {
345                // 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            }
416
417            mSlots[buf].mAcquireCalled = false;
418            mSlots[buf].mGraphicBuffer = graphicBuffer;
419            mSlots[buf].mRequestBufferCalled = false;
420            mSlots[buf].mFence = EGL_NO_SYNC_KHR;
421            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
422
423
424
425
426            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;
432    }  // end lock scope
433
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);
445
446    }
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;
505        } 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
544        mBufferHasBeenQueued = true;
545        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    }
654
655    mBufferHasBeenQueued = false;
656
657    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
697void 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
768void BufferQueue::freeBufferLocked(int i) {
769    mSlots[i].mGraphicBuffer = 0;
770    mSlots[i].mBufferState = BufferSlot::FREE;
771    mSlots[i].mFrameNumber = 0;
772    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;
778    }
779}
780
781void BufferQueue::freeAllBuffersLocked() {
782    ALOGW_IF(!mQueue.isEmpty(),
783            "freeAllBuffersLocked called but mQueue is not empty");
784    mQueue.clear();
785    mBufferHasBeenQueued = false;
786    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
787        freeBufferLocked(i);
788    }
789}
790
791status_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
876void 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    }
884    mBufferHasBeenQueued = false;
885    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
920