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