Started a create_display_modes() function that should be used by accelerants
to create their mode list. Once it's done, it should cover all possible cases, and allow the base mode list to reside in the app_server (under Haiku, at least), so that all drivers will benefit from an updated list. Right now, it might already work to a degree, but it's not yet tested. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22517 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2007, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _CREATE_DISPLAY_MODES_H
|
||||
#define _CREATE_DISPLAY_MODES_H
|
||||
|
||||
|
||||
#include <edid.h>
|
||||
|
||||
#include <Accelerant.h>
|
||||
|
||||
|
||||
typedef bool (*check_display_mode_hook)(display_mode *mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _CREATE_DISPLAY_MODES_H */
|
||||
@@ -7,6 +7,7 @@ UsePrivateHeaders [ FDirName graphics radeon ] ;
|
||||
UsePrivateHeaders [ FDirName graphics common ] ;
|
||||
|
||||
StaticLibrary libaccelerantscommon.a :
|
||||
create_display_modes.cpp
|
||||
ddc.c
|
||||
decode_edid.c
|
||||
dump_edid.c
|
||||
|
||||
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* Copyright 2007, Axel Dörfler, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <create_display_modes.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <video_overlay.h>
|
||||
|
||||
|
||||
#define POSITIVE_SYNC \
|
||||
(B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
|
||||
#define MODE_FLAGS \
|
||||
(B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS | B_SUPPORTS_OVERLAYS)
|
||||
|
||||
// TODO: move this list into the app_server
|
||||
static const display_mode kBaseModeList[] = {
|
||||
{{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) */
|
||||
{{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) */
|
||||
{{25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
|
||||
{{27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
|
||||
{{30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */
|
||||
{{31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
|
||||
{{31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
|
||||
{{36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
|
||||
{{38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
|
||||
{{40000, 800, 840, 968, 1056, 600, 601, 605, 628, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */
|
||||
{{49500, 800, 816, 896, 1056, 600, 601, 604, 625, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */
|
||||
{{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) */
|
||||
{{56250, 800, 832, 896, 1048, 600, 601, 604, 631, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */
|
||||
{{65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */
|
||||
{{75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */
|
||||
{{78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */
|
||||
{{94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */
|
||||
{{94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
|
||||
{{108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */
|
||||
{{121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
|
||||
{{108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */
|
||||
{{135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */
|
||||
{{157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */
|
||||
|
||||
{{106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */
|
||||
|
||||
{{162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */
|
||||
{{175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */
|
||||
{{189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */
|
||||
{{202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */
|
||||
{{216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
|
||||
{{229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */
|
||||
|
||||
{{147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1680X1050) */
|
||||
|
||||
{{154000, 1920, 1968, 2000, 2080, 1200, 1203, 1209, 1235, POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
|
||||
};
|
||||
static const uint32 kNumBaseModes = sizeof(kBaseModeList) / sizeof(display_mode);
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
class ModeList {
|
||||
public:
|
||||
ModeList();
|
||||
~ModeList();
|
||||
|
||||
bool AddModes(edid1_info* info);
|
||||
bool AddModes(const display_mode* modes, uint32 count);
|
||||
|
||||
bool CreateColorSpaces(const color_space* spaces, uint32 count);
|
||||
void Filter(check_display_mode_hook hook);
|
||||
void Clean();
|
||||
|
||||
const display_mode* Modes() const { return fModes; }
|
||||
uint32 Count() const { return fCount; }
|
||||
|
||||
private:
|
||||
bool _MakeSpace(uint32 count);
|
||||
bool _AddMode(const display_mode* mode);
|
||||
void _RemoveModeAt(uint32 index);
|
||||
void _AddBaseMode(uint16 width, uint16 height, uint32 refresh);
|
||||
|
||||
display_mode* fModes;
|
||||
uint32 fCount;
|
||||
uint32 fCapacity;
|
||||
};
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
using namespace BPrivate;
|
||||
|
||||
|
||||
static float
|
||||
get_refresh_rate(const display_mode& mode)
|
||||
{
|
||||
// we have to be catious as refresh rate cannot be controlled directly,
|
||||
// so it suffers under rounding errors and hardware restrictions
|
||||
return rint(10 * float(mode.timing.pixel_clock * 1000) /
|
||||
float(mode.timing.h_total * mode.timing.v_total)) / 10.0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
compare_mode(const void* _mode1, const void* _mode2)
|
||||
{
|
||||
display_mode *mode1 = (display_mode *)_mode1;
|
||||
display_mode *mode2 = (display_mode *)_mode2;
|
||||
uint16 width1, width2, height1, height2;
|
||||
|
||||
width1 = mode1->virtual_width;
|
||||
height1 = mode1->virtual_height;
|
||||
width2 = mode2->virtual_width;
|
||||
height2 = mode2->virtual_height;
|
||||
|
||||
if (width1 != width2)
|
||||
return width1 - width2;
|
||||
|
||||
if (height1 != height2)
|
||||
return height1 - height2;
|
||||
|
||||
if (mode1->space != mode2->space)
|
||||
return mode1->space - mode2->space;
|
||||
|
||||
return (int)(10 * get_refresh_rate(*mode1)
|
||||
- 10 * get_refresh_rate(*mode2));
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
ModeList::ModeList()
|
||||
:
|
||||
fModes(NULL),
|
||||
fCount(0),
|
||||
fCapacity(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ModeList::~ModeList()
|
||||
{
|
||||
free(fModes);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ModeList::AddModes(edid1_info* info)
|
||||
{
|
||||
if (info->established_timing.res_720x400x70)
|
||||
_AddBaseMode(720, 400, 70);
|
||||
if (info->established_timing.res_720x400x88)
|
||||
_AddBaseMode(720, 400, 88);
|
||||
|
||||
if (info->established_timing.res_640x480x60)
|
||||
_AddBaseMode(640, 480, 60);
|
||||
if (info->established_timing.res_640x480x67)
|
||||
_AddBaseMode(640, 480, 67);
|
||||
if (info->established_timing.res_640x480x72)
|
||||
_AddBaseMode(640, 480, 72);
|
||||
if (info->established_timing.res_640x480x75)
|
||||
_AddBaseMode(640, 480, 75);
|
||||
|
||||
if (info->established_timing.res_800x600x56)
|
||||
_AddBaseMode(800, 600, 56);
|
||||
if (info->established_timing.res_800x600x60)
|
||||
_AddBaseMode(800, 600, 60);
|
||||
if (info->established_timing.res_800x600x72)
|
||||
_AddBaseMode(800, 600, 72);
|
||||
if (info->established_timing.res_800x600x75)
|
||||
_AddBaseMode(800, 600, 75);
|
||||
|
||||
#if 0
|
||||
if (info->established_timing.res_832x624x75)
|
||||
_AddBaseMode(832, 624, 75);
|
||||
|
||||
if (info->established_timing.res_1024x768x87i)
|
||||
_AddBaseMode(1024, 768, 87);
|
||||
#endif
|
||||
if (info->established_timing.res_1024x768x60)
|
||||
_AddBaseMode(1024, 768, 60);
|
||||
if (info->established_timing.res_1024x768x70)
|
||||
_AddBaseMode(1024, 768, 70);
|
||||
if (info->established_timing.res_1024x768x75)
|
||||
_AddBaseMode(1024, 768, 75);
|
||||
|
||||
if (info->established_timing.res_1152x870x75)
|
||||
_AddBaseMode(1152, 870, 75);
|
||||
if (info->established_timing.res_1280x1024x75)
|
||||
_AddBaseMode(1280, 1024, 75);
|
||||
|
||||
for (uint32 i = 0; i < EDID1_NUM_STD_TIMING; ++i) {
|
||||
if (info->std_timing[i].h_size <= 256)
|
||||
continue;
|
||||
|
||||
_AddBaseMode(info->std_timing[i].h_size, info->std_timing[i].v_size,
|
||||
info->std_timing[i].refresh);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
|
||||
if (info->detailed_monitor[i].monitor_desc_type != EDID1_IS_DETAILED_TIMING)
|
||||
continue;
|
||||
|
||||
const edid1_detailed_timing& timing = info->detailed_monitor[i].data.detailed_timing;
|
||||
display_mode mode;
|
||||
mode.timing.pixel_clock = timing.pixel_clock * 10;
|
||||
mode.timing.h_display = timing.h_active;
|
||||
mode.timing.h_sync_start = timing.h_blank;
|
||||
mode.timing.h_sync_end = timing.h_sync_off;
|
||||
mode.timing.h_total = timing.h_sync_width;
|
||||
mode.timing.v_display = timing.v_active;
|
||||
mode.timing.v_sync_start = timing.v_blank;
|
||||
mode.timing.v_sync_end = timing.v_sync_off;
|
||||
mode.timing.v_total = timing.v_sync_width;
|
||||
mode.timing.flags = POSITIVE_SYNC;
|
||||
mode.space = B_RGB32;
|
||||
mode.virtual_width = timing.h_active;
|
||||
mode.virtual_height = timing.v_active;
|
||||
mode.h_display_start = 0;
|
||||
mode.v_display_start = 0;
|
||||
mode.flags = MODE_FLAGS;
|
||||
}
|
||||
|
||||
// TODO: add other modes from the base list that satisfy the display's
|
||||
// requirements!
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ModeList::AddModes(const display_mode* modes, uint32 count)
|
||||
{
|
||||
if (!_MakeSpace(count))
|
||||
return false;
|
||||
|
||||
for (uint32 i = 0; i < count; i++) {
|
||||
fModes[fCount++] = modes[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ModeList::CreateColorSpaces(const color_space* spaces, uint32 count)
|
||||
{
|
||||
uint32 modeCount = fCount;
|
||||
|
||||
for (uint32 i = 0; i < count; i++) {
|
||||
if (i > 0 && !AddModes(fModes, modeCount))
|
||||
return false;
|
||||
|
||||
for (uint32 j = 0; j < modeCount; j++) {
|
||||
fModes[j + fCount - modeCount].space = spaces[i];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ModeList::Filter(check_display_mode_hook hook)
|
||||
{
|
||||
if (hook == NULL)
|
||||
return;
|
||||
|
||||
for (uint32 i = fCount; i-- > 0;) {
|
||||
if (!hook(&fModes[i]))
|
||||
_RemoveModeAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ModeList::Clean()
|
||||
{
|
||||
// sort mode list
|
||||
qsort(fModes, fCount, sizeof(display_mode), compare_mode);
|
||||
|
||||
// remove duplicates
|
||||
for (uint32 i = fCount; i-- > 1;) {
|
||||
if (compare_mode(&fModes[i], &fModes[i - 1]) == 0)
|
||||
_RemoveModeAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ModeList::_AddBaseMode(uint16 width, uint16 height, uint32 refresh)
|
||||
{
|
||||
for (uint32 i = 0; i < kNumBaseModes; i++) {
|
||||
const display_mode& mode = kBaseModeList[i];
|
||||
|
||||
if (mode.timing.h_display == width && mode.timing.v_display == height
|
||||
&& get_refresh_rate(mode) == refresh) {
|
||||
_AddMode(&mode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ModeList::_MakeSpace(uint32 count)
|
||||
{
|
||||
if (fCount + count <= fCapacity)
|
||||
return true;
|
||||
|
||||
uint32 capacity = (fCapacity + count + 0xf) & ~0xf;
|
||||
display_mode* modes = (display_mode*)realloc(fModes,
|
||||
capacity * sizeof(display_mode));
|
||||
if (modes == NULL)
|
||||
return false;
|
||||
|
||||
fModes = modes;
|
||||
fCapacity = capacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ModeList::_AddMode(const display_mode* mode)
|
||||
{
|
||||
if (!_MakeSpace(1))
|
||||
return false;
|
||||
|
||||
fModes[fCount++] = *mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ModeList::_RemoveModeAt(uint32 index)
|
||||
{
|
||||
if (index < fCount - 1) {
|
||||
memmove(&fModes[index], &fModes[index + 1],
|
||||
(fCount - 1 - index) * sizeof(display_mode));
|
||||
}
|
||||
|
||||
fCount--;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (_modes == NULL || _count == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// compile initial mode list from the different sources
|
||||
|
||||
ModeList modes;
|
||||
modes.AddModes(initialModes, initialModeCount);
|
||||
|
||||
if (edid != NULL)
|
||||
modes.AddModes(edid);
|
||||
else
|
||||
modes.AddModes(kBaseModeList, kNumBaseModes);
|
||||
|
||||
// filter out modes the caller doesn't like, and multiply modes for
|
||||
// every color space
|
||||
|
||||
if (spaces == NULL) {
|
||||
const color_space kDefaultSpaces[] = {B_RGB32_LITTLE, B_RGB16_LITTLE,
|
||||
B_RGB15_LITTLE, B_CMAP8};
|
||||
modes.CreateColorSpaces(kDefaultSpaces,
|
||||
sizeof(kDefaultSpaces) / sizeof(kDefaultSpaces[0]));
|
||||
} else
|
||||
modes.CreateColorSpaces(spaces, spacesCount);
|
||||
|
||||
modes.Filter(hook);
|
||||
modes.Clean();
|
||||
|
||||
// create area for output modes
|
||||
|
||||
size_t size = (sizeof(display_mode) * modes.Count() + B_PAGE_SIZE - 1)
|
||||
& ~(B_PAGE_SIZE - 1);
|
||||
display_mode *list;
|
||||
area_id area = create_area(name, (void **)&list, B_ANY_ADDRESS,
|
||||
size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||
if (area < B_OK)
|
||||
return area;
|
||||
|
||||
memcpy(list, modes.Modes(), sizeof(display_mode) * modes.Count());
|
||||
*_modes = list;
|
||||
*_count = modes.Count();
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user