1 /*
2 * Copyright 2007-2014, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include <create_display_modes.h>
8
9 #include <math.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include <compute_display_timing.h>
14 #include <video_overlay.h>
15
16
17 #define POSITIVE_SYNC \
18 (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
19 #define MODE_FLAGS \
20 (B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS \
21 | B_SUPPORTS_OVERLAYS | B_SCROLL)
22
23 // TODO: move this list into the app_server
24 static const display_mode kBaseModeList[] = {
25 {{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) */
26
27 {{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) */
28
29 {{25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
30 {{31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
31 {{31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
32 {{36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
33
34 {{29580, 800, 816, 896, 992, 480, 481, 484, 497, B_POSITIVE_VSYNC}, B_CMAP8, 800, 480, 0, 0, MODE_FLAGS}, /* 800x480x60Hz */
35
36 {{38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
37 {{40000, 800, 840, 968, 1056, 600, 601, 605, 628, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
38 {{49500, 800, 816, 896, 1056, 600, 601, 604, 625, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
39 {{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) */
40 {{56250, 800, 832, 896, 1048, 600, 601, 604, 631, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */
41
42 {{65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */
43 {{75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */
44 {{78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
45 {{94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
46
47 {{81640, 1152, 1216, 1336, 1520, 864, 865, 868, 895, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* 1152x864x60Hz */
48 {{94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
49 {{108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
50 {{121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
51
52 {{74520, 1280, 1368, 1424, 1656, 720, 724, 730, 750, POSITIVE_SYNC}, B_CMAP8, 1280, 720, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X720) */
53
54 {{83460, 1280, 1344, 1480, 1680, 800, 801, 804, 828, B_POSITIVE_VSYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* WXGA (1280x800x60) */
55
56 {{108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
57 {{135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
58 {{157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
59
60 {{85500, 1360, 1424, 1536, 1792, 768, 771, 778, 795, POSITIVE_SYNC}, B_CMAP8, 1360, 768, 0, 0, MODE_FLAGS}, /* 1360x768 60Hz */
61
62 {{85765, 1366, 1494, 1624, 1798, 768, 770, 776, 795, POSITIVE_SYNC}, B_CMAP8, 1366, 768, 0, 0, MODE_FLAGS}, /* 1366x768 60Hz */
63
64 {{122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */
65 {{155800, 1400, 1464, 1784, 1912, 1050, 1052, 1064, 1090, POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1400X1050) */
66
67 {{106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */
68
69 {{120420, 1600, 1632, 2088, 2120, 900, 918, 927, 946, POSITIVE_SYNC}, B_CMAP8, 1600, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X900) */
70
71 {{162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */
72 {{175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */
73 {{189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */
74 {{202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */
75 {{216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
76 {{229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
77
78 {{147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1680X1050) */
79
80 //{{172000, 1920, 2040, 2248, 2576, 1080, 1081, 1084, 1118, POSITIVE_SYNC}, B_CMAP8, 1920, 1080, 0, 0, MODE_FLAGS}, /* 1920x1080 60Hz */
81 {{148500, 1920, 2008, 2052, 2200, 1080, 1084, 1089, 1125, POSITIVE_SYNC}, B_CMAP8, 1920, 1080, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1080) */
82 //{{160000, 1920, 2010, 2060, 2110, 1200, 1202, 1208, 1235, POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
83 {{193160, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
84 };
85 static const uint32 kNumBaseModes = sizeof(kBaseModeList) / sizeof(display_mode);
86
87
88 namespace BPrivate {
89
90 class ModeList {
91 public:
92 ModeList();
93 ~ModeList();
94
95 bool AddModes(edid1_info* info);
96 bool AddModes(const display_mode* modes,
97 uint32 count);
98
99 bool CreateColorSpaces(const color_space* spaces,
100 uint32 count);
101 void Filter(check_display_mode_hook hook);
102 void Clean();
103
Modes() const104 const display_mode* Modes() const { return fModes; }
Count() const105 uint32 Count() const { return fCount; }
106
107 private:
108 bool _MakeSpace(uint32 count);
109 bool _AddMode(const display_mode& mode);
110 void _RemoveModeAt(uint32 index);
111 void _AddBaseMode(uint16 width, uint16 height,
112 uint32 refresh);
113 display_mode* _FindMode(uint16 width, uint16 height) const;
114
115 private:
116 display_mode* fModes;
117 uint32 fCount;
118 uint32 fCapacity;
119 };
120
121 } // namespace BPrivate
122
123 using namespace BPrivate;
124
125
126 static float
get_refresh_rate(const display_mode & mode)127 get_refresh_rate(const display_mode& mode)
128 {
129 return float(mode.timing.pixel_clock * 1000)
130 / float(mode.timing.h_total * mode.timing.v_total);
131 }
132
133
134 static int
compare_mode(const void * _mode1,const void * _mode2)135 compare_mode(const void* _mode1, const void* _mode2)
136 {
137 display_mode *mode1 = (display_mode *)_mode1;
138 display_mode *mode2 = (display_mode *)_mode2;
139 uint16 width1, width2, height1, height2;
140
141 width1 = mode1->virtual_width;
142 height1 = mode1->virtual_height;
143 width2 = mode2->virtual_width;
144 height2 = mode2->virtual_height;
145
146 if (width1 != width2)
147 return width1 - width2;
148
149 if (height1 != height2)
150 return height1 - height2;
151
152 if (mode1->space != mode2->space)
153 return mode1->space - mode2->space;
154
155 return (int)(100 * (get_refresh_rate(*mode1) - get_refresh_rate(*mode2)));
156 }
157
158
159 // #pragma mark -
160
161
ModeList()162 ModeList::ModeList()
163 :
164 fModes(NULL),
165 fCount(0),
166 fCapacity(0)
167 {
168 }
169
170
~ModeList()171 ModeList::~ModeList()
172 {
173 free(fModes);
174 }
175
176
177 bool
AddModes(edid1_info * info)178 ModeList::AddModes(edid1_info* info)
179 {
180 if (info->established_timing.res_720x400x70)
181 _AddBaseMode(720, 400, 70);
182 if (info->established_timing.res_720x400x88)
183 _AddBaseMode(720, 400, 88);
184
185 if (info->established_timing.res_640x480x60)
186 _AddBaseMode(640, 480, 60);
187 if (info->established_timing.res_640x480x67)
188 _AddBaseMode(640, 480, 67);
189 if (info->established_timing.res_640x480x72)
190 _AddBaseMode(640, 480, 72);
191 if (info->established_timing.res_640x480x75)
192 _AddBaseMode(640, 480, 75);
193
194 if (info->established_timing.res_800x600x56)
195 _AddBaseMode(800, 600, 56);
196 if (info->established_timing.res_800x600x60)
197 _AddBaseMode(800, 600, 60);
198 if (info->established_timing.res_800x600x72)
199 _AddBaseMode(800, 600, 72);
200 if (info->established_timing.res_800x600x75)
201 _AddBaseMode(800, 600, 75);
202
203 #if 0
204 if (info->established_timing.res_832x624x75)
205 _AddBaseMode(832, 624, 75);
206
207 if (info->established_timing.res_1024x768x87i)
208 _AddBaseMode(1024, 768, 87);
209 #endif
210 if (info->established_timing.res_1024x768x60)
211 _AddBaseMode(1024, 768, 60);
212 if (info->established_timing.res_1024x768x70)
213 _AddBaseMode(1024, 768, 70);
214 if (info->established_timing.res_1024x768x75)
215 _AddBaseMode(1024, 768, 75);
216
217 if (info->established_timing.res_1152x870x75)
218 _AddBaseMode(1152, 870, 75);
219 if (info->established_timing.res_1280x1024x75)
220 _AddBaseMode(1280, 1024, 75);
221
222 for (uint32 i = 0; i < EDID1_NUM_STD_TIMING; ++i) {
223 if (info->std_timing[i].h_size <= 256)
224 continue;
225
226 _AddBaseMode(info->std_timing[i].h_size, info->std_timing[i].v_size,
227 info->std_timing[i].refresh);
228 }
229
230 bool hasRanges = false;
231 uint32 minHorizontalFrequency = 0;
232 uint32 maxHorizontalFrequency = 0;
233 uint32 minVerticalFrequency = 0;
234 uint32 maxVerticalFrequency = 0;
235 uint32 maxPixelClock = 0;
236
237 for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
238 if (info->detailed_monitor[i].monitor_desc_type
239 == EDID1_MONITOR_RANGES) {
240 edid1_monitor_range& range
241 = info->detailed_monitor[i].data.monitor_range;
242
243 hasRanges = true;
244 minHorizontalFrequency = range.min_h;
245 maxHorizontalFrequency = range.max_h;
246 minVerticalFrequency = range.min_v;
247 maxVerticalFrequency = range.max_v;
248 maxPixelClock = range.max_clock * 10000;
249 continue;
250 } else if (info->detailed_monitor[i].monitor_desc_type
251 != EDID1_IS_DETAILED_TIMING)
252 continue;
253
254 // TODO: handle flags correctly!
255 const edid1_detailed_timing& timing
256 = info->detailed_monitor[i].data.detailed_timing;
257 display_mode mode;
258
259 if (timing.pixel_clock <= 0/* || timing.sync != 3*/)
260 continue;
261
262 mode.timing.pixel_clock = timing.pixel_clock * 10;
263 mode.timing.h_display = timing.h_active;
264 mode.timing.h_sync_start = timing.h_active + timing.h_sync_off;
265 mode.timing.h_sync_end = mode.timing.h_sync_start + timing.h_sync_width;
266 mode.timing.h_total = timing.h_active + timing.h_blank;
267 mode.timing.v_display = timing.v_active;
268 mode.timing.v_sync_start = timing.v_active + timing.v_sync_off;
269 mode.timing.v_sync_end = mode.timing.v_sync_start + timing.v_sync_width;
270 mode.timing.v_total = timing.v_active + timing.v_blank;
271 mode.timing.flags = 0;
272 if (timing.sync == 3) {
273 if (timing.misc & 1)
274 mode.timing.flags |= B_POSITIVE_HSYNC;
275 if (timing.misc & 2)
276 mode.timing.flags |= B_POSITIVE_VSYNC;
277 }
278 if (timing.interlaced)
279 mode.timing.flags |= B_TIMING_INTERLACED;
280 mode.space = B_RGB32;
281 mode.virtual_width = timing.h_active;
282 mode.virtual_height = timing.v_active;
283 mode.h_display_start = 0;
284 mode.v_display_start = 0;
285 mode.flags = MODE_FLAGS;
286
287 _AddMode(mode);
288 }
289
290 // Add other modes from the base list that satisfy the display's
291 // requirements
292
293 for (uint32 i = 0; i < kNumBaseModes; i++) {
294 const display_mode& mode = kBaseModeList[i];
295
296 // Check if a mode with this resolution already exists
297
298 if (_FindMode(mode.timing.h_display, mode.timing.v_display) != NULL)
299 continue;
300
301 // Check monitor limits
302
303 if (hasRanges) {
304 uint32 verticalFrequency = 1000 * mode.timing.pixel_clock
305 / (mode.timing.h_total * mode.timing.v_total);
306 uint32 horizontalFrequency = mode.timing.h_total * verticalFrequency
307 / 1000;
308
309 if (minHorizontalFrequency > horizontalFrequency
310 || maxHorizontalFrequency < horizontalFrequency
311 || minVerticalFrequency > verticalFrequency
312 || maxVerticalFrequency < verticalFrequency
313 || maxPixelClock < mode.timing.pixel_clock)
314 continue;
315 }
316
317 _AddMode(mode);
318 }
319
320 return true;
321 }
322
323
324 bool
AddModes(const display_mode * modes,uint32 count)325 ModeList::AddModes(const display_mode* modes, uint32 count)
326 {
327 if (!_MakeSpace(count))
328 return false;
329
330 for (uint32 i = 0; i < count; i++) {
331 fModes[fCount++] = modes[i];
332 }
333
334 return true;
335 }
336
337
338 bool
CreateColorSpaces(const color_space * spaces,uint32 count)339 ModeList::CreateColorSpaces(const color_space* spaces, uint32 count)
340 {
341 uint32 baseModeCount = fCount;
342 size_t baseModesSize = baseModeCount * sizeof(display_mode);
343 display_mode* baseModes = (display_mode*)malloc(baseModesSize);
344 if (baseModes == NULL)
345 return false;
346
347 memcpy(baseModes, fModes, baseModesSize);
348
349 for (uint32 i = 0; i < count; i++) {
350 if (i > 0 && !AddModes(baseModes, baseModeCount)) {
351 free(baseModes);
352 return false;
353 }
354
355 for (uint32 j = 0; j < baseModeCount; j++) {
356 fModes[j + fCount - baseModeCount].space = spaces[i];
357 }
358 }
359
360 free(baseModes);
361 return true;
362 }
363
364
365 void
Filter(check_display_mode_hook hook)366 ModeList::Filter(check_display_mode_hook hook)
367 {
368 if (hook == NULL)
369 return;
370
371 for (uint32 i = fCount; i-- > 0;) {
372 if (!hook(&fModes[i]))
373 _RemoveModeAt(i);
374 }
375 }
376
377
378 void
Clean()379 ModeList::Clean()
380 {
381 // sort mode list
382 qsort(fModes, fCount, sizeof(display_mode), compare_mode);
383
384 // remove duplicates
385 for (uint32 i = fCount; i-- > 1;) {
386 if (compare_mode(&fModes[i], &fModes[i - 1]) == 0)
387 _RemoveModeAt(i);
388 }
389 }
390
391
392 void
_AddBaseMode(uint16 width,uint16 height,uint32 refresh)393 ModeList::_AddBaseMode(uint16 width, uint16 height, uint32 refresh)
394 {
395 // Check the manually tweaked list first
396
397 for (uint32 i = 0; i < kNumBaseModes; i++) {
398 const display_mode& mode = kBaseModeList[i];
399
400 // Add mode if width and height match, and the computed refresh rate of
401 // the mode is within 1.2 percent of the refresh rate specified by the
402 // caller. Note that refresh rates computed from mode parameters is
403 // not exact; thus, the tolerance of 1.2% was obtained by testing the
404 // various established modes that can be selected by the EDID info.
405
406 if (mode.timing.h_display == width && mode.timing.v_display == height
407 && fabs(get_refresh_rate(mode) - refresh) < refresh * 0.012) {
408 _AddMode(mode);
409 return;
410 }
411 }
412
413 // If that didn't have any entries, compute the entry
414 display_mode mode;
415 if (compute_display_timing(width, height, refresh, false, &mode.timing)
416 != B_OK)
417 return;
418
419 fill_display_mode(width, height, &mode);
420
421 _AddMode(mode);
422 }
423
424
425 display_mode*
_FindMode(uint16 width,uint16 height) const426 ModeList::_FindMode(uint16 width, uint16 height) const
427 {
428 for (uint32 i = 0; i < fCount; i++) {
429 const display_mode& mode = fModes[i];
430
431 if (mode.timing.h_display == width && mode.timing.v_display == height)
432 return &fModes[i];
433 }
434
435 return NULL;
436 }
437
438
439 bool
_MakeSpace(uint32 count)440 ModeList::_MakeSpace(uint32 count)
441 {
442 if (fCount + count <= fCapacity)
443 return true;
444
445 uint32 capacity = (fCapacity + count + 0xf) & ~0xf;
446 display_mode* modes = (display_mode*)realloc(fModes,
447 capacity * sizeof(display_mode));
448 if (modes == NULL)
449 return false;
450
451 fModes = modes;
452 fCapacity = capacity;
453 return true;
454 }
455
456
457 bool
_AddMode(const display_mode & mode)458 ModeList::_AddMode(const display_mode& mode)
459 {
460 // TODO: filter by monitor timing constraints!
461 // TODO: remove double entries
462 if (!_MakeSpace(1))
463 return false;
464
465 fModes[fCount++] = mode;
466 return true;
467 }
468
469
470 void
_RemoveModeAt(uint32 index)471 ModeList::_RemoveModeAt(uint32 index)
472 {
473 if (index < fCount - 1) {
474 memmove(&fModes[index], &fModes[index + 1],
475 (fCount - 1 - index) * sizeof(display_mode));
476 }
477
478 fCount--;
479 }
480
481
482 // #pragma mark -
483
484
485 extern "C" area_id
create_display_modes(const char * name,edid1_info * edid,const display_mode * initialModes,uint32 initialModeCount,const color_space * spaces,uint32 spacesCount,check_display_mode_hook hook,display_mode ** _modes,uint32 * _count)486 create_display_modes(const char* name, edid1_info* edid,
487 const display_mode* initialModes, uint32 initialModeCount,
488 const color_space *spaces, uint32 spacesCount,
489 check_display_mode_hook hook, display_mode** _modes, uint32* _count)
490 {
491 if (_modes == NULL || _count == NULL)
492 return B_BAD_VALUE;
493
494 // compile initial mode list from the different sources
495
496 ModeList modes;
497 if (initialModes != NULL)
498 modes.AddModes(initialModes, initialModeCount);
499
500 if (edid != NULL)
501 modes.AddModes(edid);
502 else
503 modes.AddModes(kBaseModeList, kNumBaseModes);
504
505 // filter out modes the caller doesn't like, and multiply modes for
506 // every color space
507
508 if (spaces == NULL) {
509 const color_space kDefaultSpaces[] = {B_RGB32_LITTLE, B_RGB16_LITTLE,
510 B_RGB15_LITTLE, B_CMAP8};
511 modes.CreateColorSpaces(kDefaultSpaces,
512 sizeof(kDefaultSpaces) / sizeof(kDefaultSpaces[0]));
513 } else
514 modes.CreateColorSpaces(spaces, spacesCount);
515
516 modes.Filter(hook);
517 modes.Clean();
518
519 // create area for output modes
520
521 size_t size = (sizeof(display_mode) * modes.Count() + B_PAGE_SIZE - 1)
522 & ~(B_PAGE_SIZE - 1);
523 display_mode *list;
524 area_id area = create_area(name, (void **)&list, B_ANY_ADDRESS,
525 size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA);
526 if (area < B_OK)
527 return area;
528
529 memcpy(list, modes.Modes(), sizeof(display_mode) * modes.Count());
530 *_modes = list;
531 *_count = modes.Count();
532
533 return area;
534 }
535
536
537 void
fill_display_mode(uint32 width,uint32 height,display_mode * mode)538 fill_display_mode(uint32 width, uint32 height, display_mode* mode)
539 {
540 mode->space = B_CMAP8;
541 mode->virtual_width = width;
542 mode->virtual_height = height;
543 mode->h_display_start = 0;
544 mode->v_display_start = 0;
545 mode->flags = MODE_FLAGS;
546 }
547