Home | History | Annotate | Download | only in rs
      1 
      2 /*
      3  * Copyright (C) 2009 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 #include "rsContext.h"
     19 #include "rsFileA3D.h"
     20 
     21 #include "rsMesh.h"
     22 #include "rsAnimation.h"
     23 #include "rs.h"
     24 
     25 #if !defined(__RS_PDK__)
     26     #include <androidfw/Asset.h>
     27 #endif
     28 
     29 using namespace android;
     30 using namespace android::renderscript;
     31 
     32 FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc) {
     33     mAlloc = NULL;
     34     mData = NULL;
     35     mWriteStream = NULL;
     36     mReadStream = NULL;
     37     mAsset = NULL;
     38 
     39     mMajorVersion = 0;
     40     mMinorVersion = 1;
     41     mDataSize = 0;
     42 }
     43 
     44 FileA3D::~FileA3D() {
     45     for (size_t i = 0; i < mIndex.size(); i ++) {
     46         delete mIndex[i];
     47     }
     48     for (size_t i = 0; i < mWriteIndex.size(); i ++) {
     49         delete mWriteIndex[i];
     50     }
     51     if (mWriteStream) {
     52         delete mWriteStream;
     53     }
     54     if (mReadStream) {
     55         delete mWriteStream;
     56     }
     57     if (mAlloc) {
     58         free(mAlloc);
     59     }
     60     if (mAsset) {
     61 #if !defined(__RS_PDK__)
     62         delete mAsset;
     63 #endif
     64     }
     65 }
     66 
     67 void FileA3D::parseHeader(IStream *headerStream) {
     68     mMajorVersion = headerStream->loadU32();
     69     mMinorVersion = headerStream->loadU32();
     70     uint32_t flags = headerStream->loadU32();
     71     mUse64BitOffsets = (flags & 1) != 0;
     72 
     73     uint32_t numIndexEntries = headerStream->loadU32();
     74     for (uint32_t i = 0; i < numIndexEntries; i ++) {
     75         A3DIndexEntry *entry = new A3DIndexEntry();
     76         entry->mObjectName = headerStream->loadString();
     77 
     78         //ALOGV("Header data, entry name = %s", entry->mObjectName.string());
     79         entry->mType = (RsA3DClassID)headerStream->loadU32();
     80         if (mUse64BitOffsets){
     81             entry->mOffset = headerStream->loadOffset();
     82             entry->mLength = headerStream->loadOffset();
     83         } else {
     84             entry->mOffset = headerStream->loadU32();
     85             entry->mLength = headerStream->loadU32();
     86         }
     87         entry->mRsObj = NULL;
     88         mIndex.push(entry);
     89     }
     90 }
     91 
     92 bool FileA3D::load(Asset *asset) {
     93 #if !defined(__RS_PDK__)
     94     mAsset = asset;
     95     return load(asset->getBuffer(false), asset->getLength());
     96 #else
     97     return false;
     98 #endif
     99 }
    100 
    101 bool FileA3D::load(const void *data, size_t length) {
    102     const uint8_t *localData = (const uint8_t *)data;
    103 
    104     size_t lengthRemaining = length;
    105     size_t magicStrLen = 12;
    106     if ((length < magicStrLen) ||
    107         memcmp(data, "Android3D_ff", magicStrLen)) {
    108         return false;
    109     }
    110 
    111     localData += magicStrLen;
    112     lengthRemaining -= magicStrLen;
    113 
    114     // Next we get our header size
    115     uint64_t headerSize = 0;
    116     if (lengthRemaining < sizeof(headerSize)) {
    117         return false;
    118     }
    119 
    120     memcpy(&headerSize, localData, sizeof(headerSize));
    121     localData += sizeof(headerSize);
    122     lengthRemaining -= sizeof(headerSize);
    123 
    124     if (lengthRemaining < headerSize) {
    125         return false;
    126     }
    127 
    128     // Now open the stream to parse the header
    129     IStream headerStream(localData, false);
    130     parseHeader(&headerStream);
    131 
    132     localData += headerSize;
    133     lengthRemaining -= headerSize;
    134 
    135     if (lengthRemaining < sizeof(mDataSize)) {
    136         return false;
    137     }
    138 
    139     // Read the size of the data
    140     memcpy(&mDataSize, localData, sizeof(mDataSize));
    141     localData += sizeof(mDataSize);
    142     lengthRemaining -= sizeof(mDataSize);
    143 
    144     if (lengthRemaining < mDataSize) {
    145         return false;
    146     }
    147 
    148     // We should know enough to read the file in at this point.
    149     mData = (uint8_t *)localData;
    150     mReadStream = new IStream(mData, mUse64BitOffsets);
    151 
    152     return true;
    153 }
    154 
    155 bool FileA3D::load(FILE *f) {
    156     char magicString[12];
    157     size_t len;
    158 
    159     ALOGV("file open 1");
    160     len = fread(magicString, 1, 12, f);
    161     if ((len != 12) ||
    162         memcmp(magicString, "Android3D_ff", 12)) {
    163         return false;
    164     }
    165 
    166     // Next thing is the size of the header
    167     uint64_t headerSize = 0;
    168     len = fread(&headerSize, 1, sizeof(headerSize), f);
    169     if (len != sizeof(headerSize) || headerSize == 0) {
    170         return false;
    171     }
    172 
    173     uint8_t *headerData = (uint8_t *)malloc(headerSize);
    174     if (!headerData) {
    175         return false;
    176     }
    177 
    178     len = fread(headerData, 1, headerSize, f);
    179     if (len != headerSize) {
    180         return false;
    181     }
    182 
    183     // Now open the stream to parse the header
    184     IStream headerStream(headerData, false);
    185     parseHeader(&headerStream);
    186 
    187     free(headerData);
    188 
    189     // Next thing is the size of the header
    190     len = fread(&mDataSize, 1, sizeof(mDataSize), f);
    191     if (len != sizeof(mDataSize) || mDataSize == 0) {
    192         return false;
    193     }
    194 
    195     ALOGV("file open size = %lli", mDataSize);
    196 
    197     // We should know enough to read the file in at this point.
    198     mAlloc = malloc(mDataSize);
    199     if (!mAlloc) {
    200         return false;
    201     }
    202     mData = (uint8_t *)mAlloc;
    203     len = fread(mAlloc, 1, mDataSize, f);
    204     if (len != mDataSize) {
    205         return false;
    206     }
    207 
    208     mReadStream = new IStream(mData, mUse64BitOffsets);
    209 
    210     ALOGV("Header is read an stream initialized");
    211     return true;
    212 }
    213 
    214 size_t FileA3D::getNumIndexEntries() const {
    215     return mIndex.size();
    216 }
    217 
    218 FileA3D::A3DIndexEntry::~A3DIndexEntry() {
    219     delete[] mObjectName;
    220 }
    221 
    222 const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const {
    223     if (index < mIndex.size()) {
    224         return mIndex[index];
    225     }
    226     return NULL;
    227 }
    228 
    229 ObjectBase *FileA3D::initializeFromEntry(size_t index) {
    230     if (index >= mIndex.size()) {
    231         return NULL;
    232     }
    233 
    234     FileA3D::A3DIndexEntry *entry = mIndex[index];
    235     if (!entry) {
    236         return NULL;
    237     }
    238 
    239     if (entry->mRsObj) {
    240         entry->mRsObj->incUserRef();
    241         return entry->mRsObj;
    242     }
    243 
    244     // Seek to the beginning of object
    245     mReadStream->reset(entry->mOffset);
    246     switch (entry->mType) {
    247         case RS_A3D_CLASS_ID_UNKNOWN:
    248             return NULL;
    249         case RS_A3D_CLASS_ID_MESH:
    250             entry->mRsObj = Mesh::createFromStream(mRSC, mReadStream);
    251             break;
    252         case RS_A3D_CLASS_ID_TYPE:
    253             entry->mRsObj = Type::createFromStream(mRSC, mReadStream);
    254             break;
    255         case RS_A3D_CLASS_ID_ELEMENT:
    256             entry->mRsObj = Element::createFromStream(mRSC, mReadStream);
    257             break;
    258         case RS_A3D_CLASS_ID_ALLOCATION:
    259             entry->mRsObj = Allocation::createFromStream(mRSC, mReadStream);
    260             break;
    261         case RS_A3D_CLASS_ID_PROGRAM_VERTEX:
    262             //entry->mRsObj = ProgramVertex::createFromStream(mRSC, mReadStream);
    263             break;
    264         case RS_A3D_CLASS_ID_PROGRAM_RASTER:
    265             //entry->mRsObj = ProgramRaster::createFromStream(mRSC, mReadStream);
    266             break;
    267         case RS_A3D_CLASS_ID_PROGRAM_FRAGMENT:
    268             //entry->mRsObj = ProgramFragment::createFromStream(mRSC, mReadStream);
    269             break;
    270         case RS_A3D_CLASS_ID_PROGRAM_STORE:
    271             //entry->mRsObj = ProgramStore::createFromStream(mRSC, mReadStream);
    272             break;
    273         case RS_A3D_CLASS_ID_SAMPLER:
    274             //entry->mRsObj = Sampler::createFromStream(mRSC, mReadStream);
    275             break;
    276         case RS_A3D_CLASS_ID_ANIMATION:
    277             //entry->mRsObj = Animation::createFromStream(mRSC, mReadStream);
    278             break;
    279         case RS_A3D_CLASS_ID_ADAPTER_1D:
    280             //entry->mRsObj = Adapter1D::createFromStream(mRSC, mReadStream);
    281             break;
    282         case RS_A3D_CLASS_ID_ADAPTER_2D:
    283             //entry->mRsObj = Adapter2D::createFromStream(mRSC, mReadStream);
    284             break;
    285         case RS_A3D_CLASS_ID_SCRIPT_C:
    286             break;
    287         case RS_A3D_CLASS_ID_SCRIPT_KERNEL_ID:
    288             break;
    289         case RS_A3D_CLASS_ID_SCRIPT_FIELD_ID:
    290             break;
    291         case RS_A3D_CLASS_ID_SCRIPT_METHOD_ID:
    292             break;
    293         case RS_A3D_CLASS_ID_SCRIPT_GROUP:
    294             break;
    295     }
    296     if (entry->mRsObj) {
    297         entry->mRsObj->incUserRef();
    298     }
    299     return entry->mRsObj;
    300 }
    301 
    302 bool FileA3D::writeFile(const char *filename) {
    303     if (!mWriteStream) {
    304         ALOGE("No objects to write\n");
    305         return false;
    306     }
    307     if (mWriteStream->getPos() == 0) {
    308         ALOGE("No objects to write\n");
    309         return false;
    310     }
    311 
    312     FILE *writeHandle = fopen(filename, "wb");
    313     if (!writeHandle) {
    314         ALOGE("Couldn't open the file for writing\n");
    315         return false;
    316     }
    317 
    318     // Open a new stream to make writing the header easier
    319     OStream headerStream(5*1024, false);
    320     headerStream.addU32(mMajorVersion);
    321     headerStream.addU32(mMinorVersion);
    322     uint32_t is64Bit = 0;
    323     headerStream.addU32(is64Bit);
    324 
    325     uint32_t writeIndexSize = mWriteIndex.size();
    326     headerStream.addU32(writeIndexSize);
    327     for (uint32_t i = 0; i < writeIndexSize; i ++) {
    328         headerStream.addString(mWriteIndex[i]->mObjectName);
    329         headerStream.addU32((uint32_t)mWriteIndex[i]->mType);
    330         if (mUse64BitOffsets){
    331             headerStream.addOffset(mWriteIndex[i]->mOffset);
    332             headerStream.addOffset(mWriteIndex[i]->mLength);
    333         } else {
    334             uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset;
    335             headerStream.addU32(offset);
    336             offset = (uint32_t)mWriteIndex[i]->mLength;
    337             headerStream.addU32(offset);
    338         }
    339     }
    340 
    341     // Write our magic string so we know we are reading the right file
    342     fwrite(A3D_MAGIC_KEY, sizeof(char), strlen(A3D_MAGIC_KEY), writeHandle);
    343 
    344     // Store the size of the header to make it easier to parse when we read it
    345     uint64_t headerSize = headerStream.getPos();
    346     fwrite(&headerSize, sizeof(headerSize), 1, writeHandle);
    347 
    348     // Now write our header
    349     fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle);
    350 
    351     // Now write the size of the data part of the file for easier parsing later
    352     uint64_t fileDataSize = mWriteStream->getPos();
    353     fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle);
    354 
    355     fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle);
    356 
    357     int status = fclose(writeHandle);
    358 
    359     if (status != 0) {
    360         ALOGE("Couldn't close file\n");
    361         return false;
    362     }
    363 
    364     return true;
    365 }
    366 
    367 void FileA3D::appendToFile(Context *con, ObjectBase *obj) {
    368     if (!obj) {
    369         return;
    370     }
    371     if (!mWriteStream) {
    372         const uint64_t initialStreamSize = 256*1024;
    373         mWriteStream = new OStream(initialStreamSize, false);
    374     }
    375     A3DIndexEntry *indexEntry = new A3DIndexEntry();
    376     indexEntry->mObjectName = rsuCopyString(obj->getName());
    377     indexEntry->mType = obj->getClassId();
    378     indexEntry->mOffset = mWriteStream->getPos();
    379     indexEntry->mRsObj = obj;
    380     mWriteIndex.push(indexEntry);
    381     obj->serialize(con, mWriteStream);
    382     indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset;
    383     mWriteStream->align(4);
    384 }
    385 
    386 RsObjectBase rsaFileA3DGetEntryByIndex(RsContext con, uint32_t index, RsFile file) {
    387     FileA3D *fa3d = static_cast<FileA3D *>(file);
    388     if (!fa3d) {
    389         ALOGE("Can't load entry. No valid file");
    390         return NULL;
    391     }
    392 
    393     ObjectBase *obj = fa3d->initializeFromEntry(index);
    394     //ALOGV("Returning object with name %s", obj->getName());
    395 
    396     return obj;
    397 }
    398 
    399 
    400 void rsaFileA3DGetNumIndexEntries(RsContext con, int32_t *numEntries, RsFile file) {
    401     FileA3D *fa3d = static_cast<FileA3D *>(file);
    402 
    403     if (fa3d) {
    404         *numEntries = fa3d->getNumIndexEntries();
    405     } else {
    406         *numEntries = 0;
    407     }
    408 }
    409 
    410 void rsaFileA3DGetIndexEntries(RsContext con, RsFileIndexEntry *fileEntries, uint32_t numEntries, RsFile file) {
    411     FileA3D *fa3d = static_cast<FileA3D *>(file);
    412 
    413     if (!fa3d) {
    414         ALOGE("Can't load index entries. No valid file");
    415         return;
    416     }
    417 
    418     uint32_t numFileEntries = fa3d->getNumIndexEntries();
    419     if (numFileEntries != numEntries || numEntries == 0 || fileEntries == NULL) {
    420         ALOGE("Can't load index entries. Invalid number requested");
    421         return;
    422     }
    423 
    424     for (uint32_t i = 0; i < numFileEntries; i ++) {
    425         const FileA3D::A3DIndexEntry *entry = fa3d->getIndexEntry(i);
    426         fileEntries[i].classID = entry->getType();
    427         fileEntries[i].objectName = rsuCopyString(entry->getObjectName());
    428     }
    429 }
    430 
    431 RsFile rsaFileA3DCreateFromMemory(RsContext con, const void *data, uint32_t len) {
    432     if (data == NULL) {
    433         ALOGE("File load failed. Asset stream is NULL");
    434         return NULL;
    435     }
    436 
    437     Context *rsc = static_cast<Context *>(con);
    438     FileA3D *fa3d = new FileA3D(rsc);
    439     fa3d->incUserRef();
    440 
    441     fa3d->load(data, len);
    442     return fa3d;
    443 }
    444 
    445 RsFile rsaFileA3DCreateFromAsset(RsContext con, void *_asset) {
    446 #if !defined(__RS_PDK__)
    447     Context *rsc = static_cast<Context *>(con);
    448     Asset *asset = static_cast<Asset *>(_asset);
    449     FileA3D *fa3d = new FileA3D(rsc);
    450     fa3d->incUserRef();
    451 
    452     fa3d->load(asset);
    453     return fa3d;
    454 #else
    455     return NULL;
    456 #endif
    457 }
    458 
    459 RsFile rsaFileA3DCreateFromFile(RsContext con, const char *path) {
    460     if (path == NULL) {
    461         ALOGE("File load failed. Path is NULL");
    462         return NULL;
    463     }
    464 
    465     Context *rsc = static_cast<Context *>(con);
    466     FileA3D *fa3d = NULL;
    467 
    468     FILE *f = fopen(path, "rb");
    469     if (f) {
    470         fa3d = new FileA3D(rsc);
    471         fa3d->incUserRef();
    472         fa3d->load(f);
    473         fclose(f);
    474     } else {
    475         ALOGE("Could not open file %s", path);
    476     }
    477 
    478     return fa3d;
    479 }
    480