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