1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "CpuConsumer"
19#define ATRACE_TAG ATRACE_TAG_GRAPHICS
20#include <utils/Log.h>
21
22#include <gui/CpuConsumer.h>
23
24#define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
25#define CC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
26#define CC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
27#define CC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
28#define CC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
29
30namespace android {
31
32CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) :
33    ConsumerBase(new BufferQueue(true) ),
34    mMaxLockedBuffers(maxLockedBuffers),
35    mCurrentLockedBuffers(0)
36{
37
38    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
39        mBufferPointers[i] = NULL;
40    }
41
42    mBufferQueue->setSynchronousMode(true);
43    mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
44    mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers);
45}
46
47CpuConsumer::~CpuConsumer() {
48}
49
50void CpuConsumer::setName(const String8& name) {
51    Mutex::Autolock _l(mMutex);
52    mName = name;
53    mBufferQueue->setConsumerName(name);
54}
55
56status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
57    status_t err;
58
59    if (!nativeBuffer) return BAD_VALUE;
60    if (mCurrentLockedBuffers == mMaxLockedBuffers) {
61        return INVALID_OPERATION;
62    }
63
64    BufferQueue::BufferItem b;
65
66    Mutex::Autolock _l(mMutex);
67
68    err = acquireBufferLocked(&b);
69    if (err != OK) {
70        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
71            return BAD_VALUE;
72        } else {
73            CC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
74            return err;
75        }
76    }
77
78    int buf = b.mBuf;
79
80    if (b.mFence.get()) {
81        err = b.mFence->waitForever(1000, "CpuConsumer::lockNextBuffer");
82        if (err != OK) {
83            CC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
84                    strerror(-err), err);
85            return err;
86        }
87    }
88
89    err = mSlots[buf].mGraphicBuffer->lock(
90        GraphicBuffer::USAGE_SW_READ_OFTEN,
91        b.mCrop,
92        &mBufferPointers[buf]);
93
94    if (mBufferPointers[buf] != NULL && err != OK) {
95        CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err),
96                err);
97        return err;
98    }
99
100    nativeBuffer->data   = reinterpret_cast<uint8_t*>(mBufferPointers[buf]);
101    nativeBuffer->width  = mSlots[buf].mGraphicBuffer->getWidth();
102    nativeBuffer->height = mSlots[buf].mGraphicBuffer->getHeight();
103    nativeBuffer->format = mSlots[buf].mGraphicBuffer->getPixelFormat();
104    nativeBuffer->stride = mSlots[buf].mGraphicBuffer->getStride();
105
106    nativeBuffer->crop        = b.mCrop;
107    nativeBuffer->transform   = b.mTransform;
108    nativeBuffer->scalingMode = b.mScalingMode;
109    nativeBuffer->timestamp   = b.mTimestamp;
110    nativeBuffer->frameNumber = b.mFrameNumber;
111
112    mCurrentLockedBuffers++;
113
114    return OK;
115}
116
117status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
118    Mutex::Autolock _l(mMutex);
119    int slotIndex = 0;
120    status_t err;
121
122    void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
123    for (; slotIndex < BufferQueue::NUM_BUFFER_SLOTS; slotIndex++) {
124        if (bufPtr == mBufferPointers[slotIndex]) break;
125    }
126    if (slotIndex == BufferQueue::NUM_BUFFER_SLOTS) {
127        CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
128        return BAD_VALUE;
129    }
130
131    mBufferPointers[slotIndex] = NULL;
132    err = mSlots[slotIndex].mGraphicBuffer->unlock();
133    if (err != OK) {
134        CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex);
135        return err;
136    }
137    releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
138
139    mCurrentLockedBuffers--;
140
141    return OK;
142}
143
144void CpuConsumer::freeBufferLocked(int slotIndex) {
145    if (mBufferPointers[slotIndex] != NULL) {
146        status_t err;
147        CC_LOGW("Buffer %d freed while locked by consumer", slotIndex);
148        mBufferPointers[slotIndex] = NULL;
149        err = mSlots[slotIndex].mGraphicBuffer->unlock();
150        if (err != OK) {
151            CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__,
152                    slotIndex);
153        }
154        mCurrentLockedBuffers--;
155    }
156    ConsumerBase::freeBufferLocked(slotIndex);
157}
158
159} // namespace android
160