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 	#if qWinOS
    306 
    307 	return GetTickCount () * (1.0 / 1000.0);
    308 
    309 	#elif qMacOS
    310 
    311 	#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
    312 	// TODO: Needs implementation.
    313 	ThrowProgramError ("TickCountInSeconds() not implemented on iOS");
    314 	return 0;
    315 	#else
    316 	return TickCount () * (1.0 / 60.0);
    317 	#endif  // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
    318 
    319 	#else
    320 
    321 	return TickTimeInSeconds ();
    322 
    323 	#endif
    324 
    325 	}
    326 
    327 /*****************************************************************************/
    328 
    329 bool gDNGShowTimers = true;
    330 
    331 dng_timer::dng_timer (const char *message)
    332 
    333 	:	fMessage   (message             )
    334 	,	fStartTime (TickTimeInSeconds ())
    335 
    336 	{
    337 
    338 	}
    339 
    340 /*****************************************************************************/
    341 
    342 dng_timer::~dng_timer ()
    343 	{
    344 
    345 	if (!gDNGShowTimers)
    346 		return;
    347 
    348 	real64 totalTime = TickTimeInSeconds () - fStartTime;
    349 
    350 	fprintf (stderr, "%s: %0.3f sec\n", fMessage, totalTime);
    351 
    352 	}
    353 
    354 /*****************************************************************************/
    355 
    356 real64 MaxSquaredDistancePointToRect (const dng_point_real64 &point,
    357 									  const dng_rect_real64 &rect)
    358 	{
    359 
    360 	real64 distSqr = DistanceSquared (point,
    361 									  rect.TL ());
    362 
    363 	distSqr = Max_real64 (distSqr,
    364 						  DistanceSquared (point,
    365 										   rect.BL ()));
    366 
    367 	distSqr = Max_real64 (distSqr,
    368 						  DistanceSquared (point,
    369 										   rect.BR ()));
    370 
    371 	distSqr = Max_real64 (distSqr,
    372 						  DistanceSquared (point,
    373 										   rect.TR ()));
    374 
    375 	return distSqr;
    376 
    377 	}
    378 
    379 /*****************************************************************************/
    380 
    381 real64 MaxDistancePointToRect (const dng_point_real64 &point,
    382 							   const dng_rect_real64 &rect)
    383 	{
    384 
    385 	return sqrt (MaxSquaredDistancePointToRect (point,
    386 												rect));
    387 
    388 	}
    389 
    390 /*****************************************************************************/
    391 
    392 dng_dither::dng_dither ()
    393 
    394 	:	fNoiseBuffer ()
    395 
    396 	{
    397 
    398 	const uint32 kSeed = 1;
    399 
    400 	fNoiseBuffer.Allocate (kRNGSize2D * sizeof (uint16));
    401 
    402 	uint16 *buffer = fNoiseBuffer.Buffer_uint16 ();
    403 
    404 	uint32 seed = kSeed;
    405 
    406 	for (uint32 i = 0; i < kRNGSize2D; i++)
    407 		{
    408 
    409 		seed = DNG_Random (seed);
    410 
    411 		buffer [i] = (uint16) (seed);
    412 
    413 		}
    414 
    415 	}
    416 
    417 /******************************************************************************/
    418 
    419 const dng_dither & dng_dither::Get ()
    420 	{
    421 
    422 	static dng_dither dither;
    423 
    424 	return dither;
    425 
    426 	}
    427 
    428 /*****************************************************************************/
    429 
    430 void HistogramArea (dng_host & /* host */,
    431 					const dng_image &image,
    432 					const dng_rect &area,
    433 					uint32 *hist,
    434 					uint32 maxValue,
    435 					uint32 plane)
    436 	{
    437 
    438 	DNG_ASSERT (image.PixelType () == ttShort, "Unsupported pixel type");
    439 
    440 	DoZeroBytes (hist, (maxValue + 1) * (uint32) sizeof (uint32));
    441 
    442 	dng_rect tile;
    443 
    444 	dng_tile_iterator iter (image, area);
    445 
    446 	while (iter.GetOneTile (tile))
    447 		{
    448 
    449 		dng_const_tile_buffer buffer (image, tile);
    450 
    451 		const void *sPtr = buffer.ConstPixel (tile.t,
    452 											  tile.l,
    453 											  plane);
    454 
    455 		uint32 count0 = 1;
    456 		uint32 count1 = tile.H ();
    457 		uint32 count2 = tile.W ();
    458 
    459 		int32 step0 = 0;
    460 		int32 step1 = buffer.fRowStep;
    461 		int32 step2 = buffer.fColStep;
    462 
    463 		OptimizeOrder (sPtr,
    464 					   buffer.fPixelSize,
    465 					   count0,
    466 					   count1,
    467 					   count2,
    468 					   step0,
    469 					   step1,
    470 					   step2);
    471 
    472 		DNG_ASSERT (count0 == 1, "OptimizeOrder logic error");
    473 
    474 		const uint16 *s1 = (const uint16 *) sPtr;
    475 
    476 		for (uint32 row = 0; row < count1; row++)
    477 			{
    478 
    479 			if (maxValue == 0x0FFFF && step2 == 1)
    480 				{
    481 
    482 				for (uint32 col = 0; col < count2; col++)
    483 					{
    484 
    485 					uint32 x = s1 [col];
    486 
    487 					hist [x] ++;
    488 
    489 					}
    490 
    491 				}
    492 
    493 			else
    494 				{
    495 
    496 				const uint16 *s2 = s1;
    497 
    498 				for (uint32 col = 0; col < count2; col++)
    499 					{
    500 
    501 					uint32 x = s2 [0];
    502 
    503 					if (x <= maxValue)
    504 						{
    505 
    506 						hist [x] ++;
    507 
    508 						}
    509 
    510 					s2 += step2;
    511 
    512 					}
    513 
    514 				}
    515 
    516 			s1 += step1;
    517 
    518 			}
    519 
    520 		}
    521 
    522 	}
    523 
    524 /*****************************************************************************/
    525 
    526 class dng_limit_float_depth_task: public dng_area_task
    527 	{
    528 
    529 	private:
    530 
    531 		const dng_image &fSrcImage;
    532 
    533 		dng_image &fDstImage;
    534 
    535 		uint32 fBitDepth;
    536 
    537 		real32 fScale;
    538 
    539 	public:
    540 
    541 		dng_limit_float_depth_task (const dng_image &srcImage,
    542 									dng_image &dstImage,
    543 									uint32 bitDepth,
    544 									real32 scale);
    545 
    546 		virtual dng_rect RepeatingTile1 () const
    547 			{
    548 			return fSrcImage.RepeatingTile ();
    549 			}
    550 
    551 		virtual dng_rect RepeatingTile2 () const
    552 			{
    553 			return fDstImage.RepeatingTile ();
    554 			}
    555 
    556 		virtual void Process (uint32 threadIndex,
    557 							  const dng_rect &tile,
    558 							  dng_abort_sniffer *sniffer);
    559 
    560 	};
    561 
    562 /*****************************************************************************/
    563 
    564 dng_limit_float_depth_task::dng_limit_float_depth_task (const dng_image &srcImage,
    565 														dng_image &dstImage,
    566 														uint32 bitDepth,
    567 														real32 scale)
    568 
    569 	:	fSrcImage (srcImage)
    570 	,	fDstImage (dstImage)
    571 	,	fBitDepth (bitDepth)
    572 	,	fScale    (scale)
    573 
    574 	{
    575 
    576 	}
    577 
    578 /*****************************************************************************/
    579 
    580 void dng_limit_float_depth_task::Process (uint32 /* threadIndex */,
    581 										  const dng_rect &tile,
    582 										  dng_abort_sniffer * /* sniffer */)
    583 	{
    584 
    585 	dng_const_tile_buffer srcBuffer (fSrcImage, tile);
    586 	dng_dirty_tile_buffer dstBuffer (fDstImage, tile);
    587 
    588 	uint32 count0 = tile.H ();
    589 	uint32 count1 = tile.W ();
    590 	uint32 count2 = fDstImage.Planes ();
    591 
    592 	int32 sStep0 = srcBuffer.fRowStep;
    593 	int32 sStep1 = srcBuffer.fColStep;
    594 	int32 sStep2 = srcBuffer.fPlaneStep;
    595 
    596 	int32 dStep0 = dstBuffer.fRowStep;
    597 	int32 dStep1 = dstBuffer.fColStep;
    598 	int32 dStep2 = dstBuffer.fPlaneStep;
    599 
    600 	const void *sPtr = srcBuffer.ConstPixel (tile.t,
    601 											 tile.l,
    602 											 0);
    603 
    604 		  void *dPtr = dstBuffer.DirtyPixel (tile.t,
    605 											 tile.l,
    606 											 0);
    607 
    608 	OptimizeOrder (sPtr,
    609 			       dPtr,
    610 				   srcBuffer.fPixelSize,
    611 				   dstBuffer.fPixelSize,
    612 				   count0,
    613 				   count1,
    614 				   count2,
    615 				   sStep0,
    616 				   sStep1,
    617 				   sStep2,
    618 				   dStep0,
    619 				   dStep1,
    620 				   dStep2);
    621 
    622 	const real32 *sPtr0 = (const real32 *) sPtr;
    623 		  real32 *dPtr0 = (      real32 *) dPtr;
    624 
    625 	real32 scale = fScale;
    626 
    627 	bool limit16 = (fBitDepth == 16);
    628 	bool limit24 = (fBitDepth == 24);
    629 
    630 	for (uint32 index0 = 0; index0 < count0; index0++)
    631 		{
    632 
    633 		const real32 *sPtr1 = sPtr0;
    634 			  real32 *dPtr1 = dPtr0;
    635 
    636 		for (uint32 index1 = 0; index1 < count1; index1++)
    637 			{
    638 
    639 			// If the scale is a NOP, and the data is packed solid, we can just do memory
    640 			// copy.
    641 
    642 			if (scale == 1.0f && sStep2 == 1 && dStep2 == 1)
    643 				{
    644 
    645 				if (dPtr1 != sPtr1)			// srcImage != dstImage
    646 					{
    647 
    648 					memcpy (dPtr1, sPtr1, count2 * (uint32) sizeof (real32));
    649 
    650 					}
    651 
    652 				}
    653 
    654 			else
    655 				{
    656 
    657 				const real32 *sPtr2 = sPtr1;
    658 					  real32 *dPtr2 = dPtr1;
    659 
    660 				for (uint32 index2 = 0; index2 < count2; index2++)
    661 					{
    662 
    663 					real32 x = sPtr2 [0];
    664 
    665 					x *= scale;
    666 
    667 					dPtr2 [0] = x;
    668 
    669 					sPtr2 += sStep2;
    670 					dPtr2 += dStep2;
    671 
    672 					}
    673 
    674 				}
    675 
    676 			// The data is now in the destination buffer.
    677 
    678 			if (limit16)
    679 				{
    680 
    681 				uint32 *dPtr2 = (uint32 *) dPtr1;
    682 
    683 				for (uint32 index2 = 0; index2 < count2; index2++)
    684 					{
    685 
    686 					uint32 x = dPtr2 [0];
    687 
    688 					uint16 y = DNG_FloatToHalf (x);
    689 
    690 					x = DNG_HalfToFloat (y);
    691 
    692 					dPtr2 [0] = x;
    693 
    694 					dPtr2 += dStep2;
    695 
    696 					}
    697 
    698 				}
    699 
    700 			else if (limit24)
    701 				{
    702 
    703 				uint32 *dPtr2 = (uint32 *) dPtr1;
    704 
    705 				for (uint32 index2 = 0; index2 < count2; index2++)
    706 					{
    707 
    708 					uint32 x = dPtr2 [0];
    709 
    710 					uint8 temp [3];
    711 
    712 					DNG_FloatToFP24 (x, temp);
    713 
    714 					x = DNG_FP24ToFloat (temp);
    715 
    716 					dPtr2 [0] = x;
    717 
    718 					dPtr2 += dStep2;
    719 
    720 					}
    721 
    722 				}
    723 
    724 			sPtr1 += sStep1;
    725 			dPtr1 += dStep1;
    726 
    727 			}
    728 
    729 		sPtr0 += sStep0;
    730 		dPtr0 += dStep0;
    731 
    732 		}
    733 
    734 	}
    735 
    736 /******************************************************************************/
    737 
    738 void LimitFloatBitDepth (dng_host &host,
    739 						 const dng_image &srcImage,
    740 						 dng_image &dstImage,
    741 						 uint32 bitDepth,
    742 						 real32 scale)
    743 	{
    744 
    745 	DNG_ASSERT (srcImage.PixelType () == ttFloat, "Floating point image expected");
    746 	DNG_ASSERT (dstImage.PixelType () == ttFloat, "Floating point image expected");
    747 
    748 	dng_limit_float_depth_task task (srcImage,
    749 									 dstImage,
    750 									 bitDepth,
    751 									 scale);
    752 
    753 	host.PerformAreaTask (task, dstImage.Bounds ());
    754 
    755 	}
    756 
    757 /*****************************************************************************/
    758