• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	return TickTimeInSeconds ();
306 
307 	}
308 
309 /*****************************************************************************/
310 
311 bool gDNGShowTimers = true;
312 
dng_timer(const char * message)313 dng_timer::dng_timer (const char *message)
314 
315 	:	fMessage   (message             )
316 	,	fStartTime (TickTimeInSeconds ())
317 
318 	{
319 
320 	}
321 
322 /*****************************************************************************/
323 
~dng_timer()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 
MaxSquaredDistancePointToRect(const dng_point_real64 & point,const dng_rect_real64 & rect)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 
MaxDistancePointToRect(const dng_point_real64 & point,const dng_rect_real64 & rect)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 
dng_dither()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 
Get()401 const dng_dither & dng_dither::Get ()
402 	{
403 
404 	static dng_dither dither;
405 
406 	return dither;
407 
408 	}
409 
410 /*****************************************************************************/
411 
HistogramArea(dng_host &,const dng_image & image,const dng_rect & area,uint32 * hist,uint32 maxValue,uint32 plane)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 
RepeatingTile1() const528 		virtual dng_rect RepeatingTile1 () const
529 			{
530 			return fSrcImage.RepeatingTile ();
531 			}
532 
RepeatingTile2() const533 		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 
dng_limit_float_depth_task(const dng_image & srcImage,dng_image & dstImage,uint32 bitDepth,real32 scale)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 
Process(uint32,const dng_rect & tile,dng_abort_sniffer *)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 
LimitFloatBitDepth(dng_host & host,const dng_image & srcImage,dng_image & dstImage,uint32 bitDepth,real32 scale)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