19template<std::
unsigned_
integral Pixel>
26template<std::
unsigned_
integral Pixel>
28 FrameSource& src,
unsigned srcStartY,
unsigned srcEndY,
32 unsigned stopDstY = (dstEndY == dstHeight)
33 ? dstEndY : dstEndY - 2;
34 unsigned srcY = srcStartY, dstY = dstStartY;
35 for (; dstY < stopDstY; srcY += 1, dstY += 2) {
40 if (dstY != dstHeight) {
43 assert(nextLineWidth != 1);
44 this->dispatchScale(src, srcY, srcEndY, nextLineWidth,
49template<std::
unsigned_
integral Pixel>
52 return pixelOps.template blend<1, 1>(p1, p2);
55template<std::
unsigned_
integral Pixel>
56void SaI2xScaler<Pixel>::scaleLine1on2(
57 std::span<const Pixel> srcLine0, std::span<const Pixel> srcLine1,
58 std::span<const Pixel> srcLine2, std::span<const Pixel> srcLine3,
59 std::span<Pixel> dstUpper, std::span<Pixel> dstLower)
61 auto srcWidth = srcLine0.size();
62 assert(srcLine0.size() == srcWidth);
63 assert(srcLine1.size() == srcWidth);
64 assert(srcLine2.size() == srcWidth);
65 assert(srcLine3.size() == srcWidth);
66 assert(dstUpper.size() == 2 * srcWidth);
67 assert(dstLower.size() == 2 * srcWidth);
70 for (
auto x :
xrange(srcWidth)) {
77 auto xl = x ? x - 1 : 0;
78 auto xr =
std::min(x + 1, srcWidth - 1);
79 auto xrr =
std::min(x + 2, srcWidth - 1);
85 Pixel colorI = srcLine0[xl];
86 Pixel colorE = srcLine0[x];
87 Pixel colorF = srcLine0[xr];
88 Pixel colorJ = srcLine0[xrr];
90 Pixel colorG = srcLine1[xl];
91 Pixel colorA = srcLine1[x];
92 Pixel colorB = srcLine1[xr];
93 Pixel colorK = srcLine1[xrr];
95 Pixel colorH = srcLine2[xl];
96 Pixel colorC = srcLine2[x];
97 Pixel colorD = srcLine2[xr];
98 Pixel colorL = srcLine2[xrr];
100 Pixel colorM = srcLine3[xl];
101 Pixel colorN = srcLine3[x];
102 Pixel colorO = srcLine3[xr];
105 Pixel product, product1, product2;
106 if (colorA == colorD && colorB != colorC) {
107 product = ((colorA == colorE && colorB == colorL) ||
108 (colorA == colorC && colorA == colorF &&
109 colorB != colorE && colorB == colorJ))
111 : blend(colorA, colorB);
112 product1 = ((colorA == colorG && colorC == colorO) ||
113 (colorA == colorB && colorA == colorH &&
114 colorG != colorC && colorC == colorM))
116 : blend(colorA, colorC);
118 }
else if (colorB == colorC && colorA != colorD) {
119 product = ((colorB == colorF && colorA == colorH) ||
120 (colorB == colorE && colorB == colorD &&
121 colorA != colorF && colorA == colorI))
123 : blend(colorA, colorB);
124 product1 = ((colorC == colorH && colorA == colorF) ||
125 (colorC == colorG && colorC == colorD &&
126 colorA != colorH && colorA == colorI))
128 : blend(colorA, colorC);
130 }
else if (colorA == colorD && colorB == colorC) {
131 if (colorA == colorB) {
132 product = product1 = product2 = colorA;
135 if (colorE == colorG) {
136 if (colorA == colorE) r--;
137 else if (colorB == colorE) r++;
139 if (colorF == colorK) {
140 if (colorA == colorF) r--;
141 else if (colorB == colorF) r++;
143 if (colorH == colorN) {
144 if (colorA == colorH) r--;
145 else if (colorB == colorH) r++;
147 if (colorL == colorO) {
148 if (colorA == colorL) r--;
149 else if (colorB == colorL) r++;
151 product = product1 = blend(colorA, colorB);
152 product2 = r > 0 ? colorA : (r < 0 ? colorB : product);
155 product = (colorA == colorC && colorA == colorF &&
156 colorB != colorE && colorB == colorJ)
158 : ((colorB == colorE && colorB == colorD &&
159 colorA != colorF && colorA == colorI)
161 : blend(colorA, colorB));
162 product1 = (colorA == colorB && colorA == colorH &&
163 colorG != colorC && colorC == colorM)
165 : ((colorC == colorG && colorC == colorD &&
166 colorA != colorH && colorA == colorI)
168 : blend(colorA, colorC));
170 blend(colorA, colorB),
171 blend(colorC, colorD));
174 dstUpper[x * 2 + 0] = colorA;
175 dstUpper[x * 2 + 1] = product;
176 dstLower[x * 2 + 0] = product1;
177 dstLower[x * 2 + 1] = product2;
181template<std::
unsigned_
integral Pixel>
182void SaI2xScaler<Pixel>::scaleLine1on1(
183 std::span<const Pixel> srcLine0, std::span<const Pixel> srcLine1,
184 std::span<const Pixel> srcLine2, std::span<const Pixel> srcLine3,
185 std::span<Pixel> dstUpper, std::span<Pixel> dstLower)
187 auto srcWidth = srcLine0.size();
188 assert(srcLine0.size() == srcWidth);
189 assert(srcLine1.size() == srcWidth);
190 assert(srcLine2.size() == srcWidth);
191 assert(srcLine3.size() == srcWidth);
192 assert(dstUpper.size() == srcWidth);
193 assert(dstLower.size() == srcWidth);
198 dstUpper[0] = srcLine1[0];
199 dstLower[0] = blend(srcLine1[0], srcLine2[0]);
200 for (
auto x :
xrange(1u, srcWidth - 1)) {
207 Pixel colorI = srcLine0[x - 1];
209 Pixel colorF = srcLine0[x + 1];
211 Pixel colorG = srcLine1[x - 1];
212 Pixel colorA = srcLine1[x];
213 Pixel colorB = srcLine1[x + 1];
215 Pixel colorH = srcLine2[x - 1];
216 Pixel colorC = srcLine2[x];
217 Pixel colorD = srcLine2[x + 1];
219 Pixel colorM = srcLine3[x - 1];
221 Pixel colorO = srcLine3[x + 1];
224 if (colorA == colorD && colorB != colorC) {
225 product1 = ((colorA == colorG && colorC == colorO) ||
226 (colorA == colorB && colorA == colorH &&
227 colorG != colorC && colorC == colorM))
229 : blend(colorA, colorC);
230 }
else if (colorB == colorC && colorA != colorD) {
231 product1 = ((colorC == colorH && colorA == colorF) ||
232 (colorC == colorG && colorC == colorD &&
233 colorA != colorH && colorA == colorI))
235 : blend(colorA, colorC);
236 }
else if (colorA == colorD && colorB == colorC) {
237 product1 = (colorA == colorC)
239 : blend(colorA, colorC);
241 product1 = (colorA == colorB && colorA == colorH &&
242 colorG != colorC && colorC == colorM)
244 : ((colorC == colorG && colorC == colorD &&
245 colorA != colorH && colorA == colorI)
247 : blend(colorA, colorC));
250 dstUpper[x] = colorA;
251 dstLower[x] = product1;
253 dstUpper[srcWidth - 1] = srcLine1[srcWidth - 1];
254 dstLower[srcWidth - 1] =
255 blend(srcLine1[srcWidth - 1], srcLine2[srcWidth - 1]);
258template<std::
unsigned_
integral Pixel>
260 unsigned srcStartY,
unsigned ,
unsigned srcWidth,
263 assert(dst.
getWidth() == srcWidth * 2);
270 auto srcY = narrow<int>(srcStartY);
271 auto srcLine0 = src.
getLine(srcY - 1, buf0);
272 auto srcLine1 = src.
getLine(srcY + 0, buf1);
273 auto srcLine2 = src.
getLine(srcY + 1, buf2);
275 for (
unsigned dstY = dstStartY; dstY < dstEndY; srcY += 1, dstY += 2) {
276 auto srcLine3 = src.
getLine(srcY + 2, buf3);
279 scaleLine1on2(srcLine0, srcLine1, srcLine2, srcLine3,
292template<std::
unsigned_
integral Pixel>
294 unsigned srcStartY,
unsigned ,
unsigned srcWidth,
304 auto srcY = narrow<int>(srcStartY);
305 auto srcLine0 = src.
getLine(srcY - 1, buf0);
306 auto srcLine1 = src.
getLine(srcY + 0, buf1);
307 auto srcLine2 = src.
getLine(srcY + 1, buf2);
309 for (
unsigned dstY = dstStartY; dstY < dstEndY; srcY += 1, dstY += 2) {
310 auto srcLine3 = src.
getLine(srcY + 2, buf3);
313 scaleLine1on1(srcLine0, srcLine1, srcLine2, srcLine3,
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.
std::span< const Pixel > getLine(int line, std::span< Pixel > buf) const
Gets a pointer to the pixels of the given line number.
2xSaI algorithm: edge-detection which produces a rounded look.
SaI2xScaler(const PixelOperations< Pixel > &pixelOps)
void scale1x1to2x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scaleBlank1to2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale1x1to1x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Base class for 2x scalers.
virtual unsigned getWidth() const =0
virtual unsigned getHeight() const =0
virtual void fillLine(unsigned y, Pixel color)=0
virtual void releaseLine(unsigned y, std::span< Pixel > buf)=0
virtual std::span< Pixel > acquireLine(unsigned y)=0
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
This file implemented 3 utility functions:
void swap(openmsx::MemBuffer< T > &l, openmsx::MemBuffer< T > &r) noexcept
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
constexpr auto xrange(T e)