From ce748d0b1e9f78b29cc2029f9446cd242af5fa3c Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 8 Sep 2025 16:23:21 +0300 Subject: kms++util/testpat: Add RAW Bayer testpat generation Signed-off-by: Tomi Valkeinen --- kms++util/src/conv-raw.h | 202 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 kms++util/src/conv-raw.h (limited to 'kms++util/src/conv-raw.h') diff --git a/kms++util/src/conv-raw.h b/kms++util/src/conv-raw.h new file mode 100644 index 0000000..a0752d3 --- /dev/null +++ b/kms++util/src/conv-raw.h @@ -0,0 +1,202 @@ +#pragma once + +#include + +#include +#include + +#include "conv-common.h" + +namespace kms +{ + +/* + * Raw Bayer formats + */ + +enum class BayerOrder { + RGGB, + BGGR, + GRBG, + GBRG +}; + +template +struct Bayer_Layout; + +// 8-bit bayer formats (uint8_t storage) +template +struct Bayer_Layout + : public FormatLayout>> +{ + static constexpr BayerOrder bayer_order = Order; + static constexpr size_t bit_depth = 8; +}; + +// 10-bit bayer formats (uint16_t storage) +template +struct Bayer_Layout + : public FormatLayout, + ComponentLayout>> +{ + static constexpr BayerOrder bayer_order = Order; + static constexpr size_t bit_depth = 10; +}; + +// 12-bit bayer formats (uint16_t storage) +template +struct Bayer_Layout + : public FormatLayout, + ComponentLayout>> +{ + static constexpr BayerOrder bayer_order = Order; + static constexpr size_t bit_depth = 12; +}; + +// 16-bit bayer formats (uint16_t storage) +template +struct Bayer_Layout + : public FormatLayout>> +{ + static constexpr BayerOrder bayer_order = Order; + static constexpr size_t bit_depth = 16; +}; + +// Convenient aliases for different bit depths +template using Bayer8_Layout = Bayer_Layout; +template using Bayer10_Layout = Bayer_Layout; +template using Bayer12_Layout = Bayer_Layout; +template using Bayer16_Layout = Bayer_Layout; + +// Format-specific type aliases +using SRGGB8_Layout = Bayer8_Layout; +using SGBRG8_Layout = Bayer8_Layout; +using SGRBG8_Layout = Bayer8_Layout; +using SBGGR8_Layout = Bayer8_Layout; + +using SRGGB10_Layout = Bayer10_Layout; +using SGBRG10_Layout = Bayer10_Layout; +using SGRBG10_Layout = Bayer10_Layout; +using SBGGR10_Layout = Bayer10_Layout; + +using SRGGB12_Layout = Bayer12_Layout; +using SGBRG12_Layout = Bayer12_Layout; +using SGRBG12_Layout = Bayer12_Layout; +using SBGGR12_Layout = Bayer12_Layout; + +using SRGGB16_Layout = Bayer16_Layout; +using SGBRG16_Layout = Bayer16_Layout; +using SGRBG16_Layout = Bayer16_Layout; +using SBGGR16_Layout = Bayer16_Layout; + +template +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() == 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(); + + static constexpr size_t y_idx = Plane::template find_pos(); + static constexpr size_t x_idx = has_padding ? Plane::template find_pos() : 0; + + static constexpr size_t y_shift = 16 - Plane::template component_size; + + 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 auto&& dst_line, + HasIndexOperatorReturning 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 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 linebuf(fb.width()); + + auto view = make_strided_fb_view(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 -- cgit v1.2.3