CpuConsumer.cpp revision b42b1ac1587aebda5e2f334d95b620271fafba4e
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
32// Get an ID that's unique within this process.
33static int32_t createProcessUniqueId() {
34    static volatile int32_t globalCounter = 0;
35    return android_atomic_inc(&globalCounter);
36}
37
38CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) :
39    mMaxLockedBuffers(maxLockedBuffers),
40    mCurrentLockedBuffers(0)
41{
42    mName = String8::format("cc-unnamed-%d-%d", getpid(),
43            createProcessUniqueId());
44
45    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
46        mBufferPointers[i] = NULL;
47    }
48
49    mBufferQueue = new BufferQueue(true);
50
51    wp<BufferQueue::ConsumerListener> listener;
52    sp<BufferQueue::ConsumerListener> proxy;
53    listener = static_cast<BufferQueue::ConsumerListener*>(this);
54    proxy = new BufferQueue::ProxyConsumerListener(listener);
55
56    status_t err = mBufferQueue->consumerConnect(proxy);
57    if (err != NO_ERROR) {
58        ALOGE("CpuConsumer: error connecting to BufferQueue: %s (%d)",
59                strerror(-err), err);
60    } else {
61        mBufferQueue->setSynchronousMode(true);
62        mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
63        mBufferQueue->setConsumerName(mName);
64    }
65}
66
67CpuConsumer::~CpuConsumer()
68{
69    Mutex::Autolock _l(mMutex);
70    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
71        freeBufferLocked(i);
72    }
73    mBufferQueue->consumerDisconnect();
74    mBufferQueue.clear();
75}
76
77void CpuConsumer::setName(const String8& name) {
78    Mutex::Autolock _l(mMutex);
79    mName = name;
80    mBufferQueue->setConsumerName(name);
81}
82
83status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
84    status_t err;
85
86    if (!nativeBuffer) return BAD_VALUE;
87    if (mCurrentLockedBuffers == mMaxLockedBuffers) {
88        return INVALID_OPERATION;
89    }
90
91    BufferQueue::BufferItem b;
92
93    Mutex::Autolock _l(mMutex);
94
95    err = mBufferQueue->acquireBuffer(&b);
96    if (err != OK) {
97        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
98            return BAD_VALUE;
99        } else {
100            CC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
101            return err;
102        }
103    }
104
105    int buf = b.mBuf;
106
107    if (b.mGraphicBuffer != NULL) {
108        if (mBufferPointers[buf] != NULL) {
109            CC_LOGE("Reallocation of buffer %d while in consumer use!", buf);
110            mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
111                    Fence::NO_FENCE);
112            return BAD_VALUE;
113        }
114        mBufferSlot[buf] = b.mGraphicBuffer;
115    }
116
117    if (b.mFence.get()) {
118        err = b.mFence->wait(Fence::TIMEOUT_NEVER);
119        if (err != OK) {
120            CC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
121                    strerror(-err), err);
122            return err;
123        }
124    }
125
126    err = mBufferSlot[buf]->lock(
127        GraphicBuffer::USAGE_SW_READ_OFTEN,
128        b.mCrop,
129        &mBufferPointers[buf]);
130
131    if (mBufferPointers[buf] != NULL && err != OK) {
132        CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err),
133                err);
134        return err;
135    }
136
137    nativeBuffer->data   = reinterpret_cast<uint8_t*>(mBufferPointers[buf]);
138    nativeBuffer->width  = mBufferSlot[buf]->getWidth();
139    nativeBuffer->height = mBufferSlot[buf]->getHeight();
140    nativeBuffer->format = mBufferSlot[buf]->getPixelFormat();
141    nativeBuffer->stride = mBufferSlot[buf]->getStride();
142
143    nativeBuffer->crop        = b.mCrop;
144    nativeBuffer->transform   = b.mTransform;
145    nativeBuffer->scalingMode = b.mScalingMode;
146    nativeBuffer->timestamp   = b.mTimestamp;
147    nativeBuffer->frameNumber = b.mFrameNumber;
148
149    mCurrentLockedBuffers++;
150
151    return OK;
152}
153
154status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
155    Mutex::Autolock _l(mMutex);
156    int buf = 0;
157    status_t err;
158
159    void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
160    for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) {
161        if (bufPtr == mBufferPointers[buf]) break;
162    }
163    if (buf == BufferQueue::NUM_BUFFER_SLOTS) {
164        CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
165        return BAD_VALUE;
166    }
167
168    mBufferPointers[buf] = NULL;
169    err = mBufferSlot[buf]->unlock();
170    if (err != OK) {
171        CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf);
172        return err;
173    }
174    err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
175            Fence::NO_FENCE);
176    if (err == BufferQueue::STALE_BUFFER_SLOT) {
177        freeBufferLocked(buf);
178    } else if (err != OK) {
179        CC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__,
180                buf);
181        return err;
182    }
183
184    mCurrentLockedBuffers--;
185
186    return OK;
187}
188
189void CpuConsumer::setFrameAvailableListener(
190        const sp<FrameAvailableListener>& listener) {
191    CC_LOGV("setFrameAvailableListener");
192    Mutex::Autolock lock(mMutex);
193    mFrameAvailableListener = listener;
194}
195
196
197void CpuConsumer::onFrameAvailable() {
198    CC_LOGV("onFrameAvailable");
199    sp<FrameAvailableListener> listener;
200    { // scope for the lock
201        Mutex::Autolock _l(mMutex);
202        listener = mFrameAvailableListener;
203    }
204
205    if (listener != NULL) {
206        CC_LOGV("actually calling onFrameAvailable");
207        listener->onFrameAvailable();
208    }
209}
210
211void CpuConsumer::onBuffersReleased() {
212    CC_LOGV("onBuffersReleased");
213
214    Mutex::Autolock lock(mMutex);
215
216    uint32_t mask = 0;
217    mBufferQueue->getReleasedBuffers(&mask);
218    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
219        if (mask & (1 << i)) {
220            freeBufferLocked(i);
221        }
222    }
223
224}
225
226status_t CpuConsumer::freeBufferLocked(int buf) {
227    status_t err = OK;
228
229    if (mBufferPointers[buf] != NULL) {
230        CC_LOGW("Buffer %d freed while locked by consumer", buf);
231        mBufferPointers[buf] = NULL;
232        err = mBufferSlot[buf]->unlock();
233        if (err != OK) {
234            CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf);
235        }
236        mCurrentLockedBuffers--;
237    }
238    mBufferSlot[buf] = NULL;
239    return err;
240}
241
242} // namespace android
243