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