openMSX
Scaler2.cc
Go to the documentation of this file.
1 #include "Scaler2.hh"
2 #include "LineScalers.hh"
3 #include "FrameSource.hh"
5 #include "unreachable.hh"
6 #include "vla.hh"
7 #include "build-info.hh"
8 #include <cassert>
9 #include <cstdint>
10 
11 namespace openmsx {
12 
13 template <class Pixel>
15  : pixelOps(pixelOps_)
16 {
17 }
18 
19 template <class Pixel>
21  FrameSource& src, unsigned srcStartY, unsigned /*srcEndY*/,
22  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
23 {
24  for (unsigned srcY = srcStartY, dstY = dstStartY;
25  dstY < dstEndY; srcY += 1, dstY += 2) {
26  auto color = src.getLineColor<Pixel>(srcY);
27  dst.fillLine(dstY + 0, color);
28  dst.fillLine(dstY + 1, color);
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 <typename Pixel>
45 static void doScale1(FrameSource& src,
46  unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
47  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY,
49 {
50  VLA_SSE_ALIGNED(Pixel, buf, srcWidth);
52  unsigned dstWidth = dst.getWidth();
53  for (unsigned y = dstStartY; y < dstEndY; y += 2, ++srcStartY) {
54  auto* srcLine = src.getLinePtr(srcStartY, srcWidth, buf);
55  auto* dstLine0 = dst.acquireLine(y + 0);
56  scale(srcLine, dstLine0, dstWidth);
57  auto* dstLine1 = dst.acquireLine(y + 1);
58  copy(dstLine0, dstLine1, dstWidth);
59  dst.releaseLine(y + 0, dstLine0);
60  dst.releaseLine(y + 1, dstLine1);
61  }
62 }
63 
64 template <typename Pixel>
65 static void doScale2(FrameSource& src,
66  unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
67  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY,
68  PolyLineScaler<Pixel>& scale)
69 {
70  VLA_SSE_ALIGNED(Pixel, buf, srcWidth);
71  unsigned dstWidth = dst.getWidth();
72  for (unsigned srcY = srcStartY, dstY = dstStartY;
73  dstY < dstEndY; ++dstY, ++srcY) {
74  auto* srcLine = src.getLinePtr(srcY, srcWidth, buf);
75  auto* dstLine = dst.acquireLine(dstY);
76  scale(srcLine, dstLine, dstWidth);
77  dst.releaseLine(dstY, dstLine);
78  }
79 }
80 
81 
82 template <class Pixel>
84  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
85  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
86 {
88  doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
89  dst, dstStartY, dstEndY, op);
90 }
91 
92 template <class Pixel>
94  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
95  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
96 {
98  doScale2<Pixel>(src, srcStartY, srcEndY, srcWidth,
99  dst, dstStartY, dstEndY, op);
100 }
101 
102 // TODO: In theory it's nice to have this as a fallback method, but in practice
103 // all subclasses override this method, so should we keep it or not?
104 // And if we keep it, should it be commented out like this until we
105 // need it to reduce the executable size?
106 // See also Scaler3::scale256.
107 // TODO: Why won't it compile anymore without this method enabled?
108 template <class Pixel>
110  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
111  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
112 {
114  doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
115  dst, dstStartY, dstEndY, op);
116 }
117 
118 template <class Pixel>
120  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
121  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
122 {
124  doScale2<Pixel>(src, srcStartY, srcEndY, srcWidth,
125  dst, dstStartY, dstEndY, op);
126 }
127 
128 template <class Pixel>
130  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
131  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
132 {
134  doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
135  dst, dstStartY, dstEndY, op);
136 }
137 
138 template <class Pixel>
140  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
141  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
142 {
144  doScale2<Pixel>(src, srcStartY, srcEndY, srcWidth,
145  dst, dstStartY, dstEndY, op);
146 }
147 
148 template <class Pixel>
150  unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
151  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
152 {
153  // Optimized variant: possibly avoid copy.
154  assert(dst.getWidth() == srcWidth);
156  for (unsigned y = dstStartY; y < dstEndY; y += 2, ++srcStartY) {
157  auto* dstLine0 = dst.acquireLine(y + 0);
158  auto* srcLine = src.getLinePtr(srcStartY, srcWidth, dstLine0);
159  if (srcLine != dstLine0) copy(srcLine, dstLine0, srcWidth);
160  auto* dstLine1 = dst.acquireLine(y + 1);
161  copy(dstLine0, dstLine1, srcWidth);
162  dst.releaseLine(y + 0, dstLine0);
163  dst.releaseLine(y + 1, dstLine1);
164  }
165 }
166 
167 template <class Pixel>
169  unsigned srcStartY, unsigned /*srcEndY*/, unsigned srcWidth,
170  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
171 {
172  // Optimized variant: possibly avoid copy.
173  assert(dst.getWidth() == srcWidth);
175  for (unsigned srcY = srcStartY, dstY = dstStartY;
176  dstY < dstEndY; ++dstY, ++srcY) {
177  auto* dstLine = dst.acquireLine(dstY);
178  auto* srcLine = src.getLinePtr(srcY, srcWidth, dstLine);
179  if (srcLine != dstLine) copy(srcLine, dstLine, srcWidth);
180  dst.releaseLine(dstY, dstLine);
181  }
182 }
183 
184 template <class Pixel>
186  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
187  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
188 {
190  doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
191  dst, dstStartY, dstEndY, op);
192 }
193 
194 template <class Pixel>
196  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
197  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
198 {
200  doScale2<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  doScale1<Pixel>(src, srcStartY, srcEndY, srcWidth,
211  dst, dstStartY, dstEndY, op);
212 }
213 
214 template <class Pixel>
216  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
217  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
218 {
220  doScale2<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 {
229  if (src.getHeight() == 240) {
230  switch (srcWidth) {
231  case 1:
232  scaleBlank1to2(src, srcStartY, srcEndY,
233  dst, dstStartY, dstEndY);
234  break;
235  case 213:
236  scale1x1to3x2(src, srcStartY, srcEndY, srcWidth,
237  dst, dstStartY, dstEndY);
238  break;
239  case 320:
240  scale1x1to2x2(src, srcStartY, srcEndY, srcWidth,
241  dst, dstStartY, dstEndY);
242  break;
243  case 426:
244  scale2x1to3x2(src, srcStartY, srcEndY, srcWidth,
245  dst, dstStartY, dstEndY);
246  break;
247  case 640:
248  scale1x1to1x2(src, srcStartY, srcEndY, srcWidth,
249  dst, dstStartY, dstEndY);
250  break;
251  case 853:
252  scale4x1to3x2(src, srcStartY, srcEndY, srcWidth,
253  dst, dstStartY, dstEndY);
254  break;
255  case 1280:
256  scale2x1to1x2(src, srcStartY, srcEndY, srcWidth,
257  dst, dstStartY, dstEndY);
258  break;
259  default:
260  UNREACHABLE;
261  }
262  } else {
263  assert(src.getHeight() == 480);
264  switch (srcWidth) {
265  case 1:
266  scaleBlank1to1(src, srcStartY, srcEndY,
267  dst, dstStartY, dstEndY);
268  break;
269  case 213:
270  scale1x1to3x1(src, srcStartY, srcEndY, srcWidth,
271  dst, dstStartY, dstEndY);
272  break;
273  case 320:
274  scale1x1to2x1(src, srcStartY, srcEndY, srcWidth,
275  dst, dstStartY, dstEndY);
276  break;
277  case 426:
278  scale2x1to3x1(src, srcStartY, srcEndY, srcWidth,
279  dst, dstStartY, dstEndY);
280  break;
281  case 640:
282  scale1x1to1x1(src, srcStartY, srcEndY, srcWidth,
283  dst, dstStartY, dstEndY);
284  break;
285  case 853:
286  scale4x1to3x1(src, srcStartY, srcEndY, srcWidth,
287  dst, dstStartY, dstEndY);
288  break;
289  case 1280:
290  scale2x1to1x1(src, srcStartY, srcEndY, srcWidth,
291  dst, dstStartY, dstEndY);
292  break;
293  default:
294  UNREACHABLE;
295  }
296  }
297 }
298 
299 template <class Pixel>
300 void Scaler2<Pixel>::scaleImage(FrameSource& src, const RawFrame* superImpose,
301  unsigned srcStartY, unsigned srcEndY, unsigned srcWidth,
302  ScalerOutput<Pixel>& dst, unsigned dstStartY, unsigned dstEndY)
303 {
304  if (superImpose) {
306  dst, *superImpose, pixelOps);
307  dispatchScale(src, srcStartY, srcEndY, srcWidth,
308  dst2, dstStartY, dstEndY);
309  } else {
310  dispatchScale(src, srcStartY, srcEndY, srcWidth,
311  dst, dstStartY, dstEndY);
312  }
313 }
314 
315 // Force template instantiation.
316 #if HAVE_16BPP
317 template class Scaler2<uint16_t>;
318 #endif
319 #if HAVE_32BPP
320 template class Scaler2<uint32_t>;
321 #endif
322 
323 } // namespace openmsx
virtual void scale1x1to2x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:119
virtual void scale4x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:185
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 scale1x1to3x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:93
virtual void fillLine(unsigned y, Pixel color)=0
virtual Pixel * acquireLine(unsigned y)=0
virtual void scaleBlank1to1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:33
virtual void scale1x1to1x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:149
Base class for 2x scalers.
Definition: Scaler2.hh:11
Polymorphic wrapper around another line scaler.
Definition: LineScalers.hh:310
Polymorphic line scaler.
Definition: LineScalers.hh:282
uint32_t Pixel
virtual void scale4x1to3x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:195
Interface for getting lines from a video frame.
Definition: FrameSource.hh:14
void dispatchScale(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:225
mat4 scale(const vec3 &xyz)
Definition: gl_transform.hh:19
virtual void scale2x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:129
A video frame as output by the VDP scanline conversion unit, before any postprocessing filters are ap...
Definition: RawFrame.hh:25
virtual void scale2x1to1x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:215
virtual void scale2x1to3x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:139
Scaler2(const PixelOperations< Pixel > &pixelOps)
Definition: Scaler2.cc:14
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
virtual void scaleBlank1to2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:20
virtual void releaseLine(unsigned y, Pixel *buf)=0
virtual void scale1x1to1x1(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:168
virtual void scale1x1to3x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:83
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
const PixelOperations< Pixel > pixelOps
Definition: Scaler2.hh:67
virtual void scale1x1to2x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:109
virtual unsigned getWidth() const =0
unsigned getHeight() const
Gets the number of lines in this frame.
Definition: FrameSource.hh:44
virtual void scale2x1to1x2(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY)
Definition: Scaler2.cc:205
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition: vla.hh:44
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: Scaler2.cc:300
#define UNREACHABLE
Definition: unreachable.hh:38