1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-08 12:15:49 +00:00
RetroArch/deps/switchres/custom_video_pstrip.cpp
Ben 4b2f27eff8 Ver 0.9.2 SR2 (Switchres API) Implimantation
Fixed SR close match refresh bug.
Added menu high resolution option.
Fixed desktop restore bug cuusing endless resolution change requests.
Fixed file conflicts
Added destop restore resolution back in for manu only.
Pulled Switchres fixes.
Added better PI rsolution support.

Ver 0.7 SR2 (Switchres API) Implimantation

Removed HH experimetal check. This is better done via teh switchres.ini at present.
Fixed refresh rate bug. Now new resolution and refesh is added correctly.
Removed SR deinit from menu restore. Meanu now stays at last content resolution.

Ver 0.6.2 SR2 (Switchres API) Implimantation

Fixed super resolution bug casuing abnormal video size and aspect ratio
Fixed logging issue casuing seg falts on RA exit

Ver 0.6 SR2 (Switchres API) Implimantation

Ver 0.2 SR2 (Switchres API) Implimantation

Added forced super resolutions.
Added Multi-monitor/monitor selection support.
Added desktop resolution restore when switching back to menu only.
Added new menu items for 31KHz standard and 120hz monitor profiles.
Added new menu item INI. load monitor profile from switchrss.ini.
Fixed winraw driver. Coordinates new refreshed after a resolution change.
Fixed Menu aspect ratio in super resolutions.
Removed static glabals. These have been added to videocrt_switch struct.

Ver 0.1 SR2 (Switchres API) Implimantation

Removed old CRTSwitchRes method. Added new SR2 API implimantaion.
Resolution swithcing is now done by switchres libs. Both Linux and Windows
working with native and super resolutions. Working multi-monitor support
with monitor index selection. Working 31KHz support with standard and 120Hxz
modes. The monitor index selection is still done via the RA UI. Only choose
native and 15KHz form the CRT options in the RA UI as all options are now set
in the switchres.ini. All other CRT optoins in the RA UI currently do nothing.

Added SR wrapper to fix compile issues. Added back RPi functionality

Fixed windows resize/scaling issues on resolution change

Thanks @Calamity no more need for crt_switch_driver_refresh()

Fix broken case after prevous commit

Monitor preset options 15/31KHz now active. Added new meu option.

Moitor persets can now be choosen fom the RA UI. 15KHz and 31KHz will set
arcade_15 and aracde_31 respectivly. New option INI, if this is chosen your
monitor preset will be selected from your switchres.ini file.

Added 3KHhz, 120Hz. for old RA users. Renamed 31KHz to 31 KHz,  Standard

Fixed winraw input coordinates after switching resolution.

Code cleanup

Fixed menu aspect ratio issue

Added menu resolution restore after closing content

Fixed aspect ratio after menu resolution restore.

code clean up

Fxed menu Resulition Restore Aspect Ratio. When SR uses non integer scalled resolution.

super width bug with restoring menu resolution fix

added super resolution check after setting desktop resolutoion variables

when menu active only sr_deinit() used to restore desktop mode.

Fixed menu sr_deinit bug. now setting sr_active false

Removed static globals, added them to video_switch struct

Fixex compile bug due to comment //

Fixed compile issues doe to c++ comments in teh switchres_wrapper.h

Temporarily removed SR2 logging to fix compile isses for c90

added logging back in. Removed support for winnt and osx

Added define for C89. Disabled SR if defined C89

Removed all RA compile fixes fro C89 C90 etc. Swithing now working again.

Put Switchres behind HAVE_SR2. HAVE_SR2=no by default. --enable-sr2

Ver 0.5 SR2 Implimentation.

Ver 0.4 SR2 Implimantation.

Bake SR inside RA

Removed temporary log files

Disable switchres when C89/C99 builds.

Removed C89 and C90 checks for SR

Fixed switchres_wrapper.h location

Ver 0.3 SR2 Implimenation

Dissable logging for C89 __STDC__

Fix For RPi

fixed missing EOL

fixed RPi function definition

added vidrocrt_switch stuct to RPI funcion

fixed xoffset for RPi

Removed old RPi function call

SR disabled for videocore until VC4 switching ported

Reverted back to state 5c8a56c Bake SR inside RA

Use native win32 api for threads.

Fix static lib linking
LIBERROR would be defined twice otherwise + improper function names prefixed by __imp_

Added lidstc++ to makefile.common for switchres

Fixed RPi switching. Disabled Switchres for videocore unill it is ported.

removed RAA.log. Should not exist

Added check for when SR fails to set mode with an aspect ratio fix.

added video driver re init for RPi

GB, GBA and GBC core check, adjusted reseolutions and scale. Please turn on integer scalling in the RA UI

Added logas back in. Checking STDC verstion >= C11

Fixed c89 for loop declaration.

Code clean up. Added new functions

Fix resolution switching bug introduces with HH code clean up.

Fixed menu restore bug on closw content after code clean up

Moved SR logging to relevant RA logs

Update makefile. Checks for X11 and xrandr

fixed makefile

Use native win32 api for threads.

Fix static lib linking
LIBERROR would be defined twice otherwise + improper function names prefixed by __imp_

Update switchres_wrapper.* header comments

Update year copyright

DRMKMS: build only if libdrm has the required version

XRANDR: build only if xrandr is available

Simplified maklefile

Fixed RPI compile error with unsued functions.

As before

Disable Griffin. No switching support available. Never has been

Removed log file 1

Added Win32 static define

Added SR source

Removed Videocore check on destroy SR

Moved SR deinit to trigger earlier on RA exit.

Fixed compile error after upstream rebase

Fixed aspect ration bug cused by super resolutions. Temporarily disbabled SR logging

Re inabled runtim eSR loggind. Disableed all RARCH logging on retro_deinit_drivers

Removed srdeinit from menu restore. Menu stays in current reolution until a fix can be found

Fixed refresh rate changes when no reolution change is detected.

Forgot to add teh resolution cahge in with the refresh change oops

Fixed endless no detection log.

Removed HH check. This can been better adjusted using the switchres.ini

fixed compile issue

Added better PI crt switching and fixed typo

Pulled Swicthres fixes. Updated desktop restore resolution.

removed unused makefile

Lockec menu refresh to 60hz

fixed missing new line

Fixed file conflicts

Forced 640x480@60 for menu

Added high resolution menu option

Removed item logg checker

Fixed typos

Removed unused functions

Fixed SR close match refesh bug.

Fixed typo
2021-06-04 08:32:56 -07:00

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;
}