openMSX
FrameSource.cc
Go to the documentation of this file.
1#include "FrameSource.hh"
2#include "LineScalers.hh"
3#include "MemoryOps.hh"
4#include "aligned.hh"
5#include "ranges.hh"
6#include "unreachable.hh"
7#include "vla.hh"
8#include <array>
9#include <cstdint>
10#include <span>
11
12namespace openmsx {
13
15
16std::span<const Pixel, 320> FrameSource::getLinePtr320_240(unsigned line, std::span<Pixel, 320> buf0) const
17{
18 if (getHeight() == 240) {
19 auto r = getLine(line, std::span<Pixel>{buf0});
20 assert(r.size() == 320);
21 return std::span<const Pixel, 320>(r);
22 } else {
23 assert(getHeight() == 480);
24 ALIGNAS_SSE std::array<Pixel, 320> buf1;
25 auto line0 = getLine(2 * line + 0, std::span<Pixel>(buf0));
26 auto line1 = getLine(2 * line + 1, std::span<Pixel>(buf1));
27 blendLines(line0, line1, buf0); // possibly line0 == buf0
28 return buf0;
29 }
30}
31
32std::span<const Pixel, 640> FrameSource::getLinePtr640_480(unsigned line, std::span<Pixel, 640> buf) const
33{
34 if (getHeight() == 480) {
35 auto r = getLine(line, std::span<Pixel>(buf));
36 assert(r.size() == 640);
37 return std::span<const Pixel, 640>(r);
38 } else {
39 assert(getHeight() == 240);
40 auto r = getLine(line / 2, std::span<Pixel>(buf));
41 assert(r.size() == 640);
42 return std::span<const Pixel, 640>(r);
43 }
44}
45
46std::span<const Pixel, 960> FrameSource::getLinePtr960_720(unsigned line, std::span<Pixel, 960> buf0) const
47{
48 if (getHeight() == 480) {
49 unsigned l2 = (2 * line) / 3;
50 auto line0 = getLine(l2 + 0, std::span<Pixel>(buf0));
51 if ((line % 3) != 1) {
52 assert(line0.size() == 960);
53 return std::span<const Pixel, 960>(line0);
54 }
55 ALIGNAS_SSE std::array<Pixel, 960> buf1;
56 auto line1 = getLine(l2 + 1, std::span<Pixel>(buf1));
57 blendLines(line0, line1, buf0); // possibly line0 == buf0
58 return buf0;
59 } else {
60 assert(getHeight() == 240);
61 auto r = getLine(line / 3, std::span<Pixel>(buf0));
62 assert(r.size() == 960);
63 return std::span<const Pixel, 960>(r);
64 }
65}
66
68 std::span<const Pixel> in, std::span<Pixel> out) const
69{
70 VLA_SSE_ALIGNED(Pixel, tmpBuf, in.size());
71 if (in.data() == out.data()) [[unlikely]] {
72 // Only happens in case getLineInfo() already used buf.
73 // E.g. when a line of a SuperImposedFrame also needs to be
74 // scaled.
75 // TODO If the LineScaler routines can work in-place then this
76 // copy can be avoided.
77 ranges::copy(in, tmpBuf);
78 in = tmpBuf;
79 }
80
81 // TODO is there a better way to implement this?
82 switch (in.size()) {
83 case 1: // blank
85 memset(out, in[0]);
86 break;
87 case 213:
88 switch (out.size()) {
89 case 1: out[0] = in[0]; break;
90 case 213: UNREACHABLE;
91 case 320: scale_2on3(in, out); break;
92 case 426: scale_1on2(in, out); break;
93 case 640: scale_1on3(in, out); break;
94 case 853: scale_1on4(in, out); break;
95 case 960: scale_2on9(in, out); break;
96 case 1280: scale_1on6(in, out); break;
97 default: UNREACHABLE;
98 }
99 break;
100 case 320:
101 switch (out.size()) {
102 case 1: out[0] = in[0]; break;
103 case 213: scale_3on2(in, out); break;
104 case 320: UNREACHABLE;
105 case 426: scale_3on4(in, out); break;
106 case 640: scale_1on2(in, out); break;
107 case 853: scale_3on8(in, out); break;
108 case 960: scale_1on3(in, out); break;
109 case 1280: scale_1on4(in, out); break;
110 default: UNREACHABLE;
111 }
112 break;
113 case 426:
114 switch (out.size()) {
115 case 1: out[0] = in[0]; break;
116 case 213: scale_2on1(in, out); break;
117 case 320: scale_4on3(in, out); break;
118 case 426: UNREACHABLE;
119 case 640: scale_2on3(in, out); break;
120 case 853: scale_1on2(in, out); break;
121 case 960: scale_4on9(in, out); break;
122 case 1280: scale_1on3(in, out); break;
123 default: UNREACHABLE;
124 }
125 break;
126 case 640:
127 switch (out.size()) {
128 case 1: out[0] = in[0]; break;
129 case 213: scale_3on1(in, out); break;
130 case 320: scale_2on1(in, out); break;
131 case 426: scale_3on2(in, out); break;
132 case 640: UNREACHABLE;
133 case 853: scale_3on4(in, out); break;
134 case 960: scale_2on3(in, out); break;
135 case 1280: scale_1on2(in, out); break;
136 default: UNREACHABLE;
137 }
138 break;
139 case 853:
140 switch (out.size()) {
141 case 1: out[0] = in[0]; break;
142 case 213: scale_4on1(in, out); break;
143 case 320: scale_8on3(in, out); break;
144 case 426: scale_2on1(in, out); break;
145 case 640: scale_4on3(in, out); break;
146 case 853: UNREACHABLE;
147 case 960: scale_8on9(in, out); break;
148 case 1280: scale_2on3(in, out); break;
149 default: UNREACHABLE;
150 }
151 break;
152 case 1280:
153 switch (out.size()) {
154 case 1: out[0] = in[0]; break;
155 case 213: scale_6on1(in, out); break;
156 case 320: scale_4on1(in, out); break;
157 case 426: scale_3on1(in, out); break;
158 case 640: scale_2on1(in, out); break;
159 case 853: scale_3on2(in, out); break;
160 case 960: scale_4on3(in, out); break;
161 case 1280: UNREACHABLE;
162 default: UNREACHABLE;
163 }
164 break;
165 default:
167 }
168}
169
170} // namespace openmsx
#define ALIGNAS_SSE
Definition aligned.hh:26
std::span< const Pixel > getLine(int line, std::span< Pixel > buf) const
Gets a pointer to the pixels of the given line number.
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.
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.
void scaleLine(std::span< const Pixel > in, std::span< Pixel > out) const
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.
unsigned getHeight() const
Gets the number of lines in this frame.
This file implemented 3 utility functions:
Definition Autofire.cc:11
void scale_3on1(std::span< const Pixel > in, std::span< Pixel > out)
void blendLines(std::span< const Pixel > in1, std::span< const Pixel > in2, std::span< Pixel > out)
BlendLines functor Generate an output line that is an interpolation of two input lines.
void scale_2on1(std::span< const Pixel > in, std::span< Pixel > out)
void scale_2on3(std::span< const Pixel > in, std::span< Pixel > out)
void scale_4on9(std::span< const Pixel > in, std::span< Pixel > out)
void scale_6on1(std::span< const Pixel > in, std::span< Pixel > out)
void scale_1on2(std::span< const Pixel > in, std::span< Pixel > out)
void scale_1on3(std::span< const Pixel > in, std::span< Pixel > out)
Scale_XonY functions Transforms an input line of pixel to an output line (possibly) with a different ...
void scale_4on3(std::span< const Pixel > in, std::span< Pixel > out)
void scale_3on2(std::span< const Pixel > in, std::span< Pixel > out)
void scale_3on8(std::span< const Pixel > in, std::span< Pixel > out)
void scale_2on9(std::span< const Pixel > in, std::span< Pixel > out)
void scale_1on4(std::span< const Pixel > in, std::span< Pixel > out)
CharacterConverter::Pixel Pixel
void scale_1on6(std::span< const Pixel > in, std::span< Pixel > out)
void scale_4on1(std::span< const Pixel > in, std::span< Pixel > out)
void scale_3on4(std::span< const Pixel > in, std::span< Pixel > out)
void scale_8on9(std::span< const Pixel > in, std::span< Pixel > out)
void scale_8on3(std::span< const Pixel > in, std::span< Pixel > out)
auto copy(InputRange &&range, OutputIter out)
Definition ranges.hh:250
#define UNREACHABLE
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition vla.hh:50