summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.h2
-rw-r--r--kms++util/src/testpat.cpp42
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;
}