diff --git a/rtdata/languages/default b/rtdata/languages/default index 9d6c90aa1..e7c2f208b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1225,6 +1225,12 @@ PREFERENCES_CACHECLEAR_SAFETY;Only files in the cache are cleared. Processing pr PREFERENCES_CACHEMAXENTRIES;Maximum number of cache entries PREFERENCES_CACHEOPTS;Cache Options PREFERENCES_CACHETHUMBHEIGHT;Maximum thumbnail height +PREFERENCES_CHUNKSIZES;Tiles per thread +PREFERENCES_CHUNKSIZE_RAW_AMAZE;AMaZE demosaic +PREFERENCES_CHUNKSIZE_RAW_CA;Raw CA correction +PREFERENCES_CHUNKSIZE_RAW_RCD;RCD demosaic +PREFERENCES_CHUNKSIZE_RAW_XT;Xtrans demosaic +PREFERENCES_CHUNKSIZE_RGB;RGB processing PREFERENCES_CLIPPINGIND;Clipping Indication PREFERENCES_CLUTSCACHE;HaldCLUT Cache PREFERENCES_CLUTSCACHE_LABEL;Maximum number of cached CLUTs @@ -1341,6 +1347,8 @@ PREFERENCES_PARSEDEXTADDHINT;Add entered extension to the list. PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list. PREFERENCES_PARSEDEXTDOWNHINT;Move selected extension down in the list. PREFERENCES_PARSEDEXTUPHINT;Move selected extension up in the list. +PREFERENCES_PERFORMANCE_MEASURE;Measure +PREFERENCES_PERFORMANCE_MEASURE_HINT;Logs processing times in console PREFERENCES_PERFORMANCE_THREADS;Threads PREFERENCES_PERFORMANCE_THREADS_LABEL;Maximum number of threads for Noise Reduction and Wavelet Levels (0 = Automatic) PREFERENCES_PREVDEMO;Preview Demosaic Method diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index e27f894ee..76bd31f1e 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -27,7 +27,6 @@ #include "rt_math.h" #include "gauss.h" #include "median.h" -//#define BENCHMARK #include "StopWatch.h" namespace { @@ -121,10 +120,19 @@ float* RawImageSource::CA_correct_RT( bool fitParamsIn, bool fitParamsOut, float* buffer, - bool freeBuffer + bool freeBuffer, + size_t chunkSize, + bool measure ) { - BENCHFUN + + std::unique_ptr stop; + + if (measure) { + std::cout << "CA correcting " << W << "x" << H << " image with " << chunkSize << " tiles per thread" << std::endl; + stop.reset(new StopWatch("CA correction")); + } + // multithreaded and vectorized by Ingo Weyrich constexpr int ts = 128; constexpr int tsh = ts / 2; @@ -279,7 +287,7 @@ float* RawImageSource::CA_correct_RT( float blockdenomthr[2][2] = {}; #ifdef _OPENMP - #pragma omp for collapse(2) schedule(dynamic) nowait + #pragma omp for collapse(2) schedule(dynamic, chunkSize) nowait #endif for (int top = -border ; top < height; top += ts - border2) { for (int left = -border; left < width - (W & 1); left += ts - border2) { @@ -821,7 +829,7 @@ float* RawImageSource::CA_correct_RT( //green interpolated to optical sample points for R/B float* gshift = (float (*)) (data + 2 * sizeof(float) * ts * ts + sizeof(float) * ts * tsh + 4 * 64); // there is no overlap in buffer usage => share #ifdef _OPENMP - #pragma omp for schedule(dynamic) collapse(2) + #pragma omp for schedule(dynamic, chunkSize) collapse(2) #endif for (int top = -border; top < height; top += ts - border2) { for (int left = -border; left < width - (W & 1); left += ts - border2) { diff --git a/rtengine/amaze_demosaic_RT.cc b/rtengine/amaze_demosaic_RT.cc index 31419022d..fc36ff8b5 100644 --- a/rtengine/amaze_demosaic_RT.cc +++ b/rtengine/amaze_demosaic_RT.cc @@ -38,9 +38,15 @@ namespace rtengine { -void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue) +void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, size_t chunkSize, bool measure) { - BENCHFUN + + std::unique_ptr stop; + + if (measure) { + std::cout << "Demosaicing " << W << "x" << H << " image using AMaZE with " << chunkSize << " Tiles per Thread" << std::endl; + stop.reset(new StopWatch("amaze demosaic")); + } volatile double progress = 0.0; @@ -176,7 +182,7 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, c // Main algorithm: Tile loop // use collapse(2) to collapse the 2 loops to one large loop, so there is better scaling #ifdef _OPENMP - #pragma omp for schedule(dynamic) collapse(2) nowait + #pragma omp for schedule(dynamic, chunkSize) collapse(2) nowait #endif for (int top = winy - 16; top < winy + height; top += ts - 32) { diff --git a/rtengine/curves.h b/rtengine/curves.h index 3446e982d..d3fcd5237 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -1279,9 +1279,14 @@ class AdobeToneCurve : public ToneCurve { private: void RGBTone(float& r, float& g, float& b) const; // helper for tone curve - +#ifdef __SSE2__ + void RGBTone(vfloat& r, vfloat& g, vfloat& b) const; // helper for tone curve +#endif public: void Apply(float& r, float& g, float& b) const; + void BatchApply( + const size_t start, const size_t end, + float *r, float *g, float *b) const; }; class SatAndValueBlendingToneCurve : public ToneCurve @@ -1419,7 +1424,7 @@ inline void AdobeToneCurve::Apply(float& ir, float& ig, float& ib) const RGBTone(b, r, g); // Case 2: b > r >= g } else if (b > g) { RGBTone(r, b, g); // Case 3: r >= b > g - } else { // Case 4: r >= g == b + } else { // Case 4: r == g == b r = lutToneCurve[r]; g = lutToneCurve[g]; b = g; @@ -1437,15 +1442,88 @@ inline void AdobeToneCurve::Apply(float& ir, float& ig, float& ib) const setUnlessOOG(ir, ig, ib, r, g, b); } -inline void AdobeToneCurve::RGBTone(float& r, float& g, float& b) const -{ - float rold = r, gold = g, bold = b; +inline void AdobeToneCurve::BatchApply( + const size_t start, const size_t end, + float *r, float *g, float *b) const { + assert (lutToneCurve); + assert (lutToneCurve.getClip() & LUT_CLIP_BELOW); + assert (lutToneCurve.getClip() & LUT_CLIP_ABOVE); - r = lutToneCurve[rold]; - b = lutToneCurve[bold]; - g = b + ((r - b) * (gold - bold) / (rold - bold)); + // All pointers must have the same alignment for SSE usage. In the loop body below, + // we will only check `r`, assuming that the same result would hold for `g` and `b`. + assert (reinterpret_cast(r) % 16 == reinterpret_cast(g) % 16); + assert (reinterpret_cast(g) % 16 == reinterpret_cast(b) % 16); + + size_t i = start; + while (true) { + if (i >= end) { + // If we get to the end before getting to an aligned address, just return. + // (Or, for non-SSE mode, if we get to the end.) + return; +#ifdef __SSE2__ + } else if (reinterpret_cast(&r[i]) % 16 == 0) { + // Otherwise, we get to the first aligned address; go to the SSE part. + break; +#endif + } + Apply(r[i], g[i], b[i]); + i++; + } +#ifdef __SSE2__ + const vfloat upperv = F2V(MAXVALF); + for (; i + 3 < end; i += 4) { + + vfloat rc = vclampf(LVF(r[i]), ZEROV, upperv); + vfloat gc = vclampf(LVF(g[i]), ZEROV, upperv); + vfloat bc = vclampf(LVF(b[i]), ZEROV, upperv); + + vfloat minval = vminf(vminf(rc, gc), bc); + vfloat maxval = vmaxf(vmaxf(rc, gc), bc); + vfloat medval = vmaxf(vminf(rc, gc), vminf(bc, vmaxf(rc, gc))); + + const vfloat minvalold = minval; + const vfloat maxvalold = maxval; + + RGBTone(maxval, medval, minval); + + const vfloat nr = vself(vmaskf_eq(rc, maxvalold), maxval, vself(vmaskf_eq(rc, minvalold), minval, medval)); + const vfloat ng = vself(vmaskf_eq(gc, maxvalold), maxval, vself(vmaskf_eq(gc, minvalold), minval, medval)); + const vfloat nb = vself(vmaskf_eq(bc, maxvalold), maxval, vself(vmaskf_eq(bc, minvalold), minval, medval)); + + rc = LVF(r[i]); + gc = LVF(g[i]); + bc = LVF(b[i]); + setUnlessOOG(rc, gc, bc, nr, ng, nb); + STVF(r[i], rc); + STVF(g[i], gc); + STVF(b[i], bc); + } + // Remainder in non-SSE. + for (; i < end; ++i) { + Apply(r[i], g[i], b[i]); + } +#endif } +inline void AdobeToneCurve::RGBTone (float& maxval, float& medval, float& minval) const +{ + float minvalold = minval, medvalold = medval, maxvalold = maxval; + + maxval = lutToneCurve[maxvalold]; + minval = lutToneCurve[minvalold]; + medval = minval + ((maxval - minval) * (medvalold - minvalold) / (maxvalold - minvalold)); +} +#ifdef __SSE2__ +inline void AdobeToneCurve::RGBTone (vfloat& maxval, vfloat& medval, vfloat& minval) const +{ + const vfloat minvalold = minval, maxvalold = maxval; + + maxval = lutToneCurve[maxvalold]; + minval = lutToneCurve[minvalold]; + medval = minval + ((maxval - minval) * (medval - minvalold) / (maxvalold - minvalold)); + medval = vself(vmaskf_eq(minvalold, maxvalold), minval, medval); +} +#endif // Modifying the Luminance channel only inline void LuminanceToneCurve::Apply(float &ir, float &ig, float &ib) const { diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 790275d7e..d7f3a4c14 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -44,17 +44,17 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi // contrast == 0.0 means only first demosaicer will be used if(isBayer) { if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4) ) { - amaze_demosaic_RT(0, 0, winw, winh, rawData, red, green, blue); + amaze_demosaic_RT(0, 0, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::DCBVNG4) ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCDVNG4) ) { - rcd_demosaic(); + rcd_demosaic(options.chunkSizeRCD, options.measure); } } else { if (raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FOUR_PASS) ) { - xtrans_interpolate (3, true); + xtrans_interpolate (3, true, options.chunkSizeXT, options.measure); } else { - xtrans_interpolate (1, false); + xtrans_interpolate (1, false, options.chunkSizeXT, options.measure); } } @@ -70,17 +70,17 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi vng4_demosaic(rawData, redTmp, greenTmp, blueTmp); if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4) || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::PIXELSHIFT)) { - amaze_demosaic_RT(0, 0, winw, winh, rawData, red, green, blue); + amaze_demosaic_RT(0, 0, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::DCBVNG4) ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCDVNG4) ) { - rcd_demosaic(); + rcd_demosaic(options.chunkSizeRCD, options.measure); } } else { if (raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FOUR_PASS) ) { - xtrans_interpolate (3, true); + xtrans_interpolate (3, true, options.chunkSizeXT, options.measure); } else { - xtrans_interpolate (1, false); + xtrans_interpolate (1, false, options.chunkSizeXT, options.measure); } fast_xtrans_interpolate(rawData, redTmp, greenTmp, blueTmp); } diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index dcaf6e53c..234cdc29d 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -379,6 +379,11 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } } } + // If MakeNotes are vague, fall back to Exif LensMake and LensModel if set + // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#LensType + if (lens == "Manual Lens No CPU") { + lens_from_make_and_model(); + } } } @@ -451,8 +456,6 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* found = true; lens = "Canon " + ldata; } - } else { - found = lens_from_make_and_model(); } } @@ -467,6 +470,10 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } } } + + if (!found) { + lens_from_make_and_model(); + } } else if (!make.compare(0, 6, "PENTAX") || (!make.compare(0, 5, "RICOH") && !model.compare(0, 6, "PENTAX"))) { // ISO at max value supported, check manufacturer specific if (iso_speed == 65535 || iso_speed == 0) { @@ -483,8 +490,9 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* if (mnote->getTag("LensType")) { lens = mnote->getTag ("LensType")->valueToString(); - if (!mnote->getTag("LensType")->toInt()) { - // try to find something better than "M-42 or No Lens" + // If MakeNotes are vague, fall back to Exif LensMake and LensModel if set + // https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Pentax.html#LensType + if (lens == "M-42 or No Lens" || lens == "K or M Lens" || lens == "A Series Lens" || lens == "Sigma") { lens_from_make_and_model(); } } else { @@ -510,6 +518,9 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* } else if (mnote && (!make.compare(0, 4, "SONY") || !make.compare(0, 6, "KONICA"))) { if (mnote->getTag("LensID")) { lens = mnote->getTag("LensID")->valueToString(); + if (lens == "Unknown") { + lens_from_make_and_model(); + } } } else if (!make.compare(0, 7, "OLYMPUS")) { if (mnote->getTag("Equipment")) { @@ -519,6 +530,9 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* lens = eq->getTag("LensType")->valueToString(); } } + if (lens == "Unknown") { + lens_from_make_and_model(); + } } else if (mnote && !make.compare(0, 9, "Panasonic")) { if (mnote->getTag("LensType")) { std::string panalens = mnote->getTag("LensType")->valueToString(); @@ -1302,37 +1316,33 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptrexifBase >= 0; rtexif::ExifManager exifManager(f, std::move(rml), firstFrameOnly); - - if (has_rml_exif_base) { - if (exifManager.f && exifManager.rml) { - if (exifManager.rml->exifBase >= 0) { - exifManager.parseRaw(); - - } else if (exifManager.rml->ciffBase >= 0) { - exifManager.parseCIFF(); - } - } - - // copying roots - roots = exifManager.roots; - - // creating FrameData - for (auto currFrame : exifManager.frames) { - frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); - } - - for (auto currRoot : roots) { - rtexif::Tag* t = currRoot->getTag(0x83BB); - - if (t && !iptc) { - iptc = iptc_data_new_from_data((unsigned char*)t->getValue(), (unsigned)t->getValueSize()); - break; - } + if (exifManager.f && exifManager.rml) { + if (exifManager.rml->exifBase >= 0) { + exifManager.parseRaw (); + } else if (exifManager.rml->ciffBase >= 0) { + exifManager.parseCIFF (); } } + // copying roots + roots = exifManager.roots; + + // creating FrameData + for (auto currFrame : exifManager.frames) { + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + } + + for (auto currRoot : roots) { + rtexif::Tag* t = currRoot->getTag(0x83BB); + + if (t && !iptc) { + iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); + break; + } + } + + fclose(f); } } else if (hasJpegExtension(fname)) { diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 266219882..ea17c0cf3 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -225,9 +225,7 @@ void customToneCurve(const ToneCurve &customToneCurve, ToneCurveParams::TcMode c const AdobeToneCurve& userToneCurve = static_cast(customToneCurve); for (int i = istart, ti = 0; i < tH; i++, ti++) { - for (int j = jstart, tj = 0; j < tW; j++, tj++) { - userToneCurve.Apply(rtemp[ti * tileSize + tj], gtemp[ti * tileSize + tj], btemp[ti * tileSize + tj]); - } + userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize]); } } else if (curveMode == ToneCurveParams::TcMode::SATANDVALBLENDING) { // apply the curve on the saturation and value channels const SatAndValueBlendingToneCurve& userToneCurve = static_cast(customToneCurve); @@ -2086,17 +2084,24 @@ filmlike_clip(float *r, float *g, float *b) void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve, LUTf & cl2Toningcurve, - const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve) + const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve, size_t chunkSize, bool measure) { - rgbProc(working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, sat, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf, asIn, histToneCurve); + rgbProc (working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, sat, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf, asIn, histToneCurve, chunkSize, measure); } // Process RGB image and convert to LAB space void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve, LUTf & cl2Toningcurve, - const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve) + const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve, size_t chunkSize, bool measure) { - BENCHFUN + + std::unique_ptr stop; + + if (measure) { + std::cout << "rgb processing " << working->getWidth() << "x" << working->getHeight() << " image with " << chunkSize << " tiles per thread" << std::endl; + stop.reset(new StopWatch("rgb processing")); + } + Imagefloat *tmpImage = nullptr; Imagefloat* editImgFloat = nullptr; @@ -2465,7 +2470,7 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer } #ifdef _OPENMP - #pragma omp for schedule(dynamic) collapse(2) + #pragma omp for schedule(dynamic, chunkSize) collapse(2) #endif for (int ii = 0; ii < working->getHeight(); ii += TS) diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index a97c15722..e7ff25271 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -217,11 +217,11 @@ public: void updateColorProfiles(const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck); void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, - const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve); + const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve, size_t chunkSize = 1, bool measure = false); void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, - double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve); + double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn, LUTu &histToneCurve, size_t chunkSize = 1, bool measure = false); void labtoning(float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, LUTf & clToningcurve, LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3]); void toning2col(float r, float g, float b, float &ro, float &go, float &bo, float iplow, float iphigh, float rl, float gl, float bl, float rh, float gh, float bh, float SatLow, float SatHigh, float balanS, float balanH, float reducac, int mode, int preser, float strProtect); void toningsmh(float r, float g, float b, float &ro, float &go, float &bo, float RedLow, float GreenLow, float BlueLow, float RedMed, float GreenMed, float BlueMed, float RedHigh, float GreenHigh, float BlueHigh, float reducac, int mode, float strProtect); diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index 76d1f836c..befa0d4c6 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -299,7 +299,7 @@ void RawImageSource::pixelshift(int winx, int winy, int winw, int winh, const RA { BENCHFUN if(numFrames != 4) { // fallback for non pixelshift files - amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue); + amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); return; } @@ -328,7 +328,7 @@ BENCHFUN } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::AMAZEVNG4)) { dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.dualDemosaicContrast, true); } else { - amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[0]), red, green, blue); + amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[0]), red, green, blue, options.chunkSizeAMAZE, options.measure); } multi_array2D redTmp(winw, winh); multi_array2D greenTmp(winw, winh); @@ -340,7 +340,7 @@ BENCHFUN } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::AMAZEVNG4)) { dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.dualDemosaicContrast, true); } else { - amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i]); + amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], options.chunkSizeAMAZE, options.measure); } } @@ -369,7 +369,7 @@ BENCHFUN rawParamsTmp.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4); dual_demosaic_RT (true, rawParamsTmp, winw, winh, rawData, red, green, blue, bayerParams.dualDemosaicContrast, true); } else { - amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue); + amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); } } } diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 50abb4252..7e4ab6092 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2043,13 +2043,13 @@ void RawImageSource::preprocess(const RAWParams &raw, const LensProfParams &lens if (numFrames == 4) { double fitParams[64]; - float *buffer = CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[0], fitParams, false, true, nullptr, false); + float *buffer = CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[0], fitParams, false, true, nullptr, false, options.chunkSizeCA, options.measure); for(int i = 1; i < 3; ++i) { - CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[i], fitParams, true, false, buffer, false); + CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[i], fitParams, true, false, buffer, false, options.chunkSizeCA, options.measure); } - CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[3], fitParams, true, false, buffer, true); + CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[3], fitParams, true, false, buffer, true, options.chunkSizeCA, options.measure); } else { - CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, rawData, nullptr, false, false, nullptr, true); + CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, rawData, nullptr, false, false, nullptr, true, options.chunkSizeCA, options.measure); } } @@ -2090,7 +2090,7 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AHD)) { ahd_demosaic(); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZE)) { - amaze_demosaic_RT(0, 0, W, H, rawData, red, green, blue); + amaze_demosaic_RT (0, 0, W, H, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4) || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::DCBVNG4) || raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCDVNG4)) { @@ -2115,7 +2115,7 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO)) { nodemosaic(true); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCD)) { - rcd_demosaic(); + rcd_demosaic(options.chunkSizeRCD, options.measure); } else { nodemosaic(false); } @@ -2123,9 +2123,9 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c if (raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST)) { fast_xtrans_interpolate(rawData, red, green, blue); } else if (raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::ONE_PASS)) { - xtrans_interpolate(1, false); + xtrans_interpolate(1, false, options.chunkSizeXT, options.measure); } else if (raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::THREE_PASS)) { - xtrans_interpolate(3, true); + xtrans_interpolate(3, true, options.chunkSizeXT, options.measure); } else if (raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FOUR_PASS) || raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::TWO_PASS)) { if (!autoContrast) { double threshold = raw.xtranssensor.dualDemosaicContrast; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 743d6cf4f..a3ba1b98c 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -249,7 +249,9 @@ protected: bool fitParamsIn, bool fitParamsOut, float* buffer, - bool freeBuffer + bool freeBuffer, + size_t chunkSize = 1, + bool measure = false ); void ddct8x8s(int isgn, float a[8][8]); @@ -271,12 +273,12 @@ protected: void jdl_interpolate_omp(); void igv_interpolate(int winw, int winh); void lmmse_interpolate_omp(int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations); - void amaze_demosaic_RT(int winx, int winy, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue);//Emil's code for AMaZE + void amaze_demosaic_RT(int winx, int winy, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, size_t chunkSize = 1, bool measure = false);//Emil's code for AMaZE void dual_demosaic_RT(bool isBayer, const RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast = false); void fast_demosaic();//Emil's code for fast demosaicing void dcb_demosaic(int iterations, bool dcb_enhance); void ahd_demosaic(); - void rcd_demosaic(); + void rcd_demosaic(size_t chunkSize = 1, bool measure = false); void border_interpolate(unsigned int border, float (*image)[4], unsigned int start = 0, unsigned int end = 0); void border_interpolate2(int winw, int winh, int lborders, const array2D &rawData, array2D &red, array2D &green, array2D &blue); void dcb_initTileLimits(int &colMin, int &rowMin, int &colMax, int &rowMax, int x0, int y0, int border); @@ -295,7 +297,7 @@ protected: void dcb_color_full(float (*image)[3], int x0, int y0, float (*chroma)[2]); void cielab(const float (*rgb)[3], float* l, float* a, float *b, const int width, const int height, const int labWidth, const float xyz_cam[3][3]); void xtransborder_interpolate (int border, array2D &red, array2D &green, array2D &blue); - void xtrans_interpolate(const int passes, const bool useCieLab); + void xtrans_interpolate (const int passes, const bool useCieLab, size_t chunkSize = 1, bool measure = false); void fast_xtrans_interpolate (const array2D &rawData, array2D &red, array2D &green, array2D &blue); void pixelshift(int winx, int winy, int winw, int winh, const RAWParams &rawParams, unsigned int frame, const std::string &make, const std::string &model, float rawWpCorrection); void hflip (Imagefloat* im); diff --git a/rtengine/rcd_demosaic.cc b/rtengine/rcd_demosaic.cc index 01430a894..5b6e1a164 100644 --- a/rtengine/rcd_demosaic.cc +++ b/rtengine/rcd_demosaic.cc @@ -39,9 +39,14 @@ namespace rtengine * Licensed under the GNU GPL version 3 */ // Tiled version by Ingo Weyrich (heckflosse67@gmx.de) -void RawImageSource::rcd_demosaic() +void RawImageSource::rcd_demosaic(size_t chunkSize, bool measure) { - BENCHFUN + std::unique_ptr stop; + + if (measure) { + std::cout << "Demosaicing " << W << "x" << H << " image using rcd with " << chunkSize << " tiles per thread" << std::endl; + stop.reset(new StopWatch("rcd demosaic")); + } volatile double progress = 0.0; @@ -72,7 +77,7 @@ void RawImageSource::rcd_demosaic() float *lpf = PQ_Dir; // reuse buffer, they don't overlap in usage #ifdef _OPENMP - #pragma omp for schedule(dynamic) collapse(2) nowait + #pragma omp for schedule(dynamic, chunkSize) collapse(2) nowait #endif for(int tr = 0; tr < numTh; ++tr) { for(int tc = 0; tc < numTw; ++tc) { diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 7915e22ef..914bdae24 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -998,7 +998,7 @@ private: LUTu histToneCurve; - ipf.rgbProc(baseImg, labView, nullptr, curve1, curve2, curve, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as, histToneCurve); + ipf.rgbProc (baseImg, labView, nullptr, curve1, curve2, curve, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as, histToneCurve, options.chunkSizeRGB, options.measure); if (settings->verbose) { printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob); diff --git a/rtengine/xtrans_demosaic.cc b/rtengine/xtrans_demosaic.cc index f32969d17..cb65db092 100644 --- a/rtengine/xtrans_demosaic.cc +++ b/rtengine/xtrans_demosaic.cc @@ -43,6 +43,7 @@ void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b if (!rgb) { if(!cbrtinit) { + #pragma omp parallel for for (int i = 0; i < 0x14000; i++) { double r = i / 65535.0; cbrt[i] = r > Color::eps ? std::cbrt(r) : (Color::kappa * r + 16.0) / 116.0; @@ -173,9 +174,16 @@ void RawImageSource::xtransborder_interpolate (int border, array2D &red, */ // override CLIP function to test unclipped output #define CLIP(x) (x) -void RawImageSource::xtrans_interpolate (const int passes, const bool useCieLab) +void RawImageSource::xtrans_interpolate (const int passes, const bool useCieLab, size_t chunkSize, bool measure) { - BENCHFUN + + std::unique_ptr stop; + + if (measure) { + std::cout << passes << "-pass Xtrans Demosaicing " << W << "x" << H << " image with " << chunkSize << " tiles per thread" << std::endl; + stop.reset(new StopWatch("xtrans demosaic")); + } + constexpr int ts = 114; /* Tile Size */ constexpr int tsh = ts / 2; /* half of Tile Size */ @@ -296,7 +304,7 @@ void RawImageSource::xtrans_interpolate (const int passes, const bool useCieLab) uint8_t (*homosummax)[ts] = (uint8_t (*)[ts]) homo[ndir - 1]; // we can reuse the homo-buffer because they are not used together #ifdef _OPENMP - #pragma omp for collapse(2) schedule(dynamic) nowait + #pragma omp for collapse(2) schedule(dynamic, chunkSize) nowait #endif for (int top = 3; top < height - 19; top += ts - 16) diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index f8ec3e5db..82f5e5525 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -2116,6 +2116,7 @@ void ExifManager::parseCIFF () } parseCIFF (rml->ciffLength, root); root->sort (); + parse(true); } Tag* ExifManager::saveCIFFMNTag (TagDirectory* root, int len, const char* name) diff --git a/rtgui/options.cc b/rtgui/options.cc index b570069b1..c9c7c0cb1 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -453,7 +453,12 @@ void Options::setDefaults() maxInspectorBuffers = 2; // a rather conservative value for low specced systems... inspectorDelay = 0; serializeTiffRead = true; - + measure = false; + chunkSizeAMAZE = 2; + chunkSizeCA = 2; + chunkSizeRCD = 2; + chunkSizeRGB = 2; + chunkSizeXT = 2; FileBrowserToolbarSingleRow = false; hideTPVScrollbar = false; whiteBalanceSpotSize = 8; @@ -1108,6 +1113,30 @@ void Options::readFromFile(Glib::ustring fname) serializeTiffRead = keyFile.get_boolean("Performance", "SerializeTiffRead"); } + if (keyFile.has_key("Performance", "Measure")) { + measure = keyFile.get_boolean("Performance", "Measure"); + } + + if (keyFile.has_key("Performance", "ChunkSizeAMAZE")) { + chunkSizeAMAZE = std::min(16, std::max(1, keyFile.get_integer("Performance", "ChunkSizeAMAZE"))); + } + + if (keyFile.has_key("Performance", "ChunkSizeCA")) { + chunkSizeCA = std::min(16, std::max(1, keyFile.get_integer("Performance", "ChunkSizeCA"))); + } + + if (keyFile.has_key("Performance", "ChunkSizeRCD")) { + chunkSizeRCD = std::min(16, std::max(1, keyFile.get_integer("Performance", "ChunkSizeRCD"))); + } + + if (keyFile.has_key("Performance", "ChunkSizeRGB")) { + chunkSizeRGB = std::min(16, std::max(1, keyFile.get_integer("Performance", "ChunkSizeRGB"))); + } + + if (keyFile.has_key("Performance", "ChunkSizeXT")) { + chunkSizeXT = std::min(16, std::max(1, keyFile.get_integer("Performance", "ChunkSizeXT"))); + } + if (keyFile.has_key("Performance", "ThumbnailInspectorMode")) { rtSettings.thumbnail_inspector_mode = static_cast(keyFile.get_integer("Performance", "ThumbnailInspectorMode")); } @@ -1999,6 +2028,12 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("Performance", "InspectorDelay", inspectorDelay); keyFile.set_integer("Performance", "PreviewDemosaicFromSidecar", prevdemo); keyFile.set_boolean("Performance", "SerializeTiffRead", serializeTiffRead); + keyFile.set_integer("Performance", "Measure", measure); + keyFile.set_integer("Performance", "ChunkSizeAMAZE", chunkSizeAMAZE); + keyFile.set_integer("Performance", "ChunkSizeRCD", chunkSizeRCD); + keyFile.set_integer("Performance", "ChunkSizeRGB", chunkSizeRGB); + keyFile.set_integer("Performance", "ChunkSizeXT", chunkSizeXT); + keyFile.set_integer("Performance", "ChunkSizeCA", chunkSizeCA); keyFile.set_integer("Performance", "ThumbnailInspectorMode", int(rtSettings.thumbnail_inspector_mode)); diff --git a/rtgui/options.h b/rtgui/options.h index 3c25f2150..29bb51e65 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -314,7 +314,12 @@ public: bool filledProfile; // Used as reminder for the ProfilePanel "mode" prevdemo_t prevdemo; // Demosaicing method used for the <100% preview bool serializeTiffRead; - + bool measure; + size_t chunkSizeAMAZE; + size_t chunkSizeCA; + size_t chunkSizeRCD; + size_t chunkSizeRGB; + size_t chunkSizeXT; bool menuGroupRank; bool menuGroupLabel; bool menuGroupFileOperations; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 383c17416..be9182388 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -31,6 +31,25 @@ #include #endif +namespace { +void placeSpinBox(Gtk::Container* where, Gtk::SpinButton* &spin, const std::string &labelText, int digits, int inc0, int inc1, int maxLength, int range0, int range1, const std::string &toolTip = "") { + Gtk::HBox* HB = Gtk::manage ( new Gtk::HBox () ); + HB->set_spacing (4); + if (!toolTip.empty()) { + HB->set_tooltip_text (M (toolTip)); + } + Gtk::Label* label = Gtk::manage ( new Gtk::Label (M (labelText) + ":", Gtk::ALIGN_START)); + spin = Gtk::manage ( new Gtk::SpinButton () ); + spin->set_digits (digits); + spin->set_increments (inc0, inc1); + spin->set_max_length (maxLength); // Will this be sufficient? :) + spin->set_range (range0, range1); + HB->pack_start (*label, Gtk::PACK_SHRINK, 0); + HB->pack_end (*spin, Gtk::PACK_SHRINK, 0); + where->add(*HB); +} +} + extern Options options; extern Glib::ustring argv0; Glib::RefPtr themecss; @@ -652,38 +671,36 @@ Gtk::Widget* Preferences::getPerformancePanel() vbPerformance->pack_start (*ftiffserialize, Gtk::PACK_SHRINK, 4); Gtk::Frame* fclut = Gtk::manage(new Gtk::Frame(M("PREFERENCES_CLUTSCACHE"))); - Gtk::HBox* clutCacheSizeHB = Gtk::manage(new Gtk::HBox()); - clutCacheSizeHB->set_spacing(4); - Gtk::Label* CLUTLl = Gtk::manage(new Gtk::Label(M("PREFERENCES_CLUTSCACHE_LABEL") + ":", Gtk::ALIGN_START)); - clutCacheSizeSB = Gtk::manage(new Gtk::SpinButton()); - clutCacheSizeSB->set_digits(0); - clutCacheSizeSB->set_increments(1, 5); - clutCacheSizeSB->set_max_length(2); // Will this be sufficient? :) #ifdef _OPENMP - clutCacheSizeSB->set_range(1, 3 * omp_get_num_procs()); + placeSpinBox(fclut, clutCacheSizeSB, "PREFERENCES_CLUTSCACHE_LABEL", 0, 1, 5, 2, 1, 3 * omp_get_num_procs()); #else - clutCacheSizeSB->set_range(1, 12); + placeSpinBox(fclut, clutCacheSizeSB, "PREFERENCES_CLUTSCACHE_LABEL", 0, 1, 5, 2, 1, 12); #endif - clutCacheSizeHB->pack_start(*CLUTLl, Gtk::PACK_SHRINK, 0); - clutCacheSizeHB->pack_end(*clutCacheSizeSB, Gtk::PACK_SHRINK, 0); - fclut->add(*clutCacheSizeHB); vbPerformance->pack_start (*fclut, Gtk::PACK_SHRINK, 4); - Gtk::Frame* finspect = Gtk::manage(new Gtk::Frame(M("PREFERENCES_INSPECT_LABEL"))); - Gtk::HBox* maxIBuffersHB = Gtk::manage(new Gtk::HBox()); - maxIBuffersHB->set_spacing(4); - maxIBuffersHB->set_tooltip_text(M("PREFERENCES_INSPECT_MAXBUFFERS_TOOLTIP")); - Gtk::Label* maxIBufferLbl = Gtk::manage(new Gtk::Label(M("PREFERENCES_INSPECT_MAXBUFFERS_LABEL") + ":", Gtk::ALIGN_START)); - maxInspectorBuffersSB = Gtk::manage(new Gtk::SpinButton()); - maxInspectorBuffersSB->set_digits(0); - maxInspectorBuffersSB->set_increments(1, 5); - maxInspectorBuffersSB->set_max_length(2); - maxInspectorBuffersSB->set_range(1, 12); // ... we have to set a limit, 12 seem to be enough even for systems with tons of RAM - maxIBuffersHB->pack_start(*maxIBufferLbl, Gtk::PACK_SHRINK, 0); - maxIBuffersHB->pack_end(*maxInspectorBuffersSB, Gtk::PACK_SHRINK, 0); + Gtk::Frame* fchunksize = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_CHUNKSIZES")) ); + Gtk::VBox* chunkSizeVB = Gtk::manage ( new Gtk::VBox () ); + Gtk::HBox* measureHB = Gtk::manage ( new Gtk::HBox () ); + measureHB->set_spacing (4); + measureCB = Gtk::manage ( new Gtk::CheckButton (M ("PREFERENCES_PERFORMANCE_MEASURE")) ); + measureCB->set_tooltip_text (M ("PREFERENCES_PERFORMANCE_MEASURE_HINT")); + measureHB->pack_start(*measureCB, Gtk::PACK_SHRINK, 0); + chunkSizeVB->add(*measureHB); + + placeSpinBox(chunkSizeVB, chunkSizeAMSB, "PREFERENCES_CHUNKSIZE_RAW_AMAZE", 0, 1, 5, 2, 1, 16); + placeSpinBox(chunkSizeVB, chunkSizeCASB, "PREFERENCES_CHUNKSIZE_RAW_CA", 0, 1, 5, 2, 1, 16); + placeSpinBox(chunkSizeVB, chunkSizeRCDSB, "PREFERENCES_CHUNKSIZE_RAW_RCD", 0, 1, 5, 2, 1, 16); + placeSpinBox(chunkSizeVB, chunkSizeRGBSB, "PREFERENCES_CHUNKSIZE_RGB", 0, 1, 5, 2, 1, 16); + placeSpinBox(chunkSizeVB, chunkSizeXTSB, "PREFERENCES_CHUNKSIZE_RAW_XT", 0, 1, 5, 2, 1, 16); + + fchunksize->add (*chunkSizeVB); + + vbPerformance->pack_start (*fchunksize, Gtk::PACK_SHRINK, 4); + + Gtk::Frame* finspect = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_INSPECT_LABEL")) ); Gtk::VBox *inspectorvb = Gtk::manage(new Gtk::VBox()); - inspectorvb->add(*maxIBuffersHB); + placeSpinBox(inspectorvb, maxInspectorBuffersSB, "PREFERENCES_INSPECT_MAXBUFFERS_LABEL", 0, 1, 5, 2, 1, 12, "PREFERENCES_INSPECT_MAXBUFFERS_TOOLTIP"); Gtk::HBox *insphb = Gtk::manage(new Gtk::HBox()); thumbnailInspectorMode = Gtk::manage(new Gtk::ComboBoxText()); @@ -699,24 +716,15 @@ Gtk::Widget* Preferences::getPerformancePanel() Gtk::Frame* threadsFrame = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_PERFORMANCE_THREADS")) ); Gtk::VBox* threadsVBox = Gtk::manage ( new Gtk::VBox (Gtk::PACK_SHRINK, 4) ); - Gtk::HBox* threadsHBox = Gtk::manage (new Gtk::HBox (Gtk::PACK_SHRINK, 4)); - Gtk::Label* threadsLbl = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_PERFORMANCE_THREADS_LABEL") + ":", Gtk::ALIGN_START)); - threadsSpinBtn = Gtk::manage ( new Gtk::SpinButton () ); - threadsSpinBtn->set_digits (0); - threadsSpinBtn->set_increments (1, 5); - threadsSpinBtn->set_max_length (2); // Will this be sufficient? :) #ifdef _OPENMP int maxThreadNumber = omp_get_max_threads(); #else int maxThreadNumber = 10; #endif - threadsSpinBtn->set_range (0, maxThreadNumber); - threadsHBox->pack_start (*threadsLbl, Gtk::PACK_SHRINK, 2); - threadsHBox->pack_end (*threadsSpinBtn, Gtk::PACK_SHRINK, 2); + placeSpinBox(threadsVBox, threadsSpinBtn, "PREFERENCES_PERFORMANCE_THREADS_LABEL", 0, 1, 5, 2, 0, maxThreadNumber); - threadsVBox->pack_start (*threadsHBox, Gtk::PACK_SHRINK); threadsFrame->add (*threadsVBox); vbPerformance->pack_start (*threadsFrame, Gtk::PACK_SHRINK, 4); @@ -1785,6 +1793,12 @@ void Preferences::storePreferences() moptions.rgbDenoiseThreadLimit = threadsSpinBtn->get_value_as_int(); moptions.clutCacheSize = clutCacheSizeSB->get_value_as_int(); + moptions.measure = measureCB->get_active(); + moptions.chunkSizeAMAZE = chunkSizeAMSB->get_value_as_int(); + moptions.chunkSizeCA = chunkSizeCASB->get_value_as_int(); + moptions.chunkSizeRCD = chunkSizeRCDSB->get_value_as_int(); + moptions.chunkSizeRGB = chunkSizeRGBSB->get_value_as_int(); + moptions.chunkSizeXT = chunkSizeXTSB->get_value_as_int(); moptions.maxInspectorBuffers = maxInspectorBuffersSB->get_value_as_int(); moptions.rtSettings.thumbnail_inspector_mode = static_cast(thumbnailInspectorMode->get_active_row_number()); @@ -1988,6 +2002,12 @@ void Preferences::fillPreferences() threadsSpinBtn->set_value (moptions.rgbDenoiseThreadLimit); clutCacheSizeSB->set_value (moptions.clutCacheSize); + measureCB->set_active (moptions.measure); + chunkSizeAMSB->set_value (moptions.chunkSizeAMAZE); + chunkSizeCASB->set_value (moptions.chunkSizeCA); + chunkSizeRGBSB->set_value (moptions.chunkSizeRGB); + chunkSizeRCDSB->set_value (moptions.chunkSizeRCD); + chunkSizeXTSB->set_value (moptions.chunkSizeXT); maxInspectorBuffersSB->set_value (moptions.maxInspectorBuffers); thumbnailInspectorMode->set_active(int(moptions.rtSettings.thumbnail_inspector_mode)); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 3b78c0472..6f434c477 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -161,6 +161,12 @@ class Preferences : public Gtk::Dialog, public ProfileStoreListener Gtk::SpinButton* threadsSpinBtn; Gtk::SpinButton* clutCacheSizeSB; + Gtk::CheckButton* measureCB; + Gtk::SpinButton* chunkSizeAMSB; + Gtk::SpinButton* chunkSizeCASB; + Gtk::SpinButton* chunkSizeRCDSB; + Gtk::SpinButton* chunkSizeRGBSB; + Gtk::SpinButton* chunkSizeXTSB; Gtk::SpinButton* maxInspectorBuffersSB; Gtk::ComboBoxText *thumbnailInspectorMode;