diff options
Diffstat (limited to 'kms++util/src')
| -rw-r--r-- | kms++util/src/conv-raw-packed.h | 230 | ||||
| -rw-r--r-- | kms++util/src/conv-raw.h | 202 | ||||
| -rw-r--r-- | kms++util/src/conv.h | 2 | ||||
| -rw-r--r-- | kms++util/src/testpat.cpp | 42 |
4 files changed, 476 insertions, 0 deletions
diff --git a/kms++util/src/conv-raw-packed.h b/kms++util/src/conv-raw-packed.h new file mode 100644 index 0000000..7465c6b --- /dev/null +++ b/kms++util/src/conv-raw-packed.h @@ -0,0 +1,230 @@ +#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 new file mode 100644 index 0000000..a0752d3 --- /dev/null +++ b/kms++util/src/conv-raw.h @@ -0,0 +1,202 @@ +#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.h b/kms++util/src/conv.h index 720480a..82608dd 100644 --- a/kms++util/src/conv.h +++ b/kms++util/src/conv.h @@ -7,3 +7,5 @@ #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 bdbe647..7984de8 100644 --- a/kms++util/src/testpat.cpp +++ b/kms++util/src/testpat.cpp @@ -367,6 +367,18 @@ static void draw_test_pattern_part(IFramebuffer& fb, size_t start_y, size_t end_ 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(XV20); CASE_YUV_SEMI(XV15); @@ -422,6 +434,36 @@ static void draw_test_pattern_part(IFramebuffer& fb, size_t start_y, size_t end_ CASE_YUV_PLANAR_PACKED(X403); + 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; } |
