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