1/*
2 * Copyright (C) 2009 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 "rsContext.h"
18
19using namespace android;
20using namespace android::renderscript;
21
22Type::Type(Context *rsc) : ObjectBase(rsc) {
23    memset(&mHal, 0, sizeof(mHal));
24    mDimLOD = false;
25}
26
27void Type::preDestroy() const {
28    for (uint32_t ct = 0; ct < mRSC->mStateType.mTypes.size(); ct++) {
29        if (mRSC->mStateType.mTypes[ct] == this) {
30            mRSC->mStateType.mTypes.removeAt(ct);
31            break;
32        }
33    }
34}
35
36Type::~Type() {
37    clear();
38}
39
40void Type::clear() {
41    if (mHal.state.lodCount) {
42        delete [] mHal.state.lodDimX;
43        delete [] mHal.state.lodDimY;
44        delete [] mHal.state.lodDimZ;
45        delete [] mHal.state.lodOffset;
46    }
47    mElement.clear();
48    memset(&mHal, 0, sizeof(mHal));
49}
50
51TypeState::TypeState() {
52}
53
54TypeState::~TypeState() {
55    rsAssert(!mTypes.size());
56}
57
58size_t Type::getOffsetForFace(uint32_t face) const {
59    rsAssert(mHal.state.faces);
60    return 0;
61}
62
63void Type::compute() {
64    uint32_t oldLODCount = mHal.state.lodCount;
65    if (mDimLOD) {
66        uint32_t l2x = rsFindHighBit(mHal.state.dimX) + 1;
67        uint32_t l2y = rsFindHighBit(mHal.state.dimY) + 1;
68        uint32_t l2z = rsFindHighBit(mHal.state.dimZ) + 1;
69
70        mHal.state.lodCount = rsMax(l2x, l2y);
71        mHal.state.lodCount = rsMax(mHal.state.lodCount, l2z);
72    } else {
73        mHal.state.lodCount = 1;
74    }
75    if (mHal.state.lodCount != oldLODCount) {
76        if (oldLODCount) {
77            delete [] mHal.state.lodDimX;
78            delete [] mHal.state.lodDimY;
79            delete [] mHal.state.lodDimZ;
80            delete [] mHal.state.lodOffset;
81        }
82        mHal.state.lodDimX = new uint32_t[mHal.state.lodCount];
83        mHal.state.lodDimY = new uint32_t[mHal.state.lodCount];
84        mHal.state.lodDimZ = new uint32_t[mHal.state.lodCount];
85        mHal.state.lodOffset = new uint32_t[mHal.state.lodCount];
86    }
87
88    uint32_t tx = mHal.state.dimX;
89    uint32_t ty = mHal.state.dimY;
90    uint32_t tz = mHal.state.dimZ;
91    size_t offset = 0;
92    for (uint32_t lod=0; lod < mHal.state.lodCount; lod++) {
93        mHal.state.lodDimX[lod] = tx;
94        mHal.state.lodDimY[lod] = ty;
95        mHal.state.lodDimZ[lod]  = tz;
96        mHal.state.lodOffset[lod] = offset;
97        offset += tx * rsMax(ty, 1u) * rsMax(tz, 1u) * mElement->getSizeBytes();
98        if (tx > 1) tx >>= 1;
99        if (ty > 1) ty >>= 1;
100        if (tz > 1) tz >>= 1;
101    }
102
103    // At this point the offset is the size of a mipmap chain;
104    mMipChainSizeBytes = offset;
105
106    if (mHal.state.faces) {
107        offset *= 6;
108    }
109    mTotalSizeBytes = offset;
110    mHal.state.element = mElement.get();
111}
112
113uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const {
114    uint32_t offset = mHal.state.lodOffset[lod];
115    offset += x * mElement->getSizeBytes();
116    return offset;
117}
118
119uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const {
120    uint32_t offset = mHal.state.lodOffset[lod];
121    offset += (x + y * mHal.state.lodDimX[lod]) * mElement->getSizeBytes();
122    return offset;
123}
124
125uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const {
126    uint32_t offset = mHal.state.lodOffset[lod];
127    offset += (x +
128               y * mHal.state.lodDimX[lod] +
129               z * mHal.state.lodDimX[lod] * mHal.state.lodDimY[lod]) * mElement->getSizeBytes();
130    return offset;
131}
132
133uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face,
134                                uint32_t x, uint32_t y) const {
135    uint32_t offset = mHal.state.lodOffset[lod];
136    offset += (x + y * mHal.state.lodDimX[lod]) * mElement->getSizeBytes();
137
138    if (face != 0) {
139        uint32_t faceOffset = getSizeBytes() / 6;
140        offset += faceOffset * face;
141    }
142    return offset;
143}
144
145void Type::dumpLOGV(const char *prefix) const {
146    char buf[1024];
147    ObjectBase::dumpLOGV(prefix);
148    ALOGV("%s   Type: x=%u y=%u z=%u mip=%i face=%i", prefix,
149                                                      mHal.state.dimX,
150                                                      mHal.state.dimY,
151                                                      mHal.state.dimZ,
152                                                      mHal.state.lodCount,
153                                                      mHal.state.faces);
154    snprintf(buf, sizeof(buf), "%s element: ", prefix);
155    mElement->dumpLOGV(buf);
156}
157
158void Type::serialize(Context *rsc, OStream *stream) const {
159    // Need to identify ourselves
160    stream->addU32((uint32_t)getClassId());
161
162    String8 name(getName());
163    stream->addString(&name);
164
165    mElement->serialize(rsc, stream);
166
167    stream->addU32(mHal.state.dimX);
168    stream->addU32(mHal.state.dimY);
169    stream->addU32(mHal.state.dimZ);
170
171    stream->addU8((uint8_t)(mHal.state.lodCount ? 1 : 0));
172    stream->addU8((uint8_t)(mHal.state.faces ? 1 : 0));
173}
174
175Type *Type::createFromStream(Context *rsc, IStream *stream) {
176    // First make sure we are reading the correct object
177    RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
178    if (classID != RS_A3D_CLASS_ID_TYPE) {
179        ALOGE("type loading skipped due to invalid class id\n");
180        return NULL;
181    }
182
183    String8 name;
184    stream->loadString(&name);
185
186    Element *elem = Element::createFromStream(rsc, stream);
187    if (!elem) {
188        return NULL;
189    }
190
191    uint32_t x = stream->loadU32();
192    uint32_t y = stream->loadU32();
193    uint32_t z = stream->loadU32();
194    uint8_t lod = stream->loadU8();
195    uint8_t faces = stream->loadU8();
196    Type *type = Type::getType(rsc, elem, x, y, z, lod != 0, faces !=0 );
197    elem->decUserRef();
198    return type;
199}
200
201bool Type::getIsNp2() const {
202    uint32_t x = getDimX();
203    uint32_t y = getDimY();
204    uint32_t z = getDimZ();
205
206    if (x && (x & (x-1))) {
207        return true;
208    }
209    if (y && (y & (y-1))) {
210        return true;
211    }
212    if (z && (z & (z-1))) {
213        return true;
214    }
215    return false;
216}
217
218ObjectBaseRef<Type> Type::getTypeRef(Context *rsc, const Element *e,
219                                     uint32_t dimX, uint32_t dimY, uint32_t dimZ,
220                                     bool dimLOD, bool dimFaces) {
221    ObjectBaseRef<Type> returnRef;
222
223    TypeState * stc = &rsc->mStateType;
224
225    ObjectBase::asyncLock();
226    for (uint32_t ct=0; ct < stc->mTypes.size(); ct++) {
227        Type *t = stc->mTypes[ct];
228        if (t->getElement() != e) continue;
229        if (t->getDimX() != dimX) continue;
230        if (t->getDimY() != dimY) continue;
231        if (t->getDimZ() != dimZ) continue;
232        if (t->getDimLOD() != dimLOD) continue;
233        if (t->getDimFaces() != dimFaces) continue;
234        returnRef.set(t);
235        ObjectBase::asyncUnlock();
236        return returnRef;
237    }
238    ObjectBase::asyncUnlock();
239
240
241    Type *nt = new Type(rsc);
242    nt->mDimLOD = dimLOD;
243    returnRef.set(nt);
244    nt->mElement.set(e);
245    nt->mHal.state.dimX = dimX;
246    nt->mHal.state.dimY = dimY;
247    nt->mHal.state.dimZ = dimZ;
248    nt->mHal.state.faces = dimFaces;
249    nt->compute();
250
251    ObjectBase::asyncLock();
252    stc->mTypes.push(nt);
253    ObjectBase::asyncUnlock();
254
255    return returnRef;
256}
257
258ObjectBaseRef<Type> Type::cloneAndResize1D(Context *rsc, uint32_t dimX) const {
259    return getTypeRef(rsc, mElement.get(), dimX,
260                      getDimY(), getDimZ(), getDimLOD(), getDimFaces());
261}
262
263ObjectBaseRef<Type> Type::cloneAndResize2D(Context *rsc,
264                              uint32_t dimX,
265                              uint32_t dimY) const {
266    return getTypeRef(rsc, mElement.get(), dimX, dimY,
267                      getDimZ(), getDimLOD(), getDimFaces());
268}
269
270
271void Type::incRefs(const void *ptr, size_t ct, size_t startOff) const {
272    const uint8_t *p = static_cast<const uint8_t *>(ptr);
273    const Element *e = mHal.state.element;
274    uint32_t stride = e->getSizeBytes();
275
276    p += stride * startOff;
277    while (ct > 0) {
278        e->incRefs(p);
279        ct--;
280        p += stride;
281    }
282}
283
284
285void Type::decRefs(const void *ptr, size_t ct, size_t startOff) const {
286    if (!mHal.state.element->getHasReferences()) {
287        return;
288    }
289    const uint8_t *p = static_cast<const uint8_t *>(ptr);
290    const Element *e = mHal.state.element;
291    uint32_t stride = e->getSizeBytes();
292
293    p += stride * startOff;
294    while (ct > 0) {
295        e->decRefs(p);
296        ct--;
297        p += stride;
298    }
299}
300
301
302//////////////////////////////////////////////////
303//
304namespace android {
305namespace renderscript {
306
307RsType rsi_TypeCreate(Context *rsc, RsElement _e, uint32_t dimX,
308                     uint32_t dimY, uint32_t dimZ, bool mips, bool faces) {
309    Element *e = static_cast<Element *>(_e);
310
311    return Type::getType(rsc, e, dimX, dimY, dimZ, mips, faces);
312}
313
314}
315}
316
317void rsaTypeGetNativeData(RsContext con, RsType type, uint32_t *typeData, uint32_t typeDataSize) {
318    rsAssert(typeDataSize == 6);
319    // Pack the data in the follofing way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ;
320    // mHal.state.lodCount; mHal.state.faces; mElement; into typeData
321    Type *t = static_cast<Type *>(type);
322
323    (*typeData++) = t->getDimX();
324    (*typeData++) = t->getDimY();
325    (*typeData++) = t->getDimZ();
326    (*typeData++) = t->getDimLOD() ? 1 : 0;
327    (*typeData++) = t->getDimFaces() ? 1 : 0;
328    (*typeData++) = (uint32_t)t->getElement();
329    t->getElement()->incUserRef();
330}
331