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
|
// Pattern-feature TU: built only when PIXPAT_FEATURE_PATTERN is on
// (controlled by the meson source list). pixpat.cpp's pixpat_draw_pattern
// entry calls into dispatch_draw_pattern() below via if-constexpr; when
// the feature is off this file isn't compiled, the discarded if-constexpr
// branch emits no symbol reference, and the .so simply lacks these
// symbols.
#include <cassert>
#include <cstdint>
#include <string_view>
#include <type_traits>
#include <vector>
#include "color.h"
#include "error.h"
#include "params.h"
#include "pattern.h"
#include "pattern_catalog.h"
#include "pipeline.h"
#include "pixpat_internal.h"
namespace pixpat
{
// Generated: s_pattern_* enable flags + DefaultPattern alias. Included
// inside namespace pixpat so the unqualified FormatId / s_format_catalog_count
// references resolve.
#include "pixpat_caps.inc"
// Cold pattern path: fill a per-thread normalized line buffer with
// Pattern samples in the pattern's native color kind, run a cross-
// color-kind pass over the buffer if the sink wants the other kind,
// then hand the buffer to the destination's per-format pack via
// s_format_info. Same shape as run_norm in pixpat_convert.cpp.
template <typename Pattern>
static void run_pattern_norm(const Pattern& pat,
FormatId dst_id, const pixpat_buffer* dst,
size_t W, size_t H,
size_t by_start, size_t by_end,
ColorSpec spec)
{
using P = typename Pattern::Pixel;
constexpr bool pat_is_rgb = std::is_same_v<P, RGB16>;
const auto& di = s_format_info[size_t(dst_id)];
const size_t bh = di.snk_block_h;
// Entry point (pixpat_draw_pattern) validates W%bw / H%bh.
assert(W % di.snk_block_w == 0 && H % bh == 0);
thread_local std::vector<uint8_t> norm;
norm.resize(bh * W * sizeof(RGB16)); // RGB16 / YUV16 same size
const ColorCoeffs c = coeffs_for(spec);
const bool need_xfm = (pat_is_rgb && di.kind == ColorKind::YUV) ||
(!pat_is_rgb && di.kind == ColorKind::RGB);
for (size_t by = by_start; by < by_end; by += bh) {
auto* px = reinterpret_cast<P*>(norm.data());
for (size_t dy = 0; dy < bh; ++dy)
for (size_t x = 0; x < W; ++x)
px[dy * W + x] = pat.sample(x, by + dy, W, H);
if (need_xfm) {
const size_t n = bh * W;
if constexpr (pat_is_rgb)
norm_rgb_to_yuv(norm.data(), n, c);
else
norm_yuv_to_rgb(norm.data(), n, c);
}
di.pack(dst, norm.data(), by, W);
}
}
// Construct, ready-check, and run a pattern. Patterns whose colors
// depend on the call's ColorSpec (e.g. native-YUV bar variants) opt
// in by exposing a (Params, ColorSpec) constructor; the rest take
// Params only and stay unchanged.
template <typename Pattern>
static void run_one_pattern(const Params& params,
FormatId id, const pixpat_buffer* dst,
size_t W, size_t H,
size_t by_start, size_t by_end,
ColorSpec spec)
{
auto pat = [&] {
if constexpr (std::is_constructible_v<
Pattern, const Params&, ColorSpec>)
return Pattern(params, spec);
else
return Pattern(params);
}();
if constexpr (requires { pat.ready(); }) {
if (!pat.ready())
throw invalid_argument("pattern parameters not accepted");
}
run_pattern_norm(pat, id, dst, W, H, by_start, by_end, spec);
}
// Per-pattern dispatch arm. Templated on the catalog row's RGB and
// YUV variants (either may be `void` if the pattern has no variant
// in that kind). When both are present, the sink kind picks the
// matching variant so the cross-kind pass is a no-op; when only one
// is present, the pipeline runs the cross-kind pass for opposite-
// kind sinks.
//
// Wrapping in a templated helper is what keeps the binary size down:
// `if constexpr (Enabled = false)` discards the run_pattern_norm
// reference, and because try_pattern is itself a template, the
// discarded branch is *not instantiated* — so disabled patterns
// emit no code, and the `void` arms of partial patterns never
// instantiate `Pattern::Pixel` or run_pattern_norm<void>.
template <bool Enabled, typename Rgb, typename Yuv>
static bool try_pattern(std::string_view name, std::string_view want,
const Params& params,
FormatId id, ColorKind sink_kind,
const pixpat_buffer* dst,
size_t W, size_t H,
size_t by_start, size_t by_end,
ColorSpec spec)
{
if constexpr (Enabled) {
if (name == want) {
constexpr bool has_rgb = !std::is_void_v<Rgb>;
constexpr bool has_yuv = !std::is_void_v<Yuv>;
static_assert(has_rgb || has_yuv,
"pattern needs at least one variant");
if constexpr (has_rgb && has_yuv) {
if (sink_kind == ColorKind::YUV)
run_one_pattern<Yuv>(params, id, dst, W, H,
by_start, by_end, spec);
else
run_one_pattern<Rgb>(params, id, dst, W, H,
by_start, by_end, spec);
} else if constexpr (has_rgb) {
run_one_pattern<Rgb>(params, id, dst, W, H,
by_start, by_end, spec);
} else {
run_one_pattern<Yuv>(params, id, dst, W, H,
by_start, by_end, spec);
}
return true;
}
}
return false;
}
void dispatch_draw_pattern(FormatId id, const char* pattern_name,
const Params& params,
const pixpat_buffer* dst,
size_t W, size_t H,
size_t by_start, size_t by_end,
ColorSpec spec)
{
using namespace patterns;
// NULL pattern_name selects the default ("kmstest"); see pixpat.h.
const std::string_view name = pattern_name ? pattern_name : "kmstest";
const ColorKind kind = s_format_info[size_t(id)].kind;
#define X(label, rgb, yuv, str) \
if (try_pattern<s_pattern_caps[size_t(PatternId::label)].enabled, rgb, yuv>( \
name, str, params, id, kind, dst, W, H, by_start, by_end, spec)) \
return;
PIXPAT_PATTERN_LIST(X)
#undef X
throw invalid_argument("unknown or disabled pattern name");
}
} // namespace pixpat
|