summaryrefslogtreecommitdiff
path: root/kms++util
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2025-03-27 17:24:31 +0200
committerTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2025-03-27 17:57:26 +0200
commit9673348fffea7490a85b4a15882e3ec41b62dc29 (patch)
tree8b9ecd14ea67000f88aaaa8341a60b7525d43758 /kms++util
parentdf4a5c1d3d01c04c7bc92747d5b85abe3ecf1db7 (diff)
conv: Add Y8/10/12/16 and Y10_P32 support
Only Y8 and Y10_P32 can be used and have been tested for now. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Diffstat (limited to 'kms++util')
-rw-r--r--kms++util/src/conv-gray.h130
-rw-r--r--kms++util/src/conv.h1
-rw-r--r--kms++util/src/testpat.cpp9
3 files changed, 140 insertions, 0 deletions
diff --git a/kms++util/src/conv-gray.h b/kms++util/src/conv-gray.h
new file mode 100644
index 0000000..ecb5bae
--- /dev/null
+++ b/kms++util/src/conv-gray.h
@@ -0,0 +1,130 @@
+#pragma once
+
+#include <vector>
+
+#include <kms++/framebuffer.h>
+#include <kms++util/color16.h>
+
+#include "conv-common.h"
+
+namespace kms
+{
+
+/*
+ * Grayscale formats
+ */
+
+using Y8_Layout = FormatLayout<PlaneLayout<uint8_t,
+ ComponentLayout<ComponentType::Y, 8, 0>>>;
+
+using Y10_Layout = FormatLayout<PlaneLayout<uint16_t,
+ ComponentLayout<ComponentType::Y, 10, 0>,
+ ComponentLayout<ComponentType::X, 4, 10>>>;
+
+using Y12_Layout = FormatLayout<PlaneLayout<uint16_t,
+ ComponentLayout<ComponentType::Y, 12, 0>,
+ ComponentLayout<ComponentType::X, 4, 12>>>;
+
+using Y16_Layout = FormatLayout<PlaneLayout<uint16_t,
+ ComponentLayout<ComponentType::Y, 16, 0>>>;
+
+using Y10_P32_Layout = FormatLayout<PlaneLayout<uint32_t,
+ ComponentLayout<ComponentType::Y, 10, 0>, // Y0
+ ComponentLayout<ComponentType::Y, 10, 10>, // Y1
+ ComponentLayout<ComponentType::Y, 10, 20>, // Y2
+ ComponentLayout<ComponentType::X, 2, 30>
+>>;
+
+template<typename Layout> class Y_Writer
+{
+ using Plane = Layout::template plane<0>;
+ using TStorage = Plane::storage_type;
+
+ static_assert(Layout::num_planes == 1);
+ static_assert(Plane::template component_count<ComponentType::Y>() >= 1);
+
+ 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 size_t pixels_in_group =
+ Plane::template component_count<ComponentType::Y>();
+ static constexpr bool is_packed_format = pixels_in_group > 1;
+
+public:
+ // Pack and write num_pixels pixels from src_line to dst_line
+ static void pack_line(HasIndexOperatorReturning<TStorage> auto&& dst_line,
+ HasIndexOperatorReturning<YUV16> auto&& src_line,
+ size_t num_pixels)
+ {
+ if constexpr (!is_packed_format) {
+ // Simple case: one Y component per storage unit
+ for (size_t x = 0; x < num_pixels; x++) {
+ const YUV16& pix = src_line[x];
+
+ std::array<component_storage_type, Plane::num_components>
+ components;
+
+ if constexpr (has_padding)
+ components[x_idx] = 0;
+
+ components[y_idx] = pix.y >> y_shift;
+
+ dst_line[x] = Plane::pack(components);
+ }
+ } else {
+ write_y_samples(dst_line, src_line, num_pixels);
+ }
+ }
+
+ static void write_pattern(IFramebuffer& fb, size_t start_y, size_t end_y,
+ auto&& generate_line)
+ {
+ std::vector<YUV16> linebuf(fb.width());
+
+ // View to the plane
+ auto view = make_strided_fb_view<TStorage>(fb.map(0), fb.height(),
+ fb.width() / pixels_in_group,
+ 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());
+ }
+ }
+
+private:
+ template<typename YBuf>
+ static void write_y_samples(YBuf&& y_view, auto&& linebuf, size_t num_pixels)
+ {
+ for (size_t x_src = 0; x_src < num_pixels; x_src += pixels_in_group) {
+ auto x_dst = x_src / pixels_in_group;
+
+ write_y_group(y_view, linebuf, x_src, x_dst,
+ std::make_index_sequence<pixels_in_group>{});
+ }
+ }
+
+ template<typename YBuf, size_t... I>
+ static void write_y_group(YBuf&& y_view, auto&& linebuf, size_t x_src,
+ size_t x_dst, std::index_sequence<I...>)
+ {
+ std::array<component_storage_type, Plane::num_components> y_values{
+ static_cast<component_storage_type>(
+ (linebuf[x_src + I].y >>
+ (16 - Plane::template component_size<I>)))...
+ };
+
+ y_view[x_dst] = Plane::pack(y_values);
+ }
+};
+
+} // namespace kms \ No newline at end of file
diff --git a/kms++util/src/conv.h b/kms++util/src/conv.h
index 4b2baa5..0120fed 100644
--- a/kms++util/src/conv.h
+++ b/kms++util/src/conv.h
@@ -5,3 +5,4 @@
#include "conv-yuv-packed.h"
#include "conv-yuv-semiplanar.h"
#include "conv-yuv-planar.h"
+#include "conv-gray.h"
diff --git a/kms++util/src/testpat.cpp b/kms++util/src/testpat.cpp
index a123a1f..4945f3e 100644
--- a/kms++util/src/testpat.cpp
+++ b/kms++util/src/testpat.cpp
@@ -355,6 +355,12 @@ static void draw_test_pattern_part(IFramebuffer& fb, size_t start_y, size_t end_
generate_line_yuv); \
break;
+#define CASE_Y_ONLY(x) \
+ case PixelFormat::x: \
+ Y_Writer<x##_Layout>::write_pattern(fb, start_y, end_y, \
+ generate_line_yuv); \
+ break;
+
switch (fb.format()) {
CASE_YUV_SEMI(XV20);
CASE_YUV_SEMI(XV15);
@@ -405,6 +411,9 @@ static void draw_test_pattern_part(IFramebuffer& fb, size_t start_y, size_t end_
CASE_YUV_PLANAR(YUV420);
CASE_YUV_PLANAR(YVU420);
+ CASE_Y_ONLY(Y8);
+ CASE_Y_ONLY(Y10_P32);
+
default:
break;
}