1/*
2 * Copyright (C) 2013 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#include "rsAllocation.h"
18#include "rsContext.h"
19#include "rsGrallocConsumer.h"
20#include "rs_hal.h"
21
22namespace android {
23namespace renderscript {
24
25GrallocConsumer::GrallocConsumer (const Context *rsc, Allocation *a, uint32_t numAlloc)
26{
27    mCtx = rsc;
28    mAlloc = new Allocation *[numAlloc];
29    mAcquiredBuffer = new AcquiredBuffer[numAlloc];
30    isIdxUsed = new bool[numAlloc];
31
32    mAlloc[0] = a;
33    isIdxUsed[0] = true;
34    mNumAlloc = numAlloc;
35
36    uint32_t width  = a->mHal.drvState.lod[0].dimX;
37    uint32_t height = a->mHal.drvState.lod[0].dimY;
38    if (height < 1) height = 1;
39
40    int32_t format = AIMAGE_FORMAT_RGBA_8888;
41    if (a->mHal.state.yuv) {
42        format = AIMAGE_FORMAT_YUV_420_888;
43    }
44
45    media_status_t ret = AImageReader_new(
46            width, height, format,
47            mNumAlloc, &mImgReader);
48    if (ret != AMEDIA_OK || mImgReader == nullptr) {
49        ALOGE("Error creating image reader. ret %d", ret);
50    }
51
52    ret = AImageReader_getWindow(mImgReader, &mNativeWindow);
53    if (ret != AMEDIA_OK || mNativeWindow == nullptr) {
54        ALOGE("Error creating native window. ret %d", ret);
55    }
56
57    mReaderCb = {this, GrallocConsumer::onFrameAvailable};
58    ret = AImageReader_setImageListener(mImgReader, &mReaderCb);
59
60    for (uint32_t i = 1; i < numAlloc; i++) {
61        isIdxUsed[i] = false;
62    }
63}
64
65GrallocConsumer::~GrallocConsumer() {
66    AImageReader_delete(mImgReader);
67    delete[] mAlloc;
68    delete[] mAcquiredBuffer;
69    delete[] isIdxUsed;
70}
71
72void GrallocConsumer::onFrameAvailable(void* obj, AImageReader* reader) {
73    GrallocConsumer* consumer = (GrallocConsumer *) obj;
74    for (uint32_t i = 0; i < consumer->mNumAlloc; i++) {
75        if (consumer->mAlloc[i] != nullptr) {
76            intptr_t ip = (intptr_t)(consumer->mAlloc[i]);
77            consumer->mCtx->sendMessageToClient(&ip,
78                RS_MESSAGE_TO_CLIENT_NEW_BUFFER, 0, sizeof(ip), true);
79        }
80    }
81}
82
83ANativeWindow* GrallocConsumer::getNativeWindow() {
84    return mNativeWindow;
85}
86
87media_status_t GrallocConsumer::lockNextBuffer(uint32_t idx) {
88    media_status_t ret;
89
90    if (idx >= mNumAlloc) {
91        ALOGE("Invalid buffer index: %d", idx);
92        return AMEDIA_ERROR_INVALID_PARAMETER;
93    }
94
95    if (mAcquiredBuffer[idx].mImg != nullptr) {
96        ret = unlockBuffer(idx);
97        if (ret != AMEDIA_OK) {
98            return ret;
99        }
100    }
101
102    ret = AImageReader_acquireNextImage(mImgReader, &(mAcquiredBuffer[idx].mImg));
103    if (ret != AMEDIA_OK || mAcquiredBuffer[idx].mImg == nullptr) {
104        ALOGE("%s: acquire image from reader %p failed! ret: %d, img %p",
105                __FUNCTION__, mImgReader, ret, mAcquiredBuffer[idx].mImg);
106        return ret;
107    }
108
109    AImage *img = mAcquiredBuffer[idx].mImg;
110    int32_t format = -1;
111    ret = AImage_getFormat(img, &format);
112    if (ret != AMEDIA_OK || format == -1) {
113        ALOGE("%s: get format for image %p failed! ret: %d, format %d",
114                 __FUNCTION__, img, ret, format);
115        return ret;
116    }
117
118    if (format != AIMAGE_FORMAT_YUV_420_888 && format != AIMAGE_FORMAT_RGBA_8888) {
119        ALOGE("Format %d not supported", format);
120        return AMEDIA_ERROR_INVALID_OBJECT;
121    }
122
123    uint8_t *data = nullptr;
124    int dataLength = 0;
125    ret =  AImage_getPlaneData(img, 0, &data, &dataLength);
126    if (ret != AMEDIA_OK || data == nullptr || dataLength <= 0) {
127        ALOGE("%s: get data for image %p failed! ret: %d, data %p, len %d",
128                __FUNCTION__, img, ret, data, dataLength);
129        return ret;
130    }
131
132    int64_t timestamp = -1;
133    ret = AImage_getTimestamp(img, &timestamp);
134    if (ret != AMEDIA_OK || timestamp == -1) {
135        ALOGE("%s: get timestamp for image %p failed! ret: %d",
136                __FUNCTION__, img, ret);
137        return ret;
138    }
139
140    int32_t rowstride = -1;
141    ret = AImage_getPlaneRowStride(img, 0, &rowstride);
142    if (ret != AMEDIA_OK || rowstride == -1) {
143        ALOGE("%s: get row stride for image %p failed! ret: %d, rowstride %d",
144                __FUNCTION__, img, ret, rowstride);
145        return ret;
146    }
147
148    AHardwareBuffer *hardwareBuffer = nullptr;
149    ret =  AImage_getHardwareBuffer(img, &hardwareBuffer);
150    if (ret != AMEDIA_OK || hardwareBuffer == nullptr) {
151        ALOGE("%s: get hardware buffer for image %p failed! ret: %d",
152                __FUNCTION__, img, ret);
153        return ret;
154    }
155
156    mAcquiredBuffer[idx].mBufferPointer = data;
157
158    mAlloc[idx]->mHal.drvState.lod[0].mallocPtr = data;
159    mAlloc[idx]->mHal.drvState.lod[0].stride = rowstride;
160    mAlloc[idx]->mHal.state.nativeBuffer = hardwareBuffer;
161    mAlloc[idx]->mHal.state.timestamp = timestamp;
162
163    if (format == AIMAGE_FORMAT_YUV_420_888) {
164        const int yWidth = mAlloc[idx]->mHal.drvState.lod[0].dimX;
165        const int yHeight = mAlloc[idx]->mHal.drvState.lod[0].dimY;
166
167        const int cWidth = yWidth / 2;
168        const int cHeight = yHeight / 2;
169
170        uint8_t *uData = nullptr;
171        int uDataLength = 0;
172        ret =  AImage_getPlaneData(img, 1, &uData, &uDataLength);
173        if (ret != AMEDIA_OK || uData == nullptr || uDataLength <= 0) {
174            ALOGE("%s: get U data for image %p failed! ret: %d, data %p, len %d",
175                    __FUNCTION__, img, ret, uData, uDataLength);
176            return ret;
177        }
178
179        uint8_t *vData = nullptr;
180        int vDataLength = 0;
181        ret =  AImage_getPlaneData(img, 2, &vData, &vDataLength);
182        if (ret != AMEDIA_OK || vData == nullptr || vDataLength <= 0) {
183            ALOGE("%s: get V data for image %p failed! ret: %d, data %p, len %d",
184                    __FUNCTION__, img, ret, vData, vDataLength);
185            return ret;
186        }
187
188        int32_t uRowStride = -1;
189        ret = AImage_getPlaneRowStride(img, 1, &uRowStride);
190        if (ret != AMEDIA_OK || uRowStride == -1) {
191            ALOGE("%s: get U row stride for image %p failed! ret: %d, uRowStride %d",
192                    __FUNCTION__, img, ret, uRowStride);
193            return ret;
194        }
195
196        int32_t vRowStride = -1;
197        ret = AImage_getPlaneRowStride(img, 2, &vRowStride);
198        if (ret != AMEDIA_OK || vRowStride == -1) {
199            ALOGE("%s: get V row stride for image %p failed! ret: %d, vRowStride %d",
200                    __FUNCTION__, img, ret, vRowStride);
201            return ret;
202        }
203
204        int32_t uPixStride = -1;
205        ret = AImage_getPlanePixelStride(img, 1, &uPixStride);
206        if (ret != AMEDIA_OK || uPixStride == -1) {
207            ALOGE("%s: get U pixel stride for image %p failed! ret: %d, uPixStride %d",
208                    __FUNCTION__, img, ret, uPixStride);
209            return ret;
210        }
211
212        mAlloc[idx]->mHal.drvState.lod[1].dimX = cWidth;
213        mAlloc[idx]->mHal.drvState.lod[1].dimY = cHeight;
214        mAlloc[idx]->mHal.drvState.lod[2].dimX = cWidth;
215        mAlloc[idx]->mHal.drvState.lod[2].dimY = cHeight;
216
217        mAlloc[idx]->mHal.drvState.lod[1].mallocPtr = uData;
218        mAlloc[idx]->mHal.drvState.lod[2].mallocPtr = vData;
219
220        mAlloc[idx]->mHal.drvState.lod[1].stride = uRowStride;
221        mAlloc[idx]->mHal.drvState.lod[2].stride = vRowStride;
222
223        mAlloc[idx]->mHal.drvState.yuv.shift = 1;
224        mAlloc[idx]->mHal.drvState.yuv.step = uPixStride;
225        mAlloc[idx]->mHal.drvState.lodCount = 3;
226    }
227
228    return AMEDIA_OK;
229}
230
231media_status_t GrallocConsumer::unlockBuffer(uint32_t idx) {
232    media_status_t ret;
233
234    if (idx >= mNumAlloc) {
235        ALOGE("Invalid buffer index: %d", idx);
236        return AMEDIA_ERROR_INVALID_PARAMETER;
237    }
238    if (mAcquiredBuffer[idx].mImg == nullptr) {
239       return AMEDIA_OK;
240    }
241
242    AImage_delete(mAcquiredBuffer[idx].mImg);
243    mAcquiredBuffer[idx].mImg = nullptr;
244    return AMEDIA_OK;
245}
246
247uint32_t GrallocConsumer::getNextAvailableIdx(Allocation *a) {
248    for (uint32_t i = 0; i < mNumAlloc; i++) {
249        if (isIdxUsed[i] == false) {
250            mAlloc[i] = a;
251            isIdxUsed[i] = true;
252            return i;
253        }
254    }
255    return mNumAlloc;
256}
257
258bool GrallocConsumer::releaseIdx(uint32_t idx) {
259    if (idx >= mNumAlloc) {
260        ALOGE("Invalid buffer index: %d", idx);
261        return false;
262    }
263    if (isIdxUsed[idx] == false) {
264        ALOGV("Buffer index already released: %d", idx);
265        return true;
266    }
267    media_status_t ret;
268    ret = unlockBuffer(idx);
269    if (ret != OK) {
270        ALOGE("Unable to unlock graphic buffer");
271        return false;
272    }
273    mAlloc[idx] = nullptr;
274    isIdxUsed[idx] = false;
275    return true;
276}
277
278bool GrallocConsumer::isActive() {
279    for (uint32_t i = 0; i < mNumAlloc; i++) {
280        if (isIdxUsed[i]) {
281            return true;
282        }
283    }
284    return false;
285}
286
287} // namespace renderscript
288} // namespace android
289