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:
parent
24a9c1bbba
commit
2c5fedae4b
@ -9,6 +9,7 @@ UsePrivateHeaders [ FDirName graphics radeon ] ;
|
||||
Preference Screen :
|
||||
AlertView.cpp
|
||||
AlertWindow.cpp
|
||||
gtf.cpp
|
||||
MonitorView.cpp
|
||||
multimon.cpp
|
||||
RefreshSlider.cpp
|
||||
|
@ -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;
|
||||
}
|
||||
|
116
src/preferences/screen/gtf.cpp
Normal file
116
src/preferences/screen/gtf.cpp
Normal 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
|
||||
}
|
18
src/preferences/screen/gtf.h
Normal file
18
src/preferences/screen/gtf.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user