openMSX
FrameSource.cc
Go to the documentation of this file.
1 #include "FrameSource.hh"
2 #include "PixelOperations.hh"
3 #include "MemoryOps.hh"
4 #include "LineScalers.hh"
5 #include "unreachable.hh"
6 #include "aligned.hh"
7 #include "likely.hh"
8 #include "vla.hh"
9 #include "build-info.hh"
10 #include "components.hh"
11 #include <cstdint>
12 
13 namespace openmsx {
14 
15 FrameSource::FrameSource(const SDL_PixelFormat& format)
16  : pixelFormat(format)
17 {
18 }
19 
20 template <typename Pixel>
21 const Pixel* FrameSource::getLinePtr320_240(unsigned line, Pixel* buf0) const
22 {
23  if (getHeight() == 240) {
24  return getLinePtr(line, 320, buf0);
25  } else {
26  assert(getHeight() == 480);
27  alignas(SSE_ALIGNMENT) Pixel buf1[320];
28  auto* line0 = getLinePtr(2 * line + 0, 320, buf0);
29  auto* line1 = getLinePtr(2 * line + 1, 320, buf1);
30  PixelOperations<Pixel> pixelOps(pixelFormat);
31  BlendLines<Pixel> blend(pixelOps);
32  blend(line0, line1, buf0, 320); // possibly line0 == buf0
33  return buf0;
34  }
35 }
36 
37 template <typename Pixel>
38 const Pixel* FrameSource::getLinePtr640_480(unsigned line, Pixel* buf) const
39 {
40  if (getHeight() == 480) {
41  return getLinePtr(line, 640, buf);
42  } else {
43  assert(getHeight() == 240);
44  return getLinePtr(line / 2, 640, buf);
45  }
46 }
47 
48 template <typename Pixel>
49 const Pixel* FrameSource::getLinePtr960_720(unsigned line, Pixel* buf0) const
50 {
51  if (getHeight() == 480) {
52  unsigned l2 = (2 * line) / 3;
53  auto* line0 = getLinePtr(l2 + 0, 960, buf0);
54  if ((line % 3) != 1) {
55  return line0;
56  }
57  alignas(SSE_ALIGNMENT) Pixel buf1[960];
58  auto* line1 = getLinePtr(l2 + 1, 960, buf1);
59  PixelOperations<Pixel> pixelOps(pixelFormat);
60  BlendLines<Pixel> blend(pixelOps);
61  blend(line0, line1, buf0, 960); // possibly line0 == buf0
62  return buf0;
63  } else {
64  assert(getHeight() == 240);
65  return getLinePtr(line / 3, 960, buf0);
66  }
67 }
68 
69 template <typename Pixel>
71  const Pixel* in, Pixel* out,
72  unsigned inWidth, unsigned outWidth) const
73 {
74  PixelOperations<Pixel> pixelOps(pixelFormat);
75 
76  VLA_SSE_ALIGNED(Pixel, tmpBuf, inWidth);
77  if (unlikely(in == out)) {
78  // Only happens in case getLineInfo() already used buf.
79  // E.g. when a line of a SuperImposedFrame also needs to be
80  // scaled.
81  // TODO If the LineScaler routines can work in-place then this
82  // copy can be avoided.
83  memcpy(tmpBuf, in, inWidth * sizeof(Pixel));
84  in = tmpBuf;
85  }
86 
87  // TODO is there a better way to implement this?
88  switch (inWidth) {
89  case 1: // blank
91  memset(out, outWidth, in[0]);
92  break;
93  case 213:
94  switch (outWidth) {
95  case 1:
96  out[0] = in[0];
97  break;
98  case 213:
100  case 320: {
101  Scale_2on3<Pixel> scale(pixelOps);
102  scale(in, out, outWidth);
103  break;
104  }
105  case 426: {
107  scale(in, out, outWidth);
108  break;
109  }
110  case 640: {
112  scale(in, out, outWidth);
113  break;
114  }
115  case 853: {
117  scale(in, out, outWidth);
118  break;
119  }
120  case 960: {
121  Scale_2on9<Pixel> scale(pixelOps);
122  scale(in, out, outWidth);
123  break;
124  }
125  case 1280: {
127  scale(in, out, outWidth);
128  break;
129  }
130  default:
131  UNREACHABLE;
132  }
133  break;
134  case 320:
135  switch (outWidth) {
136  case 1:
137  out[0] = in[0];
138  break;
139  case 213: {
140  Scale_3on2<Pixel> scale(pixelOps);
141  scale(in, out, outWidth);
142  break;
143  }
144  case 320:
145  UNREACHABLE;
146  case 426: {
147  Scale_3on4<Pixel> scale(pixelOps);
148  scale(in, out, outWidth);
149  break;
150  }
151  case 640: {
153  scale(in, out, outWidth);
154  break;
155  }
156  case 853: {
157  Scale_3on8<Pixel> scale(pixelOps);
158  scale(in, out, outWidth);
159  break;
160  }
161  case 960: {
163  scale(in, out, outWidth);
164  break;
165  }
166  case 1280: {
168  scale(in, out, outWidth);
169  break;
170  }
171  default:
172  UNREACHABLE;
173  }
174  break;
175  case 426:
176  switch (outWidth) {
177  case 1:
178  out[0] = in[0];
179  break;
180  case 213: {
181  Scale_2on1<Pixel> scale(pixelOps);
182  scale(in, out, outWidth);
183  break;
184  }
185  case 320: {
186  Scale_4on3<Pixel> scale(pixelOps);
187  scale(in, out, outWidth);
188  break;
189  }
190  case 426:
191  UNREACHABLE;
192  case 640: {
193  Scale_2on3<Pixel> scale(pixelOps);
194  scale(in, out, outWidth);
195  break;
196  }
197  case 853: {
199  scale(in, out, outWidth);
200  break;
201  }
202  case 960: {
203  Scale_4on9<Pixel> scale(pixelOps);
204  scale(in, out, outWidth);
205  break;
206  }
207  case 1280: {
209  scale(in, out, outWidth);
210  break;
211  }
212  default:
213  UNREACHABLE;
214  }
215  break;
216  case 640:
217  switch (outWidth) {
218  case 1:
219  out[0] = in[0];
220  break;
221  case 213: {
222  Scale_3on1<Pixel> scale(pixelOps);
223  scale(in, out, outWidth);
224  break;
225  }
226  case 320: {
227  Scale_2on1<Pixel> scale(pixelOps);
228  scale(in, out, outWidth);
229  break;
230  }
231  case 426: {
232  Scale_3on2<Pixel> scale(pixelOps);
233  scale(in, out, outWidth);
234  break;
235  }
236  case 640:
237  UNREACHABLE;
238  case 853: {
239  Scale_3on4<Pixel> scale(pixelOps);
240  scale(in, out, outWidth);
241  break;
242  }
243  case 960: {
244  Scale_2on3<Pixel> scale(pixelOps);
245  scale(in, out, outWidth);
246  break;
247  }
248  case 1280: {
250  scale(in, out, outWidth);
251  break;
252  }
253  default:
254  UNREACHABLE;
255  }
256  break;
257  case 853:
258  switch (outWidth) {
259  case 1:
260  out[0] = in[0];
261  break;
262  case 213: {
263  Scale_4on1<Pixel> scale(pixelOps);
264  scale(in, out, outWidth);
265  break;
266  }
267  case 320: {
268  Scale_8on3<Pixel> scale(pixelOps);
269  scale(in, out, outWidth);
270  break;
271  }
272  case 426: {
273  Scale_2on1<Pixel> scale(pixelOps);
274  scale(in, out, outWidth);
275  break;
276  }
277  case 640: {
278  Scale_4on3<Pixel> scale(pixelOps);
279  scale(in, out, outWidth);
280  break;
281  }
282  case 853:
283  UNREACHABLE;
284  case 960: {
285  Scale_8on9<Pixel> scale(pixelOps);
286  scale(in, out, outWidth);
287  break;
288  }
289  case 1280: {
290  Scale_2on3<Pixel> scale(pixelOps);
291  scale(in, out, outWidth);
292  break;
293  }
294  default:
295  UNREACHABLE;
296  }
297  break;
298  case 1280:
299  switch (outWidth) {
300  case 1:
301  out[0] = in[0];
302  break;
303  case 213: {
304  Scale_6on1<Pixel> scale(pixelOps);
305  scale(in, out, outWidth);
306  break;
307  }
308  case 320: {
309  Scale_4on1<Pixel> scale(pixelOps);
310  scale(in, out, outWidth);
311  break;
312  }
313  case 426: {
314  Scale_3on1<Pixel> scale(pixelOps);
315  scale(in, out, outWidth);
316  break;
317  }
318  case 640: {
319  Scale_2on1<Pixel> scale(pixelOps);
320  scale(in, out, outWidth);
321  break;
322  }
323  case 853: {
324  Scale_3on2<Pixel> scale(pixelOps);
325  scale(in, out, outWidth);
326  break;
327  }
328  case 960: {
329  Scale_4on3<Pixel> scale(pixelOps);
330  scale(in, out, outWidth);
331  break;
332  }
333  case 1280:
334  UNREACHABLE;
335  default:
336  UNREACHABLE;
337  }
338  break;
339  default:
340  UNREACHABLE;
341  }
342 }
343 
344 
345 // Force template method instantiation
346 #if HAVE_16BPP
347 template const uint16_t* FrameSource::getLinePtr320_240<uint16_t>(unsigned, uint16_t*) const;
348 template const uint16_t* FrameSource::getLinePtr640_480<uint16_t>(unsigned, uint16_t*) const;
349 template const uint16_t* FrameSource::getLinePtr960_720<uint16_t>(unsigned, uint16_t*) const;
350 template void FrameSource::scaleLine<uint16_t>(const uint16_t*, uint16_t*, unsigned, unsigned) const;
351 #endif
352 #if HAVE_32BPP || COMPONENT_GL
353 template const uint32_t* FrameSource::getLinePtr320_240<uint32_t>(unsigned, uint32_t*) const;
354 template const uint32_t* FrameSource::getLinePtr640_480<uint32_t>(unsigned, uint32_t*) const;
355 template const uint32_t* FrameSource::getLinePtr960_720<uint32_t>(unsigned, uint32_t*) const;
356 template void FrameSource::scaleLine<uint32_t>(const uint32_t*, uint32_t*, unsigned, unsigned) const;
357 #endif
358 
359 } // namespace openmsx
BlendLines functor Generate an output line that is an iterpolation of two input lines.
Definition: LineScalers.hh:224
#define unlikely(x)
Definition: likely.hh:15
uint32_t Pixel
mat4 scale(const vec3 &xyz)
Definition: gl_transform.hh:19
constexpr auto SSE_ALIGNMENT
Definition: aligned.hh:14
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
void scaleLine(const Pixel *in, Pixel *out, unsigned inWidth, unsigned outWidth) const
Definition: FrameSource.cc:70
Scale_XonY functors Transforms an input line of pixel to an output line (possibly) with a different w...
Definition: LineScalers.hh:33
const Pixel * getLinePtr640_480(unsigned line, Pixel *buf) const
Get a pointer to a given line in this frame, the frame is scaled to 640x480 pixels.
Definition: FrameSource.cc:38
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 Pixel * getLinePtr320_240(unsigned line, Pixel *buf) const
Get a pointer to a given line in this frame, the frame is scaled to 320x240 pixels.
Definition: FrameSource.cc:21
const Pixel * getLinePtr960_720(unsigned line, Pixel *buf) const
Get a pointer to a given line in this frame, the frame is scaled to 960x720 pixels.
Definition: FrameSource.cc:49
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
FrameSource(const SDL_PixelFormat &format)
Definition: FrameSource.cc:15
#define UNREACHABLE
Definition: unreachable.hh:38