summaryrefslogtreecommitdiff
path: root/kms++util/src/conv-raw.h
blob: a0752d36a3268a72b63d812060ab57a0b739d6d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
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