blob: c7e2c0f21fe4ef1c3a95bba31abbc9c7b8f7cb37 [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"
18
19#define GL_GLEXT_PROTOTYPES
20#define EGL_EGLEXT_PROTOTYPES
21
22#include <EGL/egl.h>
23#include <EGL/eglext.h>
24
25#include <gui/BufferQueue.h>
26#include <private/gui/ComposerService.h>
27#include <surfaceflinger/ISurfaceComposer.h>
28
29#include <utils/Log.h>
30
31// This compile option causes SurfaceTexture to return the buffer that is currently
32// attached to the GL texture from dequeueBuffer when no other buffers are
33// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
34// implicit cross-process synchronization to prevent the buffer from being
35// written to before the buffer has (a) been detached from the GL texture and
36// (b) all GL reads from the buffer have completed.
37#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
38#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true
39#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
40#else
41#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false
42#endif
43
44// Macros for including the BufferQueue name in log messages
45#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
46#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
47#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
48#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
49#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
50
51namespace android {
52
53// Get an ID that's unique within this process.
54static int32_t createProcessUniqueId() {
55 static volatile int32_t globalCounter = 0;
56 return android_atomic_inc(&globalCounter);
57}
58
59BufferQueue::BufferQueue( bool allowSynchronousMode ) :
60 mDefaultWidth(1),
61 mDefaultHeight(1),
62 mPixelFormat(PIXEL_FORMAT_RGBA_8888),
63 mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
64 mClientBufferCount(0),
65 mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
66 mCurrentTexture(INVALID_BUFFER_SLOT),
67 mNextTransform(0),
68 mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
69 mSynchronousMode(false),
70 mAllowSynchronousMode(allowSynchronousMode),
71 mConnectedApi(NO_CONNECTED_API),
72 mAbandoned(false),
73 mFrameCounter(0)
74{
75 // Choose a name using the PID and a process-unique ID.
76 mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
77
78 ST_LOGV("BufferQueue");
79 sp<ISurfaceComposer> composer(ComposerService::getComposerService());
80 mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
81 mNextCrop.makeInvalid();
82}
83
84BufferQueue::~BufferQueue() {
85 ST_LOGV("~BufferQueue");
86}
87
88status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
89 if (bufferCount > NUM_BUFFER_SLOTS)
90 return BAD_VALUE;
91
92 // special-case, nothing to do
93 if (bufferCount == mBufferCount)
94 return OK;
95
96 if (!mClientBufferCount &&
97 bufferCount >= mBufferCount) {
98 // easy, we just have more buffers
99 mBufferCount = bufferCount;
100 mServerBufferCount = bufferCount;
101 mDequeueCondition.signal();
102 } else {
103 // we're here because we're either
104 // - reducing the number of available buffers
105 // - or there is a client-buffer-count in effect
106
107 // less than 2 buffers is never allowed
108 if (bufferCount < 2)
109 return BAD_VALUE;
110
111 // when there is non client-buffer-count in effect, the client is not
112 // allowed to dequeue more than one buffer at a time,
113 // so the next time they dequeue a buffer, we know that they don't
114 // own one. the actual resizing will happen during the next
115 // dequeueBuffer.
116
117 mServerBufferCount = bufferCount;
118 }
119 return OK;
120}
121
122status_t BufferQueue::setBufferCount(int bufferCount) {
123 ST_LOGV("setBufferCount: count=%d", bufferCount);
124 Mutex::Autolock lock(mMutex);
125
126 if (mAbandoned) {
127 ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
128 return NO_INIT;
129 }
130 if (bufferCount > NUM_BUFFER_SLOTS) {
131 ST_LOGE("setBufferCount: bufferCount larger than slots available");
132 return BAD_VALUE;
133 }
134
135 // Error out if the user has dequeued buffers
136 for (int i=0 ; i<mBufferCount ; i++) {
137 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
138 ST_LOGE("setBufferCount: client owns some buffers");
139 return -EINVAL;
140 }
141 }
142
143 const int minBufferSlots = mSynchronousMode ?
144 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
145 if (bufferCount == 0) {
146 mClientBufferCount = 0;
147 bufferCount = (mServerBufferCount >= minBufferSlots) ?
148 mServerBufferCount : minBufferSlots;
149 return setBufferCountServerLocked(bufferCount);
150 }
151
152 if (bufferCount < minBufferSlots) {
153 ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
154 "minimum (%d)", bufferCount, minBufferSlots);
155 return BAD_VALUE;
156 }
157
158 // here we're guaranteed that the client doesn't have dequeued buffers
159 // and will release all of its buffer references.
160 freeAllBuffersLocked();
161 mBufferCount = bufferCount;
162 mClientBufferCount = bufferCount;
163 mCurrentTexture = INVALID_BUFFER_SLOT;
164 mQueue.clear();
165 mDequeueCondition.signal();
166 return OK;
167}
168
169status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
170 ST_LOGV("requestBuffer: slot=%d", slot);
171 Mutex::Autolock lock(mMutex);
172 if (mAbandoned) {
173 ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
174 return NO_INIT;
175 }
176 if (slot < 0 || mBufferCount <= slot) {
177 ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
178 mBufferCount, slot);
179 return BAD_VALUE;
180 }
181 mSlots[slot].mRequestBufferCalled = true;
182 *buf = mSlots[slot].mGraphicBuffer;
183 return NO_ERROR;
184}
185
186status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
187 uint32_t format, uint32_t usage) {
188 ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
189
190 if ((w && !h) || (!w && h)) {
191 ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
192 return BAD_VALUE;
193 }
194
195 status_t returnFlags(OK);
196 EGLDisplay dpy = EGL_NO_DISPLAY;
197 EGLSyncKHR fence = EGL_NO_SYNC_KHR;
198
199 { // Scope for the lock
200 Mutex::Autolock lock(mMutex);
201
202 int found = -1;
203 int foundSync = -1;
204 int dequeuedCount = 0;
205 bool tryAgain = true;
206 while (tryAgain) {
207 if (mAbandoned) {
208 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
209 return NO_INIT;
210 }
211
212 // We need to wait for the FIFO to drain if the number of buffer
213 // needs to change.
214 //
215 // The condition "number of buffers needs to change" is true if
216 // - the client doesn't care about how many buffers there are
217 // - AND the actual number of buffer is different from what was
218 // set in the last setBufferCountServer()
219 // - OR -
220 // setBufferCountServer() was set to a value incompatible with
221 // the synchronization mode (for instance because the sync mode
222 // changed since)
223 //
224 // As long as this condition is true AND the FIFO is not empty, we
225 // wait on mDequeueCondition.
226
227 const int minBufferCountNeeded = mSynchronousMode ?
228 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
229
230 const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
231 ((mServerBufferCount != mBufferCount) ||
232 (mServerBufferCount < minBufferCountNeeded));
233
234 if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
235 // wait for the FIFO to drain
236 mDequeueCondition.wait(mMutex);
237 // NOTE: we continue here because we need to reevaluate our
238 // whole state (eg: we could be abandoned or disconnected)
239 continue;
240 }
241
242 if (numberOfBuffersNeedsToChange) {
243 // here we're guaranteed that mQueue is empty
244 freeAllBuffersLocked();
245 mBufferCount = mServerBufferCount;
246 if (mBufferCount < minBufferCountNeeded)
247 mBufferCount = minBufferCountNeeded;
248 mCurrentTexture = INVALID_BUFFER_SLOT;
249 returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
250 }
251
252 // look for a free buffer to give to the client
253 found = INVALID_BUFFER_SLOT;
254 foundSync = INVALID_BUFFER_SLOT;
255 dequeuedCount = 0;
256 for (int i = 0; i < mBufferCount; i++) {
257 const int state = mSlots[i].mBufferState;
258 if (state == BufferSlot::DEQUEUED) {
259 dequeuedCount++;
260 }
261
262 // if buffer is FREE it CANNOT be current
263 ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
264 "dequeueBuffer: buffer %d is both FREE and current!",
265 i);
266
267 if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
268 if (state == BufferSlot::FREE || i == mCurrentTexture) {
269 foundSync = i;
270 if (i != mCurrentTexture) {
271 found = i;
272 break;
273 }
274 }
275 } else {
276 if (state == BufferSlot::FREE) {
277 /* We return the oldest of the free buffers to avoid
278 * stalling the producer if possible. This is because
279 * the consumer may still have pending reads of the
280 * buffers in flight.
281 */
282 bool isOlder = mSlots[i].mFrameNumber <
283 mSlots[found].mFrameNumber;
284 if (found < 0 || isOlder) {
285 foundSync = i;
286 found = i;
287 }
288 }
289 }
290 }
291
292 // clients are not allowed to dequeue more than one buffer
293 // if they didn't set a buffer count.
294 if (!mClientBufferCount && dequeuedCount) {
295 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
296 "setting the buffer count");
297 return -EINVAL;
298 }
299
300 // See whether a buffer has been queued since the last
301 // setBufferCount so we know whether to perform the
302 // MIN_UNDEQUEUED_BUFFERS check below.
303 bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
304 if (bufferHasBeenQueued) {
305 // make sure the client is not trying to dequeue more buffers
306 // than allowed.
307 const int avail = mBufferCount - (dequeuedCount+1);
308 if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
309 ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
310 "(dequeued=%d)",
311 MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
312 dequeuedCount);
313 return -EBUSY;
314 }
315 }
316
317 // we're in synchronous mode and didn't find a buffer, we need to
318 // wait for some buffers to be consumed
319 tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
320 if (tryAgain) {
321 mDequeueCondition.wait(mMutex);
322 }
323 }
324
325 if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
326 // foundSync guaranteed to be != INVALID_BUFFER_SLOT
327 found = foundSync;
328 }
329
330 if (found == INVALID_BUFFER_SLOT) {
331 // This should not happen.
332 ST_LOGE("dequeueBuffer: no available buffer slots");
333 return -EBUSY;
334 }
335
336 const int buf = found;
337 *outBuf = found;
338
339 const bool useDefaultSize = !w && !h;
340 if (useDefaultSize) {
341 // use the default size
342 w = mDefaultWidth;
343 h = mDefaultHeight;
344 }
345
346 const bool updateFormat = (format != 0);
347 if (!updateFormat) {
348 // keep the current (or default) format
349 format = mPixelFormat;
350 }
351
352 // buffer is now in DEQUEUED (but can also be current at the same time,
353 // if we're in synchronous mode)
354 mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
355
356 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
357 if ((buffer == NULL) ||
358 (uint32_t(buffer->width) != w) ||
359 (uint32_t(buffer->height) != h) ||
360 (uint32_t(buffer->format) != format) ||
361 ((uint32_t(buffer->usage) & usage) != usage))
362 {
363 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
364 status_t error;
365 sp<GraphicBuffer> graphicBuffer(
366 mGraphicBufferAlloc->createGraphicBuffer(
367 w, h, format, usage, &error));
368 if (graphicBuffer == 0) {
369 ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
370 "failed");
371 return error;
372 }
373 if (updateFormat) {
374 mPixelFormat = format;
375 }
376 mSlots[buf].mGraphicBuffer = graphicBuffer;
377 mSlots[buf].mRequestBufferCalled = false;
378 mSlots[buf].mFence = EGL_NO_SYNC_KHR;
379 if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
380 eglDestroyImageKHR(mSlots[buf].mEglDisplay,
381 mSlots[buf].mEglImage);
382 mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
383 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
384 }
385 if (mCurrentTexture == buf) {
386 // The current texture no longer references the buffer in this slot
387 // since we just allocated a new buffer.
388 mCurrentTexture = INVALID_BUFFER_SLOT;
389 }
390 returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
391 }
392
393 dpy = mSlots[buf].mEglDisplay;
394 fence = mSlots[buf].mFence;
395 mSlots[buf].mFence = EGL_NO_SYNC_KHR;
396 }
397
398 if (fence != EGL_NO_SYNC_KHR) {
399 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
400 // If something goes wrong, log the error, but return the buffer without
401 // synchronizing access to it. It's too late at this point to abort the
402 // dequeue operation.
403 if (result == EGL_FALSE) {
404 ALOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
405 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
406 ALOGE("dequeueBuffer: timeout waiting for fence");
407 }
408 eglDestroySyncKHR(dpy, fence);
409 }
410
411 ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
412 mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
413
414 return returnFlags;
415}
416
417status_t BufferQueue::setSynchronousMode(bool enabled) {
418 ST_LOGV("setSynchronousMode: enabled=%d", enabled);
419 Mutex::Autolock lock(mMutex);
420
421 if (mAbandoned) {
422 ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
423 return NO_INIT;
424 }
425
426 status_t err = OK;
427 if (!mAllowSynchronousMode && enabled)
428 return err;
429
430 if (!enabled) {
431 // going to asynchronous mode, drain the queue
432 err = drainQueueLocked();
433 if (err != NO_ERROR)
434 return err;
435 }
436
437 if (mSynchronousMode != enabled) {
438 // - if we're going to asynchronous mode, the queue is guaranteed to be
439 // empty here
440 // - if the client set the number of buffers, we're guaranteed that
441 // we have at least 3 (because we don't allow less)
442 mSynchronousMode = enabled;
443 mDequeueCondition.signal();
444 }
445 return err;
446}
447
448status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
449 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
450 ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
451
452 sp<FrameAvailableListener> listener;
453
454 { // scope for the lock
455 Mutex::Autolock lock(mMutex);
456 if (mAbandoned) {
457 ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
458 return NO_INIT;
459 }
460 if (buf < 0 || buf >= mBufferCount) {
461 ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
462 mBufferCount, buf);
463 return -EINVAL;
464 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
465 ST_LOGE("queueBuffer: slot %d is not owned by the client "
466 "(state=%d)", buf, mSlots[buf].mBufferState);
467 return -EINVAL;
468 } else if (buf == mCurrentTexture) {
469 ST_LOGE("queueBuffer: slot %d is current!", buf);
470 return -EINVAL;
471 } else if (!mSlots[buf].mRequestBufferCalled) {
472 ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
473 "buffer", buf);
474 return -EINVAL;
475 }
476
477 if (mSynchronousMode) {
478 // In synchronous mode we queue all buffers in a FIFO.
479 mQueue.push_back(buf);
480
481 // Synchronous mode always signals that an additional frame should
482 // be consumed.
483 listener = mFrameAvailableListener;
484 } else {
485 // In asynchronous mode we only keep the most recent buffer.
486 if (mQueue.empty()) {
487 mQueue.push_back(buf);
488
489 // Asynchronous mode only signals that a frame should be
490 // consumed if no previous frame was pending. If a frame were
491 // pending then the consumer would have already been notified.
492 listener = mFrameAvailableListener;
493 } else {
494 Fifo::iterator front(mQueue.begin());
495 // buffer currently queued is freed
496 mSlots[*front].mBufferState = BufferSlot::FREE;
497 // and we record the new buffer index in the queued list
498 *front = buf;
499 }
500 }
501
502 mSlots[buf].mBufferState = BufferSlot::QUEUED;
503 mSlots[buf].mCrop = mNextCrop;
504 mSlots[buf].mTransform = mNextTransform;
505 mSlots[buf].mScalingMode = mNextScalingMode;
506 mSlots[buf].mTimestamp = timestamp;
507 mFrameCounter++;
508 mSlots[buf].mFrameNumber = mFrameCounter;
509
510 mDequeueCondition.signal();
511
512 *outWidth = mDefaultWidth;
513 *outHeight = mDefaultHeight;
514 *outTransform = 0;
515 } // scope for the lock
516
517 // call back without lock held
518 if (listener != 0) {
519 listener->onFrameAvailable();
520 }
521 return OK;
522}
523
524void BufferQueue::cancelBuffer(int buf) {
525 ST_LOGV("cancelBuffer: slot=%d", buf);
526 Mutex::Autolock lock(mMutex);
527
528 if (mAbandoned) {
529 ST_LOGW("cancelBuffer: BufferQueue has been abandoned!");
530 return;
531 }
532
533 if (buf < 0 || buf >= mBufferCount) {
534 ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
535 mBufferCount, buf);
536 return;
537 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
538 ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
539 buf, mSlots[buf].mBufferState);
540 return;
541 }
542 mSlots[buf].mBufferState = BufferSlot::FREE;
543 mSlots[buf].mFrameNumber = 0;
544 mDequeueCondition.signal();
545}
546
547status_t BufferQueue::setCrop(const Rect& crop) {
548 ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
549 crop.bottom);
550
551 Mutex::Autolock lock(mMutex);
552 if (mAbandoned) {
553 ST_LOGE("setCrop: BufferQueue has been abandoned!");
554 return NO_INIT;
555 }
556 mNextCrop = crop;
557 return OK;
558}
559
560status_t BufferQueue::setTransform(uint32_t transform) {
561 ST_LOGV("setTransform: xform=%#x", transform);
562 Mutex::Autolock lock(mMutex);
563 if (mAbandoned) {
564 ST_LOGE("setTransform: BufferQueue has been abandoned!");
565 return NO_INIT;
566 }
567 mNextTransform = transform;
568 return OK;
569}
570
571status_t BufferQueue::setScalingMode(int mode) {
572 ST_LOGV("setScalingMode: mode=%d", mode);
573
574 switch (mode) {
575 case NATIVE_WINDOW_SCALING_MODE_FREEZE:
576 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
577 break;
578 default:
579 ST_LOGE("unknown scaling mode: %d", mode);
580 return BAD_VALUE;
581 }
582
583 Mutex::Autolock lock(mMutex);
584 mNextScalingMode = mode;
585 return OK;
586}
587
588status_t BufferQueue::connect(int api,
589 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
590 ST_LOGV("connect: api=%d", api);
591 Mutex::Autolock lock(mMutex);
592
593 if (mAbandoned) {
594 ST_LOGE("connect: BufferQueue has been abandoned!");
595 return NO_INIT;
596 }
597
598 int err = NO_ERROR;
599 switch (api) {
600 case NATIVE_WINDOW_API_EGL:
601 case NATIVE_WINDOW_API_CPU:
602 case NATIVE_WINDOW_API_MEDIA:
603 case NATIVE_WINDOW_API_CAMERA:
604 if (mConnectedApi != NO_CONNECTED_API) {
605 ST_LOGE("connect: already connected (cur=%d, req=%d)",
606 mConnectedApi, api);
607 err = -EINVAL;
608 } else {
609 mConnectedApi = api;
610 *outWidth = mDefaultWidth;
611 *outHeight = mDefaultHeight;
612 *outTransform = 0;
613 }
614 break;
615 default:
616 err = -EINVAL;
617 break;
618 }
619 return err;
620}
621
622status_t BufferQueue::disconnect(int api) {
623 ST_LOGV("disconnect: api=%d", api);
624 Mutex::Autolock lock(mMutex);
625
626 if (mAbandoned) {
627 // it is not really an error to disconnect after the surface
628 // has been abandoned, it should just be a no-op.
629 return NO_ERROR;
630 }
631
632 int err = NO_ERROR;
633 switch (api) {
634 case NATIVE_WINDOW_API_EGL:
635 case NATIVE_WINDOW_API_CPU:
636 case NATIVE_WINDOW_API_MEDIA:
637 case NATIVE_WINDOW_API_CAMERA:
638 if (mConnectedApi == api) {
639 drainQueueAndFreeBuffersLocked();
640 mConnectedApi = NO_CONNECTED_API;
641 mNextCrop.makeInvalid();
642 mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
643 mNextTransform = 0;
644 mDequeueCondition.signal();
645 } else {
646 ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
647 mConnectedApi, api);
648 err = -EINVAL;
649 }
650 break;
651 default:
652 ST_LOGE("disconnect: unknown API %d", api);
653 err = -EINVAL;
654 break;
655 }
656 return err;
657}
658
659void BufferQueue::freeBufferLocked(int i) {
660 mSlots[i].mGraphicBuffer = 0;
661 mSlots[i].mBufferState = BufferSlot::FREE;
662 mSlots[i].mFrameNumber = 0;
663 if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
664 eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
665 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
666 mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
667 }
668}
669
670void BufferQueue::freeAllBuffersLocked() {
671 ALOGW_IF(!mQueue.isEmpty(),
672 "freeAllBuffersLocked called but mQueue is not empty");
673 mCurrentTexture = INVALID_BUFFER_SLOT;
674 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
675 freeBufferLocked(i);
676 }
677}
678
679void BufferQueue::freeAllBuffersExceptHeadLocked() {
680 ALOGW_IF(!mQueue.isEmpty(),
681 "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
682 int head = -1;
683 if (!mQueue.empty()) {
684 Fifo::iterator front(mQueue.begin());
685 head = *front;
686 }
687 mCurrentTexture = INVALID_BUFFER_SLOT;
688 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
689 if (i != head) {
690 freeBufferLocked(i);
691 }
692 }
693}
694
695status_t BufferQueue::drainQueueLocked() {
696 while (mSynchronousMode && !mQueue.isEmpty()) {
697 mDequeueCondition.wait(mMutex);
698 if (mAbandoned) {
699 ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
700 return NO_INIT;
701 }
702 if (mConnectedApi == NO_CONNECTED_API) {
703 ST_LOGE("drainQueueLocked: BufferQueue is not connected!");
704 return NO_INIT;
705 }
706 }
707 return NO_ERROR;
708}
709
710status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
711 status_t err = drainQueueLocked();
712 if (err == NO_ERROR) {
713 if (mSynchronousMode) {
714 freeAllBuffersLocked();
715 } else {
716 freeAllBuffersExceptHeadLocked();
717 }
718 }
719 return err;
720}
721
722}; // namespace android