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