Home | History | Annotate | Download | only in source
      1 /*****************************************************************************/
      2 // Copyright 2006-2012 Adobe Systems Incorporated
      3 // All Rights Reserved.
      4 //
      5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
      6 // accordance with the terms of the Adobe license agreement accompanying it.
      7 /*****************************************************************************/
      8 
      9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_utils.cpp#3 $ */
     10 /* $DateTime: 2012/08/12 15:38:38 $ */
     11 /* $Change: 842799 $ */
     12 /* $Author: tknoll $ */
     13 
     14 /*****************************************************************************/
     15 
     16 #include "dng_utils.h"
     17 
     18 #include "dng_area_task.h"
     19 #include "dng_assertions.h"
     20 #include "dng_bottlenecks.h"
     21 #include "dng_exceptions.h"
     22 #include "dng_host.h"
     23 #include "dng_image.h"
     24 #include "dng_flags.h"
     25 #include "dng_point.h"
     26 #include "dng_rect.h"
     27 #include "dng_safe_arithmetic.h"
     28 #include "dng_tag_types.h"
     29 #include "dng_tile_iterator.h"
     30 
     31 #if qMacOS
     32 #include <TargetConditionals.h>
     33 #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
     34 #include <MobileCoreServices/MobileCoreServices.h>
     35 #else
     36 #include <CoreServices/CoreServices.h>
     37 #endif  // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
     38 #endif  // qMacOS
     39 
     40 #if qiPhone || qMacOS
     41 // these provide timers
     42 #include <mach/mach.h>
     43 #include <mach/mach_time.h>
     44 #endif
     45 
     46 #if qWinOS
     47 #include <windows.h>
     48 #else
     49 #include <sys/time.h>
     50 #include <stdarg.h> // for va_start/va_end
     51 #endif
     52 
     53 /*****************************************************************************/
     54 
     55 #if qDNGDebug
     56 
     57 /*****************************************************************************/
     58 
     59 #if qMacOS
     60 	#define DNG_DEBUG_BREAK __asm__ volatile ("int3")
     61 #elif qWinOS
     62 	#if qDNG64Bit
     63 		// no inline assembly on Win 64-bit, so use DebugBreak
     64 		#define DNG_DEBUG_BREAK DebugBreak()
     65 	#else
     66 		#define DNG_DEBUG_BREAK __asm__ volatile ("int3")
     67 	#endif
     68 #elif qiPhone
     69 	// simulator is running on Intel
     70 	#if qiPhoneSimulator
     71 		#define DNG_DEBUG_BREAK __asm__ volatile ("int3")
     72 	#else
     73 		// The debugger doesn't restore program counter after this is called.
     74 		//   Caller must move program counter past line to continue.
     75 		// As of iOS5/xCode 4.2, recovery may not be possible.
     76 		#define DNG_DEBUG_BREAK __asm__ volatile ("bkpt 1")
     77 	#endif
     78 #elif qAndroid
     79 	#define DNG_DEBUG_BREAK __asm__ volatile ("bkpt 1")
     80 #elif qLinux
     81 	#define DNG_DEBUG_BREAK __asm__ volatile ("int3")
     82 #else
     83 	#define DNG_DEBUG_BREAK
     84 #endif
     85 
     86 /*****************************************************************************/
     87 
     88 bool gPrintAsserts   = true;
     89 bool gBreakOnAsserts = true;
     90 
     91 /*****************************************************************************/
     92 
     93 void dng_show_message (const char *s)
     94 	{
     95 
     96 	#if qDNGPrintMessages
     97 
     98 	// display the message
     99 	if (gPrintAsserts)
    100 		fprintf (stderr, "%s\n", s);
    101 
    102 	#elif qiPhone || qAndroid || qLinux
    103 
    104 	if (gPrintAsserts)
    105 		fprintf (stderr, "%s\n", s);
    106 
    107 	// iOS doesn't print a message to the console like DebugStr and MessageBox do, so we have to do both
    108 	// You'll have to advance the program counter manually past this statement
    109 	if (gBreakOnAsserts)
    110 		DNG_DEBUG_BREAK;
    111 
    112 	#elif qMacOS
    113 
    114 	if (gBreakOnAsserts)
    115 		{
    116 		// truncate the to 255 chars
    117 		char ss [256];
    118 
    119 		uint32 len = strlen (s);
    120 		if (len > 255)
    121 			len = 255;
    122 		strncpy (&(ss [1]), s, len );
    123 		ss [0] = (unsigned char) len;
    124 
    125 		DebugStr ((unsigned char *) ss);
    126 		}
    127 	 else if (gPrintAsserts)
    128 		{
    129 		fprintf (stderr, "%s\n", s);
    130 		}
    131 
    132 	#elif qWinOS
    133 
    134 	// display a dialog
    135 	// This is not thread safe.  Multiple message boxes can be launched.
    136 	// Should also be launched in its own thread so main msg queue isn't thrown off.
    137 	if (gBreakOnAsserts)
    138 		MessageBoxA (NULL, (LPSTR) s, NULL, MB_OK);
    139 	else if (gPrintAsserts)
    140 		fprintf (stderr, "%s\n", s);
    141 
    142 	#endif
    143 
    144 	}
    145 
    146 /*****************************************************************************/
    147 
    148 void dng_show_message_f (const char *fmt, ... )
    149 	{
    150 
    151 	char buffer [1024];
    152 
    153 	va_list ap;
    154 	va_start (ap, fmt);
    155 
    156 	vsnprintf (buffer, sizeof (buffer), fmt, ap);
    157 
    158 	va_end (ap);
    159 
    160 	dng_show_message (buffer);
    161 
    162 	}
    163 
    164 /*****************************************************************************/
    165 
    166 #endif
    167 
    168 /*****************************************************************************/
    169 
    170 uint32 ComputeBufferSize(uint32 pixelType, const dng_point &tileSize,
    171 						 uint32 numPlanes, PaddingType paddingType)
    172 
    173 {
    174 
    175 	// Convert tile size to uint32.
    176 	if (tileSize.h < 0 || tileSize.v < 0)
    177 		{
    178 		ThrowMemoryFull("Negative tile size");
    179 		}
    180 	const uint32 tileSizeH = static_cast<uint32>(tileSize.h);
    181 	const uint32 tileSizeV = static_cast<uint32>(tileSize.v);
    182 
    183 	const uint32 pixelSize = TagTypeSize(pixelType);
    184 
    185 	// Add padding to width if necessary.
    186 	uint32 paddedWidth = tileSizeH;
    187 	if (paddingType == pad16Bytes)
    188 		{
    189 		if (!RoundUpForPixelSize(paddedWidth, pixelSize, &paddedWidth))
    190 			{
    191 			  ThrowMemoryFull("Arithmetic overflow computing buffer size");
    192 			}
    193 		}
    194 
    195 	// Compute buffer size.
    196 	uint32 bufferSize;
    197 	if (!SafeUint32Mult(paddedWidth, tileSizeV, &bufferSize) ||
    198 		!SafeUint32Mult(bufferSize, pixelSize, &bufferSize) ||
    199 		!SafeUint32Mult(bufferSize, numPlanes, &bufferSize))
    200 		{
    201 		ThrowMemoryFull("Arithmetic overflow computing buffer size");
    202 		}
    203 
    204 	return bufferSize;
    205 }
    206 
    207 /*****************************************************************************/
    208 
    209 real64 TickTimeInSeconds ()
    210 	{
    211 
    212 	#if qWinOS
    213 
    214 	// One might think it prudent to cache the frequency here, however
    215 	// low-power CPU modes can, and do, change the value returned.
    216 	// Thus the frequencey needs to be retrieved each time.
    217 
    218 	// Note that the frequency changing can cause the return
    219 	// result to jump backwards, which is why the TickCountInSeconds
    220 	// (below) also exists.
    221 
    222 	// Just plug in laptop when doing timings to minimize this.
    223 	//  QPC/QPH is a slow call compared to rtdsc.
    224 
    225 	#if qImagecore
    226 
    227 	// You should be plugged-in when measuring.
    228 
    229 	static real64 freqMultiplier = 0.0;
    230 
    231 	if (freqMultiplier == 0.0)
    232 		{
    233 
    234 		LARGE_INTEGER freq;
    235 
    236 		QueryPerformanceFrequency (&freq);
    237 
    238 		freqMultiplier = 1.0 / (real64) freq.QuadPart;
    239 
    240 		}
    241 
    242 	#else
    243 
    244 	LARGE_INTEGER freq;
    245 
    246 	QueryPerformanceFrequency (&freq);
    247 
    248 	real64 freqMultiplier = 1.0 / (real64) freq.QuadPart;
    249 
    250 	#endif	// qImagecore
    251 
    252 	LARGE_INTEGER cycles;
    253 
    254 	QueryPerformanceCounter (&cycles);
    255 
    256 	return (real64) cycles.QuadPart * freqMultiplier;
    257 
    258 	#elif qiPhone || qMacOS
    259 
    260 	//  this is switching Mac to high performance timer
    261 	//  and this is also the timer for iPhone
    262 
    263 	// assume frequency is unchanging, requesting frequency every time call
    264 	//   is too slow.  multiple cores, different frequency ?
    265 
    266 	static real64 freqMultiplier = 0.0;
    267 	if (freqMultiplier == 0.0)
    268 		{
    269 		mach_timebase_info_data_t freq;
    270 		mach_timebase_info(&freq);
    271 
    272 		// converts from nanos to micros
    273 		//  numer = 125, denom = 3 * 1000
    274 		freqMultiplier = ((real64)freq.numer / (real64)freq.denom) * 1.0e-9;
    275 		}
    276 
    277 	return mach_absolute_time() * freqMultiplier;
    278 
    279 	#elif qAndroid || qLinux
    280 
    281 	//this is a fast timer to nanos
    282     struct timespec now;
    283 	clock_gettime(CLOCK_MONOTONIC, &now);
    284 	return now.tv_sec + (real64)now.tv_nsec * 1.0e-9;
    285 
    286 	#else
    287 
    288 	// Perhaps a better call exists. (e.g. avoid adjtime effects)
    289 
    290 	struct timeval tv;
    291 
    292 	gettimeofday (&tv, NULL);
    293 
    294 	return tv.tv_sec + (real64)tv.tv_usec * 1.0e-6;
    295 
    296 	#endif
    297 
    298 	}
    299 
    300 /*****************************************************************************/
    301 
    302 real64 TickCountInSeconds ()
    303 	{
    304 
    305 	return TickTimeInSeconds ();
    306 
    307 	}
    308 
    309 /*****************************************************************************/
    310 
    311 bool gDNGShowTimers = true;
    312 
    313 dng_timer::dng_timer (const char *message)
    314 
    315 	:	fMessage   (message             )
    316 	,	fStartTime (TickTimeInSeconds ())
    317 
    318 	{
    319 
    320 	}
    321 
    322 /*****************************************************************************/
    323 
    324 dng_timer::~dng_timer ()
    325 	{
    326 
    327 	if (!gDNGShowTimers)
    328 		return;
    329 
    330 	real64 totalTime = TickTimeInSeconds () - fStartTime;
    331 
    332 	fprintf (stderr, "%s: %0.3f sec\n", fMessage, totalTime);
    333 
    334 	}
    335 
    336 /*****************************************************************************/
    337 
    338 real64 MaxSquaredDistancePointToRect (const dng_point_real64 &point,
    339 									  const dng_rect_real64 &rect)
    340 	{
    341 
    342 	real64 distSqr = DistanceSquared (point,
    343 									  rect.TL ());
    344 
    345 	distSqr = Max_real64 (distSqr,
    346 						  DistanceSquared (point,
    347 										   rect.BL ()));
    348 
    349 	distSqr = Max_real64 (distSqr,
    350 						  DistanceSquared (point,
    351 										   rect.BR ()));
    352 
    353 	distSqr = Max_real64 (distSqr,
    354 						  DistanceSquared (point,
    355 										   rect.TR ()));
    356 
    357 	return distSqr;
    358 
    359 	}
    360 
    361 /*****************************************************************************/
    362 
    363 real64 MaxDistancePointToRect (const dng_point_real64 &point,
    364 							   const dng_rect_real64 &rect)
    365 	{
    366 
    367 	return sqrt (MaxSquaredDistancePointToRect (point,
    368 												rect));
    369 
    370 	}
    371 
    372 /*****************************************************************************/
    373 
    374 dng_dither::dng_dither ()
    375 
    376 	:	fNoiseBuffer ()
    377 
    378 	{
    379 
    380 	const uint32 kSeed = 1;
    381 
    382 	fNoiseBuffer.Allocate (kRNGSize2D * sizeof (uint16));
    383 
    384 	uint16 *buffer = fNoiseBuffer.Buffer_uint16 ();
    385 
    386 	uint32 seed = kSeed;
    387 
    388 	for (uint32 i = 0; i < kRNGSize2D; i++)
    389 		{
    390 
    391 		seed = DNG_Random (seed);
    392 
    393 		buffer [i] = (uint16) (seed);
    394 
    395 		}
    396 
    397 	}
    398 
    399 /******************************************************************************/
    400 
    401 const dng_dither & dng_dither::Get ()
    402 	{
    403 
    404 	static dng_dither dither;
    405 
    406 	return dither;
    407 
    408 	}
    409 
    410 /*****************************************************************************/
    411 
    412 void HistogramArea (dng_host & /* host */,
    413 					const dng_image &image,
    414 					const dng_rect &area,
    415 					uint32 *hist,
    416 					uint32 maxValue,
    417 					uint32 plane)
    418 	{
    419 
    420 	DNG_ASSERT (image.PixelType () == ttShort, "Unsupported pixel type");
    421 
    422 	DoZeroBytes (hist, (maxValue + 1) * (uint32) sizeof (uint32));
    423 
    424 	dng_rect tile;
    425 
    426 	dng_tile_iterator iter (image, area);
    427 
    428 	while (iter.GetOneTile (tile))
    429 		{
    430 
    431 		dng_const_tile_buffer buffer (image, tile);
    432 
    433 		const void *sPtr = buffer.ConstPixel (tile.t,
    434 											  tile.l,
    435 											  plane);
    436 
    437 		uint32 count0 = 1;
    438 		uint32 count1 = tile.H ();
    439 		uint32 count2 = tile.W ();
    440 
    441 		int32 step0 = 0;
    442 		int32 step1 = buffer.fRowStep;
    443 		int32 step2 = buffer.fColStep;
    444 
    445 		OptimizeOrder (sPtr,
    446 					   buffer.fPixelSize,
    447 					   count0,
    448 					   count1,
    449 					   count2,
    450 					   step0,
    451 					   step1,
    452 					   step2);
    453 
    454 		DNG_ASSERT (count0 == 1, "OptimizeOrder logic error");
    455 
    456 		const uint16 *s1 = (const uint16 *) sPtr;
    457 
    458 		for (uint32 row = 0; row < count1; row++)
    459 			{
    460 
    461 			if (maxValue == 0x0FFFF && step2 == 1)
    462 				{
    463 
    464 				for (uint32 col = 0; col < count2; col++)
    465 					{
    466 
    467 					uint32 x = s1 [col];
    468 
    469 					hist [x] ++;
    470 
    471 					}
    472 
    473 				}
    474 
    475 			else
    476 				{
    477 
    478 				const uint16 *s2 = s1;
    479 
    480 				for (uint32 col = 0; col < count2; col++)
    481 					{
    482 
    483 					uint32 x = s2 [0];
    484 
    485 					if (x <= maxValue)
    486 						{
    487 
    488 						hist [x] ++;
    489 
    490 						}
    491 
    492 					s2 += step2;
    493 
    494 					}
    495 
    496 				}
    497 
    498 			s1 += step1;
    499 
    500 			}
    501 
    502 		}
    503 
    504 	}
    505 
    506 /*****************************************************************************/
    507 
    508 class dng_limit_float_depth_task: public dng_area_task
    509 	{
    510 
    511 	private:
    512 
    513 		const dng_image &fSrcImage;
    514 
    515 		dng_image &fDstImage;
    516 
    517 		uint32 fBitDepth;
    518 
    519 		real32 fScale;
    520 
    521 	public:
    522 
    523 		dng_limit_float_depth_task (const dng_image &srcImage,
    524 									dng_image &dstImage,
    525 									uint32 bitDepth,
    526 									real32 scale);
    527 
    528 		virtual dng_rect RepeatingTile1 () const
    529 			{
    530 			return fSrcImage.RepeatingTile ();
    531 			}
    532 
    533 		virtual dng_rect RepeatingTile2 () const
    534 			{
    535 			return fDstImage.RepeatingTile ();
    536 			}
    537 
    538 		virtual void Process (uint32 threadIndex,
    539 							  const dng_rect &tile,
    540 							  dng_abort_sniffer *sniffer);
    541 
    542 	};
    543 
    544 /*****************************************************************************/
    545 
    546 dng_limit_float_depth_task::dng_limit_float_depth_task (const dng_image &srcImage,
    547 														dng_image &dstImage,
    548 														uint32 bitDepth,
    549 														real32 scale)
    550 
    551 	:	fSrcImage (srcImage)
    552 	,	fDstImage (dstImage)
    553 	,	fBitDepth (bitDepth)
    554 	,	fScale    (scale)
    555 
    556 	{
    557 
    558 	}
    559 
    560 /*****************************************************************************/
    561 
    562 void dng_limit_float_depth_task::Process (uint32 /* threadIndex */,
    563 										  const dng_rect &tile,
    564 										  dng_abort_sniffer * /* sniffer */)
    565 	{
    566 
    567 	dng_const_tile_buffer srcBuffer (fSrcImage, tile);
    568 	dng_dirty_tile_buffer dstBuffer (fDstImage, tile);
    569 
    570 	uint32 count0 = tile.H ();
    571 	uint32 count1 = tile.W ();
    572 	uint32 count2 = fDstImage.Planes ();
    573 
    574 	int32 sStep0 = srcBuffer.fRowStep;
    575 	int32 sStep1 = srcBuffer.fColStep;
    576 	int32 sStep2 = srcBuffer.fPlaneStep;
    577 
    578 	int32 dStep0 = dstBuffer.fRowStep;
    579 	int32 dStep1 = dstBuffer.fColStep;
    580 	int32 dStep2 = dstBuffer.fPlaneStep;
    581 
    582 	const void *sPtr = srcBuffer.ConstPixel (tile.t,
    583 											 tile.l,
    584 											 0);
    585 
    586 		  void *dPtr = dstBuffer.DirtyPixel (tile.t,
    587 											 tile.l,
    588 											 0);
    589 
    590 	OptimizeOrder (sPtr,
    591 			       dPtr,
    592 				   srcBuffer.fPixelSize,
    593 				   dstBuffer.fPixelSize,
    594 				   count0,
    595 				   count1,
    596 				   count2,
    597 				   sStep0,
    598 				   sStep1,
    599 				   sStep2,
    600 				   dStep0,
    601 				   dStep1,
    602 				   dStep2);
    603 
    604 	const real32 *sPtr0 = (const real32 *) sPtr;
    605 		  real32 *dPtr0 = (      real32 *) dPtr;
    606 
    607 	real32 scale = fScale;
    608 
    609 	bool limit16 = (fBitDepth == 16);
    610 	bool limit24 = (fBitDepth == 24);
    611 
    612 	for (uint32 index0 = 0; index0 < count0; index0++)
    613 		{
    614 
    615 		const real32 *sPtr1 = sPtr0;
    616 			  real32 *dPtr1 = dPtr0;
    617 
    618 		for (uint32 index1 = 0; index1 < count1; index1++)
    619 			{
    620 
    621 			// If the scale is a NOP, and the data is packed solid, we can just do memory
    622 			// copy.
    623 
    624 			if (scale == 1.0f && sStep2 == 1 && dStep2 == 1)
    625 				{
    626 
    627 				if (dPtr1 != sPtr1)			// srcImage != dstImage
    628 					{
    629 
    630 					memcpy (dPtr1, sPtr1, count2 * (uint32) sizeof (real32));
    631 
    632 					}
    633 
    634 				}
    635 
    636 			else
    637 				{
    638 
    639 				const real32 *sPtr2 = sPtr1;
    640 					  real32 *dPtr2 = dPtr1;
    641 
    642 				for (uint32 index2 = 0; index2 < count2; index2++)
    643 					{
    644 
    645 					real32 x = sPtr2 [0];
    646 
    647 					x *= scale;
    648 
    649 					dPtr2 [0] = x;
    650 
    651 					sPtr2 += sStep2;
    652 					dPtr2 += dStep2;
    653 
    654 					}
    655 
    656 				}
    657 
    658 			// The data is now in the destination buffer.
    659 
    660 			if (limit16)
    661 				{
    662 
    663 				uint32 *dPtr2 = (uint32 *) dPtr1;
    664 
    665 				for (uint32 index2 = 0; index2 < count2; index2++)
    666 					{
    667 
    668 					uint32 x = dPtr2 [0];
    669 
    670 					uint16 y = DNG_FloatToHalf (x);
    671 
    672 					x = DNG_HalfToFloat (y);
    673 
    674 					dPtr2 [0] = x;
    675 
    676 					dPtr2 += dStep2;
    677 
    678 					}
    679 
    680 				}
    681 
    682 			else if (limit24)
    683 				{
    684 
    685 				uint32 *dPtr2 = (uint32 *) dPtr1;
    686 
    687 				for (uint32 index2 = 0; index2 < count2; index2++)
    688 					{
    689 
    690 					uint32 x = dPtr2 [0];
    691 
    692 					uint8 temp [3];
    693 
    694 					DNG_FloatToFP24 (x, temp);
    695 
    696 					x = DNG_FP24ToFloat (temp);
    697 
    698 					dPtr2 [0] = x;
    699 
    700 					dPtr2 += dStep2;
    701 
    702 					}
    703 
    704 				}
    705 
    706 			sPtr1 += sStep1;
    707 			dPtr1 += dStep1;
    708 
    709 			}
    710 
    711 		sPtr0 += sStep0;
    712 		dPtr0 += dStep0;
    713 
    714 		}
    715 
    716 	}
    717 
    718 /******************************************************************************/
    719 
    720 void LimitFloatBitDepth (dng_host &host,
    721 						 const dng_image &srcImage,
    722 						 dng_image &dstImage,
    723 						 uint32 bitDepth,
    724 						 real32 scale)
    725 	{
    726 
    727 	DNG_ASSERT (srcImage.PixelType () == ttFloat, "Floating point image expected");
    728 	DNG_ASSERT (dstImage.PixelType () == ttFloat, "Floating point image expected");
    729 
    730 	dng_limit_float_depth_task task (srcImage,
    731 									 dstImage,
    732 									 bitDepth,
    733 									 scale);
    734 
    735 	host.PerformAreaTask (task, dstImage.Bounds ());
    736 
    737 	}
    738 
    739 /*****************************************************************************/
    740