rsFileA3D.cpp revision 5bb6dc1933e11cb57e5f4205d13686ad113b205e
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 31using namespace android; 32using namespace android::renderscript; 33 34FileA3D::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 46FileA3D::~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 69void 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 94bool 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 103bool 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 157bool 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 216size_t FileA3D::getNumIndexEntries() const { 217 return mIndex.size(); 218} 219 220FileA3D::A3DIndexEntry::~A3DIndexEntry() { 221 delete[] mObjectName; 222} 223 224const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const { 225 if (index < mIndex.size()) { 226 return mIndex[index]; 227 } 228 return nullptr; 229} 230 231ObjectBase *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 310bool 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 375void 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 394RsObjectBase rsaFileA3DGetEntryByIndex(RsContext con, uint32_t index, RsFile file) { 395 FileA3D *fa3d = static_cast<FileA3D *>(file); 396 if (!fa3d) { 397 ALOGE("Can't load entry. No valid file"); 398 return nullptr; 399 } 400 401 ObjectBase *obj = fa3d->initializeFromEntry(index); 402 //ALOGV("Returning object with name %s", obj->getName()); 403 404 return obj; 405} 406 407 408void rsaFileA3DGetNumIndexEntries(RsContext con, int32_t *numEntries, RsFile file) { 409 FileA3D *fa3d = static_cast<FileA3D *>(file); 410 411 if (fa3d) { 412 *numEntries = fa3d->getNumIndexEntries(); 413 } else { 414 *numEntries = 0; 415 } 416} 417 418void rsaFileA3DGetIndexEntries(RsContext con, RsFileIndexEntry *fileEntries, uint32_t numEntries, RsFile file) { 419 FileA3D *fa3d = static_cast<FileA3D *>(file); 420 421 if (!fa3d) { 422 ALOGE("Can't load index entries. No valid file"); 423 return; 424 } 425 426 uint32_t numFileEntries = fa3d->getNumIndexEntries(); 427 if (numFileEntries != numEntries || numEntries == 0 || fileEntries == nullptr) { 428 ALOGE("Can't load index entries. Invalid number requested"); 429 return; 430 } 431 432 for (uint32_t i = 0; i < numFileEntries; i ++) { 433 const FileA3D::A3DIndexEntry *entry = fa3d->getIndexEntry(i); 434 fileEntries[i].classID = entry->getType(); 435 fileEntries[i].objectName = rsuCopyString(entry->getObjectName()); 436 } 437} 438 439RsFile rsaFileA3DCreateFromMemory(RsContext con, const void *data, uint32_t len) { 440 if (data == nullptr) { 441 ALOGE("File load failed. Asset stream is nullptr"); 442 return nullptr; 443 } 444 445 Context *rsc = static_cast<Context *>(con); 446 FileA3D *fa3d = new FileA3D(rsc); 447 fa3d->incUserRef(); 448 449 fa3d->load(data, len); 450 return fa3d; 451} 452 453RsFile rsaFileA3DCreateFromAsset(RsContext con, void *_asset) { 454#if !defined(__RS_PDK__) 455 Context *rsc = static_cast<Context *>(con); 456 Asset *asset = static_cast<Asset *>(_asset); 457 FileA3D *fa3d = new FileA3D(rsc); 458 fa3d->incUserRef(); 459 460 fa3d->load(asset); 461 return fa3d; 462#else 463 return nullptr; 464#endif 465} 466 467RsFile rsaFileA3DCreateFromFile(RsContext con, const char *path) { 468 if (path == nullptr) { 469 ALOGE("File load failed. Path is nullptr"); 470 return nullptr; 471 } 472 473 Context *rsc = static_cast<Context *>(con); 474 FileA3D *fa3d = nullptr; 475 476 FILE *f = fopen(path, "rb"); 477 if (f) { 478 fa3d = new FileA3D(rsc); 479 fa3d->incUserRef(); 480 fa3d->load(f); 481 fclose(f); 482 } else { 483 ALOGE("Could not open file %s", path); 484 } 485 486 return fa3d; 487} 488