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 #include <malloc.h>
18 #include <string.h>
19 
20 #include "RenderScript.h"
21 #include "rsCppInternal.h"
22 
23 // From system/graphics.h
24 enum {
25     HAL_PIXEL_FORMAT_YV12               = 0x32315659, // YCrCb 4:2:0 Planar
26     HAL_PIXEL_FORMAT_YCrCb_420_SP       = 0x11,       // NV21
27 };
28 
29 using android::RSC::Element;
30 using android::RSC::RS;
31 using android::RSC::Type;
32 using android::RSC::sp;
33 
calcElementCount()34 void Type::calcElementCount() {
35     bool hasLod = hasMipmaps();
36     uint32_t x = getX();
37     uint32_t y = getY();
38     uint32_t z = getZ();
39     uint32_t faces = 1;
40     if (hasFaces()) {
41         faces = 6;
42     }
43     if (x == 0) {
44         x = 1;
45     }
46     if (y == 0) {
47         y = 1;
48     }
49     if (z == 0) {
50         z = 1;
51     }
52 
53     uint32_t count = x * y * z * faces;
54     while (hasLod && ((x > 1) || (y > 1) || (z > 1))) {
55         if(x > 1) {
56             x >>= 1;
57         }
58         if(y > 1) {
59             y >>= 1;
60         }
61         if(z > 1) {
62             z >>= 1;
63         }
64 
65         count += x * y * z * faces;
66     }
67     mElementCount = count;
68 }
69 
70 
Type(void * id,sp<RS> rs)71 Type::Type(void *id, sp<RS> rs) : BaseObj(id, rs) {
72     mDimX = 0;
73     mDimY = 0;
74     mDimZ = 0;
75     mDimMipmaps = false;
76     mDimFaces = false;
77     mElement = nullptr;
78     mYuvFormat = RS_YUV_NONE;
79 }
80 
updateFromNative()81 void Type::updateFromNative() {
82     BaseObj::updateFromNative();
83 
84     /*
85      * We have 6 integers / pointers (uintptr_t) to obtain from the return buffer:
86      * mDimX     (buffer[0]);
87      * mDimY     (buffer[1]);
88      * mDimZ     (buffer[2]);
89      * mDimLOD   (buffer[3]);
90      * mDimFaces (buffer[4]);
91      * mElement  (buffer[5]);
92      */
93     uintptr_t dataBuffer[6];
94     RS::dispatch->TypeGetNativeData(mRS->getContext(), getID(), dataBuffer, 6);
95 
96     mDimX = (uint32_t)dataBuffer[0];
97     mDimY = (uint32_t)dataBuffer[1];
98     mDimZ = (uint32_t)dataBuffer[2];
99     mDimMipmaps = dataBuffer[3] == 1 ? true : false;
100     mDimFaces = dataBuffer[4] == 1 ? true : false;
101 
102     uintptr_t elementID = dataBuffer[5];
103     if(elementID != 0) {
104         // Just create a new Element and update it from native.
105         sp<Element> e = new Element((void *)elementID, mRS);
106         e->updateFromNative();
107         mElement = e;
108     }
109     calcElementCount();
110 }
111 
create(const sp<RS> & rs,const sp<const Element> & e,uint32_t dimX,uint32_t dimY,uint32_t dimZ)112 sp<const Type> Type::create(const sp<RS>& rs, const sp<const Element>& e, uint32_t dimX, uint32_t dimY, uint32_t dimZ) {
113     void * id = RS::dispatch->TypeCreate(rs->getContext(), e->getID(), dimX, dimY, dimZ, false, false, 0);
114     Type *t = new Type(id, rs);
115 
116     t->mElement = e;
117     t->mDimX = dimX;
118     t->mDimY = dimY;
119     t->mDimZ = dimZ;
120     t->mDimMipmaps = false;
121     t->mDimFaces = false;
122     t->mYuvFormat = RS_YUV_NONE;
123 
124     t->calcElementCount();
125 
126     return t;
127 }
128 
Builder(sp<RS> rs,sp<const Element> e)129 Type::Builder::Builder(sp<RS> rs, sp<const Element> e) {
130     mRS = rs.get();
131     mElement = e;
132     mDimX = 0;
133     mDimY = 0;
134     mDimZ = 0;
135     mDimMipmaps = false;
136     mDimFaces = false;
137     mYuvFormat = RS_YUV_NONE;
138 }
139 
setX(uint32_t value)140 void Type::Builder::setX(uint32_t value) {
141     if(value < 1) {
142         ALOGE("Values of less than 1 for Dimension X are not valid.");
143     }
144     mDimX = value;
145 }
146 
setY(uint32_t value)147 void Type::Builder::setY(uint32_t value) {
148     if(value < 1) {
149         ALOGE("Values of less than 1 for Dimension Y are not valid.");
150     }
151     mDimY = value;
152 }
153 
setZ(uint32_t value)154 void Type::Builder::setZ(uint32_t value) {
155     if(value < 1) {
156         ALOGE("Values of less than 1 for Dimension Z are not valid.");
157     }
158     mDimZ = value;
159 }
160 
setYuvFormat(RsYuvFormat format)161 void Type::Builder::setYuvFormat(RsYuvFormat format) {
162     if (format != RS_YUV_NONE && !(mElement->isCompatible(Element::YUV(mRS)))) {
163         ALOGE("Invalid element for use with YUV.");
164         return;
165     }
166 
167     if (format != RS_YUV_NONE &&
168         format != RS_YUV_YV12 &&
169         format != RS_YUV_NV21 &&
170         format != RS_YUV_420_888) {
171         ALOGE("Invalid YUV format.");
172         return;
173     }
174     mYuvFormat = format;
175 }
176 
177 
setMipmaps(bool value)178 void Type::Builder::setMipmaps(bool value) {
179     mDimMipmaps = value;
180 }
181 
setFaces(bool value)182 void Type::Builder::setFaces(bool value) {
183     mDimFaces = value;
184 }
185 
create()186 sp<const Type> Type::Builder::create() {
187     if (mDimZ > 0) {
188         if ((mDimX < 1) || (mDimY < 1)) {
189             ALOGE("Both X and Y dimension required when Z is present.");
190             return nullptr;
191         }
192         if (mDimFaces) {
193             ALOGE("Cube maps not supported with 3D types.");
194             return nullptr;
195         }
196     }
197     if (mDimY > 0) {
198         if (mDimX < 1) {
199             ALOGE("X dimension required when Y is present.");
200             return nullptr;
201         }
202     }
203     if (mDimFaces) {
204         if (mDimY < 1) {
205             ALOGE("Cube maps require 2D Types.");
206             return nullptr;
207         }
208     }
209 
210     if (mYuvFormat != RS_YUV_NONE) {
211         if (mDimZ || mDimFaces || mDimMipmaps) {
212             ALOGE("YUV only supports basic 2D.");
213             return nullptr;
214         }
215     }
216 
217     if (mYuvFormat == RS_YUV_420_888) {
218         ALOGE("YUV_420_888 not supported.");
219         return nullptr;
220     }
221 
222     void * id = RS::dispatch->TypeCreate(mRS->getContext(), mElement->getID(), mDimX, mDimY, mDimZ,
223                                          mDimMipmaps, mDimFaces, mYuvFormat);
224     Type *t = new Type(id, mRS);
225     t->mElement = mElement;
226     t->mDimX = mDimX;
227     t->mDimY = mDimY;
228     t->mDimZ = mDimZ;
229     t->mDimMipmaps = mDimMipmaps;
230     t->mDimFaces = mDimFaces;
231     t->mYuvFormat = mYuvFormat;
232 
233     t->calcElementCount();
234     return t;
235 }
236 
237