mirror of
https://github.com/libretro/RetroArch
synced 2025-02-14 15:39:59 +00:00
629 lines
18 KiB
C++
629 lines
18 KiB
C++
|
/**************************************************************
|
||
|
|
||
|
custom_video_pstrip.cpp - PowerStrip interface routines
|
||
|
|
||
|
---------------------------------------------------------
|
||
|
|
||
|
Switchres Modeline generation engine for emulation
|
||
|
|
||
|
License GPL-2.0+
|
||
|
Copyright 2010-2021 Chris Kennedy, Antonio Giner,
|
||
|
Alexandre Wodarczyk, Gil Delescluse
|
||
|
|
||
|
**************************************************************/
|
||
|
|
||
|
/* http://forums.entechtaiwan.com/index.php?topic=5534.msg20902;topicseen#msg20902
|
||
|
|
||
|
UM_SETCUSTOMTIMING = WM_USER+200;
|
||
|
wparam = monitor number, zero-based
|
||
|
lparam = atom for string pointer
|
||
|
lresult = -1 for failure else current pixel clock (integer in Hz)
|
||
|
Note: pass full PowerStrip timing string*
|
||
|
|
||
|
UM_SETREFRESHRATE = WM_USER+201;
|
||
|
wparam = monitor number, zero-based
|
||
|
lparam = refresh rate (integer in Hz), or 0 for read-only
|
||
|
lresult = -1 for failure else current refresh rate (integer in Hz)
|
||
|
|
||
|
UM_SETPOLARITY = WM_USER+202;
|
||
|
wparam = monitor number, zero-based
|
||
|
lparam = polarity bits
|
||
|
lresult = -1 for failure else current polarity bits+1
|
||
|
|
||
|
UM_REMOTECONTROL = WM_USER+210;
|
||
|
wparam = 99
|
||
|
lparam =
|
||
|
0 to hide tray icon
|
||
|
1 to show tray icon,
|
||
|
2 to get build number
|
||
|
10 to show Performance profiles
|
||
|
11 to show Color profiles
|
||
|
12 to show Display profiles
|
||
|
13 to show Application profiles
|
||
|
14 to show Adapter information
|
||
|
15 to show Monitor information
|
||
|
16 to show Hotkey manager
|
||
|
17 to show Resource manager
|
||
|
18 to show Preferences
|
||
|
19 to show Online services
|
||
|
20 to show About screen
|
||
|
21 to show Tip-of-the-day
|
||
|
22 to show Setup wizard
|
||
|
23 to show Screen fonts
|
||
|
24 to show Advanced timing options
|
||
|
25 to show Custom resolutions
|
||
|
99 to close PS
|
||
|
lresult = -1 for failure else lparam+1 for success or build number (e.g., 335)
|
||
|
if lparam was 2
|
||
|
|
||
|
UM_SETGAMMARAMP = WM_USER+203;
|
||
|
wparam = monitor number, zero-based
|
||
|
lparam = atom for string pointer
|
||
|
lresult = -1 for failure, 1 for success
|
||
|
|
||
|
UM_CREATERESOLUTION = WM_USER+204;
|
||
|
wparam = monitor number, zero-based
|
||
|
lparam = atom for string pointer
|
||
|
lresult = -1 for failure, 1 for success
|
||
|
Note: pass full PowerStrip timing string*; reboot is usually necessary to see if
|
||
|
the resolution is accepted by the display driver
|
||
|
|
||
|
UM_GETTIMING = WM_USER+205;
|
||
|
wparam = monitor number, zero-based
|
||
|
lresult = -1 for failure else GlobalAtom number identifiying the timing string*
|
||
|
Note: be sure to call GlobalDeleteAtom after reading the string associated with
|
||
|
the atom
|
||
|
|
||
|
UM_GETSETCLOCKS = WM_USER+206;
|
||
|
wparam = monitor number, zero-based
|
||
|
lparam = atom for string pointer
|
||
|
lresult = -1 for failure else GlobalAtom number identifiying the performance
|
||
|
string**
|
||
|
Note: pass full PowerStrip performance string** to set the clocks, and ull to
|
||
|
get clocks; be sure to call GlobalDeleteAtom after reading the string associated
|
||
|
with the atom
|
||
|
|
||
|
NegativeHorizontalPolarity = 0x02;
|
||
|
NegativeVerticalPolarity = 0x04;
|
||
|
|
||
|
*Timing string parameter definition:
|
||
|
1 = horizontal active pixels
|
||
|
2 = horizontal front porch
|
||
|
3 = horizontal sync width
|
||
|
4 = horizontal back porch
|
||
|
5 = vertical active pixels
|
||
|
6 = vertical front porch
|
||
|
7 = vertical sync width
|
||
|
8 = vertical back porch
|
||
|
9 = pixel clock in hertz
|
||
|
10 = timing flags, where bit:
|
||
|
1 = negative horizontal porlarity
|
||
|
2 = negative vertical polarity
|
||
|
3 = interlaced
|
||
|
5 = composite sync
|
||
|
7 = sync-on-green
|
||
|
all other bits reserved
|
||
|
|
||
|
**Performance string parameter definition:
|
||
|
1 = memory clock in hertz
|
||
|
2 = engine clock in hertz
|
||
|
3 = reserved
|
||
|
4 = reserved
|
||
|
5 = reserved
|
||
|
6 = reserved
|
||
|
7 = reserved
|
||
|
8 = reserved
|
||
|
9 = 2D memory clock in hertz (if different from 3D)
|
||
|
10 = 2D engine clock in hertz (if different from 3D) */
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include "custom_video_pstrip.h"
|
||
|
#include "log.h"
|
||
|
|
||
|
//============================================================
|
||
|
// CONSTANTS
|
||
|
//============================================================
|
||
|
|
||
|
#define UM_SETCUSTOMTIMING (WM_USER+200)
|
||
|
#define UM_SETREFRESHRATE (WM_USER+201)
|
||
|
#define UM_SETPOLARITY (WM_USER+202)
|
||
|
#define UM_REMOTECONTROL (WM_USER+210)
|
||
|
#define UM_SETGAMMARAMP (WM_USER+203)
|
||
|
#define UM_CREATERESOLUTION (WM_USER+204)
|
||
|
#define UM_GETTIMING (WM_USER+205)
|
||
|
#define UM_GETSETCLOCKS (WM_USER+206)
|
||
|
#define UM_SETCUSTOMTIMINGFAST (WM_USER+211) // glitches vertical sync with PS 3.65 build 568
|
||
|
|
||
|
#define NegativeHorizontalPolarity 0x02
|
||
|
#define NegativeVerticalPolarity 0x04
|
||
|
#define Interlace 0x08
|
||
|
|
||
|
#define HideTrayIcon 0x00
|
||
|
#define ShowTrayIcon 0x01
|
||
|
#define ClosePowerStrip 0x63
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::pstrip_timing
|
||
|
//============================================================
|
||
|
|
||
|
pstrip_timing::pstrip_timing(char *device_name, custom_video_settings *vs)
|
||
|
{
|
||
|
m_vs = *vs;
|
||
|
strcpy (m_device_name, device_name);
|
||
|
strcpy (m_ps_timing, m_vs.custom_timing);
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::~pstrip_timing()
|
||
|
//============================================================
|
||
|
|
||
|
pstrip_timing::~pstrip_timing()
|
||
|
{
|
||
|
ps_reset();
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::init
|
||
|
//============================================================
|
||
|
|
||
|
bool pstrip_timing::init()
|
||
|
{
|
||
|
m_monitor_index = ps_monitor_index(m_device_name);
|
||
|
|
||
|
hPSWnd = FindWindowA("TPShidden", NULL);
|
||
|
|
||
|
if (hPSWnd)
|
||
|
{
|
||
|
log_verbose("PStrip: PowerStrip found!\n");
|
||
|
|
||
|
// Save current settings
|
||
|
ps_get_monitor_timing(&m_timing_backup);
|
||
|
|
||
|
// If we have a -ps_timing string defined, use it as user defined modeline
|
||
|
if (strcmp(m_ps_timing, "auto"))
|
||
|
{
|
||
|
MonitorTiming timing;
|
||
|
if (ps_read_timing_string(m_ps_timing, &timing))
|
||
|
{
|
||
|
ps_pstiming_to_modeline(&timing, &m_user_mode);
|
||
|
m_user_mode.type |= CUSTOM_VIDEO_TIMING_POWERSTRIP;
|
||
|
|
||
|
char modeline_txt[256]={'\x00'};
|
||
|
log_verbose("SwitchRes: ps_string: %s (%s)\n", m_ps_timing, modeline_print(&m_user_mode, modeline_txt, MS_PARAMS));
|
||
|
}
|
||
|
else
|
||
|
log_verbose("Switchres: ps_timing string with invalid format\n");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
log_verbose("PStrip: Could not get PowerStrip API interface\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::get_timing
|
||
|
//============================================================
|
||
|
|
||
|
bool pstrip_timing::get_timing(modeline *mode)
|
||
|
{
|
||
|
// If we have an user defined mode (ps_timing), lock any non matching mode
|
||
|
if (m_user_mode.hactive)
|
||
|
{
|
||
|
if (mode->width != m_user_mode.width || mode->height != m_user_mode.height)
|
||
|
{
|
||
|
mode->type |= MODE_DISABLED;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
modeline m_temp = {};
|
||
|
if (ps_get_modeline(&m_temp))
|
||
|
{
|
||
|
// We can only get the timings of the current desktop mode, so filter out anything different
|
||
|
if (m_temp.width == mode->width && m_temp.height == mode->height && m_temp.refresh == mode->refresh)
|
||
|
{
|
||
|
*mode = m_temp;
|
||
|
}
|
||
|
mode->type |= CUSTOM_VIDEO_TIMING_POWERSTRIP;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::set_timing
|
||
|
//============================================================
|
||
|
|
||
|
bool pstrip_timing::set_timing(modeline *mode)
|
||
|
{
|
||
|
// In case -ps_timing is provided, pass it as raw string
|
||
|
if (m_user_mode.hactive)
|
||
|
ps_set_monitor_timing_string(m_ps_timing);
|
||
|
|
||
|
// Otherwise pass it as modeline
|
||
|
else
|
||
|
ps_set_modeline(mode);
|
||
|
|
||
|
Sleep(100);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_reset
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_reset()
|
||
|
{
|
||
|
return ps_set_monitor_timing(&m_timing_backup);
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// ps_get_modeline
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_get_modeline(modeline *modeline)
|
||
|
{
|
||
|
MonitorTiming timing = {};
|
||
|
|
||
|
if (ps_get_monitor_timing(&timing))
|
||
|
{
|
||
|
ps_pstiming_to_modeline(&timing, modeline);
|
||
|
return 1;
|
||
|
}
|
||
|
else return 0;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_set_modeline
|
||
|
//============================================================
|
||
|
|
||
|
bool pstrip_timing::ps_set_modeline(modeline *modeline)
|
||
|
{
|
||
|
MonitorTiming timing = {};
|
||
|
|
||
|
if (!ps_modeline_to_pstiming(modeline, &timing))
|
||
|
return false;
|
||
|
|
||
|
timing.PixelClockInKiloHertz = ps_best_pclock(&timing, timing.PixelClockInKiloHertz);
|
||
|
|
||
|
if (ps_set_monitor_timing(&timing))
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_get_monitor_timing
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_get_monitor_timing(MonitorTiming *timing)
|
||
|
{
|
||
|
LRESULT lresult;
|
||
|
char in[256];
|
||
|
|
||
|
if (!hPSWnd) return 0;
|
||
|
|
||
|
lresult = SendMessage(hPSWnd, UM_GETTIMING, m_monitor_index, 0);
|
||
|
|
||
|
if (lresult == -1)
|
||
|
{
|
||
|
log_verbose("PStrip: Could not get PowerStrip timing string\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (!GlobalGetAtomNameA(lresult, in, sizeof(in)))
|
||
|
{
|
||
|
log_verbose("PStrip: GlobalGetAtomName failed\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
log_verbose("PStrip: ps_get_monitor_timing(%d): %s\n", m_monitor_index, in);
|
||
|
|
||
|
ps_read_timing_string(in, timing);
|
||
|
|
||
|
GlobalDeleteAtom(lresult); // delete atom created by PowerStrip
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_set_monitor_timing
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_set_monitor_timing(MonitorTiming *timing)
|
||
|
{
|
||
|
LRESULT lresult;
|
||
|
ATOM atom;
|
||
|
char out[256];
|
||
|
|
||
|
if (!hPSWnd) return 0;
|
||
|
|
||
|
ps_fill_timing_string(out, timing);
|
||
|
atom = GlobalAddAtomA(out);
|
||
|
|
||
|
if (atom)
|
||
|
{
|
||
|
lresult = SendMessage(hPSWnd, UM_SETCUSTOMTIMING, m_monitor_index, atom);
|
||
|
|
||
|
if (lresult < 0)
|
||
|
{
|
||
|
log_verbose("PStrip: SendMessage failed\n");
|
||
|
GlobalDeleteAtom(atom);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
log_verbose("PStrip: ps_set_monitor_timing(%d): %s\n", m_monitor_index, out);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else log_verbose("PStrip: ps_set_monitor_timing atom creation failed\n");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_set_monitor_timing_string
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_set_monitor_timing_string(char *in)
|
||
|
{
|
||
|
MonitorTiming timing = {};
|
||
|
|
||
|
ps_read_timing_string(in, &timing);
|
||
|
return ps_set_monitor_timing(&timing);
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_set_refresh
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_set_refresh(double vfreq)
|
||
|
{
|
||
|
MonitorTiming timing = {};
|
||
|
int hht, vvt, new_vvt;
|
||
|
int desired_pClock;
|
||
|
int best_pClock;
|
||
|
|
||
|
memcpy(&timing, &m_timing_backup, sizeof(MonitorTiming));
|
||
|
|
||
|
hht = timing.HorizontalActivePixels
|
||
|
+ timing.HorizontalFrontPorch
|
||
|
+ timing.HorizontalSyncWidth
|
||
|
+ timing.HorizontalBackPorch;
|
||
|
|
||
|
vvt = timing.VerticalActivePixels
|
||
|
+ timing.VerticalFrontPorch
|
||
|
+ timing.VerticalSyncWidth
|
||
|
+ timing.VerticalBackPorch;
|
||
|
|
||
|
desired_pClock = hht * vvt * vfreq / 1000;
|
||
|
best_pClock = ps_best_pclock(&timing, desired_pClock);
|
||
|
|
||
|
new_vvt = best_pClock * 1000 / (vfreq * hht);
|
||
|
|
||
|
timing.VerticalBackPorch += (new_vvt - vvt);
|
||
|
timing.PixelClockInKiloHertz = best_pClock;
|
||
|
|
||
|
ps_set_monitor_timing(&timing);
|
||
|
ps_get_monitor_timing(&timing);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_best_pclock
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_best_pclock(MonitorTiming *timing, int desired_pclock)
|
||
|
{
|
||
|
MonitorTiming timing_read = {};
|
||
|
int best_pclock = 0;
|
||
|
|
||
|
log_verbose("PStrip: ps_best_pclock(%d), getting stable dotclocks for %d...\n", m_monitor_index, desired_pclock);
|
||
|
|
||
|
for (int i = -50; i <= 50; i += 25)
|
||
|
{
|
||
|
timing->PixelClockInKiloHertz = desired_pclock + i;
|
||
|
|
||
|
ps_set_monitor_timing(timing);
|
||
|
ps_get_monitor_timing(&timing_read);
|
||
|
|
||
|
if (abs(timing_read.PixelClockInKiloHertz - desired_pclock) < abs(desired_pclock - best_pclock))
|
||
|
best_pclock = timing_read.PixelClockInKiloHertz;
|
||
|
}
|
||
|
|
||
|
log_verbose("PStrip: ps_best_pclock(%d), new dotclock: %d\n", m_monitor_index, best_pclock);
|
||
|
|
||
|
return best_pclock;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_create_resolution
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_create_resolution(modeline *modeline)
|
||
|
{
|
||
|
LRESULT lresult;
|
||
|
ATOM atom;
|
||
|
char out[256];
|
||
|
MonitorTiming timing = {};
|
||
|
|
||
|
if (!hPSWnd) return 0;
|
||
|
|
||
|
ps_modeline_to_pstiming(modeline, &timing);
|
||
|
|
||
|
ps_fill_timing_string(out, &timing);
|
||
|
atom = GlobalAddAtomA(out);
|
||
|
|
||
|
if (atom)
|
||
|
{
|
||
|
lresult = SendMessage(hPSWnd, UM_CREATERESOLUTION, m_monitor_index, atom);
|
||
|
|
||
|
if (lresult < 0)
|
||
|
{
|
||
|
log_verbose("PStrip: SendMessage failed\n");
|
||
|
GlobalDeleteAtom(atom);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
log_verbose("PStrip: ps_create_resolution(%d): %dx%d succeded \n",
|
||
|
modeline->width, modeline->height, m_monitor_index);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else log_verbose("PStrip: ps_create_resolution atom creation failed\n");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_read_timing_string
|
||
|
//============================================================
|
||
|
|
||
|
bool pstrip_timing::ps_read_timing_string(char *in, MonitorTiming *timing)
|
||
|
{
|
||
|
if (sscanf(in,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
|
||
|
&timing->HorizontalActivePixels,
|
||
|
&timing->HorizontalFrontPorch,
|
||
|
&timing->HorizontalSyncWidth,
|
||
|
&timing->HorizontalBackPorch,
|
||
|
&timing->VerticalActivePixels,
|
||
|
&timing->VerticalFrontPorch,
|
||
|
&timing->VerticalSyncWidth,
|
||
|
&timing->VerticalBackPorch,
|
||
|
&timing->PixelClockInKiloHertz,
|
||
|
&timing->TimingFlags.w) == 10) return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_fill_timing_string
|
||
|
//============================================================
|
||
|
|
||
|
void pstrip_timing::ps_fill_timing_string(char *out, MonitorTiming *timing)
|
||
|
{
|
||
|
sprintf(out, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
|
||
|
timing->HorizontalActivePixels,
|
||
|
timing->HorizontalFrontPorch,
|
||
|
timing->HorizontalSyncWidth,
|
||
|
timing->HorizontalBackPorch,
|
||
|
timing->VerticalActivePixels,
|
||
|
timing->VerticalFrontPorch,
|
||
|
timing->VerticalSyncWidth,
|
||
|
timing->VerticalBackPorch,
|
||
|
timing->PixelClockInKiloHertz,
|
||
|
timing->TimingFlags.w);
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_modeline_to_pstiming
|
||
|
//============================================================
|
||
|
|
||
|
bool pstrip_timing::ps_modeline_to_pstiming(modeline *modeline, MonitorTiming *timing)
|
||
|
{
|
||
|
if (modeline->pclock == 0 || modeline->hactive == 0 || modeline->vactive == 0)
|
||
|
{
|
||
|
log_verbose("ps_modeline_to_pstiming error: invalid modeline\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
timing->HorizontalActivePixels = modeline->hactive;
|
||
|
timing->HorizontalFrontPorch = modeline->hbegin - modeline->hactive;
|
||
|
timing->HorizontalSyncWidth = modeline->hend - modeline->hbegin;
|
||
|
timing->HorizontalBackPorch = modeline->htotal - modeline->hend;
|
||
|
|
||
|
timing->VerticalActivePixels = modeline->vactive;
|
||
|
timing->VerticalFrontPorch = modeline->vbegin - modeline->vactive;
|
||
|
timing->VerticalSyncWidth = modeline->vend - modeline->vbegin;
|
||
|
timing->VerticalBackPorch = modeline->vtotal - modeline->vend;
|
||
|
|
||
|
timing->PixelClockInKiloHertz = modeline->pclock / 1000;
|
||
|
|
||
|
if (modeline->hsync == 0)
|
||
|
timing->TimingFlags.w |= NegativeHorizontalPolarity;
|
||
|
if (modeline->vsync == 0)
|
||
|
timing->TimingFlags.w |= NegativeVerticalPolarity;
|
||
|
if (modeline->interlace)
|
||
|
timing->TimingFlags.w |= Interlace;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_pstiming_to_modeline
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_pstiming_to_modeline(MonitorTiming *timing, modeline *modeline)
|
||
|
{
|
||
|
modeline->hactive = timing->HorizontalActivePixels;
|
||
|
modeline->hbegin = modeline->hactive + timing->HorizontalFrontPorch;
|
||
|
modeline->hend = modeline->hbegin + timing->HorizontalSyncWidth;
|
||
|
modeline->htotal = modeline->hend + timing->HorizontalBackPorch;
|
||
|
|
||
|
modeline->vactive = timing->VerticalActivePixels;
|
||
|
modeline->vbegin = modeline->vactive + timing->VerticalFrontPorch;
|
||
|
modeline->vend = modeline->vbegin + timing->VerticalSyncWidth;
|
||
|
modeline->vtotal = modeline->vend + timing->VerticalBackPorch;
|
||
|
|
||
|
modeline->width = modeline->hactive;
|
||
|
modeline->height = modeline->vactive;
|
||
|
|
||
|
modeline->pclock = timing->PixelClockInKiloHertz * 1000;
|
||
|
|
||
|
if (!(timing->TimingFlags.w & NegativeHorizontalPolarity))
|
||
|
modeline->hsync = 1;
|
||
|
|
||
|
if (!(timing->TimingFlags.w & NegativeVerticalPolarity))
|
||
|
modeline->vsync = 1;
|
||
|
|
||
|
if ((timing->TimingFlags.w & Interlace))
|
||
|
modeline->interlace = 1;
|
||
|
|
||
|
modeline->hfreq = modeline->pclock / modeline->htotal;
|
||
|
modeline->vfreq = modeline->hfreq / modeline->vtotal * (modeline->interlace?2:1);
|
||
|
modeline->refresh = int(modeline->vfreq);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::ps_monitor_index
|
||
|
//============================================================
|
||
|
|
||
|
int pstrip_timing::ps_monitor_index (const char *display_name)
|
||
|
{
|
||
|
int monitor_index = 0;
|
||
|
char sub_index[2];
|
||
|
|
||
|
sub_index[0] = display_name[strlen(display_name)-1];
|
||
|
sub_index[1] = 0;
|
||
|
if (sscanf(sub_index,"%d", &monitor_index) == 1)
|
||
|
monitor_index --;
|
||
|
|
||
|
return monitor_index;
|
||
|
}
|
||
|
|
||
|
//============================================================
|
||
|
// pstrip_timing::update_mode
|
||
|
//============================================================
|
||
|
|
||
|
bool pstrip_timing::update_mode(modeline *mode)
|
||
|
{
|
||
|
if (!set_timing(mode))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
mode->type |= CUSTOM_VIDEO_TIMING_POWERSTRIP;
|
||
|
return true;
|
||
|
}
|