#pragma once #include #include #define MDSPAN_IMPL_STANDARD_NAMESPACE md #define MDSPAN_IMPL_PROPOSED_NAMESPACE exp #include namespace kms { /* * Helpers */ template constexpr auto make_strided_view(T* data, size_t rows, size_t cols, size_t row_stride_bytes) { assert(row_stride_bytes % sizeof(T) == 0 && "Row stride must be aligned to element size"); size_t row_stride = row_stride_bytes / sizeof(T); std::array strides = { row_stride, 1 }; auto layout = md::layout_stride::mapping(md::dextents(rows, cols), strides); return md::mdspan, md::layout_stride>(data, layout); } template constexpr auto make_strided_fb_view(void* data, size_t rows, size_t cols, size_t row_stride_bytes) { return make_strided_view(reinterpret_cast(data), rows, cols, row_stride_bytes); } // Helper for static loop unrolling template constexpr void static_for(F&& f) { [&](std::index_sequence) { (f(std::integral_constant{}), ...); }(std::make_index_sequence{}); } template concept HasIndexOperatorReturning = requires(T t) { { t[0] } -> std::convertible_to; }; template concept Is2Dspan = std::convertible_to>>; /* * Packing and Layouts */ /* This type must be big enough to hold any of the components' value */ using component_storage_type = uint16_t; enum class ComponentType { X, A, R, G, B, Y, Cb, Cr, Y0, Y1, Y2, Cb0, Cb1, Cb2, Cr0, Cr1, Cr2, }; // Describes a single component's bit layout template struct ComponentLayout { static constexpr size_t size = BitSize; static constexpr size_t offset = BitOffset; static constexpr ComponentType type = Type; static_assert(sizeof(component_storage_type) * 8 >= size); static constexpr auto get_mask() { return ((1ull << BitSize) - 1) << BitOffset; } template static constexpr TStorage pack_value(TStorage value) { return (value & ((1ull << BitSize) - 1)) << BitOffset; } template static constexpr component_storage_type unpack_value(TStorage value) { return (value >> BitOffset) & ((1ull << BitSize) - 1); } }; // Describes N components packed into a storage type template struct PlaneLayout { using components_tuple = std::tuple; static constexpr size_t num_components = sizeof...(Components); static constexpr size_t total_bits = (Components::size + ...); static constexpr size_t storage_bits = sizeof(TStorage) * 8; static_assert(total_bits <= storage_bits, "Components don't fit in storage type"); template static constexpr size_t component_size = std::tuple_element_t::size; using storage_type = TStorage; static constexpr std::array order = { Components::type... }; template static constexpr size_t component_count() { return std::ranges::count(order, C); } template static constexpr size_t find_pos() { return std::ranges::find(order, C) - order.begin(); } template static constexpr size_t find_nth_pos(size_t n = 0) { auto it = std::ranges::find_if( order, [&n](ComponentType type) mutable { return type == C && n-- == 0; }); return it - order.begin(); } // Pack values into storage type (separate parameters version) template static constexpr TStorage pack(Values... values) { static_assert(sizeof...(values) == num_components, "Number of values must match number of components"); return (Components::template pack_value(values) | ...); } // Pack values into storage type (std:array version) template static constexpr TStorage pack(const std::array& values) { static_assert(N == num_components, "Number of values must match number of components"); return [&](std::index_sequence) { return (Components::template pack_value(values[I]) | ...); }(std::make_index_sequence{}); } static constexpr std::array unpack(TStorage value) { return [&](std::index_sequence) { return std::array{ std::tuple_element_t::template unpack_value< TStorage>(value)... }; }(std::make_index_sequence{}); } }; template class FormatLayout { public: static constexpr size_t num_planes = sizeof...(Planes); template using plane = std::tuple_element_t>; }; } // namespace kms