summaryrefslogtreecommitdiff
path: root/kms++/src/mode_cvt.cpp
blob: a7a10b800d14106966a4df79a0c500a23679e006 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Supports CVT 1.2 reduced blanking modes v1 and v2

#include <kms++/kms++.h>
#include <cmath>

using namespace std;

namespace kms
{
static float CELL_GRAN = 8;
static float CELL_GRAN_RND = round(CELL_GRAN);

struct CVTConsts {
	float CLOCK_STEP;
	float MIN_V_BPORCH;
	float RB_H_BLANK;
	float RB_H_FPORCH;
	float RB_H_SYNC;
	float RB_H_BPORCH;
	float RB_MIN_V_BLANK;
	float RB_V_FPORCH;
	float REFRESH_MULTIPLIER;
};

static const CVTConsts cvt_consts_v1 = {
	.CLOCK_STEP = 0.25, // Fixed
	.MIN_V_BPORCH = 6, // Min
	.RB_H_BLANK = 160, // Fixed
	.RB_H_FPORCH = 48, // Fixed
	.RB_H_SYNC = 32, // Fixed
	.RB_H_BPORCH = 80, // Fixed
	.RB_MIN_V_BLANK = 460, // Min
	.RB_V_FPORCH = 3, // Fixed
	.REFRESH_MULTIPLIER = 1, // Fixed
};

static const CVTConsts cvt_consts_v2 = {
	.CLOCK_STEP = 0.001, // Fixed
	.MIN_V_BPORCH = 6, // Fixed
	.RB_H_BLANK = 80, // Fixed
	.RB_H_FPORCH = 8, // Fixed
	.RB_H_SYNC = 32, // Fixed
	.RB_H_BPORCH = 40, // Fixed
	.RB_MIN_V_BLANK = 460, // Min
	.RB_V_FPORCH = 1, // Min
	.REFRESH_MULTIPLIER = 1, // or 1000/1001
};

Videomode videomode_from_cvt(uint32_t hact, uint32_t vact, uint32_t refresh, bool ilace, bool reduced_v2, bool video_optimized)
{
	CVTConsts c = reduced_v2 ? cvt_consts_v2 : cvt_consts_v1;

	if (video_optimized)
		c.REFRESH_MULTIPLIER = 1000.0 / 1001.0;

	bool INT_RQD = ilace;

	float H_PIXELS = hact;
	float V_LINES = vact;
	float IP_FREQ_RQD = refresh ? refresh : 60;
	if (ilace)
		IP_FREQ_RQD /= 2;

	float V_SYNC_RND;

	if (reduced_v2) {
		V_SYNC_RND = 8;
	} else {
		if (hact * 3 == vact * 4)
			V_SYNC_RND = 4;
		else if (hact * 9 == vact * 16)
			V_SYNC_RND = 5;
		else if (hact * 10 == vact * 16)
			V_SYNC_RND = 6;
		else if (hact == 1280 && (vact == 1024 || vact == 768))
			V_SYNC_RND = 7;
		else
			V_SYNC_RND = 10;
	}

	// 5.2.1
	float V_FIELD_RATE_RQD = INT_RQD ? IP_FREQ_RQD * 2 : IP_FREQ_RQD;

	// 5.2.2
	float H_PIXELS_RND = floor(H_PIXELS / CELL_GRAN_RND) * CELL_GRAN_RND;

	// 5.2.3
	float LEFT_MARGIN = 0;
	float RIGHT_MARGIN = 0;

	// 5.2.4
	float TOTAL_ACTIVE_PIXELS = H_PIXELS_RND + LEFT_MARGIN + RIGHT_MARGIN;

	// 5.2.5
	float V_LINES_RND = INT_RQD ? floor(V_LINES / 2) : floor(V_LINES);

	// 5.2.6
	float TOP_MARGIN = 0;
	float BOT_MARGIN = 0;

	// 5.2.7
	float INTERLACE = INT_RQD ? 0.5 : 0;

	// 5.4.8
	float H_PERIOD_EST = ((1000000 / V_FIELD_RATE_RQD) - c.RB_MIN_V_BLANK) / (V_LINES_RND + TOP_MARGIN + BOT_MARGIN);

	// 5.4.9
	float VBI_LINES = floor(c.RB_MIN_V_BLANK / H_PERIOD_EST) + 1;

	// 5.4.10
	float RB_MIN_VBI = c.RB_V_FPORCH + V_SYNC_RND + c.MIN_V_BPORCH;
	float ACT_VBI_LINES = VBI_LINES < RB_MIN_VBI ? RB_MIN_VBI : VBI_LINES;

	// 5.4.11
	float TOTAL_V_LINES = ACT_VBI_LINES + V_LINES_RND + TOP_MARGIN + BOT_MARGIN + INTERLACE;

	// 5.4.12
	float TOTAL_PIXELS = c.RB_H_BLANK + TOTAL_ACTIVE_PIXELS;

	// 5.4.13
	float ACT_PIXEL_FREQ = c.CLOCK_STEP * floor((V_FIELD_RATE_RQD * TOTAL_V_LINES * TOTAL_PIXELS / 1000000 * c.REFRESH_MULTIPLIER) / c.CLOCK_STEP);

	// 5.4.14
	//float ACT_H_FREQ = 1000 * ACT_PIXEL_FREQ / TOTAL_PIXELS;

	// 5.4.15
	//float ACT_FIELD_RATE = 1000 * ACT_H_FREQ / TOTAL_V_LINES;

	// 5.4.16
	//float ACT_FRAME_RATE = INT_RQD ? ACT_FIELD_RATE / 2 : ACT_FIELD_RATE;

	// 3.4.3.7 Adjust vfp
	if (reduced_v2)
		c.RB_V_FPORCH = ACT_VBI_LINES - V_SYNC_RND - c.MIN_V_BPORCH;

	Videomode mode;

	mode = videomode_from_timings(ACT_PIXEL_FREQ * 1000,
				      H_PIXELS_RND, c.RB_H_FPORCH, c.RB_H_SYNC, c.RB_H_BPORCH,
				      V_LINES_RND * (INT_RQD ? 2 : 1), c.RB_V_FPORCH, V_SYNC_RND, ACT_VBI_LINES - V_SYNC_RND - c.RB_V_FPORCH);

	mode.set_hsync(SyncPolarity::Positive);
	mode.set_vsync(SyncPolarity::Negative);

	mode.set_interlace(INT_RQD);

	return mode;
}

} // namespace kms