Skip to content

Commit ce748d0

Browse files
committed
kms++util/testpat: Add RAW Bayer testpat generation
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
1 parent 3c53f1e commit ce748d0

File tree

4 files changed

+476
-0
lines changed

4 files changed

+476
-0
lines changed

kms++util/src/conv-raw-packed.h

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
#pragma once
2+
3+
#include <vector>
4+
5+
#include <kms++/framebuffer.h>
6+
#include <kms++util/color16.h>
7+
8+
#include "conv-common.h"
9+
#include "conv-raw.h"
10+
11+
namespace kms
12+
{
13+
14+
/*
15+
* Raw Bayer Packed formats (MIPI CSI-2)
16+
*/
17+
18+
template<BayerOrder Order, size_t BitDepth>
19+
struct BayerPacked_Layout;
20+
21+
// 10-bit packed bayer formats - 4 pixels (40 bits) in 5 bytes
22+
template<BayerOrder Order>
23+
struct BayerPacked_Layout<Order, 10>
24+
: public FormatLayout<PlaneLayout<uint8_t,
25+
ComponentLayout<ComponentType::Y, 8, 0>>>
26+
{
27+
static constexpr BayerOrder bayer_order = Order;
28+
static constexpr size_t bit_depth = 10;
29+
static constexpr size_t pixels_per_group = 4;
30+
static constexpr size_t bytes_per_group = 5;
31+
};
32+
33+
// 12-bit packed bayer formats - 2 pixels (24 bits) in 3 bytes
34+
template<BayerOrder Order>
35+
struct BayerPacked_Layout<Order, 12>
36+
: public FormatLayout<PlaneLayout<uint8_t,
37+
ComponentLayout<ComponentType::Y, 8, 0>>>
38+
{
39+
static constexpr BayerOrder bayer_order = Order;
40+
static constexpr size_t bit_depth = 12;
41+
static constexpr size_t pixels_per_group = 2;
42+
static constexpr size_t bytes_per_group = 3;
43+
};
44+
45+
// Convenient aliases for different bit depths
46+
template<BayerOrder Order> using BayerPacked10_Layout = BayerPacked_Layout<Order, 10>;
47+
template<BayerOrder Order> using BayerPacked12_Layout = BayerPacked_Layout<Order, 12>;
48+
49+
// Format-specific type aliases
50+
using SRGGB10P_Layout = BayerPacked10_Layout<BayerOrder::RGGB>;
51+
using SGBRG10P_Layout = BayerPacked10_Layout<BayerOrder::GBRG>;
52+
using SGRBG10P_Layout = BayerPacked10_Layout<BayerOrder::GRBG>;
53+
using SBGGR10P_Layout = BayerPacked10_Layout<BayerOrder::BGGR>;
54+
55+
using SRGGB12P_Layout = BayerPacked12_Layout<BayerOrder::RGGB>;
56+
using SGBRG12P_Layout = BayerPacked12_Layout<BayerOrder::GBRG>;
57+
using SGRBG12P_Layout = BayerPacked12_Layout<BayerOrder::GRBG>;
58+
using SBGGR12P_Layout = BayerPacked12_Layout<BayerOrder::BGGR>;
59+
60+
template<typename Layout>
61+
class BayerPacked_Writer
62+
{
63+
using Plane = typename Layout::template plane<0>;
64+
using TStorage = typename Plane::storage_type;
65+
66+
static_assert(Layout::num_planes == 1);
67+
static_assert(std::is_same_v<TStorage, uint8_t>);
68+
69+
static constexpr BayerOrder bayer_order = Layout::bayer_order;
70+
static constexpr size_t bit_depth = Layout::bit_depth;
71+
static constexpr size_t pixels_per_group = Layout::pixels_per_group;
72+
static constexpr size_t bytes_per_group = Layout::bytes_per_group;
73+
74+
static constexpr ComponentType get_bayer_component(size_t x, size_t y)
75+
{
76+
const bool x_even = (x % 2) == 0;
77+
const bool y_even = (y % 2) == 0;
78+
79+
switch (bayer_order) {
80+
case BayerOrder::RGGB:
81+
if (y_even && x_even) return ComponentType::R;
82+
if (y_even && !x_even) return ComponentType::G;
83+
if (!y_even && x_even) return ComponentType::G;
84+
return ComponentType::B;
85+
86+
case BayerOrder::BGGR:
87+
if (y_even && x_even) return ComponentType::B;
88+
if (y_even && !x_even) return ComponentType::G;
89+
if (!y_even && x_even) return ComponentType::G;
90+
return ComponentType::R;
91+
92+
case BayerOrder::GRBG:
93+
if (y_even && x_even) return ComponentType::G;
94+
if (y_even && !x_even) return ComponentType::R;
95+
if (!y_even && x_even) return ComponentType::B;
96+
return ComponentType::G;
97+
98+
case BayerOrder::GBRG:
99+
if (y_even && x_even) return ComponentType::G;
100+
if (y_even && !x_even) return ComponentType::B;
101+
if (!y_even && x_even) return ComponentType::R;
102+
return ComponentType::G;
103+
}
104+
105+
return ComponentType::Y; // fallback
106+
}
107+
108+
static uint16_t extract_component(const RGB16& pix, ComponentType component)
109+
{
110+
switch (component) {
111+
case ComponentType::R:
112+
return pix.r;
113+
case ComponentType::G:
114+
return pix.g;
115+
case ComponentType::B:
116+
return pix.b;
117+
default:
118+
return 0;
119+
}
120+
}
121+
122+
// Pack 10-bit pixels: 4 pixels (40 bits) into 5 bytes
123+
static void pack_10bit_group(uint8_t* dst, const std::array<uint16_t, 4>& values)
124+
{
125+
// Convert from 16-bit to 10-bit values
126+
const uint16_t p0 = values[0] >> 6;
127+
const uint16_t p1 = values[1] >> 6;
128+
const uint16_t p2 = values[2] >> 6;
129+
const uint16_t p3 = values[3] >> 6;
130+
131+
// Pack MSB 8 bits of each pixel
132+
dst[0] = (p0 >> 2) & 0xFF;
133+
dst[1] = (p1 >> 2) & 0xFF;
134+
dst[2] = (p2 >> 2) & 0xFF;
135+
dst[3] = (p3 >> 2) & 0xFF;
136+
137+
// Pack LSB 2 bits of each pixel into 5th byte
138+
dst[4] = ((p0 & 0x03) << 6) |
139+
((p1 & 0x03) << 4) |
140+
((p2 & 0x03) << 2) |
141+
((p3 & 0x03) << 0);
142+
}
143+
144+
// Pack 12-bit pixels: 2 pixels (24 bits) into 3 bytes
145+
static void pack_12bit_group(uint8_t* dst, const std::array<uint16_t, 2>& values)
146+
{
147+
// Convert from 16-bit to 12-bit values
148+
const uint16_t p0 = values[0] >> 4;
149+
const uint16_t p1 = values[1] >> 4;
150+
151+
// Pack MSB 8 bits of each pixel
152+
dst[0] = (p0 >> 4) & 0xFF;
153+
dst[1] = (p1 >> 4) & 0xFF;
154+
155+
// Pack LSB 4 bits of each pixel into 3rd byte
156+
dst[2] = ((p0 & 0x0F) << 4) |
157+
((p1 & 0x0F) << 0);
158+
}
159+
160+
public:
161+
static void pack_line(HasIndexOperatorReturning<TStorage> auto&& dst_line,
162+
HasIndexOperatorReturning<RGB16> auto&& src_line,
163+
size_t num_pixels, size_t y)
164+
{
165+
if constexpr (bit_depth == 10) {
166+
// Process 4 pixels at a time for 10-bit packed
167+
for (size_t x = 0; x < num_pixels; x += pixels_per_group) {
168+
std::array<uint16_t, 4> pixel_values;
169+
170+
for (size_t i = 0; i < pixels_per_group && (x + i) < num_pixels; i++) {
171+
const RGB16& pix = src_line[x + i];
172+
const ComponentType component = get_bayer_component(x + i, y);
173+
pixel_values[i] = extract_component(pix, component);
174+
}
175+
176+
// Fill remaining pixels with 0 if at end of line
177+
for (size_t i = num_pixels - x; i < pixels_per_group; i++) {
178+
pixel_values[i] = 0;
179+
}
180+
181+
const size_t group_idx = x / pixels_per_group;
182+
uint8_t* dst_bytes = reinterpret_cast<uint8_t*>(&dst_line[0]);
183+
pack_10bit_group(dst_bytes + group_idx * bytes_per_group, pixel_values);
184+
}
185+
} else if constexpr (bit_depth == 12) {
186+
// Process 2 pixels at a time for 12-bit packed
187+
for (size_t x = 0; x < num_pixels; x += pixels_per_group) {
188+
std::array<uint16_t, 2> pixel_values;
189+
190+
for (size_t i = 0; i < pixels_per_group && (x + i) < num_pixels; i++) {
191+
const RGB16& pix = src_line[x + i];
192+
const ComponentType component = get_bayer_component(x + i, y);
193+
pixel_values[i] = extract_component(pix, component);
194+
}
195+
196+
// Fill remaining pixels with 0 if at end of line
197+
for (size_t i = num_pixels - x; i < pixels_per_group; i++) {
198+
pixel_values[i] = 0;
199+
}
200+
201+
const size_t group_idx = x / pixels_per_group;
202+
uint8_t* dst_bytes = reinterpret_cast<uint8_t*>(&dst_line[0]);
203+
pack_12bit_group(dst_bytes + group_idx * bytes_per_group, pixel_values);
204+
}
205+
}
206+
}
207+
208+
static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
209+
auto&& generate_line)
210+
{
211+
std::vector<RGB16> linebuf(fb.width());
212+
213+
// For packed formats, the stride represents bytes per line
214+
// We need to calculate the correct width in bytes for the view
215+
const size_t bytes_per_line = fb.stride(0);
216+
217+
auto view = make_strided_fb_view<TStorage>(fb.map(0), fb.height(),
218+
bytes_per_line, fb.stride(0));
219+
220+
for (size_t y_src = start_y; y_src <= end_y; y_src++) {
221+
generate_line(y_src, linebuf);
222+
223+
auto dst = md::submdspan(view, y_src, md::full_extent);
224+
225+
pack_line(dst, linebuf, fb.width(), y_src);
226+
}
227+
}
228+
};
229+
230+
} // namespace kms

0 commit comments

Comments
 (0)