File indexing completed on 2025-01-19 03:55:18

0001 /*****************************************************************************/
0002 // Copyright 2006-2019 Adobe Systems Incorporated
0003 // All Rights Reserved.
0004 //
0005 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
0006 // accordance with the terms of the Adobe license agreement accompanying it.
0007 /*****************************************************************************/
0008 
0009 #include "dng_utils.h"
0010 
0011 #include "dng_area_task.h"
0012 #include "dng_assertions.h"
0013 #include "dng_bottlenecks.h"
0014 #include "dng_flags.h"
0015 #include "dng_globals.h"
0016 #include "dng_host.h"
0017 #include "dng_image.h"
0018 #include "dng_mutex.h"
0019 #include "dng_point.h"
0020 #include "dng_rect.h"
0021 #include "dng_simd_type.h"
0022 #include "dng_tile_iterator.h"
0023 
0024 #if qMacOS
0025 #include <CoreServices/CoreServices.h>
0026 #endif
0027 
0028 #if qiPhone || qMacOS
0029 // these provide timers
0030 #include <mach/mach.h>
0031 #include <mach/mach_time.h>
0032 #endif
0033 
0034 #if qiPhone || qLinux
0035 #include <signal.h> // for raise
0036 #endif
0037 
0038 #if qWinOS
0039 #include <windows.h>
0040 #else
0041 #include <sys/time.h>
0042 #include <stdarg.h> // for va_start/va_end
0043 #endif
0044 
0045 #include <atomic>
0046 
0047 /*****************************************************************************/
0048 
0049 #if qDNGDebug
0050 
0051 /*****************************************************************************/
0052 
0053 #if qMacOS
0054     #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
0055 #elif qiPhone
0056     #if qiPhoneSimulator
0057         // simulator is running on Intel
0058         #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
0059     #else
0060         // You'll be one level deeper in __kill. Works on Linux, Android too.
0061         #define DNG_DEBUG_BREAK raise(SIGTRAP)
0062     #endif
0063 #elif qWinOS
0064     // DebugBreak has to be emulated on WinRT
0065     #define DNG_DEBUG_BREAK DebugBreak()
0066 #elif qAndroid
0067     #define DNG_DEBUG_BREAK raise(SIGTRAP)
0068 #elif qLinux
0069     #define DNG_DEBUG_BREAK raise(SIGTRAP)
0070 #else
0071     #define DNG_DEBUG_BREAK
0072 #endif
0073 
0074 /*****************************************************************************/
0075 
0076 void dng_show_message (const char *s)
0077     {
0078     // only append a newline if there isn't already one
0079     const char* nl = "\n";
0080     if (s[0] && (s[strlen(s)-1] == '\n'))
0081         nl = "";
0082 
0083     #if qDNGPrintMessages
0084 
0085     // display the message
0086     if (gPrintAsserts)
0087         fprintf (stderr, "%s%s", s, nl);
0088 
0089     #elif qiPhone || qAndroid || qLinux
0090 
0091     if (gPrintAsserts)
0092         fprintf (stderr, "%s%s", s, nl);
0093 
0094     // iOS doesn't print a message to the console like DebugStr and MessageBox do, so we have to do both
0095     // You'll have to advance the program counter manually past this statement
0096     if (gBreakOnAsserts)
0097         DNG_DEBUG_BREAK;
0098 
0099     #elif qMacOS
0100 
0101     if (gBreakOnAsserts)
0102         {
0103         // truncate the to 255 chars
0104         char ss [256];
0105 
0106         uint32 len = (uint32) strlen (s);
0107         if (len > 255)
0108             len = 255;
0109         strncpy (&(ss [1]), s, len );
0110         ss [0] = (unsigned char) len;
0111 
0112         DebugStr ((unsigned char *) ss);
0113         }
0114      else if (gPrintAsserts)
0115         {
0116         fprintf (stderr, "%s%s", s, nl);
0117         }
0118 
0119     #elif qWinOS
0120 
0121     // display a dialog
0122     // This is not thread safe.  Multiple message boxes can be launched.
0123     // Should also be launched in its own thread so main msg queue isn't thrown off.
0124     if (gBreakOnAsserts)
0125         MessageBoxA (NULL, (LPSTR) s, NULL, MB_OK);
0126     else if (gPrintAsserts)
0127         fprintf (stderr, "%s%s", s, nl);
0128 
0129     #endif
0130 
0131     }
0132 
0133 /*****************************************************************************/
0134 
0135 void dng_show_message_f (const char *fmt, ... )
0136     {
0137 
0138     char buffer [2048];
0139 
0140     va_list ap;
0141     va_start (ap, fmt);
0142 
0143     vsnprintf (buffer, sizeof (buffer), fmt, ap);
0144 
0145     va_end (ap);
0146 
0147     dng_show_message (buffer);
0148 
0149     }
0150 
0151 /*****************************************************************************/
0152 
0153 #endif
0154 
0155 /*****************************************************************************/
0156 
0157 uint32 ComputeBufferSize (uint32 pixelType,
0158                           const dng_point &tileSize,
0159                           uint32 numPlanes,
0160                           PaddingType paddingType)
0161     {
0162 
0163     // Convert tile size to uint32.
0164 
0165     if (tileSize.h < 0 || tileSize.v < 0)
0166         {
0167         ThrowMemoryFull ("Negative tile size");
0168         }
0169 
0170     const uint32 tileSizeH = static_cast<uint32> (tileSize.h);
0171     const uint32 tileSizeV = static_cast<uint32> (tileSize.v);
0172 
0173     const uint32 pixelSize = TagTypeSize (pixelType);
0174 
0175     // Add padding to width if necessary.
0176 
0177     uint32 paddedWidth = tileSizeH;
0178 
0179     if (paddingType == padSIMDBytes)
0180         {
0181 
0182         if (!RoundUpForPixelSize (paddedWidth,
0183                                   pixelSize,
0184                                   &paddedWidth))
0185             {
0186             ThrowOverflow ("Arithmetic overflow computing buffer size");
0187             }
0188 
0189         }
0190 
0191     // Compute buffer size.
0192 
0193     uint32 bufferSize;
0194 
0195     if (!SafeUint32Mult (paddedWidth, tileSizeV, &bufferSize) ||
0196         !SafeUint32Mult (bufferSize,  pixelSize, &bufferSize) ||
0197         !SafeUint32Mult (bufferSize,  numPlanes, &bufferSize))
0198         {
0199         ThrowOverflow ("Arithmetic overflow computing buffer size");
0200         }
0201 
0202     return bufferSize;
0203 
0204     }
0205 
0206 /*****************************************************************************/
0207 
0208 real64 TickTimeInSeconds ()
0209     {
0210 
0211     #if qWinOS
0212 
0213     // One might think it prudent to cache the frequency here, however
0214     // low-power CPU modes can, and do, change the value returned.
0215     // Thus the frequencey needs to be retrieved each time.
0216 
0217     // Note that the frequency changing can cause the return
0218     // result to jump backwards, which is why the TickCountInSeconds
0219     // (below) also exists.
0220 
0221     // Just plug in laptop when doing timings to minimize this.
0222     //  QPC/QPH is a slow call compared to rtdsc.
0223     //  but QPC/QPF is not tied to speed step, it's the northbridge timer.
0224     //  caching the invFrequency also avoids a costly divide
0225 
0226     static real64 freqMultiplier = 0.0;
0227 
0228     if (freqMultiplier == 0.0)
0229         {
0230 
0231         LARGE_INTEGER freq;
0232 
0233         QueryPerformanceFrequency (&freq);
0234 
0235         freqMultiplier = 1.0 / (real64) freq.QuadPart;
0236 
0237         }
0238 
0239     LARGE_INTEGER cycles;
0240 
0241     QueryPerformanceCounter (&cycles);
0242 
0243     return (real64) cycles.QuadPart * freqMultiplier;
0244 
0245     #elif qiPhone || qMacOS
0246 
0247     // cache frequency of high-perf timer
0248     static real64 freqMultiplier = 0.0;
0249     if (freqMultiplier == 0.0)
0250         {
0251 
0252         mach_timebase_info_data_t freq;
0253         mach_timebase_info(&freq);
0254 
0255         // converts from nanos to micros
0256         //  numer = 125, denom = 3 * 1000
0257         freqMultiplier = ((real64)freq.numer / (real64)freq.denom) * 1.0e-9;
0258 
0259         }
0260 
0261     return mach_absolute_time() * freqMultiplier;
0262 
0263     #elif qAndroid || qLinux
0264 
0265     //this is a fast timer to nanos
0266     struct timespec now;
0267     clock_gettime(CLOCK_MONOTONIC, &now);
0268     return now.tv_sec + (real64)now.tv_nsec * 1.0e-9;
0269 
0270     #else
0271 
0272     // Perhaps a better call exists. (e.g. avoid adjtime effects)
0273 
0274     struct timeval tv;
0275 
0276     gettimeofday (&tv, NULL);
0277 
0278     return tv.tv_sec + (real64)tv.tv_usec * 1.0e-6;
0279 
0280     #endif
0281 
0282     }
0283 
0284 /*****************************************************************************/
0285 
0286 real64 TickCountInSeconds ()
0287     {
0288 
0289     return TickTimeInSeconds ();
0290 
0291     }
0292 
0293 /*****************************************************************************/
0294 
0295 static std::atomic_int sTimerLevel (0);
0296 
0297 /*****************************************************************************/
0298 
0299 void DNGIncrementTimerLevel ()
0300     {
0301 
0302     // This isn't thread coherent, multiple threads can create/destroy cr_timer
0303     //   causing the tabbing to be invalid.  Imagecore disables this.
0304 
0305     if (!gImagecore)
0306         {
0307 
0308         sTimerLevel++;
0309 
0310         }
0311 
0312     }
0313 
0314 /*****************************************************************************/
0315 
0316 int32 DNGDecrementTimerLevel ()
0317     {
0318 
0319     if (gImagecore)
0320         {
0321 
0322         return 0;
0323 
0324         }
0325 
0326     else
0327         {
0328 
0329         return (int32) (--sTimerLevel);
0330 
0331         }
0332 
0333    }
0334 
0335 /*****************************************************************************/
0336 
0337 dng_timer::dng_timer (const char *message)
0338 
0339     :   fMessage   (message             )
0340     ,   fStartTime (TickTimeInSeconds ())
0341 
0342     {
0343 
0344     DNGIncrementTimerLevel ();
0345 
0346     }
0347 
0348 /*****************************************************************************/
0349 
0350 dng_timer::~dng_timer ()
0351     {
0352 
0353     uint32 level = Pin_int32 (0, DNGDecrementTimerLevel (), 10);
0354 
0355     if (!gDNGShowTimers)
0356         return;
0357 
0358     real64 totalTime = TickTimeInSeconds () - fStartTime;
0359 
0360     #if defined(qCRLogging) && qCRLogging && defined(cr_logi)
0361 
0362     if (gImagecore)
0363         {
0364         // Imagecore force includes cr_log and overrides DNG to go to its logging under a mutex.
0365         // don't use indenting or fprintf to stderr, want these buffered
0366         cr_logi("timer", "%s: %0.3f sec\n", fMessage, totalTime);
0367         return;
0368         }
0369 
0370     #endif
0371 
0372     fprintf (stderr, "%*s%s: %0.3f sec\n", level*2, "", fMessage, totalTime);
0373 
0374     }
0375 
0376 /*****************************************************************************/
0377 
0378 real64 MaxSquaredDistancePointToRect (const dng_point_real64 &point,
0379                                       const dng_rect_real64 &rect)
0380     {
0381 
0382     real64 distSqr = DistanceSquared (point,
0383                                       rect.TL ());
0384 
0385     distSqr = Max_real64 (distSqr,
0386                           DistanceSquared (point,
0387                                            rect.BL ()));
0388 
0389     distSqr = Max_real64 (distSqr,
0390                           DistanceSquared (point,
0391                                            rect.BR ()));
0392 
0393     distSqr = Max_real64 (distSqr,
0394                           DistanceSquared (point,
0395                                            rect.TR ()));
0396 
0397     return distSqr;
0398 
0399     }
0400 
0401 /*****************************************************************************/
0402 
0403 real64 MaxDistancePointToRect (const dng_point_real64 &point,
0404                                const dng_rect_real64 &rect)
0405     {
0406 
0407     return sqrt (MaxSquaredDistancePointToRect (point,
0408                                                 rect));
0409 
0410     }
0411 
0412 /*****************************************************************************/
0413 
0414 dng_dither::dng_dither ()
0415 
0416     :   fNoiseBuffer ()
0417 
0418     {
0419 
0420     const uint32 kSeed = 1;
0421 
0422     fNoiseBuffer.Allocate (kRNGSize2D * sizeof (uint16));
0423 
0424     uint16 *buffer = fNoiseBuffer.Buffer_uint16 ();
0425 
0426     uint32 seed = kSeed;
0427 
0428     for (uint32 i = 0; i < kRNGSize2D; i++)
0429         {
0430 
0431         // The correct math for 16 to 8-bit dither would be:
0432         //
0433         // y = (x * 255 + r) / 65535;  (0 <= r <= 65534)
0434         //
0435         // The bottlnecks are using a faster approximation of
0436         // this math (using a power of two for the division):
0437         //
0438         // y = (x * 255 + r) / 65536;  (255 <= r <= 65535)
0439         //
0440         // To insure that all exact 8 bit values in 16 bit space
0441         // round trip exactly to the same 8-bit, we need to limit
0442         // r values to the range 255 to 65535.
0443         //
0444         // This results in the dither effect being slightly
0445         // imperfect, but correct round-tripping of 8-bit values
0446         // is far more important.
0447 
0448         uint16 value;
0449 
0450         do
0451             {
0452 
0453             seed = DNG_Random (seed);
0454 
0455             value = (uint16) seed;
0456 
0457             }
0458         while (value < 255);
0459 
0460         buffer [i] = value;
0461 
0462         }
0463 
0464     }
0465 
0466 /******************************************************************************/
0467 
0468 const dng_dither & dng_dither::Get ()
0469     {
0470 
0471     static dng_dither dither;
0472 
0473     return dither;
0474 
0475     }
0476 
0477 /*****************************************************************************/
0478 
0479 void HistogramArea (dng_host & /* host */,
0480                     const dng_image &image,
0481                     const dng_rect &area,
0482                     uint32 *hist,
0483                     uint32 maxValue,
0484                     uint32 plane)
0485     {
0486 
0487     DNG_ASSERT (image.PixelType () == ttShort, "Unsupported pixel type");
0488 
0489     DoZeroBytes (hist, (maxValue + 1) * (uint32) sizeof (uint32));
0490 
0491     dng_rect tile;
0492 
0493     dng_tile_iterator iter (image, area);
0494 
0495     while (iter.GetOneTile (tile))
0496         {
0497 
0498         dng_const_tile_buffer buffer (image, tile);
0499 
0500         const void *sPtr = buffer.ConstPixel (tile.t,
0501                                               tile.l,
0502                                               plane);
0503 
0504         uint32 count0 = 1;
0505         uint32 count1 = tile.H ();
0506         uint32 count2 = tile.W ();
0507 
0508         int32 step0 = 0;
0509         int32 step1 = buffer.fRowStep;
0510         int32 step2 = buffer.fColStep;
0511 
0512         OptimizeOrder (sPtr,
0513                        buffer.fPixelSize,
0514                        count0,
0515                        count1,
0516                        count2,
0517                        step0,
0518                        step1,
0519                        step2);
0520 
0521         DNG_ASSERT (count0 == 1, "OptimizeOrder logic error");
0522 
0523         const uint16 *s1 = (const uint16 *) sPtr;
0524 
0525         for (uint32 row = 0; row < count1; row++)
0526             {
0527 
0528             if (maxValue == 0x0FFFF && step2 == 1)
0529                 {
0530 
0531                 for (uint32 col = 0; col < count2; col++)
0532                     {
0533 
0534                     uint32 x = s1 [col];
0535 
0536                     hist [x] ++;
0537 
0538                     }
0539 
0540                 }
0541 
0542             else
0543                 {
0544 
0545                 const uint16 *s2 = s1;
0546 
0547                 for (uint32 col = 0; col < count2; col++)
0548                     {
0549 
0550                     uint32 x = s2 [0];
0551 
0552                     if (x <= maxValue)
0553                         {
0554 
0555                         hist [x] ++;
0556 
0557                         }
0558 
0559                     s2 += step2;
0560 
0561                     }
0562 
0563                 }
0564 
0565             s1 += step1;
0566 
0567             }
0568 
0569         }
0570 
0571     }
0572 
0573 /*****************************************************************************/
0574 
0575 template <SIMDType simd>
0576 class dng_limit_float_depth_task: public dng_area_task
0577     {
0578 
0579     private:
0580 
0581         const dng_image &fSrcImage;
0582 
0583         dng_image &fDstImage;
0584 
0585         uint32 fBitDepth;
0586 
0587         real32 fScale;
0588 
0589     public:
0590 
0591         dng_limit_float_depth_task (const dng_image &srcImage,
0592                                     dng_image &dstImage,
0593                                     uint32 bitDepth,
0594                                     real32 scale);
0595 
0596         virtual dng_rect RepeatingTile1 () const
0597             {
0598             return fSrcImage.RepeatingTile ();
0599             }
0600 
0601         virtual dng_rect RepeatingTile2 () const
0602             {
0603             return fDstImage.RepeatingTile ();
0604             }
0605 
0606         virtual void Process (uint32 threadIndex,
0607                               const dng_rect &tile,
0608                               dng_abort_sniffer *sniffer);
0609 
0610     };
0611 
0612 /*****************************************************************************/
0613 
0614 template <SIMDType simd>
0615 dng_limit_float_depth_task<simd>::dng_limit_float_depth_task
0616     (const dng_image &srcImage,
0617      dng_image &dstImage,
0618      uint32 bitDepth,
0619      real32 scale)
0620 
0621     :   dng_area_task ("dng_limit_float_depth_task")
0622 
0623     ,   fSrcImage (srcImage)
0624     ,   fDstImage (dstImage)
0625     ,   fBitDepth (bitDepth)
0626     ,   fScale    (scale)
0627 
0628     {
0629 
0630     }
0631 
0632 /*****************************************************************************/
0633 
0634 template <SIMDType simd>
0635 void dng_limit_float_depth_task<simd>::Process (uint32 /* threadIndex */,
0636                                                 const dng_rect &tile,
0637                                                 dng_abort_sniffer * /* sniffer */)
0638     {
0639 
0640     INTEL_COMPILER_NEEDED_NOTE
0641 
0642     SET_CPU_FEATURE (simd);
0643 
0644     dng_const_tile_buffer srcBuffer (fSrcImage, tile);
0645     dng_dirty_tile_buffer dstBuffer (fDstImage, tile);
0646 
0647     uint32 count0 = tile.H ();
0648     uint32 count1 = tile.W ();
0649     uint32 count2 = fDstImage.Planes ();
0650 
0651     int32 sStep0 = srcBuffer.fRowStep;
0652     int32 sStep1 = srcBuffer.fColStep;
0653     int32 sStep2 = srcBuffer.fPlaneStep;
0654 
0655     int32 dStep0 = dstBuffer.fRowStep;
0656     int32 dStep1 = dstBuffer.fColStep;
0657     int32 dStep2 = dstBuffer.fPlaneStep;
0658 
0659     const void *sPtr = srcBuffer.ConstPixel (tile.t,
0660                                              tile.l,
0661                                              0);
0662 
0663           void *dPtr = dstBuffer.DirtyPixel (tile.t,
0664                                              tile.l,
0665                                              0);
0666 
0667     OptimizeOrder (sPtr,
0668                    dPtr,
0669                    srcBuffer.fPixelSize,
0670                    dstBuffer.fPixelSize,
0671                    count0,
0672                    count1,
0673                    count2,
0674                    sStep0,
0675                    sStep1,
0676                    sStep2,
0677                    dStep0,
0678                    dStep1,
0679                    dStep2);
0680 
0681     const real32 *sPtr0 = (const real32 *) sPtr;
0682           real32 *dPtr0 = (      real32 *) dPtr;
0683 
0684     real32 scale = fScale;
0685 
0686     bool limit16 = (fBitDepth == 16);
0687     bool limit24 = (fBitDepth == 24);
0688 
0689     for (uint32 index0 = 0; index0 < count0; index0++)
0690         {
0691 
0692         const real32 *sPtr1 = sPtr0;
0693               real32 *dPtr1 = dPtr0;
0694 
0695         for (uint32 index1 = 0; index1 < count1; index1++)
0696             {
0697 
0698             // If the scale is a NOP, and the data is packed solid, we can just do memory
0699             // copy.
0700 
0701             if (scale == 1.0f && sStep2 == 1 && dStep2 == 1)
0702                 {
0703 
0704                 if (dPtr1 != sPtr1)         // srcImage != dstImage
0705                     {
0706 
0707                     memcpy (dPtr1, sPtr1, count2 * (uint32) sizeof (real32));
0708 
0709                     }
0710 
0711                 }
0712 
0713             else
0714                 {
0715 
0716                 const real32 *sPtr2 = sPtr1;
0717                       real32 *dPtr2 = dPtr1;
0718                 INTEL_PRAGMA_SIMD_ASSERT_VECLEN_FLOAT(simd)
0719                 for (uint32 index2 = 0; index2 < count2; index2++)
0720                     {
0721 
0722                     real32 x = sPtr2 [0];
0723 
0724                     x *= scale;
0725 
0726                     dPtr2 [0] = x;
0727 
0728                     sPtr2 += sStep2;
0729                     dPtr2 += dStep2;
0730 
0731                     }
0732 
0733                 }
0734 
0735             // The data is now in the destination buffer.
0736 
0737             if (limit16)
0738                 {
0739 
0740                 //start by using intrinsic __m256 _mm256_cvtph_ps (__m128i a)
0741                 //once the intrinsic is written, merge this branch with previous one
0742 
0743                 uint32 *dPtr2 = (uint32 *) dPtr1;
0744 
0745                 INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT32(simd)
0746 
0747                 for (uint32 index2 = 0; index2 < count2; index2++)
0748                     {
0749 
0750                     uint32 x = dPtr2 [0];
0751 
0752                     uint16 y = DNG_FloatToHalf (x);
0753 
0754                     x = DNG_HalfToFloat (y);
0755 
0756                     dPtr2 [0] = x;
0757 
0758                     dPtr2 += dStep2;
0759 
0760                     }
0761 
0762                 }
0763 
0764             else if (limit24)
0765                 {
0766 
0767                 uint32 *dPtr2 = (uint32 *) dPtr1;
0768 
0769                 for (uint32 index2 = 0; index2 < count2; index2++)
0770                     {
0771 
0772                     uint32 x = dPtr2 [0];
0773 
0774                     uint8 temp [3];
0775 
0776                     DNG_FloatToFP24 (x, temp);
0777 
0778                     x = DNG_FP24ToFloat (temp);
0779 
0780                     dPtr2 [0] = x;
0781 
0782                     dPtr2 += dStep2;
0783 
0784                     }
0785 
0786                 }
0787 
0788             sPtr1 += sStep1;
0789             dPtr1 += dStep1;
0790 
0791             }
0792 
0793         sPtr0 += sStep0;
0794         dPtr0 += dStep0;
0795 
0796         }
0797 
0798     }
0799 
0800 /******************************************************************************/
0801 
0802 template <SIMDType simd>
0803 void LimitFloatBitDepth (dng_host &host,
0804                          const dng_image &srcImage,
0805                          dng_image &dstImage,
0806                          uint32 bitDepth,
0807                          real32 scale)
0808     {
0809 
0810     DNG_ASSERT (srcImage.PixelType () == ttFloat, "Floating point image expected");
0811     DNG_ASSERT (dstImage.PixelType () == ttFloat, "Floating point image expected");
0812 
0813     dng_limit_float_depth_task<simd> task (srcImage,
0814                                      dstImage,
0815                                      bitDepth,
0816                                      scale);
0817 
0818     host.PerformAreaTask (task, dstImage.Bounds ());
0819 
0820     }
0821 
0822 /*****************************************************************************/
0823 
0824 template
0825 void LimitFloatBitDepth<Scalar> (dng_host &host,
0826                                  const dng_image &srcImage,
0827                                  dng_image &dstImage,
0828                                  uint32 bitDepth,
0829                                  real32 scale);
0830 
0831 /*****************************************************************************/
0832 
0833 #if qDNGIntelCompiler
0834 
0835 template
0836 void LimitFloatBitDepth<AVX2> (dng_host &host,
0837                                const dng_image &srcImage,
0838                                dng_image &dstImage,
0839                                uint32 bitDepth,
0840                                real32 scale);
0841 
0842 #endif  // qDNGIntelCompiler
0843 
0844 /*****************************************************************************/
0845 
0846 void LimitFloatBitDepth (dng_host &host,
0847                          const dng_image &srcImage,
0848                          dng_image &dstImage,
0849                          uint32 bitDepth,
0850                          real32 scale)
0851     {
0852 
0853     // Kludge: Turning this off for now because the AVX2 path produces
0854     // slightly different results from the Scalar routine causing a mis-match
0855     // in raw digest values when building HDR merge result negatives which
0856     // causes the client to display a "file appears to be damaged" warning.
0857     // -bury 11/13/2017
0858 
0859     #if (qDNGIntelCompiler && qDNGExperimental && 0)
0860 
0861     if (gDNGMaxSIMD >= AVX2)
0862         {
0863 
0864         LimitFloatBitDepth<AVX2> (host,
0865                                   srcImage,
0866                                   dstImage,
0867                                   bitDepth,
0868                                   scale);
0869 
0870         }
0871 
0872     else
0873 
0874     #endif  // qDNGIntelCompiler && qDNGExperimental
0875 
0876         {
0877 
0878         LimitFloatBitDepth<Scalar> (host,
0879                                     srcImage,
0880                                     dstImage,
0881                                     bitDepth,
0882                                     scale);
0883 
0884         }
0885 
0886     }
0887 
0888 /*****************************************************************************/