OXYGENHUB
◆ main openmsx / src / video / FrameSource.cc
4.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "FrameSource.hh"
2
3
#include "LineScalers.hh"
4
5
#include "aligned.hh"
6
#include "inplace_buffer.hh"
7
#include "ranges.hh"
8
#include "unreachable.hh"
9
10
#include <algorithm>
11
#include <array>
12
#include <span>
13
14
namespace openmsx {
15
16
using Pixel = FrameSource::Pixel;
17
18
std::span<const Pixel, 320> FrameSource::getLinePtr320_240(unsigned line, std::span<Pixel, 320> buf0) const
19
{
20
	if (getHeight() == 240) {
21
		auto r = getLine(line, std::span<Pixel>{buf0});
22
		assert(r.size() == 320);
23
		return std::span<const Pixel, 320>(r);
24
	} else {
25
		assert(getHeight() == 480);
26
		ALIGNAS_SSE std::array<Pixel, 320> buf1;
27
		auto line0 = getLine(2 * line + 0, std::span<Pixel>(buf0));
28
		auto line1 = getLine(2 * line + 1, std::span<Pixel>(buf1));
29
		blendLines(line0, line1, buf0); // possibly line0 == buf0
30
		return buf0;
31
	}
32
}
33
34
std::span<const Pixel, 640> FrameSource::getLinePtr640_480(unsigned line, std::span<Pixel, 640> buf) const
35
{
36
	if (getHeight() == 480) {
37
		auto r = getLine(line, std::span<Pixel>(buf));
38
		assert(r.size() == 640);
39
		return std::span<const Pixel, 640>(r);
40
	} else {
41
		assert(getHeight() == 240);
42
		auto r = getLine(line / 2, std::span<Pixel>(buf));
43
		assert(r.size() == 640);
44
		return std::span<const Pixel, 640>(r);
45
	}
46
}
47
48
std::span<const Pixel, 960> FrameSource::getLinePtr960_720(unsigned line, std::span<Pixel, 960> buf0) const
49
{
50
	if (getHeight() == 480) {
51
		unsigned l2 = (2 * line) / 3;
52
		auto line0 = getLine(l2 + 0, std::span<Pixel>(buf0));
53
		if ((line % 3) != 1) {
54
			assert(line0.size() == 960);
55
			return std::span<const Pixel, 960>(line0);
56
		}
57
		ALIGNAS_SSE std::array<Pixel, 960> buf1;
58
		auto line1 = getLine(l2 + 1, std::span<Pixel>(buf1));
59
		blendLines(line0, line1, buf0); // possibly line0 == buf0
60
		return buf0;
61
	} else {
62
		assert(getHeight() == 240);
63
		auto r = getLine(line / 3, std::span<Pixel>(buf0));
64
		assert(r.size() == 960);
65
		return std::span<const Pixel, 960>(r);
66
	}
67
}
68
69
void FrameSource::scaleLine(
70
	std::span<const Pixel> in, std::span<Pixel> out) const
71
{
72
	inplace_buffer<Pixel, 1280> tmpBuf(uninitialized_tag{}, in.size());
73
	if (in.data() == out.data()) [[unlikely]] {
74
		// Only happens in case getLineInfo() already used buf.
75
		// E.g. when a line of a SuperImposedFrame also needs to be
76
		// scaled.
77
		// TODO If the LineScaler routines can work in-place then this
78
		//      copy can be avoided.
79
		copy_to_range(in, tmpBuf);
80
		in = tmpBuf;
81
	}
82
83
	// TODO is there a better way to implement this?
84
	switch (in.size()) {
85
	case 1:  // blank
86
		std::ranges::fill(out, in[0]);
87
		break;
88
	case 213:
89
		switch (out.size()) {
90
		case    1: out[0] = in[0]; break;
91
		case  213: UNREACHABLE; break;
92
		case  320: scale_2on3(in, out); break;
93
		case  426: scale_1on2(in, out); break;
94
		case  640: scale_1on3(in, out); break;
95
		case  853: scale_1on4(in, out); break;
96
		case  960: scale_2on9(in, out); break;
97
		case 1280: scale_1on6(in, out); break;
98
		default: UNREACHABLE;
99
		}
100
		break;
101
	case 320:
102
		switch (out.size()) {
103
		case    1: out[0] = in[0]; break;
104
		case  213: scale_3on2(in, out); break;
105
		case  320: UNREACHABLE; break;
106
		case  426: scale_3on4(in, out); break;
107
		case  640: scale_1on2(in, out); break;
108
		case  853: scale_3on8(in, out); break;
109
		case  960: scale_1on3(in, out); break;
110
		case 1280: scale_1on4(in, out); break;
111
		default: UNREACHABLE;
112
		}
113
		break;
114
	case 426:
115
		switch (out.size()) {
116
		case    1: out[0] = in[0]; break;
117
		case  213: scale_2on1(in, out); break;
118
		case  320: scale_4on3(in, out); break;
119
		case  426: UNREACHABLE; break;
120
		case  640: scale_2on3(in, out); break;
121
		case  853: scale_1on2(in, out); break;
122
		case  960: scale_4on9(in, out); break;
123
		case 1280: scale_1on3(in, out); break;
124
		default: UNREACHABLE;
125
		}
126
		break;
127
	case 640:
128
		switch (out.size()) {
129
		case    1: out[0] = in[0]; break;
130
		case  213: scale_3on1(in, out); break;
131
		case  320: scale_2on1(in, out); break;
132
		case  426: scale_3on2(in, out); break;
133
		case  640: UNREACHABLE; break;
134
		case  853: scale_3on4(in, out); break;
135
		case  960: scale_2on3(in, out); break;
136
		case 1280: scale_1on2(in, out); break;
137
		default: UNREACHABLE;
138
		}
139
		break;
140
	case 853:
141
		switch (out.size()) {
142
		case    1: out[0] = in[0]; break;
143
		case  213: scale_4on1(in, out); break;
144
		case  320: scale_8on3(in, out); break;
145
		case  426: scale_2on1(in, out); break;
146
		case  640: scale_4on3(in, out); break;
147
		case  853: UNREACHABLE; break;
148
		case  960: scale_8on9(in, out); break;
149
		case 1280: scale_2on3(in, out); break;
150
		default: UNREACHABLE;
151
		}
152
		break;
153
	case 1280:
154
		switch (out.size()) {
155
		case    1: out[0] = in[0]; break;
156
		case  213: scale_6on1(in, out); break;
157
		case  320: scale_4on1(in, out); break;
158
		case  426: scale_3on1(in, out); break;
159
		case  640: scale_2on1(in, out); break;
160
		case  853: scale_3on2(in, out); break;
161
		case  960: scale_4on3(in, out); break;
162
		case 1280: UNREACHABLE; break;
163
		default: UNREACHABLE;
164
		}
165
		break;
166
	default:
167
		UNREACHABLE;
168
	}
169
}
170
171
} // namespace openmsx