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