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