From f758e324e17b52116075bb9175a3dd03d223a424 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Sun, 2 Feb 2025 11:26:23 +0200 Subject: kms++util: New template based conversion & testpat code New templated conversion and test pattern code. Signed-off-by: Tomi Valkeinen --- kms++util/src/conv-common.h | 177 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 kms++util/src/conv-common.h (limited to 'kms++util/src/conv-common.h') diff --git a/kms++util/src/conv-common.h b/kms++util/src/conv-common.h new file mode 100644 index 0000000..837668f --- /dev/null +++ b/kms++util/src/conv-common.h @@ -0,0 +1,177 @@ +#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 -- cgit v1.2.3