/* This file is part of Magnum. Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Vladimír Vondruš Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "PackingBatch.h" #include #include #include "Magnum/Math/Packing.h" #include "Magnum/Math/Implementation/halfTables.hpp" namespace Magnum { namespace Math { namespace { template inline void unpackUnsignedIntoImplementation(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { CORRADE_ASSERT(src.size() == dst.size(), "Math::unpackInto(): wrong destination size, got" << dst.size() << "but expected" << src.size(), ); CORRADE_ASSERT(src.template isContiguous<1>() && dst.isContiguous<1>(), "Math::unpackInto(): second view dimension is not contiguous", ); /** @todo SSE/NEON implementations exploiting second dimension size/stride, contiguity etc */ /* Caching values to avoid inline function calls in ebug builds */ constexpr Float bitMax = Implementation::bitMax(); const char* srcPtr = reinterpret_cast(src.data()); char* dstPtr = reinterpret_cast(dst.data()); const std::ptrdiff_t srcStride = src.stride()[0]; const std::ptrdiff_t dstStride = dst.stride()[0]; const std::size_t maxJ = src.size()[1]; for(std::size_t i = 0, maxI = src.size()[0]; i != maxI; ++i) { const T* srcPtrI = reinterpret_cast(srcPtr); Float* dstPtrI = reinterpret_cast(dstPtr); for(std::size_t j = 0; j != maxJ; ++j) *dstPtrI++ = *srcPtrI++/bitMax; srcPtr += srcStride; dstPtr += dstStride; } } } void unpackInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { unpackUnsignedIntoImplementation(src, dst); } void unpackInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { unpackUnsignedIntoImplementation(src, dst); } namespace { template inline void unpackSignedIntoImplementation(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { CORRADE_ASSERT(src.size() == dst.size(), "Math::unpackInto(): wrong destination size, got" << dst.size() << "but expected" << src.size(), ); CORRADE_ASSERT(src.template isContiguous<1>() && dst.isContiguous<1>(), "Math::unpackInto(): second view dimension is not contiguous", ); /** @todo SSE/NEON implementations exploiting second dimension size/stride, contiguity etc */ /* Caching values to avoid inline function calls in debug builds */ constexpr Float bitMax = Implementation::bitMax(); const char* srcPtr = reinterpret_cast(src.data()); char* dstPtr = reinterpret_cast(dst.data()); const std::ptrdiff_t srcStride = src.stride()[0]; const std::ptrdiff_t dstStride = dst.stride()[0]; const std::size_t maxJ = src.size()[1]; for(std::size_t i = 0, maxI = src.size()[0]; i != maxI; ++i) { const T* srcPtrI = reinterpret_cast(srcPtr); Float* dstPtrI = reinterpret_cast(dstPtr); for(std::size_t j = 0; j != maxJ; ++j) { const Float value = *srcPtrI++/bitMax; /* Avoiding a max() call in Debug */ *dstPtrI++ = value < -1.0f ? -1.0f : value; } srcPtr += srcStride; dstPtr += dstStride; } } } void unpackInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { unpackSignedIntoImplementation(src, dst); } void unpackInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { unpackSignedIntoImplementation(src, dst); } namespace { template inline void packIntoImplementation(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { CORRADE_ASSERT(src.size() == dst.size(), "Math::packInto(): wrong destination size, got" << dst.size() << "but expected" << src.size(), ); CORRADE_ASSERT(src.isContiguous<1>() && dst.template isContiguous<1>(), "Math::packInto(): second view dimension is not contiguous", ); /** @todo SSE/NEON implementations exploiting second dimension size/stride, contiguity etc */ /* Caching values to avoid inline function calls in debug builds */ constexpr Float bitMax = Implementation::bitMax(); const char* srcPtr = reinterpret_cast(src.data()); char* dstPtr = reinterpret_cast(dst.data()); const std::ptrdiff_t srcStride = src.stride()[0]; const std::ptrdiff_t dstStride = dst.stride()[0]; const std::size_t maxJ = src.size()[1]; for(std::size_t i = 0, maxI = src.size()[0]; i != maxI; ++i) { const Float* srcPtrI = reinterpret_cast(srcPtr); T* dstPtrI = reinterpret_cast(dstPtr); for(std::size_t j = 0; j != maxJ; ++j) /** @todo provide a version that doesn't do rounding */ *dstPtrI++ = std::round(*srcPtrI++*bitMax); srcPtr += srcStride; dstPtr += dstStride; } } } void packInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { packIntoImplementation(src, dst); } void packInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { packIntoImplementation(src, dst); } void packInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { packIntoImplementation(src, dst); } void packInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { packIntoImplementation(src, dst); } namespace { template inline void castIntoImplementation(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { CORRADE_ASSERT(src.size() == dst.size(), "Math::castInto(): wrong destination size, got" << dst.size() << "but expected" << src.size(), ); CORRADE_ASSERT(src.template isContiguous<1>() && dst.template isContiguous<1>(), "Math::castInto(): second view dimension is not contiguous", ); /** @todo SSE/NEON implementations exploiting second dimension size/stride, contiguity etc */ /* Caching values to avoid inline function calls in debug buílds */ const char* srcPtr = reinterpret_cast(src.data()); char* dstPtr = reinterpret_cast(dst.data()); const std::ptrdiff_t srcStride = src.stride()[0]; const std::ptrdiff_t dstStride = dst.stride()[0]; const std::size_t maxJ = src.size()[1]; for(std::size_t i = 0, maxI = src.size()[0]; i != maxI; ++i) { const T* srcPtrI = reinterpret_cast(srcPtr); U* dstPtrI = reinterpret_cast(dstPtr); for(std::size_t j = 0; j != maxJ; ++j) *dstPtrI++ = U(*srcPtrI++); srcPtr += srcStride; dstPtr += dstStride; } } } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { castIntoImplementation(src, dst); } static_assert(sizeof(HalfMantissaTable) + sizeof(HalfOffsetTable) + sizeof(HalfExponentTable) == 8576, "improper size of half->float conversion tables"); static_assert(sizeof(HalfBaseTable) + sizeof(HalfShiftTable) == 1536, "improper size of float->half conversion tables"); void unpackHalfInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { CORRADE_ASSERT(src.size() == dst.size(), "Math::unpackHalfInto(): wrong destination size, got" << dst.size() << "but expected" << src.size(), ); CORRADE_ASSERT(src.isContiguous<1>() && dst.isContiguous<1>(), "Math::unpackHalfInto(): second view dimension is not contiguous", ); /* Caching values to avoid inline function calls in debug builds */ const char* srcPtr = reinterpret_cast(src.data()); char* dstPtr = reinterpret_cast(dst.data()); const std::ptrdiff_t srcStride = src.stride()[0]; const std::ptrdiff_t dstStride = dst.stride()[0]; const std::size_t maxJ = src.size()[1]; for(std::size_t i = 0, maxI = src.size()[0]; i != maxI; ++i) { const UnsignedShort* srcPtrI = reinterpret_cast(srcPtr); UnsignedInt* dstPtrI = reinterpret_cast(dstPtr); for(std::size_t j = 0; j != maxJ; ++j) { const UnsignedShort h = *srcPtrI++; *dstPtrI++ = HalfMantissaTable[HalfOffsetTable[h >> 10] + (h & 0x3ff)] + HalfExponentTable[h >> 10]; } srcPtr += srcStride; dstPtr += dstStride; } } void packHalfInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { CORRADE_ASSERT(src.size() == dst.size(), "Math::packHalfInto(): wrong destination size, got" << dst.size() << "but expected" << src.size(), ); CORRADE_ASSERT(src.isContiguous<1>() && dst.isContiguous<1>(), "Math::packHalfInto(): second view dimension is not contiguous", ); /* Caching values to avoid inline function calls in debug builds */ const char* srcPtr = reinterpret_cast(src.data()); char* dstPtr = reinterpret_cast(dst.data()); const std::ptrdiff_t srcStride = src.stride()[0]; const std::ptrdiff_t dstStride = dst.stride()[0]; const std::size_t maxJ = src.size()[1]; for(std::size_t i = 0, maxI = src.size()[0]; i != maxI; ++i) { const UnsignedInt* srcPtrI = reinterpret_cast(srcPtr); UnsignedShort* dstPtrI = reinterpret_cast(dstPtr); for(std::size_t j = 0; j != maxJ; ++j) { const UnsignedInt f = *srcPtrI++; *dstPtrI++ = HalfBaseTable[(f >> 23) & 0x1ff] + ((f & 0x007fffff) >> HalfShiftTable[(f >> 23) & 0x1ff]); } srcPtr += srcStride; dstPtr += dstStride; } } }}