/indra/llimage/llimagedxt.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 506 lines · 412 code · 49 blank · 45 comment · 43 complexity · cdf5e4253461fbbaa1a0cb3d2377d3cb MD5 · raw file

  1. /**
  2. * @file llimagedxt.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 "llimagedxt.h"
  27. #include "llmemory.h"
  28. //static
  29. void LLImageDXT::checkMinWidthHeight(EFileFormat format, S32& width, S32& height)
  30. {
  31. S32 mindim = (format >= FORMAT_DXT1 && format <= FORMAT_DXR5) ? 4 : 1;
  32. width = llmax(width, mindim);
  33. height = llmax(height, mindim);
  34. }
  35. //static
  36. S32 LLImageDXT::formatBits(EFileFormat format)
  37. {
  38. switch (format)
  39. {
  40. case FORMAT_DXT1: return 4;
  41. case FORMAT_DXR1: return 4;
  42. case FORMAT_I8: return 8;
  43. case FORMAT_A8: return 8;
  44. case FORMAT_DXT3: return 8;
  45. case FORMAT_DXR3: return 8;
  46. case FORMAT_DXR5: return 8;
  47. case FORMAT_DXT5: return 8;
  48. case FORMAT_RGB8: return 24;
  49. case FORMAT_RGBA8: return 32;
  50. default:
  51. llerrs << "LLImageDXT::Unknown format: " << format << llendl;
  52. return 0;
  53. }
  54. };
  55. //static
  56. S32 LLImageDXT::formatBytes(EFileFormat format, S32 width, S32 height)
  57. {
  58. checkMinWidthHeight(format, width, height);
  59. S32 bytes = ((width*height*formatBits(format)+7)>>3);
  60. S32 aligned = (bytes+3)&~3;
  61. return aligned;
  62. }
  63. //static
  64. S32 LLImageDXT::formatComponents(EFileFormat format)
  65. {
  66. switch (format)
  67. {
  68. case FORMAT_DXT1: return 3;
  69. case FORMAT_DXR1: return 3;
  70. case FORMAT_I8: return 1;
  71. case FORMAT_A8: return 1;
  72. case FORMAT_DXT3: return 4;
  73. case FORMAT_DXR3: return 4;
  74. case FORMAT_DXT5: return 4;
  75. case FORMAT_DXR5: return 4;
  76. case FORMAT_RGB8: return 3;
  77. case FORMAT_RGBA8: return 4;
  78. default:
  79. llerrs << "LLImageDXT::Unknown format: " << format << llendl;
  80. return 0;
  81. }
  82. };
  83. // static
  84. LLImageDXT::EFileFormat LLImageDXT::getFormat(S32 fourcc)
  85. {
  86. switch(fourcc)
  87. {
  88. case 0x20203849: return FORMAT_I8;
  89. case 0x20203841: return FORMAT_A8;
  90. case 0x20424752: return FORMAT_RGB8;
  91. case 0x41424752: return FORMAT_RGBA8;
  92. case 0x31525844: return FORMAT_DXR1;
  93. case 0x32525844: return FORMAT_DXR2;
  94. case 0x33525844: return FORMAT_DXR3;
  95. case 0x34525844: return FORMAT_DXR4;
  96. case 0x35525844: return FORMAT_DXR5;
  97. case 0x31545844: return FORMAT_DXT1;
  98. case 0x32545844: return FORMAT_DXT2;
  99. case 0x33545844: return FORMAT_DXT3;
  100. case 0x34545844: return FORMAT_DXT4;
  101. case 0x35545844: return FORMAT_DXT5;
  102. default: return FORMAT_UNKNOWN;
  103. }
  104. }
  105. //static
  106. S32 LLImageDXT::getFourCC(EFileFormat format)
  107. {
  108. switch(format)
  109. {
  110. case FORMAT_I8: return 0x20203849;
  111. case FORMAT_A8: return 0x20203841;
  112. case FORMAT_RGB8: return 0x20424752;
  113. case FORMAT_RGBA8: return 0x41424752;
  114. case FORMAT_DXR1: return 0x31525844;
  115. case FORMAT_DXR2: return 0x32525844;
  116. case FORMAT_DXR3: return 0x33525844;
  117. case FORMAT_DXR4: return 0x34525844;
  118. case FORMAT_DXR5: return 0x35525844;
  119. case FORMAT_DXT1: return 0x31545844;
  120. case FORMAT_DXT2: return 0x32545844;
  121. case FORMAT_DXT3: return 0x33545844;
  122. case FORMAT_DXT4: return 0x34545844;
  123. case FORMAT_DXT5: return 0x35545844;
  124. default: return 0x00000000;
  125. }
  126. }
  127. //static
  128. void LLImageDXT::calcDiscardWidthHeight(S32 discard_level, EFileFormat format, S32& width, S32& height)
  129. {
  130. while (discard_level > 0 && width > 1 && height > 1)
  131. {
  132. discard_level--;
  133. width >>= 1;
  134. height >>= 1;
  135. }
  136. checkMinWidthHeight(format, width, height);
  137. }
  138. //static
  139. S32 LLImageDXT::calcNumMips(S32 width, S32 height)
  140. {
  141. S32 nmips = 0;
  142. while (width > 0 && height > 0)
  143. {
  144. width >>= 1;
  145. height >>= 1;
  146. nmips++;
  147. }
  148. return nmips;
  149. }
  150. //============================================================================
  151. LLImageDXT::LLImageDXT()
  152. : LLImageFormatted(IMG_CODEC_DXT),
  153. mFileFormat(FORMAT_UNKNOWN),
  154. mHeaderSize(0)
  155. {
  156. }
  157. LLImageDXT::~LLImageDXT()
  158. {
  159. }
  160. // virtual
  161. BOOL LLImageDXT::updateData()
  162. {
  163. resetLastError();
  164. U8* data = getData();
  165. S32 data_size = getDataSize();
  166. if (!data || !data_size)
  167. {
  168. setLastError("LLImageDXT uninitialized");
  169. return FALSE;
  170. }
  171. S32 width, height, miplevelmax;
  172. dxtfile_header_t* header = (dxtfile_header_t*)data;
  173. if (header->fourcc != 0x20534444)
  174. {
  175. dxtfile_header_old_t* oldheader = (dxtfile_header_old_t*)header;
  176. mHeaderSize = sizeof(dxtfile_header_old_t);
  177. mFileFormat = EFileFormat(oldheader->format);
  178. miplevelmax = llmin(oldheader->maxlevel,MAX_IMAGE_MIP);
  179. width = oldheader->maxwidth;
  180. height = oldheader->maxheight;
  181. }
  182. else
  183. {
  184. mHeaderSize = sizeof(dxtfile_header_t);
  185. mFileFormat = getFormat(header->pixel_fmt.fourcc);
  186. miplevelmax = llmin(header->num_mips-1,MAX_IMAGE_MIP);
  187. width = header->maxwidth;
  188. height = header->maxheight;
  189. }
  190. if (data_size < mHeaderSize)
  191. {
  192. llerrs << "LLImageDXT: not enough data" << llendl;
  193. }
  194. S32 ncomponents = formatComponents(mFileFormat);
  195. setSize(width, height, ncomponents);
  196. S32 discard = calcDiscardLevelBytes(data_size);
  197. discard = llmin(discard, miplevelmax);
  198. setDiscardLevel(discard);
  199. return TRUE;
  200. }
  201. // discard: 0 = largest (last) mip
  202. S32 LLImageDXT::getMipOffset(S32 discard)
  203. {
  204. if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXT5)
  205. {
  206. llerrs << "getMipOffset called with old (unsupported) format" << llendl;
  207. }
  208. S32 width = getWidth(), height = getHeight();
  209. S32 num_mips = calcNumMips(width, height);
  210. discard = llclamp(discard, 0, num_mips-1);
  211. S32 last_mip = num_mips-1-discard;
  212. llassert(mHeaderSize > 0);
  213. S32 offset = mHeaderSize;
  214. for (S32 mipidx = num_mips-1; mipidx >= 0; mipidx--)
  215. {
  216. if (mipidx < last_mip)
  217. {
  218. offset += formatBytes(mFileFormat, width, height);
  219. }
  220. width >>= 1;
  221. height >>= 1;
  222. }
  223. return offset;
  224. }
  225. void LLImageDXT::setFormat()
  226. {
  227. S32 ncomponents = getComponents();
  228. switch (ncomponents)
  229. {
  230. case 3: mFileFormat = FORMAT_DXR1; break;
  231. case 4: mFileFormat = FORMAT_DXR3; break;
  232. default: llerrs << "LLImageDXT::setFormat called with ncomponents = " << ncomponents << llendl;
  233. }
  234. mHeaderSize = calcHeaderSize();
  235. }
  236. // virtual
  237. BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
  238. {
  239. // *TODO: Test! This has been tweaked since its intial inception,
  240. // but we don't use it any more!
  241. llassert_always(raw_image);
  242. if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
  243. {
  244. llwarns << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << llendl;
  245. return FALSE;
  246. }
  247. S32 width = getWidth(), height = getHeight();
  248. S32 ncomponents = getComponents();
  249. U8* data = NULL;
  250. if (mDiscardLevel >= 0)
  251. {
  252. data = getData() + getMipOffset(mDiscardLevel);
  253. calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height);
  254. }
  255. else
  256. {
  257. data = getData() + getMipOffset(0);
  258. }
  259. S32 image_size = formatBytes(mFileFormat, width, height);
  260. if ((!getData()) || (data + image_size > getData() + getDataSize()))
  261. {
  262. setLastError("LLImageDXT trying to decode an image with not enough data!");
  263. return FALSE;
  264. }
  265. raw_image->resize(width, height, ncomponents);
  266. memcpy(raw_image->getData(), data, image_size); /* Flawfinder: ignore */
  267. return TRUE;
  268. }
  269. BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
  270. {
  271. if (discard < 0)
  272. {
  273. discard = mDiscardLevel;
  274. }
  275. else if (discard < mDiscardLevel)
  276. {
  277. llerrs << "Request for invalid discard level" << llendl;
  278. }
  279. U8* data = getData() + getMipOffset(discard);
  280. S32 width = 0;
  281. S32 height = 0;
  282. calcDiscardWidthHeight(discard, mFileFormat, width, height);
  283. raw = new LLImageRaw(data, width, height, getComponents());
  284. return TRUE;
  285. }
  286. BOOL LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_mips)
  287. {
  288. llassert_always(raw_image);
  289. S32 ncomponents = raw_image->getComponents();
  290. EFileFormat format;
  291. switch (ncomponents)
  292. {
  293. case 1:
  294. format = FORMAT_A8;
  295. break;
  296. case 3:
  297. format = FORMAT_RGB8;
  298. break;
  299. case 4:
  300. format = FORMAT_RGBA8;
  301. break;
  302. default:
  303. llerrs << "LLImageDXT::encode: Unhandled channel number: " << ncomponents << llendl;
  304. return 0;
  305. }
  306. S32 width = raw_image->getWidth();
  307. S32 height = raw_image->getHeight();
  308. if (explicit_mips)
  309. {
  310. height = (height/3)*2;
  311. }
  312. setSize(width, height, ncomponents);
  313. mHeaderSize = sizeof(dxtfile_header_t);
  314. mFileFormat = format;
  315. S32 nmips = calcNumMips(width, height);
  316. S32 w = width;
  317. S32 h = height;
  318. S32 totbytes = mHeaderSize;
  319. for (S32 mip=0; mip<nmips; mip++)
  320. {
  321. totbytes += formatBytes(format,w,h);
  322. w >>= 1;
  323. h >>= 1;
  324. }
  325. allocateData(totbytes);
  326. U8* data = getData();
  327. dxtfile_header_t* header = (dxtfile_header_t*)data;
  328. llassert(mHeaderSize > 0);
  329. memset(header, 0, mHeaderSize);
  330. header->fourcc = 0x20534444;
  331. header->pixel_fmt.fourcc = getFourCC(format);
  332. header->num_mips = nmips;
  333. header->maxwidth = width;
  334. header->maxheight = height;
  335. U8* prev_mipdata = 0;
  336. w = width, h = height;
  337. for (S32 mip=0; mip<nmips; mip++)
  338. {
  339. U8* mipdata = data + getMipOffset(mip);
  340. S32 bytes = formatBytes(format, w, h);
  341. if (mip==0)
  342. {
  343. memcpy(mipdata, raw_image->getData(), bytes); /* Flawfinder: ignore */
  344. }
  345. else if (explicit_mips)
  346. {
  347. extractMip(raw_image->getData(), mipdata, width, height, w, h, format);
  348. }
  349. else
  350. {
  351. generateMip(prev_mipdata, mipdata, w, h, ncomponents);
  352. }
  353. w >>= 1;
  354. h >>= 1;
  355. checkMinWidthHeight(format, w, h);
  356. prev_mipdata = mipdata;
  357. }
  358. return TRUE;
  359. }
  360. // virtual
  361. BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time)
  362. {
  363. return encodeDXT(raw_image, time, false);
  364. }
  365. // virtual
  366. bool LLImageDXT::convertToDXR()
  367. {
  368. EFileFormat newformat = FORMAT_UNKNOWN;
  369. switch (mFileFormat)
  370. {
  371. case FORMAT_DXR1:
  372. case FORMAT_DXR2:
  373. case FORMAT_DXR3:
  374. case FORMAT_DXR4:
  375. case FORMAT_DXR5:
  376. return false; // nothing to do
  377. case FORMAT_DXT1: newformat = FORMAT_DXR1; break;
  378. case FORMAT_DXT2: newformat = FORMAT_DXR2; break;
  379. case FORMAT_DXT3: newformat = FORMAT_DXR3; break;
  380. case FORMAT_DXT4: newformat = FORMAT_DXR4; break;
  381. case FORMAT_DXT5: newformat = FORMAT_DXR5; break;
  382. default:
  383. llwarns << "convertToDXR: can not convert format: " << llformat("0x%08x",getFourCC(mFileFormat)) << llendl;
  384. return false;
  385. }
  386. mFileFormat = newformat;
  387. S32 width = getWidth(), height = getHeight();
  388. S32 nmips = calcNumMips(width,height);
  389. S32 total_bytes = getDataSize();
  390. U8* olddata = getData();
  391. U8* newdata = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_bytes);
  392. if (!newdata)
  393. {
  394. llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl;
  395. return false;
  396. }
  397. llassert(total_bytes > 0);
  398. memset(newdata, 0, total_bytes);
  399. memcpy(newdata, olddata, mHeaderSize); /* Flawfinder: ignore */
  400. for (S32 mip=0; mip<nmips; mip++)
  401. {
  402. S32 bytes = formatBytes(mFileFormat, width, height);
  403. S32 newoffset = getMipOffset(mip);
  404. S32 oldoffset = mHeaderSize + (total_bytes - newoffset - bytes);
  405. memcpy(newdata + newoffset, olddata + oldoffset, bytes); /* Flawfinder: ignore */
  406. width >>= 1;
  407. height >>= 1;
  408. }
  409. dxtfile_header_t* header = (dxtfile_header_t*)newdata;
  410. header->pixel_fmt.fourcc = getFourCC(newformat);
  411. setData(newdata, total_bytes);
  412. updateData();
  413. return true;
  414. }
  415. // virtual
  416. S32 LLImageDXT::calcHeaderSize()
  417. {
  418. return llmax(sizeof(dxtfile_header_old_t), sizeof(dxtfile_header_t));
  419. }
  420. // virtual
  421. S32 LLImageDXT::calcDataSize(S32 discard_level)
  422. {
  423. if (mFileFormat == FORMAT_UNKNOWN)
  424. {
  425. llerrs << "calcDataSize called with unloaded LLImageDXT" << llendl;
  426. return 0;
  427. }
  428. if (discard_level < 0)
  429. {
  430. discard_level = mDiscardLevel;
  431. }
  432. S32 bytes = getMipOffset(discard_level); // size of header + previous mips
  433. S32 w = getWidth() >> discard_level;
  434. S32 h = getHeight() >> discard_level;
  435. bytes += formatBytes(mFileFormat,w,h);
  436. return bytes;
  437. }
  438. //============================================================================
  439. //static
  440. void LLImageDXT::extractMip(const U8 *indata, U8* mipdata, int width, int height,
  441. int mip_width, int mip_height, EFileFormat format)
  442. {
  443. int initial_offset = formatBytes(format, width, height);
  444. int line_width = formatBytes(format, width, 1);
  445. int mip_line_width = formatBytes(format, mip_width, 1);
  446. int line_offset = 0;
  447. for (int ww=width>>1; ww>mip_width; ww>>=1)
  448. {
  449. line_offset += formatBytes(format, ww, 1);
  450. }
  451. for (int h=0;h<mip_height;++h)
  452. {
  453. int start_offset = initial_offset + line_width * h + line_offset;
  454. memcpy(mipdata + mip_line_width*h, indata + start_offset, mip_line_width); /* Flawfinder: ignore */
  455. }
  456. }
  457. //============================================================================