PageRenderTime 106ms CodeModel.GetById 20ms app.highlight 63ms RepoModel.GetById 18ms app.codeStats 0ms

/indra/llimage/llimagedxt.cpp

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