blob: 0791de2269ef339223386bb230af0248ca240074 [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
Daniel Lamf7c761e2012-01-30 15:51:27 -0800169int BufferQueue::query(int what, int* outValue)
170{
171 Mutex::Autolock lock(mMutex);
172
173 if (mAbandoned) {
174 ST_LOGE("query: SurfaceTexture has been abandoned!");
175 return NO_INIT;
176 }
177
178 int value;
179 switch (what) {
180 case NATIVE_WINDOW_WIDTH:
181 value = mDefaultWidth;
182 break;
183 case NATIVE_WINDOW_HEIGHT:
184 value = mDefaultHeight;
185 break;
186 case NATIVE_WINDOW_FORMAT:
187 value = mPixelFormat;
188 break;
189 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
190 value = mSynchronousMode ?
191 (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS;
192 break;
193 default:
194 return BAD_VALUE;
195 }
196 outValue[0] = value;
197 return NO_ERROR;
198}
199
Daniel Lam70e80aa2012-01-22 15:26:27 -0800200status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
201 ST_LOGV("requestBuffer: slot=%d", slot);
202 Mutex::Autolock lock(mMutex);
203 if (mAbandoned) {
204 ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
205 return NO_INIT;
206 }
207 if (slot < 0 || mBufferCount <= slot) {
208 ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
209 mBufferCount, slot);
210 return BAD_VALUE;
211 }
212 mSlots[slot].mRequestBufferCalled = true;
213 *buf = mSlots[slot].mGraphicBuffer;
214 return NO_ERROR;
215}
216
217status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
218 uint32_t format, uint32_t usage) {
219 ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
220
221 if ((w && !h) || (!w && h)) {
222 ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
223 return BAD_VALUE;
224 }
225
226 status_t returnFlags(OK);
227 EGLDisplay dpy = EGL_NO_DISPLAY;
228 EGLSyncKHR fence = EGL_NO_SYNC_KHR;
229
230 { // Scope for the lock
231 Mutex::Autolock lock(mMutex);
232
233 int found = -1;
234 int foundSync = -1;
235 int dequeuedCount = 0;
236 bool tryAgain = true;
237 while (tryAgain) {
238 if (mAbandoned) {
239 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
240 return NO_INIT;
241 }
242
243 // We need to wait for the FIFO to drain if the number of buffer
244 // needs to change.
245 //
246 // The condition "number of buffers needs to change" is true if
247 // - the client doesn't care about how many buffers there are
248 // - AND the actual number of buffer is different from what was
249 // set in the last setBufferCountServer()
250 // - OR -
251 // setBufferCountServer() was set to a value incompatible with
252 // the synchronization mode (for instance because the sync mode
253 // changed since)
254 //
255 // As long as this condition is true AND the FIFO is not empty, we
256 // wait on mDequeueCondition.
257
258 const int minBufferCountNeeded = mSynchronousMode ?
259 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
260
261 const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
262 ((mServerBufferCount != mBufferCount) ||
263 (mServerBufferCount < minBufferCountNeeded));
264
265 if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
266 // wait for the FIFO to drain
267 mDequeueCondition.wait(mMutex);
268 // NOTE: we continue here because we need to reevaluate our
269 // whole state (eg: we could be abandoned or disconnected)
270 continue;
271 }
272
273 if (numberOfBuffersNeedsToChange) {
274 // here we're guaranteed that mQueue is empty
275 freeAllBuffersLocked();
276 mBufferCount = mServerBufferCount;
277 if (mBufferCount < minBufferCountNeeded)
278 mBufferCount = minBufferCountNeeded;
279 mCurrentTexture = INVALID_BUFFER_SLOT;
280 returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
281 }
282
283 // look for a free buffer to give to the client
284 found = INVALID_BUFFER_SLOT;
285 foundSync = INVALID_BUFFER_SLOT;
286 dequeuedCount = 0;
287 for (int i = 0; i < mBufferCount; i++) {
288 const int state = mSlots[i].mBufferState;
289 if (state == BufferSlot::DEQUEUED) {
290 dequeuedCount++;
291 }
292
293 // if buffer is FREE it CANNOT be current
294 ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
295 "dequeueBuffer: buffer %d is both FREE and current!",
296 i);
297
298 if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
299 if (state == BufferSlot::FREE || i == mCurrentTexture) {
300 foundSync = i;
301 if (i != mCurrentTexture) {
302 found = i;
303 break;
304 }
305 }
306 } else {
307 if (state == BufferSlot::FREE) {
308 /* We return the oldest of the free buffers to avoid
309 * stalling the producer if possible. This is because
310 * the consumer may still have pending reads of the
311 * buffers in flight.
312 */
313 bool isOlder = mSlots[i].mFrameNumber <
314 mSlots[found].mFrameNumber;
315 if (found < 0 || isOlder) {
316 foundSync = i;
317 found = i;
318 }
319 }
320 }
321 }
322
323 // clients are not allowed to dequeue more than one buffer
324 // if they didn't set a buffer count.
325 if (!mClientBufferCount && dequeuedCount) {
326 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
327 "setting the buffer count");
328 return -EINVAL;
329 }
330
331 // See whether a buffer has been queued since the last
332 // setBufferCount so we know whether to perform the
333 // MIN_UNDEQUEUED_BUFFERS check below.
334 bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
335 if (bufferHasBeenQueued) {
336 // make sure the client is not trying to dequeue more buffers
337 // than allowed.
338 const int avail = mBufferCount - (dequeuedCount+1);
339 if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
340 ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
341 "(dequeued=%d)",
342 MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
343 dequeuedCount);
344 return -EBUSY;
345 }
346 }
347
348 // we're in synchronous mode and didn't find a buffer, we need to
349 // wait for some buffers to be consumed
350 tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
351 if (tryAgain) {
352 mDequeueCondition.wait(mMutex);
353 }
354 }
355
356 if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
357 // foundSync guaranteed to be != INVALID_BUFFER_SLOT
358 found = foundSync;
359 }
360
361 if (found == INVALID_BUFFER_SLOT) {
362 // This should not happen.
363 ST_LOGE("dequeueBuffer: no available buffer slots");
364 return -EBUSY;
365 }
366
367 const int buf = found;
368 *outBuf = found;
369
370 const bool useDefaultSize = !w && !h;
371 if (useDefaultSize) {
372 // use the default size
373 w = mDefaultWidth;
374 h = mDefaultHeight;
375 }
376
377 const bool updateFormat = (format != 0);
378 if (!updateFormat) {
379 // keep the current (or default) format
380 format = mPixelFormat;
381 }
382
383 // buffer is now in DEQUEUED (but can also be current at the same time,
384 // if we're in synchronous mode)
385 mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
386
387 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
388 if ((buffer == NULL) ||
389 (uint32_t(buffer->width) != w) ||
390 (uint32_t(buffer->height) != h) ||
391 (uint32_t(buffer->format) != format) ||
392 ((uint32_t(buffer->usage) & usage) != usage))
393 {
394 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
395 status_t error;
396 sp<GraphicBuffer> graphicBuffer(
397 mGraphicBufferAlloc->createGraphicBuffer(
398 w, h, format, usage, &error));
399 if (graphicBuffer == 0) {
400 ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
401 "failed");
402 return error;
403 }
404 if (updateFormat) {
405 mPixelFormat = format;
406 }
407 mSlots[buf].mGraphicBuffer = graphicBuffer;
408 mSlots[buf].mRequestBufferCalled = false;
409 mSlots[buf].mFence = EGL_NO_SYNC_KHR;
410 if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
411 eglDestroyImageKHR(mSlots[buf].mEglDisplay,
412 mSlots[buf].mEglImage);
413 mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
414 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
415 }
416 if (mCurrentTexture == buf) {
417 // The current texture no longer references the buffer in this slot
418 // since we just allocated a new buffer.
419 mCurrentTexture = INVALID_BUFFER_SLOT;
420 }
421 returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
422 }
423
424 dpy = mSlots[buf].mEglDisplay;
425 fence = mSlots[buf].mFence;
426 mSlots[buf].mFence = EGL_NO_SYNC_KHR;
427 }
428
429 if (fence != EGL_NO_SYNC_KHR) {
430 EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
431 // If something goes wrong, log the error, but return the buffer without
432 // synchronizing access to it. It's too late at this point to abort the
433 // dequeue operation.
434 if (result == EGL_FALSE) {
435 ALOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
436 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
437 ALOGE("dequeueBuffer: timeout waiting for fence");
438 }
439 eglDestroySyncKHR(dpy, fence);
440 }
441
442 ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
443 mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
444
445 return returnFlags;
446}
447
448status_t BufferQueue::setSynchronousMode(bool enabled) {
449 ST_LOGV("setSynchronousMode: enabled=%d", enabled);
450 Mutex::Autolock lock(mMutex);
451
452 if (mAbandoned) {
453 ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
454 return NO_INIT;
455 }
456
457 status_t err = OK;
458 if (!mAllowSynchronousMode && enabled)
459 return err;
460
461 if (!enabled) {
462 // going to asynchronous mode, drain the queue
463 err = drainQueueLocked();
464 if (err != NO_ERROR)
465 return err;
466 }
467
468 if (mSynchronousMode != enabled) {
469 // - if we're going to asynchronous mode, the queue is guaranteed to be
470 // empty here
471 // - if the client set the number of buffers, we're guaranteed that
472 // we have at least 3 (because we don't allow less)
473 mSynchronousMode = enabled;
474 mDequeueCondition.signal();
475 }
476 return err;
477}
478
479status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
480 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
481 ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
482
483 sp<FrameAvailableListener> listener;
484
485 { // scope for the lock
486 Mutex::Autolock lock(mMutex);
487 if (mAbandoned) {
488 ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
489 return NO_INIT;
490 }
491 if (buf < 0 || buf >= mBufferCount) {
492 ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
493 mBufferCount, buf);
494 return -EINVAL;
495 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
496 ST_LOGE("queueBuffer: slot %d is not owned by the client "
497 "(state=%d)", buf, mSlots[buf].mBufferState);
498 return -EINVAL;
499 } else if (buf == mCurrentTexture) {
500 ST_LOGE("queueBuffer: slot %d is current!", buf);
501 return -EINVAL;
502 } else if (!mSlots[buf].mRequestBufferCalled) {
503 ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
504 "buffer", buf);
505 return -EINVAL;
506 }
507
508 if (mSynchronousMode) {
509 // In synchronous mode we queue all buffers in a FIFO.
510 mQueue.push_back(buf);
511
512 // Synchronous mode always signals that an additional frame should
513 // be consumed.
514 listener = mFrameAvailableListener;
515 } else {
516 // In asynchronous mode we only keep the most recent buffer.
517 if (mQueue.empty()) {
518 mQueue.push_back(buf);
519
520 // Asynchronous mode only signals that a frame should be
521 // consumed if no previous frame was pending. If a frame were
522 // pending then the consumer would have already been notified.
523 listener = mFrameAvailableListener;
524 } else {
525 Fifo::iterator front(mQueue.begin());
526 // buffer currently queued is freed
527 mSlots[*front].mBufferState = BufferSlot::FREE;
528 // and we record the new buffer index in the queued list
529 *front = buf;
530 }
531 }
532
533 mSlots[buf].mBufferState = BufferSlot::QUEUED;
534 mSlots[buf].mCrop = mNextCrop;
535 mSlots[buf].mTransform = mNextTransform;
536 mSlots[buf].mScalingMode = mNextScalingMode;
537 mSlots[buf].mTimestamp = timestamp;
538 mFrameCounter++;
539 mSlots[buf].mFrameNumber = mFrameCounter;
540
541 mDequeueCondition.signal();
542
543 *outWidth = mDefaultWidth;
544 *outHeight = mDefaultHeight;
545 *outTransform = 0;
546 } // scope for the lock
547
548 // call back without lock held
549 if (listener != 0) {
550 listener->onFrameAvailable();
551 }
552 return OK;
553}
554
555void BufferQueue::cancelBuffer(int buf) {
556 ST_LOGV("cancelBuffer: slot=%d", buf);
557 Mutex::Autolock lock(mMutex);
558
559 if (mAbandoned) {
560 ST_LOGW("cancelBuffer: BufferQueue has been abandoned!");
561 return;
562 }
563
564 if (buf < 0 || buf >= mBufferCount) {
565 ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
566 mBufferCount, buf);
567 return;
568 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
569 ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
570 buf, mSlots[buf].mBufferState);
571 return;
572 }
573 mSlots[buf].mBufferState = BufferSlot::FREE;
574 mSlots[buf].mFrameNumber = 0;
575 mDequeueCondition.signal();
576}
577
578status_t BufferQueue::setCrop(const Rect& crop) {
579 ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
580 crop.bottom);
581
582 Mutex::Autolock lock(mMutex);
583 if (mAbandoned) {
584 ST_LOGE("setCrop: BufferQueue has been abandoned!");
585 return NO_INIT;
586 }
587 mNextCrop = crop;
588 return OK;
589}
590
591status_t BufferQueue::setTransform(uint32_t transform) {
592 ST_LOGV("setTransform: xform=%#x", transform);
593 Mutex::Autolock lock(mMutex);
594 if (mAbandoned) {
595 ST_LOGE("setTransform: BufferQueue has been abandoned!");
596 return NO_INIT;
597 }
598 mNextTransform = transform;
599 return OK;
600}
601
602status_t BufferQueue::setScalingMode(int mode) {
603 ST_LOGV("setScalingMode: mode=%d", mode);
604
605 switch (mode) {
606 case NATIVE_WINDOW_SCALING_MODE_FREEZE:
607 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
608 break;
609 default:
610 ST_LOGE("unknown scaling mode: %d", mode);
611 return BAD_VALUE;
612 }
613
614 Mutex::Autolock lock(mMutex);
615 mNextScalingMode = mode;
616 return OK;
617}
618
619status_t BufferQueue::connect(int api,
620 uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
621 ST_LOGV("connect: api=%d", api);
622 Mutex::Autolock lock(mMutex);
623
624 if (mAbandoned) {
625 ST_LOGE("connect: BufferQueue has been abandoned!");
626 return NO_INIT;
627 }
628
629 int err = NO_ERROR;
630 switch (api) {
631 case NATIVE_WINDOW_API_EGL:
632 case NATIVE_WINDOW_API_CPU:
633 case NATIVE_WINDOW_API_MEDIA:
634 case NATIVE_WINDOW_API_CAMERA:
635 if (mConnectedApi != NO_CONNECTED_API) {
636 ST_LOGE("connect: already connected (cur=%d, req=%d)",
637 mConnectedApi, api);
638 err = -EINVAL;
639 } else {
640 mConnectedApi = api;
641 *outWidth = mDefaultWidth;
642 *outHeight = mDefaultHeight;
643 *outTransform = 0;
644 }
645 break;
646 default:
647 err = -EINVAL;
648 break;
649 }
650 return err;
651}
652
653status_t BufferQueue::disconnect(int api) {
654 ST_LOGV("disconnect: api=%d", api);
655 Mutex::Autolock lock(mMutex);
656
657 if (mAbandoned) {
658 // it is not really an error to disconnect after the surface
659 // has been abandoned, it should just be a no-op.
660 return NO_ERROR;
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 == api) {
670 drainQueueAndFreeBuffersLocked();
671 mConnectedApi = NO_CONNECTED_API;
672 mNextCrop.makeInvalid();
673 mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
674 mNextTransform = 0;
675 mDequeueCondition.signal();
676 } else {
677 ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
678 mConnectedApi, api);
679 err = -EINVAL;
680 }
681 break;
682 default:
683 ST_LOGE("disconnect: unknown API %d", api);
684 err = -EINVAL;
685 break;
686 }
687 return err;
688}
689
690void BufferQueue::freeBufferLocked(int i) {
691 mSlots[i].mGraphicBuffer = 0;
692 mSlots[i].mBufferState = BufferSlot::FREE;
693 mSlots[i].mFrameNumber = 0;
694 if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
695 eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
696 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
697 mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
698 }
699}
700
701void BufferQueue::freeAllBuffersLocked() {
702 ALOGW_IF(!mQueue.isEmpty(),
703 "freeAllBuffersLocked called but mQueue is not empty");
704 mCurrentTexture = INVALID_BUFFER_SLOT;
705 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
706 freeBufferLocked(i);
707 }
708}
709
710void BufferQueue::freeAllBuffersExceptHeadLocked() {
711 ALOGW_IF(!mQueue.isEmpty(),
712 "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
713 int head = -1;
714 if (!mQueue.empty()) {
715 Fifo::iterator front(mQueue.begin());
716 head = *front;
717 }
718 mCurrentTexture = INVALID_BUFFER_SLOT;
719 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
720 if (i != head) {
721 freeBufferLocked(i);
722 }
723 }
724}
725
726status_t BufferQueue::drainQueueLocked() {
727 while (mSynchronousMode && !mQueue.isEmpty()) {
728 mDequeueCondition.wait(mMutex);
729 if (mAbandoned) {
730 ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
731 return NO_INIT;
732 }
733 if (mConnectedApi == NO_CONNECTED_API) {
734 ST_LOGE("drainQueueLocked: BufferQueue is not connected!");
735 return NO_INIT;
736 }
737 }
738 return NO_ERROR;
739}
740
741status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
742 status_t err = drainQueueLocked();
743 if (err == NO_ERROR) {
744 if (mSynchronousMode) {
745 freeAllBuffersLocked();
746 } else {
747 freeAllBuffersExceptHeadLocked();
748 }
749 }
750 return err;
751}
752
753}; // namespace android