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
FileA3D(Context * rsc)34 FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc) {
35 mAlloc = nullptr;
36 mData = nullptr;
37 mWriteStream = nullptr;
38 mReadStream = nullptr;
39 mAsset = nullptr;
40
41 mMajorVersion = 0;
42 mMinorVersion = 1;
43 mDataSize = 0;
44 }
45
~FileA3D()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 mReadStream;
58 }
59 if (mAlloc) {
60 free(mAlloc);
61 }
62 if (mAsset) {
63 #if !defined(__RS_PDK__)
64 delete mAsset;
65 #endif
66 }
67 }
68
parseHeader(IStream * headerStream)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 = nullptr;
90 mIndex.push(entry);
91 }
92 }
93
load(Asset * asset)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
load(const void * data,size_t length)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
load(FILE * f)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
getNumIndexEntries() const216 size_t FileA3D::getNumIndexEntries() const {
217 return mIndex.size();
218 }
219
~A3DIndexEntry()220 FileA3D::A3DIndexEntry::~A3DIndexEntry() {
221 delete[] mObjectName;
222 }
223
getIndexEntry(size_t index) const224 const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const {
225 if (index < mIndex.size()) {
226 return mIndex[index];
227 }
228 return nullptr;
229 }
230
initializeFromEntry(size_t index)231 ObjectBase *FileA3D::initializeFromEntry(size_t index) {
232 if (index >= mIndex.size()) {
233 return nullptr;
234 }
235
236 FileA3D::A3DIndexEntry *entry = mIndex[index];
237 if (!entry) {
238 return nullptr;
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 nullptr;
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_INVOKE_ID:
292 break;
293 case RS_A3D_CLASS_ID_SCRIPT_FIELD_ID:
294 break;
295 case RS_A3D_CLASS_ID_SCRIPT_METHOD_ID:
296 break;
297 case RS_A3D_CLASS_ID_SCRIPT_GROUP:
298 break;
299 case RS_A3D_CLASS_ID_CLOSURE:
300 break;
301 case RS_A3D_CLASS_ID_SCRIPT_GROUP2:
302 break;
303 }
304 if (entry->mRsObj) {
305 entry->mRsObj->incUserRef();
306 }
307 return entry->mRsObj;
308 }
309
writeFile(const char * filename)310 bool FileA3D::writeFile(const char *filename) {
311 if (!mWriteStream) {
312 ALOGE("No objects to write\n");
313 return false;
314 }
315 if (mWriteStream->getPos() == 0) {
316 ALOGE("No objects to write\n");
317 return false;
318 }
319
320 FILE *writeHandle = fopen(filename, "wb");
321 if (!writeHandle) {
322 ALOGE("Couldn't open the file for writing\n");
323 return false;
324 }
325
326 // Open a new stream to make writing the header easier
327 OStream headerStream(5*1024, false);
328 headerStream.addU32(mMajorVersion);
329 headerStream.addU32(mMinorVersion);
330 uint32_t is64Bit = 0;
331 headerStream.addU32(is64Bit);
332
333 uint32_t writeIndexSize = mWriteIndex.size();
334 headerStream.addU32(writeIndexSize);
335 for (uint32_t i = 0; i < writeIndexSize; i ++) {
336 headerStream.addString(mWriteIndex[i]->mObjectName);
337 headerStream.addU32((uint32_t)mWriteIndex[i]->mType);
338 if (mUse64BitOffsets){
339 headerStream.addOffset(mWriteIndex[i]->mOffset);
340 headerStream.addOffset(mWriteIndex[i]->mLength);
341 } else {
342 uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset;
343 headerStream.addU32(offset);
344 offset = (uint32_t)mWriteIndex[i]->mLength;
345 headerStream.addU32(offset);
346 }
347 }
348
349 // Write our magic string so we know we are reading the right file
350 fwrite(A3D_MAGIC_KEY, sizeof(char), strlen(A3D_MAGIC_KEY), writeHandle);
351
352 // Store the size of the header to make it easier to parse when we read it
353 uint64_t headerSize = headerStream.getPos();
354 fwrite(&headerSize, sizeof(headerSize), 1, writeHandle);
355
356 // Now write our header
357 fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle);
358
359 // Now write the size of the data part of the file for easier parsing later
360 uint64_t fileDataSize = mWriteStream->getPos();
361 fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle);
362
363 fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle);
364
365 int status = fclose(writeHandle);
366
367 if (status != 0) {
368 ALOGE("Couldn't close file\n");
369 return false;
370 }
371
372 return true;
373 }
374
appendToFile(Context * con,ObjectBase * obj)375 void FileA3D::appendToFile(Context *con, ObjectBase *obj) {
376 if (!obj) {
377 return;
378 }
379 if (!mWriteStream) {
380 const uint64_t initialStreamSize = 256*1024;
381 mWriteStream = new OStream(initialStreamSize, false);
382 }
383 A3DIndexEntry *indexEntry = new A3DIndexEntry();
384 indexEntry->mObjectName = rsuCopyString(obj->getName());
385 indexEntry->mType = obj->getClassId();
386 indexEntry->mOffset = mWriteStream->getPos();
387 indexEntry->mRsObj = obj;
388 mWriteIndex.push(indexEntry);
389 obj->serialize(con, mWriteStream);
390 indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset;
391 mWriteStream->align(4);
392 }
393
394