widget/gonk/nativewindow/GonkBufferQueueJB.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rwxr-xr-x

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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
michael@0 27 #include "mozilla/layers/GrallocTextureClient.h"
michael@0 28 #include "mozilla/layers/ImageBridgeChild.h"
michael@0 29
michael@0 30 #include "GonkBufferQueueJB.h"
michael@0 31
michael@0 32 // Macros for including the GonkBufferQueue name in log messages
michael@0 33 #define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
michael@0 34 #define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
michael@0 35 #define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
michael@0 36 #define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
michael@0 37 #define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
michael@0 38
michael@0 39 #define ATRACE_BUFFER_INDEX(index)
michael@0 40
michael@0 41 using namespace mozilla;
michael@0 42 using namespace mozilla::gfx;
michael@0 43 using namespace mozilla::layers;
michael@0 44
michael@0 45 namespace android {
michael@0 46
michael@0 47 // Get an ID that's unique within this process.
michael@0 48 static int32_t createProcessUniqueId() {
michael@0 49 static volatile int32_t globalCounter = 0;
michael@0 50 return android_atomic_inc(&globalCounter);
michael@0 51 }
michael@0 52
michael@0 53 static const char* scalingModeName(int scalingMode) {
michael@0 54 switch (scalingMode) {
michael@0 55 case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
michael@0 56 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
michael@0 57 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
michael@0 58 default: return "Unknown";
michael@0 59 }
michael@0 60 }
michael@0 61
michael@0 62 class nsProxyReleaseTask : public Task
michael@0 63 {
michael@0 64 public:
michael@0 65 nsProxyReleaseTask(TextureClient* aClient)
michael@0 66 : mTextureClient(aClient) {
michael@0 67 }
michael@0 68
michael@0 69 virtual void Run() MOZ_OVERRIDE
michael@0 70 {
michael@0 71 mTextureClient = nullptr;
michael@0 72 }
michael@0 73
michael@0 74 private:
michael@0 75 mozilla::RefPtr<TextureClient> mTextureClient;
michael@0 76 };
michael@0 77
michael@0 78 GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode,
michael@0 79 const sp<IGraphicBufferAlloc>& allocator) :
michael@0 80 mDefaultWidth(1),
michael@0 81 mDefaultHeight(1),
michael@0 82 mMaxAcquiredBufferCount(1),
michael@0 83 mDefaultMaxBufferCount(2),
michael@0 84 mOverrideMaxBufferCount(0),
michael@0 85 mSynchronousMode(true), // GonkBufferQueue always works in sync mode.
michael@0 86 mAllowSynchronousMode(allowSynchronousMode),
michael@0 87 mConnectedApi(NO_CONNECTED_API),
michael@0 88 mAbandoned(false),
michael@0 89 mFrameCounter(0),
michael@0 90 mBufferHasBeenQueued(false),
michael@0 91 mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
michael@0 92 mConsumerUsageBits(0),
michael@0 93 mTransformHint(0)
michael@0 94 {
michael@0 95 // Choose a name using the PID and a process-unique ID.
michael@0 96 mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
michael@0 97
michael@0 98 ST_LOGV("GonkBufferQueue");
michael@0 99 }
michael@0 100
michael@0 101 GonkBufferQueue::~GonkBufferQueue() {
michael@0 102 ST_LOGV("~GonkBufferQueue");
michael@0 103 }
michael@0 104
michael@0 105 status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) {
michael@0 106 if (count < 2 || count > NUM_BUFFER_SLOTS)
michael@0 107 return BAD_VALUE;
michael@0 108
michael@0 109 mDefaultMaxBufferCount = count;
michael@0 110 mDequeueCondition.broadcast();
michael@0 111
michael@0 112 return NO_ERROR;
michael@0 113 }
michael@0 114
michael@0 115 bool GonkBufferQueue::isSynchronousMode() const {
michael@0 116 Mutex::Autolock lock(mMutex);
michael@0 117 return mSynchronousMode;
michael@0 118 }
michael@0 119
michael@0 120 void GonkBufferQueue::setConsumerName(const String8& name) {
michael@0 121 Mutex::Autolock lock(mMutex);
michael@0 122 mConsumerName = name;
michael@0 123 }
michael@0 124
michael@0 125 status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
michael@0 126 Mutex::Autolock lock(mMutex);
michael@0 127 mDefaultBufferFormat = defaultFormat;
michael@0 128 return NO_ERROR;
michael@0 129 }
michael@0 130
michael@0 131 status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) {
michael@0 132 Mutex::Autolock lock(mMutex);
michael@0 133 mConsumerUsageBits = usage;
michael@0 134 return NO_ERROR;
michael@0 135 }
michael@0 136
michael@0 137 status_t GonkBufferQueue::setTransformHint(uint32_t hint) {
michael@0 138 ST_LOGV("setTransformHint: %02x", hint);
michael@0 139 Mutex::Autolock lock(mMutex);
michael@0 140 mTransformHint = hint;
michael@0 141 return NO_ERROR;
michael@0 142 }
michael@0 143
michael@0 144 TemporaryRef<TextureClient>
michael@0 145 GonkBufferQueue::getTextureClientFromBuffer(ANativeWindowBuffer* buffer)
michael@0 146 {
michael@0 147 Mutex::Autolock _l(mMutex);
michael@0 148 if (buffer == NULL) {
michael@0 149 ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
michael@0 150 return nullptr;
michael@0 151 }
michael@0 152
michael@0 153 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 154 if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) {
michael@0 155 return mSlots[i].mTextureClient;
michael@0 156 }
michael@0 157 }
michael@0 158 ST_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
michael@0 159 return nullptr;
michael@0 160 }
michael@0 161
michael@0 162 int GonkBufferQueue::getSlotFromTextureClientLocked(
michael@0 163 TextureClient* client) const
michael@0 164 {
michael@0 165 if (client == NULL) {
michael@0 166 ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
michael@0 167 return BAD_VALUE;
michael@0 168 }
michael@0 169
michael@0 170 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 171 if (mSlots[i].mTextureClient == client) {
michael@0 172 return i;
michael@0 173 }
michael@0 174 }
michael@0 175 ST_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client);
michael@0 176 return BAD_VALUE;
michael@0 177 }
michael@0 178
michael@0 179
michael@0 180 status_t GonkBufferQueue::setBufferCount(int bufferCount) {
michael@0 181 ST_LOGV("setBufferCount: count=%d", bufferCount);
michael@0 182
michael@0 183 sp<ConsumerListener> listener;
michael@0 184 {
michael@0 185 Mutex::Autolock lock(mMutex);
michael@0 186
michael@0 187 if (mAbandoned) {
michael@0 188 ST_LOGE("setBufferCount: GonkBufferQueue has been abandoned!");
michael@0 189 return NO_INIT;
michael@0 190 }
michael@0 191 if (bufferCount > NUM_BUFFER_SLOTS) {
michael@0 192 ST_LOGE("setBufferCount: bufferCount too large (max %d)",
michael@0 193 NUM_BUFFER_SLOTS);
michael@0 194 return BAD_VALUE;
michael@0 195 }
michael@0 196
michael@0 197 // Error out if the user has dequeued buffers
michael@0 198 int maxBufferCount = getMaxBufferCountLocked();
michael@0 199 for (int i=0 ; i<maxBufferCount; i++) {
michael@0 200 if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
michael@0 201 ST_LOGE("setBufferCount: client owns some buffers");
michael@0 202 return -EINVAL;
michael@0 203 }
michael@0 204 }
michael@0 205
michael@0 206 const int minBufferSlots = getMinMaxBufferCountLocked();
michael@0 207 if (bufferCount == 0) {
michael@0 208 mOverrideMaxBufferCount = 0;
michael@0 209 mDequeueCondition.broadcast();
michael@0 210 return NO_ERROR;
michael@0 211 }
michael@0 212
michael@0 213 if (bufferCount < minBufferSlots) {
michael@0 214 ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
michael@0 215 "minimum (%d)", bufferCount, minBufferSlots);
michael@0 216 return BAD_VALUE;
michael@0 217 }
michael@0 218
michael@0 219 // here we're guaranteed that the client doesn't have dequeued buffers
michael@0 220 // and will release all of its buffer references.
michael@0 221 //
michael@0 222 // XXX: Should this use drainQueueAndFreeBuffersLocked instead?
michael@0 223 freeAllBuffersLocked();
michael@0 224 mOverrideMaxBufferCount = bufferCount;
michael@0 225 mBufferHasBeenQueued = false;
michael@0 226 mDequeueCondition.broadcast();
michael@0 227 listener = mConsumerListener;
michael@0 228 } // scope for lock
michael@0 229
michael@0 230 if (listener != NULL) {
michael@0 231 listener->onBuffersReleased();
michael@0 232 }
michael@0 233
michael@0 234 return NO_ERROR;
michael@0 235 }
michael@0 236
michael@0 237 int GonkBufferQueue::query(int what, int* outValue)
michael@0 238 {
michael@0 239 Mutex::Autolock lock(mMutex);
michael@0 240
michael@0 241 if (mAbandoned) {
michael@0 242 ST_LOGE("query: GonkBufferQueue has been abandoned!");
michael@0 243 return NO_INIT;
michael@0 244 }
michael@0 245
michael@0 246 int value;
michael@0 247 switch (what) {
michael@0 248 case NATIVE_WINDOW_WIDTH:
michael@0 249 value = mDefaultWidth;
michael@0 250 break;
michael@0 251 case NATIVE_WINDOW_HEIGHT:
michael@0 252 value = mDefaultHeight;
michael@0 253 break;
michael@0 254 case NATIVE_WINDOW_FORMAT:
michael@0 255 value = mDefaultBufferFormat;
michael@0 256 break;
michael@0 257 case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
michael@0 258 value = getMinUndequeuedBufferCountLocked();
michael@0 259 break;
michael@0 260 case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
michael@0 261 value = (mQueue.size() >= 2);
michael@0 262 break;
michael@0 263 default:
michael@0 264 return BAD_VALUE;
michael@0 265 }
michael@0 266 outValue[0] = value;
michael@0 267 return NO_ERROR;
michael@0 268 }
michael@0 269
michael@0 270 status_t GonkBufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
michael@0 271 ST_LOGV("requestBuffer: slot=%d", slot);
michael@0 272 Mutex::Autolock lock(mMutex);
michael@0 273 if (mAbandoned) {
michael@0 274 ST_LOGE("requestBuffer: GonkBufferQueue has been abandoned!");
michael@0 275 return NO_INIT;
michael@0 276 }
michael@0 277 int maxBufferCount = getMaxBufferCountLocked();
michael@0 278 if (slot < 0 || maxBufferCount <= slot) {
michael@0 279 ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
michael@0 280 maxBufferCount, slot);
michael@0 281 return BAD_VALUE;
michael@0 282 } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
michael@0 283 // XXX: I vaguely recall there was some reason this can be valid, but
michael@0 284 // for the life of me I can't recall under what circumstances that's
michael@0 285 // the case.
michael@0 286 ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
michael@0 287 slot, mSlots[slot].mBufferState);
michael@0 288 return BAD_VALUE;
michael@0 289 }
michael@0 290 mSlots[slot].mRequestBufferCalled = true;
michael@0 291 *buf = mSlots[slot].mGraphicBuffer;
michael@0 292 return NO_ERROR;
michael@0 293 }
michael@0 294
michael@0 295 status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
michael@0 296 uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
michael@0 297 ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
michael@0 298
michael@0 299 if ((w && !h) || (!w && h)) {
michael@0 300 ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
michael@0 301 return BAD_VALUE;
michael@0 302 }
michael@0 303
michael@0 304 status_t returnFlags(OK);
michael@0 305 int buf = INVALID_BUFFER_SLOT;
michael@0 306
michael@0 307 { // Scope for the lock
michael@0 308 Mutex::Autolock lock(mMutex);
michael@0 309
michael@0 310 if (format == 0) {
michael@0 311 format = mDefaultBufferFormat;
michael@0 312 }
michael@0 313 // turn on usage bits the consumer requested
michael@0 314 usage |= mConsumerUsageBits;
michael@0 315
michael@0 316 int found = -1;
michael@0 317 int dequeuedCount = 0;
michael@0 318 bool tryAgain = true;
michael@0 319 while (tryAgain) {
michael@0 320 if (mAbandoned) {
michael@0 321 ST_LOGE("dequeueBuffer: GonkBufferQueue has been abandoned!");
michael@0 322 return NO_INIT;
michael@0 323 }
michael@0 324
michael@0 325 const int maxBufferCount = getMaxBufferCountLocked();
michael@0 326
michael@0 327 // Free up any buffers that are in slots beyond the max buffer
michael@0 328 // count.
michael@0 329 //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
michael@0 330 // assert(mSlots[i].mBufferState == BufferSlot::FREE);
michael@0 331 // if (mSlots[i].mGraphicBuffer != NULL) {
michael@0 332 // freeBufferLocked(i);
michael@0 333 // returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
michael@0 334 // }
michael@0 335 //}
michael@0 336
michael@0 337 // look for a free buffer to give to the client
michael@0 338 found = INVALID_BUFFER_SLOT;
michael@0 339 dequeuedCount = 0;
michael@0 340 for (int i = 0; i < maxBufferCount; i++) {
michael@0 341 const int state = mSlots[i].mBufferState;
michael@0 342 if (state == BufferSlot::DEQUEUED) {
michael@0 343 dequeuedCount++;
michael@0 344 }
michael@0 345
michael@0 346 if (state == BufferSlot::FREE) {
michael@0 347 /* We return the oldest of the free buffers to avoid
michael@0 348 * stalling the producer if possible. This is because
michael@0 349 * the consumer may still have pending reads of the
michael@0 350 * buffers in flight.
michael@0 351 */
michael@0 352 if ((found < 0) ||
michael@0 353 mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
michael@0 354 found = i;
michael@0 355 }
michael@0 356 }
michael@0 357 }
michael@0 358
michael@0 359 // clients are not allowed to dequeue more than one buffer
michael@0 360 // if they didn't set a buffer count.
michael@0 361 if (!mOverrideMaxBufferCount && dequeuedCount) {
michael@0 362 ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
michael@0 363 "setting the buffer count");
michael@0 364 return -EINVAL;
michael@0 365 }
michael@0 366
michael@0 367 // See whether a buffer has been queued since the last
michael@0 368 // setBufferCount so we know whether to perform the min undequeued
michael@0 369 // buffers check below.
michael@0 370 if (mBufferHasBeenQueued) {
michael@0 371 // make sure the client is not trying to dequeue more buffers
michael@0 372 // than allowed.
michael@0 373 const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
michael@0 374 const int minUndequeuedCount = getMinUndequeuedBufferCountLocked();
michael@0 375 if (newUndequeuedCount < minUndequeuedCount) {
michael@0 376 ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
michael@0 377 "exceeded (dequeued=%d undequeudCount=%d)",
michael@0 378 minUndequeuedCount, dequeuedCount,
michael@0 379 newUndequeuedCount);
michael@0 380 return -EBUSY;
michael@0 381 }
michael@0 382 }
michael@0 383
michael@0 384 // If no buffer is found, wait for a buffer to be released or for
michael@0 385 // the max buffer count to change.
michael@0 386 tryAgain = found == INVALID_BUFFER_SLOT;
michael@0 387 if (tryAgain) {
michael@0 388 mDequeueCondition.wait(mMutex);
michael@0 389 }
michael@0 390 }
michael@0 391
michael@0 392
michael@0 393 if (found == INVALID_BUFFER_SLOT) {
michael@0 394 // This should not happen.
michael@0 395 ST_LOGE("dequeueBuffer: no available buffer slots");
michael@0 396 return -EBUSY;
michael@0 397 }
michael@0 398
michael@0 399 buf = found;
michael@0 400 *outBuf = found;
michael@0 401
michael@0 402 const bool useDefaultSize = !w && !h;
michael@0 403 if (useDefaultSize) {
michael@0 404 // use the default size
michael@0 405 w = mDefaultWidth;
michael@0 406 h = mDefaultHeight;
michael@0 407 }
michael@0 408
michael@0 409 mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
michael@0 410
michael@0 411 const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
michael@0 412 if ((buffer == NULL) ||
michael@0 413 (uint32_t(buffer->width) != w) ||
michael@0 414 (uint32_t(buffer->height) != h) ||
michael@0 415 (uint32_t(buffer->format) != format) ||
michael@0 416 ((uint32_t(buffer->usage) & usage) != usage))
michael@0 417 {
michael@0 418 mSlots[buf].mAcquireCalled = false;
michael@0 419 mSlots[buf].mGraphicBuffer = NULL;
michael@0 420 mSlots[buf].mRequestBufferCalled = false;
michael@0 421 mSlots[buf].mFence = Fence::NO_FENCE;
michael@0 422 if (mSlots[buf].mTextureClient) {
michael@0 423 mSlots[buf].mTextureClient->ClearRecycleCallback();
michael@0 424 // release TextureClient in ImageBridge thread
michael@0 425 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient);
michael@0 426 mSlots[buf].mTextureClient = NULL;
michael@0 427 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
michael@0 428 }
michael@0 429 returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
michael@0 430 }
michael@0 431
michael@0 432 *outFence = mSlots[buf].mFence;
michael@0 433 mSlots[buf].mFence = Fence::NO_FENCE;
michael@0 434 } // end lock scope
michael@0 435
michael@0 436 sp<GraphicBuffer> graphicBuffer;
michael@0 437 if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
michael@0 438 RefPtr<GrallocTextureClientOGL> textureClient =
michael@0 439 new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(),
michael@0 440 gfx::SurfaceFormat::UNKNOWN,
michael@0 441 gfx::BackendType::NONE,
michael@0 442 TEXTURE_DEALLOCATE_CLIENT);
michael@0 443 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
michael@0 444 bool result = textureClient->AllocateGralloc(IntSize(w, h), format, usage);
michael@0 445 sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer();
michael@0 446 if (!result || !graphicBuffer.get()) {
michael@0 447 ST_LOGE("dequeueBuffer: failed to alloc gralloc buffer");
michael@0 448 return -ENOMEM;
michael@0 449 }
michael@0 450
michael@0 451 { // Scope for the lock
michael@0 452 Mutex::Autolock lock(mMutex);
michael@0 453
michael@0 454 if (mAbandoned) {
michael@0 455 ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
michael@0 456 return NO_INIT;
michael@0 457 }
michael@0 458
michael@0 459 mSlots[buf].mGraphicBuffer = graphicBuffer;
michael@0 460 mSlots[buf].mTextureClient = textureClient;
michael@0 461 ST_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
michael@0 462 mSlots[buf].mGraphicBuffer->handle);
michael@0 463 //mSlots[*outBuf].mGraphicBuffer = graphicBuffer;
michael@0 464 }
michael@0 465 }
michael@0 466
michael@0 467 ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
michael@0 468 mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
michael@0 469
michael@0 470 return returnFlags;
michael@0 471 }
michael@0 472
michael@0 473 status_t GonkBufferQueue::setSynchronousMode(bool enabled) {
michael@0 474 return NO_ERROR;
michael@0 475 }
michael@0 476
michael@0 477 status_t GonkBufferQueue::queueBuffer(int buf,
michael@0 478 const QueueBufferInput& input, QueueBufferOutput* output) {
michael@0 479
michael@0 480 Rect crop;
michael@0 481 uint32_t transform;
michael@0 482 int scalingMode;
michael@0 483 int64_t timestamp;
michael@0 484 sp<Fence> fence;
michael@0 485
michael@0 486 input.deflate(&timestamp, &crop, &scalingMode, &transform, &fence);
michael@0 487
michael@0 488 #if ANDROID_VERSION >= 18
michael@0 489 if (fence == NULL) {
michael@0 490 ST_LOGE("queueBuffer: fence is NULL");
michael@0 491 return BAD_VALUE;
michael@0 492 }
michael@0 493 #endif
michael@0 494
michael@0 495 ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
michael@0 496 "scale=%s",
michael@0 497 buf, timestamp, crop.left, crop.top, crop.right, crop.bottom,
michael@0 498 transform, scalingModeName(scalingMode));
michael@0 499
michael@0 500 sp<ConsumerListener> listener;
michael@0 501
michael@0 502 { // scope for the lock
michael@0 503 Mutex::Autolock lock(mMutex);
michael@0 504 if (mAbandoned) {
michael@0 505 ST_LOGE("queueBuffer: GonkBufferQueue has been abandoned!");
michael@0 506 return NO_INIT;
michael@0 507 }
michael@0 508 int maxBufferCount = getMaxBufferCountLocked();
michael@0 509 if (buf < 0 || buf >= maxBufferCount) {
michael@0 510 ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
michael@0 511 maxBufferCount, buf);
michael@0 512 return -EINVAL;
michael@0 513 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
michael@0 514 ST_LOGE("queueBuffer: slot %d is not owned by the client "
michael@0 515 "(state=%d)", buf, mSlots[buf].mBufferState);
michael@0 516 return -EINVAL;
michael@0 517 } else if (!mSlots[buf].mRequestBufferCalled) {
michael@0 518 ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
michael@0 519 "buffer", buf);
michael@0 520 return -EINVAL;
michael@0 521 }
michael@0 522
michael@0 523 const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);
michael@0 524 Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
michael@0 525 Rect croppedCrop;
michael@0 526 crop.intersect(bufferRect, &croppedCrop);
michael@0 527 if (croppedCrop != crop) {
michael@0 528 ST_LOGE("queueBuffer: crop rect is not contained within the "
michael@0 529 "buffer in slot %d", buf);
michael@0 530 return -EINVAL;
michael@0 531 }
michael@0 532
michael@0 533 if (mSynchronousMode) {
michael@0 534 // In synchronous mode we queue all buffers in a FIFO.
michael@0 535 mQueue.push_back(buf);
michael@0 536
michael@0 537 // Synchronous mode always signals that an additional frame should
michael@0 538 // be consumed.
michael@0 539 listener = mConsumerListener;
michael@0 540 } else {
michael@0 541 // In asynchronous mode we only keep the most recent buffer.
michael@0 542 if (mQueue.empty()) {
michael@0 543 mQueue.push_back(buf);
michael@0 544
michael@0 545 // Asynchronous mode only signals that a frame should be
michael@0 546 // consumed if no previous frame was pending. If a frame were
michael@0 547 // pending then the consumer would have already been notified.
michael@0 548 listener = mConsumerListener;
michael@0 549 } else {
michael@0 550 Fifo::iterator front(mQueue.begin());
michael@0 551 // buffer currently queued is freed
michael@0 552 mSlots[*front].mBufferState = BufferSlot::FREE;
michael@0 553 // and we record the new buffer index in the queued list
michael@0 554 *front = buf;
michael@0 555 }
michael@0 556 }
michael@0 557
michael@0 558 mSlots[buf].mTimestamp = timestamp;
michael@0 559 mSlots[buf].mCrop = crop;
michael@0 560 mSlots[buf].mTransform = transform;
michael@0 561 mSlots[buf].mFence = fence;
michael@0 562
michael@0 563 switch (scalingMode) {
michael@0 564 case NATIVE_WINDOW_SCALING_MODE_FREEZE:
michael@0 565 case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
michael@0 566 case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
michael@0 567 break;
michael@0 568 default:
michael@0 569 ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode);
michael@0 570 scalingMode = mSlots[buf].mScalingMode;
michael@0 571 break;
michael@0 572 }
michael@0 573
michael@0 574 mSlots[buf].mBufferState = BufferSlot::QUEUED;
michael@0 575 mSlots[buf].mScalingMode = scalingMode;
michael@0 576 mFrameCounter++;
michael@0 577 mSlots[buf].mFrameNumber = mFrameCounter;
michael@0 578
michael@0 579 mBufferHasBeenQueued = true;
michael@0 580 mDequeueCondition.broadcast();
michael@0 581
michael@0 582 output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,
michael@0 583 mQueue.size());
michael@0 584 } // scope for the lock
michael@0 585
michael@0 586 // call back without lock held
michael@0 587 if (listener != 0) {
michael@0 588 listener->onFrameAvailable();
michael@0 589 }
michael@0 590 return NO_ERROR;
michael@0 591 }
michael@0 592
michael@0 593 #if ANDROID_VERSION == 17
michael@0 594 void GonkBufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
michael@0 595 #else
michael@0 596 void GonkBufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
michael@0 597 #endif
michael@0 598
michael@0 599 ST_LOGV("cancelBuffer: slot=%d", buf);
michael@0 600 Mutex::Autolock lock(mMutex);
michael@0 601
michael@0 602 if (mAbandoned) {
michael@0 603 ST_LOGW("cancelBuffer: GonkBufferQueue has been abandoned!");
michael@0 604 return;
michael@0 605 }
michael@0 606
michael@0 607 int maxBufferCount = getMaxBufferCountLocked();
michael@0 608 if (buf < 0 || buf >= maxBufferCount) {
michael@0 609 ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
michael@0 610 maxBufferCount, buf);
michael@0 611 return;
michael@0 612 } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
michael@0 613 ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
michael@0 614 buf, mSlots[buf].mBufferState);
michael@0 615 return;
michael@0 616 #if ANDROID_VERSION >= 18
michael@0 617 } else if (fence == NULL) {
michael@0 618 ST_LOGE("cancelBuffer: fence is NULL");
michael@0 619 return;
michael@0 620 #endif
michael@0 621 }
michael@0 622 mSlots[buf].mBufferState = BufferSlot::FREE;
michael@0 623 mSlots[buf].mFrameNumber = 0;
michael@0 624 mSlots[buf].mFence = fence;
michael@0 625 mDequeueCondition.broadcast();
michael@0 626 }
michael@0 627
michael@0 628 status_t GonkBufferQueue::connect(int api, QueueBufferOutput* output) {
michael@0 629 ST_LOGV("connect: api=%d", api);
michael@0 630 Mutex::Autolock lock(mMutex);
michael@0 631
michael@0 632 if (mAbandoned) {
michael@0 633 ST_LOGE("connect: GonkBufferQueue has been abandoned!");
michael@0 634 return NO_INIT;
michael@0 635 }
michael@0 636
michael@0 637 if (mConsumerListener == NULL) {
michael@0 638 ST_LOGE("connect: GonkBufferQueue has no consumer!");
michael@0 639 return NO_INIT;
michael@0 640 }
michael@0 641
michael@0 642 int err = NO_ERROR;
michael@0 643 switch (api) {
michael@0 644 case NATIVE_WINDOW_API_EGL:
michael@0 645 case NATIVE_WINDOW_API_CPU:
michael@0 646 case NATIVE_WINDOW_API_MEDIA:
michael@0 647 case NATIVE_WINDOW_API_CAMERA:
michael@0 648 if (mConnectedApi != NO_CONNECTED_API) {
michael@0 649 ST_LOGE("connect: already connected (cur=%d, req=%d)",
michael@0 650 mConnectedApi, api);
michael@0 651 err = -EINVAL;
michael@0 652 } else {
michael@0 653 mConnectedApi = api;
michael@0 654 output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,
michael@0 655 mQueue.size());
michael@0 656 }
michael@0 657 break;
michael@0 658 default:
michael@0 659 err = -EINVAL;
michael@0 660 break;
michael@0 661 }
michael@0 662
michael@0 663 mBufferHasBeenQueued = false;
michael@0 664
michael@0 665 return err;
michael@0 666 }
michael@0 667
michael@0 668 status_t GonkBufferQueue::disconnect(int api) {
michael@0 669 ST_LOGV("disconnect: api=%d", api);
michael@0 670
michael@0 671 int err = NO_ERROR;
michael@0 672 sp<ConsumerListener> listener;
michael@0 673
michael@0 674 { // Scope for the lock
michael@0 675 Mutex::Autolock lock(mMutex);
michael@0 676
michael@0 677 if (mAbandoned) {
michael@0 678 // it is not really an error to disconnect after the surface
michael@0 679 // has been abandoned, it should just be a no-op.
michael@0 680 return NO_ERROR;
michael@0 681 }
michael@0 682
michael@0 683 switch (api) {
michael@0 684 case NATIVE_WINDOW_API_EGL:
michael@0 685 case NATIVE_WINDOW_API_CPU:
michael@0 686 case NATIVE_WINDOW_API_MEDIA:
michael@0 687 case NATIVE_WINDOW_API_CAMERA:
michael@0 688 if (mConnectedApi == api) {
michael@0 689 freeAllBuffersLocked();
michael@0 690 mConnectedApi = NO_CONNECTED_API;
michael@0 691 mDequeueCondition.broadcast();
michael@0 692 listener = mConsumerListener;
michael@0 693 } else {
michael@0 694 ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
michael@0 695 mConnectedApi, api);
michael@0 696 err = -EINVAL;
michael@0 697 }
michael@0 698 break;
michael@0 699 default:
michael@0 700 ST_LOGE("disconnect: unknown API %d", api);
michael@0 701 err = -EINVAL;
michael@0 702 break;
michael@0 703 }
michael@0 704 }
michael@0 705
michael@0 706 if (listener != NULL) {
michael@0 707 listener->onBuffersReleased();
michael@0 708 }
michael@0 709
michael@0 710 return err;
michael@0 711 }
michael@0 712
michael@0 713 void GonkBufferQueue::dump(String8& result) const
michael@0 714 {
michael@0 715 char buffer[1024];
michael@0 716 GonkBufferQueue::dump(result, "", buffer, 1024);
michael@0 717 }
michael@0 718
michael@0 719 void GonkBufferQueue::dump(String8& result, const char* prefix,
michael@0 720 char* buffer, size_t SIZE) const
michael@0 721 {
michael@0 722 Mutex::Autolock _l(mMutex);
michael@0 723
michael@0 724 String8 fifo;
michael@0 725 int fifoSize = 0;
michael@0 726 Fifo::const_iterator i(mQueue.begin());
michael@0 727 while (i != mQueue.end()) {
michael@0 728 snprintf(buffer, SIZE, "%02d ", *i++);
michael@0 729 fifoSize++;
michael@0 730 fifo.append(buffer);
michael@0 731 }
michael@0 732
michael@0 733 int maxBufferCount = getMaxBufferCountLocked();
michael@0 734
michael@0 735 snprintf(buffer, SIZE,
michael@0 736 "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
michael@0 737 "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
michael@0 738 prefix, maxBufferCount, mSynchronousMode, mDefaultWidth,
michael@0 739 mDefaultHeight, mDefaultBufferFormat, mTransformHint,
michael@0 740 fifoSize, fifo.string());
michael@0 741 result.append(buffer);
michael@0 742
michael@0 743
michael@0 744 struct {
michael@0 745 const char * operator()(int state) const {
michael@0 746 switch (state) {
michael@0 747 case BufferSlot::DEQUEUED: return "DEQUEUED";
michael@0 748 case BufferSlot::QUEUED: return "QUEUED";
michael@0 749 case BufferSlot::FREE: return "FREE";
michael@0 750 case BufferSlot::ACQUIRED: return "ACQUIRED";
michael@0 751 default: return "Unknown";
michael@0 752 }
michael@0 753 }
michael@0 754 } stateName;
michael@0 755
michael@0 756 for (int i=0 ; i<maxBufferCount ; i++) {
michael@0 757 const BufferSlot& slot(mSlots[i]);
michael@0 758 snprintf(buffer, SIZE,
michael@0 759 "%s%s[%02d] "
michael@0 760 "state=%-8s, crop=[%d,%d,%d,%d], "
michael@0 761 "xform=0x%02x, time=%#llx, scale=%s",
michael@0 762 prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i,
michael@0 763 stateName(slot.mBufferState),
michael@0 764 slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
michael@0 765 slot.mCrop.bottom, slot.mTransform, slot.mTimestamp,
michael@0 766 scalingModeName(slot.mScalingMode)
michael@0 767 );
michael@0 768 result.append(buffer);
michael@0 769
michael@0 770 const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
michael@0 771 if (buf != NULL) {
michael@0 772 snprintf(buffer, SIZE,
michael@0 773 ", %p [%4ux%4u:%4u,%3X]",
michael@0 774 buf->handle, buf->width, buf->height, buf->stride,
michael@0 775 buf->format);
michael@0 776 result.append(buffer);
michael@0 777 }
michael@0 778 result.append("\n");
michael@0 779 }
michael@0 780 }
michael@0 781
michael@0 782 void GonkBufferQueue::freeAllBuffersLocked()
michael@0 783 {
michael@0 784 ALOGW_IF(!mQueue.isEmpty(),
michael@0 785 "freeAllBuffersLocked called but mQueue is not empty");
michael@0 786 mQueue.clear();
michael@0 787 mBufferHasBeenQueued = false;
michael@0 788 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 789 mSlots[i].mGraphicBuffer = 0;
michael@0 790 if (mSlots[i].mTextureClient) {
michael@0 791 mSlots[i].mTextureClient->ClearRecycleCallback();
michael@0 792 // release TextureClient in ImageBridge thread
michael@0 793 nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient);
michael@0 794 mSlots[i].mTextureClient = NULL;
michael@0 795 ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
michael@0 796 }
michael@0 797 if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
michael@0 798 mSlots[i].mNeedsCleanupOnRelease = true;
michael@0 799 }
michael@0 800 mSlots[i].mBufferState = BufferSlot::FREE;
michael@0 801 mSlots[i].mFrameNumber = 0;
michael@0 802 mSlots[i].mAcquireCalled = false;
michael@0 803 // destroy fence as GonkBufferQueue now takes ownership
michael@0 804 mSlots[i].mFence = Fence::NO_FENCE;
michael@0 805 }
michael@0 806 }
michael@0 807
michael@0 808 status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer) {
michael@0 809 Mutex::Autolock _l(mMutex);
michael@0 810
michael@0 811 // Check that the consumer doesn't currently have the maximum number of
michael@0 812 // buffers acquired. We allow the max buffer count to be exceeded by one
michael@0 813 // buffer, so that the consumer can successfully set up the newly acquired
michael@0 814 // buffer before releasing the old one.
michael@0 815 int numAcquiredBuffers = 0;
michael@0 816 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 817 if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
michael@0 818 numAcquiredBuffers++;
michael@0 819 }
michael@0 820 }
michael@0 821 if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) {
michael@0 822 ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)",
michael@0 823 numAcquiredBuffers, mMaxAcquiredBufferCount);
michael@0 824 return INVALID_OPERATION;
michael@0 825 }
michael@0 826
michael@0 827 // check if queue is empty
michael@0 828 // In asynchronous mode the list is guaranteed to be one buffer
michael@0 829 // deep, while in synchronous mode we use the oldest buffer.
michael@0 830 if (!mQueue.empty()) {
michael@0 831 Fifo::iterator front(mQueue.begin());
michael@0 832 int buf = *front;
michael@0 833
michael@0 834 // In android, when the buffer is aquired by BufferConsumer,
michael@0 835 // BufferQueue releases a reference to the buffer and
michael@0 836 // it's ownership moves to the BufferConsumer.
michael@0 837 // In b2g, GonkBufferQueue continues to have a buffer ownership.
michael@0 838 // It is necessary to free buffer via ImageBridgeChild.
michael@0 839
michael@0 840 //if (mSlots[buf].mAcquireCalled) {
michael@0 841 // buffer->mGraphicBuffer = NULL;
michael@0 842 //} else {
michael@0 843 // buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
michael@0 844 //}
michael@0 845 buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
michael@0 846 buffer->mCrop = mSlots[buf].mCrop;
michael@0 847 buffer->mTransform = mSlots[buf].mTransform;
michael@0 848 buffer->mScalingMode = mSlots[buf].mScalingMode;
michael@0 849 buffer->mFrameNumber = mSlots[buf].mFrameNumber;
michael@0 850 buffer->mTimestamp = mSlots[buf].mTimestamp;
michael@0 851 buffer->mBuf = buf;
michael@0 852 buffer->mFence = mSlots[buf].mFence;
michael@0 853
michael@0 854 mSlots[buf].mAcquireCalled = true;
michael@0 855 mSlots[buf].mNeedsCleanupOnRelease = false;
michael@0 856 mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
michael@0 857 mSlots[buf].mFence = Fence::NO_FENCE;
michael@0 858
michael@0 859 mQueue.erase(front);
michael@0 860 mDequeueCondition.broadcast();
michael@0 861 } else {
michael@0 862 return NO_BUFFER_AVAILABLE;
michael@0 863 }
michael@0 864
michael@0 865 return NO_ERROR;
michael@0 866 }
michael@0 867
michael@0 868 status_t GonkBufferQueue::releaseBuffer(int buf, const sp<Fence>& fence) {
michael@0 869 Mutex::Autolock _l(mMutex);
michael@0 870
michael@0 871 #if ANDROID_VERSION == 17
michael@0 872 if (buf == INVALID_BUFFER_SLOT) {
michael@0 873 #else
michael@0 874 if (buf == INVALID_BUFFER_SLOT || fence == NULL) {
michael@0 875 #endif
michael@0 876 return BAD_VALUE;
michael@0 877 }
michael@0 878
michael@0 879 mSlots[buf].mFence = fence;
michael@0 880
michael@0 881 // The buffer can now only be released if its in the acquired state
michael@0 882 if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
michael@0 883 mSlots[buf].mBufferState = BufferSlot::FREE;
michael@0 884 } else if (mSlots[buf].mNeedsCleanupOnRelease) {
michael@0 885 ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState);
michael@0 886 mSlots[buf].mNeedsCleanupOnRelease = false;
michael@0 887 return STALE_BUFFER_SLOT;
michael@0 888 } else {
michael@0 889 ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState);
michael@0 890 return -EINVAL;
michael@0 891 }
michael@0 892
michael@0 893 mDequeueCondition.broadcast();
michael@0 894 return NO_ERROR;
michael@0 895 }
michael@0 896
michael@0 897 status_t GonkBufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) {
michael@0 898 ST_LOGV("consumerConnect");
michael@0 899 Mutex::Autolock lock(mMutex);
michael@0 900
michael@0 901 if (mAbandoned) {
michael@0 902 ST_LOGE("consumerConnect: GonkBufferQueue has been abandoned!");
michael@0 903 return NO_INIT;
michael@0 904 }
michael@0 905 if (consumerListener == NULL) {
michael@0 906 ST_LOGE("consumerConnect: consumerListener may not be NULL");
michael@0 907 return BAD_VALUE;
michael@0 908 }
michael@0 909
michael@0 910 mConsumerListener = consumerListener;
michael@0 911
michael@0 912 return NO_ERROR;
michael@0 913 }
michael@0 914
michael@0 915 status_t GonkBufferQueue::consumerDisconnect() {
michael@0 916 ST_LOGV("consumerDisconnect");
michael@0 917 Mutex::Autolock lock(mMutex);
michael@0 918
michael@0 919 if (mConsumerListener == NULL) {
michael@0 920 ST_LOGE("consumerDisconnect: No consumer is connected!");
michael@0 921 return -EINVAL;
michael@0 922 }
michael@0 923
michael@0 924 mAbandoned = true;
michael@0 925 mConsumerListener = NULL;
michael@0 926 mQueue.clear();
michael@0 927 freeAllBuffersLocked();
michael@0 928 mDequeueCondition.broadcast();
michael@0 929 return NO_ERROR;
michael@0 930 }
michael@0 931
michael@0 932 status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) {
michael@0 933 ST_LOGV("getReleasedBuffers");
michael@0 934 Mutex::Autolock lock(mMutex);
michael@0 935
michael@0 936 if (mAbandoned) {
michael@0 937 ST_LOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!");
michael@0 938 return NO_INIT;
michael@0 939 }
michael@0 940
michael@0 941 uint32_t mask = 0;
michael@0 942 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
michael@0 943 if (!mSlots[i].mAcquireCalled) {
michael@0 944 mask |= 1 << i;
michael@0 945 }
michael@0 946 }
michael@0 947 *slotMask = mask;
michael@0 948
michael@0 949 ST_LOGV("getReleasedBuffers: returning mask %#x", mask);
michael@0 950 return NO_ERROR;
michael@0 951 }
michael@0 952
michael@0 953 status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
michael@0 954 {
michael@0 955 ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
michael@0 956 if (!w || !h) {
michael@0 957 ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
michael@0 958 w, h);
michael@0 959 return BAD_VALUE;
michael@0 960 }
michael@0 961
michael@0 962 Mutex::Autolock lock(mMutex);
michael@0 963 mDefaultWidth = w;
michael@0 964 mDefaultHeight = h;
michael@0 965 return NO_ERROR;
michael@0 966 }
michael@0 967
michael@0 968 status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) {
michael@0 969 Mutex::Autolock lock(mMutex);
michael@0 970 return setDefaultMaxBufferCountLocked(bufferCount);
michael@0 971 }
michael@0 972
michael@0 973 status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
michael@0 974 Mutex::Autolock lock(mMutex);
michael@0 975 if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) {
michael@0 976 ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d",
michael@0 977 maxAcquiredBuffers);
michael@0 978 return BAD_VALUE;
michael@0 979 }
michael@0 980 if (mConnectedApi != NO_CONNECTED_API) {
michael@0 981 return INVALID_OPERATION;
michael@0 982 }
michael@0 983 mMaxAcquiredBufferCount = maxAcquiredBuffers;
michael@0 984 return NO_ERROR;
michael@0 985 }
michael@0 986
michael@0 987 int GonkBufferQueue::getMinMaxBufferCountLocked() const {
michael@0 988 return getMinUndequeuedBufferCountLocked() + 1;
michael@0 989 }
michael@0 990
michael@0 991 int GonkBufferQueue::getMinUndequeuedBufferCountLocked() const {
michael@0 992 return mSynchronousMode ? mMaxAcquiredBufferCount :
michael@0 993 mMaxAcquiredBufferCount + 1;
michael@0 994 }
michael@0 995
michael@0 996 int GonkBufferQueue::getMaxBufferCountLocked() const {
michael@0 997 int minMaxBufferCount = getMinMaxBufferCountLocked();
michael@0 998
michael@0 999 int maxBufferCount = mDefaultMaxBufferCount;
michael@0 1000 if (maxBufferCount < minMaxBufferCount) {
michael@0 1001 maxBufferCount = minMaxBufferCount;
michael@0 1002 }
michael@0 1003 if (mOverrideMaxBufferCount != 0) {
michael@0 1004 assert(mOverrideMaxBufferCount >= minMaxBufferCount);
michael@0 1005 maxBufferCount = mOverrideMaxBufferCount;
michael@0 1006 }
michael@0 1007
michael@0 1008 // Any buffers that are dequeued by the producer or sitting in the queue
michael@0 1009 // waiting to be consumed need to have their slots preserved. Such
michael@0 1010 // buffers will temporarily keep the max buffer count up until the slots
michael@0 1011 // no longer need to be preserved.
michael@0 1012 for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
michael@0 1013 BufferSlot::BufferState state = mSlots[i].mBufferState;
michael@0 1014 if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
michael@0 1015 maxBufferCount = i + 1;
michael@0 1016 }
michael@0 1017 }
michael@0 1018
michael@0 1019 return maxBufferCount;
michael@0 1020 }
michael@0 1021
michael@0 1022 GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener(
michael@0 1023 const wp<GonkBufferQueue::ConsumerListener>& consumerListener):
michael@0 1024 mConsumerListener(consumerListener) {}
michael@0 1025
michael@0 1026 GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
michael@0 1027
michael@0 1028 void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() {
michael@0 1029 sp<GonkBufferQueue::ConsumerListener> listener(mConsumerListener.promote());
michael@0 1030 if (listener != NULL) {
michael@0 1031 listener->onFrameAvailable();
michael@0 1032 }
michael@0 1033 }
michael@0 1034
michael@0 1035 void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() {
michael@0 1036 sp<GonkBufferQueue::ConsumerListener> listener(mConsumerListener.promote());
michael@0 1037 if (listener != NULL) {
michael@0 1038 listener->onBuffersReleased();
michael@0 1039 }
michael@0 1040 }
michael@0 1041
michael@0 1042 }; // namespace android

mercurial