BufferQueue.cpp revision 6b091c53000c843211c218ce40287a7edca9bc63
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 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 723