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 104 const display_mode* Modes() const { return fModes; } 105 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 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 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 162 ModeList::ModeList() 163 : 164 fModes(NULL), 165 fCount(0), 166 fCapacity(0) 167 { 168 } 169 170 171 ModeList::~ModeList() 172 { 173 free(fModes); 174 } 175 176 177 bool 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 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 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 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 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 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* 426 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 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 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 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 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 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