openMSX
Scaler1.cc
Go to the documentation of this file.
1#include "Scaler1.hh"
2#include "LineScalers.hh"
3#include "FrameSource.hh"
5#include "vla.hh"
6#include "unreachable.hh"
7#include "xrange.hh"
8#include "build-info.hh"
9#include <algorithm>
10#include <cassert>
11#include <cstdint>
12
13namespace openmsx {
14
15template<std::unsigned_integral Pixel>
17 : pixelOps(pixelOps_)
18{
19}
20
21/*template<std::unsigned_integral Pixel>
22void Scaler1<Pixel>::averageHalve(const Pixel* pIn0, const Pixel* pIn1, Pixel* pOut, unsigned dstWidth)
23{
24 // TODO SSE optimizations
25 // pure C++ version
26 for (auto i : xrange(dstWidth)) {
27 Pixel tmp0 = blend(pIn0[2 * i + 0], pIn0[2 * i + 1]);
28 Pixel tmp1 = blend(pIn1[2 * i + 0], pIn1[2 * i + 1]);
29 pOut[i] = blend(tmp0, tmp1);
30 }
31}*/
32
33template<std::unsigned_integral Pixel>
35 FrameSource& src, unsigned srcStartY, unsigned /*srcEndY*/,
36 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
37{
38 for (unsigned srcY = srcStartY, dstY = dstStartY;
39 dstY < dstEndY; srcY += 1, dstY += 1) {
40 auto color = src.getLineColor<Pixel>(srcY);
41 dst.fillLine(dstY, color);
42 }
43}
44
45template<std::unsigned_integral Pixel>
47 FrameSource& src, unsigned srcStartY, unsigned /*srcEndY*/,
48 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
49{
50 for (unsigned srcY = srcStartY, dstY = dstStartY;
51 dstY < dstEndY; srcY += 2, dstY += 1) {
52 auto color0 = src.getLineColor<Pixel>(srcY + 0);
53 auto color1 = src.getLineColor<Pixel>(srcY + 1);
54 Pixel color01 = pixelOps.template blend<1, 1>(color0, color1);
55 dst.fillLine(dstY, color01);
56 }
57}
58
59template<std::unsigned_integral Pixel>
60static void doScale1(FrameSource& src,
61 unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
62 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY,
64{
65 VLA_SSE_ALIGNED(Pixel, buf, srcWidth);
66 for (unsigned srcY = srcStartY, dstY = dstStartY;
67 dstY < dstEndY; ++srcY, ++dstY) {
68 auto srcLine = src.getLine(srcY, buf);
69 auto dstLine = dst.acquireLine(dstY);
70 scale(srcLine, dstLine);
71 dst.releaseLine(dstY, dstLine);
72 }
73}
74
75template<std::unsigned_integral Pixel>
76static void doScaleDV(FrameSource& src,
77 unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
78 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY,
79 PixelOperations<Pixel> ops, PolyLineScaler<Pixel>& scale)
80{
81 BlendLines<Pixel> blend(ops);
82 unsigned dstWidth = dst.getWidth();
83 VLA_SSE_ALIGNED(Pixel, buf02, std::max(srcWidth, dstWidth));
84 VLA_SSE_ALIGNED(Pixel, buf1, srcWidth);
85 auto buf0 = buf02.subspan(0, srcWidth);
86 auto buf2 = buf02.subspan(0, dstWidth);
87 for (unsigned srcY = srcStartY, dstY = dstStartY;
88 dstY < dstEndY; srcY += 2, dstY += 1) {
89 auto srcLine0 = src.getLine(srcY + 0, buf0);
90 auto srcLine1 = src.getLine(srcY + 1, buf1);
91 auto dstLine = dst.acquireLine(dstY);
92 scale(srcLine0, dstLine); // buf02 -> dstLine
93 scale(srcLine1, buf2); // buf1 -> buf02
94 blend(dstLine, buf0, dstLine); // dstLine + buf02 -> dstLine
95 dst.releaseLine(dstY, dstLine);
96 }
97}
98
99
100template<std::unsigned_integral Pixel>
102 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
103 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
104{
106 doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
107 dst, dstStartY, dstEndY, op);
108}
109
110template<std::unsigned_integral Pixel>
112 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
113 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
114{
116 doScaleDV<Pixel>(src, srcStartY, srcEndY, srcWidth,
117 dst, dstStartY, dstEndY, pixelOps, op);
118}
119
120template<std::unsigned_integral Pixel>
122 unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
123 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
124{
125 // Optimized variant: pass dstLine to getLine(), so we can
126 // potentially avoid the copy operation.
127 assert(dst.getWidth() == srcWidth); (void)srcWidth;
129 for (unsigned srcY = srcStartY, dstY = dstStartY;
130 dstY < dstEndY; ++srcY, ++dstY) {
131 auto dstLine = dst.acquireLine(dstY);
132 auto srcLine = src.getLine(srcY, dstLine);
133 if (srcLine.data() != dstLine.data()) copy(srcLine, dstLine);
134 dst.releaseLine(dstY, dstLine);
135 }
136}
137
138template<std::unsigned_integral Pixel>
140 unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
141 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
142{
143 // No need to scale to local buffer first, like doScaleDV does.
144 VLA_SSE_ALIGNED(Pixel, buf, srcWidth);
145 BlendLines<Pixel> blend(pixelOps);
146 for (auto dstY : xrange(dstStartY, dstEndY)) {
147 auto dstLine = dst.acquireLine(dstY);
148 auto srcLine0 = src.getLine(srcStartY++, dstLine); // dstLine
149 auto srcLine1 = src.getLine(srcStartY++, buf); // buf
150 blend(srcLine0, srcLine1, dstLine); // dstLine + buf -> dstLine
151 dst.releaseLine(dstY, dstLine);
152 }
153}
154
155template<std::unsigned_integral Pixel>
157 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
158 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
159{
161 doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
162 dst, dstStartY, dstEndY, op);
163}
164
165template<std::unsigned_integral Pixel>
167 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
168 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
169{
171 doScaleDV<Pixel>(src, srcStartY, srcEndY, srcWidth,
172 dst, dstStartY, dstEndY, pixelOps, op);
173}
174
175template<std::unsigned_integral Pixel>
177 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
178 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
179{
181 doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
182 dst, dstStartY, dstEndY, op);
183}
184
185template<std::unsigned_integral Pixel>
187 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
188 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
189{
191 doScaleDV<Pixel>(src, srcStartY, srcEndY, srcWidth,
192 dst, dstStartY, dstEndY, pixelOps, op);
193}
194
195template<std::unsigned_integral Pixel>
197 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
198 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
199{
201 doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
202 dst, dstStartY, dstEndY, op);
203}
204
205template<std::unsigned_integral Pixel>
207 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
208 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
209{
211 doScaleDV<Pixel>(src, srcStartY, srcEndY, srcWidth,
212 dst, dstStartY, dstEndY, pixelOps, op);
213}
214
215template<std::unsigned_integral Pixel>
217 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
218 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
219{
221 doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
222 dst, dstStartY, dstEndY, op);
223}
224
225template<std::unsigned_integral Pixel>
227 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
228 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
229{
231 doScaleDV<Pixel>(src, srcStartY, srcEndY, srcWidth,
232 dst, dstStartY, dstEndY, pixelOps, op);
233}
234
235template<std::unsigned_integral Pixel>
237 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
238 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
239{
240 if (src.getHeight() == 240) {
241 switch (srcWidth) {
242 case 1:
243 scaleBlank1to1(src, srcStartY, srcEndY,
244 dst, dstStartY, dstEndY);
245 break;
246 case 213:
247 scale2x1to3x1(src, srcStartY, srcEndY, srcWidth,
248 dst, dstStartY, dstEndY);
249 break;
250 case 320:
251 scale1x1to1x1(src, srcStartY, srcEndY, srcWidth,
252 dst, dstStartY, dstEndY);
253 break;
254 case 426:
255 scale4x1to3x1(src, srcStartY, srcEndY, srcWidth,
256 dst, dstStartY, dstEndY);
257 break;
258 case 640:
259 scale2x1to1x1(src, srcStartY, srcEndY, srcWidth,
260 dst, dstStartY, dstEndY);
261 break;
262 case 853:
263 scale8x1to3x1(src, srcStartY, srcEndY, srcWidth,
264 dst, dstStartY, dstEndY);
265 break;
266 case 1280:
267 scale4x1to1x1(src, srcStartY, srcEndY, srcWidth,
268 dst, dstStartY, dstEndY);
269 break;
270 default:
272 }
273 } else {
274 assert(src.getHeight() == 480);
275 switch (srcWidth) {
276 case 1:
277 scaleBlank2to1(src, srcStartY, srcEndY,
278 dst, dstStartY, dstEndY);
279 break;
280 case 213:
281 scale2x2to3x1(src, srcStartY, srcEndY, srcWidth,
282 dst, dstStartY, dstEndY);
283 break;
284 case 320:
285 scale1x2to1x1(src, srcStartY, srcEndY, srcWidth,
286 dst, dstStartY, dstEndY);
287 break;
288 case 426:
289 scale4x2to3x1(src, srcStartY, srcEndY, srcWidth,
290 dst, dstStartY, dstEndY);
291 break;
292 case 640:
293 scale2x2to1x1(src, srcStartY, srcEndY, srcWidth,
294 dst, dstStartY, dstEndY);
295 break;
296 case 853:
297 scale8x2to3x1(src, srcStartY, srcEndY, srcWidth,
298 dst, dstStartY, dstEndY);
299 break;
300 case 1280:
301 scale4x2to1x1(src, srcStartY, srcEndY, srcWidth,
302 dst, dstStartY, dstEndY);
303 break;
304 default:
306 }
307 }
308}
309
310template<std::unsigned_integral Pixel>
311void Scaler1<Pixel>::scaleImage(FrameSource& src, const RawFrame* superImpose,
312 unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
313 ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
314{
315 if (superImpose) {
317 dst, *superImpose, pixelOps);
318 dispatchScale(src, srcStartY, srcEndY, srcWidth,
319 dst2, dstStartY, dstEndY);
320 } else {
321 dispatchScale(src, srcStartY, srcEndY, srcWidth,
322 dst, dstStartY, dstEndY);
323 }
324}
325
326// Force template instantiation.
327#if HAVE_16BPP
328template class Scaler1<uint16_t>;
329#endif
330#if HAVE_32BPP
331template class Scaler1<uint32_t>;
332#endif
333
334} // namespace openmsx
BlendLines functor Generate an output line that is an interpolation of two input lines.
Definition: LineScalers.hh:230
Interface for getting lines from a video frame.
Definition: FrameSource.hh:20
Pixel getLineColor(unsigned line) const
Get the (single) color of the given line.
Definition: FrameSource.hh:79
std::span< const Pixel > getLine(int line, std::span< Pixel > buf) const
Gets a pointer to the pixels of the given line number.
Definition: FrameSource.hh:96
unsigned getHeight() const
Gets the number of lines in this frame.
Definition: FrameSource.hh:49
Polymorphic line scaler.
Definition: LineScalers.hh:286
Polymorphic wrapper around another line scaler.
Definition: LineScalers.hh:313
A video frame as output by the VDP scanline conversion unit, before any postprocessing filters are ap...
Definition: RawFrame.hh:15
virtual void scale4x2to3x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:166
virtual void scale1x2to1x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:139
void scaleImage(FrameSource &src, const RawFrame *superImpose, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Scales the image in the given area, which must consist of lines which are all equally wide.
Definition: Scaler1.cc:311
virtual void scale2x2to1x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:186
virtual void scaleBlank2to1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:46
virtual void scale2x1to1x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:176
virtual void scale2x1to3x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:101
virtual void scale2x2to3x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:111
void dispatchScale(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:236
virtual void scale8x1to3x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:196
virtual void scale1x1to1x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:121
virtual void scaleBlank1to1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:34
virtual void scale4x1to3x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:156
virtual void scale8x2to3x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:206
virtual void scale4x2to1x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:226
virtual void scale4x1to1x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler1.cc:216
Scaler1(const PixelOperations< Pixel > &pixelOps)
Definition: Scaler1.cc:16
virtual unsigned getWidth() 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 > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:285
constexpr mat4 scale(const vec3 &xyz)
Definition: gl_transform.hh:19
This file implemented 3 utility functions:
Definition: Autofire.cc:9
uint32_t Pixel
auto copy(InputRange &&range, OutputIter out)
Definition: ranges.hh:232
#define UNREACHABLE
Definition: unreachable.hh:38
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition: vla.hh:50
constexpr auto xrange(T e)
Definition: xrange.hh:132