blob: 48a54c77e335a45fd48f9c781a9733aa1b6b8918 [file] [log] [blame]
Eino-Ville Talvalae41b3182012-04-16 17:54:33 -07001/*
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 return BAD_VALUE;
112 }
113 mBufferSlot[buf] = b.mGraphicBuffer;
114 }
115
116 err = mBufferSlot[buf]->lock(
117 GraphicBuffer::USAGE_SW_READ_OFTEN,
118 b.mCrop,
119 &mBufferPointers[buf]);
120
121 if (mBufferPointers[buf] != NULL && err != OK) {
122 CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err),
123 err);
124 return err;
125 }
126
127 nativeBuffer->data = reinterpret_cast<uint8_t*>(mBufferPointers[buf]);
128 nativeBuffer->width = mBufferSlot[buf]->getWidth();
129 nativeBuffer->height = mBufferSlot[buf]->getHeight();
130 nativeBuffer->format = mBufferSlot[buf]->getPixelFormat();
131 nativeBuffer->stride = mBufferSlot[buf]->getStride();
132
133 nativeBuffer->crop = b.mCrop;
134 nativeBuffer->transform = b.mTransform;
135 nativeBuffer->scalingMode = b.mScalingMode;
136 nativeBuffer->timestamp = b.mTimestamp;
137 nativeBuffer->frameNumber = b.mFrameNumber;
138
139 mCurrentLockedBuffers++;
140
141 return OK;
142}
143
144status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
145 Mutex::Autolock _l(mMutex);
146 int buf = 0;
147 status_t err;
148
149 void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
150 for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) {
151 if (bufPtr == mBufferPointers[buf]) break;
152 }
153 if (buf == BufferQueue::NUM_BUFFER_SLOTS) {
154 CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
155 return BAD_VALUE;
156 }
157
158 mBufferPointers[buf] = NULL;
159 err = mBufferSlot[buf]->unlock();
160 if (err != OK) {
161 CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf);
162 return err;
163 }
164 err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
165 if (err == BufferQueue::STALE_BUFFER_SLOT) {
166 freeBufferLocked(buf);
167 } else if (err != OK) {
168 CC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__,
169 buf);
170 return err;
171 }
172
173 mCurrentLockedBuffers--;
174
175 return OK;
176}
177
178void CpuConsumer::setFrameAvailableListener(
179 const sp<FrameAvailableListener>& listener) {
180 CC_LOGV("setFrameAvailableListener");
181 Mutex::Autolock lock(mMutex);
182 mFrameAvailableListener = listener;
183}
184
185
186void CpuConsumer::onFrameAvailable() {
187 CC_LOGV("onFrameAvailable");
188 sp<FrameAvailableListener> listener;
189 { // scope for the lock
190 Mutex::Autolock _l(mMutex);
191 listener = mFrameAvailableListener;
192 }
193
194 if (listener != NULL) {
195 CC_LOGV("actually calling onFrameAvailable");
196 listener->onFrameAvailable();
197 }
198}
199
200void CpuConsumer::onBuffersReleased() {
201 CC_LOGV("onBuffersReleased");
202
203 Mutex::Autolock lock(mMutex);
204
205 uint32_t mask = 0;
206 mBufferQueue->getReleasedBuffers(&mask);
207 for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
208 if (mask & (1 << i)) {
209 freeBufferLocked(i);
210 }
211 }
212
213}
214
215status_t CpuConsumer::freeBufferLocked(int buf) {
216 status_t err = OK;
217
218 if (mBufferPointers[buf] != NULL) {
219 CC_LOGW("Buffer %d freed while locked by consumer", buf);
220 mBufferPointers[buf] = NULL;
221 err = mBufferSlot[buf]->unlock();
222 if (err != OK) {
223 CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf);
224 }
225 mCurrentLockedBuffers--;
226 }
227 mBufferSlot[buf] = NULL;
228 return err;
229}
230
231} // namespace android