From 77eccdf13df8f1190d13d854f5dfd12daca09011 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Fri, 2 Nov 2018 00:54:02 -0500 Subject: [PATCH 1/9] Fix mismatched malloc/delete leak From the Valgrind report: ``` Mismatched free() / delete / delete [] at 0x4838EAB: operator delete(void*) (vg_replace_malloc.c:576) by 0xBC5C87: std::default_delete::operator()(cJSON*) const (unique_ptr.h:81) by 0xBC4ACA: std::unique_ptr >::~unique_ptr() (unique_ptr.h:274) by 0xBBB755: (anonymous namespace)::getAliases(Glib::ustring const&) (dcp.cc:422) by 0xBC1CCA: rtengine::DCPStore::init(Glib::ustring const&, bool) (dcp.cc:1846) by 0xC3ED4F: rtengine::init(rtengine::Settings const*, Glib::ustring, Glib::ustring, bool) [clone ._omp_fn.0] (init.cc:81) by 0x89743FF: GOMP_parallel_sections (sections.c:158) by 0xC3E906: rtengine::init(rtengine::Settings const*, Glib::ustring, Glib::ustring, bool) (init.cc:52) by 0x9CE10E: Options::load(bool) (options.cc:2358) by 0x982CD6: main (main.cc:603) Address 0xd62d700 is 0 bytes inside a block of size 64 alloc'd at 0x483777F: malloc (vg_replace_malloc.c:299) by 0xE97390: cJSON_New_Item (cJSON.c:205) by 0xE98718: cJSON_ParseWithOpts (cJSON.c:1020) by 0xE9886F: cJSON_Parse (cJSON.c:1083) by 0xBBB4D3: (anonymous namespace)::getAliases(Glib::ustring const&) (dcp.cc:422) by 0xBC1CCA: rtengine::DCPStore::init(Glib::ustring const&, bool) (dcp.cc:1846) by 0xC3ED4F: rtengine::init(rtengine::Settings const*, Glib::ustring, Glib::ustring, bool) [clone ._omp_fn.0] (init.cc:81) by 0x89743FF: GOMP_parallel_sections (sections.c:158) by 0xC3E906: rtengine::init(rtengine::Settings const*, Glib::ustring, Glib::ustring, bool) (init.cc:52) by 0x9CE10E: Options::load(bool) (options.cc:2358) by 0x982CD6: main (main.cc:603) ``` --- rtengine/dcp.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index c18ee8915..a1b0db323 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -393,6 +393,13 @@ double xyCoordToTemperature(const std::array& white_xy) return res; } +struct cJSON_deleter { + template + void operator()(T *t) { + cJSON_Delete(const_cast::type*>(t)); + } +}; + std::map getAliases(const Glib::ustring& profile_dir) { const std::unique_ptr> file( @@ -419,7 +426,7 @@ std::map getAliases(const Glib::ustring& profile_dir) buffer[read] = 0; cJSON_Minify(buffer.get()); - const std::unique_ptr root(cJSON_Parse(buffer.get())); + const std::unique_ptr root(cJSON_Parse(buffer.get())); if (!root || !root->child) { if (settings->verbose) { std::cout << "Could not parse 'camera_model_aliases.json' file." << std::endl; From 5081c85f26d72446aae40bb4b45ff850dbcd15d1 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Fri, 2 Nov 2018 01:11:00 -0500 Subject: [PATCH 2/9] Fix leak of heap-allocated mutexes --- rtengine/rtlensfun.cc | 20 +++++++++----------- rtengine/rtlensfun.h | 4 ++-- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/rtengine/rtlensfun.cc b/rtengine/rtlensfun.cc index 792a86b61..50b3c8a66 100644 --- a/rtengine/rtlensfun.cc +++ b/rtengine/rtlensfun.cc @@ -33,7 +33,7 @@ extern const Settings *settings; LFModifier::~LFModifier() { if (data_) { - MyMutex::MyLock lock(*lfModifierMutex); + MyMutex::MyLock lock(lfModifierMutex); data_->Destroy(); } } @@ -113,14 +113,14 @@ void LFModifier::correctCA(double &x, double &y, int cx, int cy, int channel) co void LFModifier::processVignetteLine(int width, int y, float *line) const { - MyMutex::MyLock lock(*lfModifierMutex); + MyMutex::MyLock lock(lfModifierMutex); data_->ApplyColorModification(line, 0, y, width, 1, LF_CR_1(INTENSITY), 0); } void LFModifier::processVignetteLine3Channels(int width, int y, float *line) const { - MyMutex::MyLock lock(*lfModifierMutex); + MyMutex::MyLock lock(lfModifierMutex); data_->ApplyColorModification(line, 0, y, width, 1, LF_CR_3(RED, GREEN, BLUE), 0); } @@ -160,7 +160,6 @@ LFModifier::LFModifier(lfModifier *m, bool swap_xy, int flags): swap_xy_(swap_xy), flags_(flags) { - lfModifierMutex = new MyMutex; } @@ -378,14 +377,13 @@ bool LFDatabase::LoadDirectory(const char *dirname) LFDatabase::LFDatabase(): data_(nullptr) { - lfDBMutex = new MyMutex; } LFDatabase::~LFDatabase() { if (data_) { - MyMutex::MyLock lock(*lfDBMutex); + MyMutex::MyLock lock(lfDBMutex); data_->Destroy(); } } @@ -401,7 +399,7 @@ std::vector LFDatabase::getCameras() const { std::vector ret; if (data_) { - MyMutex::MyLock lock(*lfDBMutex); + MyMutex::MyLock lock(lfDBMutex); auto cams = data_->GetCameras(); while (*cams) { ret.emplace_back(); @@ -417,7 +415,7 @@ std::vector LFDatabase::getLenses() const { std::vector ret; if (data_) { - MyMutex::MyLock lock(*lfDBMutex); + MyMutex::MyLock lock(lfDBMutex); auto lenses = data_->GetLenses(); while (*lenses) { ret.emplace_back(); @@ -433,7 +431,7 @@ LFCamera LFDatabase::findCamera(const Glib::ustring &make, const Glib::ustring & { LFCamera ret; if (data_) { - MyMutex::MyLock lock(*lfDBMutex); + MyMutex::MyLock lock(lfDBMutex); auto found = data_->FindCamerasExt(make.c_str(), model.c_str()); if (found) { ret.data_ = found[0]; @@ -448,7 +446,7 @@ LFLens LFDatabase::findLens(const LFCamera &camera, const Glib::ustring &name) c { LFLens ret; if (data_) { - MyMutex::MyLock lock(*lfDBMutex); + MyMutex::MyLock lock(lfDBMutex); auto found = data_->FindLenses(camera.data_, nullptr, name.c_str()); for (size_t pos = 0; !found && pos < name.size(); ) { // try to split the maker from the model of the lens -- we have to @@ -486,7 +484,7 @@ std::unique_ptr LFDatabase::getModifier(const LFCamera &camera, cons { std::unique_ptr ret; if (data_) { - MyMutex::MyLock lock(*lfDBMutex); + MyMutex::MyLock lock(lfDBMutex); if (camera && lens) { lfModifier *mod = lfModifier::Create(lens.data_, camera.getCropFactor(), width, height); int flags = LF_MODIFY_DISTORTION | LF_MODIFY_SCALE | LF_MODIFY_TCA; diff --git a/rtengine/rtlensfun.h b/rtengine/rtlensfun.h index f75f25d4f..ef6d2192b 100644 --- a/rtengine/rtlensfun.h +++ b/rtengine/rtlensfun.h @@ -57,7 +57,7 @@ private: lfModifier *data_; bool swap_xy_; int flags_; - MyMutex *lfModifierMutex; + mutable MyMutex lfModifierMutex; }; class LFCamera final @@ -122,7 +122,7 @@ private: LFDatabase(); bool LoadDirectory(const char *dirname); - MyMutex *lfDBMutex; + mutable MyMutex lfDBMutex; static LFDatabase instance_; lfDatabase *data_; }; From ec814dbf05b8065f09ec58b74dfce8c1a1432575 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Fri, 2 Nov 2018 02:25:03 -0500 Subject: [PATCH 3/9] FramesData: Don't leak allocated frames, and remove unused functions Valgrind report: ``` 14,960 (11,544 direct, 3,416 indirect) bytes in 37 blocks are definitely lost in loss record 20,483 of 20,540 at 0x4837DEF: operator new(unsigned long) (vg_replace_malloc.c:334) by 0xC06963: rtengine::FramesData::FramesData(Glib::ustring const&, std::unique_ptr >, bool) (imagedata.cc:1121) by 0xBD774F: rtengine::DFManager::addFileInfo(Glib::ustring const&, bool) (dfmanager.cc:380) by 0xBD6E90: rtengine::DFManager::init(Glib::ustring) (dfmanager.cc:303) by 0xC3EC5D: rtengine::init(rtengine::Settings const*, Glib::ustring, Glib::ustring, bool) [clone ._omp_fn.0] (init.cc:93) by 0x897CABD: gomp_thread_start (team.c:120) by 0x89B7A9C: start_thread (in /usr/lib/libpthread-2.28.so) by 0x8ACCB22: clone (in /usr/lib/libc-2.28.so) ``` --- rtengine/imagedata.cc | 16 +++------------- rtengine/imagedata.h | 4 ++-- rtengine/imagesource.h | 1 - rtengine/rawimagesource.h | 4 ---- rtengine/stdimagesource.h | 4 ---- 5 files changed, 5 insertions(+), 24 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 572bd7e42..47bb0b490 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -809,11 +809,6 @@ unsigned int FramesData::getFrameCount () const return dcrawFrameCount ? dcrawFrameCount : frames.size(); } -FrameData *FramesData::getFrameData (unsigned int frame) const -{ - return frames.empty() || frame >= frames.size() ? nullptr : frames.at(frame); -} - bool FramesData::getPixelShift () const { // So far only Pentax and Sony provide multi-frame Pixel Shift files. @@ -1118,9 +1113,7 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptrgetRoot(), roots.at(0)); - - frames.push_back(fd); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); } for (auto currRoot : roots) { rtexif::Tag* t = currRoot->getTag(0x83BB); @@ -1142,8 +1135,7 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptrgetRoot(), roots.at(0)); - frames.push_back(fd); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); } rewind (exifManager.f); // Not sure this is necessary iptc = iptc_data_new_from_jpeg_file (exifManager.f); @@ -1161,9 +1153,7 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptrgetRoot(), roots.at(0)); - - frames.push_back(fd); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); } for (auto currRoot : roots) { rtexif::Tag* t = currRoot->getTag(0x83BB); diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index 0427ee519..1c3aff7e9 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -20,6 +20,7 @@ #define __IMAGEDATA_H__ #include +#include #include "rawimage.h" #include #include @@ -89,7 +90,7 @@ public: class FramesData : public FramesMetaData { private: // frame's root IFD, can be a file root IFD or a SUB-IFD - std::vector frames; + std::vector> frames; // root IFD in the file std::vector roots; IptcData* iptc; @@ -102,7 +103,6 @@ public: void setDCRawFrameCount (unsigned int frameCount); unsigned int getRootCount () const; unsigned int getFrameCount () const; - FrameData *getFrameData (unsigned int frame) const; bool getPixelShift () const; bool getHDR (unsigned int frame = 0) const; std::string getImageType (unsigned int frame) const; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index a7c867e08..c1bd8fd64 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -110,7 +110,6 @@ public: return 0; } - virtual FrameData* getImageData (unsigned int frameNum) = 0; virtual ImageMatrices* getImageMatrices () = 0; virtual bool isRAW () const = 0; virtual DCPProfile* getDCP (const ColorManagementParams &cmp, DCPProfile::ApplyState &as) diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 8ee403ea2..af0c1a116 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -168,10 +168,6 @@ public: return ri->get_rotateDegree(); } - FrameData* getImageData (unsigned int frameNum) - { - return idata->getFrameData (frameNum); - } ImageMatrices* getImageMatrices () { return &imatrices; diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 1dbb65001..605b2926c 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -69,10 +69,6 @@ public: void getFullSize (int& w, int& h, int tr = TR_NONE); void getSize (const PreviewProps &pp, int& w, int& h); - FrameData* getImageData (unsigned int frameNum) - { - return idata->getFrameData (frameNum); - } ImageIO* getImageIO () { return img; From 7cbf198db8e565bb7c0baca637664dce86f67031 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Wed, 7 Nov 2018 11:55:02 -0600 Subject: [PATCH 4/9] Revert "Fix mismatched malloc/delete leak" This reverts commit 77eccdf13df8f1190d13d854f5dfd12daca09011. --- rtengine/dcp.cc | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index a1b0db323..c18ee8915 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -393,13 +393,6 @@ double xyCoordToTemperature(const std::array& white_xy) return res; } -struct cJSON_deleter { - template - void operator()(T *t) { - cJSON_Delete(const_cast::type*>(t)); - } -}; - std::map getAliases(const Glib::ustring& profile_dir) { const std::unique_ptr> file( @@ -426,7 +419,7 @@ std::map getAliases(const Glib::ustring& profile_dir) buffer[read] = 0; cJSON_Minify(buffer.get()); - const std::unique_ptr root(cJSON_Parse(buffer.get())); + const std::unique_ptr root(cJSON_Parse(buffer.get())); if (!root || !root->child) { if (settings->verbose) { std::cout << "Could not parse 'camera_model_aliases.json' file." << std::endl; From a63cd8a87c5e5c880d2e64c99f53c70691a68539 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Fri, 2 Nov 2018 00:54:02 -0500 Subject: [PATCH 5/9] Fix mismatched malloc/delete leak, take 2 with cJSON_Delete From the Valgrind report: ``` Mismatched free() / delete / delete [] at 0x4838EAB: operator delete(void*) (vg_replace_malloc.c:576) by 0xBC5C87: std::default_delete::operator()(cJSON*) const (unique_ptr.h:81) by 0xBC4ACA: std::unique_ptr >::~unique_ptr() (unique_ptr.h:274) by 0xBBB755: (anonymous namespace)::getAliases(Glib::ustring const&) (dcp.cc:422) by 0xBC1CCA: rtengine::DCPStore::init(Glib::ustring const&, bool) (dcp.cc:1846) by 0xC3ED4F: rtengine::init(rtengine::Settings const*, Glib::ustring, Glib::ustring, bool) [clone ._omp_fn.0] (init.cc:81) by 0x89743FF: GOMP_parallel_sections (sections.c:158) by 0xC3E906: rtengine::init(rtengine::Settings const*, Glib::ustring, Glib::ustring, bool) (init.cc:52) by 0x9CE10E: Options::load(bool) (options.cc:2358) by 0x982CD6: main (main.cc:603) Address 0xd62d700 is 0 bytes inside a block of size 64 alloc'd at 0x483777F: malloc (vg_replace_malloc.c:299) by 0xE97390: cJSON_New_Item (cJSON.c:205) by 0xE98718: cJSON_ParseWithOpts (cJSON.c:1020) by 0xE9886F: cJSON_Parse (cJSON.c:1083) by 0xBBB4D3: (anonymous namespace)::getAliases(Glib::ustring const&) (dcp.cc:422) by 0xBC1CCA: rtengine::DCPStore::init(Glib::ustring const&, bool) (dcp.cc:1846) by 0xC3ED4F: rtengine::init(rtengine::Settings const*, Glib::ustring, Glib::ustring, bool) [clone ._omp_fn.0] (init.cc:81) by 0x89743FF: GOMP_parallel_sections (sections.c:158) by 0xC3E906: rtengine::init(rtengine::Settings const*, Glib::ustring, Glib::ustring, bool) (init.cc:52) by 0x9CE10E: Options::load(bool) (options.cc:2358) by 0x982CD6: main (main.cc:603) ``` --- rtengine/dcp.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index c18ee8915..c60e80587 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -419,7 +419,7 @@ std::map getAliases(const Glib::ustring& profile_dir) buffer[read] = 0; cJSON_Minify(buffer.get()); - const std::unique_ptr root(cJSON_Parse(buffer.get())); + const std::unique_ptr root(cJSON_Parse(buffer.get()), cJSON_Delete); if (!root || !root->child) { if (settings->verbose) { std::cout << "Could not parse 'camera_model_aliases.json' file." << std::endl; From b4813273d21f991789749d30eeb2ac437cdcc698 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Wed, 7 Nov 2018 12:16:16 -0600 Subject: [PATCH 6/9] ImageData: Use terser emplace_back to add unique_ptr to vector --- rtengine/imagedata.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 47bb0b490..849a7199f 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -1113,7 +1113,8 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + // Note: could leak if emplace_back throws (below as well). Unlikely in practice. + frames.emplace_back(new FrameData(currFrame, currFrame->getRoot(), roots.at(0))); } for (auto currRoot : roots) { rtexif::Tag* t = currRoot->getTag(0x83BB); @@ -1135,7 +1136,7 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.emplace_back(new FrameData(currFrame, currFrame->getRoot(), roots.at(0))); } rewind (exifManager.f); // Not sure this is necessary iptc = iptc_data_new_from_jpeg_file (exifManager.f); @@ -1153,7 +1154,7 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.emplace_back(new FrameData(currFrame, currFrame->getRoot(), roots.at(0))); } for (auto currRoot : roots) { rtexif::Tag* t = currRoot->getTag(0x83BB); From 2502312242bf004dcf4ea2527b843c6dee45f215 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 8 Nov 2018 14:35:03 +0100 Subject: [PATCH 7/9] Small speedup for dehaze, closes #4944 --- rtengine/ipdehaze.cc | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/rtengine/ipdehaze.cc b/rtengine/ipdehaze.cc index fecc73e7d..5522107e0 100644 --- a/rtengine/ipdehaze.cc +++ b/rtengine/ipdehaze.cc @@ -197,23 +197,16 @@ void extract_channels(Imagefloat *img, array2D &r, array2D &g, arr const int W = img->getWidth(); const int H = img->getHeight(); -#ifdef _OPENMP - #pragma omp parallel for if (multithread) -#endif - for (int y = 0; y < H; ++y) { - for (int x = 0; x < W; ++x) { - r[y][x] = img->r(y, x); - g[y][x] = img->g(y, x); - b[y][x] = img->b(y, x); - } - } + array2D imgR(W, H, img->r.ptrs, ARRAY2D_BYREFERENCE); + guidedFilter(imgR, imgR, r, radius, epsilon, multithread); - guidedFilter(r, r, r, radius, epsilon, multithread); - guidedFilter(g, g, g, radius, epsilon, multithread); - guidedFilter(b, b, b, radius, epsilon, multithread); + array2D imgG(W, H, img->g.ptrs, ARRAY2D_BYREFERENCE); + guidedFilter(imgG, imgG, g, radius, epsilon, multithread); + + array2D imgB(W, H, img->b.ptrs, ARRAY2D_BYREFERENCE); + guidedFilter(imgB, imgB, b, radius, epsilon, multithread); } - } // namespace From 6cd50adc54f744ff5d9702548107a27dbb796d20 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Thu, 8 Nov 2018 09:57:02 -0600 Subject: [PATCH 8/9] Revert "ImageData: Use terser emplace_back to add unique_ptr to vector" This reverts commit b4813273d21f991789749d30eeb2ac437cdcc698. --- rtengine/imagedata.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 849a7199f..47bb0b490 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -1113,8 +1113,7 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptrgetRoot(), roots.at(0))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); } for (auto currRoot : roots) { rtexif::Tag* t = currRoot->getTag(0x83BB); @@ -1136,7 +1135,7 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptrgetRoot(), roots.at(0))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); } rewind (exifManager.f); // Not sure this is necessary iptc = iptc_data_new_from_jpeg_file (exifManager.f); @@ -1154,7 +1153,7 @@ FramesData::FramesData (const Glib::ustring& fname, std::unique_ptrgetRoot(), roots.at(0))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); } for (auto currRoot : roots) { rtexif::Tag* t = currRoot->getTag(0x83BB); From a1d4acf72f634303625b158ca0acacd06413247c Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 9 Nov 2018 13:55:58 +0100 Subject: [PATCH 9/9] Artefacts with toncurve 2 / weighted standard with RT-dev-1098, fixes #4948 --- rtengine/curves.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtengine/curves.h b/rtengine/curves.h index c66c19a27..f1b402dd3 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -1084,11 +1084,12 @@ inline float WeightedStdToneCurve::Triangle(float a, float a1, float b) const #ifdef __SSE2__ inline vfloat WeightedStdToneCurve::Triangle(vfloat a, vfloat a1, vfloat b) const { + vmask eqmask = vmaskf_eq(b, a); vfloat a2 = a1 - a; vmask cmask = vmaskf_lt(b, a); vfloat b3 = vself(cmask, b, F2V(65535.f) - b); vfloat a3 = vself(cmask, a, F2V(65535.f) - a); - return b + a2 * b3 / a3; + return vself(eqmask, a1, b + a2 * b3 / a3); } #endif