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