• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FileA3D(Context * rsc)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 
~FileA3D()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 
parseHeader(IStream * headerStream)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 
load(Asset * asset)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 
load(const void * data,size_t length)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 
load(FILE * f)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 
getNumIndexEntries() const213 size_t FileA3D::getNumIndexEntries() const {
214     return mIndex.size();
215 }
216 
getIndexEntry(size_t index) const217 const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const {
218     if (index < mIndex.size()) {
219         return mIndex[index];
220     }
221     return NULL;
222 }
223 
initializeFromEntry(size_t index)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 
writeFile(const char * filename)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 
appendToFile(Context * con,ObjectBase * obj)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 
rsaFileA3DGetEntryByIndex(RsContext con,uint32_t index,RsFile file)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 
rsaFileA3DGetNumIndexEntries(RsContext con,int32_t * numEntries,RsFile file)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 
rsaFileA3DGetIndexEntries(RsContext con,RsFileIndexEntry * fileEntries,uint32_t numEntries,RsFile file)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 
rsaFileA3DCreateFromMemory(RsContext con,const void * data,uint32_t len)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 
rsaFileA3DCreateFromAsset(RsContext con,void * _asset)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 
rsaFileA3DCreateFromFile(RsContext con,const char * path)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