Skip to content

Commit

Permalink
kms++util: New template based conversion & testpat code
Browse files Browse the repository at this point in the history
New templated conversion and test pattern code.

Signed-off-by: Tomi Valkeinen <[email protected]>
  • Loading branch information
tomba committed Feb 11, 2025
1 parent fd27835 commit e57e79c
Show file tree
Hide file tree
Showing 11 changed files with 1,354 additions and 107 deletions.
14 changes: 13 additions & 1 deletion kms++util/inc/kms++util/kms++util.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,19 @@ void draw_text(IFramebuffer& buf, uint32_t x, uint32_t y, const std::string& str

void draw_color_bar(IFramebuffer& buf, int old_xpos, int xpos, int width);

void draw_test_pattern(IFramebuffer& fb, YUVType yuvt = YUVType::BT601_Lim);
void draw_test_pattern_old(IFramebuffer& fb, YUVType yuvt = YUVType::BT601_Lim);
void draw_test_pattern_single_old(IFramebuffer& fb, YUVType yuvt = YUVType::BT601_Lim);
void draw_test_pattern_multi_old(IFramebuffer& fb, YUVType yuvt = YUVType::BT601_Lim);

struct TestPatternOptions {
std::string pattern;
RecStandard rec = RecStandard::BT709;
ColorRange range = ColorRange::Limited;
};

void draw_test_pattern(IFramebuffer& fb, const TestPatternOptions& options = {});
void draw_test_pattern_single(IFramebuffer& fb, const TestPatternOptions& options = {});
void draw_test_pattern_multi(IFramebuffer& fb, const TestPatternOptions& options = {});
} // namespace kms

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
Expand Down
2 changes: 1 addition & 1 deletion kms++util/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public_headers = [
'inc/kms++util/resourcemanager.h',
]

private_includes = include_directories('src', 'inc')
private_includes = include_directories('src', 'inc', '../ext/mdspan/include')
public_includes = include_directories('inc')

thread_dep = dependency('threads', required : false)
Expand Down
177 changes: 177 additions & 0 deletions kms++util/src/conv-common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#pragma once

#include <algorithm>
#include <array>

#define MDSPAN_IMPL_STANDARD_NAMESPACE md
#define MDSPAN_IMPL_PROPOSED_NAMESPACE exp

#include <mdspan/mdspan.hpp>

namespace kms
{

/*
* Helpers
*/

template<class T>
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<size_t, 2> strides = { row_stride, 1 };

auto layout = md::layout_stride::mapping(md::dextents<size_t, 2>(rows, cols), strides);

return md::mdspan<T, md::dextents<size_t, 2>, md::layout_stride>(data, layout);
}

template<class T>
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<T*>(data), rows, cols, row_stride_bytes);
}

// Helper for static loop unrolling
template<size_t Begin, size_t End, typename F>
constexpr void static_for(F&& f)
{
[&]<size_t... I>(std::index_sequence<I...>) {
(f(std::integral_constant<size_t, Begin + I>{}), ...);
}(std::make_index_sequence<End - Begin>{});
}

template<typename T, typename TElement>
concept HasIndexOperatorReturning = requires(T t) {
{ t[0] } -> std::convertible_to<const TElement&>;
};

template<typename T, typename TElement>
concept Is2Dspan = std::convertible_to<T, md::mdspan<TElement, md::dextents<size_t, 2>>>;

/*
* 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<ComponentType Type, size_t BitSize, size_t BitOffset>
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<typename TStorage>
static constexpr TStorage pack_value(TStorage value)
{
return (value & ((1ull << BitSize) - 1)) << BitOffset;
}

template<typename TStorage>
static constexpr component_storage_type unpack_value(TStorage value)
{
return (value >> BitOffset) & ((1ull << BitSize) - 1);
}
};

// Describes N components packed into a storage type
template<typename TStorage, typename... Components>
struct PlaneLayout {
using components_tuple = std::tuple<Components...>;

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<size_t N>
static constexpr size_t component_size = std::tuple_element_t<N, components_tuple>::size;

using storage_type = TStorage;

static constexpr std::array<ComponentType, sizeof...(Components)> order = {
Components::type...
};

template<ComponentType C>
static constexpr size_t component_count()
{
return std::ranges::count(order, C);
}

template<ComponentType C>
static constexpr size_t find_pos()
{
return std::ranges::find(order, C) - order.begin();
}

template<ComponentType C>
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<typename... Values>
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<TStorage>(values) | ...);
}

// Pack values into storage type (std:array version)
template<typename T, size_t N>
static constexpr TStorage pack(const std::array<T, N>& values)
{
static_assert(N == num_components,
"Number of values must match number of components");
return [&]<size_t... I>(std::index_sequence<I...>) {
return (Components::template pack_value<TStorage>(values[I]) | ...);
}(std::make_index_sequence<N>{});
}

static constexpr std::array<component_storage_type, num_components>
unpack(TStorage value)
{
return [&]<size_t... I>(std::index_sequence<I...>) {
return std::array{
std::tuple_element_t<I, components_tuple>::template unpack_value<
TStorage>(value)...
};
}(std::make_index_sequence<num_components>{});
}
};

template<typename... Planes>
class FormatLayout
{
public:
static constexpr size_t num_planes = sizeof...(Planes);

template<size_t N> using plane = std::tuple_element_t<N, std::tuple<Planes...>>;
};

} // namespace kms
Loading

0 comments on commit e57e79c

Please sign in to comment.