OXYGENHUB
◆ main openmsx / src / video / FrameSource.hh
5.0 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef FRAMESOURCE_HH
2
#define FRAMESOURCE_HH
3
4
#include "aligned.hh"
5
#include "narrow.hh"
6
#include "xrange.hh"
7
8
#include <algorithm>
9
#include <array>
10
#include <bit>
11
#include <cassert>
12
#include <cstdint>
13
#include <span>
14
15
namespace openmsx {
16
17
/** Interface for getting lines from a video frame.
18
  */
19
class FrameSource
20
{
21
public:
22
	using Pixel = uint32_t;
23
24
	/** What role does this frame play in interlacing?
25
	  */
26
	enum class FieldType : uint8_t {
27
		/** Interlacing is off for this frame.
28
		  */
29
		NONINTERLACED,
30
		/** Interlacing is on and this is an even frame.
31
		  */
32
		EVEN,
33
		/** Interlacing is on and this is an odd frame.
34
		  */
35
		ODD,
36
	};
37
38
	/** (Re)initialize an existing FrameSource. This method sets the
39
	  * Fieldtype and flushes the 'getLinePtr' buffers.
40
	  */
41
	void init(FieldType fieldType_) { fieldType = fieldType_; }
42
43
	/** Gets the role this frame plays in interlacing.
44
	  */
45
	[[nodiscard]] FieldType getField() const {
46
		return fieldType;
47
	}
48
49
	/** Gets the number of lines in this frame.
50
	  */
51
	[[nodiscard]] unsigned getHeight() const {
52
		return height;
53
	}
54
55
	/** Gets the number of display pixels on the given line.
56
	  * @return line width (=1 for a vertical border line)
57
	  */
58
	[[nodiscard]] virtual unsigned getLineWidth(unsigned line) const = 0;
59
60
	/** Get the width of (all) lines in this frame.
61
	 * This only makes sense when all lines have the same width, so this
62
	 * methods asserts that all lines actually have the same width. This
63
	 * is for example not always the case for MSX frames, but it is for
64
	 * video frames (for superimpose).
65
	 */
66
	[[nodiscard]] unsigned getWidth() const {
67
		assert(height > 0);
68
		unsigned result = getLineWidth(0);
69
		for (auto line : xrange(1u, height)) {
70
			assert(result == getLineWidth(line)); (void)line;
71
		}
72
		return result;
73
	}
74
75
	/** Get the (single) color of the given line.
76
	  * Typically this will be used to get the color of a vertical border
77
	  * line. But it's fine to call this on non-border lines as well, in
78
	  * that case the color of the first pixel of the line is returned.
79
	  */
80
	[[nodiscard]] Pixel getLineColor(unsigned line) const {
81
		ALIGNAS_SSE std::array<Pixel, 1280> buf; // large enough for widest line
82
		return getUnscaledLine(line, buf)[0];
83
	}
84
85
	/** Gets a pointer to the pixels of the given line number.
86
	  * The line returned is guaranteed to have the given width. If the
87
	  * original line had a different width the result will be computed in
88
	  * the provided work buffer. So that buffer should be big enough to
89
	  * hold the scaled line. This also means the lifetime of the result
90
	  * is tied to the lifetime of that work buffer. In any case the return
91
	  * value of this function will point to the line data (some internal
92
	  * buffer or the work buffer).
93
	  */
94
	[[nodiscard]] std::span<const Pixel> getLine(int line, std::span<Pixel> buf) const
95
	{
96
		line = std::clamp(line, 0, narrow<int>(getHeight() - 1));
97
		auto unscaledLine = getUnscaledLine(line, buf);
98
		if (unscaledLine.size() == buf.size()) {
99
			// Already the correct width.
100
			return unscaledLine;
101
		} else {
102
			// slow path, non-inlined
103
			// internalData might be equal to buf
104
			scaleLine(unscaledLine, buf);
105
			return buf;
106
		}
107
	}
108
109
	/** Get a specific line, with the 'native' line-width.
110
	  * @param line The line number for the requested line.
111
	  * @param helpBuf Buffer space that can _optionally_ be used by the
112
	  *                implementation.
113
	  * @return Returns a span of the requested line. This span may or may
114
	            not use the helper input buffer.
115
	  */
116
	[[nodiscard]] virtual std::span<const Pixel> getUnscaledLine(
117
		unsigned line, std::span<Pixel> helpBuf) const = 0;
118
119
	/** Get a pointer to a given line in this frame, the frame is scaled
120
	  * to 320x240 pixels. The difference between this method and
121
	  * getLinePtr() is that this method also does vertical scaling.
122
	  * This is used for video recording.
123
	  */
124
	[[nodiscard]] std::span<const Pixel, 320> getLinePtr320_240(unsigned line, std::span<Pixel, 320> buf) const;
125
126
	/** Get a pointer to a given line in this frame, the frame is scaled
127
	  * to 640x480 pixels. Same as getLinePtr320_240, but then for a
128
	  * higher resolution output.
129
	  */
130
	[[nodiscard]] std::span<const Pixel, 640> getLinePtr640_480(unsigned line, std::span<Pixel, 640> buf) const;
131
132
	/** Get a pointer to a given line in this frame, the frame is scaled
133
	  * to 960x720 pixels. Same as getLinePtr320_240, but then for a
134
	  * higher resolution output.
135
	  */
136
	[[nodiscard]] std::span<const Pixel, 960> getLinePtr960_720(unsigned line, std::span<Pixel, 960> buf) const;
137
138
protected:
139
	FrameSource() = default;
140
	~FrameSource() = default;
141
142
	void setHeight(unsigned height_) { height = height_; }
143
144
	/** Returns true when two consecutive rows are also consecutive in
145
	  * memory.
146
	  */
147
	[[nodiscard]] virtual bool hasContiguousStorage() const {
148
		return false;
149
	}
150
151
	void scaleLine(std::span<const Pixel> in, std::span<Pixel> out) const;
152
153
private:
154
	/** Number of lines in this frame.
155
	  */
156
	unsigned height;
157
158
	FieldType fieldType;
159
};
160
161
} // namespace openmsx
162
163
#endif // FRAMESOURCE_HH