xref: /haiku/src/add-ons/accelerants/common/validate_display_mode.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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
15 extern "C"
16 #endif
17 void _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 
26 static uint16
27 round(uint16 value, uint16 resolution)
28 {
29 	return value / resolution * resolution;
30 }
31 
32 
33 static void
34 sanitize_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 */
87 bool
88 sanitize_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 
133 bool
134 is_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.h_display < low.timing.h_display
150 		|| mode.timing.h_display > high.timing.h_display
151 		|| mode.timing.h_sync_start < low.timing.h_sync_start
152 		|| mode.timing.h_sync_start > high.timing.h_sync_start
153 		|| mode.timing.h_sync_end < low.timing.h_sync_end
154 		|| mode.timing.h_sync_end > high.timing.h_sync_end
155 		|| mode.timing.h_total < low.timing.h_total
156 		|| mode.timing.h_total > high.timing.h_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