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