widget/gonk/nativewindow/GonkBufferQueueJB.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/gonk/nativewindow/GonkBufferQueueJB.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1042 @@
     1.4 +/*
     1.5 + * Copyright (C) 2012 The Android Open Source Project
     1.6 + * Copyright (C) 2013 Mozilla Foundation
     1.7 + *
     1.8 + * Licensed under the Apache License, Version 2.0 (the "License");
     1.9 + * you may not use this file except in compliance with the License.
    1.10 + * You may obtain a copy of the License at
    1.11 + *
    1.12 + *      http://www.apache.org/licenses/LICENSE-2.0
    1.13 + *
    1.14 + * Unless required by applicable law or agreed to in writing, software
    1.15 + * distributed under the License is distributed on an "AS IS" BASIS,
    1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.17 + * See the License for the specific language governing permissions and
    1.18 + * limitations under the License.
    1.19 + */
    1.20 +
    1.21 +#define LOG_TAG "GonkBufferQueue"
    1.22 +#define ATRACE_TAG ATRACE_TAG_GRAPHICS
    1.23 +#define LOG_NDEBUG 0
    1.24 +
    1.25 +#define GL_GLEXT_PROTOTYPES
    1.26 +#define EGL_EGLEXT_PROTOTYPES
    1.27 +
    1.28 +#include <utils/Log.h>
    1.29 +
    1.30 +#include "mozilla/layers/GrallocTextureClient.h"
    1.31 +#include "mozilla/layers/ImageBridgeChild.h"
    1.32 +
    1.33 +#include "GonkBufferQueueJB.h"
    1.34 +
    1.35 +// Macros for including the GonkBufferQueue name in log messages
    1.36 +#define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
    1.37 +#define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
    1.38 +#define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
    1.39 +#define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
    1.40 +#define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
    1.41 +
    1.42 +#define ATRACE_BUFFER_INDEX(index)
    1.43 +
    1.44 +using namespace mozilla;
    1.45 +using namespace mozilla::gfx;
    1.46 +using namespace mozilla::layers;
    1.47 +
    1.48 +namespace android {
    1.49 +
    1.50 +// Get an ID that's unique within this process.
    1.51 +static int32_t createProcessUniqueId() {
    1.52 +    static volatile int32_t globalCounter = 0;
    1.53 +    return android_atomic_inc(&globalCounter);
    1.54 +}
    1.55 +
    1.56 +static const char* scalingModeName(int scalingMode) {
    1.57 +    switch (scalingMode) {
    1.58 +        case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
    1.59 +        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
    1.60 +        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
    1.61 +        default: return "Unknown";
    1.62 +    }
    1.63 +}
    1.64 +
    1.65 +class nsProxyReleaseTask : public Task
    1.66 +{
    1.67 +public:
    1.68 +    nsProxyReleaseTask(TextureClient* aClient)
    1.69 +        : mTextureClient(aClient) {
    1.70 +    }
    1.71 +
    1.72 +    virtual void Run() MOZ_OVERRIDE
    1.73 +    {
    1.74 +        mTextureClient = nullptr;
    1.75 +    }
    1.76 +
    1.77 +private:
    1.78 +    mozilla::RefPtr<TextureClient> mTextureClient;
    1.79 +};
    1.80 +
    1.81 +GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode,
    1.82 +        const sp<IGraphicBufferAlloc>& allocator) :
    1.83 +    mDefaultWidth(1),
    1.84 +    mDefaultHeight(1),
    1.85 +    mMaxAcquiredBufferCount(1),
    1.86 +    mDefaultMaxBufferCount(2),
    1.87 +    mOverrideMaxBufferCount(0),
    1.88 +    mSynchronousMode(true), // GonkBufferQueue always works in sync mode.
    1.89 +    mAllowSynchronousMode(allowSynchronousMode),
    1.90 +    mConnectedApi(NO_CONNECTED_API),
    1.91 +    mAbandoned(false),
    1.92 +    mFrameCounter(0),
    1.93 +    mBufferHasBeenQueued(false),
    1.94 +    mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
    1.95 +    mConsumerUsageBits(0),
    1.96 +    mTransformHint(0)
    1.97 +{
    1.98 +    // Choose a name using the PID and a process-unique ID.
    1.99 +    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
   1.100 +
   1.101 +    ST_LOGV("GonkBufferQueue");
   1.102 +}
   1.103 +
   1.104 +GonkBufferQueue::~GonkBufferQueue() {
   1.105 +    ST_LOGV("~GonkBufferQueue");
   1.106 +}
   1.107 +
   1.108 +status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) {
   1.109 +    if (count < 2 || count > NUM_BUFFER_SLOTS)
   1.110 +        return BAD_VALUE;
   1.111 +
   1.112 +    mDefaultMaxBufferCount = count;
   1.113 +    mDequeueCondition.broadcast();
   1.114 +
   1.115 +    return NO_ERROR;
   1.116 +}
   1.117 +
   1.118 +bool GonkBufferQueue::isSynchronousMode() const {
   1.119 +    Mutex::Autolock lock(mMutex);
   1.120 +    return mSynchronousMode;
   1.121 +}
   1.122 +
   1.123 +void GonkBufferQueue::setConsumerName(const String8& name) {
   1.124 +    Mutex::Autolock lock(mMutex);
   1.125 +    mConsumerName = name;
   1.126 +}
   1.127 +
   1.128 +status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
   1.129 +    Mutex::Autolock lock(mMutex);
   1.130 +    mDefaultBufferFormat = defaultFormat;
   1.131 +    return NO_ERROR;
   1.132 +}
   1.133 +
   1.134 +status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) {
   1.135 +    Mutex::Autolock lock(mMutex);
   1.136 +    mConsumerUsageBits = usage;
   1.137 +    return NO_ERROR;
   1.138 +}
   1.139 +
   1.140 +status_t GonkBufferQueue::setTransformHint(uint32_t hint) {
   1.141 +    ST_LOGV("setTransformHint: %02x", hint);
   1.142 +    Mutex::Autolock lock(mMutex);
   1.143 +    mTransformHint = hint;
   1.144 +    return NO_ERROR;
   1.145 +}
   1.146 +
   1.147 +TemporaryRef<TextureClient>
   1.148 +GonkBufferQueue::getTextureClientFromBuffer(ANativeWindowBuffer* buffer)
   1.149 +{
   1.150 +    Mutex::Autolock _l(mMutex);
   1.151 +    if (buffer == NULL) {
   1.152 +        ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
   1.153 +        return nullptr;
   1.154 +    }
   1.155 +
   1.156 +    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
   1.157 +        if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) {
   1.158 +            return mSlots[i].mTextureClient;
   1.159 +        }
   1.160 +    }
   1.161 +    ST_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
   1.162 +    return nullptr;
   1.163 +}
   1.164 +
   1.165 +int GonkBufferQueue::getSlotFromTextureClientLocked(
   1.166 +        TextureClient* client) const
   1.167 +{
   1.168 +    if (client == NULL) {
   1.169 +        ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
   1.170 +        return BAD_VALUE;
   1.171 +    }
   1.172 +
   1.173 +    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
   1.174 +        if (mSlots[i].mTextureClient == client) {
   1.175 +            return i;
   1.176 +        }
   1.177 +    }
   1.178 +    ST_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client);
   1.179 +    return BAD_VALUE;
   1.180 +}
   1.181 +
   1.182 +
   1.183 +status_t GonkBufferQueue::setBufferCount(int bufferCount) {
   1.184 +    ST_LOGV("setBufferCount: count=%d", bufferCount);
   1.185 +
   1.186 +    sp<ConsumerListener> listener;
   1.187 +    {
   1.188 +        Mutex::Autolock lock(mMutex);
   1.189 +
   1.190 +        if (mAbandoned) {
   1.191 +            ST_LOGE("setBufferCount: GonkBufferQueue has been abandoned!");
   1.192 +            return NO_INIT;
   1.193 +        }
   1.194 +        if (bufferCount > NUM_BUFFER_SLOTS) {
   1.195 +            ST_LOGE("setBufferCount: bufferCount too large (max %d)",
   1.196 +                    NUM_BUFFER_SLOTS);
   1.197 +            return BAD_VALUE;
   1.198 +        }
   1.199 +
   1.200 +        // Error out if the user has dequeued buffers
   1.201 +        int maxBufferCount = getMaxBufferCountLocked();
   1.202 +        for (int i=0 ; i<maxBufferCount; i++) {
   1.203 +            if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
   1.204 +                ST_LOGE("setBufferCount: client owns some buffers");
   1.205 +                return -EINVAL;
   1.206 +            }
   1.207 +        }
   1.208 +
   1.209 +        const int minBufferSlots = getMinMaxBufferCountLocked();
   1.210 +        if (bufferCount == 0) {
   1.211 +            mOverrideMaxBufferCount = 0;
   1.212 +            mDequeueCondition.broadcast();
   1.213 +            return NO_ERROR;
   1.214 +        }
   1.215 +
   1.216 +        if (bufferCount < minBufferSlots) {
   1.217 +            ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
   1.218 +                    "minimum (%d)", bufferCount, minBufferSlots);
   1.219 +            return BAD_VALUE;
   1.220 +        }
   1.221 +
   1.222 +        // here we're guaranteed that the client doesn't have dequeued buffers
   1.223 +        // and will release all of its buffer references.
   1.224 +        //
   1.225 +        // XXX: Should this use drainQueueAndFreeBuffersLocked instead?
   1.226 +        freeAllBuffersLocked();
   1.227 +        mOverrideMaxBufferCount = bufferCount;
   1.228 +        mBufferHasBeenQueued = false;
   1.229 +        mDequeueCondition.broadcast();
   1.230 +        listener = mConsumerListener;
   1.231 +    } // scope for lock
   1.232 +
   1.233 +    if (listener != NULL) {
   1.234 +        listener->onBuffersReleased();
   1.235 +    }
   1.236 +
   1.237 +    return NO_ERROR;
   1.238 +}
   1.239 +
   1.240 +int GonkBufferQueue::query(int what, int* outValue)
   1.241 +{
   1.242 +    Mutex::Autolock lock(mMutex);
   1.243 +
   1.244 +    if (mAbandoned) {
   1.245 +        ST_LOGE("query: GonkBufferQueue has been abandoned!");
   1.246 +        return NO_INIT;
   1.247 +    }
   1.248 +
   1.249 +    int value;
   1.250 +    switch (what) {
   1.251 +    case NATIVE_WINDOW_WIDTH:
   1.252 +        value = mDefaultWidth;
   1.253 +        break;
   1.254 +    case NATIVE_WINDOW_HEIGHT:
   1.255 +        value = mDefaultHeight;
   1.256 +        break;
   1.257 +    case NATIVE_WINDOW_FORMAT:
   1.258 +        value = mDefaultBufferFormat;
   1.259 +        break;
   1.260 +    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
   1.261 +        value = getMinUndequeuedBufferCountLocked();
   1.262 +        break;
   1.263 +    case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
   1.264 +        value = (mQueue.size() >= 2);
   1.265 +        break;
   1.266 +    default:
   1.267 +        return BAD_VALUE;
   1.268 +    }
   1.269 +    outValue[0] = value;
   1.270 +    return NO_ERROR;
   1.271 +}
   1.272 +
   1.273 +status_t GonkBufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
   1.274 +    ST_LOGV("requestBuffer: slot=%d", slot);
   1.275 +    Mutex::Autolock lock(mMutex);
   1.276 +    if (mAbandoned) {
   1.277 +        ST_LOGE("requestBuffer: GonkBufferQueue has been abandoned!");
   1.278 +        return NO_INIT;
   1.279 +    }
   1.280 +    int maxBufferCount = getMaxBufferCountLocked();
   1.281 +    if (slot < 0 || maxBufferCount <= slot) {
   1.282 +        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
   1.283 +                maxBufferCount, slot);
   1.284 +        return BAD_VALUE;
   1.285 +    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
   1.286 +        // XXX: I vaguely recall there was some reason this can be valid, but
   1.287 +        // for the life of me I can't recall under what circumstances that's
   1.288 +        // the case.
   1.289 +        ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
   1.290 +                slot, mSlots[slot].mBufferState);
   1.291 +        return BAD_VALUE;
   1.292 +    }
   1.293 +    mSlots[slot].mRequestBufferCalled = true;
   1.294 +    *buf = mSlots[slot].mGraphicBuffer;
   1.295 +    return NO_ERROR;
   1.296 +}
   1.297 +
   1.298 +status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
   1.299 +        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
   1.300 +    ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
   1.301 +
   1.302 +    if ((w && !h) || (!w && h)) {
   1.303 +        ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
   1.304 +        return BAD_VALUE;
   1.305 +    }
   1.306 +
   1.307 +    status_t returnFlags(OK);
   1.308 +    int buf = INVALID_BUFFER_SLOT;
   1.309 +
   1.310 +    { // Scope for the lock
   1.311 +        Mutex::Autolock lock(mMutex);
   1.312 +
   1.313 +        if (format == 0) {
   1.314 +            format = mDefaultBufferFormat;
   1.315 +        }
   1.316 +        // turn on usage bits the consumer requested
   1.317 +        usage |= mConsumerUsageBits;
   1.318 +
   1.319 +        int found = -1;
   1.320 +        int dequeuedCount = 0;
   1.321 +        bool tryAgain = true;
   1.322 +        while (tryAgain) {
   1.323 +            if (mAbandoned) {
   1.324 +                ST_LOGE("dequeueBuffer: GonkBufferQueue has been abandoned!");
   1.325 +                return NO_INIT;
   1.326 +            }
   1.327 +
   1.328 +            const int maxBufferCount = getMaxBufferCountLocked();
   1.329 +
   1.330 +            // Free up any buffers that are in slots beyond the max buffer
   1.331 +            // count.
   1.332 +            //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
   1.333 +            //    assert(mSlots[i].mBufferState == BufferSlot::FREE);
   1.334 +            //    if (mSlots[i].mGraphicBuffer != NULL) {
   1.335 +            //        freeBufferLocked(i);
   1.336 +            //        returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
   1.337 +            //    }
   1.338 +            //}
   1.339 +
   1.340 +            // look for a free buffer to give to the client
   1.341 +            found = INVALID_BUFFER_SLOT;
   1.342 +            dequeuedCount = 0;
   1.343 +            for (int i = 0; i < maxBufferCount; i++) {
   1.344 +                const int state = mSlots[i].mBufferState;
   1.345 +                if (state == BufferSlot::DEQUEUED) {
   1.346 +                    dequeuedCount++;
   1.347 +                }
   1.348 +
   1.349 +                if (state == BufferSlot::FREE) {
   1.350 +                    /* We return the oldest of the free buffers to avoid
   1.351 +                     * stalling the producer if possible.  This is because
   1.352 +                     * the consumer may still have pending reads of the
   1.353 +                     * buffers in flight.
   1.354 +                     */
   1.355 +                    if ((found < 0) ||
   1.356 +                            mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
   1.357 +                        found = i;
   1.358 +                    }
   1.359 +                }
   1.360 +            }
   1.361 +
   1.362 +            // clients are not allowed to dequeue more than one buffer
   1.363 +            // if they didn't set a buffer count.
   1.364 +            if (!mOverrideMaxBufferCount && dequeuedCount) {
   1.365 +                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
   1.366 +                        "setting the buffer count");
   1.367 +                return -EINVAL;
   1.368 +            }
   1.369 +
   1.370 +            // See whether a buffer has been queued since the last
   1.371 +            // setBufferCount so we know whether to perform the min undequeued
   1.372 +            // buffers check below.
   1.373 +            if (mBufferHasBeenQueued) {
   1.374 +                // make sure the client is not trying to dequeue more buffers
   1.375 +                // than allowed.
   1.376 +                const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
   1.377 +                const int minUndequeuedCount = getMinUndequeuedBufferCountLocked();
   1.378 +                if (newUndequeuedCount < minUndequeuedCount) {
   1.379 +                    ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
   1.380 +                            "exceeded (dequeued=%d undequeudCount=%d)",
   1.381 +                            minUndequeuedCount, dequeuedCount,
   1.382 +                            newUndequeuedCount);
   1.383 +                    return -EBUSY;
   1.384 +                }
   1.385 +            }
   1.386 +
   1.387 +            // If no buffer is found, wait for a buffer to be released or for
   1.388 +            // the max buffer count to change.
   1.389 +            tryAgain = found == INVALID_BUFFER_SLOT;
   1.390 +            if (tryAgain) {
   1.391 +                mDequeueCondition.wait(mMutex);
   1.392 +            }
   1.393 +        }
   1.394 +
   1.395 +
   1.396 +        if (found == INVALID_BUFFER_SLOT) {
   1.397 +            // This should not happen.
   1.398 +            ST_LOGE("dequeueBuffer: no available buffer slots");
   1.399 +            return -EBUSY;
   1.400 +        }
   1.401 +
   1.402 +        buf = found;
   1.403 +        *outBuf = found;
   1.404 +
   1.405 +        const bool useDefaultSize = !w && !h;
   1.406 +        if (useDefaultSize) {
   1.407 +            // use the default size
   1.408 +            w = mDefaultWidth;
   1.409 +            h = mDefaultHeight;
   1.410 +        }
   1.411 +
   1.412 +        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
   1.413 +
   1.414 +        const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
   1.415 +        if ((buffer == NULL) ||
   1.416 +            (uint32_t(buffer->width)  != w) ||
   1.417 +            (uint32_t(buffer->height) != h) ||
   1.418 +            (uint32_t(buffer->format) != format) ||
   1.419 +            ((uint32_t(buffer->usage) & usage) != usage))
   1.420 +        {
   1.421 +            mSlots[buf].mAcquireCalled = false;
   1.422 +            mSlots[buf].mGraphicBuffer = NULL;
   1.423 +            mSlots[buf].mRequestBufferCalled = false;
   1.424 +            mSlots[buf].mFence = Fence::NO_FENCE;
   1.425 +            if (mSlots[buf].mTextureClient) {
   1.426 +              mSlots[buf].mTextureClient->ClearRecycleCallback();
   1.427 +              // release TextureClient in ImageBridge thread
   1.428 +              nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[buf].mTextureClient);
   1.429 +              mSlots[buf].mTextureClient = NULL;
   1.430 +              ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
   1.431 +            }
   1.432 +            returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
   1.433 +        }
   1.434 +
   1.435 +        *outFence = mSlots[buf].mFence;
   1.436 +        mSlots[buf].mFence = Fence::NO_FENCE;
   1.437 +    }  // end lock scope
   1.438 +
   1.439 +    sp<GraphicBuffer> graphicBuffer;
   1.440 +    if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
   1.441 +        RefPtr<GrallocTextureClientOGL> textureClient =
   1.442 +            new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(),
   1.443 +                                        gfx::SurfaceFormat::UNKNOWN,
   1.444 +                                        gfx::BackendType::NONE,
   1.445 +                                        TEXTURE_DEALLOCATE_CLIENT);
   1.446 +        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
   1.447 +        bool result = textureClient->AllocateGralloc(IntSize(w, h), format, usage);
   1.448 +        sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer();
   1.449 +        if (!result || !graphicBuffer.get()) {
   1.450 +            ST_LOGE("dequeueBuffer: failed to alloc gralloc buffer");
   1.451 +            return -ENOMEM;
   1.452 +        }
   1.453 +
   1.454 +        { // Scope for the lock
   1.455 +            Mutex::Autolock lock(mMutex);
   1.456 +
   1.457 +            if (mAbandoned) {
   1.458 +                ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
   1.459 +                return NO_INIT;
   1.460 +            }
   1.461 +
   1.462 +            mSlots[buf].mGraphicBuffer = graphicBuffer;
   1.463 +            mSlots[buf].mTextureClient = textureClient;
   1.464 +            ST_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
   1.465 +                    mSlots[buf].mGraphicBuffer->handle);
   1.466 +            //mSlots[*outBuf].mGraphicBuffer = graphicBuffer;
   1.467 +        }
   1.468 +    }
   1.469 +
   1.470 +    ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
   1.471 +            mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
   1.472 +
   1.473 +    return returnFlags;
   1.474 +}
   1.475 +
   1.476 +status_t GonkBufferQueue::setSynchronousMode(bool enabled) {
   1.477 +    return NO_ERROR;
   1.478 +}
   1.479 +
   1.480 +status_t GonkBufferQueue::queueBuffer(int buf,
   1.481 +        const QueueBufferInput& input, QueueBufferOutput* output) {
   1.482 +
   1.483 +    Rect crop;
   1.484 +    uint32_t transform;
   1.485 +    int scalingMode;
   1.486 +    int64_t timestamp;
   1.487 +    sp<Fence> fence;
   1.488 +
   1.489 +    input.deflate(&timestamp, &crop, &scalingMode, &transform, &fence);
   1.490 +
   1.491 +#if ANDROID_VERSION >= 18
   1.492 +    if (fence == NULL) {
   1.493 +        ST_LOGE("queueBuffer: fence is NULL");
   1.494 +        return BAD_VALUE;
   1.495 +    }
   1.496 +#endif
   1.497 +
   1.498 +    ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
   1.499 +            "scale=%s",
   1.500 +            buf, timestamp, crop.left, crop.top, crop.right, crop.bottom,
   1.501 +            transform, scalingModeName(scalingMode));
   1.502 +
   1.503 +    sp<ConsumerListener> listener;
   1.504 +
   1.505 +    { // scope for the lock
   1.506 +        Mutex::Autolock lock(mMutex);
   1.507 +        if (mAbandoned) {
   1.508 +            ST_LOGE("queueBuffer: GonkBufferQueue has been abandoned!");
   1.509 +            return NO_INIT;
   1.510 +        }
   1.511 +        int maxBufferCount = getMaxBufferCountLocked();
   1.512 +        if (buf < 0 || buf >= maxBufferCount) {
   1.513 +            ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
   1.514 +                    maxBufferCount, buf);
   1.515 +            return -EINVAL;
   1.516 +        } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
   1.517 +            ST_LOGE("queueBuffer: slot %d is not owned by the client "
   1.518 +                    "(state=%d)", buf, mSlots[buf].mBufferState);
   1.519 +            return -EINVAL;
   1.520 +        } else if (!mSlots[buf].mRequestBufferCalled) {
   1.521 +            ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
   1.522 +                    "buffer", buf);
   1.523 +            return -EINVAL;
   1.524 +        }
   1.525 +
   1.526 +        const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);
   1.527 +        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
   1.528 +        Rect croppedCrop;
   1.529 +        crop.intersect(bufferRect, &croppedCrop);
   1.530 +        if (croppedCrop != crop) {
   1.531 +            ST_LOGE("queueBuffer: crop rect is not contained within the "
   1.532 +                    "buffer in slot %d", buf);
   1.533 +            return -EINVAL;
   1.534 +        }
   1.535 +
   1.536 +        if (mSynchronousMode) {
   1.537 +            // In synchronous mode we queue all buffers in a FIFO.
   1.538 +            mQueue.push_back(buf);
   1.539 +
   1.540 +            // Synchronous mode always signals that an additional frame should
   1.541 +            // be consumed.
   1.542 +            listener = mConsumerListener;
   1.543 +        } else {
   1.544 +            // In asynchronous mode we only keep the most recent buffer.
   1.545 +            if (mQueue.empty()) {
   1.546 +                mQueue.push_back(buf);
   1.547 +
   1.548 +                // Asynchronous mode only signals that a frame should be
   1.549 +                // consumed if no previous frame was pending. If a frame were
   1.550 +                // pending then the consumer would have already been notified.
   1.551 +                listener = mConsumerListener;
   1.552 +            } else {
   1.553 +                Fifo::iterator front(mQueue.begin());
   1.554 +                // buffer currently queued is freed
   1.555 +                mSlots[*front].mBufferState = BufferSlot::FREE;
   1.556 +                // and we record the new buffer index in the queued list
   1.557 +                *front = buf;
   1.558 +            }
   1.559 +        }
   1.560 +
   1.561 +        mSlots[buf].mTimestamp = timestamp;
   1.562 +        mSlots[buf].mCrop = crop;
   1.563 +        mSlots[buf].mTransform = transform;
   1.564 +        mSlots[buf].mFence = fence;
   1.565 +
   1.566 +        switch (scalingMode) {
   1.567 +            case NATIVE_WINDOW_SCALING_MODE_FREEZE:
   1.568 +            case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
   1.569 +            case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
   1.570 +                break;
   1.571 +            default:
   1.572 +                ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode);
   1.573 +                scalingMode = mSlots[buf].mScalingMode;
   1.574 +                break;
   1.575 +        }
   1.576 +
   1.577 +        mSlots[buf].mBufferState = BufferSlot::QUEUED;
   1.578 +        mSlots[buf].mScalingMode = scalingMode;
   1.579 +        mFrameCounter++;
   1.580 +        mSlots[buf].mFrameNumber = mFrameCounter;
   1.581 +
   1.582 +        mBufferHasBeenQueued = true;
   1.583 +        mDequeueCondition.broadcast();
   1.584 +
   1.585 +        output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,
   1.586 +                mQueue.size());
   1.587 +    } // scope for the lock
   1.588 +
   1.589 +    // call back without lock held
   1.590 +    if (listener != 0) {
   1.591 +        listener->onFrameAvailable();
   1.592 +    }
   1.593 +    return NO_ERROR;
   1.594 +}
   1.595 +
   1.596 +#if ANDROID_VERSION == 17
   1.597 +void GonkBufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
   1.598 +#else
   1.599 +void GonkBufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
   1.600 +#endif
   1.601 +
   1.602 +    ST_LOGV("cancelBuffer: slot=%d", buf);
   1.603 +    Mutex::Autolock lock(mMutex);
   1.604 +
   1.605 +    if (mAbandoned) {
   1.606 +        ST_LOGW("cancelBuffer: GonkBufferQueue has been abandoned!");
   1.607 +        return;
   1.608 +    }
   1.609 +
   1.610 +    int maxBufferCount = getMaxBufferCountLocked();
   1.611 +    if (buf < 0 || buf >= maxBufferCount) {
   1.612 +        ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
   1.613 +                maxBufferCount, buf);
   1.614 +        return;
   1.615 +    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
   1.616 +        ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
   1.617 +                buf, mSlots[buf].mBufferState);
   1.618 +        return;
   1.619 +#if ANDROID_VERSION >= 18
   1.620 +    } else if (fence == NULL) {
   1.621 +        ST_LOGE("cancelBuffer: fence is NULL");
   1.622 +        return;
   1.623 +#endif
   1.624 +    }
   1.625 +    mSlots[buf].mBufferState = BufferSlot::FREE;
   1.626 +    mSlots[buf].mFrameNumber = 0;
   1.627 +    mSlots[buf].mFence = fence;
   1.628 +    mDequeueCondition.broadcast();
   1.629 +}
   1.630 +
   1.631 +status_t GonkBufferQueue::connect(int api, QueueBufferOutput* output) {
   1.632 +    ST_LOGV("connect: api=%d", api);
   1.633 +    Mutex::Autolock lock(mMutex);
   1.634 +
   1.635 +    if (mAbandoned) {
   1.636 +        ST_LOGE("connect: GonkBufferQueue has been abandoned!");
   1.637 +        return NO_INIT;
   1.638 +    }
   1.639 +
   1.640 +    if (mConsumerListener == NULL) {
   1.641 +        ST_LOGE("connect: GonkBufferQueue has no consumer!");
   1.642 +        return NO_INIT;
   1.643 +    }
   1.644 +
   1.645 +    int err = NO_ERROR;
   1.646 +    switch (api) {
   1.647 +        case NATIVE_WINDOW_API_EGL:
   1.648 +        case NATIVE_WINDOW_API_CPU:
   1.649 +        case NATIVE_WINDOW_API_MEDIA:
   1.650 +        case NATIVE_WINDOW_API_CAMERA:
   1.651 +            if (mConnectedApi != NO_CONNECTED_API) {
   1.652 +                ST_LOGE("connect: already connected (cur=%d, req=%d)",
   1.653 +                        mConnectedApi, api);
   1.654 +                err = -EINVAL;
   1.655 +            } else {
   1.656 +                mConnectedApi = api;
   1.657 +                output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,
   1.658 +                        mQueue.size());
   1.659 +            }
   1.660 +            break;
   1.661 +        default:
   1.662 +            err = -EINVAL;
   1.663 +            break;
   1.664 +    }
   1.665 +
   1.666 +    mBufferHasBeenQueued = false;
   1.667 +
   1.668 +    return err;
   1.669 +}
   1.670 +
   1.671 +status_t GonkBufferQueue::disconnect(int api) {
   1.672 +    ST_LOGV("disconnect: api=%d", api);
   1.673 +
   1.674 +    int err = NO_ERROR;
   1.675 +    sp<ConsumerListener> listener;
   1.676 +
   1.677 +    { // Scope for the lock
   1.678 +        Mutex::Autolock lock(mMutex);
   1.679 +
   1.680 +        if (mAbandoned) {
   1.681 +            // it is not really an error to disconnect after the surface
   1.682 +            // has been abandoned, it should just be a no-op.
   1.683 +            return NO_ERROR;
   1.684 +        }
   1.685 +
   1.686 +        switch (api) {
   1.687 +            case NATIVE_WINDOW_API_EGL:
   1.688 +            case NATIVE_WINDOW_API_CPU:
   1.689 +            case NATIVE_WINDOW_API_MEDIA:
   1.690 +            case NATIVE_WINDOW_API_CAMERA:
   1.691 +                if (mConnectedApi == api) {
   1.692 +                    freeAllBuffersLocked();
   1.693 +                    mConnectedApi = NO_CONNECTED_API;
   1.694 +                    mDequeueCondition.broadcast();
   1.695 +                    listener = mConsumerListener;
   1.696 +                } else {
   1.697 +                    ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
   1.698 +                            mConnectedApi, api);
   1.699 +                    err = -EINVAL;
   1.700 +                }
   1.701 +                break;
   1.702 +            default:
   1.703 +                ST_LOGE("disconnect: unknown API %d", api);
   1.704 +                err = -EINVAL;
   1.705 +                break;
   1.706 +        }
   1.707 +    }
   1.708 +
   1.709 +    if (listener != NULL) {
   1.710 +        listener->onBuffersReleased();
   1.711 +    }
   1.712 +
   1.713 +    return err;
   1.714 +}
   1.715 +
   1.716 +void GonkBufferQueue::dump(String8& result) const
   1.717 +{
   1.718 +    char buffer[1024];
   1.719 +    GonkBufferQueue::dump(result, "", buffer, 1024);
   1.720 +}
   1.721 +
   1.722 +void GonkBufferQueue::dump(String8& result, const char* prefix,
   1.723 +        char* buffer, size_t SIZE) const
   1.724 +{
   1.725 +    Mutex::Autolock _l(mMutex);
   1.726 +
   1.727 +    String8 fifo;
   1.728 +    int fifoSize = 0;
   1.729 +    Fifo::const_iterator i(mQueue.begin());
   1.730 +    while (i != mQueue.end()) {
   1.731 +       snprintf(buffer, SIZE, "%02d ", *i++);
   1.732 +       fifoSize++;
   1.733 +       fifo.append(buffer);
   1.734 +    }
   1.735 +
   1.736 +    int maxBufferCount = getMaxBufferCountLocked();
   1.737 +
   1.738 +    snprintf(buffer, SIZE,
   1.739 +            "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
   1.740 +            "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
   1.741 +            prefix, maxBufferCount, mSynchronousMode, mDefaultWidth,
   1.742 +            mDefaultHeight, mDefaultBufferFormat, mTransformHint,
   1.743 +            fifoSize, fifo.string());
   1.744 +    result.append(buffer);
   1.745 +
   1.746 +
   1.747 +    struct {
   1.748 +        const char * operator()(int state) const {
   1.749 +            switch (state) {
   1.750 +                case BufferSlot::DEQUEUED: return "DEQUEUED";
   1.751 +                case BufferSlot::QUEUED: return "QUEUED";
   1.752 +                case BufferSlot::FREE: return "FREE";
   1.753 +                case BufferSlot::ACQUIRED: return "ACQUIRED";
   1.754 +                default: return "Unknown";
   1.755 +            }
   1.756 +        }
   1.757 +    } stateName;
   1.758 +
   1.759 +    for (int i=0 ; i<maxBufferCount ; i++) {
   1.760 +        const BufferSlot& slot(mSlots[i]);
   1.761 +        snprintf(buffer, SIZE,
   1.762 +                "%s%s[%02d] "
   1.763 +                "state=%-8s, crop=[%d,%d,%d,%d], "
   1.764 +                "xform=0x%02x, time=%#llx, scale=%s",
   1.765 +                prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i,
   1.766 +                stateName(slot.mBufferState),
   1.767 +                slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
   1.768 +                slot.mCrop.bottom, slot.mTransform, slot.mTimestamp,
   1.769 +                scalingModeName(slot.mScalingMode)
   1.770 +        );
   1.771 +        result.append(buffer);
   1.772 +
   1.773 +        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
   1.774 +        if (buf != NULL) {
   1.775 +            snprintf(buffer, SIZE,
   1.776 +                    ", %p [%4ux%4u:%4u,%3X]",
   1.777 +                    buf->handle, buf->width, buf->height, buf->stride,
   1.778 +                    buf->format);
   1.779 +            result.append(buffer);
   1.780 +        }
   1.781 +        result.append("\n");
   1.782 +    }
   1.783 +}
   1.784 +
   1.785 +void GonkBufferQueue::freeAllBuffersLocked()
   1.786 +{
   1.787 +    ALOGW_IF(!mQueue.isEmpty(),
   1.788 +            "freeAllBuffersLocked called but mQueue is not empty");
   1.789 +    mQueue.clear();
   1.790 +    mBufferHasBeenQueued = false;
   1.791 +    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
   1.792 +        mSlots[i].mGraphicBuffer = 0;
   1.793 +        if (mSlots[i].mTextureClient) {
   1.794 +          mSlots[i].mTextureClient->ClearRecycleCallback();
   1.795 +          // release TextureClient in ImageBridge thread
   1.796 +          nsProxyReleaseTask* task = new nsProxyReleaseTask(mSlots[i].mTextureClient);
   1.797 +          mSlots[i].mTextureClient = NULL;
   1.798 +          ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(FROM_HERE, task);
   1.799 +        }
   1.800 +        if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
   1.801 +            mSlots[i].mNeedsCleanupOnRelease = true;
   1.802 +        }
   1.803 +        mSlots[i].mBufferState = BufferSlot::FREE;
   1.804 +        mSlots[i].mFrameNumber = 0;
   1.805 +        mSlots[i].mAcquireCalled = false;
   1.806 +        // destroy fence as GonkBufferQueue now takes ownership
   1.807 +        mSlots[i].mFence = Fence::NO_FENCE;
   1.808 +    }
   1.809 +}
   1.810 +
   1.811 +status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer) {
   1.812 +    Mutex::Autolock _l(mMutex);
   1.813 +
   1.814 +    // Check that the consumer doesn't currently have the maximum number of
   1.815 +    // buffers acquired.  We allow the max buffer count to be exceeded by one
   1.816 +    // buffer, so that the consumer can successfully set up the newly acquired
   1.817 +    // buffer before releasing the old one.
   1.818 +    int numAcquiredBuffers = 0;
   1.819 +    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
   1.820 +        if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
   1.821 +            numAcquiredBuffers++;
   1.822 +        }
   1.823 +    }
   1.824 +    if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) {
   1.825 +        ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)",
   1.826 +                numAcquiredBuffers, mMaxAcquiredBufferCount);
   1.827 +        return INVALID_OPERATION;
   1.828 +    }
   1.829 +
   1.830 +    // check if queue is empty
   1.831 +    // In asynchronous mode the list is guaranteed to be one buffer
   1.832 +    // deep, while in synchronous mode we use the oldest buffer.
   1.833 +    if (!mQueue.empty()) {
   1.834 +        Fifo::iterator front(mQueue.begin());
   1.835 +        int buf = *front;
   1.836 +
   1.837 +        // In android, when the buffer is aquired by BufferConsumer,
   1.838 +        // BufferQueue releases a reference to the buffer and
   1.839 +        // it's ownership moves to the BufferConsumer.
   1.840 +        // In b2g, GonkBufferQueue continues to have a buffer ownership.
   1.841 +        // It is necessary to free buffer via ImageBridgeChild.
   1.842 +
   1.843 +        //if (mSlots[buf].mAcquireCalled) {
   1.844 +        //    buffer->mGraphicBuffer = NULL;
   1.845 +        //} else {
   1.846 +        //    buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
   1.847 +        //}
   1.848 +        buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
   1.849 +        buffer->mCrop = mSlots[buf].mCrop;
   1.850 +        buffer->mTransform = mSlots[buf].mTransform;
   1.851 +        buffer->mScalingMode = mSlots[buf].mScalingMode;
   1.852 +        buffer->mFrameNumber = mSlots[buf].mFrameNumber;
   1.853 +        buffer->mTimestamp = mSlots[buf].mTimestamp;
   1.854 +        buffer->mBuf = buf;
   1.855 +        buffer->mFence = mSlots[buf].mFence;
   1.856 +
   1.857 +        mSlots[buf].mAcquireCalled = true;
   1.858 +        mSlots[buf].mNeedsCleanupOnRelease = false;
   1.859 +        mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
   1.860 +        mSlots[buf].mFence = Fence::NO_FENCE;
   1.861 +
   1.862 +        mQueue.erase(front);
   1.863 +        mDequeueCondition.broadcast();
   1.864 +    } else {
   1.865 +        return NO_BUFFER_AVAILABLE;
   1.866 +    }
   1.867 +
   1.868 +    return NO_ERROR;
   1.869 +}
   1.870 +
   1.871 +status_t GonkBufferQueue::releaseBuffer(int buf, const sp<Fence>& fence) {
   1.872 +    Mutex::Autolock _l(mMutex);
   1.873 +
   1.874 +#if ANDROID_VERSION == 17
   1.875 +    if (buf == INVALID_BUFFER_SLOT) {
   1.876 +#else
   1.877 +    if (buf == INVALID_BUFFER_SLOT || fence == NULL) {
   1.878 +#endif
   1.879 +        return BAD_VALUE;
   1.880 +    }
   1.881 +
   1.882 +    mSlots[buf].mFence = fence;
   1.883 +
   1.884 +    // The buffer can now only be released if its in the acquired state
   1.885 +    if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
   1.886 +        mSlots[buf].mBufferState = BufferSlot::FREE;
   1.887 +    } else if (mSlots[buf].mNeedsCleanupOnRelease) {
   1.888 +        ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState);
   1.889 +        mSlots[buf].mNeedsCleanupOnRelease = false;
   1.890 +        return STALE_BUFFER_SLOT;
   1.891 +    } else {
   1.892 +        ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState);
   1.893 +        return -EINVAL;
   1.894 +    }
   1.895 +
   1.896 +    mDequeueCondition.broadcast();
   1.897 +    return NO_ERROR;
   1.898 +}
   1.899 +
   1.900 +status_t GonkBufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) {
   1.901 +    ST_LOGV("consumerConnect");
   1.902 +    Mutex::Autolock lock(mMutex);
   1.903 +
   1.904 +    if (mAbandoned) {
   1.905 +        ST_LOGE("consumerConnect: GonkBufferQueue has been abandoned!");
   1.906 +        return NO_INIT;
   1.907 +    }
   1.908 +    if (consumerListener == NULL) {
   1.909 +        ST_LOGE("consumerConnect: consumerListener may not be NULL");
   1.910 +        return BAD_VALUE;
   1.911 +    }
   1.912 +
   1.913 +    mConsumerListener = consumerListener;
   1.914 +
   1.915 +    return NO_ERROR;
   1.916 +}
   1.917 +
   1.918 +status_t GonkBufferQueue::consumerDisconnect() {
   1.919 +    ST_LOGV("consumerDisconnect");
   1.920 +    Mutex::Autolock lock(mMutex);
   1.921 +
   1.922 +    if (mConsumerListener == NULL) {
   1.923 +        ST_LOGE("consumerDisconnect: No consumer is connected!");
   1.924 +        return -EINVAL;
   1.925 +    }
   1.926 +
   1.927 +    mAbandoned = true;
   1.928 +    mConsumerListener = NULL;
   1.929 +    mQueue.clear();
   1.930 +    freeAllBuffersLocked();
   1.931 +    mDequeueCondition.broadcast();
   1.932 +    return NO_ERROR;
   1.933 +}
   1.934 +
   1.935 +status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) {
   1.936 +    ST_LOGV("getReleasedBuffers");
   1.937 +    Mutex::Autolock lock(mMutex);
   1.938 +
   1.939 +    if (mAbandoned) {
   1.940 +        ST_LOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!");
   1.941 +        return NO_INIT;
   1.942 +    }
   1.943 +
   1.944 +    uint32_t mask = 0;
   1.945 +    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
   1.946 +        if (!mSlots[i].mAcquireCalled) {
   1.947 +            mask |= 1 << i;
   1.948 +        }
   1.949 +    }
   1.950 +    *slotMask = mask;
   1.951 +
   1.952 +    ST_LOGV("getReleasedBuffers: returning mask %#x", mask);
   1.953 +    return NO_ERROR;
   1.954 +}
   1.955 +
   1.956 +status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
   1.957 +{
   1.958 +    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
   1.959 +    if (!w || !h) {
   1.960 +        ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
   1.961 +                w, h);
   1.962 +        return BAD_VALUE;
   1.963 +    }
   1.964 +
   1.965 +    Mutex::Autolock lock(mMutex);
   1.966 +    mDefaultWidth = w;
   1.967 +    mDefaultHeight = h;
   1.968 +    return NO_ERROR;
   1.969 +}
   1.970 +
   1.971 +status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) {
   1.972 +    Mutex::Autolock lock(mMutex);
   1.973 +    return setDefaultMaxBufferCountLocked(bufferCount);
   1.974 +}
   1.975 +
   1.976 +status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
   1.977 +    Mutex::Autolock lock(mMutex);
   1.978 +    if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) {
   1.979 +        ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d",
   1.980 +                maxAcquiredBuffers);
   1.981 +        return BAD_VALUE;
   1.982 +    }
   1.983 +    if (mConnectedApi != NO_CONNECTED_API) {
   1.984 +        return INVALID_OPERATION;
   1.985 +    }
   1.986 +    mMaxAcquiredBufferCount = maxAcquiredBuffers;
   1.987 +    return NO_ERROR;
   1.988 +}
   1.989 +
   1.990 +int GonkBufferQueue::getMinMaxBufferCountLocked() const {
   1.991 +    return getMinUndequeuedBufferCountLocked() + 1;
   1.992 +}
   1.993 +
   1.994 +int GonkBufferQueue::getMinUndequeuedBufferCountLocked() const {
   1.995 +    return mSynchronousMode ? mMaxAcquiredBufferCount :
   1.996 +            mMaxAcquiredBufferCount + 1;
   1.997 +}
   1.998 +
   1.999 +int GonkBufferQueue::getMaxBufferCountLocked() const {
  1.1000 +    int minMaxBufferCount = getMinMaxBufferCountLocked();
  1.1001 +
  1.1002 +    int maxBufferCount = mDefaultMaxBufferCount;
  1.1003 +    if (maxBufferCount < minMaxBufferCount) {
  1.1004 +        maxBufferCount = minMaxBufferCount;
  1.1005 +    }
  1.1006 +    if (mOverrideMaxBufferCount != 0) {
  1.1007 +        assert(mOverrideMaxBufferCount >= minMaxBufferCount);
  1.1008 +        maxBufferCount = mOverrideMaxBufferCount;
  1.1009 +    }
  1.1010 +
  1.1011 +    // Any buffers that are dequeued by the producer or sitting in the queue
  1.1012 +    // waiting to be consumed need to have their slots preserved.  Such
  1.1013 +    // buffers will temporarily keep the max buffer count up until the slots
  1.1014 +    // no longer need to be preserved.
  1.1015 +    for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
  1.1016 +        BufferSlot::BufferState state = mSlots[i].mBufferState;
  1.1017 +        if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
  1.1018 +            maxBufferCount = i + 1;
  1.1019 +        }
  1.1020 +    }
  1.1021 +
  1.1022 +    return maxBufferCount;
  1.1023 +}
  1.1024 +
  1.1025 +GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener(
  1.1026 +        const wp<GonkBufferQueue::ConsumerListener>& consumerListener):
  1.1027 +        mConsumerListener(consumerListener) {}
  1.1028 +
  1.1029 +GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
  1.1030 +
  1.1031 +void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() {
  1.1032 +    sp<GonkBufferQueue::ConsumerListener> listener(mConsumerListener.promote());
  1.1033 +    if (listener != NULL) {
  1.1034 +        listener->onFrameAvailable();
  1.1035 +    }
  1.1036 +}
  1.1037 +
  1.1038 +void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() {
  1.1039 +    sp<GonkBufferQueue::ConsumerListener> listener(mConsumerListener.promote());
  1.1040 +    if (listener != NULL) {
  1.1041 +        listener->onBuffersReleased();
  1.1042 +    }
  1.1043 +}
  1.1044 +
  1.1045 +}; // namespace android

mercurial