/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include using filament::math::half; namespace filament { namespace geometry { // The internal workhorse function of the Transcoder, which takes arbitrary input but always // produced packed floats. We expose a more readable interface than this to users, who often have // untyped blobs of interleaved data. Note that this variant takes an arbitrary number of // components, we also have a fixed-size variant for better compiler output. template void convert(float* UTILS_RESTRICT target, void const* UTILS_RESTRICT source, size_t count, int componentCount, int srcStride) noexcept { constexpr float scale = 1.0f / float(NORMALIZATION_FACTOR); uint8_t const* srcBytes = (uint8_t const*) source; for (size_t i = 0; i < count; ++i, target += componentCount, srcBytes += srcStride) { SOURCE_TYPE const* src = (SOURCE_TYPE const*) srcBytes; for (int n = 0; n < componentCount; ++n) { target[n] = float(src[n]) * scale; } } } template void convert(float* UTILS_RESTRICT target, void const* UTILS_RESTRICT source, size_t count, int srcStride) noexcept { constexpr float scale = 1.0f / float(NORMALIZATION_FACTOR); uint8_t const* srcBytes = (uint8_t const*) source; for (size_t i = 0; i < count; ++i, target += NUM_COMPONENTS, srcBytes += srcStride) { SOURCE_TYPE const* src = (SOURCE_TYPE const*) srcBytes; for (int n = 0; n < NUM_COMPONENTS; ++n) { target[n] = float(src[n]) * scale; } } } // Similar to "convert" but clamps the result to -1, which is required for normalized signed types. // For example, -128 can be represented in SBYTE but is outside the permitted range and should // therefore be clamped. For more information, see the Vulkan spec under the section "Conversion // from Normalized Fixed-Point to Floating-Point". template void convertClamped(float* UTILS_RESTRICT target, void const* UTILS_RESTRICT source, size_t count, int componentCount, int srcStride) noexcept { constexpr float scale = 1.0f / float(NORMALIZATION_FACTOR); uint8_t const* srcBytes = (uint8_t const*) source; for (size_t i = 0; i < count; ++i, target += componentCount, srcBytes += srcStride) { SOURCE_TYPE const* src = (SOURCE_TYPE const*) srcBytes; for (int n = 0; n < componentCount; ++n) { const float value = float(src[n]) * scale; target[n] = value < -1.0f ? -1.0f : value; } } } template void convertClamped(float* UTILS_RESTRICT target, void const* UTILS_RESTRICT source, size_t count, int srcStride) noexcept { constexpr float scale = 1.0f / float(NORMALIZATION_FACTOR); uint8_t const* srcBytes = (uint8_t const*) source; for (size_t i = 0; i < count; ++i, target += NUM_COMPONENTS, srcBytes += srcStride) { SOURCE_TYPE const* src = (SOURCE_TYPE const*) srcBytes; for (int n = 0; n < NUM_COMPONENTS; ++n) { const float value = float(src[n]) * scale; target[n] = value < -1.0f ? -1.0f : value; } } } size_t Transcoder::operator()(float* UTILS_RESTRICT target, void const* UTILS_RESTRICT source, size_t count) const noexcept { const size_t required = count * mConfig.componentCount * sizeof(float); if (target == nullptr) { return required; } const uint32_t comp = mConfig.componentCount; switch (mConfig.componentType) { case ComponentType::BYTE: { const uint32_t stride = mConfig.inputStrideBytes ? mConfig.inputStrideBytes : comp; if (mConfig.normalized) { if (comp == 2) { convertClamped(target, source, count, stride); } else if (comp == 3) { convertClamped(target, source, count, stride); } else { convertClamped(target, source, count, comp, stride); } } else { if (comp == 2) { convert(target, source, count, stride); } else if (comp == 3) { convert(target, source, count, stride); } else { convert(target, source, count, comp, stride); } } return required; } case ComponentType::UBYTE: { const uint32_t stride = mConfig.inputStrideBytes ? mConfig.inputStrideBytes : comp; if (mConfig.normalized) { if (comp == 2) { convert(target, source, count, stride); } else if (comp == 3) { convert(target, source, count, stride); } else { convert(target, source, count, comp, stride); } } else { if (comp == 2) { convert(target, source, count, stride); } else if (comp == 3) { convert(target, source, count, stride); } else { convert(target, source, count, comp, stride); } } return required; } case ComponentType::SHORT: { const uint32_t stride = mConfig.inputStrideBytes ? mConfig.inputStrideBytes : (2 * comp); if (mConfig.normalized) { if (comp == 2) { convertClamped(target, source, count, stride); } else if (comp == 3) { convertClamped(target, source, count, stride); } else { convertClamped(target, source, count, comp, stride); } } else { if (comp == 2) { convert(target, source, count, stride); } else if (comp == 3) { convert(target, source, count, stride); } else { convert(target, source, count, comp, stride); } } return required; } case ComponentType::USHORT: { const uint32_t stride = mConfig.inputStrideBytes ? mConfig.inputStrideBytes : (2 * comp); if (mConfig.normalized) { if (comp == 2) { convert(target, source, count, stride); } else if (comp == 3) { convert(target, source, count, stride); } else { convert(target, source, count, comp, stride); } } else { if (comp == 2) { convert(target, source, count, stride); } else if (comp == 3) { convert(target, source, count, stride); } else { convert(target, source, count, comp, stride); } } return required; } case ComponentType::HALF: { const uint32_t stride = mConfig.inputStrideBytes ? mConfig.inputStrideBytes : (2 * comp); uint8_t const* srcBytes = (uint8_t const*) source; for (size_t i = 0; i < count; ++i, target += comp, srcBytes += stride) { half const* src = (half const*) srcBytes; for (int n = 0; n < comp; ++n) { target[n] = float(src[n]); } } return required; } } return 0; } } // namespace geometry } // namespace filament