widget/gonk/nativewindow/GonkBufferQueueKK.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Copyright (C) 2012 The Android Open Source Project
michael@0 3 * Copyright (C) 2013 Mozilla Foundation
michael@0 4 *
michael@0 5 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 6 * you may not use this file except in compliance with the License.
michael@0 7 * You may obtain a copy of the License at
michael@0 8 *
michael@0 9 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 10 *
michael@0 11 * Unless required by applicable law or agreed to in writing, software
michael@0 12 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 14 * See the License for the specific language governing permissions and
michael@0 15 * limitations under the License.
michael@0 16 */
michael@0 17
michael@0 18 #define LOG_TAG "GonkBufferQueue"
michael@0 19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
michael@0 20 #define LOG_NDEBUG 0
michael@0 21
michael@0 22 #define GL_GLEXT_PROTOTYPES
michael@0 23 #define EGL_EGLEXT_PROTOTYPES
michael@0 24
michael@0 25 #include <utils/Log.h>
michael@0 26 #include <utils/Trace.h>
michael@0 27 #include <utils/CallStack.h>
michael@0 28 #include <cutils/compiler.h>
michael@0 29
michael@0 30 #include "mozilla/layers/GrallocTextureClient.h"
michael@0 31 #include "mozilla/layers/ImageBridgeChild.h"
michael@0 32 #include "GonkBufferQueueKK.h"
michael@0 33
michael@0 34 // Macros for including the GonkBufferQueue name in log messages
michael@0 35 #define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
michael@0 36 #define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
michael@0 37 #define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
michael@0 38 #define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
michael@0 39 #define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
michael@0 40
michael@0 41 #define ATRACE_BUFFER_INDEX(index)
michael@0 42
michael@0 43 using namespace mozilla;
michael@0 44 using namespace mozilla::gfx;
michael@0 45 using namespace mozilla::layers;
michael@0 46
michael@0 47 namespace android {
michael@0 48
michael@0 49 // Get an ID that's unique within this process.
michael@0 50 static int32_t createProcessUniqueId() {
michael@0 51 static volatile int32_t globalCounter = 0;
michael@0 52 return android_atomic_inc(&globalCounter);
michael@0 53 }
michael@0 54
michael@0 55 static const char* scalingModeName(int scalingMode) {
michael@0 56 switch (scalingMode) {
michael@0 57 case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
michael@0 58 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
michael@0 59 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
michael@0 60 default: return "Unknown";
michael@0 61 }
michael@0 62 }
michael@0 63
michael@0 64 class nsProxyReleaseTask : public Task
michael@0 65 {
michael@0 66 public:
michael@0 67 nsProxyReleaseTask(TextureClient* aClient)
michael@0 68 : mTextureClient(aClient) {
michael@0 69 }
michael@0 70
michael@0 71 virtual void Run() MOZ_OVERRIDE
michael@0 72 {
michael@0 73 mTextureClient = nullptr;
michael@0 74 }
michael@0 75
michael@0 76 private:
michael@0 77 mozilla::RefPtr<TextureClient> mTextureClient;
michael@0 78 };
michael@0 79
michael@0 80 GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode,
michael@0 81 const sp<IGraphicBufferAlloc>& allocator) :
michael@0 82 mDefaultWidth(1),
michael@0 83 mDefaultHeight(1),
michael@0 84 mMaxAcquiredBufferCount(1),
michael@0 85 mDefaultMaxBufferCount(2),
michael@0 86 mOverrideMaxBufferCount(0),
michael@0 87 // mSynchronousMode(true), // GonkBufferQueue always works in sync mode.
michael@0 88 mConsumerControlledByApp(false),
michael@0 89 mDequeueBufferCannotBlock(false),
michael@0 90 mUseAsyncBuffer(true),
michael@0 91 mConnectedApi(NO_CONNECTED_API),
michael@0 92 mAbandoned(false),
michael@0 93 mFrameCounter(0),
michael@0 94 mBufferHasBeenQueued(false),
michael@0 95 mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
michael@0 96 mConsumerUsageBits(0),
michael@0 97 mTransformHint(0)
michael@0 98 {
michael@0 99 // Choose a name using the PID and a process-unique ID.
michael@0 100 mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
michael@0 101
michael@0 102 ST_LOGV("GonkBufferQueue");
michael@0 103 }
michael@0 104
michael@0 105 GonkBufferQueue::~GonkBufferQueue() {
michael@0 106 ST_LOGV("~GonkBufferQueue");
michael@0 107 }
michael@0 108
michael@0 109 status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) {
michael@0 110 if (count < 2 || count > NUM_BUFFER_SLOTS)
michael@0 111 return BAD_VALUE;
michael@0 112
michael@0 113 mDefaultMaxBufferCount = count;
michael@0 114 mDequeueCondition.broadcast();
michael@0 115
michael@0 116 return NO_ERROR;
michael@0 117 }
michael@0 118
michael@0 119 void GonkBufferQueue::setConsumerName(const String8& name) {
michael@0 120 Mutex::Autolock lock(mMutex);
michael@0 121 mConsumerName = name;
michael@0 122 }
michael@0 123
michael@0 124 status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
michael@0 125 Mutex::Autolock lock(mMutex);
michael@0 126 mDefaultBufferFormat = defaultFormat;
michael@0 127 return NO_ERROR;
michael@0 128 }
michael@0 129
michael@0 130 status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) {
michael@0 131 Mutex::Autolock lock(mMutex);
michael@0 132 mConsumerUsageBits = usage;
michael@0 133 return NO_ERROR;
michael@0 134 }
michael@0 135
michael@0 136 status_t GonkBufferQueue::setTransformHint(uint32_t hint) {
michael@0 137 ST_LOGV("setTransformHint: %02x", hint);
michael@0 138 Mutex::Autolock lock(mMutex);
michael@0 139 mTransformHint = hint;
michael@0 140 return NO_ERROR;
michael@0 141 }
michael@0 142
michael@0 143 TemporaryRef<TextureClient>
michael@0 144 GonkBufferQueue::getTextureClientFromBuffer(ANativeWindowBuffer* buffer)
michael@0 145 {
michael@0 146 Mutex::Autolock _l(mMutex);
michael@0 147 if (buffer == NULL) {
michael@0 148 ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
michael@0 149 return nullptr;
michael@0 150 }
michael@0 151
michael@0 152 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 153 if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) {
michael@0 154 return mSlots[i].mTextureClient;
michael@0 155 }
michael@0 156 }
michael@0 157 ST_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
michael@0 158 return nullptr;
michael@0 159 }
michael@0 160
michael@0 161 int GonkBufferQueue::getSlotFromTextureClientLocked(
michael@0 162 TextureClient* client) const
michael@0 163 {
michael@0 164 if (client == NULL) {
michael@0 165 ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
michael@0 166 return BAD_VALUE;
michael@0 167 }
michael@0 168
michael@0 169 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 170 if (mSlots[i].mTextureClient == client) {
michael@0 171 return i;
michael@0 172 }
michael@0 173 }
michael@0 174 ST_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client);
michael@0 175 return BAD_VALUE;
michael@0 176 }
michael@0 177
michael@0 178 status_t GonkBufferQueue::setBufferCount(int bufferCount) {
michael@0 179 ST_LOGV("setBufferCount: count=%d", bufferCount);
michael@0 180
michael@0 181 sp<IConsumerListener> listener;
michael@0 182 {
michael@0 183 Mutex::Autolock lock(mMutex);
michael@0 184
michael@0 185 if (mAbandoned) {
michael@0 186 ST_LOGE("setBufferCount: GonkBufferQueue has been abandoned!");
michael@0 187 return NO_INIT;
michael@0 188 }
michael@0 189 if (bufferCount > NUM_BUFFER_SLOTS) {
michael@0 190 ST_LOGE("setBufferCount: bufferCount too large (max %d)",
michael@0 191 NUM_BUFFER_SLOTS);
michael@0 192 return BAD_VALUE;
michael@0 193 }
michael@0 194
michael@0 195 // Error out if the user has dequeued buffers
michael@0 196 for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) {
michael@0 197 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
michael@0 198 ST_LOGE("setBufferCount: client owns some buffers");
michael@0 199 return -EINVAL;
michael@0 200 }
michael@0 201 }
michael@0 202
michael@0 203 if (bufferCount == 0) {
michael@0 204 mOverrideMaxBufferCount = 0;
michael@0 205 mDequeueCondition.broadcast();
michael@0 206 return NO_ERROR;
michael@0 207 }
michael@0 208
michael@0 209 // fine to assume async to false before we're setting the buffer count
michael@0 210 const int minBufferSlots = getMinMaxBufferCountLocked(false);
michael@0 211 if (bufferCount < minBufferSlots) {
michael@0 212 ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
michael@0 213 "minimum (%d)", bufferCount, minBufferSlots);
michael@0 214 return BAD_VALUE;
michael@0 215 }
michael@0 216
michael@0 217 // here we're guaranteed that the client doesn't have dequeued buffers
michael@0 218 // and will release all of its buffer references. We don't clear the
michael@0 219 // queue, however, so currently queued buffers still get displayed.
michael@0 220 // XXX: Should this use drainQueueAndFreeBuffersLocked instead?
michael@0 221 freeAllBuffersLocked();
michael@0 222 mOverrideMaxBufferCount = bufferCount;
michael@0 223 mDequeueCondition.broadcast();
michael@0 224 listener = mConsumerListener;
michael@0 225 } // scope for lock
michael@0 226
michael@0 227 if (listener != NULL) {
michael@0 228 listener->onBuffersReleased();
michael@0 229 }
michael@0 230
michael@0 231 return NO_ERROR;
michael@0 232 }
michael@0 233
michael@0 234 int GonkBufferQueue::query(int what, int* outValue)
michael@0 235 {
michael@0 236 ATRACE_CALL();
michael@0 237 Mutex::Autolock lock(mMutex);
michael@0 238
michael@0 239 if (mAbandoned) {
michael@0 240 ST_LOGE("query: GonkBufferQueue has been abandoned!");
michael@0 241 return NO_INIT;
michael@0 242 }
michael@0 243
michael@0 244 int value;
michael@0 245 switch (what) {
michael@0 246 case NATIVE_WINDOW_WIDTH:
michael@0 247 value = mDefaultWidth;
michael@0 248 break;
michael@0 249 case NATIVE_WINDOW_HEIGHT:
michael@0 250 value = mDefaultHeight;
michael@0 251 break;
michael@0 252 case NATIVE_WINDOW_FORMAT:
michael@0 253 value = mDefaultBufferFormat;
michael@0 254 break;
michael@0 255 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
michael@0 256 value = getMinUndequeuedBufferCount(false);
michael@0 257 break;
michael@0 258 case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
michael@0 259 value = (mQueue.size() >= 2);
michael@0 260 break;
michael@0 261 case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
michael@0 262 value = mConsumerUsageBits;
michael@0 263 break;
michael@0 264 default:
michael@0 265 return BAD_VALUE;
michael@0 266 }
michael@0 267 outValue[0] = value;
michael@0 268 return NO_ERROR;
michael@0 269 }
michael@0 270
michael@0 271 status_t GonkBufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
michael@0 272 ATRACE_CALL();
michael@0 273 ST_LOGV("requestBuffer: slot=%d", slot);
michael@0 274 Mutex::Autolock lock(mMutex);
michael@0 275 if (mAbandoned) {
michael@0 276 ST_LOGE("requestBuffer: GonkBufferQueue has been abandoned!");
michael@0 277 return NO_INIT;
michael@0 278 }
michael@0 279 if (slot < 0 || slot >= NUM_BUFFER_SLOTS) {
michael@0 280 ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
michael@0 281 NUM_BUFFER_SLOTS, slot);
michael@0 282 return BAD_VALUE;
michael@0 283 } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
michael@0 284 ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
michael@0 285 slot, mSlots[slot].mBufferState);
michael@0 286 return BAD_VALUE;
michael@0 287 }
michael@0 288 mSlots[slot].mRequestBufferCalled = true;
michael@0 289 *buf = mSlots[slot].mGraphicBuffer;
michael@0 290 return NO_ERROR;
michael@0 291 }
michael@0 292
michael@0 293 status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async,
michael@0 294 uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
michael@0 295 ATRACE_CALL();
michael@0 296 ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
michael@0 297
michael@0 298 if ((w && !h) || (!w && h)) {
michael@0 299 ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
michael@0 300 return BAD_VALUE;
michael@0 301 }
michael@0 302
michael@0 303 status_t returnFlags(OK);
michael@0 304 int buf = INVALID_BUFFER_SLOT;
michael@0 305
michael@0 306 { // Scope for the lock
michael@0 307 Mutex::Autolock lock(mMutex);
michael@0 308
michael@0 309 if (format == 0) {
michael@0 310 format = mDefaultBufferFormat;
michael@0 311 }
michael@0 312 // turn on usage bits the consumer requested
michael@0 313 usage |= mConsumerUsageBits;
michael@0 314
michael@0 315 int found = -1;
michael@0 316 bool tryAgain = true;
michael@0 317 while (tryAgain) {
michael@0 318 if (mAbandoned) {
michael@0 319 ST_LOGE("dequeueBuffer: GonkBufferQueue has been abandoned!");
michael@0 320 return NO_INIT;
michael@0 321 }
michael@0 322
michael@0 323 const int maxBufferCount = getMaxBufferCountLocked(async);
michael@0 324 if (async && mOverrideMaxBufferCount) {
michael@0 325 // FIXME: some drivers are manually setting the buffer-count (which they
michael@0 326 // shouldn't), so we do this extra test here to handle that case.
michael@0 327 // This is TEMPORARY, until we get this fixed.
michael@0 328 if (mOverrideMaxBufferCount < maxBufferCount) {
michael@0 329 ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override");
michael@0 330 return BAD_VALUE;
michael@0 331 }
michael@0 332 }
michael@0 333
michael@0 334 // Free up any buffers that are in slots beyond the max buffer
michael@0 335 // count.
michael@0 336 //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
michael@0 337 // assert(mSlots[i].mBufferState == BufferSlot::FREE);
michael@0 338 // if (mSlots[i].mGraphicBuffer != NULL) {
michael@0 339 // freeBufferLocked(i);
michael@0 340 // returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
michael@0 341 // }
michael@0 342 //}
michael@0 343
michael@0 344 // look for a free buffer to give to the client
michael@0 345 found = INVALID_BUFFER_SLOT;
michael@0 346 int dequeuedCount = 0;
michael@0 347 int acquiredCount = 0;
michael@0 348 for (int i = 0; i < maxBufferCount; i++) {
michael@0 349 const int state = mSlots[i].mBufferState;
michael@0 350 switch (state) {
michael@0 351 case BufferSlot::DEQUEUED:
michael@0 352 dequeuedCount++;
michael@0 353 break;
michael@0 354 case BufferSlot::ACQUIRED:
michael@0 355 acquiredCount++;
michael@0 356 break;
michael@0 357 case BufferSlot::FREE:
michael@0 358 /* We return the oldest of the free buffers to avoid
michael@0 359 * stalling the producer if possible. This is because
michael@0 360 * the consumer may still have pending reads of the
michael@0 361 * buffers in flight.
michael@0 362 */
michael@0 363 if ((found < 0) ||
michael@0 364 mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
michael@0 365 found = i;
michael@0 366 }
michael@0 367 break;
michael@0 368 }
michael@0 369 }
michael@0 370
michael@0 371 // clients are not allowed to dequeue more than one buffer
michael@0 372 // if they didn't set a buffer count.
michael@0 373 if (!mOverrideMaxBufferCount && dequeuedCount) {
michael@0 374 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
michael@0 375 "setting the buffer count");
michael@0 376 return -EINVAL;
michael@0 377 }
michael@0 378
michael@0 379 // See whether a buffer has been queued since the last
michael@0 380 // setBufferCount so we know whether to perform the min undequeued
michael@0 381 // buffers check below.
michael@0 382 if (mBufferHasBeenQueued) {
michael@0 383 // make sure the client is not trying to dequeue more buffers
michael@0 384 // than allowed.
michael@0 385 const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
michael@0 386 const int minUndequeuedCount = getMinUndequeuedBufferCount(async);
michael@0 387 if (newUndequeuedCount < minUndequeuedCount) {
michael@0 388 ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
michael@0 389 "exceeded (dequeued=%d undequeudCount=%d)",
michael@0 390 minUndequeuedCount, dequeuedCount,
michael@0 391 newUndequeuedCount);
michael@0 392 return -EBUSY;
michael@0 393 }
michael@0 394 }
michael@0 395
michael@0 396 // If no buffer is found, wait for a buffer to be released or for
michael@0 397 // the max buffer count to change.
michael@0 398 tryAgain = found == INVALID_BUFFER_SLOT;
michael@0 399 if (tryAgain) {
michael@0 400 // return an error if we're in "cannot block" mode (producer and consumer
michael@0 401 // are controlled by the application) -- however, the consumer is allowed
michael@0 402 // to acquire briefly an extra buffer (which could cause us to have to wait here)
michael@0 403 // and that's okay because we know the wait will be brief (it happens
michael@0 404 // if we dequeue a buffer while the consumer has acquired one but not released
michael@0 405 // the old one yet -- for e.g.: see GLConsumer::updateTexImage()).
michael@0 406 if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) {
michael@0 407 ST_LOGE("dequeueBuffer: would block! returning an error instead.");
michael@0 408 return WOULD_BLOCK;
michael@0 409 }
michael@0 410 mDequeueCondition.wait(mMutex);
michael@0 411 }
michael@0 412 }
michael@0 413
michael@0 414
michael@0 415 if (found == INVALID_BUFFER_SLOT) {
michael@0 416 // This should not happen.
michael@0 417 ST_LOGE("dequeueBuffer: no available buffer slots");
michael@0 418 return -EBUSY;
michael@0 419 }
michael@0 420
michael@0 421 buf = found;
michael@0 422 *outBuf = found;
michael@0 423
michael@0 424 const bool useDefaultSize = !w && !h;
michael@0 425 if (useDefaultSize) {
michael@0 426 // use the default size
michael@0 427 w = mDefaultWidth;
michael@0 428 h = mDefaultHeight;
michael@0 429 }
michael@0 430
michael@0 431 mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
michael@0 432
michael@0 433 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
michael@0 434 if ((buffer == NULL) ||
michael@0 435 (uint32_t(buffer->width) != w) ||
michael@0 436 (uint32_t(buffer->height) != h) ||
michael@0 437 (uint32_t(buffer->format) != format) ||
michael@0 438 ((uint32_t(buffer->usage) & usage) != usage))
michael@0 439 {
michael@0 440 mSlots[buf].mAcquireCalled = false;
michael@0 441 mSlots[buf].mGraphicBuffer = NULL;
michael@0 442 mSlots[buf].mRequestBufferCalled = false;
michael@0 443 mSlots[buf].mFence = Fence::NO_FENCE;
michael@0 444 if (mSlots[buf].mTextureClient) {
michael@0 445 mSlots[buf].mTextureClient->ClearRecycleCallback();
michael@0 446 // release TextureClient in ImageBridge thread
michael@0 447 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient);
michael@0 448 mSlots[buf].mTextureClient = NULL;
michael@0 449 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
michael@0 450 }
michael@0 451 returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
michael@0 452 }
michael@0 453
michael@0 454
michael@0 455 if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) {
michael@0 456 ST_LOGE("dequeueBuffer: about to return a NULL fence from mSlot. "
michael@0 457 "buf=%d, w=%d, h=%d, format=%d",
michael@0 458 buf, buffer->width, buffer->height, buffer->format);
michael@0 459 }
michael@0 460 *outFence = mSlots[buf].mFence;
michael@0 461 mSlots[buf].mFence = Fence::NO_FENCE;
michael@0 462 } // end lock scope
michael@0 463
michael@0 464 sp<GraphicBuffer> graphicBuffer;
michael@0 465 if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
michael@0 466 RefPtr<GrallocTextureClientOGL> textureClient =
michael@0 467 new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(),
michael@0 468 gfx::SurfaceFormat::UNKNOWN,
michael@0 469 gfx::BackendType::NONE,
michael@0 470 TEXTURE_DEALLOCATE_CLIENT);
michael@0 471 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
michael@0 472 bool result = textureClient->AllocateGralloc(IntSize(w, h), format, usage);
michael@0 473 sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer();
michael@0 474 if (!result || !graphicBuffer.get()) {
michael@0 475 ST_LOGE("dequeueBuffer: failed to alloc gralloc buffer");
michael@0 476 return -ENOMEM;
michael@0 477 }
michael@0 478
michael@0 479 { // Scope for the lock
michael@0 480 Mutex::Autolock lock(mMutex);
michael@0 481
michael@0 482 if (mAbandoned) {
michael@0 483 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
michael@0 484 return NO_INIT;
michael@0 485 }
michael@0 486
michael@0 487 mSlots[buf].mGraphicBuffer = graphicBuffer;
michael@0 488 mSlots[buf].mTextureClient = textureClient;
michael@0 489 ST_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
michael@0 490 mSlots[buf].mGraphicBuffer->handle);
michael@0 491
michael@0 492 }
michael@0 493
michael@0 494 }
michael@0 495
michael@0 496 ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf,
michael@0 497 mSlots[*outBuf].mFrameNumber,
michael@0 498 mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
michael@0 499
michael@0 500 return returnFlags;
michael@0 501 }
michael@0 502
michael@0 503 status_t GonkBufferQueue::queueBuffer(int buf,
michael@0 504 const QueueBufferInput& input, QueueBufferOutput* output) {
michael@0 505 ATRACE_CALL();
michael@0 506
michael@0 507 Rect crop;
michael@0 508 uint32_t transform;
michael@0 509 int scalingMode;
michael@0 510 int64_t timestamp;
michael@0 511 bool isAutoTimestamp;
michael@0 512 bool async;
michael@0 513 sp<Fence> fence;
michael@0 514
michael@0 515 input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode, &transform,
michael@0 516 &async, &fence);
michael@0 517
michael@0 518 if (fence == NULL) {
michael@0 519 ST_LOGE("queueBuffer: fence is NULL");
michael@0 520 return BAD_VALUE;
michael@0 521 }
michael@0 522
michael@0 523 ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
michael@0 524 "scale=%s",
michael@0 525 buf, timestamp, crop.left, crop.top, crop.right, crop.bottom,
michael@0 526 transform, scalingModeName(scalingMode));
michael@0 527
michael@0 528 switch (scalingMode) {
michael@0 529 case NATIVE_WINDOW_SCALING_MODE_FREEZE:
michael@0 530 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
michael@0 531 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
michael@0 532 case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
michael@0 533 break;
michael@0 534 default:
michael@0 535 ST_LOGE("unknown scaling mode: %d", scalingMode);
michael@0 536 return -EINVAL;
michael@0 537 }
michael@0 538
michael@0 539 sp<IConsumerListener> listener;
michael@0 540
michael@0 541 { // scope for the lock
michael@0 542 Mutex::Autolock lock(mMutex);
michael@0 543
michael@0 544 if (mAbandoned) {
michael@0 545 ST_LOGE("queueBuffer: GonkBufferQueue has been abandoned!");
michael@0 546 return NO_INIT;
michael@0 547 }
michael@0 548
michael@0 549 const int maxBufferCount = getMaxBufferCountLocked(async);
michael@0 550 if (async && mOverrideMaxBufferCount) {
michael@0 551 // FIXME: some drivers are manually setting the buffer-count (which they
michael@0 552 // shouldn't), so we do this extra test here to handle that case.
michael@0 553 // This is TEMPORARY, until we get this fixed.
michael@0 554 if (mOverrideMaxBufferCount < maxBufferCount) {
michael@0 555 ST_LOGE("queueBuffer: async mode is invalid with buffercount override");
michael@0 556 return BAD_VALUE;
michael@0 557 }
michael@0 558 }
michael@0 559 if (buf < 0 || buf >= maxBufferCount) {
michael@0 560 ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
michael@0 561 maxBufferCount, buf);
michael@0 562 return -EINVAL;
michael@0 563 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
michael@0 564 ST_LOGE("queueBuffer: slot %d is not owned by the client "
michael@0 565 "(state=%d)", buf, mSlots[buf].mBufferState);
michael@0 566 return -EINVAL;
michael@0 567 } else if (!mSlots[buf].mRequestBufferCalled) {
michael@0 568 ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
michael@0 569 "buffer", buf);
michael@0 570 return -EINVAL;
michael@0 571 }
michael@0 572
michael@0 573 ST_LOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] "
michael@0 574 "tr=%#x scale=%s",
michael@0 575 buf, mFrameCounter + 1, timestamp,
michael@0 576 crop.left, crop.top, crop.right, crop.bottom,
michael@0 577 transform, scalingModeName(scalingMode));
michael@0 578
michael@0 579 const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);
michael@0 580 Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
michael@0 581 Rect croppedCrop;
michael@0 582 crop.intersect(bufferRect, &croppedCrop);
michael@0 583 if (croppedCrop != crop) {
michael@0 584 ST_LOGE("queueBuffer: crop rect is not contained within the "
michael@0 585 "buffer in slot %d", buf);
michael@0 586 return -EINVAL;
michael@0 587 }
michael@0 588
michael@0 589 mSlots[buf].mFence = fence;
michael@0 590 mSlots[buf].mBufferState = BufferSlot::QUEUED;
michael@0 591 mFrameCounter++;
michael@0 592 mSlots[buf].mFrameNumber = mFrameCounter;
michael@0 593
michael@0 594 BufferItem item;
michael@0 595 item.mAcquireCalled = mSlots[buf].mAcquireCalled;
michael@0 596 item.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
michael@0 597 item.mCrop = crop;
michael@0 598 item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
michael@0 599 item.mTransformToDisplayInverse = bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
michael@0 600 item.mScalingMode = scalingMode;
michael@0 601 item.mTimestamp = timestamp;
michael@0 602 item.mIsAutoTimestamp = isAutoTimestamp;
michael@0 603 item.mFrameNumber = mFrameCounter;
michael@0 604 item.mBuf = buf;
michael@0 605 item.mFence = fence;
michael@0 606 item.mIsDroppable = mDequeueBufferCannotBlock || async;
michael@0 607
michael@0 608 if (mQueue.empty()) {
michael@0 609 // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and
michael@0 610 // simply queue this buffer.
michael@0 611 mQueue.push_back(item);
michael@0 612 listener = mConsumerListener;
michael@0 613 } else {
michael@0 614 // when the queue is not empty, we need to look at the front buffer
michael@0 615 // state and see if we need to replace it.
michael@0 616 Fifo::iterator front(mQueue.begin());
michael@0 617 if (front->mIsDroppable) {
michael@0 618 // buffer slot currently queued is marked free if still tracked
michael@0 619 if (stillTracking(front)) {
michael@0 620 mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
michael@0 621 // reset the frame number of the freed buffer so that it is the first in
michael@0 622 // line to be dequeued again.
michael@0 623 mSlots[front->mBuf].mFrameNumber = 0;
michael@0 624 }
michael@0 625 // and we record the new buffer in the queued list
michael@0 626 *front = item;
michael@0 627 } else {
michael@0 628 mQueue.push_back(item);
michael@0 629 listener = mConsumerListener;
michael@0 630 }
michael@0 631 }
michael@0 632
michael@0 633 mBufferHasBeenQueued = true;
michael@0 634 mDequeueCondition.broadcast();
michael@0 635
michael@0 636 output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,
michael@0 637 mQueue.size());
michael@0 638
michael@0 639 } // scope for the lock
michael@0 640
michael@0 641 // call back without lock held
michael@0 642 if (listener != 0) {
michael@0 643 listener->onFrameAvailable();
michael@0 644 }
michael@0 645 return NO_ERROR;
michael@0 646 }
michael@0 647
michael@0 648 void GonkBufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
michael@0 649 ATRACE_CALL();
michael@0 650 ST_LOGV("cancelBuffer: slot=%d", buf);
michael@0 651 Mutex::Autolock lock(mMutex);
michael@0 652
michael@0 653 if (mAbandoned) {
michael@0 654 ST_LOGW("cancelBuffer: GonkBufferQueue has been abandoned!");
michael@0 655 return;
michael@0 656 }
michael@0 657
michael@0 658 if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
michael@0 659 ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
michael@0 660 NUM_BUFFER_SLOTS, buf);
michael@0 661 return;
michael@0 662 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
michael@0 663 ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
michael@0 664 buf, mSlots[buf].mBufferState);
michael@0 665 return;
michael@0 666 } else if (fence == NULL) {
michael@0 667 ST_LOGE("cancelBuffer: fence is NULL");
michael@0 668 return;
michael@0 669 }
michael@0 670 mSlots[buf].mBufferState = BufferSlot::FREE;
michael@0 671 mSlots[buf].mFrameNumber = 0;
michael@0 672 mSlots[buf].mFence = fence;
michael@0 673 mDequeueCondition.broadcast();
michael@0 674 }
michael@0 675
michael@0 676
michael@0 677 status_t GonkBufferQueue::connect(const sp<IBinder>& token,
michael@0 678 int api, bool producerControlledByApp, QueueBufferOutput* output) {
michael@0 679 ATRACE_CALL();
michael@0 680 ST_LOGV("connect: api=%d producerControlledByApp=%s", api,
michael@0 681 producerControlledByApp ? "true" : "false");
michael@0 682 Mutex::Autolock lock(mMutex);
michael@0 683
michael@0 684 retry:
michael@0 685 if (mAbandoned) {
michael@0 686 ST_LOGE("connect: GonkBufferQueue has been abandoned!");
michael@0 687 return NO_INIT;
michael@0 688 }
michael@0 689
michael@0 690 if (mConsumerListener == NULL) {
michael@0 691 ST_LOGE("connect: GonkBufferQueue has no consumer!");
michael@0 692 return NO_INIT;
michael@0 693 }
michael@0 694
michael@0 695 if (mConnectedApi != NO_CONNECTED_API) {
michael@0 696 ST_LOGE("connect: already connected (cur=%d, req=%d)",
michael@0 697 mConnectedApi, api);
michael@0 698 return -EINVAL;
michael@0 699 }
michael@0 700
michael@0 701 // If we disconnect and reconnect quickly, we can be in a state where our slots are
michael@0 702 // empty but we have many buffers in the queue. This can cause us to run out of
michael@0 703 // memory if we outrun the consumer. Wait here if it looks like we have too many
michael@0 704 // buffers queued up.
michael@0 705 int maxBufferCount = getMaxBufferCountLocked(false); // worst-case, i.e. largest value
michael@0 706 if (mQueue.size() > (size_t) maxBufferCount) {
michael@0 707 // TODO: make this bound tighter?
michael@0 708 ST_LOGV("queue size is %d, waiting", mQueue.size());
michael@0 709 mDequeueCondition.wait(mMutex);
michael@0 710 goto retry;
michael@0 711 }
michael@0 712
michael@0 713 int err = NO_ERROR;
michael@0 714 switch (api) {
michael@0 715 case NATIVE_WINDOW_API_EGL:
michael@0 716 case NATIVE_WINDOW_API_CPU:
michael@0 717 case NATIVE_WINDOW_API_MEDIA:
michael@0 718 case NATIVE_WINDOW_API_CAMERA:
michael@0 719 mConnectedApi = api;
michael@0 720 output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size());
michael@0 721
michael@0 722 // set-up a death notification so that we can disconnect
michael@0 723 // automatically when/if the remote producer dies.
michael@0 724 if (token != NULL && token->remoteBinder() != NULL) {
michael@0 725 status_t err = token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
michael@0 726 if (err == NO_ERROR) {
michael@0 727 mConnectedProducerToken = token;
michael@0 728 } else {
michael@0 729 ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err);
michael@0 730 }
michael@0 731 }
michael@0 732 break;
michael@0 733 default:
michael@0 734 err = -EINVAL;
michael@0 735 break;
michael@0 736 }
michael@0 737
michael@0 738 mBufferHasBeenQueued = false;
michael@0 739 mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
michael@0 740
michael@0 741 return err;
michael@0 742 }
michael@0 743
michael@0 744 void GonkBufferQueue::binderDied(const wp<IBinder>& who) {
michael@0 745 // If we're here, it means that a producer we were connected to died.
michael@0 746 // We're GUARANTEED that we still are connected to it because it has no other way
michael@0 747 // to get disconnected -- or -- we wouldn't be here because we're removing this
michael@0 748 // callback upon disconnect. Therefore, it's okay to read mConnectedApi without
michael@0 749 // synchronization here.
michael@0 750 int api = mConnectedApi;
michael@0 751 this->disconnect(api);
michael@0 752 }
michael@0 753
michael@0 754 status_t GonkBufferQueue::disconnect(int api) {
michael@0 755 ATRACE_CALL();
michael@0 756 ST_LOGV("disconnect: api=%d", api);
michael@0 757
michael@0 758 int err = NO_ERROR;
michael@0 759 sp<IConsumerListener> listener;
michael@0 760
michael@0 761 { // Scope for the lock
michael@0 762 Mutex::Autolock lock(mMutex);
michael@0 763
michael@0 764 if (mAbandoned) {
michael@0 765 // it is not really an error to disconnect after the surface
michael@0 766 // has been abandoned, it should just be a no-op.
michael@0 767 return NO_ERROR;
michael@0 768 }
michael@0 769
michael@0 770 switch (api) {
michael@0 771 case NATIVE_WINDOW_API_EGL:
michael@0 772 case NATIVE_WINDOW_API_CPU:
michael@0 773 case NATIVE_WINDOW_API_MEDIA:
michael@0 774 case NATIVE_WINDOW_API_CAMERA:
michael@0 775 if (mConnectedApi == api) {
michael@0 776 freeAllBuffersLocked();
michael@0 777 mConnectedApi = NO_CONNECTED_API;
michael@0 778 mDequeueCondition.broadcast();
michael@0 779 listener = mConsumerListener;
michael@0 780 } else {
michael@0 781 ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
michael@0 782 mConnectedApi, api);
michael@0 783 err = -EINVAL;
michael@0 784 }
michael@0 785 break;
michael@0 786 default:
michael@0 787 ST_LOGE("disconnect: unknown API %d", api);
michael@0 788 err = -EINVAL;
michael@0 789 break;
michael@0 790 }
michael@0 791 }
michael@0 792
michael@0 793 if (listener != NULL) {
michael@0 794 listener->onBuffersReleased();
michael@0 795 }
michael@0 796
michael@0 797 return err;
michael@0 798 }
michael@0 799
michael@0 800 void GonkBufferQueue::dump(String8& result, const char* prefix) const {
michael@0 801 Mutex::Autolock _l(mMutex);
michael@0 802
michael@0 803 String8 fifo;
michael@0 804 int fifoSize = 0;
michael@0 805 Fifo::const_iterator i(mQueue.begin());
michael@0 806 while (i != mQueue.end()) {
michael@0 807 fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
michael@0 808 "xform=0x%02x, time=%#llx, scale=%s\n",
michael@0 809 i->mBuf, i->mGraphicBuffer.get(),
michael@0 810 i->mCrop.left, i->mCrop.top, i->mCrop.right,
michael@0 811 i->mCrop.bottom, i->mTransform, i->mTimestamp,
michael@0 812 scalingModeName(i->mScalingMode)
michael@0 813 );
michael@0 814 i++;
michael@0 815 fifoSize++;
michael@0 816 }
michael@0 817
michael@0 818
michael@0 819 result.appendFormat(
michael@0 820 "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
michael@0 821 "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
michael@0 822 prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
michael@0 823 mDefaultHeight, mDefaultBufferFormat, mTransformHint,
michael@0 824 fifoSize, fifo.string());
michael@0 825
michael@0 826 struct {
michael@0 827 const char * operator()(int state) const {
michael@0 828 switch (state) {
michael@0 829 case BufferSlot::DEQUEUED: return "DEQUEUED";
michael@0 830 case BufferSlot::QUEUED: return "QUEUED";
michael@0 831 case BufferSlot::FREE: return "FREE";
michael@0 832 case BufferSlot::ACQUIRED: return "ACQUIRED";
michael@0 833 default: return "Unknown";
michael@0 834 }
michael@0 835 }
michael@0 836 } stateName;
michael@0 837
michael@0 838 // just trim the free buffers to not spam the dump
michael@0 839 int maxBufferCount = 0;
michael@0 840 for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) {
michael@0 841 const BufferSlot& slot(mSlots[i]);
michael@0 842 if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) {
michael@0 843 maxBufferCount = i+1;
michael@0 844 break;
michael@0 845 }
michael@0 846 }
michael@0 847
michael@0 848 for (int i=0 ; i<maxBufferCount ; i++) {
michael@0 849 const BufferSlot& slot(mSlots[i]);
michael@0 850 const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
michael@0 851 result.appendFormat(
michael@0 852 "%s%s[%02d:%p] state=%-8s",
michael@0 853 prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(),
michael@0 854 stateName(slot.mBufferState)
michael@0 855 );
michael@0 856
michael@0 857 if (buf != NULL) {
michael@0 858 result.appendFormat(
michael@0 859 ", %p [%4ux%4u:%4u,%3X]",
michael@0 860 buf->handle, buf->width, buf->height, buf->stride,
michael@0 861 buf->format);
michael@0 862 }
michael@0 863 result.append("\n");
michael@0 864 }
michael@0 865 }
michael@0 866
michael@0 867 void GonkBufferQueue::freeAllBuffersLocked()
michael@0 868 {
michael@0 869 ALOGW_IF(!mQueue.isEmpty(),
michael@0 870 "freeAllBuffersLocked called but mQueue is not empty");
michael@0 871 mQueue.clear();
michael@0 872 mBufferHasBeenQueued = false;
michael@0 873 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 874 mSlots[i].mGraphicBuffer = 0;
michael@0 875 if (mSlots[i].mTextureClient) {
michael@0 876 mSlots[i].mTextureClient->ClearRecycleCallback();
michael@0 877 // release TextureClient in ImageBridge thread
michael@0 878 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient);
michael@0 879 mSlots[i].mTextureClient = NULL;
michael@0 880 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
michael@0 881 }
michael@0 882 if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
michael@0 883 mSlots[i].mNeedsCleanupOnRelease = true;
michael@0 884 }
michael@0 885 mSlots[i].mBufferState = BufferSlot::FREE;
michael@0 886 mSlots[i].mFrameNumber = 0;
michael@0 887 mSlots[i].mAcquireCalled = false;
michael@0 888 // destroy fence as GonkBufferQueue now takes ownership
michael@0 889 mSlots[i].mFence = Fence::NO_FENCE;
michael@0 890 }
michael@0 891 }
michael@0 892
michael@0 893 status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) {
michael@0 894 ATRACE_CALL();
michael@0 895 Mutex::Autolock _l(mMutex);
michael@0 896
michael@0 897 // Check that the consumer doesn't currently have the maximum number of
michael@0 898 // buffers acquired. We allow the max buffer count to be exceeded by one
michael@0 899 // buffer, so that the consumer can successfully set up the newly acquired
michael@0 900 // buffer before releasing the old one.
michael@0 901 int numAcquiredBuffers = 0;
michael@0 902 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 903 if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
michael@0 904 numAcquiredBuffers++;
michael@0 905 }
michael@0 906 }
michael@0 907 if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) {
michael@0 908 ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)",
michael@0 909 numAcquiredBuffers, mMaxAcquiredBufferCount);
michael@0 910 return INVALID_OPERATION;
michael@0 911 }
michael@0 912
michael@0 913 // check if queue is empty
michael@0 914 // In asynchronous mode the list is guaranteed to be one buffer
michael@0 915 // deep, while in synchronous mode we use the oldest buffer.
michael@0 916 if (mQueue.empty()) {
michael@0 917 return NO_BUFFER_AVAILABLE;
michael@0 918 }
michael@0 919
michael@0 920 Fifo::iterator front(mQueue.begin());
michael@0 921
michael@0 922 // If expectedPresent is specified, we may not want to return a buffer yet.
michael@0 923 // If it's specified and there's more than one buffer queued, we may
michael@0 924 // want to drop a buffer.
michael@0 925 if (expectedPresent != 0) {
michael@0 926 const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
michael@0 927
michael@0 928 // The "expectedPresent" argument indicates when the buffer is expected
michael@0 929 // to be presented on-screen. If the buffer's desired-present time
michael@0 930 // is earlier (less) than expectedPresent, meaning it'll be displayed
michael@0 931 // on time or possibly late if we show it ASAP, we acquire and return
michael@0 932 // it. If we don't want to display it until after the expectedPresent
michael@0 933 // time, we return PRESENT_LATER without acquiring it.
michael@0 934 //
michael@0 935 // To be safe, we don't defer acquisition if expectedPresent is
michael@0 936 // more than one second in the future beyond the desired present time
michael@0 937 // (i.e. we'd be holding the buffer for a long time).
michael@0 938 //
michael@0 939 // NOTE: code assumes monotonic time values from the system clock are
michael@0 940 // positive.
michael@0 941
michael@0 942 // Start by checking to see if we can drop frames. We skip this check
michael@0 943 // if the timestamps are being auto-generated by Surface -- if the
michael@0 944 // app isn't generating timestamps explicitly, they probably don't
michael@0 945 // want frames to be discarded based on them.
michael@0 946 while (mQueue.size() > 1 && !mQueue[0].mIsAutoTimestamp) {
michael@0 947 // If entry[1] is timely, drop entry[0] (and repeat). We apply
michael@0 948 // an additional criteria here: we only drop the earlier buffer if
michael@0 949 // our desiredPresent falls within +/- 1 second of the expected
michael@0 950 // present. Otherwise, bogus desiredPresent times (e.g. 0 or
michael@0 951 // a small relative timestamp), which normally mean "ignore the
michael@0 952 // timestamp and acquire immediately", would cause us to drop
michael@0 953 // frames.
michael@0 954 //
michael@0 955 // We may want to add an additional criteria: don't drop the
michael@0 956 // earlier buffer if entry[1]'s fence hasn't signaled yet.
michael@0 957 //
michael@0 958 // (Vector front is [0], back is [size()-1])
michael@0 959 const BufferItem& bi(mQueue[1]);
michael@0 960 nsecs_t desiredPresent = bi.mTimestamp;
michael@0 961 if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
michael@0 962 desiredPresent > expectedPresent) {
michael@0 963 // This buffer is set to display in the near future, or
michael@0 964 // desiredPresent is garbage. Either way we don't want to
michael@0 965 // drop the previous buffer just to get this on screen sooner.
michael@0 966 ST_LOGV("pts nodrop: des=%lld expect=%lld (%lld) now=%lld",
michael@0 967 desiredPresent, expectedPresent, desiredPresent - expectedPresent,
michael@0 968 systemTime(CLOCK_MONOTONIC));
michael@0 969 break;
michael@0 970 }
michael@0 971 ST_LOGV("pts drop: queue1des=%lld expect=%lld size=%d",
michael@0 972 desiredPresent, expectedPresent, mQueue.size());
michael@0 973 if (stillTracking(front)) {
michael@0 974 // front buffer is still in mSlots, so mark the slot as free
michael@0 975 mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
michael@0 976 }
michael@0 977 mQueue.erase(front);
michael@0 978 front = mQueue.begin();
michael@0 979 }
michael@0 980
michael@0 981 // See if the front buffer is due.
michael@0 982 nsecs_t desiredPresent = front->mTimestamp;
michael@0 983 if (desiredPresent > expectedPresent &&
michael@0 984 desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
michael@0 985 ST_LOGV("pts defer: des=%lld expect=%lld (%lld) now=%lld",
michael@0 986 desiredPresent, expectedPresent, desiredPresent - expectedPresent,
michael@0 987 systemTime(CLOCK_MONOTONIC));
michael@0 988 return PRESENT_LATER;
michael@0 989 }
michael@0 990
michael@0 991 ST_LOGV("pts accept: des=%lld expect=%lld (%lld) now=%lld",
michael@0 992 desiredPresent, expectedPresent, desiredPresent - expectedPresent,
michael@0 993 systemTime(CLOCK_MONOTONIC));
michael@0 994 }
michael@0 995
michael@0 996 int buf = front->mBuf;
michael@0 997 buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
michael@0 998 buffer->mFrameNumber = mSlots[buf].mFrameNumber;
michael@0 999 buffer->mBuf = buf;
michael@0 1000 buffer->mFence = mSlots[buf].mFence;
michael@0 1001 ATRACE_BUFFER_INDEX(buf);
michael@0 1002
michael@0 1003 ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
michael@0 1004 front->mBuf, front->mFrameNumber,
michael@0 1005 front->mGraphicBuffer->handle);
michael@0 1006 // if front buffer still being tracked update slot state
michael@0 1007 if (stillTracking(front)) {
michael@0 1008 mSlots[buf].mAcquireCalled = true;
michael@0 1009 mSlots[buf].mNeedsCleanupOnRelease = false;
michael@0 1010 mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
michael@0 1011 mSlots[buf].mFence = Fence::NO_FENCE;
michael@0 1012 }
michael@0 1013
michael@0 1014 // If the buffer has previously been acquired by the consumer, set
michael@0 1015 // mGraphicBuffer to NULL to avoid unnecessarily remapping this
michael@0 1016 // buffer on the consumer side.
michael@0 1017 //if (buffer->mAcquireCalled) {
michael@0 1018 // buffer->mGraphicBuffer = NULL;
michael@0 1019 //}
michael@0 1020
michael@0 1021 mQueue.erase(front);
michael@0 1022 mDequeueCondition.broadcast();
michael@0 1023
michael@0 1024 return NO_ERROR;
michael@0 1025 }
michael@0 1026
michael@0 1027 status_t GonkBufferQueue::releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& fence) {
michael@0 1028 ATRACE_CALL();
michael@0 1029
michael@0 1030 if (buf == INVALID_BUFFER_SLOT || fence == NULL) {
michael@0 1031 return BAD_VALUE;
michael@0 1032 }
michael@0 1033
michael@0 1034 Mutex::Autolock _l(mMutex);
michael@0 1035
michael@0 1036 // If the frame number has changed because buffer has been reallocated,
michael@0 1037 // we can ignore this releaseBuffer for the old buffer.
michael@0 1038 //if (frameNumber != mSlots[buf].mFrameNumber) {
michael@0 1039 // return STALE_BUFFER_SLOT;
michael@0 1040 //}
michael@0 1041
michael@0 1042
michael@0 1043 // Internal state consistency checks:
michael@0 1044 // Make sure this buffers hasn't been queued while we were owning it (acquired)
michael@0 1045 Fifo::iterator front(mQueue.begin());
michael@0 1046 Fifo::const_iterator const end(mQueue.end());
michael@0 1047 while (front != end) {
michael@0 1048 if (front->mBuf == buf) {
michael@0 1049 LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been "
michael@0 1050 "acquired", mConsumerName.string(), frameNumber, buf);
michael@0 1051 break; // never reached
michael@0 1052 }
michael@0 1053 front++;
michael@0 1054 }
michael@0 1055
michael@0 1056 // The buffer can now only be released if its in the acquired state
michael@0 1057 if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
michael@0 1058 mSlots[buf].mFence = fence;
michael@0 1059 mSlots[buf].mBufferState = BufferSlot::FREE;
michael@0 1060 } else if (mSlots[buf].mNeedsCleanupOnRelease) {
michael@0 1061 ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState);
michael@0 1062 mSlots[buf].mNeedsCleanupOnRelease = false;
michael@0 1063 return STALE_BUFFER_SLOT;
michael@0 1064 } else {
michael@0 1065 ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState);
michael@0 1066 return -EINVAL;
michael@0 1067 }
michael@0 1068
michael@0 1069 mDequeueCondition.broadcast();
michael@0 1070 return NO_ERROR;
michael@0 1071 }
michael@0 1072
michael@0 1073 status_t GonkBufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener,
michael@0 1074 bool controlledByApp) {
michael@0 1075 ST_LOGV("consumerConnect controlledByApp=%s",
michael@0 1076 controlledByApp ? "true" : "false");
michael@0 1077 Mutex::Autolock lock(mMutex);
michael@0 1078
michael@0 1079 if (mAbandoned) {
michael@0 1080 ST_LOGE("consumerConnect: GonkBufferQueue has been abandoned!");
michael@0 1081 return NO_INIT;
michael@0 1082 }
michael@0 1083 if (consumerListener == NULL) {
michael@0 1084 ST_LOGE("consumerConnect: consumerListener may not be NULL");
michael@0 1085 return BAD_VALUE;
michael@0 1086 }
michael@0 1087
michael@0 1088 mConsumerListener = consumerListener;
michael@0 1089 mConsumerControlledByApp = controlledByApp;
michael@0 1090
michael@0 1091 return NO_ERROR;
michael@0 1092 }
michael@0 1093
michael@0 1094 status_t GonkBufferQueue::consumerDisconnect() {
michael@0 1095 ST_LOGV("consumerDisconnect");
michael@0 1096 Mutex::Autolock lock(mMutex);
michael@0 1097
michael@0 1098 if (mConsumerListener == NULL) {
michael@0 1099 ST_LOGE("consumerDisconnect: No consumer is connected!");
michael@0 1100 return -EINVAL;
michael@0 1101 }
michael@0 1102
michael@0 1103 mAbandoned = true;
michael@0 1104 mConsumerListener = NULL;
michael@0 1105 mQueue.clear();
michael@0 1106 freeAllBuffersLocked();
michael@0 1107 mDequeueCondition.broadcast();
michael@0 1108 return NO_ERROR;
michael@0 1109 }
michael@0 1110
michael@0 1111 status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) {
michael@0 1112 ST_LOGV("getReleasedBuffers");
michael@0 1113 Mutex::Autolock lock(mMutex);
michael@0 1114
michael@0 1115 if (mAbandoned) {
michael@0 1116 ST_LOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!");
michael@0 1117 return NO_INIT;
michael@0 1118 }
michael@0 1119
michael@0 1120 uint32_t mask = 0;
michael@0 1121 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 1122 if (!mSlots[i].mAcquireCalled) {
michael@0 1123 mask |= 1 << i;
michael@0 1124 }
michael@0 1125 }
michael@0 1126
michael@0 1127 // Remove buffers in flight (on the queue) from the mask where acquire has
michael@0 1128 // been called, as the consumer will not receive the buffer address, so
michael@0 1129 // it should not free these slots.
michael@0 1130 Fifo::iterator front(mQueue.begin());
michael@0 1131 while (front != mQueue.end()) {
michael@0 1132 if (front->mAcquireCalled)
michael@0 1133 mask &= ~(1 << front->mBuf);
michael@0 1134 front++;
michael@0 1135 }
michael@0 1136
michael@0 1137 *slotMask = mask;
michael@0 1138
michael@0 1139 ST_LOGV("getReleasedBuffers: returning mask %#x", mask);
michael@0 1140 return NO_ERROR;
michael@0 1141 }
michael@0 1142
michael@0 1143 status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) {
michael@0 1144 ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
michael@0 1145 if (!w || !h) {
michael@0 1146 ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
michael@0 1147 w, h);
michael@0 1148 return BAD_VALUE;
michael@0 1149 }
michael@0 1150
michael@0 1151 Mutex::Autolock lock(mMutex);
michael@0 1152 mDefaultWidth = w;
michael@0 1153 mDefaultHeight = h;
michael@0 1154 return NO_ERROR;
michael@0 1155 }
michael@0 1156
michael@0 1157 status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) {
michael@0 1158 ATRACE_CALL();
michael@0 1159 Mutex::Autolock lock(mMutex);
michael@0 1160 return setDefaultMaxBufferCountLocked(bufferCount);
michael@0 1161 }
michael@0 1162
michael@0 1163 status_t GonkBufferQueue::disableAsyncBuffer() {
michael@0 1164 ATRACE_CALL();
michael@0 1165 Mutex::Autolock lock(mMutex);
michael@0 1166 if (mConsumerListener != NULL) {
michael@0 1167 ST_LOGE("disableAsyncBuffer: consumer already connected!");
michael@0 1168 return INVALID_OPERATION;
michael@0 1169 }
michael@0 1170 mUseAsyncBuffer = false;
michael@0 1171 return NO_ERROR;
michael@0 1172 }
michael@0 1173
michael@0 1174 status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
michael@0 1175 ATRACE_CALL();
michael@0 1176 Mutex::Autolock lock(mMutex);
michael@0 1177 if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) {
michael@0 1178 ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d",
michael@0 1179 maxAcquiredBuffers);
michael@0 1180 return BAD_VALUE;
michael@0 1181 }
michael@0 1182 if (mConnectedApi != NO_CONNECTED_API) {
michael@0 1183 return INVALID_OPERATION;
michael@0 1184 }
michael@0 1185 mMaxAcquiredBufferCount = maxAcquiredBuffers;
michael@0 1186 return NO_ERROR;
michael@0 1187 }
michael@0 1188
michael@0 1189 int GonkBufferQueue::getMinUndequeuedBufferCount(bool async) const {
michael@0 1190 // if dequeueBuffer is allowed to error out, we don't have to
michael@0 1191 // add an extra buffer.
michael@0 1192 if (!mUseAsyncBuffer)
michael@0 1193 return mMaxAcquiredBufferCount;
michael@0 1194
michael@0 1195 // we're in async mode, or we want to prevent the app to
michael@0 1196 // deadlock itself, we throw-in an extra buffer to guarantee it.
michael@0 1197 if (mDequeueBufferCannotBlock || async)
michael@0 1198 return mMaxAcquiredBufferCount + 1;
michael@0 1199
michael@0 1200 return mMaxAcquiredBufferCount;
michael@0 1201 }
michael@0 1202
michael@0 1203 int GonkBufferQueue::getMinMaxBufferCountLocked(bool async) const {
michael@0 1204 return getMinUndequeuedBufferCount(async) + 1;
michael@0 1205 }
michael@0 1206
michael@0 1207 int GonkBufferQueue::getMaxBufferCountLocked(bool async) const {
michael@0 1208 int minMaxBufferCount = getMinMaxBufferCountLocked(async);
michael@0 1209
michael@0 1210 int maxBufferCount = mDefaultMaxBufferCount;
michael@0 1211 if (maxBufferCount < minMaxBufferCount) {
michael@0 1212 maxBufferCount = minMaxBufferCount;
michael@0 1213 }
michael@0 1214 if (mOverrideMaxBufferCount != 0) {
michael@0 1215 assert(mOverrideMaxBufferCount >= minMaxBufferCount);
michael@0 1216 maxBufferCount = mOverrideMaxBufferCount;
michael@0 1217 }
michael@0 1218
michael@0 1219 // Any buffers that are dequeued by the producer or sitting in the queue
michael@0 1220 // waiting to be consumed need to have their slots preserved. Such
michael@0 1221 // buffers will temporarily keep the max buffer count up until the slots
michael@0 1222 // no longer need to be preserved.
michael@0 1223 for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
michael@0 1224 BufferSlot::BufferState state = mSlots[i].mBufferState;
michael@0 1225 if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
michael@0 1226 maxBufferCount = i + 1;
michael@0 1227 }
michael@0 1228 }
michael@0 1229
michael@0 1230 return maxBufferCount;
michael@0 1231 }
michael@0 1232
michael@0 1233 bool GonkBufferQueue::stillTracking(const BufferItem *item) const {
michael@0 1234 const BufferSlot &slot = mSlots[item->mBuf];
michael@0 1235
michael@0 1236 ST_LOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, "
michael@0 1237 "slot: { slot=%d/%llu, buffer=%p }",
michael@0 1238 item->mBuf, item->mFrameNumber,
michael@0 1239 (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0),
michael@0 1240 item->mBuf, slot.mFrameNumber,
michael@0 1241 (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0));
michael@0 1242
michael@0 1243 // Compare item with its original buffer slot. We can check the slot
michael@0 1244 // as the buffer would not be moved to a different slot by the producer.
michael@0 1245 return (slot.mGraphicBuffer != NULL &&
michael@0 1246 item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle);
michael@0 1247 }
michael@0 1248
michael@0 1249 GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener(
michael@0 1250 const wp<ConsumerListener>& consumerListener):
michael@0 1251 mConsumerListener(consumerListener) {}
michael@0 1252
michael@0 1253 GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
michael@0 1254
michael@0 1255 void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() {
michael@0 1256 sp<ConsumerListener> listener(mConsumerListener.promote());
michael@0 1257 if (listener != NULL) {
michael@0 1258 listener->onFrameAvailable();
michael@0 1259 }
michael@0 1260 }
michael@0 1261
michael@0 1262 void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() {
michael@0 1263 sp<ConsumerListener> listener(mConsumerListener.promote());
michael@0 1264 if (listener != NULL) {
michael@0 1265 listener->onBuffersReleased();
michael@0 1266 }
michael@0 1267 }
michael@0 1268
michael@0 1269 }; // namespace android

mercurial