1/*
2 * Copyright 2011, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <validate_display_mode.h>
8
9#include <string.h>
10
11
12//#define TRACE_VALIDATION
13#ifdef TRACE_VALIDATION
14#ifdef __cplusplus
15extern "C"
16#endif
17void _sPrintf(const char *format, ...);
18#   define TRACE(x...) _sPrintf("accelerant common: " x)
19#else
20#   define TRACE(x...) ;
21#endif
22
23#define ERROR(x...) _sPrintf("accelerant common: " x)
24
25
26static uint16
27round(uint16 value, uint16 resolution)
28{
29	return value / resolution * resolution;
30}
31
32
33static void
34sanitize_timing(uint16& display, uint16& syncStart, uint16& syncEnd,
35	uint16& total, const timing_constraints& constraints)
36{
37	if (syncStart < display + constraints.min_before_sync) {
38		TRACE("%s: syncStart(%" B_PRIu16 ") < display(%" B_PRIu16 ")"
39			" + min_before_sync(%" B_PRIu16 ")\n", __func__, syncStart,
40			display, constraints.min_before_sync);
41		syncStart = display + constraints.min_before_sync;
42	} else if (syncStart > constraints.max_sync_start) {
43		TRACE("%s: syncStart(%" B_PRIu16 ") > max_sync_start(%" B_PRIu16 ")\n",
44			__func__, syncStart, constraints.max_sync_start);
45		syncStart = constraints.max_sync_start;
46	}
47
48	uint32 syncLength = syncEnd - syncStart;
49	if (syncLength < constraints.min_sync_length) {
50		TRACE("%s: syncLength(%" B_PRIu16 ")"
51			" < min_sync_length(%" B_PRIu16 ")\n",
52			__func__, syncLength, constraints.min_sync_length);
53		syncLength = constraints.min_sync_length;
54	} else if (syncLength > constraints.max_sync_length) {
55		TRACE("%s: syncLength(%" B_PRIu16 ")"
56			" > max_sync_length(%" B_PRIu16 ")\n",
57			__func__, syncLength, constraints.max_sync_length);
58		syncLength = constraints.max_sync_length;
59	}
60
61	if (total < syncStart + syncLength + constraints.min_after_sync) {
62		TRACE("%s: total(%" B_PRIu16 ")"
63			" < syncStart(%" B_PRIu16 ")"
64			" + syncLength(%" B_PRIu16 ")"
65			" + min_after_sync(%" B_PRIu16 ")\n",
66			__func__, total, syncStart, syncLength, constraints.min_after_sync);
67		total = syncStart + syncLength + constraints.min_after_sync;
68	}
69
70	if (total > constraints.max_total) {
71		TRACE("%s: total(%" B_PRIu16 ") > max_total(%" B_PRIu16 ")\n",
72			__func__, total, constraints.max_total);
73		total = constraints.max_total;
74		syncLength = min_c(syncLength, uint16(total - syncStart));
75	}
76
77	syncEnd = round(syncStart + syncLength, constraints.resolution);
78	syncStart = round(syncStart, constraints.resolution);
79	display = round(display, constraints.resolution);
80	total = round(total, constraints.resolution);
81}
82
83
84/*! Makes sure the passed in \a mode fulfills the specified \a constraints.
85	Returns whether or not the mode had to be changed.
86*/
87bool
88sanitize_display_mode(display_mode& mode,
89	const display_constraints& constraints, const edid1_info* edid)
90{
91	display_mode originalMode = mode;
92
93	// size
94
95	if (mode.timing.h_display < constraints.min_h_display) {
96		TRACE("%s: h_display(%" B_PRIu16 ") < min_h_display(%" B_PRIu16 ")\n",
97			__func__, mode.timing.h_display, constraints.min_h_display);
98		mode.timing.h_display = constraints.min_h_display;
99	} else if (mode.timing.h_display > constraints.max_h_display) {
100		TRACE("%s: h_display(%" B_PRIu16 ") > max_h_display(%" B_PRIu16 ")\n",
101			__func__, mode.timing.h_display, constraints.max_h_display);
102		mode.timing.h_display = constraints.max_h_display;
103	}
104
105	if (mode.timing.v_display < constraints.min_v_display) {
106		TRACE("%s: v_display(%" B_PRIu16 ") < min_v_display(%" B_PRIu16 ")\n",
107			__func__, mode.timing.v_display, constraints.min_v_display);
108		mode.timing.v_display = constraints.min_v_display;
109	} else if (mode.timing.v_display > constraints.max_v_display) {
110		TRACE("%s: v_display(%" B_PRIu16 ") > max_v_display(%" B_PRIu16 ")\n",
111			__func__, mode.timing.v_display, constraints.max_v_display);
112		mode.timing.v_display = constraints.max_v_display;
113	}
114
115	// horizontal timing
116
117	sanitize_timing(mode.timing.h_display, mode.timing.h_sync_start,
118		mode.timing.h_sync_end, mode.timing.h_total,
119		constraints.horizontal_timing);
120
121	// vertical timing
122
123	sanitize_timing(mode.timing.v_display, mode.timing.v_sync_start,
124		mode.timing.v_sync_end, mode.timing.v_total,
125		constraints.vertical_timing);
126
127	// TODO: take EDID and pixel clock into account!
128
129	return memcmp(&mode, &originalMode, sizeof(display_mode)) != 0;
130}
131
132
133bool
134is_display_mode_within_bounds(display_mode& mode, const display_mode& low,
135	const display_mode& high)
136{
137	// Check horizontal timing
138	if (mode.timing.h_display < low.timing.h_display
139		|| mode.timing.h_display > high.timing.h_display
140		|| mode.timing.h_sync_start < low.timing.h_sync_start
141		|| mode.timing.h_sync_start > high.timing.h_sync_start
142		|| mode.timing.h_sync_end < low.timing.h_sync_end
143		|| mode.timing.h_sync_end > high.timing.h_sync_end
144		|| mode.timing.h_total < low.timing.h_total
145		|| mode.timing.h_total > high.timing.h_total)
146		return false;
147
148	// Check vertical timing
149	if (mode.timing.v_display < low.timing.v_display
150		|| mode.timing.v_display > high.timing.v_display
151		|| mode.timing.v_sync_start < low.timing.v_sync_start
152		|| mode.timing.v_sync_start > high.timing.v_sync_start
153		|| mode.timing.v_sync_end < low.timing.v_sync_end
154		|| mode.timing.v_sync_end > high.timing.v_sync_end
155		|| mode.timing.v_total < low.timing.v_total
156		|| mode.timing.v_total > high.timing.v_total)
157		return false;
158
159	// Check pixel clock
160	if (mode.timing.pixel_clock > high.timing.pixel_clock
161		|| mode.timing.pixel_clock < low.timing.pixel_clock)
162		return false;
163
164	// Check horizontal size
165	if (mode.virtual_width > high.virtual_width
166		|| mode.virtual_width < low.virtual_width)
167		return false;
168
169	// Check vertical size
170	if (mode.virtual_height > high.virtual_height
171		|| mode.virtual_height < low.virtual_height)
172		return false;
173
174	return true;
175}
176