From e0b7d30fd437292c88141fb08d60681870b86c6e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 8 May 2026 17:22:58 +0300 Subject: Squashed 'subprojects/pixpat/' content from commit d444626 git-subtree-dir: subprojects/pixpat git-subtree-split: d444626e6ba988ec6d487800721e447f94b1eaf5 --- pixpat-native/src/layout.h | 141 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 pixpat-native/src/layout.h (limited to 'pixpat-native/src/layout.h') diff --git a/pixpat-native/src/layout.h b/pixpat-native/src/layout.h new file mode 100644 index 0000000..d092bb1 --- /dev/null +++ b/pixpat-native/src/layout.h @@ -0,0 +1,141 @@ +#pragma once + +#include +#include +#include +#include + +namespace pixpat +{ + +enum class ColorKind { RGB, YUV }; + +// Normalized inter-stage pixel types. 16-bit-per-component integer. +// N-bit storage values bit-replicate up to normalized 16-bit (so +// N-bit max maps to 0xFFFF); encoding back is a truncating +// `normalized >> (16 - N)`. See io/detail.h for the round-trip +// argument. Sources without an A component emit a=0; cross-color-kind +// ColorXfm resets a=0xFFFF; sinks with X write 0, sinks with A +// encode `a`. +struct RGB16 { + static constexpr ColorKind kind = ColorKind::RGB; + uint16_t r, g, b, a; +}; + +struct YUV16 { + static constexpr ColorKind kind = ColorKind::YUV; + uint16_t y, u, v, a; +}; + +inline constexpr uint16_t kNormMax = 0xFFFF; + +enum class C : uint8_t { X, A, R, G, B, Y, U, V }; + +struct Comp { + C c; + uint8_t bits; + uint8_t shift; +}; + +template +struct Plane { + using storage_t = Storage; + + static constexpr size_t num_comps = sizeof...(Cs); + static constexpr std::array comps{ Cs ... }; + static constexpr size_t total_bits = (size_t(Cs.bits) + ... + 0); + static constexpr size_t storage_bits = sizeof(Storage) * 8; + static constexpr size_t bytes_per_pixel = (total_bits + 7) / 8; + + static_assert(total_bits <= storage_bits, "components overflow storage word"); + + // Index of the n-th component matching Tag, or num_comps if absent. + template + static constexpr size_t find_pos(size_t n = 0) + { + for (size_t i = 0; i < num_comps; ++i) { + if (comps[i].c == Tag) { + if (n == 0) + return i; + --n; + } + } + return num_comps; + } + + // Count of components matching Tag. Used to derive + // pixels_per_word for multi-pixel-per-storage formats (XYYY2101010, + // P030, ...). + template + static constexpr size_t component_count() + { + size_t cnt = 0; + for (size_t i = 0; i < num_comps; ++i) + if (comps[i].c == Tag) + ++cnt; + return cnt; + } + + // Mask each input value to its bit-width and OR-shift it into the + // storage word. The loop trip count and the comps[i] reads are + // compile-time constant, so the optimizer unrolls and folds. + static constexpr Storage pack(const std::array& v) noexcept + { + Storage out{}; + for (size_t i = 0; i < num_comps; ++i) { + const Storage mask = (Storage{ 1 } << comps[i].bits) - 1; + out |= Storage(v[i] & mask) << comps[i].shift; + } + return out; + } + + // Mirror of `pack`. + static constexpr std::array unpack(Storage word) noexcept + { + std::array out{}; + for (size_t i = 0; i < num_comps; ++i) { + const Storage mask = (Storage{ 1 } << comps[i].bits) - 1; + out[i] = uint16_t((word >> comps[i].shift) & mask); + } + return out; + } +}; + +template +struct Layout { + static constexpr ColorKind kind = Kind; + static constexpr size_t h_sub = Hsub; + static constexpr size_t v_sub = Vsub; + static constexpr size_t num_planes = sizeof...(Planes); + + template + using plane = std::tuple_element_t >; + + // Index of the first plane containing component Tag, or num_planes + // if no plane has it. Lets PlanarSource/Sink map C::U / C::V to a + // plane regardless of YUV vs YVU ordering. + // Comma-fold over plane indices: for each plane I check if it has + // Tag, and on the first hit assign `found = I`. Subsequent hits are + // suppressed by the `found == num_planes` guard. The whole fold + // evaluates to a discarded list of int 0s; the `found` capture + // carries the result out. + template + static constexpr size_t find_plane() + { + return [&](std::index_sequence) { + size_t found = num_planes; + ((plane::template find_pos() < plane::num_comps + ? (found == num_planes ? (found = I, 0) : 0) + : 0), ...); + return found; + } (std::make_index_sequence{}); + } +}; + +template +struct Buffer { + std::array data; + std::array stride; +}; + +} // namespace pixpat -- cgit v1.2.3