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     }
    283     if (entry->mRsObj) {
    284         entry->mRsObj->incUserRef();
    285     }
    286     return entry->mRsObj;
    287 }
    288 
    289 bool FileA3D::writeFile(const char *filename) {
    290     if (!mWriteStream) {
    291         ALOGE("No objects to write\n");
    292         return false;
    293     }
    294     if (mWriteStream->getPos() == 0) {
    295         ALOGE("No objects to write\n");
    296         return false;
    297     }
    298 
    299     FILE *writeHandle = fopen(filename, "wb");
    300     if (!writeHandle) {
    301         ALOGE("Couldn't open the file for writing\n");
    302         return false;
    303     }
    304 
    305     // Open a new stream to make writing the header easier
    306     OStream headerStream(5*1024, false);
    307     headerStream.addU32(mMajorVersion);
    308     headerStream.addU32(mMinorVersion);
    309     uint32_t is64Bit = 0;
    310     headerStream.addU32(is64Bit);
    311 
    312     uint32_t writeIndexSize = mWriteIndex.size();
    313     headerStream.addU32(writeIndexSize);
    314     for (uint32_t i = 0; i < writeIndexSize; i ++) {
    315         headerStream.addString(&mWriteIndex[i]->mObjectName);
    316         headerStream.addU32((uint32_t)mWriteIndex[i]->mType);
    317         if (mUse64BitOffsets){
    318             headerStream.addOffset(mWriteIndex[i]->mOffset);
    319             headerStream.addOffset(mWriteIndex[i]->mLength);
    320         } else {
    321             uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset;
    322             headerStream.addU32(offset);
    323             offset = (uint32_t)mWriteIndex[i]->mLength;
    324             headerStream.addU32(offset);
    325         }
    326     }
    327 
    328     // Write our magic string so we know we are reading the right file
    329     String8 magicString(A3D_MAGIC_KEY);
    330     fwrite(magicString.string(), sizeof(char), magicString.size(), writeHandle);
    331 
    332     // Store the size of the header to make it easier to parse when we read it
    333     uint64_t headerSize = headerStream.getPos();
    334     fwrite(&headerSize, sizeof(headerSize), 1, writeHandle);
    335 
    336     // Now write our header
    337     fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle);
    338 
    339     // Now write the size of the data part of the file for easier parsing later
    340     uint64_t fileDataSize = mWriteStream->getPos();
    341     fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle);
    342 
    343     fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle);
    344 
    345     int status = fclose(writeHandle);
    346 
    347     if (status != 0) {
    348         ALOGE("Couldn't close file\n");
    349         return false;
    350     }
    351 
    352     return true;
    353 }
    354 
    355 void FileA3D::appendToFile(ObjectBase *obj) {
    356     if (!obj) {
    357         return;
    358     }
    359     if (!mWriteStream) {
    360         const uint64_t initialStreamSize = 256*1024;
    361         mWriteStream = new OStream(initialStreamSize, false);
    362     }
    363     A3DIndexEntry *indexEntry = new A3DIndexEntry();
    364     indexEntry->mObjectName.setTo(obj->getName());
    365     indexEntry->mType = obj->getClassId();
    366     indexEntry->mOffset = mWriteStream->getPos();
    367     indexEntry->mRsObj = obj;
    368     mWriteIndex.push(indexEntry);
    369     obj->serialize(mWriteStream);
    370     indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset;
    371     mWriteStream->align(4);
    372 }
    373 
    374 RsObjectBase rsaFileA3DGetEntryByIndex(RsContext con, uint32_t index, RsFile file) {
    375     FileA3D *fa3d = static_cast<FileA3D *>(file);
    376     if (!fa3d) {
    377         ALOGE("Can't load entry. No valid file");
    378         return NULL;
    379     }
    380 
    381     ObjectBase *obj = fa3d->initializeFromEntry(index);
    382     //ALOGV("Returning object with name %s", obj->getName());
    383 
    384     return obj;
    385 }
    386 
    387 
    388 void rsaFileA3DGetNumIndexEntries(RsContext con, int32_t *numEntries, RsFile file) {
    389     FileA3D *fa3d = static_cast<FileA3D *>(file);
    390 
    391     if (fa3d) {
    392         *numEntries = fa3d->getNumIndexEntries();
    393     } else {
    394         *numEntries = 0;
    395     }
    396 }
    397 
    398 void rsaFileA3DGetIndexEntries(RsContext con, RsFileIndexEntry *fileEntries, uint32_t numEntries, RsFile file) {
    399     FileA3D *fa3d = static_cast<FileA3D *>(file);
    400 
    401     if (!fa3d) {
    402         ALOGE("Can't load index entries. No valid file");
    403         return;
    404     }
    405 
    406     uint32_t numFileEntries = fa3d->getNumIndexEntries();
    407     if (numFileEntries != numEntries || numEntries == 0 || fileEntries == NULL) {
    408         ALOGE("Can't load index entries. Invalid number requested");
    409         return;
    410     }
    411 
    412     for (uint32_t i = 0; i < numFileEntries; i ++) {
    413         const FileA3D::A3DIndexEntry *entry = fa3d->getIndexEntry(i);
    414         fileEntries[i].classID = entry->getType();
    415         fileEntries[i].objectName = entry->getObjectName().string();
    416     }
    417 }
    418 
    419 RsFile rsaFileA3DCreateFromMemory(RsContext con, const void *data, uint32_t len) {
    420     if (data == NULL) {
    421         ALOGE("File load failed. Asset stream is NULL");
    422         return NULL;
    423     }
    424 
    425     Context *rsc = static_cast<Context *>(con);
    426     FileA3D *fa3d = new FileA3D(rsc);
    427     fa3d->incUserRef();
    428 
    429     fa3d->load(data, len);
    430     return fa3d;
    431 }
    432 
    433 RsFile rsaFileA3DCreateFromAsset(RsContext con, void *_asset) {
    434 #if !defined(__RS_PDK__)
    435     Context *rsc = static_cast<Context *>(con);
    436     Asset *asset = static_cast<Asset *>(_asset);
    437     FileA3D *fa3d = new FileA3D(rsc);
    438     fa3d->incUserRef();
    439 
    440     fa3d->load(asset);
    441     return fa3d;
    442 #else
    443     return NULL;
    444 #endif
    445 }
    446 
    447 RsFile rsaFileA3DCreateFromFile(RsContext con, const char *path) {
    448     if (path == NULL) {
    449         ALOGE("File load failed. Path is NULL");
    450         return NULL;
    451     }
    452 
    453     Context *rsc = static_cast<Context *>(con);
    454     FileA3D *fa3d = NULL;
    455 
    456     FILE *f = fopen(path, "rb");
    457     if (f) {
    458         fa3d = new FileA3D(rsc);
    459         fa3d->incUserRef();
    460         fa3d->load(f);
    461         fclose(f);
    462     } else {
    463         ALOGE("Could not open file %s", path);
    464     }
    465 
    466     return fa3d;
    467 }
    468