diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp index bd5f19b399..6b803fece6 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ComputeArrayStatistics.cpp @@ -664,7 +664,7 @@ void FindStatistics(const DataArray& source, const Int32Array* featureIds, co indexAlgArrays.push_back(mostPopulatedBinPtr); #ifdef SIMPLNX_ENABLE_MULTICORE - if(IParallelAlgorithm::CheckArraysInMemory(indexAlgArrays)) + if(detail::CheckArraysInMemory(indexAlgArrays)) { const tbb::simple_partitioner simplePartitioner; const size_t grainSize = 500; diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertColorToGrayScale.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertColorToGrayScale.cpp index c37c8f3e10..0647dd5393 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertColorToGrayScale.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/ConvertColorToGrayScale.cpp @@ -2,7 +2,6 @@ #include "simplnx/Common/Array.hpp" #include "simplnx/Common/Range.hpp" -#include "simplnx/Core/Application.hpp" #include "simplnx/Core/Preferences.hpp" #include "simplnx/DataStructure/DataArray.hpp" #include "simplnx/DataStructure/DataGroup.hpp" @@ -12,11 +11,11 @@ using namespace nx::core; namespace { - +template class LuminosityImpl { public: - LuminosityImpl(const UInt8Array& data, UInt8Array& outputData, const FloatVec3& colorWeights, size_t numComp) + LuminosityImpl(const UInt8AbstractDataStore& data, UInt8AbstractDataStore& outputData, const FloatVec3& colorWeights, size_t numComp) : m_ImageData(data) , m_FlatImageData(outputData) , m_ColorWeights(colorWeights) @@ -36,9 +35,18 @@ class LuminosityImpl { for(size_t i = start; i < end; i++) { - auto temp = static_cast( - roundf((m_ImageData.at(m_NumComp * i) * m_ColorWeights.getX()) + (m_ImageData.at(m_NumComp * i + 1) * m_ColorWeights.getY()) + (m_ImageData.at(m_NumComp * i + 2) * m_ColorWeights.getZ()))); - m_FlatImageData.setValue(i, static_cast(temp)); + if constexpr(BoundsCheckV) + { + auto temp = static_cast(roundf((m_ImageData.at(m_NumComp * i) * m_ColorWeights.getX()) + (m_ImageData.at(m_NumComp * i + 1) * m_ColorWeights.getY()) + + (m_ImageData.at(m_NumComp * i + 2) * m_ColorWeights.getZ()))); + m_FlatImageData.setValue(i, static_cast(temp)); + } + else + { + auto temp = static_cast( + roundf((m_ImageData[m_NumComp * i] * m_ColorWeights.getX()) + (m_ImageData[m_NumComp * i + 1] * m_ColorWeights.getY()) + (m_ImageData[m_NumComp * i + 2] * m_ColorWeights.getZ()))); + m_FlatImageData.setValue(i, static_cast(temp)); + } } } @@ -48,8 +56,8 @@ class LuminosityImpl } private: - const UInt8Array& m_ImageData; - UInt8Array& m_FlatImageData; + const UInt8AbstractDataStore& m_ImageData; + UInt8AbstractDataStore& m_FlatImageData; const FloatVec3& m_ColorWeights; size_t m_NumComp; }; @@ -57,7 +65,7 @@ class LuminosityImpl class LightnessImpl { public: - LightnessImpl(const UInt8Array& data, UInt8Array& outputData, size_t numComp) + LightnessImpl(const UInt8AbstractDataStore& data, UInt8AbstractDataStore& outputData, size_t numComp) : m_ImageData(data) , m_FlatImageData(outputData) , m_NumComp(numComp) @@ -84,16 +92,16 @@ class LightnessImpl } private: - const UInt8Array& m_ImageData; - UInt8Array& m_FlatImageData; + const UInt8AbstractDataStore& m_ImageData; + UInt8AbstractDataStore& m_FlatImageData; size_t m_NumComp; }; +template class SingleChannelImpl { - public: - SingleChannelImpl(const UInt8Array& data, UInt8Array& outputData, size_t numComp, int32_t channel) + SingleChannelImpl(const UInt8AbstractDataStore& data, UInt8AbstractDataStore& outputData, size_t numComp, int32_t channel) : m_ImageData(data) , m_FlatImageData(outputData) , m_NumComp(numComp) @@ -110,7 +118,14 @@ class SingleChannelImpl { for(size_t i = start; i < end; i++) { - m_FlatImageData.setValue(i, static_cast((m_ImageData.at(m_NumComp * i + static_cast(m_Channel))))); + if constexpr(BoundsCheckV) + { + m_FlatImageData.setValue(i, m_ImageData.at(m_NumComp * i + static_cast(m_Channel))); + } + else + { + m_FlatImageData.setValue(i, m_ImageData[m_NumComp * i + static_cast(m_Channel)]); + } } } @@ -120,8 +135,8 @@ class SingleChannelImpl } private: - const UInt8Array& m_ImageData; - UInt8Array& m_FlatImageData; + const UInt8AbstractDataStore& m_ImageData; + UInt8AbstractDataStore& m_FlatImageData; size_t m_NumComp; int32_t m_Channel; }; @@ -136,11 +151,11 @@ class ParallelWrapper ParallelWrapper& operator=(ParallelWrapper&&) = delete; // Move Assignment Not Implemented template - static void Run(T impl, size_t totalPoints, typename IParallelAlgorithm::AlgorithmArrays algArrays) + static void Run(T impl, size_t totalPoints, const typename IParallelAlgorithm::AlgorithmStores& algStores) { ParallelDataAlgorithm dataAlg; dataAlg.setRange(0, totalPoints); - dataAlg.requireArraysInMemory(algArrays); + dataAlg.requireStoresInMemory(algStores); dataAlg.execute(impl); } @@ -180,32 +195,56 @@ Result<> ConvertColorToGrayScale::operator()() { break; } - const auto& inputColorData = m_DataStructure.getDataRefAs(arrayPath); - auto& outputGrayData = m_DataStructure.getDataRefAs(*outputPathIter); + const auto& inputColorData = m_DataStructure.getDataAs(arrayPath)->getDataStoreRef(); + auto& outputGrayData = m_DataStructure.getDataAs(*outputPathIter)->getDataStoreRef(); auto convType = static_cast(m_InputValues->ConversionAlgorithm); size_t comp = inputColorData.getNumberOfComponents(); size_t totalPoints = inputColorData.getNumberOfTuples(); - typename IParallelAlgorithm::AlgorithmArrays algArrays; - algArrays.push_back(&inputColorData); - algArrays.push_back(&outputGrayData); + typename IParallelAlgorithm::AlgorithmStores algStores; + algStores.push_back(&inputColorData); + algStores.push_back(&outputGrayData); switch(convType) { case ConversionType::Luminosity: - ParallelWrapper::Run(LuminosityImpl(inputColorData, outputGrayData, m_InputValues->ColorWeights, comp), totalPoints, algArrays); + if(comp < 3) // Pre-check bounds to try to avoid `.at()`; algorithm hardcoded a component access size of 3 + { + // Do bounds check + ParallelWrapper::Run>(LuminosityImpl(inputColorData, outputGrayData, m_InputValues->ColorWeights, comp), totalPoints, algStores); + } + else + { + ParallelWrapper::Run>(LuminosityImpl(inputColorData, outputGrayData, m_InputValues->ColorWeights, comp), totalPoints, algStores); + } break; case ConversionType::Average: - ParallelWrapper::Run(LuminosityImpl(inputColorData, outputGrayData, {0.3333f, 0.3333f, 0.3333f}, comp), totalPoints, algArrays); + if(comp < 3) // Pre-check bounds to try to avoid `.at()`; algorithm hardcoded a component access size of 3 + { + // Do bounds check + ParallelWrapper::Run>(LuminosityImpl(inputColorData, outputGrayData, {0.3333f, 0.3333f, 0.3333f}, comp), totalPoints, algStores); + } + else + { + ParallelWrapper::Run>(LuminosityImpl(inputColorData, outputGrayData, {0.3333f, 0.3333f, 0.3333f}, comp), totalPoints, algStores); + } break; case ConversionType::Lightness: { - ParallelWrapper::Run(LightnessImpl(inputColorData, outputGrayData, comp), totalPoints, algArrays); + ParallelWrapper::Run(LightnessImpl(inputColorData, outputGrayData, comp), totalPoints, algStores); break; } case ConversionType::SingleChannel: - ParallelWrapper::Run(SingleChannelImpl(inputColorData, outputGrayData, comp, m_InputValues->ColorChannel), totalPoints, algArrays); + if(comp * (totalPoints - 1) + m_InputValues->ColorChannel < inputColorData.getSize()) // Pre-check bounds to try to avoid `.at()` + { + // Do bounds check + ParallelWrapper::Run>(SingleChannelImpl(inputColorData, outputGrayData, comp, m_InputValues->ColorChannel), totalPoints, algStores); + } + else + { + ParallelWrapper::Run>(SingleChannelImpl(inputColorData, outputGrayData, comp, m_InputValues->ColorChannel), totalPoints, algStores); + } break; } } diff --git a/src/simplnx/Utilities/IParallelAlgorithm.cpp b/src/simplnx/Utilities/IParallelAlgorithm.cpp index ebc0aceb80..c3358fb063 100644 --- a/src/simplnx/Utilities/IParallelAlgorithm.cpp +++ b/src/simplnx/Utilities/IParallelAlgorithm.cpp @@ -2,10 +2,37 @@ #include "simplnx/Core/Application.hpp" +namespace +{ +// ----------------------------------------------------------------------------- +bool CheckStoresInMemory(const nx::core::IParallelAlgorithm::AlgorithmStores& stores) +{ + if(stores.empty()) + { + return true; + } + + for(const auto* storePtr : stores) + { + if(storePtr == nullptr) + { + continue; + } + + if(!storePtr->getDataFormat().empty()) + { + return false; + } + } + + return true; +} +} // namespace + namespace nx::core { // ----------------------------------------------------------------------------- -bool IParallelAlgorithm::CheckArraysInMemory(const AlgorithmArrays& arrays) +bool detail::CheckArraysInMemory(const nx::core::IParallelAlgorithm::AlgorithmArrays& arrays) { if(arrays.empty()) { @@ -56,6 +83,12 @@ void IParallelAlgorithm::setParallelizationEnabled(bool doParallel) // ----------------------------------------------------------------------------- void IParallelAlgorithm::requireArraysInMemory(const AlgorithmArrays& arrays) { - setParallelizationEnabled(CheckArraysInMemory(arrays)); + setParallelizationEnabled(detail::CheckArraysInMemory(arrays)); +} + +// ----------------------------------------------------------------------------- +void IParallelAlgorithm::requireStoresInMemory(const AlgorithmStores& stores) +{ + setParallelizationEnabled(::CheckStoresInMemory(stores)); } } // namespace nx::core diff --git a/src/simplnx/Utilities/IParallelAlgorithm.hpp b/src/simplnx/Utilities/IParallelAlgorithm.hpp index 3a1e5aee21..07ab720b82 100644 --- a/src/simplnx/Utilities/IParallelAlgorithm.hpp +++ b/src/simplnx/Utilities/IParallelAlgorithm.hpp @@ -2,6 +2,7 @@ #include "simplnx/Common/Types.hpp" #include "simplnx/DataStructure/IDataArray.hpp" +#include "simplnx/DataStructure/IDataStore.hpp" #include "simplnx/simplnx_export.hpp" #include @@ -12,8 +13,7 @@ class SIMPLNX_EXPORT IParallelAlgorithm { public: using AlgorithmArrays = std::vector; - - static bool CheckArraysInMemory(const AlgorithmArrays& arrays); + using AlgorithmStores = std::vector; IParallelAlgorithm(const IParallelAlgorithm&) = default; IParallelAlgorithm(IParallelAlgorithm&&) noexcept = default; @@ -24,7 +24,7 @@ class SIMPLNX_EXPORT IParallelAlgorithm * @brief Returns true if parallelization is enabled. Returns false otherwise. * @return */ - bool getParallelizationEnabled() const; + [[nodiscard]] bool getParallelizationEnabled() const; /** * @brief Sets whether parallelization is enabled. @@ -34,6 +34,8 @@ class SIMPLNX_EXPORT IParallelAlgorithm void requireArraysInMemory(const AlgorithmArrays& arrays); + void requireStoresInMemory(const AlgorithmStores& arrays); + protected: IParallelAlgorithm(); ~IParallelAlgorithm(); @@ -45,4 +47,9 @@ class SIMPLNX_EXPORT IParallelAlgorithm bool m_RunParallel = false; #endif }; + +namespace detail +{ +bool CheckArraysInMemory(const nx::core::IParallelAlgorithm::AlgorithmArrays& arrays); +} } // namespace nx::core