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 
dng_show_message(const char * s)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 
dng_show_message_f(const char * fmt,...)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 
ComputeBufferSize(uint32 pixelType,const dng_point & tileSize,uint32 numPlanes,PaddingType paddingType)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 
TickTimeInSeconds()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 
TickCountInSeconds()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 
dng_timer(const char * message)331 dng_timer::dng_timer (const char *message)
332 
333 	:	fMessage   (message             )
334 	,	fStartTime (TickTimeInSeconds ())
335 
336 	{
337 
338 	}
339 
340 /*****************************************************************************/
341 
~dng_timer()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 
MaxSquaredDistancePointToRect(const dng_point_real64 & point,const dng_rect_real64 & rect)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 
MaxDistancePointToRect(const dng_point_real64 & point,const dng_rect_real64 & rect)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 
dng_dither()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 
Get()419 const dng_dither & dng_dither::Get ()
420 	{
421 
422 	static dng_dither dither;
423 
424 	return dither;
425 
426 	}
427 
428 /*****************************************************************************/
429 
HistogramArea(dng_host &,const dng_image & image,const dng_rect & area,uint32 * hist,uint32 maxValue,uint32 plane)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 
RepeatingTile1() const546 		virtual dng_rect RepeatingTile1 () const
547 			{
548 			return fSrcImage.RepeatingTile ();
549 			}
550 
RepeatingTile2() const551 		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 
dng_limit_float_depth_task(const dng_image & srcImage,dng_image & dstImage,uint32 bitDepth,real32 scale)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 
Process(uint32,const dng_rect & tile,dng_abort_sniffer *)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 
LimitFloatBitDepth(dng_host & host,const dng_image & srcImage,dng_image & dstImage,uint32 bitDepth,real32 scale)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