17 template<std::
unsigned_
integral Pixel>
24 template<std::
unsigned_
integral Pixel>
26 FrameSource& src,
unsigned srcStartY,
unsigned srcEndY,
30 unsigned stopDstY = (dstEndY == dstHeight)
31 ? dstEndY : dstEndY - 3;
32 unsigned srcY = srcStartY, dstY = dstStartY;
33 for (; dstY < stopDstY; srcY += 1, dstY += 3) {
39 if (dstY != dstHeight) {
42 assert(nextLineWidth != 1);
43 this->dispatchScale(src, srcY, srcEndY, nextLineWidth,
48 template<std::
unsigned_
integral Pixel>
51 return pixelOps.template blend<1, 1>(p1, p2);
54 static constexpr
unsigned redblueMask = 0xF81F;
55 static constexpr
unsigned greenMask = 0x7E0;
58 template<std::
unsigned_
integral Pixel>
59 [[nodiscard]]
static Pixel bilinear(
unsigned a,
unsigned b,
unsigned x);
65 const unsigned areaB =
x >> 11;
66 const unsigned areaA = 0x20 - areaB;
68 a = (a & redblueMask) | ((a & greenMask) << 16);
69 b = (b & redblueMask) | ((b & greenMask) << 16);
70 const unsigned result = ((areaA * a) + (areaB * b)) >> 5;
71 return (result & redblueMask) | ((result >> 16) & greenMask);
78 const unsigned areaB =
x >> 8;
79 const unsigned areaA = 0x100 - areaB;
81 const unsigned result0 =
82 ((a & 0x00FF00FF) * areaA + (b & 0x00FF00FF) * areaB) >> 8;
83 const unsigned result1 =
84 ((a & 0xFF00FF00) >> 8) * areaA + ((b & 0xFF00FF00) >> 8) * areaB;
85 return (result0 & 0x00FF00FF) | (result1 & 0xFF00FF00);
89 template<std::
unsigned_
integral Pixel> [[nodiscard]]
static Pixel bilinear4(
90 unsigned a,
unsigned b,
unsigned c,
unsigned d,
unsigned x,
unsigned y);
93 unsigned a,
unsigned b,
unsigned c,
unsigned d,
unsigned x,
unsigned y)
97 const unsigned xy = (
x * y) >> 5;
99 const unsigned areaA = 0x20 + xy -
x - y;
100 const unsigned areaB =
x - xy;
101 const unsigned areaC = y - xy;
102 const unsigned areaD = xy;
104 a = (a & redblueMask) | ((a & greenMask) << 16);
105 b = (b & redblueMask) | ((b & greenMask) << 16);
106 c = (c & redblueMask) | ((c & greenMask) << 16);
107 d = (d & redblueMask) | ((d & greenMask) << 16);
109 (areaA * a) + (areaB * b) + (areaC * c) + (areaD * d)
111 return (result & redblueMask) | ((result >> 16) & greenMask);
115 unsigned a,
unsigned b,
unsigned c,
unsigned d,
unsigned x,
unsigned y)
119 const unsigned xy = (
x * y) >> 8;
121 const unsigned areaA = (1 << 8) + xy -
x - y;
122 const unsigned areaB =
x - xy;
123 const unsigned areaC = y - xy;
124 const unsigned areaD = xy;
126 const unsigned result0 =
127 ((a & 0x00FF00FF) * areaA + (b & 0x00FF00FF) * areaB +
128 (c & 0x00FF00FF) * areaC + (d & 0x00FF00FF) * areaD) >> 8;
129 const unsigned result1 =
130 ((a & 0xFF00FF00) >> 8) * areaA + ((b & 0xFF00FF00) >> 8) * areaB +
131 ((c & 0xFF00FF00) >> 8) * areaC + ((d & 0xFF00FF00) >> 8) * areaD;
132 return (result0 & 0x00FF00FF) | (result1 & 0xFF00FF00);
135 template<std::
unsigned_
integral Pixel>
140 [[nodiscard]]
inline static Pixel blend(
unsigned a,
unsigned b);
142 template<
unsigned x,
unsigned y>
143 [[nodiscard]]
inline static Pixel blend(
unsigned a,
unsigned b,
unsigned c,
unsigned d);
146 template<
unsigned X,
unsigned OLD,
unsigned NEW>
148 static_assert(OLD > NEW);
150 (X >> (OLD - NEW)) + ((X >> (OLD - NEW - 1)) & 1);
153 template<std::
unsigned_
integral Pixel>
157 if (a == b)
return a;
159 const unsigned bits = (
sizeof(
Pixel) == 2) ? 5 : 8;
161 const unsigned areaA = (1 << bits) - areaB;
163 if constexpr (
sizeof(
Pixel) == 2) {
164 a = (a & redblueMask) | ((a & greenMask) << 16);
165 b = (b & redblueMask) | ((b & greenMask) << 16);
166 const unsigned result = ((areaA * a) + (areaB * b)) >> bits;
167 return (result & redblueMask) | ((result >> 16) & greenMask);
169 const unsigned result0 =
170 ((a & 0x00FF00FF) * areaA +
171 (b & 0x00FF00FF) * areaB) >> bits;
172 const unsigned result1 =
173 ((a & 0xFF00FF00) >> bits) * areaA +
174 ((b & 0xFF00FF00) >> bits) * areaB;
175 return (result0 & 0x00FF00FF) | (result1 & 0xFF00FF00);
179 template<std::
unsigned_
integral Pixel>
180 template<
unsigned wx,
unsigned wy>
182 unsigned a,
unsigned b,
unsigned c,
unsigned d)
184 const unsigned bits = (
sizeof(
Pixel) == 2) ? 5 : 8;
185 const unsigned xy = (wx * wy) >> 16;
186 const unsigned areaB =
Round<wx - xy, 16, bits>::result;
187 const unsigned areaC =
Round<wy - xy, 16, bits>::result;
189 const unsigned areaA = (1 << bits) - areaB - areaC - areaD;
191 if constexpr (
sizeof(
Pixel) == 2) {
192 a = (a & redblueMask) | ((a & greenMask) << 16);
193 b = (b & redblueMask) | ((b & greenMask) << 16);
194 c = (c & redblueMask) | ((c & greenMask) << 16);
195 d = (d & redblueMask) | ((d & greenMask) << 16);
197 (areaA * a) + (areaB * b) + (areaC * c) + (areaD * d)
199 return (result & redblueMask) | ((result >> 16) & greenMask);
201 const unsigned result0 =
202 ((a & 0x00FF00FF) * areaA +
203 (b & 0x00FF00FF) * areaB +
204 (c & 0x00FF00FF) * areaC +
205 (d & 0x00FF00FF) * areaD) >> bits;
206 const unsigned result1 =
207 ((a & 0xFF00FF00) >> bits) * areaA +
208 ((b & 0xFF00FF00) >> bits) * areaB +
209 ((c & 0xFF00FF00) >> bits) * areaC +
210 ((d & 0xFF00FF00) >> bits) * areaD;
211 return (result0 & 0x00FF00FF) | (result1 & 0xFF00FF00);
219 template<std::
unsigned_
integral Pixel>
225 template<
unsigned NX,
unsigned y, std::
unsigned_
integral Pixel>
228 unsigned sa,
unsigned sb,
unsigned sc,
unsigned sd,
229 unsigned se,
unsigned sg,
unsigned sj,
unsigned sl)
232 const unsigned x1 = ((NX - i) << 16) / NX;
233 const unsigned y1 = y;
234 const unsigned f1 = (x1 >> 1) + (0x10000 >> 2);
235 const unsigned f2 = (y1 >> 1) + (0x10000 >> 2);
236 if (y1 <= f1 && sa == sj && sa != se) {
238 }
else if (y1 >= f1 && sa == sg && sa != sl) {
240 }
else if (x1 >= f2 && sa == se && sa != sj) {
242 }
else if (x1 <= f2 && sa == sl && sa != sg) {
244 }
else if (y1 >= x1) {
246 }
else if (y1 <= x1) {
250 dp, sa, sb, sc, sd, se, sg, sj, sl);
253 template<
unsigned NX,
unsigned y, std::
unsigned_
integral Pixel>
256 unsigned sa,
unsigned sb,
unsigned sc,
unsigned sd,
257 unsigned sf,
unsigned sh,
unsigned si,
unsigned sk)
260 const unsigned x1 = ((NX - i) << 16) / NX;
261 const unsigned x2 = 0x10000 - x1;
262 const unsigned y1 = y;
263 const unsigned y2 = 0x10000 - y1;
264 const unsigned f1 = (x1 >> 1) + (0x10000 >> 2);
265 const unsigned f2 = (y1 >> 1) + (0x10000 >> 2);
266 if (y2 >= f1 && sb == sh && sb != sf) {
268 }
else if (y2 <= f1 && sb == si && sb != sk) {
270 }
else if (x2 >= f2 && sb == sf && sb != sh) {
272 }
else if (x2 <= f2 && sb == sk && sb != si) {
274 }
else if (y2 >= x1) {
276 }
else if (y2 <= x1) {
280 dp, sa, sb, sc, sd, sf, sh, si, sk);
283 template<
unsigned NX,
unsigned y, std::
unsigned_
integral Pixel>
285 Pixel*& dp,
unsigned sa,
unsigned sb,
unsigned sc,
unsigned sd)
287 const unsigned x = ((NX - i) << 16) / NX;
296 template<std::
unsigned_
integral Pixel>
299 template<
unsigned NX,
unsigned y, std::
unsigned_
integral Pixel>
301 Pixel*& ,
unsigned ,
unsigned ,
302 unsigned ,
unsigned ,
unsigned ,
303 unsigned ,
unsigned ,
unsigned ) { }
305 template<
unsigned NX,
unsigned y, std::
unsigned_
integral Pixel>
307 Pixel*& ,
unsigned ,
unsigned ,
308 unsigned ,
unsigned ,
unsigned ,
309 unsigned ,
unsigned ,
unsigned ) { }
311 template<
unsigned NX,
unsigned y, std::
unsigned_
integral Pixel>
313 unsigned ,
unsigned ,
unsigned ) { }
320 template<
unsigned NX,
unsigned NY, std::
unsigned_
integral Pixel>
322 const Pixel* __restrict src0,
const Pixel* __restrict src1,
323 const Pixel* __restrict src2,
const Pixel* __restrict src3,
329 static constexpr
unsigned y1 = ((NY - i) << 16) / NY;
337 const unsigned pos0 = pos1;
340 pos3 =
std::min(pos1 + 3, srcWidth) - 1;
348 if (sa == sb && sc == sd && sa == sc) {
351 }
else if (sa == sd && sb != sc) {
354 dp, sa, sb, sc, sd, src0[pos1], src1[pos0], src2[pos3], src3[pos2]);
355 }
else if (sb == sc && sa != sd) {
358 dp, sa, sb, sc, sd, src0[pos2], src2[pos0], src1[pos3], src3[pos1]);
368 LineRepeater<i - 1>::template scaleFixedLine<NX, NY, Pixel>(
369 src0, src1, src2, src3, srcWidth, dst, dstY);
376 template<
unsigned NX,
unsigned NY, std::
unsigned_
integral Pixel>
379 const Pixel* ,
unsigned ,
384 template<std::
unsigned_
integral Pixel>
385 template<
unsigned NX,
unsigned NY>
386 void SaI3xScaler<Pixel>::scaleFixed(FrameSource& src,
387 unsigned srcStartY,
unsigned ,
unsigned srcWidth,
388 ScalerOutput<Pixel>& dst,
unsigned dstStartY,
unsigned dstEndY)
390 assert(dst.getWidth() == srcWidth * NX);
391 assert(dst.getHeight() == src.getHeight() * NY);
398 int srcY = srcStartY;
399 auto* src0 = src.getLinePtr(srcY - 1, srcWidth, buf0);
400 auto* src1 = src.getLinePtr(srcY + 0, srcWidth, buf1);
401 auto* src2 = src.getLinePtr(srcY + 1, srcWidth, buf2);
403 for (
auto dstY :
xrange(dstStartY, dstEndY)) {
404 auto* src3 = src.getLinePtr(srcY + 2, srcWidth, buf3);
405 LineRepeater<NY>::template scaleFixedLine<NX, NY, Pixel>(
406 src0, src1, src2, src3, srcWidth, dst, dstY);
410 std::swap(buf0, buf1);
411 std::swap(buf1, buf2);
412 std::swap(buf2, buf3);
416 template<std::
unsigned_
integral Pixel>
417 void SaI3xScaler<Pixel>::scaleAny(FrameSource& src,
418 unsigned srcStartY,
unsigned ,
unsigned srcWidth,
419 ScalerOutput<Pixel>& dst,
unsigned dstStartY,
unsigned dstEndY) __restrict
422 const unsigned wFinish = (srcWidth - 1) << 16;
423 const unsigned dw = wFinish / (dst.getWidth() - 1);
424 const unsigned hFinish = (src.getHeight() - 1) << 16;
425 const unsigned dh = hFinish / (dst.getHeight() - 1);
433 for (
auto dstY :
xrange(dstStartY, dstEndY)) {
435 int line = srcStartY + (h >> 16);
437 auto* src0 = src.getLinePtr(line - 1, srcWidth, buf0);
438 auto* src1 = src.getLinePtr(line + 0, srcWidth, buf1);
439 auto* src2 = src.getLinePtr(line + 1, srcWidth, buf2);
440 auto* src3 = src.getLinePtr(line + 2, srcWidth, buf3);
443 auto* dstLine = dst.acquireLine(dstY);
447 const unsigned y1 = h & 0xffff;
448 const unsigned y2 = 0x10000 - y1;
457 for (
unsigned w = 0; w < wFinish; ) {
458 const unsigned pos0 = pos1;
461 pos3 =
std::min(pos1 + 3, srcWidth) - 1;
469 if (
A ==
B &&
C ==
D &&
A ==
C) {
473 }
while ((w >> 16) == pos1);
474 }
else if (
A ==
D &&
B !=
C) {
477 const unsigned x1 = w & 0xffff;
478 const unsigned f1 = (x1 >> 1) + (0x10000 >> 2);
479 const unsigned f2 = (y1 >> 1) + (0x10000 >> 2);
481 if (y1 <= f1 &&
A == src2[pos3] &&
A != src0[pos1]) {
482 product1 = bilinear<Pixel>(
A,
B, f1 - y1);
483 }
else if (y1 >= f1 &&
A == src1[pos0] &&
A != src3[pos2]) {
484 product1 = bilinear<Pixel>(
A,
C, y1 - f1);
485 }
else if (x1 >= f2 &&
A == src0[pos1] &&
A != src2[pos3]) {
486 product1 = bilinear<Pixel>(
A,
B, x1 - f2);
487 }
else if (x1 <= f2 &&
A == src3[pos2] &&
A != src1[pos0]) {
488 product1 = bilinear<Pixel>(
A,
C, f2 - x1);
489 }
else if (y1 >= x1) {
490 product1 = bilinear<Pixel>(
A,
C, y1 - x1);
493 product1 = bilinear<Pixel>(
A,
B, x1 - y1);
497 }
while ((w >> 16) == pos1);
498 }
else if (
B ==
C &&
A !=
D) {
501 const unsigned x1 = w & 0xffff;
502 const unsigned x2 = 0x10000 - x1;
503 const unsigned f1 = (x1 >> 1) + (0x10000 >> 2);
504 const unsigned f2 = (y1 >> 1) + (0x10000 >> 2);
506 if (y2 >= f1 &&
B == src2[pos0] &&
B != src0[pos2]) {
507 product1 = bilinear<Pixel>(
B,
A, y2 - f1);
508 }
else if (y2 <= f1 &&
B == src1[pos3] &&
B != src3[pos1]) {
509 product1 = bilinear<Pixel>(
B,
D, f1 - y2);
510 }
else if (x2 >= f2 &&
B == src0[pos2] &&
B != src2[pos0]) {
511 product1 = bilinear<Pixel>(
B,
A, x2 - f2);
512 }
else if (x2 <= f2 &&
B == src3[pos1] &&
B != src1[pos3]) {
513 product1 = bilinear<Pixel>(
B,
D, f2 - x2);
514 }
else if (y2 >= x1) {
515 product1 = bilinear<Pixel>(
B,
A, y2 - x1);
518 product1 = bilinear<Pixel>(
B,
D, x1 - y2);
522 }
while ((w >> 16) == pos1);
526 const unsigned x1 = w & 0xffff;
527 *dp++ = bilinear4<Pixel>(
A,
B,
C,
D, x1, y1);
529 }
while ((w >> 16) == pos1);
532 dst.releaseLine(dstY, dstLine);
536 template<std::
unsigned_
integral Pixel>
538 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
541 scaleFixed<3, 3>(src, srcStartY, srcEndY, srcWidth, dst, dstStartY, dstEndY);
static Pixel blend(unsigned a, unsigned b)
Interface for getting lines from a video frame.
Pixel getLineColor(unsigned line) const
Get the (single) color of the given line.
virtual unsigned getLineWidth(unsigned line) const =0
Gets the number of display pixels on the given line.
static void scaleFixedLine(const Pixel *, const Pixel *, const Pixel *, const Pixel *, unsigned, ScalerOutput< Pixel > &, unsigned &)
static void scaleFixedLine(const Pixel *src0, const Pixel *src1, const Pixel *src2, const Pixel *src3, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned &dstY)
static void blendSlash(Pixel *&, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned)
static void blend4(Pixel *&, unsigned, unsigned, unsigned, unsigned)
static void fill(Pixel *&, unsigned)
static void blendBackslash(Pixel *&, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned)
static void blendBackslash(Pixel *&dp, unsigned sa, unsigned sb, unsigned sc, unsigned sd, unsigned se, unsigned sg, unsigned sj, unsigned sl)
static void fill(Pixel *&dp, unsigned sa)
static void blendSlash(Pixel *&dp, unsigned sa, unsigned sb, unsigned sc, unsigned sd, unsigned sf, unsigned sh, unsigned si, unsigned sk)
static void blend4(Pixel *&dp, unsigned sa, unsigned sb, unsigned sc, unsigned sd)
2xSaI algorithm: edge-detection which produces a rounded look.
void scale1x1to3x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scaleBlank1to3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
SaI3xScaler(const PixelOperations< Pixel > &pixelOps)
Base class for 3x scalers.
virtual Pixel * acquireLine(unsigned y)=0
virtual unsigned getHeight() const =0
virtual void fillLine(unsigned y, Pixel color)=0
virtual void releaseLine(unsigned y, Pixel *buf)=0
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
This file implemented 3 utility functions:
uint16_t bilinear< uint16_t >(unsigned a, unsigned b, unsigned x)
uint32_t bilinear4< uint32_t >(unsigned a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned y)
constexpr KeyMatrixPosition x
Keyboard bindings.
uint32_t bilinear< uint32_t >(unsigned a, unsigned b, unsigned x)
uint16_t bilinear4< uint16_t >(unsigned a, unsigned b, unsigned c, unsigned d, unsigned x, unsigned y)
static constexpr unsigned result
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
constexpr auto xrange(T e)