/indra/llimage/llimagej2c.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 580 lines · 411 code · 82 blank · 87 comment · 55 complexity · 3ff587831171bf98d6c3b91017b2db26 MD5 · raw file

  1. /**
  2. * @file llimagej2c.cpp
  3. *
  4. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2010, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #include "linden_common.h"
  26. #include "lldir.h"
  27. #include "llimagej2c.h"
  28. #include "llmemtype.h"
  29. #include "lltimer.h"
  30. #include "llmath.h"
  31. #include "llmemory.h"
  32. typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)();
  33. typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*);
  34. typedef const char* (*EngineInfoLLImageJ2CFunction)();
  35. // Declare the prototype for theses functions here. Their functionality
  36. // will be implemented in other files which define a derived LLImageJ2CImpl
  37. // but only ONE static library which has the implementation for these
  38. // functions should ever be included.
  39. LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl();
  40. void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl);
  41. const char* fallbackEngineInfoLLImageJ2CImpl();
  42. // Test data gathering handle
  43. LLImageCompressionTester* LLImageJ2C::sTesterp = NULL ;
  44. const std::string sTesterName("ImageCompressionTester");
  45. //static
  46. std::string LLImageJ2C::getEngineInfo()
  47. {
  48. return fallbackEngineInfoLLImageJ2CImpl();
  49. }
  50. LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
  51. mMaxBytes(0),
  52. mRawDiscardLevel(-1),
  53. mRate(0.0f),
  54. mReversible(FALSE),
  55. mAreaUsedForDataSizeCalcs(0)
  56. {
  57. mImpl = fallbackCreateLLImageJ2CImpl();
  58. // Clear data size table
  59. for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++)
  60. { // Array size is MAX_DISCARD_LEVEL+1
  61. mDataSizes[i] = 0;
  62. }
  63. // If that test log has ben requested but not yet created, create it
  64. if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName))
  65. {
  66. sTesterp = new LLImageCompressionTester() ;
  67. if (!sTesterp->isValid())
  68. {
  69. delete sTesterp;
  70. sTesterp = NULL;
  71. }
  72. }
  73. }
  74. // virtual
  75. LLImageJ2C::~LLImageJ2C()
  76. {
  77. if ( mImpl )
  78. {
  79. fallbackDestroyLLImageJ2CImpl(mImpl);
  80. }
  81. }
  82. // virtual
  83. void LLImageJ2C::resetLastError()
  84. {
  85. mLastError.clear();
  86. }
  87. //virtual
  88. void LLImageJ2C::setLastError(const std::string& message, const std::string& filename)
  89. {
  90. mLastError = message;
  91. if (!filename.empty())
  92. mLastError += std::string(" FILE: ") + filename;
  93. }
  94. // virtual
  95. S8 LLImageJ2C::getRawDiscardLevel()
  96. {
  97. return mRawDiscardLevel;
  98. }
  99. BOOL LLImageJ2C::updateData()
  100. {
  101. BOOL res = TRUE;
  102. resetLastError();
  103. // Check to make sure that this instance has been initialized with data
  104. if (!getData() || (getDataSize() < 16))
  105. {
  106. setLastError("LLImageJ2C uninitialized");
  107. res = FALSE;
  108. }
  109. else
  110. {
  111. res = mImpl->getMetadata(*this);
  112. }
  113. if (res)
  114. {
  115. // SJB: override discard based on mMaxBytes elsewhere
  116. S32 max_bytes = getDataSize(); // mMaxBytes ? mMaxBytes : getDataSize();
  117. S32 discard = calcDiscardLevelBytes(max_bytes);
  118. setDiscardLevel(discard);
  119. }
  120. if (!mLastError.empty())
  121. {
  122. LLImage::setLastError(mLastError);
  123. }
  124. return res;
  125. }
  126. BOOL LLImageJ2C::initDecode(LLImageRaw &raw_image, int discard_level, int* region)
  127. {
  128. return mImpl->initDecode(*this,raw_image,discard_level,region);
  129. }
  130. BOOL LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
  131. {
  132. return mImpl->initEncode(*this,raw_image,blocks_size,precincts_size,levels);
  133. }
  134. BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
  135. {
  136. return decodeChannels(raw_imagep, decode_time, 0, 4);
  137. }
  138. // Returns TRUE to mean done, whether successful or not.
  139. BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
  140. {
  141. LLTimer elapsed;
  142. LLMemType mt1(mMemType);
  143. BOOL res = TRUE;
  144. resetLastError();
  145. // Check to make sure that this instance has been initialized with data
  146. if (!getData() || (getDataSize() < 16))
  147. {
  148. setLastError("LLImageJ2C uninitialized");
  149. res = TRUE; // done
  150. }
  151. else
  152. {
  153. // Update the raw discard level
  154. updateRawDiscardLevel();
  155. mDecoding = TRUE;
  156. res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count);
  157. }
  158. if (res)
  159. {
  160. if (!mDecoding)
  161. {
  162. // Failed
  163. raw_imagep->deleteData();
  164. }
  165. else
  166. {
  167. mDecoding = FALSE;
  168. }
  169. }
  170. if (!mLastError.empty())
  171. {
  172. LLImage::setLastError(mLastError);
  173. }
  174. LLImageCompressionTester* tester = (LLImageCompressionTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
  175. if (tester)
  176. {
  177. // Decompression stat gathering
  178. // Note that we *do not* take into account the decompression failures data so we might overestimate the time spent processing
  179. // Always add the decompression time to the stat
  180. tester->updateDecompressionStats(elapsed.getElapsedTimeF32()) ;
  181. if (res)
  182. {
  183. // The whole data stream is finally decompressed when res is returned as TRUE
  184. tester->updateDecompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ;
  185. }
  186. }
  187. return res;
  188. }
  189. BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time)
  190. {
  191. return encode(raw_imagep, NULL, encode_time);
  192. }
  193. BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time)
  194. {
  195. LLTimer elapsed;
  196. LLMemType mt1(mMemType);
  197. resetLastError();
  198. BOOL res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible);
  199. if (!mLastError.empty())
  200. {
  201. LLImage::setLastError(mLastError);
  202. }
  203. LLImageCompressionTester* tester = (LLImageCompressionTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
  204. if (tester)
  205. {
  206. // Compression stat gathering
  207. // Note that we *do not* take into account the compression failures cases so we night overestimate the time spent processing
  208. // Always add the compression time to the stat
  209. tester->updateCompressionStats(elapsed.getElapsedTimeF32()) ;
  210. if (res)
  211. {
  212. // The whole data stream is finally compressed when res is returned as TRUE
  213. tester->updateCompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ;
  214. }
  215. }
  216. return res;
  217. }
  218. //static
  219. S32 LLImageJ2C::calcHeaderSizeJ2C()
  220. {
  221. return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size...
  222. }
  223. //static
  224. S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate)
  225. {
  226. // Note: this only provides an *estimate* of the size in bytes of an image level
  227. // *TODO: find a way to read the true size (when available) and convey the fact
  228. // that the result is an estimate in the other cases
  229. if (rate <= 0.f) rate = .125f;
  230. while (discard_level > 0)
  231. {
  232. if (w < 1 || h < 1)
  233. break;
  234. w >>= 1;
  235. h >>= 1;
  236. discard_level--;
  237. }
  238. S32 bytes = (S32)((F32)(w*h*comp)*rate);
  239. bytes = llmax(bytes, calcHeaderSizeJ2C());
  240. return bytes;
  241. }
  242. S32 LLImageJ2C::calcHeaderSize()
  243. {
  244. return calcHeaderSizeJ2C();
  245. }
  246. // calcDataSize() returns how many bytes to read
  247. // to load discard_level (including header and higher discard levels)
  248. S32 LLImageJ2C::calcDataSize(S32 discard_level)
  249. {
  250. discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL);
  251. if ( mAreaUsedForDataSizeCalcs != (getHeight() * getWidth())
  252. || mDataSizes[0] == 0)
  253. {
  254. mAreaUsedForDataSizeCalcs = getHeight() * getWidth();
  255. S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard
  256. while ( level >= 0 )
  257. {
  258. mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate);
  259. level--;
  260. }
  261. /* This is technically a more correct way to calculate the size required
  262. for each discard level, since they should include the size needed for
  263. lower levels. Unfortunately, this doesn't work well and will lead to
  264. download stalls. The true correct way is to parse the header. This will
  265. all go away with http textures at some point.
  266. // Calculate the size for each discard level. Lower levels (higher quality)
  267. // contain the cumulative size of higher levels
  268. S32 total_size = calcHeaderSizeJ2C();
  269. S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard
  270. while ( level >= 0 )
  271. { // Add in this discard level and all before it
  272. total_size += calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate);
  273. mDataSizes[level] = total_size;
  274. level--;
  275. }
  276. */
  277. }
  278. return mDataSizes[discard_level];
  279. }
  280. S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes)
  281. {
  282. llassert(bytes >= 0);
  283. S32 discard_level = 0;
  284. if (bytes == 0)
  285. {
  286. return MAX_DISCARD_LEVEL;
  287. }
  288. while (1)
  289. {
  290. S32 bytes_needed = calcDataSize(discard_level); // virtual
  291. if (bytes >= bytes_needed - (bytes_needed>>2)) // For J2c, up the res at 75% of the optimal number of bytes
  292. {
  293. break;
  294. }
  295. discard_level++;
  296. if (discard_level >= MAX_DISCARD_LEVEL)
  297. {
  298. break;
  299. }
  300. }
  301. return discard_level;
  302. }
  303. void LLImageJ2C::setRate(F32 rate)
  304. {
  305. mRate = rate;
  306. }
  307. void LLImageJ2C::setMaxBytes(S32 max_bytes)
  308. {
  309. mMaxBytes = max_bytes;
  310. }
  311. void LLImageJ2C::setReversible(const BOOL reversible)
  312. {
  313. mReversible = reversible;
  314. }
  315. BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
  316. {
  317. BOOL res = TRUE;
  318. resetLastError();
  319. S32 file_size = 0;
  320. LLAPRFile infile ;
  321. infile.open(filename, LL_APR_RB, NULL, &file_size);
  322. apr_file_t* apr_file = infile.getFileHandle() ;
  323. if (!apr_file)
  324. {
  325. setLastError("Unable to open file for reading", filename);
  326. res = FALSE;
  327. }
  328. else if (file_size == 0)
  329. {
  330. setLastError("File is empty",filename);
  331. res = FALSE;
  332. }
  333. else
  334. {
  335. U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size);
  336. apr_size_t bytes_read = file_size;
  337. apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
  338. infile.close() ;
  339. if (s != APR_SUCCESS || (S32)bytes_read != file_size)
  340. {
  341. FREE_MEM(LLImageBase::getPrivatePool(), data);
  342. setLastError("Unable to read entire file");
  343. res = FALSE;
  344. }
  345. else
  346. {
  347. res = validate(data, file_size);
  348. }
  349. }
  350. if (!mLastError.empty())
  351. {
  352. LLImage::setLastError(mLastError);
  353. }
  354. return res;
  355. }
  356. BOOL LLImageJ2C::validate(U8 *data, U32 file_size)
  357. {
  358. LLMemType mt1(mMemType);
  359. resetLastError();
  360. setData(data, file_size);
  361. BOOL res = updateData();
  362. if ( res )
  363. {
  364. // Check to make sure that this instance has been initialized with data
  365. if (!getData() || (0 == getDataSize()))
  366. {
  367. setLastError("LLImageJ2C uninitialized");
  368. res = FALSE;
  369. }
  370. else
  371. {
  372. res = mImpl->getMetadata(*this);
  373. }
  374. }
  375. if (!mLastError.empty())
  376. {
  377. LLImage::setLastError(mLastError);
  378. }
  379. return res;
  380. }
  381. void LLImageJ2C::decodeFailed()
  382. {
  383. mDecoding = FALSE;
  384. }
  385. void LLImageJ2C::updateRawDiscardLevel()
  386. {
  387. mRawDiscardLevel = mMaxBytes ? calcDiscardLevelBytes(mMaxBytes) : mDiscardLevel;
  388. }
  389. LLImageJ2CImpl::~LLImageJ2CImpl()
  390. {
  391. }
  392. //----------------------------------------------------------------------------------------------
  393. // Start of LLImageCompressionTester
  394. //----------------------------------------------------------------------------------------------
  395. LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTesterBasic(sTesterName)
  396. {
  397. addMetric("Time Decompression (s)");
  398. addMetric("Volume In Decompression (kB)");
  399. addMetric("Volume Out Decompression (kB)");
  400. addMetric("Decompression Ratio (x:1)");
  401. addMetric("Perf Decompression (kB/s)");
  402. addMetric("Time Compression (s)");
  403. addMetric("Volume In Compression (kB)");
  404. addMetric("Volume Out Compression (kB)");
  405. addMetric("Compression Ratio (x:1)");
  406. addMetric("Perf Compression (kB/s)");
  407. mRunBytesInDecompression = 0;
  408. mRunBytesInCompression = 0;
  409. mTotalBytesInDecompression = 0;
  410. mTotalBytesOutDecompression = 0;
  411. mTotalBytesInCompression = 0;
  412. mTotalBytesOutCompression = 0;
  413. mTotalTimeDecompression = 0.0f;
  414. mTotalTimeCompression = 0.0f;
  415. }
  416. LLImageCompressionTester::~LLImageCompressionTester()
  417. {
  418. outputTestResults();
  419. LLImageJ2C::sTesterp = NULL;
  420. }
  421. //virtual
  422. void LLImageCompressionTester::outputTestRecord(LLSD *sd)
  423. {
  424. std::string currentLabel = getCurrentLabelName();
  425. F32 decompressionPerf = 0.0f;
  426. F32 compressionPerf = 0.0f;
  427. F32 decompressionRate = 0.0f;
  428. F32 compressionRate = 0.0f;
  429. F32 totalkBInDecompression = (F32)(mTotalBytesInDecompression) / 1000.0;
  430. F32 totalkBOutDecompression = (F32)(mTotalBytesOutDecompression) / 1000.0;
  431. F32 totalkBInCompression = (F32)(mTotalBytesInCompression) / 1000.0;
  432. F32 totalkBOutCompression = (F32)(mTotalBytesOutCompression) / 1000.0;
  433. if (!is_approx_zero(mTotalTimeDecompression))
  434. {
  435. decompressionPerf = totalkBInDecompression / mTotalTimeDecompression;
  436. }
  437. if (!is_approx_zero(totalkBInDecompression))
  438. {
  439. decompressionRate = totalkBOutDecompression / totalkBInDecompression;
  440. }
  441. if (!is_approx_zero(mTotalTimeCompression))
  442. {
  443. compressionPerf = totalkBInCompression / mTotalTimeCompression;
  444. }
  445. if (!is_approx_zero(totalkBOutCompression))
  446. {
  447. compressionRate = totalkBInCompression / totalkBOutCompression;
  448. }
  449. (*sd)[currentLabel]["Time Decompression (s)"] = (LLSD::Real)mTotalTimeDecompression;
  450. (*sd)[currentLabel]["Volume In Decompression (kB)"] = (LLSD::Real)totalkBInDecompression;
  451. (*sd)[currentLabel]["Volume Out Decompression (kB)"]= (LLSD::Real)totalkBOutDecompression;
  452. (*sd)[currentLabel]["Decompression Ratio (x:1)"] = (LLSD::Real)decompressionRate;
  453. (*sd)[currentLabel]["Perf Decompression (kB/s)"] = (LLSD::Real)decompressionPerf;
  454. (*sd)[currentLabel]["Time Compression (s)"] = (LLSD::Real)mTotalTimeCompression;
  455. (*sd)[currentLabel]["Volume In Compression (kB)"] = (LLSD::Real)totalkBInCompression;
  456. (*sd)[currentLabel]["Volume Out Compression (kB)"] = (LLSD::Real)totalkBOutCompression;
  457. (*sd)[currentLabel]["Compression Ratio (x:1)"] = (LLSD::Real)compressionRate;
  458. (*sd)[currentLabel]["Perf Compression (kB/s)"] = (LLSD::Real)compressionPerf;
  459. }
  460. void LLImageCompressionTester::updateCompressionStats(const F32 deltaTime)
  461. {
  462. mTotalTimeCompression += deltaTime;
  463. }
  464. void LLImageCompressionTester::updateCompressionStats(const S32 bytesCompress, const S32 bytesRaw)
  465. {
  466. mTotalBytesInCompression += bytesRaw;
  467. mRunBytesInCompression += bytesRaw;
  468. mTotalBytesOutCompression += bytesCompress;
  469. if (mRunBytesInCompression > (1000000))
  470. {
  471. // Output everything
  472. outputTestResults();
  473. // Reset the compression data of the run
  474. mRunBytesInCompression = 0;
  475. }
  476. }
  477. void LLImageCompressionTester::updateDecompressionStats(const F32 deltaTime)
  478. {
  479. mTotalTimeDecompression += deltaTime;
  480. }
  481. void LLImageCompressionTester::updateDecompressionStats(const S32 bytesIn, const S32 bytesOut)
  482. {
  483. mTotalBytesInDecompression += bytesIn;
  484. mRunBytesInDecompression += bytesIn;
  485. mTotalBytesOutDecompression += bytesOut;
  486. if (mRunBytesInDecompression > (1000000))
  487. {
  488. // Output everything
  489. outputTestResults();
  490. // Reset the decompression data of the run
  491. mRunBytesInDecompression = 0;
  492. }
  493. }
  494. //----------------------------------------------------------------------------------------------
  495. // End of LLTexturePipelineTester
  496. //----------------------------------------------------------------------------------------------