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:
Axel Dörfler
2007-10-12 15:59:50 +00:00
parent 13a81299f1
commit 7bdf92f3f7
3 changed files with 431 additions and 0 deletions
@@ -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 */
+1
View File
@@ -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;
}