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