| /* | 
 |  * Copyright (C) 2009 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 |  | 
 | #ifndef ANDROID_RS_BUILD_FOR_HOST | 
 | #include "rsContext.h" | 
 | #include <GLES/gl.h> | 
 | #else | 
 | #include "rsContextHostStub.h" | 
 | #include <OpenGL/gl.h> | 
 | #endif | 
 |  | 
 | using namespace android; | 
 | using namespace android::renderscript; | 
 |  | 
 |  | 
 | Element::Element(Context *rsc) : ObjectBase(rsc) | 
 | { | 
 |     mBits = 0; | 
 |     mFields = NULL; | 
 |     mFieldCount = 0; | 
 |     mHasReference = false; | 
 | } | 
 |  | 
 |  | 
 | Element::~Element() | 
 | { | 
 |     for (uint32_t ct = 0; ct < mRSC->mStateElement.mElements.size(); ct++) { | 
 |         if (mRSC->mStateElement.mElements[ct] == this) { | 
 |             mRSC->mStateElement.mElements.removeAt(ct); | 
 |             break; | 
 |         } | 
 |     } | 
 |     clear(); | 
 | } | 
 |  | 
 | void Element::clear() | 
 | { | 
 |     delete [] mFields; | 
 |     mFields = NULL; | 
 |     mFieldCount = 0; | 
 |     mHasReference = false; | 
 | } | 
 |  | 
 | size_t Element::getSizeBits() const | 
 | { | 
 |     if (!mFieldCount) { | 
 |         return mBits; | 
 |     } | 
 |  | 
 |     size_t total = 0; | 
 |     for (size_t ct=0; ct < mFieldCount; ct++) { | 
 |         total += mFields[ct].e->mBits * mFields[ct].arraySize; | 
 |     } | 
 |     return total; | 
 | } | 
 |  | 
 | void Element::dumpLOGV(const char *prefix) const | 
 | { | 
 |     ObjectBase::dumpLOGV(prefix); | 
 |     LOGV("%s Element: fieldCount: %i,  size bytes: %i", prefix, mFieldCount, getSizeBytes()); | 
 |     for (uint32_t ct = 0; ct < mFieldCount; ct++) { | 
 |         LOGV("%s Element field index: %u ------------------", prefix, ct); | 
 |         LOGV("%s name: %s, offsetBits: %u, arraySize: %u", | 
 |              prefix, mFields[ct].name.string(), mFields[ct].offsetBits, mFields[ct].arraySize); | 
 |         mFields[ct].e->dumpLOGV(prefix); | 
 |     } | 
 | } | 
 |  | 
 | void Element::serialize(OStream *stream) const | 
 | { | 
 |     // Need to identify ourselves | 
 |     stream->addU32((uint32_t)getClassId()); | 
 |  | 
 |     String8 name(getName()); | 
 |     stream->addString(&name); | 
 |  | 
 |     mComponent.serialize(stream); | 
 |  | 
 |     // Now serialize all the fields | 
 |     stream->addU32(mFieldCount); | 
 |     for(uint32_t ct = 0; ct < mFieldCount; ct++) { | 
 |         stream->addString(&mFields[ct].name); | 
 |         stream->addU32(mFields[ct].arraySize); | 
 |         mFields[ct].e->serialize(stream); | 
 |     } | 
 | } | 
 |  | 
 | Element *Element::createFromStream(Context *rsc, IStream *stream) | 
 | { | 
 |     // First make sure we are reading the correct object | 
 |     RsA3DClassID classID = (RsA3DClassID)stream->loadU32(); | 
 |     if(classID != RS_A3D_CLASS_ID_ELEMENT) { | 
 |         LOGE("element loading skipped due to invalid class id\n"); | 
 |         return NULL; | 
 |     } | 
 |  | 
 |     String8 name; | 
 |     stream->loadString(&name); | 
 |  | 
 |     Element *elem = new Element(rsc); | 
 |     elem->mComponent.loadFromStream(stream); | 
 |     elem->mBits = elem->mComponent.getBits(); | 
 |     elem->mHasReference = elem->mComponent.isReference(); | 
 |  | 
 |     elem->mFieldCount = stream->loadU32(); | 
 |     if(elem->mFieldCount) { | 
 |         uint32_t offset = 0; | 
 |         elem->mFields = new ElementField_t [elem->mFieldCount]; | 
 |         for(uint32_t ct = 0; ct < elem->mFieldCount; ct ++) { | 
 |             stream->loadString(&elem->mFields[ct].name); | 
 |             elem->mFields[ct].arraySize = stream->loadU32(); | 
 |             Element *fieldElem = Element::createFromStream(rsc, stream); | 
 |             elem->mFields[ct].e.set(fieldElem); | 
 |             elem->mFields[ct].offsetBits = offset; | 
 |             offset += fieldElem->getSizeBits(); | 
 |             // Check if our sub-elements have references | 
 |             if(fieldElem->mHasReference) { | 
 |                 elem->mHasReference = true; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     // We need to check if this already exists | 
 |     for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) { | 
 |         Element *ee = rsc->mStateElement.mElements[ct]; | 
 |         if(ee->isEqual(elem)) { | 
 |             ObjectBase::checkDelete(elem); | 
 |             ee->incUserRef(); | 
 |             return ee; | 
 |         } | 
 |     } | 
 |  | 
 |     rsc->mStateElement.mElements.push(elem); | 
 |     return elem; | 
 | } | 
 |  | 
 | bool Element::isEqual(const Element *other) const { | 
 |     if(other == NULL) { | 
 |         return false; | 
 |     } | 
 |     if (!other->getFieldCount() && !mFieldCount) { | 
 |         if((other->getType() == getType()) && | 
 |            (other->getKind() == getKind()) && | 
 |            (other->getComponent().getIsNormalized() == getComponent().getIsNormalized()) && | 
 |            (other->getComponent().getVectorSize() == getComponent().getVectorSize())) { | 
 |             return true; | 
 |         } | 
 |         return false; | 
 |     } | 
 |     if (other->getFieldCount() == mFieldCount) { | 
 |         for (uint32_t i=0; i < mFieldCount; i++) { | 
 |             if ((!other->mFields[i].e->isEqual(mFields[i].e.get())) || | 
 |                 (other->mFields[i].name.length() != mFields[i].name.length()) || | 
 |                 (other->mFields[i].name != mFields[i].name) || | 
 |                 (other->mFields[i].arraySize != mFields[i].arraySize)) { | 
 |                 return false; | 
 |             } | 
 |         } | 
 |         return true; | 
 |     } | 
 |     return false; | 
 | } | 
 |  | 
 | const Element * Element::create(Context *rsc, RsDataType dt, RsDataKind dk, | 
 |                             bool isNorm, uint32_t vecSize) | 
 | { | 
 |     // Look for an existing match. | 
 |     for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) { | 
 |         const Element *ee = rsc->mStateElement.mElements[ct]; | 
 |         if (!ee->getFieldCount() && | 
 |             (ee->getComponent().getType() == dt) && | 
 |             (ee->getComponent().getKind() == dk) && | 
 |             (ee->getComponent().getIsNormalized() == isNorm) && | 
 |             (ee->getComponent().getVectorSize() == vecSize)) { | 
 |             // Match | 
 |             ee->incUserRef(); | 
 |             return ee; | 
 |         } | 
 |     } | 
 |  | 
 |     Element *e = new Element(rsc); | 
 |     e->mComponent.set(dt, dk, isNorm, vecSize); | 
 |     e->mBits = e->mComponent.getBits(); | 
 |     e->mHasReference = e->mComponent.isReference(); | 
 |     rsc->mStateElement.mElements.push(e); | 
 |     return e; | 
 | } | 
 |  | 
 | const Element * Element::create(Context *rsc, size_t count, const Element **ein, | 
 |                             const char **nin, const size_t * lengths, const uint32_t *asin) | 
 | { | 
 |     // Look for an existing match. | 
 |     for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) { | 
 |         const Element *ee = rsc->mStateElement.mElements[ct]; | 
 |         if (ee->getFieldCount() == count) { | 
 |             bool match = true; | 
 |             for (uint32_t i=0; i < count; i++) { | 
 |                 if ((ee->mFields[i].e.get() != ein[i]) || | 
 |                     (ee->mFields[i].name.length() != lengths[i]) || | 
 |                     (ee->mFields[i].name != nin[i]) || | 
 |                     (ee->mFields[i].arraySize != asin[i])) { | 
 |                     match = false; | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             if (match) { | 
 |                 ee->incUserRef(); | 
 |                 return ee; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     Element *e = new Element(rsc); | 
 |     e->mFields = new ElementField_t [count]; | 
 |     e->mFieldCount = count; | 
 |     size_t bits = 0; | 
 |     for (size_t ct=0; ct < count; ct++) { | 
 |         e->mFields[ct].e.set(ein[ct]); | 
 |         e->mFields[ct].name.setTo(nin[ct], lengths[ct]); | 
 |         e->mFields[ct].offsetBits = bits; | 
 |         e->mFields[ct].arraySize = asin[ct]; | 
 |         bits += ein[ct]->getSizeBits(); | 
 |  | 
 |         if (ein[ct]->mHasReference) { | 
 |             e->mHasReference = true; | 
 |         } | 
 |     } | 
 |  | 
 |     rsc->mStateElement.mElements.push(e); | 
 |     return e; | 
 | } | 
 |  | 
 | String8 Element::getGLSLType(uint32_t indent) const | 
 | { | 
 |     String8 s; | 
 |     for (uint32_t ct=0; ct < indent; ct++) { | 
 |         s.append(" "); | 
 |     } | 
 |  | 
 |     if (!mFieldCount) { | 
 |         // Basic component. | 
 |         s.append(mComponent.getGLSLType()); | 
 |     } else { | 
 |         rsAssert(0); | 
 |         //s.append("struct "); | 
 |         //s.append(getCStructBody(indent)); | 
 |     } | 
 |  | 
 |     return s; | 
 | } | 
 |  | 
 | void Element::incRefs(const void *ptr) const | 
 | { | 
 |     if (!mFieldCount) { | 
 |         if (mComponent.isReference()) { | 
 |             ObjectBase *const*obp = static_cast<ObjectBase *const*>(ptr); | 
 |             ObjectBase *ob = obp[0]; | 
 |             if (ob) ob->incSysRef(); | 
 |         } | 
 |         return; | 
 |     } | 
 |  | 
 |     const uint8_t *p = static_cast<const uint8_t *>(ptr); | 
 |     for (uint32_t i=0; i < mFieldCount; i++) { | 
 |         if (mFields[i].e->mHasReference) { | 
 |             p = &p[mFields[i].offsetBits >> 3]; | 
 |             for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) { | 
 |                 mFields[i].e->incRefs(p); | 
 |                 p += mFields[i].e->getSizeBytes(); | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | void Element::decRefs(const void *ptr) const | 
 | { | 
 |     if (!mFieldCount) { | 
 |         if (mComponent.isReference()) { | 
 |             ObjectBase *const*obp = static_cast<ObjectBase *const*>(ptr); | 
 |             ObjectBase *ob = obp[0]; | 
 |             if (ob) ob->decSysRef(); | 
 |         } | 
 |         return; | 
 |     } | 
 |  | 
 |     const uint8_t *p = static_cast<const uint8_t *>(ptr); | 
 |     for (uint32_t i=0; i < mFieldCount; i++) { | 
 |         if (mFields[i].e->mHasReference) { | 
 |             p = &p[mFields[i].offsetBits >> 3]; | 
 |             for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) { | 
 |                 mFields[i].e->decRefs(p); | 
 |                 p += mFields[i].e->getSizeBytes(); | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | ElementState::ElementState() | 
 | { | 
 |     const uint32_t initialCapacity = 32; | 
 |     mBuilderElements.setCapacity(initialCapacity); | 
 |     mBuilderNameStrings.setCapacity(initialCapacity); | 
 |     mBuilderNameLengths.setCapacity(initialCapacity); | 
 |     mBuilderArrays.setCapacity(initialCapacity); | 
 | } | 
 |  | 
 | ElementState::~ElementState() | 
 | { | 
 |     rsAssert(!mElements.size()); | 
 | } | 
 |  | 
 | void ElementState::elementBuilderBegin() { | 
 |     mBuilderElements.clear(); | 
 |     mBuilderNameStrings.clear(); | 
 |     mBuilderNameLengths.clear(); | 
 |     mBuilderArrays.clear(); | 
 | } | 
 |  | 
 | void ElementState::elementBuilderAdd(const Element *e, const char *nameStr, uint32_t arraySize) { | 
 |     mBuilderElements.push(e); | 
 |     mBuilderNameStrings.push(nameStr); | 
 |     mBuilderNameLengths.push(strlen(nameStr)); | 
 |     mBuilderArrays.push(arraySize); | 
 |  | 
 | } | 
 |  | 
 | const Element *ElementState::elementBuilderCreate(Context *rsc) { | 
 |     return Element::create(rsc, mBuilderElements.size(), | 
 |                                 &(mBuilderElements.editArray()[0]), | 
 |                                 &(mBuilderNameStrings.editArray()[0]), | 
 |                                 mBuilderNameLengths.editArray(), | 
 |                                 mBuilderArrays.editArray()); | 
 | } | 
 |  | 
 |  | 
 | ///////////////////////////////////////// | 
 | // | 
 |  | 
 | namespace android { | 
 | namespace renderscript { | 
 |  | 
 | RsElement rsi_ElementCreate(Context *rsc, | 
 |                             RsDataType dt, | 
 |                             RsDataKind dk, | 
 |                             bool norm, | 
 |                             uint32_t vecSize) | 
 | { | 
 |     //LOGE("rsi_ElementCreate %i %i %i %i", dt, dk, norm, vecSize); | 
 |     const Element *e = Element::create(rsc, dt, dk, norm, vecSize); | 
 |     e->incUserRef(); | 
 |     return (RsElement)e; | 
 | } | 
 |  | 
 | RsElement rsi_ElementCreate2(Context *rsc, | 
 |                              size_t count, | 
 |                              const RsElement * ein, | 
 |                              const char ** names, | 
 |                              const size_t * nameLengths, | 
 |                              const uint32_t * arraySizes) | 
 | { | 
 |     //LOGE("rsi_ElementCreate2 %i", count); | 
 |     const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths, arraySizes); | 
 |     e->incUserRef(); | 
 |     return (RsElement)e; | 
 | } | 
 |  | 
 | } | 
 | } | 
 |  | 
 | void rsaElementGetNativeData(RsContext con, RsElement elem, uint32_t *elemData, uint32_t elemDataSize) | 
 | { | 
 |     rsAssert(elemDataSize == 5); | 
 |     // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements | 
 |     Element *e = static_cast<Element *>(elem); | 
 |  | 
 |     (*elemData++) = (uint32_t)e->getType(); | 
 |     (*elemData++) = (uint32_t)e->getKind(); | 
 |     (*elemData++) = e->getComponent().getIsNormalized() ? 1 : 0; | 
 |     (*elemData++) = e->getComponent().getVectorSize(); | 
 |     (*elemData++) = e->getFieldCount(); | 
 |  | 
 | } | 
 |  | 
 | void rsaElementGetSubElements(RsContext con, RsElement elem, uint32_t *ids, const char **names, uint32_t dataSize) | 
 | { | 
 |     Element *e = static_cast<Element *>(elem); | 
 |     rsAssert(e->getFieldCount() == dataSize); | 
 |  | 
 |     for(uint32_t i = 0; i < dataSize; i ++) { | 
 |         e->getField(i)->incUserRef(); | 
 |         ids[i] = (uint32_t)e->getField(i); | 
 |         names[i] = e->getFieldName(i); | 
 |     } | 
 |  | 
 | } |