Applied patch by Gerald Zajac, revised by me to match our coding style:

* imported X.org's GTF function, and use it to compute modes that are not on
  the list.
* Also, accept a 6% variation for the selected mode refresh rate.
* Automatic whitespace cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31654 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-07-20 15:18:05 +00:00
parent 24a9c1bbba
commit 2c5fedae4b
4 changed files with 180 additions and 32 deletions

View File

@ -9,6 +9,7 @@ UsePrivateHeaders [ FDirName graphics radeon ] ;
Preference Screen :
AlertView.cpp
AlertWindow.cpp
gtf.cpp
MonitorView.cpp
multimon.cpp
RefreshSlider.cpp

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005-2008, Haiku.
* Copyright 2005-2009, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -8,6 +8,7 @@
#include "ScreenMode.h"
#include "gtf.h"
#include <InterfaceDefs.h>
@ -49,8 +50,8 @@ get_refresh_rate(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;
return rint(10 * float(mode.timing.pixel_clock * 1000)
/ float(mode.timing.h_total * mode.timing.v_total)) / 10.0;
}
@ -189,10 +190,10 @@ ScreenMode::Set(const screen_mode& mode, int32 workspace)
UpdateOriginalModes();
BScreen screen(fWindow);
if (workspace == ~0)
workspace = current_workspace();
// TODO: our app_server doesn't fully support workspaces, yet
SetSwapDisplays(&screen, mode.swap_displays);
SetUseLaptopPanel(&screen, mode.use_laptop_panel);
@ -211,15 +212,15 @@ ScreenMode::Get(screen_mode& mode, int32 workspace) const
{
display_mode displayMode;
BScreen screen(fWindow);
if (workspace == ~0)
workspace = current_workspace();
if (screen.GetMode(workspace, &displayMode) != B_OK)
return B_ERROR;
mode.SetTo(displayMode);
// TODO: our app_server doesn't fully support workspaces, yet
if (GetSwapDisplays(&screen, &mode.swap_displays) != B_OK)
mode.swap_displays = false;
@ -239,9 +240,9 @@ ScreenMode::GetOriginalMode(screen_mode& mode, int32 workspace) const
workspace = current_workspace();
else if(workspace > 31)
return B_BAD_INDEX;
mode = fOriginal[workspace];
return B_OK;
}
@ -275,7 +276,7 @@ ScreenMode::Revert()
if (result != B_OK)
break;
}
return result;
}
@ -350,10 +351,10 @@ ScreenMode::GetDisplayMode(const screen_mode& mode, display_mode& displayMode)
int32 bestIndex = -1;
float bestDiff = 999;
virtualWidth = mode.combine == kCombineHorizontally ?
mode.width * 2 : mode.width;
virtualHeight = mode.combine == kCombineVertically ?
mode.height * 2 : mode.height;
virtualWidth = mode.combine == kCombineHorizontally
? mode.width * 2 : mode.width;
virtualHeight = mode.combine == kCombineVertically
? mode.height * 2 : mode.height;
// try to find mode in list provided by driver
for (uint32 i = 0; i < fModeCount; i++) {
@ -362,18 +363,34 @@ ScreenMode::GetDisplayMode(const screen_mode& mode, display_mode& displayMode)
|| (color_space)fModeList[i].space != mode.space)
continue;
float refresh = get_refresh_rate(fModeList[i]);
if (refresh == mode.refresh) {
// we have luck - we can use this mode directly
// Accept the mode if the computed refresh rate of the mode is within
// 0.6 percent of the refresh rate specified by the caller. Note that
// refresh rates computed from mode parameters is not exact; especially
// some of the older modes such as 640x480, 800x600, and 1024x768.
// The tolerance of 0.6% was obtained by examining the various possible
// modes.
float refreshDiff = fabs(get_refresh_rate(fModeList[i]) - mode.refresh);
if (refreshDiff < 0.006 * mode.refresh) {
// Accept this mode.
displayMode = fModeList[i];
displayMode.h_display_start = 0;
displayMode.v_display_start = 0;
// Since the computed refresh rate of the selected mode might differ
// from selected refresh rate by a few tenths (e.g. 60.2 instead of
// 60.0), tweak the pixel clock so the the refresh rate of the mode
// matches the selected refresh rate.
displayMode.timing.pixel_clock = uint32(((displayMode.timing.h_total
* displayMode.timing.v_total * mode.refresh) / 1000.0) + 0.5);
return true;
}
float diff = fabs(refresh - mode.refresh);
if (diff < bestDiff) {
bestDiff = diff;
// Mode not acceptable.
if (refreshDiff < bestDiff) {
bestDiff = refreshDiff;
bestIndex = i;
}
}
@ -382,20 +399,16 @@ ScreenMode::GetDisplayMode(const screen_mode& mode, display_mode& displayMode)
if (bestIndex == -1)
return false;
// now, we are better of using GMT formula, but
// as we don't have it, we just tune the pixel
// clock of the best mode.
displayMode = fModeList[bestIndex];
displayMode.h_display_start = 0;
displayMode.v_display_start = 0;
// after some fiddling, it looks like this is the formula
// used by the original panel (notice that / 10 happens before
// multiplying with refresh rate - this leads to different
// rounding)
displayMode.timing.pixel_clock = ((uint32)displayMode.timing.h_total
* displayMode.timing.v_total / 10 * int32(mode.refresh * 10)) / 1000;
// For the mode selected by the width, height, and refresh rate, compute
// the video timing parameters for the mode by using the VESA Generalized
// Timing Formula (GTF).
ComputeGTFVideoTiming(displayMode.timing.h_display,
displayMode.timing.v_display, mode.refresh, displayMode.timing);
return true;
}

View File

@ -0,0 +1,116 @@
/*
* Copyright 2009 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Authors:
* Gerald Zajac
*/
/*! This file contains function(s) to generate video mode timings using the
GTF Timing Standard. The code in this file was adapted from the X.org
source file gtf.c which has the following copyright:
Copyright (c) 2001, Andy Ritger aritger@nvidia.com All rights reserved.
*/
#include "gtf.h"
#include <math.h>
#define CELL_GRAN 8.0 // assumed character cell granularity
#define MIN_PORCH 1 // minimum front porch
#define V_SYNC_RQD 3 // width of vsync in lines
#define H_SYNC_PERCENT 8.0 // width of hsync as % of total line
#define MIN_VSYNC_PLUS_BP 550.0 // min time of vsync + back porch (microsec)
// C' and M' are part of the Blanking Duty Cycle computation.
#define C_PRIME 30.0
#define M_PRIME 300.0
/*! Computes the timing values for the specified video mode using the
VESA Generalized Timing Formula (GTF).
\a width is the display width in pixels, \a lines is the display height
in lines, and \a refreshRate is the refresh rate in Hz. The computed
timing values are returned in \a modeTiming.
*/
void
ComputeGTFVideoTiming(int width, int lines, double refreshRate,
display_timing& modeTiming)
{
// In order to give correct results, the number of horizontal pixels
// requested is first processed to ensure that it is divisible by the
// character size, by rounding it to the nearest character cell boundary.
width = int((width / CELL_GRAN) * CELL_GRAN);
// Estimate the Horizontal period.
double horizontalPeriodEstimate = (((1.0 / refreshRate)
- (MIN_VSYNC_PLUS_BP / 1000000.0)) / (lines + MIN_PORCH) * 1000000.0);
// Compute the number of lines in V sync + back porch.
double verticalSyncAndBackPorch
= rint(MIN_VSYNC_PLUS_BP / horizontalPeriodEstimate);
// Compute the total number of lines in Vertical field period.
double totalLines = lines + verticalSyncAndBackPorch + MIN_PORCH;
// Estimate the Vertical field frequency.
double verticalFieldRateEstimate = 1.0 / horizontalPeriodEstimate
/ totalLines * 1000000.0;
// Compute the actual horizontal period.
double horizontalPeriod = horizontalPeriodEstimate
/ (refreshRate / verticalFieldRateEstimate);
// Compute the ideal blanking duty cycle from the blanking duty cycle
// equation.
double idealDutyCycle = C_PRIME - (M_PRIME * horizontalPeriod / 1000.0);
// Compute the number of pixels in the horizontal blanking time to the
// nearest double character cell.
double horizontalBlank = rint(width * idealDutyCycle
/ (100.0 - idealDutyCycle)
/ (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
// Compute the total number of pixels in a horizontal line.
double totalWidth = width + horizontalBlank;
// Compute the number of pixels in the horizontal sync period.
double horizontalSync
= rint(H_SYNC_PERCENT / 100.0 * totalWidth / CELL_GRAN) * CELL_GRAN;
// Compute the number of pixels in the horizontal front porch period.
double horizontalFrontPorch = (horizontalBlank / 2.0) - horizontalSync;
// Finally, return the results in a display_timing struct.
modeTiming.pixel_clock = uint32(totalWidth * 1000.0 / horizontalPeriod);
modeTiming.h_display = uint16(width);
modeTiming.h_sync_start = uint16(width + horizontalFrontPorch);
modeTiming.h_sync_end
= uint16(width + horizontalFrontPorch + horizontalSync);
modeTiming.h_total = uint16(totalWidth);
modeTiming.v_display = uint16(lines);
modeTiming.v_sync_start = uint16(lines + MIN_PORCH);
modeTiming.v_sync_end = uint16(lines + MIN_PORCH + V_SYNC_RQD);
modeTiming.v_total = uint16(totalLines);
modeTiming.flags = B_POSITIVE_VSYNC;
// GTF timings use -hSync and +vSync
}

View File

@ -0,0 +1,18 @@
/*
* Copyright 2009 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Authors:
* Gerald Zajac
*/
#ifndef GTF_H
#define GTF_H
#include <Accelerant.h>
void ComputeGTFVideoTiming(int width, int lines, double refreshRate,
display_timing& modeTiming);
#endif // GTF_H