xref: /haiku/src/add-ons/accelerants/common/create_display_modes.cpp (revision 7badc72cf1d72904b4665b908f27d7326d6685e4)
17bdf92f3SAxel Dörfler /*
2*7badc72cSAxel Dörfler  * Copyright 2007-2009, Axel Dörfler, axeld@pinc-software.de.
37bdf92f3SAxel Dörfler  * Distributed under the terms of the MIT License.
47bdf92f3SAxel Dörfler  */
57bdf92f3SAxel Dörfler 
67bdf92f3SAxel Dörfler 
77bdf92f3SAxel Dörfler #include <create_display_modes.h>
87bdf92f3SAxel Dörfler 
97bdf92f3SAxel Dörfler #include <math.h>
107bdf92f3SAxel Dörfler #include <stdlib.h>
117bdf92f3SAxel Dörfler #include <string.h>
127bdf92f3SAxel Dörfler 
137bdf92f3SAxel Dörfler #include <video_overlay.h>
147bdf92f3SAxel Dörfler 
157bdf92f3SAxel Dörfler 
167bdf92f3SAxel Dörfler #define	POSITIVE_SYNC \
177bdf92f3SAxel Dörfler 	(B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
187bdf92f3SAxel Dörfler #define MODE_FLAGS \
1979566892SAxel Dörfler 	(B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS \
2079566892SAxel Dörfler 		| B_SUPPORTS_OVERLAYS)
217bdf92f3SAxel Dörfler 
227bdf92f3SAxel Dörfler // TODO: move this list into the app_server
237bdf92f3SAxel Dörfler static const display_mode kBaseModeList[] = {
247bdf92f3SAxel Dörfler 	{{25175, 640, 656, 752, 800, 350, 387, 389, 449, B_POSITIVE_HSYNC}, B_CMAP8, 640, 350, 0, 0, MODE_FLAGS}, /* 640x350 - www.epanorama.net/documents/pc/vga_timing.html) */
25f54507d7SAxel Dörfler 
267bdf92f3SAxel Dörfler 	{{25175, 640, 656, 752, 800, 400, 412, 414, 449, B_POSITIVE_VSYNC}, B_CMAP8, 640, 400, 0, 0, MODE_FLAGS}, /* 640x400 - www.epanorama.net/documents/pc/vga_timing.html) */
27f54507d7SAxel Dörfler 
287bdf92f3SAxel Dörfler 	{{25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
297bdf92f3SAxel Dörfler 	{{31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
307bdf92f3SAxel Dörfler 	{{31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
317bdf92f3SAxel Dörfler 	{{36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
32f54507d7SAxel Dörfler 
336c398600SAxel Dörfler 	{{29580, 800, 816, 896, 992, 480, 481, 484, 497, B_POSITIVE_VSYNC}, B_CMAP8, 800, 480, 0, 0, MODE_FLAGS}, /* 800x480x60Hz */
34f54507d7SAxel Dörfler 
357bdf92f3SAxel Dörfler 	{{38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
367bdf92f3SAxel Dörfler 	{{40000, 800, 840, 968, 1056, 600, 601, 605, 628, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
377bdf92f3SAxel Dörfler 	{{49500, 800, 816, 896, 1056, 600, 601, 604, 625, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
387bdf92f3SAxel Dörfler 	{{50000, 800, 856, 976, 1040, 600, 637, 643, 666, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */
397bdf92f3SAxel Dörfler 	{{56250, 800, 832, 896, 1048, 600, 601, 604, 631, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */
40f54507d7SAxel Dörfler 
417bdf92f3SAxel Dörfler 	{{65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */
427bdf92f3SAxel Dörfler 	{{75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */
437bdf92f3SAxel Dörfler 	{{78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
447bdf92f3SAxel Dörfler 	{{94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
45f54507d7SAxel Dörfler 
46f54507d7SAxel Dörfler 	{{81640, 1152, 1216, 1336, 1520, 864, 865, 868, 895, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* 1152x864x60Hz */
477bdf92f3SAxel Dörfler 	{{94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
487bdf92f3SAxel Dörfler 	{{108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
497bdf92f3SAxel Dörfler 	{{121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
50f54507d7SAxel Dörfler 
514165dff9SAxel Dörfler 	{{74520, 1280, 1368, 1424, 1656, 720, 724, 730, 750, POSITIVE_SYNC}, B_CMAP8, 1280, 720, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X720) */
52f54507d7SAxel Dörfler 
536c398600SAxel Dörfler 	{{83460, 1280, 1344, 1480, 1680, 800, 801, 804, 828, B_POSITIVE_VSYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* WXGA (1280x800x60) */
54f54507d7SAxel Dörfler 
557bdf92f3SAxel Dörfler 	{{108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
567bdf92f3SAxel Dörfler 	{{135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
577bdf92f3SAxel Dörfler 	{{157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
58f54507d7SAxel Dörfler 
594165dff9SAxel Dörfler 	{{122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */
60f54507d7SAxel Dörfler 	{{155800, 1400, 1464, 1784, 1912, 1050, 1052, 1064, 1090, POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1400X1050) */
617bdf92f3SAxel Dörfler 
627bdf92f3SAxel Dörfler 	{{106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */
637bdf92f3SAxel Dörfler 
647bdf92f3SAxel Dörfler 	{{162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */
657bdf92f3SAxel Dörfler 	{{175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */
667bdf92f3SAxel Dörfler 	{{189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */
677bdf92f3SAxel Dörfler 	{{202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */
687bdf92f3SAxel Dörfler 	{{216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
697bdf92f3SAxel Dörfler 	{{229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
707bdf92f3SAxel Dörfler 
717bdf92f3SAxel Dörfler 	{{147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1680X1050) */
727bdf92f3SAxel Dörfler 
73258ca318SAxel Dörfler 	//{{160000, 1920, 2010, 2060, 2110, 1200, 1202, 1208, 1235, POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
74258ca318SAxel Dörfler 	{{193160, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
757bdf92f3SAxel Dörfler };
767bdf92f3SAxel Dörfler static const uint32 kNumBaseModes = sizeof(kBaseModeList) / sizeof(display_mode);
777bdf92f3SAxel Dörfler 
787bdf92f3SAxel Dörfler 
797bdf92f3SAxel Dörfler namespace BPrivate {
807bdf92f3SAxel Dörfler 
817bdf92f3SAxel Dörfler class ModeList {
827bdf92f3SAxel Dörfler public:
837bdf92f3SAxel Dörfler 	ModeList();
847bdf92f3SAxel Dörfler 	~ModeList();
857bdf92f3SAxel Dörfler 
867bdf92f3SAxel Dörfler 	bool AddModes(edid1_info* info);
877bdf92f3SAxel Dörfler 	bool AddModes(const display_mode* modes, uint32 count);
887bdf92f3SAxel Dörfler 
897bdf92f3SAxel Dörfler 	bool CreateColorSpaces(const color_space* spaces, uint32 count);
907bdf92f3SAxel Dörfler 	void Filter(check_display_mode_hook hook);
917bdf92f3SAxel Dörfler 	void Clean();
927bdf92f3SAxel Dörfler 
937bdf92f3SAxel Dörfler 	const display_mode* Modes() const { return fModes; }
947bdf92f3SAxel Dörfler 	uint32 Count() const { return fCount; }
957bdf92f3SAxel Dörfler 
967bdf92f3SAxel Dörfler private:
977bdf92f3SAxel Dörfler 	bool _MakeSpace(uint32 count);
987bdf92f3SAxel Dörfler 	bool _AddMode(const display_mode* mode);
997bdf92f3SAxel Dörfler 	void _RemoveModeAt(uint32 index);
1007bdf92f3SAxel Dörfler 	void _AddBaseMode(uint16 width, uint16 height, uint32 refresh);
101*7badc72cSAxel Dörfler 	display_mode* _FindMode(uint16 width, uint16 height) const;
1027bdf92f3SAxel Dörfler 
1037bdf92f3SAxel Dörfler 	display_mode*	fModes;
1047bdf92f3SAxel Dörfler 	uint32			fCount;
1057bdf92f3SAxel Dörfler 	uint32			fCapacity;
1067bdf92f3SAxel Dörfler };
1077bdf92f3SAxel Dörfler 
1087bdf92f3SAxel Dörfler }	// namespace BPrivate
1097bdf92f3SAxel Dörfler 
1107bdf92f3SAxel Dörfler using namespace BPrivate;
1117bdf92f3SAxel Dörfler 
1127bdf92f3SAxel Dörfler 
1137bdf92f3SAxel Dörfler static float
1147bdf92f3SAxel Dörfler get_refresh_rate(const display_mode& mode)
1157bdf92f3SAxel Dörfler {
116*7badc72cSAxel Dörfler 	return float(mode.timing.pixel_clock * 1000)
117*7badc72cSAxel Dörfler 		/ float(mode.timing.h_total * mode.timing.v_total);
1187bdf92f3SAxel Dörfler }
1197bdf92f3SAxel Dörfler 
1207bdf92f3SAxel Dörfler 
1217bdf92f3SAxel Dörfler static int
1227bdf92f3SAxel Dörfler compare_mode(const void* _mode1, const void* _mode2)
1237bdf92f3SAxel Dörfler {
1247bdf92f3SAxel Dörfler 	display_mode *mode1 = (display_mode *)_mode1;
1257bdf92f3SAxel Dörfler 	display_mode *mode2 = (display_mode *)_mode2;
1267bdf92f3SAxel Dörfler 	uint16 width1, width2, height1, height2;
1277bdf92f3SAxel Dörfler 
1287bdf92f3SAxel Dörfler 	width1 = mode1->virtual_width;
1297bdf92f3SAxel Dörfler 	height1 = mode1->virtual_height;
1307bdf92f3SAxel Dörfler 	width2 = mode2->virtual_width;
1317bdf92f3SAxel Dörfler 	height2 = mode2->virtual_height;
1327bdf92f3SAxel Dörfler 
1337bdf92f3SAxel Dörfler 	if (width1 != width2)
1347bdf92f3SAxel Dörfler 		return width1 - width2;
1357bdf92f3SAxel Dörfler 
1367bdf92f3SAxel Dörfler 	if (height1 != height2)
1377bdf92f3SAxel Dörfler 		return height1 - height2;
1387bdf92f3SAxel Dörfler 
1397bdf92f3SAxel Dörfler 	if (mode1->space != mode2->space)
1407bdf92f3SAxel Dörfler 		return mode1->space - mode2->space;
1417bdf92f3SAxel Dörfler 
142c54a6536SAxel Dörfler 	return (int)(100 * (get_refresh_rate(*mode1) - get_refresh_rate(*mode2)));
1437bdf92f3SAxel Dörfler }
1447bdf92f3SAxel Dörfler 
1457bdf92f3SAxel Dörfler 
1467bdf92f3SAxel Dörfler //	#pragma mark -
1477bdf92f3SAxel Dörfler 
1487bdf92f3SAxel Dörfler 
1497bdf92f3SAxel Dörfler ModeList::ModeList()
1507bdf92f3SAxel Dörfler 	:
1517bdf92f3SAxel Dörfler 	fModes(NULL),
1527bdf92f3SAxel Dörfler 	fCount(0),
1537bdf92f3SAxel Dörfler 	fCapacity(0)
1547bdf92f3SAxel Dörfler {
1557bdf92f3SAxel Dörfler }
1567bdf92f3SAxel Dörfler 
1577bdf92f3SAxel Dörfler 
1587bdf92f3SAxel Dörfler ModeList::~ModeList()
1597bdf92f3SAxel Dörfler {
1607bdf92f3SAxel Dörfler 	free(fModes);
1617bdf92f3SAxel Dörfler }
1627bdf92f3SAxel Dörfler 
1637bdf92f3SAxel Dörfler 
1647bdf92f3SAxel Dörfler bool
1657bdf92f3SAxel Dörfler ModeList::AddModes(edid1_info* info)
1667bdf92f3SAxel Dörfler {
1677bdf92f3SAxel Dörfler 	if (info->established_timing.res_720x400x70)
1687bdf92f3SAxel Dörfler 		_AddBaseMode(720, 400, 70);
1697bdf92f3SAxel Dörfler 	if (info->established_timing.res_720x400x88)
1707bdf92f3SAxel Dörfler 		_AddBaseMode(720, 400, 88);
1717bdf92f3SAxel Dörfler 
1727bdf92f3SAxel Dörfler 	if (info->established_timing.res_640x480x60)
1737bdf92f3SAxel Dörfler 		_AddBaseMode(640, 480, 60);
1747bdf92f3SAxel Dörfler 	if (info->established_timing.res_640x480x67)
1757bdf92f3SAxel Dörfler 		_AddBaseMode(640, 480, 67);
1767bdf92f3SAxel Dörfler 	if (info->established_timing.res_640x480x72)
1777bdf92f3SAxel Dörfler 		_AddBaseMode(640, 480, 72);
1787bdf92f3SAxel Dörfler 	if (info->established_timing.res_640x480x75)
1797bdf92f3SAxel Dörfler 		_AddBaseMode(640, 480, 75);
1807bdf92f3SAxel Dörfler 
1817bdf92f3SAxel Dörfler 	if (info->established_timing.res_800x600x56)
1827bdf92f3SAxel Dörfler 		_AddBaseMode(800, 600, 56);
1837bdf92f3SAxel Dörfler 	if (info->established_timing.res_800x600x60)
1847bdf92f3SAxel Dörfler 		_AddBaseMode(800, 600, 60);
1857bdf92f3SAxel Dörfler 	if (info->established_timing.res_800x600x72)
1867bdf92f3SAxel Dörfler 		_AddBaseMode(800, 600, 72);
1877bdf92f3SAxel Dörfler 	if (info->established_timing.res_800x600x75)
1887bdf92f3SAxel Dörfler 		_AddBaseMode(800, 600, 75);
1897bdf92f3SAxel Dörfler 
1907bdf92f3SAxel Dörfler #if 0
1917bdf92f3SAxel Dörfler 	if (info->established_timing.res_832x624x75)
1927bdf92f3SAxel Dörfler 		_AddBaseMode(832, 624, 75);
1937bdf92f3SAxel Dörfler 
1947bdf92f3SAxel Dörfler 	if (info->established_timing.res_1024x768x87i)
1957bdf92f3SAxel Dörfler 		_AddBaseMode(1024, 768, 87);
1967bdf92f3SAxel Dörfler #endif
1977bdf92f3SAxel Dörfler 	if (info->established_timing.res_1024x768x60)
1987bdf92f3SAxel Dörfler 		_AddBaseMode(1024, 768, 60);
1997bdf92f3SAxel Dörfler 	if (info->established_timing.res_1024x768x70)
2007bdf92f3SAxel Dörfler 		_AddBaseMode(1024, 768, 70);
2017bdf92f3SAxel Dörfler 	if (info->established_timing.res_1024x768x75)
2027bdf92f3SAxel Dörfler 		_AddBaseMode(1024, 768, 75);
2037bdf92f3SAxel Dörfler 
2047bdf92f3SAxel Dörfler 	if (info->established_timing.res_1152x870x75)
2057bdf92f3SAxel Dörfler 		_AddBaseMode(1152, 870, 75);
2067bdf92f3SAxel Dörfler 	if (info->established_timing.res_1280x1024x75)
2077bdf92f3SAxel Dörfler 		_AddBaseMode(1280, 1024, 75);
2087bdf92f3SAxel Dörfler 
2097bdf92f3SAxel Dörfler 	for (uint32 i = 0; i < EDID1_NUM_STD_TIMING; ++i) {
2107bdf92f3SAxel Dörfler 		if (info->std_timing[i].h_size <= 256)
2117bdf92f3SAxel Dörfler 			continue;
2127bdf92f3SAxel Dörfler 
2137bdf92f3SAxel Dörfler 		_AddBaseMode(info->std_timing[i].h_size, info->std_timing[i].v_size,
2147bdf92f3SAxel Dörfler 			info->std_timing[i].refresh);
2157bdf92f3SAxel Dörfler 	}
2167bdf92f3SAxel Dörfler 
217*7badc72cSAxel Dörfler 	bool hasRanges = false;
218*7badc72cSAxel Dörfler 	uint32 minHorizontalFrequency = 0;
219*7badc72cSAxel Dörfler 	uint32 maxHorizontalFrequency = 0;
220*7badc72cSAxel Dörfler 	uint32 minVerticalFrequency = 0;
221*7badc72cSAxel Dörfler 	uint32 maxVerticalFrequency = 0;
222*7badc72cSAxel Dörfler 	uint32 maxPixelClock = 0;
223*7badc72cSAxel Dörfler 
2247bdf92f3SAxel Dörfler 	for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
22579566892SAxel Dörfler 		if (info->detailed_monitor[i].monitor_desc_type
226*7badc72cSAxel Dörfler 				== EDID1_MONITOR_RANGES) {
227*7badc72cSAxel Dörfler 			edid1_monitor_range& range
228*7badc72cSAxel Dörfler 				= info->detailed_monitor[i].data.monitor_range;
229*7badc72cSAxel Dörfler 
230*7badc72cSAxel Dörfler 			hasRanges = true;
231*7badc72cSAxel Dörfler 			minHorizontalFrequency = range.min_h;
232*7badc72cSAxel Dörfler 			maxHorizontalFrequency = range.max_h;
233*7badc72cSAxel Dörfler 			minVerticalFrequency = range.min_v;
234*7badc72cSAxel Dörfler 			maxVerticalFrequency = range.max_v;
235*7badc72cSAxel Dörfler 			maxPixelClock = range.max_clock * 10000;
236*7badc72cSAxel Dörfler 			continue;
237*7badc72cSAxel Dörfler 		} else if (info->detailed_monitor[i].monitor_desc_type
23879566892SAxel Dörfler 				!= EDID1_IS_DETAILED_TIMING)
2397bdf92f3SAxel Dörfler 			continue;
2407bdf92f3SAxel Dörfler 
241c54a6536SAxel Dörfler 		// TODO: handle flags correctly!
24279566892SAxel Dörfler 		const edid1_detailed_timing& timing
24379566892SAxel Dörfler 			= info->detailed_monitor[i].data.detailed_timing;
2447bdf92f3SAxel Dörfler 		display_mode mode;
245c54a6536SAxel Dörfler 
24679566892SAxel Dörfler 		if (timing.pixel_clock <= 0/* || timing.sync != 3*/)
247c54a6536SAxel Dörfler 			continue;
248c54a6536SAxel Dörfler 
2497bdf92f3SAxel Dörfler 		mode.timing.pixel_clock = timing.pixel_clock * 10;
2507bdf92f3SAxel Dörfler 		mode.timing.h_display = timing.h_active;
251fe2aaee7SAxel Dörfler 		mode.timing.h_sync_start = timing.h_active + timing.h_sync_off;
252fe2aaee7SAxel Dörfler 		mode.timing.h_sync_end = mode.timing.h_sync_start + timing.h_sync_width;
253fe2aaee7SAxel Dörfler 		mode.timing.h_total = timing.h_active + timing.h_blank;
2547bdf92f3SAxel Dörfler 		mode.timing.v_display = timing.v_active;
255fe2aaee7SAxel Dörfler 		mode.timing.v_sync_start = timing.v_active + timing.v_sync_off;
256fe2aaee7SAxel Dörfler 		mode.timing.v_sync_end = mode.timing.v_sync_start + timing.v_sync_width;
257fe2aaee7SAxel Dörfler 		mode.timing.v_total = timing.v_active + timing.v_blank;
258c54a6536SAxel Dörfler 		mode.timing.flags = 0;
259c54a6536SAxel Dörfler 		if (timing.sync == 3) {
260c54a6536SAxel Dörfler 			if (timing.misc & 1)
261c54a6536SAxel Dörfler 				mode.timing.flags |= B_POSITIVE_HSYNC;
262c54a6536SAxel Dörfler 			if (timing.misc & 2)
263c54a6536SAxel Dörfler 				mode.timing.flags |= B_POSITIVE_VSYNC;
264c54a6536SAxel Dörfler 		}
265fe2aaee7SAxel Dörfler 		if (timing.interlaced)
266fe2aaee7SAxel Dörfler 			mode.timing.flags |= B_TIMING_INTERLACED;
2677bdf92f3SAxel Dörfler 		mode.space = B_RGB32;
2687bdf92f3SAxel Dörfler 		mode.virtual_width = timing.h_active;
2697bdf92f3SAxel Dörfler 		mode.virtual_height = timing.v_active;
2707bdf92f3SAxel Dörfler 		mode.h_display_start = 0;
2717bdf92f3SAxel Dörfler 		mode.v_display_start = 0;
2727bdf92f3SAxel Dörfler 		mode.flags = MODE_FLAGS;
273c54a6536SAxel Dörfler 
274c54a6536SAxel Dörfler 		_AddMode(&mode);
2757bdf92f3SAxel Dörfler 	}
2767bdf92f3SAxel Dörfler 
277*7badc72cSAxel Dörfler 	// Add other modes from the base list that satisfy the display's
278*7badc72cSAxel Dörfler 	// requirements
279*7badc72cSAxel Dörfler 
280*7badc72cSAxel Dörfler 	for (uint32 i = 0; i < kNumBaseModes; i++) {
281*7badc72cSAxel Dörfler 		const display_mode& mode = kBaseModeList[i];
282*7badc72cSAxel Dörfler 
283*7badc72cSAxel Dörfler 		// Check if a mode with this resolution already exists
284*7badc72cSAxel Dörfler 
285*7badc72cSAxel Dörfler 		if (_FindMode(mode.timing.h_display, mode.timing.v_display) != NULL)
286*7badc72cSAxel Dörfler 			continue;
287*7badc72cSAxel Dörfler 
288*7badc72cSAxel Dörfler 		// Check monitor limits
289*7badc72cSAxel Dörfler 
290*7badc72cSAxel Dörfler 		if (hasRanges) {
291*7badc72cSAxel Dörfler 			uint32 verticalFrequency = 1000 * mode.timing.pixel_clock
292*7badc72cSAxel Dörfler 				/ (mode.timing.h_total * mode.timing.v_total);
293*7badc72cSAxel Dörfler 			uint32 horizontalFrequency = mode.timing.h_total * verticalFrequency
294*7badc72cSAxel Dörfler 				/ 1000;
295*7badc72cSAxel Dörfler 
296*7badc72cSAxel Dörfler 			if (minHorizontalFrequency > horizontalFrequency
297*7badc72cSAxel Dörfler 				|| maxHorizontalFrequency < horizontalFrequency
298*7badc72cSAxel Dörfler 				|| minVerticalFrequency > verticalFrequency
299*7badc72cSAxel Dörfler 				|| maxVerticalFrequency < verticalFrequency
300*7badc72cSAxel Dörfler 				|| maxPixelClock < mode.timing.pixel_clock)
301*7badc72cSAxel Dörfler 				continue;
302*7badc72cSAxel Dörfler 		}
303*7badc72cSAxel Dörfler 
304*7badc72cSAxel Dörfler 		_AddMode(&mode);
305*7badc72cSAxel Dörfler 	}
3067bdf92f3SAxel Dörfler 
3077bdf92f3SAxel Dörfler 	return true;
3087bdf92f3SAxel Dörfler }
3097bdf92f3SAxel Dörfler 
3107bdf92f3SAxel Dörfler 
3117bdf92f3SAxel Dörfler bool
3127bdf92f3SAxel Dörfler ModeList::AddModes(const display_mode* modes, uint32 count)
3137bdf92f3SAxel Dörfler {
3147bdf92f3SAxel Dörfler 	if (!_MakeSpace(count))
3157bdf92f3SAxel Dörfler 		return false;
3167bdf92f3SAxel Dörfler 
3177bdf92f3SAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
3187bdf92f3SAxel Dörfler 		fModes[fCount++] = modes[i];
3197bdf92f3SAxel Dörfler 	}
3207bdf92f3SAxel Dörfler 
3217bdf92f3SAxel Dörfler 	return true;
3227bdf92f3SAxel Dörfler }
3237bdf92f3SAxel Dörfler 
3247bdf92f3SAxel Dörfler 
3257bdf92f3SAxel Dörfler bool
3267bdf92f3SAxel Dörfler ModeList::CreateColorSpaces(const color_space* spaces, uint32 count)
3277bdf92f3SAxel Dörfler {
3287bdf92f3SAxel Dörfler 	uint32 modeCount = fCount;
3297bdf92f3SAxel Dörfler 
3307bdf92f3SAxel Dörfler 	for (uint32 i = 0; i < count; i++) {
3317bdf92f3SAxel Dörfler 		if (i > 0 && !AddModes(fModes, modeCount))
3327bdf92f3SAxel Dörfler 			return false;
3337bdf92f3SAxel Dörfler 
3347bdf92f3SAxel Dörfler 		for (uint32 j = 0; j < modeCount; j++) {
3357bdf92f3SAxel Dörfler 			fModes[j + fCount - modeCount].space = spaces[i];
3367bdf92f3SAxel Dörfler 		}
3377bdf92f3SAxel Dörfler 	}
3387bdf92f3SAxel Dörfler 
3397bdf92f3SAxel Dörfler 	return true;
3407bdf92f3SAxel Dörfler }
3417bdf92f3SAxel Dörfler 
3427bdf92f3SAxel Dörfler 
3437bdf92f3SAxel Dörfler void
3447bdf92f3SAxel Dörfler ModeList::Filter(check_display_mode_hook hook)
3457bdf92f3SAxel Dörfler {
3467bdf92f3SAxel Dörfler 	if (hook == NULL)
3477bdf92f3SAxel Dörfler 		return;
3487bdf92f3SAxel Dörfler 
3497bdf92f3SAxel Dörfler 	for (uint32 i = fCount; i-- > 0;) {
3507bdf92f3SAxel Dörfler 		if (!hook(&fModes[i]))
3517bdf92f3SAxel Dörfler 			_RemoveModeAt(i);
3527bdf92f3SAxel Dörfler 	}
3537bdf92f3SAxel Dörfler }
3547bdf92f3SAxel Dörfler 
3557bdf92f3SAxel Dörfler 
3567bdf92f3SAxel Dörfler void
3577bdf92f3SAxel Dörfler ModeList::Clean()
3587bdf92f3SAxel Dörfler {
3597bdf92f3SAxel Dörfler 	// sort mode list
3607bdf92f3SAxel Dörfler 	qsort(fModes, fCount, sizeof(display_mode), compare_mode);
3617bdf92f3SAxel Dörfler 
3627bdf92f3SAxel Dörfler 	// remove duplicates
3637bdf92f3SAxel Dörfler 	for (uint32 i = fCount; i-- > 1;) {
3647bdf92f3SAxel Dörfler 		if (compare_mode(&fModes[i], &fModes[i - 1]) == 0)
3657bdf92f3SAxel Dörfler 			_RemoveModeAt(i);
3667bdf92f3SAxel Dörfler 	}
3677bdf92f3SAxel Dörfler }
3687bdf92f3SAxel Dörfler 
3697bdf92f3SAxel Dörfler 
3707bdf92f3SAxel Dörfler void
3717bdf92f3SAxel Dörfler ModeList::_AddBaseMode(uint16 width, uint16 height, uint32 refresh)
3727bdf92f3SAxel Dörfler {
3737bdf92f3SAxel Dörfler 	for (uint32 i = 0; i < kNumBaseModes; i++) {
3747bdf92f3SAxel Dörfler 		const display_mode& mode = kBaseModeList[i];
3757bdf92f3SAxel Dörfler 
376c54a6536SAxel Dörfler 		// Add mode if width and height match, and the computed refresh rate of
377c54a6536SAxel Dörfler 		// the mode is within 1.2 percent of the refresh rate specified by the
378c54a6536SAxel Dörfler 		// caller.  Note that refresh rates computed from mode parameters is
379c54a6536SAxel Dörfler 		// not exact;  thus, the tolerance of 1.2% was obtained by testing the
380c54a6536SAxel Dörfler 		// various established modes that can be selected by the EDID info.
381c54a6536SAxel Dörfler 
3827bdf92f3SAxel Dörfler 		if (mode.timing.h_display == width && mode.timing.v_display == height
383c54a6536SAxel Dörfler 			&& fabs(get_refresh_rate(mode) - refresh) < refresh * 0.012) {
3847bdf92f3SAxel Dörfler 			_AddMode(&mode);
3857bdf92f3SAxel Dörfler 		}
3867bdf92f3SAxel Dörfler 	}
3877bdf92f3SAxel Dörfler }
3887bdf92f3SAxel Dörfler 
3897bdf92f3SAxel Dörfler 
390*7badc72cSAxel Dörfler display_mode*
391*7badc72cSAxel Dörfler ModeList::_FindMode(uint16 width, uint16 height) const
392*7badc72cSAxel Dörfler {
393*7badc72cSAxel Dörfler 	for (uint32 i = 0; i < fCount; i++) {
394*7badc72cSAxel Dörfler 		const display_mode& mode = fModes[i];
395*7badc72cSAxel Dörfler 
396*7badc72cSAxel Dörfler 		if (mode.timing.h_display == width && mode.timing.v_display == height)
397*7badc72cSAxel Dörfler 			return &fModes[i];
398*7badc72cSAxel Dörfler 	}
399*7badc72cSAxel Dörfler 
400*7badc72cSAxel Dörfler 	return NULL;
401*7badc72cSAxel Dörfler }
402*7badc72cSAxel Dörfler 
403*7badc72cSAxel Dörfler 
4047bdf92f3SAxel Dörfler bool
4057bdf92f3SAxel Dörfler ModeList::_MakeSpace(uint32 count)
4067bdf92f3SAxel Dörfler {
4077bdf92f3SAxel Dörfler 	if (fCount + count <= fCapacity)
4087bdf92f3SAxel Dörfler 		return true;
4097bdf92f3SAxel Dörfler 
4107bdf92f3SAxel Dörfler 	uint32 capacity = (fCapacity + count + 0xf) & ~0xf;
4117bdf92f3SAxel Dörfler 	display_mode* modes = (display_mode*)realloc(fModes,
4127bdf92f3SAxel Dörfler 		capacity * sizeof(display_mode));
4137bdf92f3SAxel Dörfler 	if (modes == NULL)
4147bdf92f3SAxel Dörfler 		return false;
4157bdf92f3SAxel Dörfler 
4167bdf92f3SAxel Dörfler 	fModes = modes;
4177bdf92f3SAxel Dörfler 	fCapacity = capacity;
4187bdf92f3SAxel Dörfler 	return true;
4197bdf92f3SAxel Dörfler }
4207bdf92f3SAxel Dörfler 
4217bdf92f3SAxel Dörfler 
4227bdf92f3SAxel Dörfler bool
4237bdf92f3SAxel Dörfler ModeList::_AddMode(const display_mode* mode)
4247bdf92f3SAxel Dörfler {
4257bdf92f3SAxel Dörfler 	if (!_MakeSpace(1))
4267bdf92f3SAxel Dörfler 		return false;
4277bdf92f3SAxel Dörfler 
4287bdf92f3SAxel Dörfler 	fModes[fCount++] = *mode;
4297bdf92f3SAxel Dörfler 	return true;
4307bdf92f3SAxel Dörfler }
4317bdf92f3SAxel Dörfler 
4327bdf92f3SAxel Dörfler 
4337bdf92f3SAxel Dörfler void
4347bdf92f3SAxel Dörfler ModeList::_RemoveModeAt(uint32 index)
4357bdf92f3SAxel Dörfler {
4367bdf92f3SAxel Dörfler 	if (index < fCount - 1) {
4377bdf92f3SAxel Dörfler 		memmove(&fModes[index], &fModes[index + 1],
4387bdf92f3SAxel Dörfler 			(fCount - 1 - index) * sizeof(display_mode));
4397bdf92f3SAxel Dörfler 	}
4407bdf92f3SAxel Dörfler 
4417bdf92f3SAxel Dörfler 	fCount--;
4427bdf92f3SAxel Dörfler }
4437bdf92f3SAxel Dörfler 
4447bdf92f3SAxel Dörfler 
4457bdf92f3SAxel Dörfler //	#pragma mark -
4467bdf92f3SAxel Dörfler 
4477bdf92f3SAxel Dörfler 
4487bdf92f3SAxel Dörfler extern "C" area_id
4497bdf92f3SAxel Dörfler create_display_modes(const char* name, edid1_info* edid,
4507bdf92f3SAxel Dörfler 	const display_mode* initialModes, uint32 initialModeCount,
4517bdf92f3SAxel Dörfler 	const color_space *spaces, uint32 spacesCount,
4527bdf92f3SAxel Dörfler 	check_display_mode_hook hook, display_mode** _modes, uint32* _count)
4537bdf92f3SAxel Dörfler {
4547bdf92f3SAxel Dörfler 	if (_modes == NULL || _count == NULL)
4557bdf92f3SAxel Dörfler 		return B_BAD_VALUE;
4567bdf92f3SAxel Dörfler 
4577bdf92f3SAxel Dörfler 	// compile initial mode list from the different sources
4587bdf92f3SAxel Dörfler 
4597bdf92f3SAxel Dörfler 	ModeList modes;
4607bdf92f3SAxel Dörfler 	modes.AddModes(initialModes, initialModeCount);
4617bdf92f3SAxel Dörfler 
4627bdf92f3SAxel Dörfler 	if (edid != NULL)
4637bdf92f3SAxel Dörfler 		modes.AddModes(edid);
4647bdf92f3SAxel Dörfler 	else
4657bdf92f3SAxel Dörfler 		modes.AddModes(kBaseModeList, kNumBaseModes);
4667bdf92f3SAxel Dörfler 
4677bdf92f3SAxel Dörfler 	// filter out modes the caller doesn't like, and multiply modes for
4687bdf92f3SAxel Dörfler 	// every color space
4697bdf92f3SAxel Dörfler 
4707bdf92f3SAxel Dörfler 	if (spaces == NULL) {
4717bdf92f3SAxel Dörfler 		const color_space kDefaultSpaces[] = {B_RGB32_LITTLE, B_RGB16_LITTLE,
4727bdf92f3SAxel Dörfler 			B_RGB15_LITTLE, B_CMAP8};
4737bdf92f3SAxel Dörfler 		modes.CreateColorSpaces(kDefaultSpaces,
4747bdf92f3SAxel Dörfler 			sizeof(kDefaultSpaces) / sizeof(kDefaultSpaces[0]));
4757bdf92f3SAxel Dörfler 	} else
4767bdf92f3SAxel Dörfler 		modes.CreateColorSpaces(spaces, spacesCount);
4777bdf92f3SAxel Dörfler 
4787bdf92f3SAxel Dörfler 	modes.Filter(hook);
4797bdf92f3SAxel Dörfler 	modes.Clean();
4807bdf92f3SAxel Dörfler 
4817bdf92f3SAxel Dörfler 	// create area for output modes
4827bdf92f3SAxel Dörfler 
4837bdf92f3SAxel Dörfler 	size_t size = (sizeof(display_mode) * modes.Count() + B_PAGE_SIZE - 1)
4847bdf92f3SAxel Dörfler 		& ~(B_PAGE_SIZE - 1);
4857bdf92f3SAxel Dörfler 	display_mode *list;
4867bdf92f3SAxel Dörfler 	area_id area = create_area(name, (void **)&list, B_ANY_ADDRESS,
4877bdf92f3SAxel Dörfler 		size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
4887bdf92f3SAxel Dörfler 	if (area < B_OK)
4897bdf92f3SAxel Dörfler 		return area;
4907bdf92f3SAxel Dörfler 
4917bdf92f3SAxel Dörfler 	memcpy(list, modes.Modes(), sizeof(display_mode) * modes.Count());
4927bdf92f3SAxel Dörfler 	*_modes = list;
4937bdf92f3SAxel Dörfler 	*_count = modes.Count();
4947bdf92f3SAxel Dörfler 
4957bdf92f3SAxel Dörfler 	return area;
4967bdf92f3SAxel Dörfler }
4977bdf92f3SAxel Dörfler 
498