summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2026-05-04 16:19:04 +0300
committerTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2026-05-08 17:25:34 +0300
commit549c347d6feb2e94a810a720c97a8bf0f57317a1 (patch)
tree8225a757a97e3aadb561f107adee7b1bc526c711
parent4e2b291a4acdc2cbd39f005c88bda363bc06bd34 (diff)
kms++util: Replace test-pattern generator with pixpat
Switch draw_test_pattern() to call libpixpat (linked statically into libkms++util.so) instead of the in-tree pattern generator. Pixpat covers every pattern (kmstest, smpte, solid colors) and every pixel format the previous generator handled, so behavior is unchanged for all callers. Drop the now-unused machinery: conv.h and conv-*.h template writers, color16.h (RGB16/YUV16 plus conversions), the *_old / _single / _multi declarations that had no definitions or callers, and the c_draw_test_pattern C ABI which had no callers anywhere in the tree. RecStandard and ColorRange move from color16.h directly into kms++util.h, since they are still part of the public TestPatternOptions struct.
-rw-r--r--kms++util/inc/kms++util/color16.h184
-rw-r--r--kms++util/inc/kms++util/kms++util.h30
-rw-r--r--kms++util/meson.build9
-rw-r--r--kms++util/src/conv-common.h177
-rw-r--r--kms++util/src/conv-gray.h130
-rw-r--r--kms++util/src/conv-raw-packed.h230
-rw-r--r--kms++util/src/conv-raw.h202
-rw-r--r--kms++util/src/conv-rgb.h299
-rw-r--r--kms++util/src/conv-yuv-packed.h83
-rw-r--r--kms++util/src/conv-yuv-planar-packed.h125
-rw-r--r--kms++util/src/conv-yuv-planar.h214
-rw-r--r--kms++util/src/conv-yuv-semiplanar.h214
-rw-r--r--kms++util/src/conv-yuv.h147
-rw-r--r--kms++util/src/conv.h11
-rw-r--r--kms++util/src/testpat.cpp598
15 files changed, 54 insertions, 2599 deletions
diff --git a/kms++util/inc/kms++util/color16.h b/kms++util/inc/kms++util/color16.h
deleted file mode 100644
index 340ce6a..0000000
--- a/kms++util/inc/kms++util/color16.h
+++ /dev/null
@@ -1,184 +0,0 @@
-#pragma once
-
-#include <cmath>
-#include <cstdint>
-#include <algorithm>
-
-namespace kms
-{
-
-enum class ColorRange { Limited, Full };
-
-enum class RecStandard { BT601, BT709, BT2020 };
-
-class YUV16;
-class RGB16;
-
-// Conversion coefficients for different standards
-struct ConversionCoefficients {
- double kr;
- double kg;
- double kb;
-
- static constexpr ConversionCoefficients get(RecStandard rec) noexcept
- {
- switch (rec) {
- case RecStandard::BT601:
- return { 0.299, 0.587, 0.114 };
- default: // Default to BT709
- case RecStandard::BT709:
- return { 0.2126, 0.7152, 0.0722 };
- case RecStandard::BT2020:
- return { 0.2627, 0.6780, 0.0593 };
- }
- }
-};
-
-// Range scaling factors
-struct RangeScaling {
- double y_min;
- double y_max;
- double c_min;
- double c_max;
-
- static constexpr RangeScaling get(ColorRange range) noexcept
- {
- switch (range) {
- case ColorRange::Limited:
- return {
- 16.0 / 255.0, // y_min
- 235.0 / 255.0, // y_max
- 16.0 / 255.0, // c_min
- 240.0 / 255.0 // c_max
- };
- case ColorRange::Full:
- default:
- return { 0.0, 1.0, 0.0, 1.0 };
- }
- }
-};
-
-class RGB16
-{
-public:
- uint16_t r = 0;
- uint16_t g = 0;
- uint16_t b = 0;
- uint16_t a = 0;
-
- constexpr RGB16() noexcept = default;
- constexpr RGB16(uint16_t r, uint16_t g, uint16_t b) noexcept : r(r), g(g), b(b), a(max_value) {}
- constexpr RGB16(uint16_t r, uint16_t g, uint16_t b, uint16_t a) noexcept : r(r), g(g), b(b), a(a) {}
-
- static constexpr RGB16 from_8(uint8_t r, uint8_t g, uint8_t b)
- {
- return RGB16 {
- static_cast<uint16_t>((r << 8) | r),
- static_cast<uint16_t>((g << 8) | g),
- static_cast<uint16_t>((b << 8) | b),
- };
- }
-
- [[nodiscard]]
- constexpr YUV16 to_yuv(RecStandard rec = RecStandard::BT709,
- ColorRange range = ColorRange::Limited) const noexcept;
-
- static constexpr uint16_t max_value = 0xffff;
-};
-
-class YUV16
-{
-public:
- uint16_t y = 0;
- uint16_t u = 0;
- uint16_t v = 0;
- uint16_t a = 0;
-
- constexpr YUV16() noexcept = default;
- constexpr YUV16(uint16_t y, uint16_t u, uint16_t v) noexcept : y(y), u(u), v(v), a(max_value) {}
- constexpr YUV16(uint16_t y, uint16_t u, uint16_t v, uint16_t a) noexcept : y(y), u(u), v(v), a(a) {}
-
- [[nodiscard]]
- constexpr RGB16 to_rgb(RecStandard rec = RecStandard::BT709,
- ColorRange range = ColorRange::Limited) const noexcept;
-
-
- static constexpr YUV16 from_10(uint16_t r, uint16_t g, uint16_t b)
- {
- return YUV16 {
- static_cast<uint16_t>((r << 6) | (r >> 4)),
- static_cast<uint16_t>((g << 6) | (g >> 4)),
- static_cast<uint16_t>((b << 6) | (b >> 4)),
- };
- }
-
- static constexpr YUV16 from_12(uint16_t r, uint16_t g, uint16_t b)
- {
- return YUV16 {
- static_cast<uint16_t>((r << 4) | (r >> 8)),
- static_cast<uint16_t>((g << 4) | (g >> 8)),
- static_cast<uint16_t>((b << 4) | (b >> 8)),
- };
- }
-
- static constexpr uint16_t max_value = 0xffff;
-};
-
-constexpr YUV16 RGB16::to_yuv(RecStandard rec, ColorRange range) const noexcept
-{
- const auto coeff = ConversionCoefficients::get(rec);
- const auto scaling = RangeScaling::get(range);
-
- // Normalize RGB values to [0,1]
- const double r_norm = static_cast<double>(r) / max_value;
- const double g_norm = static_cast<double>(g) / max_value;
- const double b_norm = static_cast<double>(b) / max_value;
-
- // Calculate Y (unscaled)
- double y_unscaled = coeff.kr * r_norm + coeff.kg * g_norm + coeff.kb * b_norm;
-
- // Calculate U and V using unscaled Y
- double u = (b_norm - y_unscaled) / (2.0 * (1.0 - coeff.kb));
- double v = (r_norm - y_unscaled) / (2.0 * (1.0 - coeff.kr));
-
- // Scale Y to target range
- double y = y_unscaled * (scaling.y_max - scaling.y_min) + scaling.y_min;
-
- // Scale U and V to target range
- u = u * (scaling.c_max - scaling.c_min) + (scaling.c_max + scaling.c_min) / 2.0;
- v = v * (scaling.c_max - scaling.c_min) + (scaling.c_max + scaling.c_min) / 2.0;
-
- // Convert back to 16-bit values
- return YUV16(static_cast<uint16_t>(std::round(y * max_value)),
- static_cast<uint16_t>(std::round(u * max_value)),
- static_cast<uint16_t>(std::round(v * max_value)));
-}
-
-constexpr RGB16 YUV16::to_rgb(RecStandard rec, ColorRange range) const noexcept
-{
- const auto coeff = ConversionCoefficients::get(rec);
- const auto scaling = RangeScaling::get(range);
-
- // Normalize YUV values to [0,1]
- double y_norm = static_cast<double>(y) / max_value;
- double u_norm = static_cast<double>(u) / max_value;
- double v_norm = static_cast<double>(v) / max_value;
-
- // Rescale from target range to [0,1]
- y_norm = (y_norm - scaling.y_min) / (scaling.y_max - scaling.y_min);
- u_norm = (u_norm - (scaling.c_max + scaling.c_min) / 2.0) / (scaling.c_max - scaling.c_min);
- v_norm = (v_norm - (scaling.c_max + scaling.c_min) / 2.0) / (scaling.c_max - scaling.c_min);
-
- // Convert to RGB
- const double r = y_norm + 2.0 * v_norm * (1.0 - coeff.kr);
- const double g = y_norm - 2.0 * u_norm * (1.0 - coeff.kb) * coeff.kb / coeff.kg -
- 2.0 * v_norm * (1.0 - coeff.kr) * coeff.kr / coeff.kg;
- const double b = y_norm + 2.0 * u_norm * (1.0 - coeff.kb);
-
- // Clamp and convert back to 16-bit values
- return RGB16(static_cast<uint16_t>(std::round(std::clamp(r, 0.0, 1.0) * max_value)),
- static_cast<uint16_t>(std::round(std::clamp(g, 0.0, 1.0) * max_value)),
- static_cast<uint16_t>(std::round(std::clamp(b, 0.0, 1.0) * max_value)));
-}
-
-} // namespace kms
diff --git a/kms++util/inc/kms++util/kms++util.h b/kms++util/inc/kms++util/kms++util.h
index 396d18c..be06cab 100644
--- a/kms++util/inc/kms++util/kms++util.h
+++ b/kms++util/inc/kms++util/kms++util.h
@@ -3,7 +3,6 @@
#include <kms++/kms++.h>
#include <kms++util/color.h>
-#include <kms++util/color16.h>
#include <kms++util/strhelpers.h>
#include <kms++util/cpuframebuffer.h>
#include <kms++util/extcpuframebuffer.h>
@@ -18,6 +17,9 @@ namespace kms
{
class IFramebuffer;
+enum class ColorRange { Limited, Full };
+enum class RecStandard { BT601, BT709, BT2020 };
+
void draw_rgb_pixel(IFramebuffer& buf, unsigned x, unsigned y, RGB color);
void draw_yuv444_pixel(IFramebuffer& buf, unsigned x, unsigned y, YUV yuv);
void draw_yuv422_macropixel(IFramebuffer& buf, unsigned x, unsigned y, YUV yuv1, YUV yuv2);
@@ -29,10 +31,6 @@ 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_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;
@@ -40,8 +38,6 @@ struct TestPatternOptions {
};
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]))
@@ -84,23 +80,3 @@ void draw_test_pattern_multi(IFramebuffer& fb, const TestPatternOptions& options
fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
exit(-1); \
}
-
-extern "C" {
-
-struct CDrawTestPatternParameters {
- uint32_t width;
- uint32_t height;
- const char* format_name;
- uint8_t* buffers[4];
- uint32_t sizes[4];
- uint32_t pitches[4];
- uint32_t offsets[4];
-
- const char* pattern;
- uint32_t rec_standard;
- bool full_range;
-};
-
-int c_draw_test_pattern(struct CDrawTestPatternParameters* params);
-
-}
diff --git a/kms++util/meson.build b/kms++util/meson.build
index e2beed6..dcdae8f 100644
--- a/kms++util/meson.build
+++ b/kms++util/meson.build
@@ -19,7 +19,6 @@ libkmsxxutil_sources = files([
public_headers = [
'inc/kms++util/color.h',
- 'inc/kms++util/color16.h',
'inc/kms++util/kms++util.h',
'inc/kms++util/stopwatch.h',
'inc/kms++util/cpuframebuffer.h',
@@ -29,7 +28,7 @@ public_headers = [
'inc/kms++util/resourcemanager.h',
]
-private_includes = include_directories('src', 'inc', '../ext/mdspan/include')
+private_includes = include_directories('src', 'inc')
public_includes = include_directories('inc')
thread_dep = dependency('threads', required : false)
@@ -40,7 +39,11 @@ if thread_dep.found()
libkmsxxutil_args += [ '-DHAS_PTHREAD' ]
endif
-libkmsxxutil_deps = [ libkmsxx_dep, thread_dep ]
+pixpat_proj = subproject('pixpat',
+ default_options : ['config=pixpat-native/profiles/pattern_only.toml'])
+libpixpat_dep = pixpat_proj.get_variable('libpixpat_static_dep')
+
+libkmsxxutil_deps = [ libkmsxx_dep, thread_dep, libpixpat_dep ]
libkmsxxutil = library('kms++util',
libkmsxxutil_sources,
diff --git a/kms++util/src/conv-common.h b/kms++util/src/conv-common.h
deleted file mode 100644
index 837668f..0000000
--- a/kms++util/src/conv-common.h
+++ /dev/null
@@ -1,177 +0,0 @@
-#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
diff --git a/kms++util/src/conv-gray.h b/kms++util/src/conv-gray.h
deleted file mode 100644
index 7fead46..0000000
--- a/kms++util/src/conv-gray.h
+++ /dev/null
@@ -1,130 +0,0 @@
-#pragma once
-
-#include <vector>
-
-#include <kms++/framebuffer.h>
-#include <kms++util/color16.h>
-
-#include "conv-common.h"
-
-namespace kms
-{
-
-/*
- * Grayscale formats
- */
-
-using Y8_Layout = FormatLayout<PlaneLayout<uint8_t,
- ComponentLayout<ComponentType::Y, 8, 0>>>;
-
-using Y10_Layout = FormatLayout<PlaneLayout<uint16_t,
- ComponentLayout<ComponentType::Y, 10, 0>,
- ComponentLayout<ComponentType::X, 4, 10>>>;
-
-using Y12_Layout = FormatLayout<PlaneLayout<uint16_t,
- ComponentLayout<ComponentType::Y, 12, 0>,
- ComponentLayout<ComponentType::X, 4, 12>>>;
-
-using Y16_Layout = FormatLayout<PlaneLayout<uint16_t,
- ComponentLayout<ComponentType::Y, 16, 0>>>;
-
-using XYYY2101010_Layout = FormatLayout<PlaneLayout<uint32_t,
- ComponentLayout<ComponentType::Y, 10, 0>, // Y0
- ComponentLayout<ComponentType::Y, 10, 10>, // Y1
- ComponentLayout<ComponentType::Y, 10, 20>, // Y2
- ComponentLayout<ComponentType::X, 2, 30>
->>;
-
-template<typename Layout> class Y_Writer
-{
- using Plane = typename Layout::template plane<0>;
- using TStorage = typename Plane::storage_type;
-
- static_assert(Layout::num_planes == 1);
- static_assert(Plane::template component_count<ComponentType::Y>() >= 1);
-
- static constexpr bool has_padding =
- Plane::template component_count<ComponentType::X>();
-
- static constexpr size_t y_idx = Plane::template find_pos<ComponentType::Y>();
- static constexpr size_t x_idx =
- has_padding ? Plane::template find_pos<ComponentType::X>() : 0;
-
- static constexpr size_t y_shift = 16 - Plane::template component_size<y_idx>;
-
- static constexpr size_t pixels_in_group =
- Plane::template component_count<ComponentType::Y>();
- static constexpr bool is_packed_format = pixels_in_group > 1;
-
-public:
- // Pack and write num_pixels pixels from src_line to dst_line
- static void pack_line(HasIndexOperatorReturning<TStorage> auto&& dst_line,
- HasIndexOperatorReturning<YUV16> auto&& src_line,
- size_t num_pixels)
- {
- if constexpr (!is_packed_format) {
- // Simple case: one Y component per storage unit
- for (size_t x = 0; x < num_pixels; x++) {
- const YUV16& pix = src_line[x];
-
- std::array<component_storage_type, Plane::num_components>
- components;
-
- if constexpr (has_padding)
- components[x_idx] = 0;
-
- components[y_idx] = pix.y >> y_shift;
-
- dst_line[x] = Plane::pack(components);
- }
- } else {
- write_y_samples(dst_line, src_line, num_pixels);
- }
- }
-
- static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
- auto&& generate_line)
- {
- std::vector<YUV16> linebuf(fb.width());
-
- // View to the plane
- auto view = make_strided_fb_view<TStorage>(fb.map(0), fb.height(),
- fb.width() / pixels_in_group,
- fb.stride(0));
-
- for (size_t y_src = start_y; y_src <= end_y; y_src++) {
- generate_line(y_src, linebuf);
-
- auto dst = md::submdspan(view, y_src, md::full_extent);
-
- pack_line(dst, linebuf, fb.width());
- }
- }
-
-private:
- template<typename YBuf>
- static void write_y_samples(YBuf&& y_view, auto&& linebuf, size_t num_pixels)
- {
- for (size_t x_src = 0; x_src < num_pixels; x_src += pixels_in_group) {
- auto x_dst = x_src / pixels_in_group;
-
- write_y_group(y_view, linebuf, x_src, x_dst,
- std::make_index_sequence<pixels_in_group>{});
- }
- }
-
- template<typename YBuf, size_t... I>
- static void write_y_group(YBuf&& y_view, auto&& linebuf, size_t x_src,
- size_t x_dst, std::index_sequence<I...>)
- {
- std::array<component_storage_type, Plane::num_components> y_values{
- static_cast<component_storage_type>(
- (linebuf[x_src + I].y >>
- (16 - Plane::template component_size<I>)))...
- };
-
- y_view[x_dst] = Plane::pack(y_values);
- }
-};
-
-} // namespace kms \ No newline at end of file
diff --git a/kms++util/src/conv-raw-packed.h b/kms++util/src/conv-raw-packed.h
deleted file mode 100644
index 7465c6b..0000000
--- a/kms++util/src/conv-raw-packed.h
+++ /dev/null
@@ -1,230 +0,0 @@
-#pragma once
-
-#include <vector>
-
-#include <kms++/framebuffer.h>
-#include <kms++util/color16.h>
-
-#include "conv-common.h"
-#include "conv-raw.h"
-
-namespace kms
-{
-
-/*
- * Raw Bayer Packed formats (MIPI CSI-2)
- */
-
-template<BayerOrder Order, size_t BitDepth>
-struct BayerPacked_Layout;
-
-// 10-bit packed bayer formats - 4 pixels (40 bits) in 5 bytes
-template<BayerOrder Order>
-struct BayerPacked_Layout<Order, 10>
- : public FormatLayout<PlaneLayout<uint8_t,
- ComponentLayout<ComponentType::Y, 8, 0>>>
-{
- static constexpr BayerOrder bayer_order = Order;
- static constexpr size_t bit_depth = 10;
- static constexpr size_t pixels_per_group = 4;
- static constexpr size_t bytes_per_group = 5;
-};
-
-// 12-bit packed bayer formats - 2 pixels (24 bits) in 3 bytes
-template<BayerOrder Order>
-struct BayerPacked_Layout<Order, 12>
- : public FormatLayout<PlaneLayout<uint8_t,
- ComponentLayout<ComponentType::Y, 8, 0>>>
-{
- static constexpr BayerOrder bayer_order = Order;
- static constexpr size_t bit_depth = 12;
- static constexpr size_t pixels_per_group = 2;
- static constexpr size_t bytes_per_group = 3;
-};
-
-// Convenient aliases for different bit depths
-template<BayerOrder Order> using BayerPacked10_Layout = BayerPacked_Layout<Order, 10>;
-template<BayerOrder Order> using BayerPacked12_Layout = BayerPacked_Layout<Order, 12>;
-
-// Format-specific type aliases
-using SRGGB10P_Layout = BayerPacked10_Layout<BayerOrder::RGGB>;
-using SGBRG10P_Layout = BayerPacked10_Layout<BayerOrder::GBRG>;
-using SGRBG10P_Layout = BayerPacked10_Layout<BayerOrder::GRBG>;
-using SBGGR10P_Layout = BayerPacked10_Layout<BayerOrder::BGGR>;
-
-using SRGGB12P_Layout = BayerPacked12_Layout<BayerOrder::RGGB>;
-using SGBRG12P_Layout = BayerPacked12_Layout<BayerOrder::GBRG>;
-using SGRBG12P_Layout = BayerPacked12_Layout<BayerOrder::GRBG>;
-using SBGGR12P_Layout = BayerPacked12_Layout<BayerOrder::BGGR>;
-
-template<typename Layout>
-class BayerPacked_Writer
-{
- using Plane = typename Layout::template plane<0>;
- using TStorage = typename Plane::storage_type;
-
- static_assert(Layout::num_planes == 1);
- static_assert(std::is_same_v<TStorage, uint8_t>);
-
- static constexpr BayerOrder bayer_order = Layout::bayer_order;
- static constexpr size_t bit_depth = Layout::bit_depth;
- static constexpr size_t pixels_per_group = Layout::pixels_per_group;
- static constexpr size_t bytes_per_group = Layout::bytes_per_group;
-
- static constexpr ComponentType get_bayer_component(size_t x, size_t y)
- {
- const bool x_even = (x % 2) == 0;
- const bool y_even = (y % 2) == 0;
-
- switch (bayer_order) {
- case BayerOrder::RGGB:
- if (y_even && x_even) return ComponentType::R;
- if (y_even && !x_even) return ComponentType::G;
- if (!y_even && x_even) return ComponentType::G;
- return ComponentType::B;
-
- case BayerOrder::BGGR:
- if (y_even && x_even) return ComponentType::B;
- if (y_even && !x_even) return ComponentType::G;
- if (!y_even && x_even) return ComponentType::G;
- return ComponentType::R;
-
- case BayerOrder::GRBG:
- if (y_even && x_even) return ComponentType::G;
- if (y_even && !x_even) return ComponentType::R;
- if (!y_even && x_even) return ComponentType::B;
- return ComponentType::G;
-
- case BayerOrder::GBRG:
- if (y_even && x_even) return ComponentType::G;
- if (y_even && !x_even) return ComponentType::B;
- if (!y_even && x_even) return ComponentType::R;
- return ComponentType::G;
- }
-
- return ComponentType::Y; // fallback
- }
-
- static uint16_t extract_component(const RGB16& pix, ComponentType component)
- {
- switch (component) {
- case ComponentType::R:
- return pix.r;
- case ComponentType::G:
- return pix.g;
- case ComponentType::B:
- return pix.b;
- default:
- return 0;
- }
- }
-
- // Pack 10-bit pixels: 4 pixels (40 bits) into 5 bytes
- static void pack_10bit_group(uint8_t* dst, const std::array<uint16_t, 4>& values)
- {
- // Convert from 16-bit to 10-bit values
- const uint16_t p0 = values[0] >> 6;
- const uint16_t p1 = values[1] >> 6;
- const uint16_t p2 = values[2] >> 6;
- const uint16_t p3 = values[3] >> 6;
-
- // Pack MSB 8 bits of each pixel
- dst[0] = (p0 >> 2) & 0xFF;
- dst[1] = (p1 >> 2) & 0xFF;
- dst[2] = (p2 >> 2) & 0xFF;
- dst[3] = (p3 >> 2) & 0xFF;
-
- // Pack LSB 2 bits of each pixel into 5th byte
- dst[4] = ((p0 & 0x03) << 6) |
- ((p1 & 0x03) << 4) |
- ((p2 & 0x03) << 2) |
- ((p3 & 0x03) << 0);
- }
-
- // Pack 12-bit pixels: 2 pixels (24 bits) into 3 bytes
- static void pack_12bit_group(uint8_t* dst, const std::array<uint16_t, 2>& values)
- {
- // Convert from 16-bit to 12-bit values
- const uint16_t p0 = values[0] >> 4;
- const uint16_t p1 = values[1] >> 4;
-
- // Pack MSB 8 bits of each pixel
- dst[0] = (p0 >> 4) & 0xFF;
- dst[1] = (p1 >> 4) & 0xFF;
-
- // Pack LSB 4 bits of each pixel into 3rd byte
- dst[2] = ((p0 & 0x0F) << 4) |
- ((p1 & 0x0F) << 0);
- }
-
-public:
- static void pack_line(HasIndexOperatorReturning<TStorage> auto&& dst_line,
- HasIndexOperatorReturning<RGB16> auto&& src_line,
- size_t num_pixels, size_t y)
- {
- if constexpr (bit_depth == 10) {
- // Process 4 pixels at a time for 10-bit packed
- for (size_t x = 0; x < num_pixels; x += pixels_per_group) {
- std::array<uint16_t, 4> pixel_values;
-
- for (size_t i = 0; i < pixels_per_group && (x + i) < num_pixels; i++) {
- const RGB16& pix = src_line[x + i];
- const ComponentType component = get_bayer_component(x + i, y);
- pixel_values[i] = extract_component(pix, component);
- }
-
- // Fill remaining pixels with 0 if at end of line
- for (size_t i = num_pixels - x; i < pixels_per_group; i++) {
- pixel_values[i] = 0;
- }
-
- const size_t group_idx = x / pixels_per_group;
- uint8_t* dst_bytes = reinterpret_cast<uint8_t*>(&dst_line[0]);
- pack_10bit_group(dst_bytes + group_idx * bytes_per_group, pixel_values);
- }
- } else if constexpr (bit_depth == 12) {
- // Process 2 pixels at a time for 12-bit packed
- for (size_t x = 0; x < num_pixels; x += pixels_per_group) {
- std::array<uint16_t, 2> pixel_values;
-
- for (size_t i = 0; i < pixels_per_group && (x + i) < num_pixels; i++) {
- const RGB16& pix = src_line[x + i];
- const ComponentType component = get_bayer_component(x + i, y);
- pixel_values[i] = extract_component(pix, component);
- }
-
- // Fill remaining pixels with 0 if at end of line
- for (size_t i = num_pixels - x; i < pixels_per_group; i++) {
- pixel_values[i] = 0;
- }
-
- const size_t group_idx = x / pixels_per_group;
- uint8_t* dst_bytes = reinterpret_cast<uint8_t*>(&dst_line[0]);
- pack_12bit_group(dst_bytes + group_idx * bytes_per_group, pixel_values);
- }
- }
- }
-
- static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
- auto&& generate_line)
- {
- std::vector<RGB16> linebuf(fb.width());
-
- // For packed formats, the stride represents bytes per line
- // We need to calculate the correct width in bytes for the view
- const size_t bytes_per_line = fb.stride(0);
-
- auto view = make_strided_fb_view<TStorage>(fb.map(0), fb.height(),
- bytes_per_line, fb.stride(0));
-
- for (size_t y_src = start_y; y_src <= end_y; y_src++) {
- generate_line(y_src, linebuf);
-
- auto dst = md::submdspan(view, y_src, md::full_extent);
-
- pack_line(dst, linebuf, fb.width(), y_src);
- }
- }
-};
-
-} // namespace kms
diff --git a/kms++util/src/conv-raw.h b/kms++util/src/conv-raw.h
deleted file mode 100644
index a0752d3..0000000
--- a/kms++util/src/conv-raw.h
+++ /dev/null
@@ -1,202 +0,0 @@
-#pragma once
-
-#include <vector>
-
-#include <kms++/framebuffer.h>
-#include <kms++util/color16.h>
-
-#include "conv-common.h"
-
-namespace kms
-{
-
-/*
- * Raw Bayer formats
- */
-
-enum class BayerOrder {
- RGGB,
- BGGR,
- GRBG,
- GBRG
-};
-
-template<BayerOrder Order, size_t BitDepth>
-struct Bayer_Layout;
-
-// 8-bit bayer formats (uint8_t storage)
-template<BayerOrder Order>
-struct Bayer_Layout<Order, 8>
- : public FormatLayout<PlaneLayout<uint8_t,
- ComponentLayout<ComponentType::Y, 8, 0>>>
-{
- static constexpr BayerOrder bayer_order = Order;
- static constexpr size_t bit_depth = 8;
-};
-
-// 10-bit bayer formats (uint16_t storage)
-template<BayerOrder Order>
-struct Bayer_Layout<Order, 10>
- : public FormatLayout<PlaneLayout<uint16_t,
- ComponentLayout<ComponentType::Y, 10, 0>,
- ComponentLayout<ComponentType::X, 6, 10>>>
-{
- static constexpr BayerOrder bayer_order = Order;
- static constexpr size_t bit_depth = 10;
-};
-
-// 12-bit bayer formats (uint16_t storage)
-template<BayerOrder Order>
-struct Bayer_Layout<Order, 12>
- : public FormatLayout<PlaneLayout<uint16_t,
- ComponentLayout<ComponentType::Y, 12, 0>,
- ComponentLayout<ComponentType::X, 4, 12>>>
-{
- static constexpr BayerOrder bayer_order = Order;
- static constexpr size_t bit_depth = 12;
-};
-
-// 16-bit bayer formats (uint16_t storage)
-template<BayerOrder Order>
-struct Bayer_Layout<Order, 16>
- : public FormatLayout<PlaneLayout<uint16_t,
- ComponentLayout<ComponentType::Y, 16, 0>>>
-{
- static constexpr BayerOrder bayer_order = Order;
- static constexpr size_t bit_depth = 16;
-};
-
-// Convenient aliases for different bit depths
-template<BayerOrder Order> using Bayer8_Layout = Bayer_Layout<Order, 8>;
-template<BayerOrder Order> using Bayer10_Layout = Bayer_Layout<Order, 10>;
-template<BayerOrder Order> using Bayer12_Layout = Bayer_Layout<Order, 12>;
-template<BayerOrder Order> using Bayer16_Layout = Bayer_Layout<Order, 16>;
-
-// Format-specific type aliases
-using SRGGB8_Layout = Bayer8_Layout<BayerOrder::RGGB>;
-using SGBRG8_Layout = Bayer8_Layout<BayerOrder::GBRG>;
-using SGRBG8_Layout = Bayer8_Layout<BayerOrder::GRBG>;
-using SBGGR8_Layout = Bayer8_Layout<BayerOrder::BGGR>;
-
-using SRGGB10_Layout = Bayer10_Layout<BayerOrder::RGGB>;
-using SGBRG10_Layout = Bayer10_Layout<BayerOrder::GBRG>;
-using SGRBG10_Layout = Bayer10_Layout<BayerOrder::GRBG>;
-using SBGGR10_Layout = Bayer10_Layout<BayerOrder::BGGR>;
-
-using SRGGB12_Layout = Bayer12_Layout<BayerOrder::RGGB>;
-using SGBRG12_Layout = Bayer12_Layout<BayerOrder::GBRG>;
-using SGRBG12_Layout = Bayer12_Layout<BayerOrder::GRBG>;
-using SBGGR12_Layout = Bayer12_Layout<BayerOrder::BGGR>;
-
-using SRGGB16_Layout = Bayer16_Layout<BayerOrder::RGGB>;
-using SGBRG16_Layout = Bayer16_Layout<BayerOrder::GBRG>;
-using SGRBG16_Layout = Bayer16_Layout<BayerOrder::GRBG>;
-using SBGGR16_Layout = Bayer16_Layout<BayerOrder::BGGR>;
-
-template<typename Layout>
-class Bayer_Writer
-{
- using Plane = typename Layout::template plane<0>;
- using TStorage = typename Plane::storage_type;
-
- static_assert(Layout::num_planes == 1);
- static_assert(Plane::template component_count<ComponentType::Y>() == 1);
-
- static constexpr BayerOrder bayer_order = Layout::bayer_order;
- static constexpr size_t bit_depth = Layout::bit_depth;
- static constexpr bool has_padding = Plane::template component_count<ComponentType::X>();
-
- static constexpr size_t y_idx = Plane::template find_pos<ComponentType::Y>();
- static constexpr size_t x_idx = has_padding ? Plane::template find_pos<ComponentType::X>() : 0;
-
- static constexpr size_t y_shift = 16 - Plane::template component_size<y_idx>;
-
- static constexpr ComponentType get_bayer_component(size_t x, size_t y)
- {
- const bool x_even = (x % 2) == 0;
- const bool y_even = (y % 2) == 0;
-
- switch (bayer_order) {
- case BayerOrder::RGGB:
- if (y_even && x_even) return ComponentType::R;
- if (y_even && !x_even) return ComponentType::G;
- if (!y_even && x_even) return ComponentType::G;
- return ComponentType::B;
-
- case BayerOrder::BGGR:
- if (y_even && x_even) return ComponentType::B;
- if (y_even && !x_even) return ComponentType::G;
- if (!y_even && x_even) return ComponentType::G;
- return ComponentType::R;
-
- case BayerOrder::GRBG:
- if (y_even && x_even) return ComponentType::G;
- if (y_even && !x_even) return ComponentType::R;
- if (!y_even && x_even) return ComponentType::B;
- return ComponentType::G;
-
- case BayerOrder::GBRG:
- if (y_even && x_even) return ComponentType::G;
- if (y_even && !x_even) return ComponentType::B;
- if (!y_even && x_even) return ComponentType::R;
- return ComponentType::G;
- }
-
- return ComponentType::Y; // fallback
- }
-
- static uint16_t extract_component(const RGB16& pix, ComponentType component)
- {
- switch (component) {
- case ComponentType::R:
- return pix.r;
- case ComponentType::G:
- return pix.g;
- case ComponentType::B:
- return pix.b;
- default:
- return 0;
- }
- }
-
-public:
- static void pack_line(HasIndexOperatorReturning<TStorage> auto&& dst_line,
- HasIndexOperatorReturning<RGB16> auto&& src_line,
- size_t num_pixels, size_t y)
- {
- for (size_t x = 0; x < num_pixels; x++) {
- const RGB16& pix = src_line[x];
-
- const ComponentType component = get_bayer_component(x, y);
- const uint16_t value = extract_component(pix, component);
-
- std::array<component_storage_type, Plane::num_components> components;
-
- if constexpr (has_padding)
- components[x_idx] = 0;
-
- components[y_idx] = value >> y_shift;
-
- dst_line[x] = Plane::pack(components);
- }
- }
-
- static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
- auto&& generate_line)
- {
- std::vector<RGB16> linebuf(fb.width());
-
- auto view = make_strided_fb_view<TStorage>(fb.map(0), fb.height(), fb.width(),
- fb.stride(0));
-
- for (size_t y_src = start_y; y_src <= end_y; y_src++) {
- generate_line(y_src, linebuf);
-
- auto dst = md::submdspan(view, y_src, md::full_extent);
-
- pack_line(dst, linebuf, fb.width(), y_src);
- }
- }
-};
-
-} // namespace kms
diff --git a/kms++util/src/conv-rgb.h b/kms++util/src/conv-rgb.h
deleted file mode 100644
index 6993247..0000000
--- a/kms++util/src/conv-rgb.h
+++ /dev/null
@@ -1,299 +0,0 @@
-#pragma once
-
-#include <vector>
-
-#include <kms++/framebuffer.h>
-#include <kms++util/color16.h>
-
-#include "conv-common.h"
-
-namespace kms
-{
-
-/*
- * RGB
- */
-
-template<ComponentType C3, size_t size3, size_t offset3,
- ComponentType C2, size_t size2, size_t offset2,
- ComponentType C1, size_t size1, size_t offset1,
- ComponentType C0, size_t size0, size_t offset0>
-struct RGB_16_Layout
- : public FormatLayout<PlaneLayout<uint16_t,
- ComponentLayout<C0, size0, offset0>,
- ComponentLayout<C1, size1, offset1>,
- ComponentLayout<C2, size2, offset2>,
- ComponentLayout<C3, size3, offset3>>>
-{
-};
-
-using XRGB4444_Layout = RGB_16_Layout<
- ComponentType::X, 4, 12,
- ComponentType::R, 4, 8,
- ComponentType::G, 4, 4,
- ComponentType::B, 4, 0
->;
-
-using ARGB4444_Layout = RGB_16_Layout<
- ComponentType::A, 4, 12,
- ComponentType::R, 4, 8,
- ComponentType::G, 4, 4,
- ComponentType::B, 4, 0
->;
-
-using XRGB1555_Layout = RGB_16_Layout<
- ComponentType::X, 1, 15,
- ComponentType::R, 5, 10,
- ComponentType::G, 5, 5,
- ComponentType::B, 5, 0
->;
-
-using ARGB1555_Layout = RGB_16_Layout<
- ComponentType::A, 1, 15,
- ComponentType::R, 5, 10,
- ComponentType::G, 5, 5,
- ComponentType::B, 5, 0
->;
-
-using RGB565_Layout = FormatLayout<PlaneLayout<uint16_t,
- ComponentLayout<ComponentType::R, 5, 11>,
- ComponentLayout<ComponentType::G, 6, 5>,
- ComponentLayout<ComponentType::B, 5, 0>>
->;
-
-using BGR565_Layout = FormatLayout<PlaneLayout<uint16_t,
- ComponentLayout<ComponentType::B, 5, 11>,
- ComponentLayout<ComponentType::G, 6, 5>,
- ComponentLayout<ComponentType::R, 5, 0>>
->;
-
-using RGB888_Layout = FormatLayout<PlaneLayout<uint32_t,
- ComponentLayout<ComponentType::R, 8, 16>,
- ComponentLayout<ComponentType::G, 8, 8>,
- ComponentLayout<ComponentType::B, 8, 0>>
->;
-
-using BGR888_Layout = FormatLayout<PlaneLayout<uint32_t,
- ComponentLayout<ComponentType::B, 8, 16>,
- ComponentLayout<ComponentType::G, 8, 8>,
- ComponentLayout<ComponentType::R, 8, 0>>
->;
-
-template<ComponentType C3, size_t size3, size_t offset3,
- ComponentType C2, size_t size2, size_t offset2,
- ComponentType C1, size_t size1, size_t offset1,
- ComponentType C0, size_t size0, size_t offset0>
-struct RGB_32_Layout
- : public FormatLayout<PlaneLayout<uint32_t,
- ComponentLayout<C0, size0, offset0>,
- ComponentLayout<C1, size1, offset1>,
- ComponentLayout<C2, size2, offset2>,
- ComponentLayout<C3, size3, offset3>>>
-{
-};
-
-template<ComponentType C3, ComponentType C2, ComponentType C1, ComponentType C0>
-struct RGB_8_32_Layout
- : public RGB_32_Layout<
- C0, 8, 0,
- C1, 8, 8,
- C2, 8, 16,
- C3, 8, 24>
-{
-};
-
-using XRGB8888_Layout = RGB_8_32_Layout<ComponentType::X, ComponentType::R, ComponentType::G, ComponentType::B>;
-using ARGB8888_Layout = RGB_8_32_Layout<ComponentType::A, ComponentType::R, ComponentType::G, ComponentType::B>;
-
-using XBGR8888_Layout = RGB_8_32_Layout<ComponentType::X, ComponentType::B, ComponentType::G, ComponentType::R>;
-using ABGR8888_Layout = RGB_8_32_Layout<ComponentType::A, ComponentType::B, ComponentType::G, ComponentType::R>;
-
-using RGBX8888_Layout = RGB_8_32_Layout<ComponentType::R, ComponentType::G, ComponentType::B, ComponentType::X>;
-using RGBA8888_Layout = RGB_8_32_Layout<ComponentType::R, ComponentType::G, ComponentType::B, ComponentType::A>;
-
-using BGRX8888_Layout = RGB_8_32_Layout<ComponentType::B, ComponentType::G, ComponentType::R, ComponentType::X>;
-using BGRA8888_Layout = RGB_8_32_Layout<ComponentType::B, ComponentType::G, ComponentType::R, ComponentType::A>;
-
-using XRGB2101010_Layout = RGB_32_Layout<
- ComponentType::X, 2, 30,
- ComponentType::R, 10, 20,
- ComponentType::G, 10, 10,
- ComponentType::B, 10, 0
->;
-
-using ARGB2101010_Layout = RGB_32_Layout<
- ComponentType::A, 2, 30,
- ComponentType::R, 10, 20,
- ComponentType::G, 10, 10,
- ComponentType::B, 10, 0
->;
-
-using XBGR2101010_Layout = RGB_32_Layout<
- ComponentType::X, 2, 30,
- ComponentType::B, 10, 20,
- ComponentType::G, 10, 10,
- ComponentType::R, 10, 0
->;
-
-using ABGR2101010_Layout = RGB_32_Layout<
- ComponentType::A, 2, 30,
- ComponentType::B, 10, 20,
- ComponentType::G, 10, 10,
- ComponentType::R, 10, 0
->;
-
-using RGBX1010102_Layout = RGB_32_Layout<
- ComponentType::R, 10, 22,
- ComponentType::G, 10, 12,
- ComponentType::B, 10, 2,
- ComponentType::X, 2, 0
->;
-
-using RGBA1010102_Layout = RGB_32_Layout<
- ComponentType::R, 10, 22,
- ComponentType::G, 10, 12,
- ComponentType::B, 10, 2,
- ComponentType::A, 2, 0
->;
-
-using BGRX1010102_Layout = RGB_32_Layout<
- ComponentType::B, 10, 22,
- ComponentType::G, 10, 12,
- ComponentType::R, 10, 2,
- ComponentType::X, 2, 0
->;
-
-using BGRA1010102_Layout = RGB_32_Layout<
- ComponentType::B, 10, 22,
- ComponentType::G, 10, 12,
- ComponentType::R, 10, 2,
- ComponentType::A, 2, 0
->;
-
-template<typename Layout>
-class ARGB_Writer
-{
- using Plane = typename Layout::template plane<0>;
- using TStorage = typename Plane::storage_type;
-
- static_assert(Layout::num_planes == 1);
- static_assert(Plane::num_components == 3 || Plane::num_components == 4);
-
- static_assert(Plane::template component_count<ComponentType::R>() == 1);
- static_assert(Plane::template component_count<ComponentType::G>() == 1);
- static_assert(Plane::template component_count<ComponentType::B>() == 1);
-
- static constexpr bool has_alpha = Plane::template component_count<ComponentType::A>();
- static constexpr bool has_padding = Plane::template component_count<ComponentType::X>();
-
- static constexpr bool needs_packed_access = Plane::total_bits != Plane::storage_bits;
-
- static constexpr size_t a_idx = Plane::template find_pos<ComponentType::A>();
- static constexpr size_t x_idx = Plane::template find_pos<ComponentType::X>();
- static constexpr size_t r_idx = Plane::template find_pos<ComponentType::R>();
- static constexpr size_t g_idx = Plane::template find_pos<ComponentType::G>();
- static constexpr size_t b_idx = Plane::template find_pos<ComponentType::B>();
-
- static constexpr size_t a_shift = has_alpha ? 16 - Plane::template component_size<a_idx> : 0;
- static constexpr size_t r_shift = 16 - Plane::template component_size<r_idx>;
- static constexpr size_t g_shift = 16 - Plane::template component_size<g_idx>;
- static constexpr size_t b_shift = 16 - Plane::template component_size<b_idx>;
-
- static_assert(Plane::total_bits % 8 == 0);
- static constexpr size_t bytes_per_pixel = Plane::total_bits / 8;
-
-public:
- // Pack and write num_pixels pixels from src_line to dst_line
- static void pack_line(HasIndexOperatorReturning<TStorage> auto&& dst_line,
- HasIndexOperatorReturning<RGB16> auto&& src_line,
- size_t num_pixels)
- {
- for (size_t x = 0; x < num_pixels; x++) {
- const RGB16& pix = src_line[x];
-
- std::array<component_storage_type, Plane::num_components>
- components;
-
- if constexpr (has_alpha)
- components[a_idx] = pix.a >> a_shift;
-
- if constexpr (has_padding)
- components[x_idx] = 0;
-
- components[r_idx] = pix.r >> r_shift;
- components[g_idx] = pix.g >> g_shift;
- components[b_idx] = pix.b >> b_shift;
-
- if constexpr (!needs_packed_access) {
- dst_line[x] = Plane::pack(components);
- } else {
- auto dst_bytes = reinterpret_cast<uint8_t*>(&dst_line[0]);
-
- TStorage packed = Plane::pack(components);
-
- memcpy(dst_bytes + x * bytes_per_pixel, &packed,
- bytes_per_pixel);
- }
- }
- }
-
- // Read and unpack num_pixels pixels from src_line to dst_line
- static void unpack_line(HasIndexOperatorReturning<RGB16> auto&& dst_line,
- HasIndexOperatorReturning<TStorage> auto&& src_line,
- size_t num_pixels)
- {
- for (size_t x = 0; x < num_pixels; x++) {
- decltype(Plane::unpack(src_line[x])) components;
-
- if constexpr (!needs_packed_access) {
- components = Plane::unpack(src_line[x]);
- } else {
- auto src_bytes =
- reinterpret_cast<const uint8_t*>(&src_line[0]);
- TStorage packed;
-
- memcpy(&packed, src_bytes + x * bytes_per_pixel,
- bytes_per_pixel);
-
- components = Plane::unpack(packed);
- }
-
- dst_line[x] = RGB16 {
- static_cast<uint16_t>(components[r_idx] << r_shift),
- static_cast<uint16_t>(components[g_idx] << g_shift),
- static_cast<uint16_t>(components[b_idx] << b_shift),
- static_cast<uint16_t>(has_alpha ? components[a_idx] << a_shift : 0),
- };
- }
- }
-
- static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
- auto&& generate_line)
- {
- std::vector<RGB16> linebuf(fb.width());
-
- // View to the plane
- auto view = make_strided_fb_view<TStorage>(fb.map(0), fb.height(), fb.width(),
- fb.stride(0));
-
- for (size_t y_src = start_y; y_src <= end_y; y_src++) {
- generate_line(y_src, linebuf);
-
- auto dst = md::submdspan(view, y_src, md::full_extent);
-
- pack_line(dst, linebuf, fb.width());
- }
- }
-
- static void get_line(IFramebuffer& fb, size_t w, size_t h, size_t row, std::span<RGB16> linebuf)
- {
- auto view = make_strided_fb_view<const TStorage>(fb.map(0), fb.height(), fb.width(),
- fb.stride(0));
-
- auto src = md::submdspan(view, row, md::full_extent);
-
- unpack_line(linebuf, src);
- }
-};
-
-} // namespace kms
diff --git a/kms++util/src/conv-yuv-packed.h b/kms++util/src/conv-yuv-packed.h
deleted file mode 100644
index 01278ef..0000000
--- a/kms++util/src/conv-yuv-packed.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#pragma once
-
-#include <vector>
-
-#include <kms++/framebuffer.h>
-#include <kms++util/color16.h>
-
-#include "conv-common.h"
-
-namespace kms
-{
-
-/* YUV Packed */
-
-template<ComponentType C0, ComponentType C1, ComponentType C2, ComponentType C3>
-struct YUV_Packed_Format
- : public FormatLayout<
- PlaneLayout<uint32_t,
- ComponentLayout<C0, 8, 0>,
- ComponentLayout<C1, 8, 8>,
- ComponentLayout<C2, 8, 16>,
- ComponentLayout<C3, 8, 24>
- >
- >
-{
-};
-
-// Define common packed YUV formats
-using YUYV_Layout = YUV_Packed_Format<ComponentType::Y0, ComponentType::Cb,
- ComponentType::Y1, ComponentType::Cr>;
-
-using YVYU_Layout = YUV_Packed_Format<ComponentType::Y0, ComponentType::Cr,
- ComponentType::Y1, ComponentType::Cb>;
-
-using UYVY_Layout = YUV_Packed_Format<ComponentType::Cb, ComponentType::Y0,
- ComponentType::Cr, ComponentType::Y1>;
-
-using VYUY_Layout = YUV_Packed_Format<ComponentType::Cr, ComponentType::Y0,
- ComponentType::Cb, ComponentType::Y1>;
-
-template<typename Layout>
-class YUVPackedWriter
-{
- using Plane = typename Layout::template plane<0>;
- using TStorage = typename Plane::storage_type;
-
- static constexpr size_t y0_pos = Plane::template find_pos<ComponentType::Y0>();
- static constexpr size_t y1_pos = Plane::template find_pos<ComponentType::Y1>();
- static constexpr size_t cb_pos = Plane::template find_pos<ComponentType::Cb>();
- static constexpr size_t cr_pos = Plane::template find_pos<ComponentType::Cr>();
-
-public:
- static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
- auto&& generate_line)
- {
- std::vector<YUV16> linebuf(fb.width());
-
- auto view = make_strided_fb_view<TStorage>(fb.map(0), fb.height(),
- fb.width() / 2, // Two pixels per storage unit
- fb.stride(0));
-
- for (size_t y = start_y; y <= end_y; y++) {
- generate_line(y, linebuf);
-
- for (size_t x = 0; x < fb.width(); x += 2) {
- // Get two pixels
- const YUV16& pix0 = linebuf[x];
- const YUV16& pix1 = linebuf[x + 1];
-
- std::array<uint8_t, 4> components;
-
- components[y0_pos] = pix0.y >> 8;
- components[y1_pos] = pix1.y >> 8;
- components[cb_pos] = ((pix0.u + pix1.u) / 2) >> 8;
- components[cr_pos] = ((pix0.v + pix1.v) / 2) >> 8;
-
- view(y, x / 2) = Plane::pack(components);
- }
- }
- }
-};
-
-} // namespace kms
diff --git a/kms++util/src/conv-yuv-planar-packed.h b/kms++util/src/conv-yuv-planar-packed.h
deleted file mode 100644
index 481b594..0000000
--- a/kms++util/src/conv-yuv-planar-packed.h
+++ /dev/null
@@ -1,125 +0,0 @@
-#pragma once
-
-#include <vector>
-
-#include <kms++/framebuffer.h>
-#include <kms++util/color16.h>
-
-#include "conv-common.h"
-
-namespace kms
-{
-/* YUV Planar Packed (only T430 for now) */
-
-struct T430_Layout : FormatLayout <
- PlaneLayout<uint32_t,
- ComponentLayout<ComponentType::Y, 10, 0>,
- ComponentLayout<ComponentType::Y, 10, 10>,
- ComponentLayout<ComponentType::Y, 10, 20>,
- ComponentLayout<ComponentType::X, 2, 30>>,
- PlaneLayout<uint32_t,
- ComponentLayout<ComponentType::Cb, 10, 0>,
- ComponentLayout<ComponentType::Cb, 10, 10>,
- ComponentLayout<ComponentType::Cb, 10, 20>,
- ComponentLayout<ComponentType::X, 2, 30>>,
- PlaneLayout<uint32_t,
- ComponentLayout<ComponentType::Cr, 10, 0>,
- ComponentLayout<ComponentType::Cr, 10, 10>,
- ComponentLayout<ComponentType::Cr, 10, 20>,
- ComponentLayout<ComponentType::X, 2, 30>>
- >
-{
- static constexpr size_t y_plane = 0;
- static constexpr size_t cb_plane = 1;
- static constexpr size_t cr_plane = 2;
-
-};
-
-template<typename Format>
-class YUVPlanarPackedWriter
-{
- using YLayout = typename Format::template plane<Format::y_plane>;
- using CbLayout = typename Format::template plane<Format::cb_plane>;
- using CrLayout = typename Format::template plane<Format::cr_plane>;
-
- using TY = typename YLayout::storage_type;
- using TCb = typename CbLayout::storage_type;
- using TCr = typename CrLayout::storage_type;
-
- static constexpr size_t pixels_in_group = 3;
-
- // Helper to extract the correct component based on component type
- template<ComponentType CType>
- static uint16_t extract_component(const YUV16& pixel)
- {
- if constexpr (CType == ComponentType::Y)
- return pixel.y;
- else if constexpr (CType == ComponentType::Cb)
- return pixel.u;
- else if constexpr (CType == ComponentType::Cr)
- return pixel.v;
- else
- return 0; // For padding or other component types
- }
-
-public:
- static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
- auto&& generate_line)
- {
- // Line buffers
- std::vector<YUV16> linebuf(fb.width());
-
- // Views to all planes
- auto y_buf = make_strided_fb_view<TY>(fb.map(Format::y_plane),
- fb.height(), fb.width(),
- fb.stride(Format::y_plane));
-
- auto cb_buf = make_strided_fb_view<TCb>(fb.map(Format::cb_plane),
- fb.height(), fb.width(),
- fb.stride(Format::cb_plane));
-
- auto cr_buf = make_strided_fb_view<TCr>(fb.map(Format::cr_plane),
- fb.height(), fb.width(),
- fb.stride(Format::cr_plane));
-
- for (size_t y_src = start_y; y_src <= end_y; y_src++) {
- generate_line(y_src, linebuf);
-
- write_samples<YLayout, ComponentType::Y>(md::submdspan(y_buf, y_src, md::full_extent), linebuf, fb.width());
- write_samples<CbLayout, ComponentType::Cb>(md::submdspan(cb_buf, y_src, md::full_extent), linebuf, fb.width());
- write_samples<CrLayout, ComponentType::Cr>(md::submdspan(cr_buf, y_src, md::full_extent), linebuf, fb.width());
- }
- }
-
-
-private:
- template<typename Plane, ComponentType CType, typename Buf>
- static void write_samples(Buf&& view, auto&& linebuf, size_t num_pixels)
- {
- for (size_t x_src = 0; x_src < num_pixels; x_src += pixels_in_group) {
- auto x_dst = x_src / pixels_in_group;
-
- write_group<Plane, CType>(view, linebuf, x_src, x_dst,
- std::make_index_sequence<pixels_in_group>{});
- }
- }
-
- template<typename Plane, ComponentType CType, typename YBuf, size_t... I>
- static void write_group(YBuf&& view, auto&& linebuf, size_t x_src,
- size_t x_dst, std::index_sequence<I...>)
- {
- std::array<component_storage_type, Plane::num_components> values{
- static_cast<component_storage_type>(
- (extract_component<CType>(linebuf[x_src + I]) >>
- (16 - Plane::template component_size<I>)))...
- };
-
- // Set padding bits to 0
- if constexpr (Plane::template component_count<ComponentType::X>())
- values[Plane::template find_pos<ComponentType::X>()] = 0;
-
- view[x_dst] = Plane::pack(values);
- }
-};
-
-} // namespace kms
diff --git a/kms++util/src/conv-yuv-planar.h b/kms++util/src/conv-yuv-planar.h
deleted file mode 100644
index b8e9247..0000000
--- a/kms++util/src/conv-yuv-planar.h
+++ /dev/null
@@ -1,214 +0,0 @@
-#pragma once
-
-#include <vector>
-
-#include <kms++/framebuffer.h>
-#include <kms++util/color16.h>
-
-#include "conv-common.h"
-
-namespace kms
-{
-/* YUV Planar */
-
-template<ComponentType P1, ComponentType P2, size_t HSubUV = 1, size_t VSubUV = 1>
-class YUV_Planar_Layout
- : public FormatLayout<
- PlaneLayout<uint8_t, ComponentLayout<ComponentType::Y, 8, 0>>,
- PlaneLayout<uint8_t, ComponentLayout<P1, 8, 0>>,
- PlaneLayout<uint8_t, ComponentLayout<P2, 8, 0>>
- >
-{
-public:
- static constexpr std::array<ComponentType, 2> uv_order = { P1, P2 };
- static constexpr size_t h_sub = HSubUV;
- static constexpr size_t v_sub = VSubUV;
-
- template<ComponentType P>
- static constexpr size_t find_plane()
- {
- return 1 + (std::ranges::find(uv_order, P) - uv_order.begin());
- }
-
- static constexpr size_t y_plane = 0; // Y is always plane 0
- static constexpr size_t cb_plane = find_plane<ComponentType::Cb>();
- static constexpr size_t cr_plane = find_plane<ComponentType::Cr>();
-};
-
-using YUV444_Layout = YUV_Planar_Layout<ComponentType::Cb, ComponentType::Cr>;
-using YVU444_Layout = YUV_Planar_Layout<ComponentType::Cr, ComponentType::Cb>;
-using YUV422_Layout = YUV_Planar_Layout<ComponentType::Cb, ComponentType::Cr, 2, 1>;
-using YVU422_Layout = YUV_Planar_Layout<ComponentType::Cr, ComponentType::Cb, 2, 1>;
-using YUV420_Layout = YUV_Planar_Layout<ComponentType::Cb, ComponentType::Cr, 2, 2>;
-using YVU420_Layout = YUV_Planar_Layout<ComponentType::Cr, ComponentType::Cb, 2, 2>;
-
-template<typename Format>
-class YUVPlanarWriter
-{
- using YLayout = typename Format::template plane<Format::y_plane>;
- using CbLayout = typename Format::template plane<Format::cb_plane>;
- using CrLayout = typename Format::template plane<Format::cr_plane>;
-
- using TY = typename YLayout::storage_type;
- using TCb = typename CbLayout::storage_type;
- using TCr = typename CrLayout::storage_type;
-public:
- static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
- auto&& generate_line)
- {
- assert(start_y % Format::v_sub == 0);
- assert((end_y + 1) % Format::v_sub == 0);
-
- // Line buffers
- std::vector<YUV16> linebuf_storage(fb.width() * Format::v_sub);
- auto linebuf = md::mdspan(linebuf_storage.data(), Format::v_sub, fb.width());
-
- // Views to all planes
- auto y_buf = make_strided_fb_view<TY>(fb.map(Format::y_plane), fb.height(),
- fb.width(), fb.stride(Format::y_plane));
-
- auto cb_buf = make_strided_fb_view<TCb>(fb.map(Format::cb_plane),
- fb.height() / Format::v_sub,
- fb.width() / Format::h_sub,
- fb.stride(Format::cb_plane));
-
- auto cr_buf = make_strided_fb_view<TCr>(fb.map(Format::cr_plane),
- fb.height() / Format::v_sub,
- fb.width() / Format::h_sub,
- fb.stride(Format::cr_plane));
-
- for (size_t y_src = start_y; y_src <= end_y; y_src++) {
- size_t y_offset = y_src % Format::v_sub;
-
- if (y_offset == 0) {
- // Fill line buffers
- for (size_t buf_y = 0; buf_y < Format::v_sub; buf_y++) {
- auto line = md::submdspan(linebuf, buf_y, md::full_extent);
- std::span<YUV16> span(line.data_handle(), line.size());
- generate_line(y_src + buf_y, span);
- }
- }
-
- // Write Y plane
- write_y_line(y_buf, y_src, linebuf, y_offset);
-
- // Write Cb/Cr planes if we're at a subsampling boundary
- if (y_offset == 0)
- write_uv_line(cb_buf, cr_buf, linebuf, y_src);
- }
- }
-
- static void write_lines(IFramebuffer& fb, size_t start_y, size_t end_y,
- Is2Dspan<YUV16> auto&& lines)
- {
- const size_t height = end_y - start_y + 1;
-
- if (lines.extent(0) < height || lines.extent(1) < fb.width())
- throw std::invalid_argument("Source line buffer too small");
-
- assert(start_y % Format::v_sub == 0);
- assert((end_y + 1) % Format::v_sub == 0);
-
- // Views to all planes
- auto y_buf = make_strided_fb_view<TY>(fb.map(Format::y_plane), fb.height(),
- fb.width(), fb.stride(Format::y_plane));
-
- auto cb_buf = make_strided_fb_view<TCb>(fb.map(Format::cb_plane),
- fb.height() / Format::v_sub,
- fb.width() / Format::h_sub,
- fb.stride(Format::cb_plane));
-
- auto cr_buf = make_strided_fb_view<TCr>(fb.map(Format::cr_plane),
- fb.height() / Format::v_sub,
- fb.width() / Format::h_sub,
- fb.stride(Format::cr_plane));
-
- for (size_t y_src = start_y; y_src <= end_y; y_src++) {
- size_t y_offset = y_src % Format::v_sub;
-
- // Write Y plane
- write_y_line(y_buf, y_src, lines, y_offset);
-
- // Write Cb/Cr planes if we're at a subsampling boundary
- if (y_offset == 0)
- write_uv_line(cb_buf, cr_buf, lines, y_src);
- }
- }
-
-private:
- template<typename YBuf>
- static void write_y_line(YBuf& y_buf, size_t y_src, auto& linebuf, size_t y_offset)
- {
- for (size_t x = 0; x < linebuf.extent(1); x++)
- y_buf(y_src, x) = YLayout::pack(linebuf(y_offset, x).y >> 8);
- }
-
- template<typename UVBuf>
- static void write_uv_line(UVBuf& cb_buf, UVBuf& cr_buf, auto& linebuf, size_t y_src)
- {
- const size_t uv_y = y_src / Format::v_sub;
-
- for (size_t x = 0; x < linebuf.extent(1); x += Format::h_sub) {
- // Average subsampled region
- uint32_t u_sum = 0, v_sum = 0;
- for (size_t y = 0; y < Format::v_sub; y++) {
- for (size_t x_off = 0; x_off < Format::h_sub; x_off++) {
- u_sum += linebuf(y, x + x_off).u;
- v_sum += linebuf(y, x + x_off).v;
- }
- }
-
- const size_t total_samples = Format::h_sub * Format::v_sub;
- const size_t uv_x = x / Format::h_sub;
-
- cb_buf(uv_y, uv_x) = CbLayout::pack(u_sum / total_samples >> 8);
- cr_buf(uv_y, uv_x) = CrLayout::pack(v_sum / total_samples >> 8);
- }
- }
-
-public:
- static void read_lines(IFramebuffer& fb, size_t start_y, size_t end_y,
- Is2Dspan<YUV16> auto&& dest)
- {
- const size_t height = end_y - start_y + 1;
-
- if (dest.extent(0) < height || dest.extent(1) < fb.width())
- throw std::invalid_argument("Destination line buffer too small");
-
- assert(start_y % Format::v_sub == 0);
- assert((end_y + 1) % Format::v_sub == 0);
-
- auto y_buf = make_strided_fb_view<const TY>(fb.map(Format::y_plane), fb.height(),
- fb.width(), fb.stride(Format::y_plane));
-
- auto cb_buf = make_strided_fb_view<const TCb>(fb.map(Format::cb_plane),
- fb.height() / Format::v_sub,
- fb.width() / Format::h_sub,
- fb.stride(Format::cb_plane));
-
- auto cr_buf = make_strided_fb_view<const TCr>(fb.map(Format::cr_plane),
- fb.height() / Format::v_sub,
- fb.width() / Format::h_sub,
- fb.stride(Format::cr_plane));
-
- for (size_t y = start_y; y <= end_y; y++) {
- for (size_t x = 0; x < fb.width(); x++) {
- const auto y_val = YLayout::unpack(y_buf(y, x))[0];
-
- const size_t uv_y = y / Format::v_sub;
- const size_t uv_x = x / Format::h_sub;
-
- const auto u_val = CbLayout::unpack(cb_buf(uv_y, uv_x))[0];
- const auto v_val = CrLayout::unpack(cr_buf(uv_y, uv_x))[0];
-
- dest(y - start_y, x) = YUV16 {
- static_cast<uint16_t>(y_val << 8),
- static_cast<uint16_t>(u_val << 8),
- static_cast<uint16_t>(v_val << 8)
- };
- }
- }
- }
-};
-
-} // namespace kms
diff --git a/kms++util/src/conv-yuv-semiplanar.h b/kms++util/src/conv-yuv-semiplanar.h
deleted file mode 100644
index 81117c1..0000000
--- a/kms++util/src/conv-yuv-semiplanar.h
+++ /dev/null
@@ -1,214 +0,0 @@
-#pragma once
-
-#include <vector>
-
-#include <kms++/framebuffer.h>
-#include <kms++util/color16.h>
-
-#include "conv-common.h"
-
-namespace kms
-{
-
-/* Semiplanar YUV */
-
-template<ComponentType C0, ComponentType C1, size_t HSub, size_t VSub>
-struct NV12_Family_Layout
- : public FormatLayout<
- PlaneLayout<uint8_t,
- ComponentLayout<ComponentType::Y, 8, 0>
- >,
- PlaneLayout<uint16_t,
- ComponentLayout<C0, 8, 0>,
- ComponentLayout<C1, 8, 8>
- >
- >
-{
- static constexpr size_t h_sub = HSub;
- static constexpr size_t v_sub = VSub;
-};
-
-using NV12_Layout = NV12_Family_Layout<ComponentType::Cb, ComponentType::Cr, 2, 2>;
-using NV21_Layout = NV12_Family_Layout<ComponentType::Cr, ComponentType::Cb, 2, 2>;
-
-using NV16_Layout = NV12_Family_Layout<ComponentType::Cb, ComponentType::Cr, 2, 1>;
-using NV61_Layout = NV12_Family_Layout<ComponentType::Cr, ComponentType::Cb, 2, 1>;
-
-template<size_t HSub, size_t VSub>
-struct P030_Family_Layout
- : public FormatLayout<
- PlaneLayout<uint32_t,
- ComponentLayout<ComponentType::Y, 10, 0>,
- ComponentLayout<ComponentType::Y, 10, 10>,
- ComponentLayout<ComponentType::Y, 10, 20>
- >,
- PlaneLayout<uint64_t,
- ComponentLayout<ComponentType::Cb, 10, 0>,
- ComponentLayout<ComponentType::Cr, 10, 10>,
- ComponentLayout<ComponentType::Cb, 10, 20>,
- ComponentLayout<ComponentType::Cr, 10, 32>,
- ComponentLayout<ComponentType::Cb, 10, 42>,
- ComponentLayout<ComponentType::Cr, 10, 52>
- >
- >
-{
- static constexpr size_t h_sub = HSub;
- static constexpr size_t v_sub = VSub;
-};
-
-using P030_Layout = P030_Family_Layout<2, 2>;
-using P230_Layout = P030_Family_Layout<2, 1>;
-
-template<size_t HSub, size_t VSub>
-struct SubsampleHelper {
- template<typename View> static constexpr auto subsample(const View& view, size_t group_idx)
- {
- uint32_t sum = 0;
-
- static_for<0, HSub>([&](auto x) { sum += view(0, group_idx + x); });
-
- if constexpr (VSub > 1) {
- static_for<1, VSub>([&](auto y) {
- static_for<0, HSub>([&](auto x) { sum += view(y, group_idx + x); });
- });
- }
-
- return sum / (HSub * VSub);
- }
-};
-
-template<typename Layout>
-class YUVSemiPlanarWriter
-{
- static_assert(Layout::num_planes == 2);
-
- static constexpr size_t h_sub = Layout::h_sub;
- static constexpr size_t v_sub = Layout::v_sub;
-
- using YLayout = typename Layout::template plane<0>;
- using UVLayout = typename Layout::template plane<1>;
-
- using TY = typename YLayout::storage_type;
- using TCrCb = typename UVLayout::storage_type;
-
- static constexpr size_t pixels_in_group = YLayout::template component_count<ComponentType::Y>();
- static_assert(pixels_in_group == UVLayout::template component_count<ComponentType::Cb>());
- static_assert(pixels_in_group == UVLayout::template component_count<ComponentType::Cr>());
-
-public:
- static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
- auto&& generate_line)
- {
- assert(start_y % v_sub == 0);
- assert((end_y + 1) % v_sub == 0);
- if (fb.width() % pixels_in_group != 0)
- throw std::invalid_argument("FB width doesn't align to pixel format");
-
- // Line buffers
- std::vector<YUV16> linebuf_storage(fb.width() * v_sub);
- auto linebuf = md::mdspan(linebuf_storage.data(), v_sub, fb.width());
-
- // Views to the planes
- auto y_view = make_strided_fb_view<TY>(fb.map(0), fb.height(),
- fb.width() / pixels_in_group, fb.stride(0));
-
- auto uv_view = make_strided_fb_view<TCrCb>(fb.map(1), fb.height() / v_sub,
- fb.width() / pixels_in_group / h_sub,
- fb.stride(1));
-
- for (size_t y_src = start_y; y_src <= end_y; y_src++) {
- size_t y_offset = y_src % v_sub;
-
- if (y_offset == 0) {
- // Fill line buffers
- for (size_t y_off = 0; y_off < v_sub; y_off++) {
- auto line = md::submdspan(linebuf, y_off, md::full_extent);
- std::span<YUV16> span(line.data_handle(), line.size());
- generate_line(y_src + y_off, span);
- }
- }
-
- // Write Y values from the line buffer
- write_y_samples(md::submdspan(y_view, y_src, md::full_extent),
- md::submdspan(linebuf, y_offset, md::full_extent));
-
- if (y_offset == 0) {
- // Write UV values from the line buffers
- write_uv_samples(uv_view, linebuf, y_src);
- }
- }
- }
-
-private:
-
- template<typename YBuf>
- static void write_y_samples(YBuf&& y_view, auto&& linebuf)
- {
- for (size_t x_src = 0; x_src < linebuf.extent(1); x_src += pixels_in_group) {
- auto x_dst = x_src / pixels_in_group;
-
- write_y_group(y_view, linebuf, x_src, x_dst,
- std::make_index_sequence<pixels_in_group>{});
- }
- }
-
- template<typename YBuf, size_t... I>
- static void write_y_group(YBuf&& y_view, auto&& linebuf, size_t x_src,
- size_t x_dst, std::index_sequence<I...>)
- {
- std::array<component_storage_type, YLayout::num_components> y_values{
- static_cast<component_storage_type>((linebuf(x_src + I).y >> (16 - YLayout::template component_size<I>)))...
- };
-
- y_view(x_dst) = YLayout::pack(y_values);
- }
-
- template<typename UVBuf>
- static void write_uv_samples(UVBuf& uv_view, auto& linebuf, size_t y_src)
- {
- for (size_t x_src = 0; x_src < linebuf.extent(1); x_src += pixels_in_group * h_sub) {
- const size_t y_offset = 0;
- auto y_dst = (y_src + y_offset) / v_sub;
- auto x_dst = x_src / (pixels_in_group * h_sub);
-
- auto group_view = md::submdspan(linebuf, std::tuple(y_offset, y_offset + v_sub),
- std::tuple(x_src, x_src + h_sub * pixels_in_group));
-
- write_uv_group(uv_view, group_view, y_dst, x_dst,
- std::make_index_sequence<pixels_in_group>{});
- }
- }
-
- template<typename UVBuf, size_t... I>
- static void write_uv_group(UVBuf& uv_view, auto& group_view, size_t y_dst, size_t x_dst,
- std::index_sequence<I...>)
- {
- std::array<component_storage_type, UVLayout::num_components> uv_values;
-
- (
- [&]<size_t i>() {
- constexpr size_t group_idx = i * h_sub;
-
- constexpr size_t u_idx = UVLayout::template find_nth_pos<ComponentType::Cb>(i);
- constexpr size_t v_idx = UVLayout::template find_nth_pos<ComponentType::Cr>(i);
-
- auto u = SubsampleHelper<h_sub, v_sub>::subsample(
- [&group_view](size_t y, size_t x) { return group_view(y, x).u; },
- group_idx);
-
- auto v = SubsampleHelper<h_sub, v_sub>::subsample(
- [&group_view](size_t y, size_t x) { return group_view(y, x).v; },
- group_idx);
-
- uv_values[u_idx] =
- u >> (16 - UVLayout::template component_size<u_idx>);
- uv_values[v_idx] =
- v >> (16 - UVLayout::template component_size<v_idx>);
- }.template operator()<I>(),
- ...);
-
- uv_view(y_dst, x_dst) = UVLayout::pack(uv_values);
- }
-};
-
-} // namespace kms
diff --git a/kms++util/src/conv-yuv.h b/kms++util/src/conv-yuv.h
deleted file mode 100644
index 1695129..0000000
--- a/kms++util/src/conv-yuv.h
+++ /dev/null
@@ -1,147 +0,0 @@
-#pragma once
-
-#include <vector>
-
-#include <kms++/framebuffer.h>
-#include <kms++util/color16.h>
-
-#include "conv-common.h"
-
-namespace kms
-{
-
-using XVUY2101010_Layout =
- FormatLayout<PlaneLayout<uint32_t,
- ComponentLayout<ComponentType::Y, 10, 0>,
- ComponentLayout<ComponentType::Cb, 10, 10>,
- ComponentLayout<ComponentType::Cr, 10, 20>,
- ComponentLayout<ComponentType::X, 2, 30>>>;
-
-template<typename Layout>
-class YUV_Writer
-{
- using Plane = typename Layout::template plane<0>;
- using TStorage = typename Plane::storage_type;
-
- static_assert(Layout::num_planes == 1);
- static_assert(Plane::num_components == 3 || Plane::num_components == 4);
-
- static_assert(Plane::template component_count<ComponentType::Y>() == 1);
- static_assert(Plane::template component_count<ComponentType::Cb>() == 1);
- static_assert(Plane::template component_count<ComponentType::Cr>() == 1);
-
- static constexpr bool has_alpha = Plane::template component_count<ComponentType::A>();
- static constexpr bool has_padding = Plane::template component_count<ComponentType::X>();
-
- static constexpr bool needs_packed_access = Plane::total_bits != Plane::storage_bits;
-
- static constexpr size_t a_idx = Plane::template find_pos<ComponentType::A>();
- static constexpr size_t x_idx = Plane::template find_pos<ComponentType::X>();
- static constexpr size_t y_idx = Plane::template find_pos<ComponentType::Y>();
- static constexpr size_t cb_idx = Plane::template find_pos<ComponentType::Cb>();
- static constexpr size_t cr_idx = Plane::template find_pos<ComponentType::Cr>();
-
- static constexpr size_t a_shift = has_alpha ? 16 - Plane::template component_size<a_idx> : 0;
- static constexpr size_t x_shift = has_padding ? 16 - Plane::template component_size<x_idx> : 0;
- static constexpr size_t y_shift = 16 - Plane::template component_size<y_idx>;
- static constexpr size_t cb_shift = 16 - Plane::template component_size<cb_idx>;
- static constexpr size_t cr_shift = 16 - Plane::template component_size<cr_idx>;
-
- static_assert(Plane::total_bits % 8 == 0);
- static constexpr size_t bytes_per_pixel = Plane::total_bits / 8;
-
-public:
- // Pack and write num_pixels pixels from src_line to dst_line
- static void pack_line(HasIndexOperatorReturning<TStorage> auto&& dst_line,
- HasIndexOperatorReturning<YUV16> auto&& src_line,
- size_t num_pixels)
- {
- for (size_t x = 0; x < num_pixels; x++) {
- const YUV16& pix = src_line[x];
-
- std::array<component_storage_type, Plane::num_components>
- components;
-
- if constexpr (has_alpha)
- components[a_idx] = pix.a >> a_shift;
-
- if constexpr (has_padding)
- components[x_idx] = 0;
-
- components[y_idx] = pix.y >> y_shift;
- components[cb_idx] = pix.u >> cb_shift;
- components[cr_idx] = pix.v >> cr_shift;
-
- if constexpr (!needs_packed_access) {
- dst_line[x] = Plane::pack(components);
- } else {
- auto dst_bytes = reinterpret_cast<uint8_t*>(&dst_line[0]);
-
- TStorage packed = Plane::pack(components);
-
- memcpy(dst_bytes + x * bytes_per_pixel, &packed,
- bytes_per_pixel);
- }
- }
- }
-
- // Read and unpack num_pixels pixels from src_line to dst_line
- static void unpack_line(HasIndexOperatorReturning<YUV16> auto&& dst_line,
- HasIndexOperatorReturning<TStorage> auto&& src_line,
- size_t num_pixels)
- {
- for (size_t x = 0; x < num_pixels; x++) {
- decltype(Plane::unpack(src_line[x])) components;
-
- if constexpr (!needs_packed_access) {
- components = Plane::unpack(src_line[x]);
- } else {
- auto src_bytes =
- reinterpret_cast<const uint8_t*>(&src_line[0]);
- TStorage packed;
-
- memcpy(&packed, src_bytes + x * bytes_per_pixel,
- bytes_per_pixel);
-
- components = Plane::unpack(packed);
- }
-
- dst_line[x] = YUV16 {
- static_cast<uint16_t>(components[y_idx] << y_shift),
- static_cast<uint16_t>(components[cb_idx] << cb_shift),
- static_cast<uint16_t>(components[cr_idx] << cr_shift),
- static_cast<uint16_t>(has_alpha ? components[a_idx] << a_shift : 0),
- };
- }
- }
-
- static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
- auto&& generate_line)
- {
- std::vector<YUV16> linebuf(fb.width());
-
- // View to the plane
- auto view = make_strided_fb_view<TStorage>(fb.map(0), fb.height(), fb.width(),
- fb.stride(0));
-
- for (size_t y_src = start_y; y_src <= end_y; y_src++) {
- generate_line(y_src, linebuf);
-
- auto dst = md::submdspan(view, y_src, md::full_extent);
-
- pack_line(dst, linebuf, fb.width());
- }
- }
-
- static void get_line(IFramebuffer& fb, size_t w, size_t h, size_t row, std::span<YUV16> linebuf)
- {
- auto view = make_strided_fb_view<const TStorage>(fb.map(0), fb.height(), fb.width(),
- fb.stride(0));
-
- auto src = md::submdspan(view, row, md::full_extent);
-
- unpack_line(linebuf, src);
- }
-};
-
-} // namespace kms
diff --git a/kms++util/src/conv.h b/kms++util/src/conv.h
deleted file mode 100644
index 82608dd..0000000
--- a/kms++util/src/conv.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-#include "conv-rgb.h"
-#include "conv-yuv.h"
-#include "conv-yuv-packed.h"
-#include "conv-yuv-semiplanar.h"
-#include "conv-yuv-planar.h"
-#include "conv-yuv-planar-packed.h"
-#include "conv-gray.h"
-#include "conv-raw.h"
-#include "conv-raw-packed.h"
diff --git a/kms++util/src/testpat.cpp b/kms++util/src/testpat.cpp
index b9f1e56..bd0aeb8 100644
--- a/kms++util/src/testpat.cpp
+++ b/kms++util/src/testpat.cpp
@@ -1,577 +1,69 @@
-
-#include <cstring>
-#include <functional>
-#include <optional>
-#include <span>
#include <stdexcept>
-#include <vector>
-
-#ifdef HAS_PTHREAD
-#include <thread>
-#endif
+#include <string>
#include <kms++/kms++.h>
#include <kms++util/kms++util.h>
-#include "conv.h"
-
-using namespace std;
+#include <pixpat/pixpat.h>
namespace kms
{
-static RGB16 get_test_pattern_pixel_16(size_t w, size_t h, size_t x, size_t y)
-{
- const unsigned mw = 20;
-
- const unsigned xm1 = mw;
- const unsigned xm2 = w - mw - 1;
- const unsigned ym1 = mw;
- const unsigned ym2 = h - mw - 1;
-
- // white margin lines
- if (x == xm1 || x == xm2 || y == ym1 || y == ym2)
- return RGB16::from_8(255, 255, 255);
- // white box in top left corner
- else if (x < xm1 && y < ym1)
- return RGB16::from_8(255, 255, 255);
- // white box outlines to corners
- else if ((x == 0 || x == w - 1) && (y < ym1 || y > ym2))
- return RGB16::from_8(255, 255, 255);
- // white box outlines to corners
- else if ((y == 0 || y == h - 1) && (x < xm1 || x > xm2))
- return RGB16::from_8(255, 255, 255);
- // blue bar on the left
- else if (x < xm1 && (y > ym1 && y < ym2))
- return RGB16::from_8(0, 0, 255);
- // blue bar on the top
- else if (y < ym1 && (x > xm1 && x < xm2))
- return RGB16::from_8(0, 0, 255);
- // red bar on the right
- else if (x > xm2 && (y > ym1 && y < ym2))
- return RGB16::from_8(255, 0, 0);
- // red bar on the bottom
- else if (y > ym2 && (x > xm1 && x < xm2))
- return RGB16::from_8(255, 0, 0);
- // inside the margins
- else if (x > xm1 && x < xm2 && y > ym1 && y < ym2) {
- // diagonal line
- if (x == y || w - x == h - y)
- return RGB16::from_8(255, 255, 255);
- // diagonal line
- else if (w - x - 1 == y || x == h - y - 1)
- return RGB16::from_8(255, 255, 255);
- else {
- int t = (x - xm1 - 1) * 8 / (xm2 - xm1 - 1);
- unsigned r = 0, g = 0, b = 0;
-
- unsigned c = (y - ym1 - 1) % 256;
-
- switch (t) {
- case 0:
- r = c;
- break;
- case 1:
- g = c;
- break;
- case 2:
- b = c;
- break;
- case 3:
- g = b = c;
- break;
- case 4:
- r = b = c;
- break;
- case 5:
- r = g = c;
- break;
- case 6:
- r = g = b = c;
- break;
- case 7:
- break;
- }
-
- return RGB16::from_8(r, g, b);
- }
- } else {
- // black corners
- return RGB16::from_8(0, 0, 0);
- }
-}
-
-static void get_test_pattern_line(size_t w, size_t h, size_t row, std::span<RGB16> buf)
-{
- for (size_t x = 0; x < w; ++x)
- buf[x] = get_test_pattern_pixel_16(w, h, x, row);
-}
-
-static void get_test_pattern_line_yuv(size_t w, size_t h, size_t row,
- std::span<YUV16> buf,
- const TestPatternOptions& options)
-{
- for (size_t x = 0; x < w; ++x)
- buf[x] = get_test_pattern_pixel_16(w, h, x, row)
- .to_yuv(options.rec, options.range);
-}
-// SMPTE RP 219-1:2014
-// High-Definition, Standard-Definition Compatible Color Bar Signal
-// Limited range YUV
-static YUV16 get_smpte_pixel(size_t w, size_t h, size_t x, size_t y)
+void draw_test_pattern(IFramebuffer& fb, const TestPatternOptions& options)
{
- // Pattern colors (12-bit values, limited range)
- constexpr YUV16 gray40 = YUV16::from_12(1658, 2048, 2048); // 40% Gray
- constexpr YUV16 white75 = YUV16::from_12(2884, 2048, 2048); // 75% White
- constexpr YUV16 yellow75 = YUV16::from_12(2694, 704, 2171); // 75% Yellow
- constexpr YUV16 cyan75 = YUV16::from_12(2325, 2356, 704); // 75% Cyan
- constexpr YUV16 green75 = YUV16::from_12(2136, 1012, 827); // 75% Green
- constexpr YUV16 magenta75 = YUV16::from_12(1004, 3084, 3269); // 75% Magenta
- constexpr YUV16 red75 = YUV16::from_12(815, 1740, 3392); // 75% Red
- constexpr YUV16 blue75 = YUV16::from_12(446, 3392, 1925); // 75% Blue
- constexpr YUV16 cyan100 = YUV16::from_12(3015, 2459, 256); // 100% Cyan
- constexpr YUV16 blue100 = YUV16::from_12(509, 3840, 1884); // 100% Blue
- constexpr YUV16 yellow100 = YUV16::from_12(3507, 256, 2212); // 100% Yellow
- constexpr YUV16 black = YUV16::from_12(256, 2048, 2048); // 0% Black
- constexpr YUV16 white100 = YUV16::from_12(3760, 2048, 2048); // 100% White
- constexpr YUV16 red100 = YUV16::from_12(1001, 1637, 3840); // 100% Red
- constexpr YUV16 gray15 = YUV16::from_12(782, 2048, 2048); // 15% Gray
-
- // PLUGE steps
- constexpr YUV16 black_m2 = YUV16::from_12(186, 2048, 2048); // -2% Black
- constexpr YUV16 black_p2 = YUV16::from_12(326, 2048, 2048); // +2% Black
- constexpr YUV16 black_p4 = YUV16::from_12(396, 2048, 2048); // +4% Black
-
- // High precision for x-axis calculations
- constexpr size_t M = 1024;
- x = x * M;
- const size_t a = w * M;
- const size_t c = (a * 3 / 4) / 7;
- const size_t d = a / 8;
-
- // Pattern heights
- const size_t pattern1_height = (h * 7) / 12;
- const size_t pattern2_height = pattern1_height + (h / 12);
- const size_t pattern3_height = pattern2_height + (h / 12);
-
- // Pattern 1 (75% color bars)
- if (y < pattern1_height) {
- if (x < d || x >= (a - d))
- return gray40;
-
- size_t bar_index = (x - d) / c;
- switch (bar_index) {
- case 0:
- return white75;
- case 1:
- return yellow75;
- case 2:
- return cyan75;
- case 3:
- return green75;
- case 4:
- return magenta75;
- case 5:
- return red75;
- default:
- return blue75;
- }
- }
-
- // Pattern 2 (Color difference reference)
- if (y >= pattern1_height && y < pattern2_height) {
- if (x < d)
- return cyan100;
-
- if (x >= (a - d))
- return blue100;
-
- return white75;
- }
-
- // Pattern 3 (Ramp)
- if (y >= pattern2_height && y < pattern3_height) {
- if (x < d)
- return yellow100;
+ const auto& info = get_pixel_format_info(fb.format());
- if (x >= (a - d))
- return red100;
+ pixpat_buffer buf{};
+ buf.format = info.name.c_str();
+ buf.width = fb.width();
+ buf.height = fb.height();
+ buf.num_planes = fb.num_planes();
- const size_t ramp_width = a - 2 * d;
- const size_t ramp_x = x - d;
+ if (buf.num_planes > 4)
+ throw std::runtime_error("Too many planes");
- uint16_t y_val = 256 + (3760 - 256) * ramp_x / ramp_width;
- return YUV16::from_12(y_val, 2048, 2048);
+ for (unsigned i = 0; i < buf.num_planes; ++i) {
+ buf.planes[i] = fb.map(i);
+ buf.strides[i] = fb.stride(i);
}
- // Pattern 4 (PLUGE)
- if (y >= pattern3_height) {
- const size_t c0 = d;
- const size_t c1 = c0 + c * 3 / 2;
- const size_t c2 = c1 + 2 * c;
- const size_t c3 = c2 + c * 5 / 6;
-
- if (x < c0)
- return gray15;
-
- if (x < c1)
- return black;
-
- if (x < c2)
- return white100;
-
- if (x < c3)
- return black;
-
- if (x >= a - d)
- return gray15;
-
- if (x >= a - d - c)
- return black;
-
- const size_t step = (x - c3) / (c / 3);
-
- switch (step) {
- case 0:
- return black_m2; // -2%
- case 1:
- return black; // 0%
- case 2:
- return black_p2; // +2%
- case 3:
- return black; // 0%
- default:
- return black_p4; // +4%
- }
+ pixpat_pattern_opts popts{};
+ switch (options.rec) {
+ case RecStandard::BT601: popts.rec = PIXPAT_REC_BT601; break;
+ case RecStandard::BT709: popts.rec = PIXPAT_REC_BT709; break;
+ case RecStandard::BT2020: popts.rec = PIXPAT_REC_BT2020; break;
}
-
- return black;
-}
-
-static void get_smpte_line_rgb(size_t w, size_t h, size_t row, std::span<RGB16> buf,
- const TestPatternOptions& options)
-{
- for (size_t x = 0; x < w; ++x)
- buf[x] = get_smpte_pixel(w, h, x, row)
- .to_rgb(RecStandard::BT709, ColorRange::Limited);
-}
-
-static void get_smpte_line_yuv(size_t w, size_t h, size_t row, std::span<YUV16> buf,
- const TestPatternOptions& options)
-{
- for (size_t x = 0; x < w; ++x)
- buf[x] = get_smpte_pixel(w, h, x, row);
-}
-
-static void get_plain_line_rgb(size_t w, const RGB16& color, std::span<RGB16> buf)
-{
- for (size_t x = 0; x < w; ++x)
- buf[x] = color;
-}
-
-static void get_plain_line_yuv(size_t w, const YUV16& color, std::span<YUV16> buf)
-{
- for (size_t x = 0; x < w; ++x)
- buf[x] = color;
-}
-
-static void draw_test_pattern_part(IFramebuffer& fb, size_t start_y, size_t end_y,
- const TestPatternOptions& options)
-{
- std::optional<RGB16> solid;
-
- if (options.pattern == "red")
- solid = RGB16(0xffff, 0, 0);
- else if (options.pattern == "green")
- solid = RGB16(0, 0xffff, 0);
- else if (options.pattern == "blue")
- solid = RGB16(0, 0, 0xffff);
- else if (options.pattern == "white")
- solid = RGB16(0xffff, 0xffff, 0xffff);
- else if (options.pattern == "black")
- solid = RGB16(0, 0, 0);
-
- std::function<void(size_t y, std::span<RGB16> span)> generate_line_rgb;
- std::function<void(size_t y, std::span<YUV16> span)> generate_line_yuv;
-
- if (solid.has_value()) {
- generate_line_rgb = [&fb, rgb = solid.value()](size_t y,
- std::span<RGB16> span) {
- get_plain_line_rgb(fb.width(), rgb, span);
+ popts.range = options.range == ColorRange::Full ? PIXPAT_RANGE_FULL
+ : PIXPAT_RANGE_LIMITED;
+ popts.num_threads = 0;
+
+ const char* pattern = options.pattern.empty() ? nullptr : options.pattern.c_str();
+ std::string params;
+
+ if (pattern) {
+ struct {
+ const char* alias;
+ const char* color;
+ } static const solid_aliases[] = {
+ { "red", "ff0000" },
+ { "green", "00ff00" },
+ { "blue", "0000ff" },
+ { "white", "ffffff" },
+ { "black", "000000" },
};
- generate_line_yuv = [&fb, rgb = solid.value(),
- &options](size_t y, std::span<YUV16> span) {
- get_plain_line_yuv(fb.width(),
- rgb.to_yuv(options.rec, options.range), span);
- };
- } else if (options.pattern == "smpte") {
- generate_line_rgb = [&fb, &options](size_t y, std::span<RGB16> span) {
- get_smpte_line_rgb(fb.width(), fb.height(), y, span, options);
- };
-
- generate_line_yuv = [&fb, &options](size_t y, std::span<YUV16> span) {
- get_smpte_line_yuv(fb.width(), fb.height(), y, span, options);
- };
- } else {
- generate_line_rgb = [&fb](size_t y, std::span<RGB16> span) {
- get_test_pattern_line(fb.width(), fb.height(), y, span);
- };
-
- generate_line_yuv = [&fb, &options](size_t y, std::span<YUV16> span) {
- get_test_pattern_line_yuv(fb.width(), fb.height(), y, span,
- options);
- };
- }
-
-#define CASE_ARGB(x) \
- case PixelFormat::x: \
- ARGB_Writer<x##_Layout>::write_pattern(fb, start_y, end_y, \
- generate_line_rgb); \
- break;
-
-#define CASE_YUV(x) \
- case PixelFormat::x: \
- YUV_Writer<x##_Layout>::write_pattern(fb, start_y, end_y, \
- generate_line_yuv); \
- break;
-
-#define CASE_YUV_PACKED(x) \
- case PixelFormat::x: \
- YUVPackedWriter<x##_Layout>::write_pattern(fb, start_y, end_y, \
- generate_line_yuv); \
- break;
-
-#define CASE_YUV_SEMI(x) \
- case PixelFormat::x: \
- YUVSemiPlanarWriter<x##_Layout>::write_pattern(fb, start_y, end_y, \
- generate_line_yuv); \
- break;
-
-#define CASE_YUV_PLANAR(x) \
- case PixelFormat::x: \
- YUVPlanarWriter<x##_Layout>::write_pattern(fb, start_y, end_y, \
- generate_line_yuv); \
- break;
-
-#define CASE_Y_ONLY(x) \
- case PixelFormat::x: \
- Y_Writer<x##_Layout>::write_pattern(fb, start_y, end_y, \
- generate_line_yuv); \
- break;
-
-#define CASE_YUV_PLANAR_PACKED(x) \
- case PixelFormat::x: \
- YUVPlanarPackedWriter<x##_Layout>::write_pattern(fb, start_y, end_y, \
- generate_line_yuv); \
- break;
-
-#define CASE_RAW(x) \
- case PixelFormat::x: \
- Bayer_Writer<x##_Layout>::write_pattern(fb, start_y, end_y, \
- generate_line_rgb); \
- break;
-
-#define CASE_RAW_PACKED(x) \
- case PixelFormat::x: \
- BayerPacked_Writer<x##_Layout>::write_pattern(fb, start_y, end_y, \
- generate_line_rgb); \
- break;
-
- switch (fb.format()) {
- CASE_YUV_SEMI(P230);
- CASE_YUV_SEMI(P030);
- CASE_YUV_SEMI(NV12);
- CASE_YUV_SEMI(NV21);
- CASE_YUV_SEMI(NV16);
- CASE_YUV_SEMI(NV61);
-
- CASE_ARGB(RGB565);
- CASE_ARGB(BGR565);
-
- CASE_ARGB(XRGB1555);
- CASE_ARGB(ARGB1555);
- CASE_ARGB(XRGB4444);
- CASE_ARGB(ARGB4444);
-
- CASE_ARGB(RGB888);
- CASE_ARGB(BGR888);
-
- CASE_ARGB(XRGB8888);
- CASE_ARGB(ARGB8888);
- CASE_ARGB(XBGR8888);
- CASE_ARGB(ABGR8888);
- CASE_ARGB(RGBX8888);
- CASE_ARGB(RGBA8888);
- CASE_ARGB(BGRX8888);
- CASE_ARGB(BGRA8888);
- CASE_ARGB(XRGB2101010);
- CASE_ARGB(ARGB2101010);
- CASE_ARGB(XBGR2101010);
- CASE_ARGB(ABGR2101010);
- CASE_ARGB(RGBX1010102);
- CASE_ARGB(RGBA1010102);
- CASE_ARGB(BGRX1010102);
- CASE_ARGB(BGRA1010102);
-
- CASE_YUV_PACKED(YUYV);
- CASE_YUV_PACKED(YVYU);
- CASE_YUV_PACKED(UYVY);
- CASE_YUV_PACKED(VYUY);
-
- CASE_YUV(XVUY2101010);
-
- CASE_YUV_PLANAR(YUV444);
- CASE_YUV_PLANAR(YVU444);
- CASE_YUV_PLANAR(YUV422);
- CASE_YUV_PLANAR(YVU422);
- CASE_YUV_PLANAR(YUV420);
- CASE_YUV_PLANAR(YVU420);
-
- CASE_Y_ONLY(Y8);
- CASE_Y_ONLY(XYYY2101010);
-
- CASE_YUV_PLANAR_PACKED(T430);
-
- CASE_RAW(SRGGB8);
- CASE_RAW(SGBRG8);
- CASE_RAW(SGRBG8);
- CASE_RAW(SBGGR8);
-
- CASE_RAW(SRGGB10);
- CASE_RAW(SGBRG10);
- CASE_RAW(SGRBG10);
- CASE_RAW(SBGGR10);
-
- CASE_RAW(SRGGB12);
- CASE_RAW(SGBRG12);
- CASE_RAW(SGRBG12);
- CASE_RAW(SBGGR12);
-
- CASE_RAW(SRGGB16);
- CASE_RAW(SGBRG16);
- CASE_RAW(SGRBG16);
- CASE_RAW(SBGGR16);
-
- CASE_RAW_PACKED(SRGGB10P);
- CASE_RAW_PACKED(SGBRG10P);
- CASE_RAW_PACKED(SGRBG10P);
- CASE_RAW_PACKED(SBGGR10P);
-
- CASE_RAW_PACKED(SRGGB12P);
- CASE_RAW_PACKED(SGBRG12P);
- CASE_RAW_PACKED(SGRBG12P);
- CASE_RAW_PACKED(SBGGR12P);
-
- default:
- break;
- }
-}
-
-void draw_test_pattern_multi(IFramebuffer& fb, const TestPatternOptions& options)
-{
- const auto& info = get_pixel_format_info(fb.format());
- uint8_t v_sub = 0;
- for (size_t p = 0; p < info.num_planes; ++p)
- v_sub = max(v_sub, info.planes[p].vsub);
-
- if (!v_sub || fb.height() % v_sub)
- throw invalid_argument("FB height must be divisible with vsub");
-
- // Create the mmaps before starting the threads
- for (size_t i = 0; i < fb.num_planes(); ++i)
- fb.map(i);
-
- size_t num_threads = thread::hardware_concurrency();
-
- size_t part_height = fb.height() / num_threads;
-
- // round up to v_sub
- part_height = (part_height + v_sub - 1) / v_sub * v_sub;
-
- vector<thread> workers;
-
- std::vector<std::exception_ptr> errors(num_threads);
-
- for (size_t n = 0; n < num_threads; ++n) {
- size_t start = n * part_height;
- size_t end = start + part_height - 1;
-
- if (n == num_threads - 1)
- end = fb.height() - 1;
-
- workers.push_back(thread([&fb, start, end, &options, &error = errors[n]]() {
- try {
- draw_test_pattern_part(fb, start, end, options);
- } catch (...) {
- error = std::current_exception();
+ for (const auto& a : solid_aliases) {
+ if (options.pattern == a.alias) {
+ pattern = "plain";
+ params = std::string("color=") + a.color;
+ popts.params = params.c_str();
+ break;
}
- }));
+ }
}
- for (thread& t : workers)
- t.join();
-
- auto i = std::find_if(errors.begin(), errors.end(),
- [](const auto& e) { return e != nullptr; });
- if (i != errors.end())
- std::rethrow_exception(*i);
-}
-
-void draw_test_pattern_single(IFramebuffer& fb, const TestPatternOptions& options)
-{
- draw_test_pattern_part(fb, 0, fb.height() - 1, options);
-}
-
-void draw_test_pattern(IFramebuffer& fb, const TestPatternOptions& options)
-{
-#ifdef HAS_PTHREAD
- draw_test_pattern_multi(fb, options);
-#else
- draw_test_pattern_single(fb, options);
-#endif
+ if (pixpat_draw_pattern(&buf, pattern, &popts) != 0)
+ throw std::runtime_error("pixpat_draw_pattern failed");
}
} // namespace kms
-
-extern "C" {
-
-int c_draw_test_pattern(struct CDrawTestPatternParameters* params)
-{
- using namespace kms;
-
- try {
- auto fmt = find_pixel_format_by_name(params->format_name);
-
- ExtCPUFramebuffer fb(params->width,
- params->height,
- fmt,
- params->buffers,
- params->sizes,
- params->pitches,
- params->offsets);
-
- RecStandard rec;
- if (params->rec_standard == 0)
- rec = RecStandard::BT601;
- else if (params->rec_standard == 1)
- rec = RecStandard::BT709;
- else if (params->rec_standard == 2)
- rec = RecStandard::BT2020;
- else
- return -1;
-
- TestPatternOptions options;
- options.pattern = params->pattern;
- options.rec = rec;
- options.range = params->full_range ? ColorRange::Full : ColorRange::Limited;
-
- draw_test_pattern(fb, options);
- } catch (const exception&) {
- return -1;
- }
-
- return 0;
-}
-
-}