#pragma once //////////////////////////////////////////////////////////////////////////////// // The MIT License (MIT) // // Copyright (c) 2019 Nicholas Frechette & Animation Compression Library contributors // // 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 "acl/core/impl/compiler_utils.h" #include "acl/core/iallocator.h" #include "acl/core/bitset.h" #include "acl/core/track_desc.h" #include "acl/core/variable_bit_rates.h" #include "acl/compression/track_array.h" #include "acl/compression/impl/track_range.h" #include #include ACL_IMPL_FILE_PRAGMA_PUSH namespace acl { namespace acl_impl { struct scalar_bit_rate { uint8_t value; }; struct qvv_bit_rate { uint8_t rotation; uint8_t translation; uint8_t scale; }; union track_bit_rate { scalar_bit_rate scalar; qvv_bit_rate qvv; track_bit_rate() : qvv{k_invalid_bit_rate, k_invalid_bit_rate, k_invalid_bit_rate} {} }; struct track_list_context { iallocator* allocator; const track_array* reference_list; track_array track_list; track_range* range_list; uint32_t* constant_tracks_bitset; track_bit_rate* bit_rate_list; uint32_t* track_output_indices; uint32_t num_tracks; uint32_t num_output_tracks; uint32_t num_samples; float sample_rate; float duration; track_list_context() : allocator(nullptr) , reference_list(nullptr) , track_list() , range_list(nullptr) , constant_tracks_bitset(nullptr) , bit_rate_list(nullptr) , track_output_indices(nullptr) , num_tracks(0) , num_output_tracks(0) , num_samples(0) , sample_rate(0.0F) , duration(0.0F) {} ~track_list_context() { if (allocator != nullptr) { deallocate_type_array(*allocator, range_list, num_tracks); const bitset_description bitset_desc = bitset_description::make_from_num_bits(num_tracks); deallocate_type_array(*allocator, constant_tracks_bitset, bitset_desc.get_size()); deallocate_type_array(*allocator, bit_rate_list, num_tracks); deallocate_type_array(*allocator, track_output_indices, num_output_tracks); } } bool is_valid() const { return allocator != nullptr; } bool is_constant(uint32_t track_index) const { return bitset_test(constant_tracks_bitset, bitset_description::make_from_num_bits(num_tracks), track_index); } track_list_context(const track_list_context&) = delete; track_list_context(track_list_context&&) = delete; track_list_context& operator=(const track_list_context&) = delete; track_list_context& operator=(track_list_context&&) = delete; }; // Promote scalar tracks to vector tracks for SIMD alignment and padding inline track_array copy_and_promote_track_list(iallocator& allocator, const track_array& ref_track_list, bool& out_are_samples_valid) { using namespace rtm; const uint32_t num_tracks = ref_track_list.get_num_tracks(); const uint32_t num_samples = ref_track_list.get_num_samples_per_track(); const float sample_rate = ref_track_list.get_sample_rate(); bool are_samples_valid = true; track_array out_track_list(allocator, num_tracks); for (uint32_t track_index = 0; track_index < num_tracks; ++track_index) { const track& ref_track = ref_track_list[track_index]; track& out_track = out_track_list[track_index]; switch (ref_track.get_type()) { case track_type8::float1f: { const track_float1f& typed_ref_track = track_cast(ref_track); track_vector4f track = track_vector4f::make_reserve(ref_track.get_description(), allocator, num_samples, sample_rate); for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index) { const vector4f sample = vector_load1(&typed_ref_track[sample_index]); are_samples_valid &= scalar_is_finite(scalarf(vector_get_x(sample))); track[sample_index] = sample; } out_track = std::move(track); break; } case track_type8::float2f: { const track_float2f& typed_ref_track = track_cast(ref_track); track_vector4f track = track_vector4f::make_reserve(ref_track.get_description(), allocator, num_samples, sample_rate); for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index) { const vector4f sample = vector_load2(&typed_ref_track[sample_index]); are_samples_valid &= vector_is_finite2(sample); track[sample_index] = sample; } out_track = std::move(track); break; } case track_type8::float3f: { const track_float3f& typed_ref_track = track_cast(ref_track); track_vector4f track = track_vector4f::make_reserve(ref_track.get_description(), allocator, num_samples, sample_rate); for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index) { const vector4f sample = vector_load3(&typed_ref_track[sample_index]); are_samples_valid &= vector_is_finite3(sample); track[sample_index] = sample; } out_track = std::move(track); break; } case track_type8::float4f: { const track_float4f& typed_ref_track = track_cast(ref_track); track_vector4f track = track_vector4f::make_reserve(ref_track.get_description(), allocator, num_samples, sample_rate); for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index) { const vector4f sample = vector_load(&typed_ref_track[sample_index]); are_samples_valid &= vector_is_finite(sample); track[sample_index] = sample; } out_track = std::move(track); break; } case track_type8::vector4f: { const track_vector4f& typed_ref_track = track_cast(ref_track); track_vector4f track = track_vector4f::make_reserve(ref_track.get_description(), allocator, num_samples, sample_rate); for (uint32_t sample_index = 0; sample_index < num_samples; ++sample_index) { const vector4f sample = typed_ref_track[sample_index]; are_samples_valid &= vector_is_finite(sample); track[sample_index] = sample; } out_track = std::move(track); break; } default: ACL_ASSERT(false, "Unexpected track type"); are_samples_valid = false; break; } } out_are_samples_valid = are_samples_valid; return out_track_list; } inline uint32_t* create_output_track_mapping(iallocator& allocator, const track_array& track_list, uint32_t& out_num_output_tracks) { const uint32_t num_tracks = track_list.get_num_tracks(); uint32_t num_output_tracks = num_tracks; for (uint32_t track_index = 0; track_index < num_tracks; ++track_index) { const uint32_t output_index = track_list[track_index].get_output_index(); if (output_index == k_invalid_track_index) num_output_tracks--; // Stripped from the output } uint32_t* output_indices = allocate_type_array(allocator, num_output_tracks); for (uint32_t track_index = 0; track_index < num_tracks; ++track_index) { const uint32_t output_index = track_list[track_index].get_output_index(); if (output_index != k_invalid_track_index) output_indices[output_index] = track_index; } out_num_output_tracks = num_output_tracks; return output_indices; } inline bool initialize_context(iallocator& allocator, const track_array& track_list, track_list_context& context) { ACL_ASSERT(track_list.is_valid().empty(), "Invalid track list"); ACL_ASSERT(!context.is_valid(), "Context already initialized"); bool are_samples_valid = true; context.allocator = &allocator; context.reference_list = &track_list; context.track_list = copy_and_promote_track_list(allocator, track_list, are_samples_valid); context.range_list = nullptr; context.constant_tracks_bitset = nullptr; context.track_output_indices = nullptr; context.num_tracks = track_list.get_num_tracks(); context.num_output_tracks = 0; context.num_samples = track_list.get_num_samples_per_track(); context.sample_rate = track_list.get_sample_rate(); context.duration = track_list.get_duration(); context.track_output_indices = create_output_track_mapping(allocator, track_list, context.num_output_tracks); return are_samples_valid; } } } ACL_IMPL_FILE_PRAGMA_POP