diff options
Diffstat (limited to 'testing/mame/groovymame.patch')
-rw-r--r-- | testing/mame/groovymame.patch | 7810 |
1 files changed, 0 insertions, 7810 deletions
diff --git a/testing/mame/groovymame.patch b/testing/mame/groovymame.patch deleted file mode 100644 index e16837b107d..00000000000 --- a/testing/mame/groovymame.patch +++ /dev/null @@ -1,7810 +0,0 @@ -diff --git a/scripts/src/emu.lua b/scripts/src/emu.lua -index b7736fb4c27..2be746a8b5f 100644 ---- a/scripts/src/emu.lua -+++ b/scripts/src/emu.lua -@@ -259,6 +259,11 @@ files { - MAME_DIR .. "src/emu/video/rgbsse.h", - MAME_DIR .. "src/emu/video/rgbvmx.cpp", - MAME_DIR .. "src/emu/video/rgbvmx.h", -+ MAME_DIR .. "src/emu/switchres/modeline.cpp", -+ MAME_DIR .. "src/emu/switchres/monitor.cpp", -+ MAME_DIR .. "src/emu/switchres/util.cpp", -+ MAME_DIR .. "src/emu/switchres/switchres.cpp", -+ MAME_DIR .. "src/emu/switchres/switchres.h", - } - - pchsource(MAME_DIR .. "src/emu/main.cpp") -diff --git a/scripts/src/osd/sdl.lua b/scripts/src/osd/sdl.lua -index 10aa9940c52..0a87568a2aa 100644 ---- a/scripts/src/osd/sdl.lua -+++ b/scripts/src/osd/sdl.lua -@@ -47,12 +47,19 @@ function maintargetosdoptions(_target,_subtarget) - if BASE_TARGETOS=="unix" and _OPTIONS["targetos"]~="macosx" and _OPTIONS["targetos"]~="android" and _OPTIONS["targetos"]~="asmjs" then - links { - "SDL2_ttf", -+ "Xrandr", - } - local str = backtick(pkgconfigcmd() .. " --libs fontconfig") - addlibfromstring(str) - addoptionsfromstring(str) - end - -+ if BASE_TARGETOS=="unix" and _OPTIONS["targetos"]=="linux" then -+ local str = backtick("pkg-config --libs libdrm") -+ addlibfromstring(str) -+ addoptionsfromstring(str) -+ end -+ - if _OPTIONS["targetos"]=="windows" then - if _OPTIONS["with-bundled-sdl2"]~=nil then - configuration { "mingw*"} -@@ -435,6 +442,7 @@ project ("osd_" .. _OPTIONS["osd"]) - MAME_DIR .. "src/osd/sdl/video.cpp", - MAME_DIR .. "src/osd/sdl/window.cpp", - MAME_DIR .. "src/osd/sdl/window.h", -+ MAME_DIR .. "src/osd/sdl/switchres_sdl.cpp", - MAME_DIR .. "src/osd/modules/osdwindow.cpp", - MAME_DIR .. "src/osd/modules/osdwindow.h", - MAME_DIR .. "src/osd/modules/render/drawsdl.cpp", -diff --git a/scripts/src/osd/sdl_cfg.lua b/scripts/src/osd/sdl_cfg.lua -index e942e50fdde..c9b37d07c70 100644 ---- a/scripts/src/osd/sdl_cfg.lua -+++ b/scripts/src/osd/sdl_cfg.lua -@@ -134,6 +134,9 @@ if _OPTIONS["targetos"]=="windows" then - configuration { } - - elseif _OPTIONS["targetos"]=="linux" then -+ buildoptions { -+ backtick("pkg-config --cflags libdrm"), -+ } - if _OPTIONS["QT_HOME"]~=nil then - buildoptions { - "-I" .. backtick(_OPTIONS["QT_HOME"] .. "/bin/qmake -query QT_INSTALL_HEADERS"), -diff --git a/scripts/src/osd/windows.lua b/scripts/src/osd/windows.lua -index 963980b22ca..91344edea4a 100644 ---- a/scripts/src/osd/windows.lua -+++ b/scripts/src/osd/windows.lua -@@ -45,6 +45,7 @@ function maintargetosdoptions(_target,_subtarget) - "psapi", - "ole32", - "shlwapi", -+ "dwmapi", - } - end - -@@ -170,6 +171,16 @@ project ("osd_" .. _OPTIONS["osd"]) - MAME_DIR .. "src/osd/windows/winmenu.cpp", - MAME_DIR .. "src/osd/windows/winmain.cpp", - MAME_DIR .. "src/osd/windows/winmain.h", -+ MAME_DIR .. "src/osd/windows/switchres_windows.cpp", -+ MAME_DIR .. "src/osd/windows/custom_video.cpp", -+ MAME_DIR .. "src/osd/windows/custom_video.h", -+ MAME_DIR .. "src/osd/windows/custom_video_ati.cpp", -+ MAME_DIR .. "src/osd/windows/custom_video_ati.h", -+ MAME_DIR .. "src/osd/windows/custom_video_adl.cpp", -+ MAME_DIR .. "src/osd/windows/custom_video_adl.h", -+ MAME_DIR .. "src/osd/windows/custom_video_ati_family.cpp", -+ MAME_DIR .. "src/osd/windows/custom_video_pstrip.cpp", -+ MAME_DIR .. "src/osd/windows/custom_video_pstrip.h", - MAME_DIR .. "src/osd/osdepend.h", - MAME_DIR .. "src/osd/modules/debugger/win/consolewininfo.cpp", - MAME_DIR .. "src/osd/modules/debugger/win/consolewininfo.h", -diff --git a/src/emu/drivenum.cpp b/src/emu/drivenum.cpp -index 5a29dcabd9a..34f5a912cb0 100644 ---- a/src/emu/drivenum.cpp -+++ b/src/emu/drivenum.cpp -@@ -238,7 +238,7 @@ void driver_enumerator::find_approximate_matches(std::string const &string, std: - if (m_included[index]) - templist[arrayindex++] = index; - assert(arrayindex == m_filtered_count); -- -+/* - // shuffle - for (int shufnum = 0; shufnum < (4 * s_driver_count); shufnum++) - { -@@ -248,7 +248,7 @@ void driver_enumerator::find_approximate_matches(std::string const &string, std: - templist[item1] = templist[item2]; - templist[item2] = temp; - } -- -+*/ - // copy out the first few entries - for (int matchnum = 0; matchnum < count; matchnum++) - results[matchnum] = templist[matchnum % m_filtered_count]; -diff --git a/src/emu/drivers/empty.cpp b/src/emu/drivers/empty.cpp -index faa17f60158..47744719cb9 100644 ---- a/src/emu/drivers/empty.cpp -+++ b/src/emu/drivers/empty.cpp -@@ -52,7 +52,7 @@ void empty_state::___empty(machine_config &config) - screen.set_screen_update(FUNC(empty_state::screen_update)); - screen.set_size(640, 480); - screen.set_visarea(0, 639, 0, 479); -- screen.set_refresh_hz(30); -+ screen.set_refresh_hz(61); - } - - -diff --git a/src/emu/emu.h b/src/emu/emu.h -index 35a5d6a3f60..ee75aa354ba 100644 ---- a/src/emu/emu.h -+++ b/src/emu/emu.h -@@ -84,6 +84,9 @@ - #include "gamedrv.h" - #include "parameters.h" - -+// Switchres -+#include "switchres/switchres.h" -+ - // the running machine - #include "main.h" - #include "machine.h" -@@ -108,4 +111,7 @@ - // member templates that don't like incomplete types - #include "device.ipp" - -+// Switchres prototypes -+#include "switchres/switchres_proto.h" -+ - #endif // __EMU_H__ -diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp -index a48a4f80811..5a60c9338ea 100644 ---- a/src/emu/emuopts.cpp -+++ b/src/emu/emuopts.cpp -@@ -85,10 +85,12 @@ const options_entry emu_options::s_option_entries[] = - { OPTION_FRAMESKIP ";fs(0-10)", "0", OPTION_INTEGER, "set frameskip to fixed value, 0-10 (autoframeskip must be disabled)" }, - { OPTION_SECONDS_TO_RUN ";str", "0", OPTION_INTEGER, "number of emulated seconds to run before automatically exiting" }, - { OPTION_THROTTLE, "1", OPTION_BOOLEAN, "throttle emulation to keep system running in sync with real time" }, -+ { OPTION_SYNCREFRESH ";srf", "0", OPTION_BOOLEAN, "enable using the start of VBLANK for throttling instead of the game time" }, -+ { OPTION_AUTOSYNC ";as", "1", OPTION_BOOLEAN, "automatically enable syncrefresh if refresh difference is below syncrefresh_tolerance" }, - { OPTION_SLEEP, "1", OPTION_BOOLEAN, "enable sleeping, which gives time back to other applications when idle" }, - { OPTION_SPEED "(0.01-100)", "1.0", OPTION_FLOAT, "controls the speed of gameplay, relative to realtime; smaller numbers are slower" }, - { OPTION_REFRESHSPEED ";rs", "0", OPTION_BOOLEAN, "automatically adjust emulation speed to keep the emulated refresh rate slower than the host screen" }, -- { OPTION_LOWLATENCY ";lolat", "0", OPTION_BOOLEAN, "draws new frame before throttling to reduce input latency" }, -+ { OPTION_LOWLATENCY ";lolat", "1", OPTION_BOOLEAN, "draws new frame before throttling to reduce input latency" }, - - // render options - { nullptr, nullptr, OPTION_HEADER, "CORE RENDER OPTIONS" }, -@@ -113,7 +115,7 @@ const options_entry emu_options::s_option_entries[] = - - // artwork options - { nullptr, nullptr, OPTION_HEADER, "CORE ARTWORK OPTIONS" }, -- { OPTION_ARTWORK_CROP ";artcrop", "0", OPTION_BOOLEAN, "crop artwork so emulated screen image fills output screen/window in one axis" }, -+ { OPTION_ARTWORK_CROP ";artcrop", "1", OPTION_BOOLEAN, "crop artwork so emulated screen image fills output screen/window in one axis" }, - { OPTION_FALLBACK_ARTWORK, nullptr, OPTION_STRING, "fallback artwork if no external artwork or internal driver layout defined" }, - { OPTION_OVERRIDE_ARTWORK, nullptr, OPTION_STRING, "override artwork for external artwork and internal driver layout" }, - -@@ -216,6 +218,38 @@ const options_entry emu_options::s_option_entries[] = - { OPTION_HTTP_PORT, "8080", OPTION_INTEGER, "HTTP server port" }, - { OPTION_HTTP_ROOT, "web", OPTION_STRING, "HTTP server document root" }, - -+ // Switchres options -+ { nullptr, nullptr, OPTION_HEADER, "CORE SWITCHRES OPTIONS" }, -+ { OPTION_MODELINE_GENERATION ";ml", "1", OPTION_BOOLEAN, "Automatic generation of modelines based on the specified monitor type" }, -+ { OPTION_MONITOR ";m", "generic_15",OPTION_STRING, "Monitor type, e.g.: generic_15, arcade_15, lcd, custom, etc." }, -+ { OPTION_ORIENTATION ";or", "horizontal",OPTION_STRING, "Monitor orientation (horizontal|vertical|rotate|rotate_r|rotate_l)" }, -+ { OPTION_CONNECTOR ";cn", "auto", OPTION_STRING, "[Linux] video card output (VGA-0|VGA-1|DVI-0|DVI-1)" }, -+ { OPTION_INTERLACE ";in", "1", OPTION_BOOLEAN, "Enable interlaced scanning when necessary" }, -+ { OPTION_DOUBLESCAN ";ds", "1", OPTION_BOOLEAN, "Enable double scanning when necessary (unsupported under Windows)" }, -+ { OPTION_SUPER_WIDTH ";cs", "2560", OPTION_INTEGER, "Automatically apply -unevenstretchx if resolution width is equal or greater than this value" }, -+ { OPTION_CHANGERES ";cr", "1", OPTION_BOOLEAN, "Enable dynamic in-game video mode switching" }, -+ { OPTION_POWERSTRIP ";ps", "0", OPTION_BOOLEAN, "Use Powerstrip API for dynamic setting of custom video timings" }, -+ { OPTION_LOCK_SYSTEM_MODES ";lsm", "1", OPTION_BOOLEAN, "Lock system (non-custom) video modes, only use modes created by us" }, -+ { OPTION_LOCK_UNSUPPORTED_MODES ";lum", "1", OPTION_BOOLEAN, "Lock video modes reported as unsupported by your monitor's EDID" }, -+ { OPTION_REFRESH_DONT_CARE ";rdc", "0", OPTION_BOOLEAN, "Ignore video mode's refresh reported by OS when checking ranges" }, -+ { OPTION_DOTCLOCK_MIN ";dcm", "0", OPTION_STRING, "Lowest pixel clock supported by video card, in MHz, default is 0" }, -+ { OPTION_SYNC_REFRESH_TOLERANCE ";srt", "2.0", OPTION_STRING, "Maximum refresh difference, in Hz, allowed in order to synchronize" }, -+ { OPTION_FRAME_DELAY ";fd", "0", OPTION_INTEGER, "Delays the start of each frame to minimize input lag (0-9)"}, -+ { OPTION_VSYNC_OFFSET, "0", OPTION_INTEGER, "Offset vsync position by this many lines to prevent tearing with frame_delay and high-resolution displays" }, -+ { OPTION_BLACK_FRAME_INSERTION ";bfi", "0", OPTION_BOOLEAN, "Inserts a black frame after each normal frame, intended to reduce motion blur on 120 Hz monitors" }, -+ { OPTION_MODELINE ";mode", "auto", OPTION_STRING, "Use custom defined modeline" }, -+ { OPTION_PS_TIMING ";pst", "auto", OPTION_STRING, "Use custom Powertrip timing string" }, -+ { OPTION_LCD_RANGE ";lcd", "auto", OPTION_STRING, "Add custom LCD range, VfreqMin-VfreqMax, in Hz, e.g.: 55.50-61.00" }, -+ { OPTION_CRT_RANGE0 ";crt0", "auto", OPTION_STRING, "Add custom CRT range, see documentation for details." }, -+ { OPTION_CRT_RANGE1 ";crt1", "auto", OPTION_STRING, "Add custom CRT range" }, -+ { OPTION_CRT_RANGE2 ";crt2", "auto", OPTION_STRING, "Add custom CRT range" }, -+ { OPTION_CRT_RANGE3 ";crt3", "auto", OPTION_STRING, "Add custom CRT range" }, -+ { OPTION_CRT_RANGE4 ";crt4", "auto", OPTION_STRING, "Add custom CRT range" }, -+ { OPTION_CRT_RANGE5 ";crt5", "auto", OPTION_STRING, "Add custom CRT range" }, -+ { OPTION_CRT_RANGE6 ";crt6", "auto", OPTION_STRING, "Add custom CRT range" }, -+ { OPTION_CRT_RANGE7 ";crt7", "auto", OPTION_STRING, "Add custom CRT range" }, -+ { OPTION_CRT_RANGE8 ";crt8", "auto", OPTION_STRING, "Add custom CRT range" }, -+ { OPTION_CRT_RANGE9 ";crt9", "auto", OPTION_STRING, "Add custom CRT range" }, - { nullptr } - }; - -diff --git a/src/emu/emuopts.h b/src/emu/emuopts.h -index a1a23e77a2b..1a12f23d99b 100644 ---- a/src/emu/emuopts.h -+++ b/src/emu/emuopts.h -@@ -72,6 +72,8 @@ - #define OPTION_FRAMESKIP "frameskip" - #define OPTION_SECONDS_TO_RUN "seconds_to_run" - #define OPTION_THROTTLE "throttle" -+#define OPTION_SYNCREFRESH "syncrefresh" -+#define OPTION_AUTOSYNC "autosync" - #define OPTION_SLEEP "sleep" - #define OPTION_SPEED "speed" - #define OPTION_REFRESHSPEED "refreshspeed" -@@ -193,6 +195,38 @@ - #define OPTION_HTTP_PORT "http_port" - #define OPTION_HTTP_ROOT "http_root" - -+/* Switchres Options */ -+#define OPTION_MODELINE_GENERATION "modeline_generation" -+#define OPTION_MONITOR "monitor" -+#define OPTION_CONNECTOR "connector" -+#define OPTION_ORIENTATION "orientation" -+#define OPTION_INTERLACE "interlace" -+#define OPTION_DOUBLESCAN "doublescan" -+#define OPTION_SUPER_WIDTH "super_width" -+#define OPTION_CHANGERES "changeres" -+#define OPTION_POWERSTRIP "powerstrip" -+#define OPTION_LOCK_SYSTEM_MODES "lock_system_modes" -+#define OPTION_LOCK_UNSUPPORTED_MODES "lock_unsupported_modes" -+#define OPTION_REFRESH_DONT_CARE "refresh_dont_care" -+#define OPTION_DOTCLOCK_MIN "dotclock_min" -+#define OPTION_SYNC_REFRESH_TOLERANCE "sync_refresh_tolerance" -+#define OPTION_FRAME_DELAY "frame_delay" -+#define OPTION_VSYNC_OFFSET "vsync_offset" -+#define OPTION_BLACK_FRAME_INSERTION "black_frame_insertion" -+#define OPTION_MODELINE "modeline" -+#define OPTION_PS_TIMING "ps_timing" -+#define OPTION_LCD_RANGE "lcd_range" -+#define OPTION_CRT_RANGE0 "crt_range0" -+#define OPTION_CRT_RANGE1 "crt_range1" -+#define OPTION_CRT_RANGE2 "crt_range2" -+#define OPTION_CRT_RANGE3 "crt_range3" -+#define OPTION_CRT_RANGE4 "crt_range4" -+#define OPTION_CRT_RANGE5 "crt_range5" -+#define OPTION_CRT_RANGE6 "crt_range6" -+#define OPTION_CRT_RANGE7 "crt_range7" -+#define OPTION_CRT_RANGE8 "crt_range8" -+#define OPTION_CRT_RANGE9 "crt_range9" -+ - //************************************************************************** - // TYPE DEFINITIONS - //************************************************************************** -@@ -350,6 +384,8 @@ public: - int frameskip() const { return int_value(OPTION_FRAMESKIP); } - int seconds_to_run() const { return int_value(OPTION_SECONDS_TO_RUN); } - bool throttle() const { return bool_value(OPTION_THROTTLE); } -+ bool sync_refresh() const { return bool_value(OPTION_SYNCREFRESH); } -+ bool autosync() const { return bool_value(OPTION_AUTOSYNC); } - bool sleep() const { return m_sleep; } - float speed() const { return float_value(OPTION_SPEED); } - bool refresh_speed() const { return m_refresh_speed; } -@@ -444,6 +480,38 @@ public: - const char *ram_size() const { return value(OPTION_RAMSIZE); } - bool nvram_save() const { return bool_value(OPTION_NVRAM_SAVE); } - -+ // Switchres options -+ bool modeline_generation() const { return bool_value(OPTION_MODELINE_GENERATION); } -+ const char *monitor() const { return value(OPTION_MONITOR); } -+ const char *connector() const { return value(OPTION_CONNECTOR); } -+ const char *orientation() const { return value(OPTION_ORIENTATION); } -+ bool doublescan() const { return bool_value(OPTION_DOUBLESCAN); } -+ bool interlace() const { return bool_value(OPTION_INTERLACE); } -+ int super_width() const { return int_value(OPTION_SUPER_WIDTH); } -+ int changeres() const { return int_value(OPTION_CHANGERES); } -+ bool powerstrip() const { return bool_value(OPTION_POWERSTRIP); } -+ bool lock_system_modes() const { return bool_value(OPTION_LOCK_SYSTEM_MODES); } -+ bool lock_unsupported_modes() const { return bool_value(OPTION_LOCK_UNSUPPORTED_MODES); } -+ bool refresh_dont_care() const { return bool_value(OPTION_REFRESH_DONT_CARE); } -+ const char *dotclock_min() const { return value(OPTION_DOTCLOCK_MIN); } -+ const char *sync_refresh_tolerance() const { return value(OPTION_SYNC_REFRESH_TOLERANCE); } -+ int frame_delay() const { return int_value(OPTION_FRAME_DELAY); } -+ int vsync_offset() const { return int_value(OPTION_VSYNC_OFFSET); } -+ bool black_frame_insertion() const { return bool_value(OPTION_BLACK_FRAME_INSERTION); } -+ const char *modeline() const { return value(OPTION_MODELINE); } -+ const char *ps_timing() const { return value(OPTION_PS_TIMING); } -+ const char *lcd_range() const { return value(OPTION_LCD_RANGE); } -+ const char *crt_range0() const { return value(OPTION_CRT_RANGE0); } -+ const char *crt_range1() const { return value(OPTION_CRT_RANGE1); } -+ const char *crt_range2() const { return value(OPTION_CRT_RANGE2); } -+ const char *crt_range3() const { return value(OPTION_CRT_RANGE3); } -+ const char *crt_range4() const { return value(OPTION_CRT_RANGE4); } -+ const char *crt_range5() const { return value(OPTION_CRT_RANGE5); } -+ const char *crt_range6() const { return value(OPTION_CRT_RANGE6); } -+ const char *crt_range7() const { return value(OPTION_CRT_RANGE7); } -+ const char *crt_range8() const { return value(OPTION_CRT_RANGE8); } -+ const char *crt_range9() const { return value(OPTION_CRT_RANGE9); } -+ - // core comm options - const char *comm_localhost() const { return value(OPTION_COMM_LOCAL_HOST); } - const char *comm_localport() const { return value(OPTION_COMM_LOCAL_PORT); } -diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp -index 7b86af34925..0b93346b0d3 100644 ---- a/src/emu/machine.cpp -+++ b/src/emu/machine.cpp -@@ -135,6 +135,7 @@ running_machine::running_machine(const machine_config &_config, machine_manager - m_dummy_space(_config, "dummy_space", &root_device(), 0) - { - memset(&m_base_time, 0, sizeof(m_base_time)); -+ memset(&switchres, 0, sizeof(switchres)); - - m_dummy_space.set_machine(*this); - m_dummy_space.config_complete(); -diff --git a/src/emu/machine.h b/src/emu/machine.h -index 205988fbbe6..5d641a1cb7e 100644 ---- a/src/emu/machine.h -+++ b/src/emu/machine.h -@@ -257,6 +257,9 @@ public: - std::string compose_saveload_filename(std::string &&base_filename, const char **searchpath = nullptr); - std::string get_statename(const char *statename_opt) const; - -+ // SwitchRes manager -+ switchres_manager switchres; // SwitchRes data -+ - private: - // side effect disable counter - u32 m_side_effects_disabled; -diff --git a/src/emu/sound.cpp b/src/emu/sound.cpp -index c876431c41b..15fd0116787 100644 ---- a/src/emu/sound.cpp -+++ b/src/emu/sound.cpp -@@ -866,16 +866,13 @@ sound_manager::sound_manager(running_machine &machine) - machine.add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(&sound_manager::resume, this)); - machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(&sound_manager::reset, this)); - machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&sound_manager::stop_recording, this)); -+ machine.add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(&sound_manager::update, this)); - - // register global states - machine.save().save_item(NAME(m_last_update)); - - // set the starting attenuation - set_attenuation(machine.options().volume()); -- -- // start the periodic update flushing timer -- m_update_timer = machine.scheduler().timer_alloc(timer_expired_delegate(FUNC(sound_manager::update), this)); -- m_update_timer->adjust(STREAMS_UPDATE_ATTOTIME, 0, STREAMS_UPDATE_ATTOTIME); - } - - -@@ -1077,7 +1074,7 @@ void sound_manager::config_save(config_type cfg_type, util::xml::data_node *pare - // and send it to the OSD layer - //------------------------------------------------- - --void sound_manager::update(void *ptr, int param) -+void sound_manager::update() - { - VPRINTF(("sound_update\n")); - -@@ -1089,13 +1086,13 @@ void sound_manager::update(void *ptr, int param) - speaker.mix(&m_leftmix[0], &m_rightmix[0], m_samples_this_update, (m_muted & MUTE_REASON_SYSTEM)); - - // now downmix the final result -- u32 finalmix_step = machine().video().speed_factor(); -+ u32 finalmix_step = machine().video().speed_factor() * 100; - u32 finalmix_offset = 0; - s16 *finalmix = &m_finalmix[0]; - int sample; -- for (sample = m_finalmix_leftover; sample < m_samples_this_update * 1000; sample += finalmix_step) -+ for (sample = m_finalmix_leftover; sample < m_samples_this_update * 100000; sample += finalmix_step) - { -- int sampindex = sample / 1000; -+ int sampindex = sample / 100000; - - // clamp the left side - s32 samp = m_leftmix[sampindex]; -@@ -1113,7 +1110,7 @@ void sound_manager::update(void *ptr, int param) - samp = 32767; - finalmix[finalmix_offset++] = samp; - } -- m_finalmix_leftover = sample - m_samples_this_update * 1000; -+ m_finalmix_leftover = sample - m_samples_this_update * 100000; - - // play the result - if (finalmix_offset > 0) -diff --git a/src/emu/sound.h b/src/emu/sound.h -index 7301a4d69ba..91fd6b0de4a 100644 ---- a/src/emu/sound.h -+++ b/src/emu/sound.h -@@ -225,7 +225,7 @@ private: - void config_load(config_type cfg_type, util::xml::data_node const *parentnode); - void config_save(config_type cfg_type, util::xml::data_node *parentnode); - -- void update(void *ptr = nullptr, s32 param = 0); -+ void update(); - - // internal state - running_machine & m_machine; // reference to our machine -diff --git a/src/emu/switchres/modeline.cpp b/src/emu/switchres/modeline.cpp -new file mode 100644 -index 00000000000..8eddd2b4e2a ---- /dev/null -+++ b/src/emu/switchres/modeline.cpp -@@ -0,0 +1,690 @@ -+/************************************************************** -+ -+ modeline.cpp - Modeline generation and scoring routines -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+#include "emu.h" -+ -+#define max(a,b)({ __typeof__ (a) _a = (a);__typeof__ (b) _b = (b);_a > _b ? _a : _b; }) -+#define min(a,b)({ __typeof__ (a) _a = (a);__typeof__ (b) _b = (b);_a < _b ? _a : _b; }) -+ -+//============================================================ -+// PROTOTYPES -+//============================================================ -+ -+int get_line_params(modeline *mode, monitor_range *range); -+int scale_into_range (int value, int lower_limit, int higher_limit); -+int scale_into_range (float value, float lower_limit, float higher_limit); -+int scale_into_aspect (int source_res, int tot_res, float original_monitor_aspect, float users_monitor_aspect, float *best_diff); -+int stretch_into_range(float vfreq, monitor_range *range, bool interlace_allowed, float *interlace); -+int total_lines_for_yres(int yres, float vfreq, monitor_range *range, float interlace); -+float max_vfreq_for_yres (int yres, monitor_range *range, float interlace); -+int round_near (double number); -+ -+//============================================================ -+// modeline_create -+//============================================================ -+ -+int modeline_create(modeline *s_mode, modeline *t_mode, monitor_range *range, config_settings *cs) -+{ -+ float vfreq = 0; -+ float vfreq_real = 0; -+ int xres = 0; -+ int yres = 0; -+ float interlace = 1; -+ float doublescan = 1; -+ float scan_factor = 1; -+ int x_scale = 0; -+ int y_scale = 0; -+ int v_scale = 0; -+ float x_diff = 0; -+ float y_diff = 0; -+ float v_diff = 0; -+ float y_ratio = 0; -+ float x_ratio = 0; -+ -+ // init all editable fields with source or user values -+ if (t_mode->type & X_RES_EDITABLE) -+ xres = cs->width? cs->width : s_mode->hactive; -+ else -+ xres = t_mode->hactive; -+ if (t_mode->type & Y_RES_EDITABLE) -+ yres = cs->height? cs->height : s_mode->vactive; -+ else -+ yres = t_mode->vactive; -+ if (t_mode->type & V_FREQ_EDITABLE) -+ vfreq = s_mode->vfreq; -+ else -+ vfreq = t_mode->vfreq; -+ -+ // lock resolution fields if required -+ if (cs->width) t_mode->type &= ~X_RES_EDITABLE; -+ if (cs->height) t_mode->type &= ~Y_RES_EDITABLE; -+ -+ // ··· Vertical refresh ··· -+ // try to fit vertical frequency into current range -+ v_scale = scale_into_range(vfreq, range->vfreq_min, range->vfreq_max); -+ -+ if (!v_scale && (t_mode->type & V_FREQ_EDITABLE)) -+ { -+ vfreq = vfreq < range->vfreq_min? range->vfreq_min : range->vfreq_max; -+ v_scale = 1; -+ } -+ else if (v_scale != 1 && !(t_mode->type & V_FREQ_EDITABLE)) -+ { -+ t_mode->result.weight |= R_OUT_OF_RANGE; -+ return -1; -+ } -+ -+ // ··· Vertical resolution ··· -+ // try to fit active lines in the progressive range first -+ if (range->progressive_lines_min && (!t_mode->interlace || (t_mode->type & V_FREQ_EDITABLE))) -+ y_scale = scale_into_range(yres, range->progressive_lines_min, range->progressive_lines_max); -+ -+ // if not possible, try to fit in the interlaced range, if any -+ if (!y_scale && range->interlaced_lines_min && cs->interlace && (t_mode->interlace || (t_mode->type & V_FREQ_EDITABLE))) -+ { -+ y_scale = scale_into_range(yres, range->interlaced_lines_min, range->interlaced_lines_max); -+ interlace = 2; -+ } -+ -+ // if we succeeded, let's see if we can apply integer scaling -+ if (y_scale == 1 || (y_scale > 1 && (t_mode->type & Y_RES_EDITABLE))) -+ { -+ // check if we should apply doublescan -+ if (cs->doublescan && y_scale % 2 == 0) -+ { -+ y_scale /= 2; -+ doublescan = 0.5; -+ } -+ scan_factor = interlace * doublescan; -+ -+ // calculate expected achievable refresh for this height -+ vfreq_real = min(vfreq * v_scale, max_vfreq_for_yres(yres * y_scale, range, scan_factor)); -+ if (vfreq_real != vfreq * v_scale && !(t_mode->type & V_FREQ_EDITABLE)) -+ { -+ t_mode->result.weight |= R_OUT_OF_RANGE; -+ return -1; -+ } -+ -+ // calculate the ratio that our scaled yres represents with respect to the original height -+ y_ratio = float(yres) * y_scale / s_mode->vactive; -+ int y_source_scaled = s_mode->vactive * floor(y_ratio); -+ -+ // if our original height doesn't fit the target height, we're forced to stretch -+ if (!y_source_scaled) -+ t_mode->result.weight |= R_RES_STRETCH; -+ -+ // otherwise we try to perform integer scaling -+ else -+ { -+ if (t_mode->type & V_FREQ_EDITABLE) -+ { -+ // calculate y borders considering physical lines (instead of logical resolution) -+ int tot_yres = total_lines_for_yres(yres * y_scale, vfreq_real, range, scan_factor); -+ int tot_source = total_lines_for_yres(y_source_scaled, vfreq * v_scale, range, scan_factor); -+ y_diff = tot_yres > tot_source?float(tot_yres % tot_source) / tot_yres * 100:0; -+ -+ // we penalize for the logical lines we need to add in order to meet the user's lower active lines limit -+ int y_min = interlace == 2?range->interlaced_lines_min:range->progressive_lines_min; -+ int tot_rest = (y_min >= y_source_scaled)? y_min % y_source_scaled:0; -+ y_diff += float(tot_rest) / tot_yres * 100; -+ } -+ else -+ y_diff = float((yres * y_scale) % y_source_scaled) / (yres * y_scale) * 100; -+ -+ // we save the integer ratio between source and target resolutions, this will be used for prescaling -+ y_scale = floor(y_ratio); -+ -+ // now if the borders obtained are low enough (< 10%) we'll finally apply integer scaling -+ // otherwise we'll stretch the original resolution over the target one -+ if (!(y_ratio >= 1.0 && y_ratio < 16.0 && y_diff < 10.0)) -+ t_mode->result.weight |= R_RES_STRETCH; -+ } -+ } -+ -+ // otherwise, check if we're allowed to apply fractional scaling -+ else if (t_mode->type & Y_RES_EDITABLE) -+ t_mode->result.weight |= R_RES_STRETCH; -+ -+ // if there's nothing we can do, we're out of range -+ else -+ { -+ t_mode->result.weight |= R_OUT_OF_RANGE; -+ return -1; -+ } -+ -+ // ··· Horizontal resolution ··· -+ // make the best possible adjustment of xres depending on what happened in the previous steps -+ // let's start with the SCALED case -+ if (!(t_mode->result.weight & R_RES_STRETCH)) -+ { -+ // if we can, let's apply the same scaling to both directions -+ if (t_mode->type & X_RES_EDITABLE) -+ { -+ if (t_mode->type & Y_RES_EDITABLE) yres *= y_scale; -+ x_scale = y_scale; -+ xres = normalize(float(xres) * float(x_scale) * cs->monitor_aspect / (cs->effective_orientation? (1.0/(STANDARD_CRT_ASPECT)) : (STANDARD_CRT_ASPECT)), 8); -+ } -+ -+ // otherwise, try to get the best out of our current xres -+ else -+ { -+ x_scale = xres / s_mode->hactive; -+ // if the source width fits our xres, try applying integer scaling -+ if (x_scale) -+ { -+ x_scale = scale_into_aspect(s_mode->hactive, xres, cs->effective_orientation?1.0/(STANDARD_CRT_ASPECT):STANDARD_CRT_ASPECT, cs->monitor_aspect, &x_diff); -+ if (x_diff > 15.0 && t_mode->width < cs->super_width) -+ t_mode->result.weight |= R_RES_STRETCH; -+ } -+ // otherwise apply fractional scaling -+ else -+ t_mode->result.weight |= R_RES_STRETCH; -+ } -+ } -+ -+ // if the result was fractional scaling in any of the previous steps, deal with it -+ if (t_mode->result.weight & R_RES_STRETCH) -+ { -+ if (t_mode->type & Y_RES_EDITABLE) -+ { -+ // always try to use the interlaced range first if it exists, for better resolution -+ yres = stretch_into_range(vfreq, range, cs->interlace, &interlace); -+ -+ // check in case we couldn't achieve the desired refresh -+ vfreq_real = min(vfreq, max_vfreq_for_yres(yres, range, interlace)); -+ } -+ -+ // check if we can create a normal aspect resolution -+ if (t_mode->type & X_RES_EDITABLE) -+ xres = max(xres, normalize(STANDARD_CRT_ASPECT * yres, 8)); -+ -+ // calculate integer scale for prescaling -+ x_scale = max(1, scale_into_aspect(s_mode->hactive, xres, cs->effective_orientation?1.0/(STANDARD_CRT_ASPECT):STANDARD_CRT_ASPECT, cs->monitor_aspect, &x_diff)); -+ y_scale = max(1, floor(float(yres) / s_mode->vactive)); -+ -+ scan_factor = interlace; -+ doublescan = 1; -+ } -+ -+ x_ratio = float(xres) / s_mode->hactive; -+ y_ratio = float(yres) / s_mode->vactive; -+ v_scale = max(round_near(vfreq_real / s_mode->vfreq), 1); -+ v_diff = (vfreq_real / v_scale) - s_mode->vfreq; -+ if (fabs(v_diff) > cs->sync_refresh_tolerance) -+ t_mode->result.weight |= R_V_FREQ_OFF; -+ -+ // ··· Modeline generation ··· -+ // compute new modeline if we are allowed to -+ if (cs->modeline_generation && (t_mode->type & V_FREQ_EDITABLE)) -+ { -+ float margin = 0; -+ float vblank_lines = 0; -+ float vvt_ini = 0; -+ -+ // Get games basic resolution -+ t_mode->hactive = xres; -+ t_mode->vactive = yres; -+ t_mode->vfreq = vfreq_real; -+ -+ // Get total vertical lines -+ vvt_ini = total_lines_for_yres(t_mode->vactive, t_mode->vfreq, range, scan_factor) + (interlace == 2?0.5:0); -+ -+ // Calculate horizontal frequency -+ t_mode->hfreq = t_mode->vfreq * vvt_ini; -+ -+ horizontal_values: -+ -+ // Fill horizontal part of modeline -+ get_line_params(t_mode, range); -+ -+ // Calculate pixel clock -+ t_mode->pclock = t_mode->htotal * t_mode->hfreq; -+ if (t_mode->pclock <= cs->pclock_min) -+ { -+ if (t_mode->type & X_RES_EDITABLE) -+ { -+ x_scale *= 2; -+ t_mode->hactive *= 2; -+ goto horizontal_values; -+ } -+ else -+ { -+ t_mode->result.weight |= R_OUT_OF_RANGE; -+ return -1; -+ } -+ } -+ -+ // Vertical blanking -+ t_mode->vtotal = vvt_ini * scan_factor; -+ vblank_lines = int(t_mode->hfreq * range->vertical_blank) + (interlace == 2?0.5:0); -+ margin = (t_mode->vtotal - t_mode->vactive - vblank_lines * scan_factor) / 2; -+ t_mode->vbegin = t_mode->vactive + max(round_near(t_mode->hfreq * range->vfront_porch * scan_factor + margin), 1); -+ t_mode->vend = t_mode->vbegin + max(round_near(t_mode->hfreq * range->vsync_pulse * scan_factor), 1); -+ -+ // Recalculate final vfreq -+ t_mode->vfreq = (t_mode->hfreq / t_mode->vtotal) * scan_factor; -+ -+ t_mode->hsync = range->hsync_polarity; -+ t_mode->vsync = range->vsync_polarity; -+ t_mode->interlace = interlace == 2?1:0; -+ t_mode->doublescan = doublescan == 1?0:1; -+ } -+ -+ // finally, store result -+ t_mode->result.x_scale = x_scale; -+ t_mode->result.y_scale = y_scale; -+ t_mode->result.v_scale = v_scale; -+ t_mode->result.x_diff = x_diff; -+ t_mode->result.y_diff = y_diff; -+ t_mode->result.v_diff = v_diff; -+ t_mode->result.x_ratio = x_ratio; -+ t_mode->result.y_ratio = y_ratio; -+ t_mode->result.v_ratio = 0; -+ t_mode->result.rotated = cs->effective_orientation; -+ -+ return 0; -+} -+ -+//============================================================ -+// get_line_params -+//============================================================ -+ -+int get_line_params(modeline *mode, monitor_range *range) -+{ -+ int hhi, hhf, hht; -+ int hh, hs, he, ht; -+ float line_time, char_time, new_char_time; -+ float hfront_porch_min, hsync_pulse_min, hback_porch_min; -+ -+ hfront_porch_min = range->hfront_porch * .90; -+ hsync_pulse_min = range->hsync_pulse * .90; -+ hback_porch_min = range->hback_porch * .90; -+ -+ line_time = 1 / mode->hfreq * 1000000; -+ -+ hh = round(mode->hactive / 8); -+ hs = he = ht = 1; -+ -+ do { -+ char_time = line_time / (hh + hs + he + ht); -+ if (hs * char_time < hfront_porch_min || -+ fabs((hs + 1) * char_time - range->hfront_porch) < fabs(hs * char_time - range->hfront_porch)) -+ hs++; -+ -+ if (he * char_time < hsync_pulse_min || -+ fabs((he + 1) * char_time - range->hsync_pulse) < fabs(he * char_time - range->hsync_pulse)) -+ he++; -+ -+ if (ht * char_time < hback_porch_min || -+ fabs((ht + 1) * char_time - range->hback_porch) < fabs(ht * char_time - range->hback_porch)) -+ ht++; -+ -+ new_char_time = line_time / (hh + hs + he + ht); -+ } while (new_char_time != char_time); -+ -+ hhi = (hh + hs) * 8; -+ hhf = (hh + hs + he) * 8; -+ hht = (hh + hs + he + ht) * 8; -+ -+ mode->hbegin = hhi; -+ mode->hend = hhf; -+ mode->htotal = hht; -+ -+ return 0; -+} -+ -+//============================================================ -+// scale_into_range -+//============================================================ -+ -+int scale_into_range (int value, int lower_limit, int higher_limit) -+{ -+ int scale = 1; -+ while (value * scale < lower_limit) scale ++; -+ if (value * scale <= higher_limit) -+ return scale; -+ else -+ return 0; -+} -+ -+//============================================================ -+// scale_into_range -+//============================================================ -+ -+int scale_into_range (float value, float lower_limit, float higher_limit) -+{ -+ int scale = 1; -+ while (value * scale < lower_limit) scale ++; -+ if (value * scale <= higher_limit) -+ return scale; -+ else -+ return 0; -+} -+ -+//============================================================ -+// scale_into_aspect -+//============================================================ -+ -+int scale_into_aspect (int source_res, int tot_res, float original_monitor_aspect, float users_monitor_aspect, float *best_diff) -+{ -+ int scale = 1, best_scale = 1; -+ float diff = 0; -+ *best_diff = 0; -+ -+ while (source_res * scale <= tot_res) -+ { -+ diff = fabs(1.0 - (users_monitor_aspect / (float(tot_res) / float(source_res * scale) * original_monitor_aspect))) * 100.0; -+ if (diff < *best_diff || *best_diff == 0) -+ { -+ *best_diff = diff; -+ best_scale = scale; -+ } -+ scale ++; -+ } -+ return best_scale; -+} -+ -+//============================================================ -+// stretch_into_range -+//============================================================ -+ -+int stretch_into_range(float vfreq, monitor_range *range, bool interlace_allowed, float *interlace) -+{ -+ int yres, lower_limit; -+ -+ if (range->interlaced_lines_min && interlace_allowed) -+ { -+ yres = range->interlaced_lines_max; -+ lower_limit = range->interlaced_lines_min; -+ *interlace = 2; -+ } -+ else -+ { -+ yres = range->progressive_lines_max; -+ lower_limit = range->progressive_lines_min; -+ } -+ -+ while (yres > lower_limit && max_vfreq_for_yres(yres, range, *interlace) < vfreq) -+ yres -= 8; -+ -+ return yres; -+} -+ -+ -+//============================================================ -+// total_lines_for_yres -+//============================================================ -+ -+int total_lines_for_yres(int yres, float vfreq, monitor_range *range, float interlace) -+{ -+ int vvt = max(yres / interlace + round_near(vfreq * yres / (interlace * (1.0 - vfreq * range->vertical_blank)) * range->vertical_blank), 1); -+ while ((vfreq * vvt < range->hfreq_min) && (vfreq * (vvt + 1) < range->hfreq_max)) vvt++; -+ return vvt; -+} -+ -+//============================================================ -+// max_vfreq_for_yres -+//============================================================ -+ -+float max_vfreq_for_yres (int yres, monitor_range *range, float interlace) -+{ -+ return range->hfreq_max / (yres / interlace + round_near(range->hfreq_max * range->vertical_blank)); -+} -+ -+//============================================================ -+// modeline_print -+//============================================================ -+ -+char * modeline_print(modeline *mode, char *modeline, int flags) -+{ -+ char label[48]={'\x00'}; -+ char params[192]={'\x00'}; -+ -+ if (flags & MS_LABEL) -+ sprintf(label, "\"%dx%d_%d %.6fKHz %.6fHz\"", mode->hactive, mode->vactive, mode->refresh, mode->hfreq/1000, mode->vfreq); -+ -+ if (flags & MS_LABEL_SDL) -+ sprintf(label, "\"%dx%d_%.6f\"", mode->hactive, mode->vactive, mode->vfreq); -+ -+ if (flags & MS_PARAMS) -+ sprintf(params, " %.6f %d %d %d %d %d %d %d %d %s %s %s %s", float(mode->pclock)/1000000.0, mode->hactive, mode->hbegin, mode->hend, mode->htotal, mode->vactive, mode->vbegin, mode->vend, mode->vtotal, -+ mode->interlace?"interlace":"", mode->doublescan?"doublescan":"", mode->hsync?"+hsync":"-hsync", mode->vsync?"+vsync":"-vsync"); -+ -+ sprintf(modeline, "%s%s", label, params); -+ -+ return modeline; -+} -+ -+//============================================================ -+// modeline_result -+//============================================================ -+ -+char * modeline_result(modeline *mode, char *result) -+{ -+ osd_printf_verbose(" rng(%d): ", mode->range); -+ -+ if (mode->result.weight & R_OUT_OF_RANGE) -+ sprintf(result, " out of range"); -+ -+ else -+ sprintf(result, "%4d x%4d_%3.6f%s%s %3.6f [%s] scale(%d, %d, %d) diff(%.2f, %.2f, %.4f) ratio(%.3f, %.3f)", -+ mode->hactive, mode->vactive, mode->vfreq, mode->interlace?"i":"p", mode->doublescan?"d":"", mode->hfreq/1000, mode->result.weight & R_RES_STRETCH?"fract":"integ", -+ mode->result.x_scale, mode->result.y_scale, mode->result.v_scale, mode->result.x_diff, mode->result.y_diff, mode->result.v_diff, mode->result.x_ratio, mode->result.y_ratio); -+ return result; -+} -+ -+//============================================================ -+// modeline_compare -+//============================================================ -+ -+int modeline_compare(modeline *t, modeline *best) -+{ -+ bool vector = (t->hactive == (int)t->result.x_ratio); -+ -+ if (t->result.weight < best->result.weight) -+ return 1; -+ -+ else if (t->result.weight <= best->result.weight) -+ { -+ float t_v_diff = fabs(t->result.v_diff); -+ float b_v_diff = fabs(best->result.v_diff); -+ -+ if (t->result.weight & R_RES_STRETCH || vector) -+ { -+ float t_y_score = t->result.y_ratio * (t->interlace?(2.0/3.0):1.0); -+ float b_y_score = best->result.y_ratio * (best->interlace?(2.0/3.0):1.0); -+ -+ if ((t_v_diff < b_v_diff) || -+ ((t_v_diff == b_v_diff) && (t_y_score > b_y_score)) || -+ ((t_v_diff == b_v_diff) && (t_y_score == b_y_score) && (t->result.x_ratio > best->result.x_ratio))) -+ return 1; -+ } -+ else -+ { -+ int t_y_score = t->result.y_scale + t->interlace + t->doublescan; -+ int b_y_score = best->result.y_scale + best->interlace + best->doublescan; -+ float xy_diff = roundf((t->result.x_diff + t->result.y_diff) * 100) / 100; -+ float best_xy_diff = roundf((best->result.x_diff + best->result.y_diff) * 100) / 100; -+ -+ if ((t_y_score < b_y_score) || -+ ((t_y_score == b_y_score) && (xy_diff < best_xy_diff)) || -+ ((t_y_score == b_y_score) && (xy_diff == best_xy_diff) && (t->result.x_scale < best->result.x_scale)) || -+ ((t_y_score == b_y_score) && (xy_diff == best_xy_diff) && (t->result.x_scale == best->result.x_scale) && (t_v_diff < b_v_diff))) -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+//============================================================ -+// modeline_vesa_gtf -+// Based on the VESA GTF spreadsheet by Andy Morrish 1/5/97 -+//============================================================ -+ -+int modeline_vesa_gtf(modeline *m) -+{ -+ int C, M; -+ int v_sync_lines, v_porch_lines_min, v_front_porch_lines, v_back_porch_lines, v_sync_v_back_porch_lines, v_total_lines; -+ int h_sync_width_percent, h_sync_width_pixels, h_blanking_pixels, h_front_porch_pixels, h_total_pixels; -+ float v_freq, v_freq_est, v_freq_real, v_sync_v_back_porch; -+ float h_freq, h_period, h_period_real, h_ideal_blanking; -+ float pixel_freq, interlace; -+ -+ // Check if there's a value defined for vfreq. We're assuming input vfreq is the total field vfreq regardless interlace -+ v_freq = m->vfreq? m->vfreq:float(m->refresh); -+ -+ // These values are GTF defined defaults -+ v_sync_lines = 3; -+ v_porch_lines_min = 1; -+ v_front_porch_lines = v_porch_lines_min; -+ v_sync_v_back_porch = 550; -+ h_sync_width_percent = 8; -+ M = 128.0 / 256 * 600; -+ C = ((40 - 20) * 128.0 / 256) + 20; -+ -+ // GTF calculation -+ interlace = m->interlace?0.5:0; -+ h_period = ((1.0 / v_freq) - (v_sync_v_back_porch / 1000000)) / ((float)m->height + v_front_porch_lines + interlace) * 1000000; -+ v_sync_v_back_porch_lines = round_near(v_sync_v_back_porch / h_period); -+ v_back_porch_lines = v_sync_v_back_porch_lines - v_sync_lines; -+ v_total_lines = m->height + v_front_porch_lines + v_sync_lines + v_back_porch_lines; -+ v_freq_est = (1.0 / h_period) / v_total_lines * 1000000; -+ h_period_real = h_period / (v_freq / v_freq_est); -+ v_freq_real = (1.0 / h_period_real) / v_total_lines * 1000000; -+ h_ideal_blanking = float(C - (M * h_period_real / 1000)); -+ h_blanking_pixels = round_near(m->width * h_ideal_blanking /(100 - h_ideal_blanking) / (2 * 8)) * (2 * 8); -+ h_total_pixels = m->width + h_blanking_pixels; -+ pixel_freq = h_total_pixels / h_period_real * 1000000; -+ h_freq = 1000000 / h_period_real; -+ h_sync_width_pixels = round_near(h_sync_width_percent * h_total_pixels / 100 / 8) * 8; -+ h_front_porch_pixels = (h_blanking_pixels / 2) - h_sync_width_pixels; -+ -+ // Results -+ m->hactive = m->width; -+ m->hbegin = m->hactive + h_front_porch_pixels; -+ m->hend = m->hbegin + h_sync_width_pixels; -+ m->htotal = h_total_pixels; -+ m->vactive = m->height; -+ m->vbegin = m->vactive + v_front_porch_lines; -+ m->vend = m->vbegin + v_sync_lines; -+ m->vtotal = v_total_lines; -+ m->hfreq = h_freq; -+ m->vfreq = v_freq_real; -+ m->pclock = pixel_freq; -+ m->hsync = 0; -+ m->vsync = 1; -+ -+ return true; -+} -+ -+//============================================================ -+// modeline_parse -+//============================================================ -+ -+int modeline_parse(const char *user_modeline, modeline *mode) -+{ -+ char modeline_txt[256]={'\x00'}; -+ -+ if (strcmp(user_modeline, "auto")) -+ { -+ // Remove quotes -+ char *quote_start, *quote_end; -+ quote_start = strstr((char*)user_modeline, "\""); -+ if (quote_start) -+ { -+ quote_start++; -+ quote_end = strstr(quote_start, "\""); -+ if (!quote_end || *quote_end++ == 0) -+ return false; -+ user_modeline = quote_end; -+ } -+ -+ // Get timing flags -+ mode->interlace = strstr(user_modeline, "interlace")?1:0; -+ mode->doublescan = strstr(user_modeline, "doublescan")?1:0; -+ mode->hsync = strstr(user_modeline, "+hsync")?1:0; -+ mode->vsync = strstr(user_modeline, "+vsync")?1:0; -+ -+ // Get timing values -+ float pclock; -+ int e = sscanf(user_modeline, " %f %d %d %d %d %d %d %d %d", -+ &pclock, -+ &mode->hactive, &mode->hbegin, &mode->hend, &mode->htotal, -+ &mode->vactive, &mode->vbegin, &mode->vend, &mode->vtotal); -+ -+ if (e != 9) -+ { -+ osd_printf_error("SwitchRes: missing parameter in user modeline\n %s\n", user_modeline); -+ memset(mode, 0, sizeof(struct modeline)); -+ return false; -+ } -+ -+ // Calculate timings -+ mode->pclock = pclock * 1000000.0; -+ mode->hfreq = mode->pclock / mode->htotal; -+ mode->vfreq = mode->hfreq / mode->vtotal * (mode->interlace?2:1); -+ mode->refresh = mode->vfreq; -+ osd_printf_verbose("SwitchRes: user modeline %s\n", modeline_print(mode, modeline_txt, MS_FULL)); -+ } -+ return true; -+} -+ -+//============================================================ -+// modeline_to_monitor_range -+//============================================================ -+ -+int modeline_to_monitor_range(monitor_range *range, modeline *mode) -+{ -+ if (range->vfreq_min == 0) -+ { -+ range->vfreq_min = mode->vfreq - 0.2; -+ range->vfreq_max = mode->vfreq + 0.2; -+ } -+ -+ float line_time = 1 / mode->hfreq; -+ float pixel_time = line_time / mode->htotal * 1000000; -+ -+ range->hfront_porch = pixel_time * (mode->hbegin - mode->hactive); -+ range->hsync_pulse = pixel_time * (mode->hend - mode->hbegin); -+ range->hback_porch = pixel_time * (mode->htotal - mode->hend); -+ -+ range->vfront_porch = line_time * (mode->vbegin - mode->vactive); -+ range->vsync_pulse = line_time * (mode->vend - mode->vbegin); -+ range->vback_porch = line_time * (mode->vtotal - mode->vend); -+ range->vertical_blank = range->vfront_porch + range->vsync_pulse + range->vback_porch; -+ -+ range->hsync_polarity = mode->hsync; -+ range->vsync_polarity = mode->vsync; -+ -+ range->progressive_lines_min = mode->interlace?0:mode->vactive; -+ range->progressive_lines_max = mode->interlace?0:mode->vactive; -+ range->interlaced_lines_min = mode->interlace?mode->vactive:0; -+ range->interlaced_lines_max= mode->interlace?mode->vactive:0; -+ -+ range->hfreq_min = range->vfreq_min * mode->vtotal; -+ range->hfreq_max = range->vfreq_max * mode->vtotal; -+ -+ return 1; -+} -+ -+//============================================================ -+// round_near -+//============================================================ -+ -+int round_near(double number) -+{ -+ return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5); -+} -diff --git a/src/emu/switchres/modeline.h b/src/emu/switchres/modeline.h -new file mode 100644 -index 00000000000..ef59b98cd4a ---- /dev/null -+++ b/src/emu/switchres/modeline.h -@@ -0,0 +1,118 @@ -+/************************************************************** -+ -+ modeline.h - Modeline generation header -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+#ifndef __MODELINE_H__ -+#define __MODELINE_H__ -+ -+#include "monitor.h" -+ -+//============================================================ -+// CONSTANTS -+//============================================================ -+ -+// Modeline print flags -+#define MS_LABEL 0x00000001 -+#define MS_LABEL_SDL 0x00000002 -+#define MS_PARAMS 0x00000004 -+#define MS_FULL MS_LABEL | MS_PARAMS -+ -+// Modeline result -+#define R_V_FREQ_OFF 0x00000001 -+#define R_RES_STRETCH 0x00000002 -+#define R_OUT_OF_RANGE 0x00000004 -+ -+// Modeline commands -+#define MODELINE_DELETE 0x001 -+#define MODELINE_CREATE 0x002 -+#define MODELINE_UPDATE 0x004 -+#define MODELINE_UPDATE_LIST 0x008 -+ -+// Mode types -+#define MODE_OK 0x00000000 -+#define MODE_DESKTOP 0x10000000 -+#define MODE_ROTATED 0x20000000 -+#define MODE_DISABLED 0x40000000 -+#define MODE_USER_DEF 0x80000000 -+#define V_FREQ_EDITABLE 0x00000001 -+#define X_RES_EDITABLE 0x00000002 -+#define Y_RES_EDITABLE 0x00000004 -+#define XYV_EDITABLE (X_RES_EDITABLE | Y_RES_EDITABLE | V_FREQ_EDITABLE ) -+ -+#define DUMMY_WIDTH 1234 -+#define MAX_MODELINES 256 -+ -+//============================================================ -+// TYPE DEFINITIONS -+//============================================================ -+ -+typedef struct mode_result -+{ -+ int weight; -+ int x_scale; -+ int y_scale; -+ int v_scale; -+ float x_diff; -+ float y_diff; -+ float v_diff; -+ float x_ratio; -+ float y_ratio; -+ float v_ratio; -+ bool rotated; -+} mode_result; -+ -+typedef struct modeline -+{ -+ uint64_t pclock; -+ int hactive; -+ int hbegin; -+ int hend; -+ int htotal; -+ int vactive; -+ int vbegin; -+ int vend; -+ int vtotal; -+ int interlace; -+ int doublescan; -+ int hsync; -+ int vsync; -+ // -+ double vfreq; -+ double hfreq; -+ // -+ int width; -+ int height; -+ int refresh; -+ int refresh_label; -+ // -+ int type; -+ int range; -+ // -+ mode_result result; -+} modeline; -+ -+//============================================================ -+// PROTOTYPES -+//============================================================ -+ -+int modeline_create(modeline *s_mode, modeline *t_mode, monitor_range *range, config_settings *cs); -+int modeline_compare(modeline *t_mode, modeline *best_mode); -+char * modeline_print(modeline *mode, char *modeline, int flags); -+char * modeline_result(modeline *mode, char *result); -+int modeline_vesa_gtf(modeline *m); -+int modeline_parse(const char *user_modeline, modeline *mode); -+int modeline_to_monitor_range(monitor_range *range, modeline *mode); -+ -+#endif -diff --git a/src/emu/switchres/monitor.cpp b/src/emu/switchres/monitor.cpp -new file mode 100644 -index 00000000000..4a83d1802eb ---- /dev/null -+++ b/src/emu/switchres/monitor.cpp -@@ -0,0 +1,481 @@ -+/************************************************************** -+ -+ monitor.cpp - Monitor presets and custom monitor definition -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+#include "emu.h" -+ -+//============================================================ -+// CONSTANTS -+//============================================================ -+ -+#define HFREQ_MIN 14000 -+#define HFREQ_MAX 540672 // 8192 * 1.1 * 60 -+#define VFREQ_MIN 40 -+#define VFREQ_MAX 200 -+#define PROGRESSIVE_LINES_MIN 128 -+ -+//============================================================ -+// monitor_fill_range -+//============================================================ -+ -+int monitor_fill_range(monitor_range *range, const char *specs_line) -+{ -+ monitor_range new_range; -+ -+ if (strcmp(specs_line, "auto")) { -+ int e = sscanf(specs_line, "%lf-%lf,%lf-%lf,%lf,%lf,%lf,%lf,%lf,%lf,%d,%d,%d,%d,%d,%d", -+ &new_range.hfreq_min, &new_range.hfreq_max, -+ &new_range.vfreq_min, &new_range.vfreq_max, -+ &new_range.hfront_porch, &new_range.hsync_pulse, &new_range.hback_porch, -+ &new_range.vfront_porch, &new_range.vsync_pulse, &new_range.vback_porch, -+ &new_range.hsync_polarity, &new_range.vsync_polarity, -+ &new_range.progressive_lines_min, &new_range.progressive_lines_max, -+ &new_range.interlaced_lines_min, &new_range.interlaced_lines_max); -+ -+ if (e != 16) { -+ osd_printf_error("SwitchRes: Error trying to fill monitor range with\n %s\n", specs_line); -+ return -1; -+ } -+ -+ new_range.vfront_porch /= 1000; -+ new_range.vsync_pulse /= 1000; -+ new_range.vback_porch /= 1000; -+ new_range.vertical_blank = (new_range.vfront_porch + new_range.vsync_pulse + new_range.vback_porch); -+ -+ if (monitor_evaluate_range(&new_range)) -+ { -+ osd_printf_error("SwitchRes: Error in monitor range (ignoring): %s\n", specs_line); -+ return -1; -+ } -+ else -+ { -+ memcpy(range, &new_range, sizeof(struct monitor_range)); -+ monitor_show_range(range); -+ } -+ } -+ return 0; -+} -+ -+//============================================================ -+// monitor_fill_lcd_range -+//============================================================ -+ -+int monitor_fill_lcd_range(monitor_range *range, const char *specs_line) -+{ -+ if (strcmp(specs_line, "auto")) -+ { -+ if (sscanf(specs_line, "%lf-%lf", &range->vfreq_min, &range->vfreq_max) == 2) -+ { -+ osd_printf_verbose("SwitchRes: LCD vfreq range set by user as %f-%f\n", range->vfreq_min, range->vfreq_max); -+ return true; -+ } -+ else -+ osd_printf_error("SwitchRes: Error trying to fill LCD range with\n %s\n", specs_line); -+ } -+ // Use default values -+ range->vfreq_min = 59; -+ range->vfreq_max = 61; -+ osd_printf_verbose("SwitchRes: Using default vfreq range for LCD %f-%f\n", range->vfreq_min, range->vfreq_max); -+ -+ return 0; -+} -+ -+//============================================================ -+// monitor_fill_vesa_gtf -+//============================================================ -+ -+int monitor_fill_vesa_gtf(monitor_range *range, const char *max_lines) -+{ -+ int lines = 0; -+ sscanf(max_lines, "vesa_%d", &lines); -+ -+ if (!lines) -+ return 0; -+ -+ int i = 0; -+ if (lines >= 480) -+ i += monitor_fill_vesa_range(&range[i], 384, 480); -+ if (lines >= 600) -+ i += monitor_fill_vesa_range(&range[i], 480, 600); -+ if (lines >= 768) -+ i += monitor_fill_vesa_range(&range[i], 600, 768); -+ if (lines >= 1024) -+ i += monitor_fill_vesa_range(&range[i], 768, 1024); -+ -+ return i; -+} -+ -+//============================================================ -+// monitor_fill_vesa_range -+//============================================================ -+ -+int monitor_fill_vesa_range(monitor_range *range, int lines_min, int lines_max) -+{ -+ modeline mode; -+ memset(&mode, 0, sizeof(modeline)); -+ -+ mode.width = real_res(STANDARD_CRT_ASPECT * lines_max); -+ mode.height = lines_max; -+ mode.refresh = 60; -+ range->vfreq_min = 50; -+ range->vfreq_max = 65; -+ -+ modeline_vesa_gtf(&mode); -+ modeline_to_monitor_range(range, &mode); -+ -+ range->progressive_lines_min = lines_min; -+ range->hfreq_min = mode.hfreq - 500; -+ range->hfreq_max = mode.hfreq + 500; -+ monitor_show_range(range); -+ -+ return 1; -+} -+ -+//============================================================ -+// monitor_show_range -+//============================================================ -+ -+int monitor_show_range(monitor_range *range) -+{ -+ osd_printf_verbose("SwitchRes: Monitor range %.2f-%.2f,%.2f-%.2f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%d,%d,%d,%d,%d,%d\n", -+ range->hfreq_min, range->hfreq_max, -+ range->vfreq_min, range->vfreq_max, -+ range->hfront_porch, range->hsync_pulse, range->hback_porch, -+ range->vfront_porch * 1000, range->vsync_pulse * 1000, range->vback_porch * 1000, -+ range->hsync_polarity, range->vsync_polarity, -+ range->progressive_lines_min, range->progressive_lines_max, -+ range->interlaced_lines_min, range->interlaced_lines_max); -+ -+ return 0; -+} -+ -+//============================================================ -+// monitor_set_preset -+//============================================================ -+ -+int monitor_set_preset(char *type, monitor_range *range) -+{ -+ // PAL TV - 50 Hz/625 -+ if (!strcmp(type, "pal")) -+ { -+ monitor_fill_range(&range[0], "15625.00-15625.00, 50.00-50.00, 1.500, 4.700, 5.800, 0.064, 0.160, 1.056, 0, 0, 192, 288, 448, 576"); -+ return 1; -+ } -+ // NTSC TV - 60 Hz/525 -+ else if (!strcmp(type, "ntsc")) -+ { -+ monitor_fill_range(&range[0], "15734.26-15734.26, 59.94-59.94, 1.500, 4.700, 4.700, 0.191, 0.191, 0.953, 0, 0, 192, 240, 448, 480"); -+ return 1; -+ } -+ // Generic 15.7 kHz -+ else if (!strcmp(type, "generic_15")) -+ { -+ monitor_fill_range(&range[0], "15625-15750, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); -+ return 1; -+ } -+ // Arcade 15.7 kHz - standard resolution -+ else if (!strcmp(type, "arcade_15")) -+ { -+ monitor_fill_range(&range[0], "15625-16200, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); -+ return 1; -+ } -+ // Arcade 15.7-16.5 kHz - extended resolution -+ else if (!strcmp(type, "arcade_15ex")) -+ { -+ monitor_fill_range(&range[0], "15625-16500, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); -+ return 1; -+ } -+ // Arcade 25.0 kHz - medium resolution -+ else if (!strcmp(type, "arcade_25")) -+ { -+ monitor_fill_range(&range[0], "24960-24960, 49.50-65.00, 0.800, 4.000, 3.200, 0.080, 0.200, 1.000, 0, 0, 384, 400, 768, 800"); -+ return 1; -+ } -+ // Arcade 31.5 kHz - medium resolution -+ else if (!strcmp(type, "arcade_31")) -+ { -+ monitor_fill_range(&range[0], "31400-31500, 49.50-65.00, 0.940, 3.770, 1.890, 0.349, 0.064, 1.017, 0, 0, 400, 512, 0, 0"); -+ return 1; -+ } -+ // Arcade 15.7/25.0 kHz - dual-sync -+ else if (!strcmp(type, "arcade_15_25")) -+ { -+ monitor_fill_range(&range[0], "15625-16200, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); -+ monitor_fill_range(&range[1], "24960-24960, 49.50-65.00, 0.800, 4.000, 3.200, 0.080, 0.200, 1.000, 0, 0, 384, 400, 768, 800"); -+ return 2; -+ } -+ // Arcade 15.7/31.5 kHz - dual-sync -+ else if (!strcmp(type, "arcade_15_31")) -+ { -+ monitor_fill_range(&range[0], "15625-16200, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); -+ monitor_fill_range(&range[1], "31400-31500, 49.50-65.00, 0.940, 3.770, 1.890, 0.349, 0.064, 1.017, 0, 0, 400, 512, 0, 0"); -+ return 2; -+ } -+ // Arcade 15.7/25.0/31.5 kHz - tri-sync -+ else if (!strcmp(type, "arcade_15_25_31")) -+ { -+ monitor_fill_range(&range[0], "15625-16200, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 0, 0, 192, 288, 448, 576"); -+ monitor_fill_range(&range[1], "24960-24960, 49.50-65.00, 0.800, 4.000, 3.200, 0.080, 0.200, 1.000, 0, 0, 384, 400, 768, 800"); -+ monitor_fill_range(&range[2], "31400-31500, 49.50-65.00, 0.940, 3.770, 1.890, 0.349, 0.064, 1.017, 0, 0, 400, 512, 0, 0"); -+ return 3; -+ } -+ // Makvision 2929D -+ else if (!strcmp(type, "m2929")) -+ { -+ monitor_fill_range(&range[0], "30000-40000, 47.00-90.00, 0.600, 2.500, 2.800, 0.032, 0.096, 0.448, 0, 0, 384, 640, 0, 0"); -+ return 1; -+ } -+ // Wells Gardner D9800, D9400 -+ else if (!strcmp(type, "d9800") || !strcmp(type, "d9400")) -+ { -+ monitor_fill_range(&range[0], "15250-18000, 40-80, 2.187, 4.688, 6.719, 0.190, 0.191, 1.018, 0, 0, 224, 288, 448, 576"); -+ monitor_fill_range(&range[1], "18001-19000, 40-80, 2.187, 4.688, 6.719, 0.140, 0.191, 0.950, 0, 0, 288, 320, 0, 0"); -+ monitor_fill_range(&range[2], "20501-29000, 40-80, 2.910, 3.000, 4.440, 0.451, 0.164, 1.048, 0, 0, 320, 384, 0, 0"); -+ monitor_fill_range(&range[3], "29001-32000, 40-80, 0.636, 3.813, 1.906, 0.318, 0.064, 1.048, 0, 0, 384, 480, 0, 0"); -+ monitor_fill_range(&range[4], "32001-34000, 40-80, 0.636, 3.813, 1.906, 0.020, 0.106, 0.607, 0, 0, 480, 576, 0, 0"); -+ monitor_fill_range(&range[5], "34001-38000, 40-80, 1.000, 3.200, 2.200, 0.020, 0.106, 0.607, 0, 0, 576, 600, 0, 0"); -+ return 6; -+ } -+ // Wells Gardner D9200 -+ else if (!strcmp(type, "d9200")) -+ { -+ monitor_fill_range(&range[0], "15250-16500, 40-80, 2.187, 4.688, 6.719, 0.190, 0.191, 1.018, 0, 0, 224, 288, 448, 576"); -+ monitor_fill_range(&range[1], "23900-24420, 40-80, 2.910, 3.000, 4.440, 0.451, 0.164, 1.148, 0, 0, 384, 400, 0, 0"); -+ monitor_fill_range(&range[2], "31000-32000, 40-80, 0.636, 3.813, 1.906, 0.318, 0.064, 1.048, 0, 0, 400, 512, 0, 0"); -+ monitor_fill_range(&range[3], "37000-38000, 40-80, 1.000, 3.200, 2.200, 0.020, 0.106, 0.607, 0, 0, 512, 600, 0, 0"); -+ return 4; -+ } -+ // Wells Gardner K7000 -+ else if (!strcmp(type, "k7000")) -+ { -+ monitor_fill_range(&range[0], "15625-15800, 49.50-63.00, 2.000, 4.700, 8.000, 0.064, 0.160, 1.056, 0, 0, 192, 288, 448, 576"); -+ return 1; -+ } -+ // Wells Gardner 25K7131 -+ else if (!strcmp(type, "k7131")) -+ { -+ monitor_fill_range(&range[0], "15625-16670, 49.5-65, 2.000, 4.700, 8.000, 0.064, 0.160, 1.056, 0, 0, 192, 288, 448, 576"); -+ return 1; -+ } -+ // Wei-Ya M3129 -+ else if (!strcmp(type, "m3129")) -+ { -+ monitor_fill_range(&range[0], "15250-16500, 40-80, 2.187, 4.688, 6.719, 0.190, 0.191, 1.018, 1, 1, 192, 288, 448, 576"); -+ monitor_fill_range(&range[1], "23900-24420, 40-80, 2.910, 3.000, 4.440, 0.451, 0.164, 1.048, 1, 1, 384, 400, 0, 0"); -+ monitor_fill_range(&range[2], "31000-32000, 40-80, 0.636, 3.813, 1.906, 0.318, 0.064, 1.048, 1, 1, 400, 512, 0, 0"); -+ return 3; -+ } -+ // Hantarex MTC 9110 -+ else if (!strcmp(type, "h9110") || !strcmp(type, "polo")) -+ { -+ monitor_fill_range(&range[0], "15625-16670, 49.5-65, 2.000, 4.700, 8.000, 0.064, 0.160, 1.056, 0, 0, 192, 288, 448, 576"); -+ return 1; -+ } -+ // Hantarex Polostar 25 -+ else if (!strcmp(type, "pstar")) -+ { -+ monitor_fill_range(&range[0], "15700-15800, 50-65, 1.800, 0.400, 7.400, 0.064, 0.160, 1.056, 0, 0, 192, 256, 0, 0"); -+ monitor_fill_range(&range[1], "16200-16300, 50-65, 0.200, 0.400, 8.000, 0.040, 0.040, 0.640, 0, 0, 256, 264, 512, 528"); -+ monitor_fill_range(&range[2], "25300-25400, 50-65, 0.200, 0.400, 8.000, 0.040, 0.040, 0.640, 0, 0, 384, 400, 768, 800"); -+ monitor_fill_range(&range[3], "31500-31600, 50-65, 0.170, 0.350, 5.500, 0.040, 0.040, 0.640, 0, 0, 400, 512, 0, 0"); -+ return 4; -+ } -+ // Nanao MS-2930, MS-2931 -+ else if (!strcmp(type, "ms2930")) -+ { -+ monitor_fill_range(&range[0], "15450-16050, 50-65, 3.190, 4.750, 6.450, 0.191, 0.191, 1.164, 0, 0, 192, 288, 448, 576"); -+ monitor_fill_range(&range[1], "23900-24900, 50-65, 2.870, 3.000, 4.440, 0.451, 0.164, 1.148, 0, 0, 384, 400, 0, 0"); -+ monitor_fill_range(&range[2], "31000-32000, 50-65, 0.330, 3.580, 1.750, 0.316, 0.063, 1.137, 0, 0, 480, 512, 0, 0"); -+ return 3; -+ } -+ // Nanao MS9-29 -+ else if (!strcmp(type, "ms929")) -+ { -+ monitor_fill_range(&range[0], "15450-16050, 50-65, 3.910, 4.700, 6.850, 0.190, 0.191, 1.018, 0, 0, 192, 288, 448, 576"); -+ monitor_fill_range(&range[1], "23900-24900, 50-65, 2.910, 3.000, 4.440, 0.451, 0.164, 1.048, 0, 0, 384, 400, 0, 0"); -+ return 2; -+ } -+ // Rodotron 666B-29 -+ else if (!strcmp(type, "r666b")) -+ { -+ monitor_fill_range(&range[0], "15450-16050, 50-65, 3.190, 4.750, 6.450, 0.191, 0.191, 1.164, 0, 0, 192, 288, 448, 576"); -+ monitor_fill_range(&range[1], "23900-24900, 50-65, 2.870, 3.000, 4.440, 0.451, 0.164, 1.148, 0, 0, 384, 400, 0, 0"); -+ monitor_fill_range(&range[2], "31000-32500, 50-65, 0.330, 3.580, 1.750, 0.316, 0.063, 1.137, 0, 0, 400, 512, 0, 0"); -+ return 3; -+ } -+ // PC CRT 70kHz/120Hz -+ else if (!strcmp(type, "pc_31_120")) -+ { -+ monitor_fill_range(&range[0], "31400-31600, 100-130, 0.671, 2.683, 3.353, 0.034, 0.101, 0.436, 0, 0, 200, 256, 0, 0"); -+ monitor_fill_range(&range[1], "31400-31600, 50-65, 0.671, 2.683, 3.353, 0.034, 0.101, 0.436, 0, 0, 400, 512, 0, 0"); -+ return 2; -+ } -+ // PC CRT 70kHz/120Hz -+ else if (!strcmp(type, "pc_70_120")) -+ { -+ monitor_fill_range(&range[0], "30000-70000, 100-130, 2.201, 0.275, 4.678, 0.063, 0.032, 0.633, 0, 0, 192, 320, 0, 0"); -+ monitor_fill_range(&range[1], "30000-70000, 50-65, 2.201, 0.275, 4.678, 0.063, 0.032, 0.633, 0, 0, 400, 1024, 0, 0"); -+ return 2; -+ } -+ // VESA GTF -+ else if (!strcmp(type, "vesa_480") || !strcmp(type, "vesa_600") || !strcmp(type, "vesa_768") || !strcmp(type, "vesa_1024")) -+ { -+ return monitor_fill_vesa_gtf(&range[0], type); -+ } -+ -+ osd_printf_error("SwitchRes: Monitor type unknown: %s\n", type); -+ return 0; -+} -+ -+//============================================================ -+// monitor_evaluate_range -+//============================================================ -+ -+int monitor_evaluate_range(monitor_range *range) -+{ -+ // First we check that all frequency ranges are reasonable -+ if (range->hfreq_min < HFREQ_MIN || range->hfreq_min > HFREQ_MAX) -+ { -+ osd_printf_error("SwitchRes: hfreq_min %.2f out of range\n", range->hfreq_min); -+ return 1; -+ } -+ if (range->hfreq_max < HFREQ_MIN || range->hfreq_max < range->hfreq_min || range->hfreq_max > HFREQ_MAX) -+ { -+ osd_printf_error("SwitchRes: hfreq_max %.2f out of range\n", range->hfreq_max); -+ return 1; -+ } -+ if (range->vfreq_min < VFREQ_MIN || range->vfreq_min > VFREQ_MAX) -+ { -+ osd_printf_error("SwitchRes: vfreq_min %.2f out of range\n", range->vfreq_min); -+ return 1; -+ } -+ if (range->vfreq_max < VFREQ_MIN || range->vfreq_max < range->vfreq_min || range->vfreq_max > VFREQ_MAX) -+ { -+ osd_printf_error("SwitchRes: vfreq_max %.2f out of range\n", range->vfreq_max); -+ return 1; -+ } -+ -+ // line_time in µs. We check that no horizontal value is longer than a whole line -+ double line_time = 1 / range->hfreq_max * 1000000; -+ -+ if (range->hfront_porch <= 0 || range->hfront_porch > line_time) -+ { -+ osd_printf_error("SwitchRes: hfront_porch %.3f out of range\n", range->hfront_porch); -+ return 1; -+ } -+ if (range->hsync_pulse <= 0 || range->hsync_pulse > line_time) -+ { -+ osd_printf_error("SwitchRes: hsync_pulse %.3f out of range\n", range->hsync_pulse); -+ return 1; -+ } -+ if (range->hback_porch <= 0 || range->hback_porch > line_time) -+ { -+ osd_printf_error("SwitchRes: hback_porch %.3f out of range\n", range->hback_porch); -+ return 1; -+ } -+ -+ // frame_time in ms. We check that no vertical value is longer than a whole frame -+ double frame_time = 1 / range->vfreq_max * 1000; -+ -+ if (range->vfront_porch <= 0 || range->vfront_porch > frame_time) -+ { -+ osd_printf_error("SwitchRes: vfront_porch %.3f out of range\n", range->vfront_porch); -+ return 1; -+ } -+ if (range->vsync_pulse <= 0 || range->vsync_pulse > frame_time) -+ { -+ osd_printf_error("SwitchRes: vsync_pulse %.3f out of range\n", range->vsync_pulse); -+ return 1; -+ } -+ if (range->vback_porch <= 0 || range->vback_porch > frame_time) -+ { -+ osd_printf_error("SwitchRes: vback_porch %.3f out of range\n", range->vback_porch); -+ return 1; -+ } -+ -+ // Now we check sync polarities -+ if (range->hsync_polarity != 0 && range->hsync_polarity != 1) -+ { -+ osd_printf_error("SwitchRes: Hsync polarity can be only 0 or 1\n"); -+ return 1; -+ } -+ if (range->vsync_polarity != 0 && range->vsync_polarity != 1) -+ { -+ osd_printf_error("SwitchRes: Vsync polarity can be only 0 or 1\n"); -+ return 1; -+ } -+ -+ // Finally we check that the line limiters are reasonable -+ // Progressive range: -+ if (range->progressive_lines_min > 0 && range->progressive_lines_min < PROGRESSIVE_LINES_MIN) -+ { -+ osd_printf_error("SwitchRes: progressive_lines_min must be greater than %d\n", PROGRESSIVE_LINES_MIN); -+ return 1; -+ } -+ if ((range->progressive_lines_min + range->hfreq_max * range->vertical_blank) * range->vfreq_min > range->hfreq_max) -+ { -+ osd_printf_error("SwitchRes: progressive_lines_min %d out of range\n", range->progressive_lines_min); -+ return 1; -+ } -+ if (range->progressive_lines_max < range->progressive_lines_min) -+ { -+ osd_printf_error("SwitchRes: progressive_lines_max must greater than progressive_lines_min\n"); -+ return 1; -+ } -+ if ((range->progressive_lines_max + range->hfreq_max * range->vertical_blank) * range->vfreq_min > range->hfreq_max) -+ { -+ osd_printf_error("SwitchRes: progressive_lines_max %d out of range\n", range->progressive_lines_max); -+ return 1; -+ } -+ -+ // Interlaced range: -+ if (range->interlaced_lines_min != 0) -+ { -+ if (range->interlaced_lines_min < range->progressive_lines_max) -+ { -+ osd_printf_error("SwitchRes: interlaced_lines_min must greater than progressive_lines_max\n"); -+ return 1; -+ } -+ if (range->interlaced_lines_min < PROGRESSIVE_LINES_MIN * 2) -+ { -+ osd_printf_error("SwitchRes: interlaced_lines_min must be greater than %d\n", PROGRESSIVE_LINES_MIN * 2); -+ return 1; -+ } -+ if ((range->interlaced_lines_min / 2 + range->hfreq_max * range->vertical_blank) * range->vfreq_min > range->hfreq_max) -+ { -+ osd_printf_error("SwitchRes: interlaced_lines_min %d out of range\n", range->interlaced_lines_min); -+ return 1; -+ } -+ if (range->interlaced_lines_max < range->interlaced_lines_min) -+ { -+ osd_printf_error("SwitchRes: interlaced_lines_max must greater than interlaced_lines_min\n"); -+ return 1; -+ } -+ if ((range->interlaced_lines_max / 2 + range->hfreq_max * range->vertical_blank) * range->vfreq_min > range->hfreq_max) -+ { -+ osd_printf_error("SwitchRes: interlaced_lines_max %d out of range\n", range->interlaced_lines_max); -+ return 1; -+ } -+ } -+ else -+ { -+ if (range->interlaced_lines_max != 0) -+ { -+ osd_printf_error("SwitchRes: interlaced_lines_max must be zero if interlaced_lines_min is not defined\n"); -+ return 1; -+ } -+ } -+ return 0; -+} -diff --git a/src/emu/switchres/monitor.h b/src/emu/switchres/monitor.h -new file mode 100644 -index 00000000000..49aecf20b3d ---- /dev/null -+++ b/src/emu/switchres/monitor.h -@@ -0,0 +1,66 @@ -+/************************************************************** -+ -+ monitor.h - Monitor presets header -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+#ifndef __MONITOR_H__ -+#define __MONITOR_H__ -+ -+//============================================================ -+// CONSTANTS -+//============================================================ -+ -+#define MAX_RANGES 10 -+#define MONITOR_CRT 0 -+#define MONITOR_LCD 1 -+#define STANDARD_CRT_ASPECT 4.0/3.0 -+ -+//============================================================ -+// TYPE DEFINITIONS -+//============================================================ -+ -+typedef struct monitor_range -+{ -+ double hfreq_min; -+ double hfreq_max; -+ double vfreq_min; -+ double vfreq_max; -+ double hfront_porch; -+ double hsync_pulse; -+ double hback_porch; -+ double vfront_porch; -+ double vsync_pulse; -+ double vback_porch; -+ int hsync_polarity; -+ int vsync_polarity; -+ int progressive_lines_min; -+ int progressive_lines_max; -+ int interlaced_lines_min; -+ int interlaced_lines_max; -+ double vertical_blank; -+} monitor_range; -+ -+//============================================================ -+// PROTOTYPES -+//============================================================ -+ -+int monitor_fill_range(monitor_range *range, const char *specs_line); -+int monitor_show_range(monitor_range *range); -+int monitor_set_preset(char *type, monitor_range *range); -+int monitor_fill_lcd_range(monitor_range *range, const char *specs_line); -+int monitor_fill_vesa_gtf(monitor_range *range, const char *max_lines); -+int monitor_fill_vesa_range(monitor_range *range, int lines_min, int lines_max); -+int monitor_evaluate_range(monitor_range *range); -+ -+#endif -diff --git a/src/emu/switchres/switchres.cpp b/src/emu/switchres/switchres.cpp -new file mode 100644 -index 00000000000..6b406a33651 ---- /dev/null -+++ b/src/emu/switchres/switchres.cpp -@@ -0,0 +1,386 @@ -+/************************************************************** -+ -+ switchres.cpp - SwichRes core routines -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+#include "emu.h" -+#include "emuopts.h" -+#include "../frontend/mame/mameopts.h" -+#include "config.h" -+#include "rendutil.h" -+ -+#define CUSTOM_VIDEO_TIMING_SYSTEM 0x00000010 -+ -+//============================================================ -+// PROTOTYPES -+//============================================================ -+ -+void set_option(running_machine &machine, const char *option_ID, bool state); -+ -+//============================================================ -+// switchres_get_video_mode -+//============================================================ -+ -+bool switchres_get_video_mode(running_machine &machine) -+{ -+ switchres_manager *switchres = &machine.switchres; -+ config_settings *cs = &switchres->cs; -+ game_info *game = &switchres->game; -+ monitor_range *range = switchres->range; -+ modeline *mode; -+ modeline *mode_table = switchres->video_modes; -+ modeline *best_mode = &switchres->best_mode; -+ modeline *user_mode = &switchres->user_mode; -+ modeline source_mode, *s_mode = &source_mode; -+ modeline target_mode, *t_mode = &target_mode; -+ char modeline[256]={'\x00'}; -+ char result[256]={'\x00'}; -+ int i = 0, j = 0, table_size = 0; -+ -+ cs->effective_orientation = effective_orientation(machine); -+ -+ osd_printf_verbose("SwitchRes: v%s:[%s] Calculating best video mode for %dx%d@%.6f orientation: %s\n", -+ SWITCHRES_VERSION, game->name, game->width, game->height, game->refresh, -+ cs->effective_orientation?"rotated":"normal"); -+ -+ memset(best_mode, 0, sizeof(struct modeline)); -+ best_mode->result.weight |= R_OUT_OF_RANGE; -+ s_mode->hactive = game->vector?1:normalize(game->width, 8); -+ s_mode->vactive = game->vector?1:game->height; -+ s_mode->vfreq = game->refresh; -+ -+ if (user_mode->hactive) -+ { -+ table_size = 1; -+ mode = user_mode; -+ } -+ else -+ { -+ i = 1; -+ table_size = MAX_MODELINES; -+ mode = &mode_table[i]; -+ } -+ -+ while (mode->width && i < table_size) -+ { -+ // apply options to mode type -+ if (!cs->modeline_generation) -+ mode->type &= ~XYV_EDITABLE; -+ -+ if (cs->refresh_dont_care) -+ mode->type |= V_FREQ_EDITABLE; -+ -+ if (cs->lock_system_modes && (mode->type & CUSTOM_VIDEO_TIMING_SYSTEM) && !(mode->type & MODE_DESKTOP) && !(mode->type & MODE_USER_DEF)) -+ mode->type |= MODE_DISABLED; -+ -+ osd_printf_verbose("\nSwitchRes: %s%4d%sx%s%4d%s_%s%d=%.6fHz%s%s\n", -+ mode->type & X_RES_EDITABLE?"(":"[", mode->width, mode->type & X_RES_EDITABLE?")":"]", -+ mode->type & Y_RES_EDITABLE?"(":"[", mode->height, mode->type & Y_RES_EDITABLE?")":"]", -+ mode->type & V_FREQ_EDITABLE?"(":"[", mode->refresh, mode->vfreq, mode->type & V_FREQ_EDITABLE?")":"]", -+ mode->type & MODE_DISABLED?" - locked":""); -+ -+ // now get the mode if allowed -+ if (!(mode->type & MODE_DISABLED)) -+ { -+ for (j = 0 ; j < MAX_RANGES ; j++) -+ { -+ if (range[j].hfreq_min) -+ { -+ memcpy(t_mode, mode, sizeof(struct modeline)); -+ modeline_create(s_mode, t_mode, &range[j], cs); -+ t_mode->range = j; -+ -+ osd_printf_verbose("%s\n", modeline_result(t_mode, result)); -+ -+ if (modeline_compare(t_mode, best_mode)) -+ memcpy(best_mode, t_mode, sizeof(struct modeline)); -+ } -+ } -+ } -+ mode++; -+ i++; -+ } -+ -+ if (best_mode->result.weight & R_OUT_OF_RANGE) -+ { -+ osd_printf_error("SwitchRes: could not find a video mode that meets your specs\n"); -+ return false; -+ } -+ -+ osd_printf_info("\nSwitchRes: [%s] (%d) %s (%dx%d@%.6f)->(%dx%d@%.6f)\n", game->name, game->screens, game->orientation?"vertical":"horizontal", -+ game->width, game->height, game->refresh, best_mode->hactive, best_mode->vactive, best_mode->vfreq); -+ -+ osd_printf_verbose("%s\n", modeline_result(best_mode, result)); -+ if (cs->modeline_generation) -+ osd_printf_verbose("SwitchRes: Modeline %s\n", modeline_print(best_mode, modeline, MS_FULL)); -+ -+ return true; -+} -+ -+//============================================================ -+// switchres_get_monitor_specs -+//============================================================ -+ -+int switchres_get_monitor_specs(running_machine &machine) -+{ -+ switchres_manager *switchres = &machine.switchres; -+ char default_monitor[] = "generic_15"; -+ -+ memset(&switchres->range[0], 0, sizeof(struct monitor_range) * MAX_RANGES); -+ -+ if (!strcmp(switchres->cs.monitor, "custom")) -+ { -+ monitor_fill_range(&switchres->range[0],machine.options().crt_range0()); -+ monitor_fill_range(&switchres->range[1],machine.options().crt_range1()); -+ monitor_fill_range(&switchres->range[2],machine.options().crt_range2()); -+ monitor_fill_range(&switchres->range[3],machine.options().crt_range3()); -+ monitor_fill_range(&switchres->range[4],machine.options().crt_range4()); -+ monitor_fill_range(&switchres->range[5],machine.options().crt_range5()); -+ monitor_fill_range(&switchres->range[6],machine.options().crt_range6()); -+ monitor_fill_range(&switchres->range[7],machine.options().crt_range7()); -+ monitor_fill_range(&switchres->range[8],machine.options().crt_range8()); -+ monitor_fill_range(&switchres->range[9],machine.options().crt_range9()); -+ } -+ else if (!strcmp(switchres->cs.monitor, "lcd")) -+ monitor_fill_lcd_range(&switchres->range[0],machine.options().lcd_range()); -+ -+ else if (monitor_set_preset(switchres->cs.monitor, switchres->range) == 0) -+ monitor_set_preset(default_monitor, switchres->range); -+ -+ return 0; -+} -+ -+//============================================================ -+// switchres_init -+//============================================================ -+ -+void switchres_init(running_machine &machine) -+{ -+ emu_options &options = machine.options(); -+ config_settings *cs = &machine.switchres.cs; -+ modeline *user_mode = &machine.switchres.user_mode; -+ -+ osd_printf_verbose("SwitchRes: v%s, Monitor: %s, Orientation: %s, Modeline generation: %s\n", -+ SWITCHRES_VERSION, options.monitor(), options.orientation(), options.modeline_generation()?"enabled":"disabled"); -+ -+ // Get user defined modeline -+ if (options.modeline_generation()) -+ { -+ modeline_parse(options.modeline(), user_mode); -+ user_mode->type |= MODE_USER_DEF; -+ } -+ -+ // Get monitor specs -+ sprintf(cs->monitor, "%s", options.monitor()); -+ sprintf(cs->connector, "%s", options.connector()); -+ for (int i = 0; cs->monitor[i]; i++) cs->monitor[i] = tolower(cs->monitor[i]); -+ if (user_mode->hactive) -+ { -+ modeline_to_monitor_range(machine.switchres.range, user_mode); -+ monitor_show_range(machine.switchres.range); -+ } -+ else -+ switchres_get_monitor_specs(machine); -+ -+ // Get rest of config options -+ cs->modeline_generation = options.modeline_generation(); -+ cs->doublescan = options.doublescan(); -+ cs->interlace = options.interlace(); -+ cs->lock_system_modes = options.lock_system_modes(); -+ cs->lock_unsupported_modes = options.lock_unsupported_modes(); -+ cs->refresh_dont_care = options.refresh_dont_care(); -+ cs->super_width = options.super_width(); -+ sscanf(options.sync_refresh_tolerance(), "%f", &cs->sync_refresh_tolerance); -+ float pclock_min; -+ sscanf(options.dotclock_min(), "%f", &pclock_min); -+ cs->pclock_min = pclock_min * 1000000; -+} -+ -+//============================================================ -+// switchres_get_game_info -+//============================================================ -+ -+void switchres_get_game_info(running_machine &machine) -+{ -+ emu_options &options = machine.options(); -+ game_info *game = &machine.switchres.game; -+ const game_driver *game_drv = &machine.system(); -+ const screen_device *screen; -+ -+ // Get game information -+ sprintf(game->name, "%s", options.system_name()); -+ if (game->name[0] == 0) sprintf(game->name, "empty"); -+ -+ machine_config config(*game_drv, options); -+ screen = screen_device_iterator(config.root_device()).first(); -+ -+ // Fill in current video mode settings -+ game->orientation = effective_orientation(machine); -+ -+ if (screen->screen_type() == SCREEN_TYPE_VECTOR) -+ { -+ game->vector = 1; -+ game->width = 640; -+ game->height = 480; -+ } -+ -+ // Output width and height only for games that are not vector -+ else -+ { -+ const rectangle &visarea = screen->visible_area(); -+ int w = visarea.max_x - visarea.min_x + 1; -+ int h = visarea.max_y - visarea.min_y + 1; -+ game->width = game->orientation?h:w; -+ game->height = game->orientation?w:h; -+ } -+ -+ game->refresh = ATTOSECONDS_TO_HZ(screen->refresh_attoseconds()); -+ -+ // Check for multiple screens -+ screen_device_iterator iter(config.root_device()); -+ game->screens = iter.count(); -+} -+ -+//============================================================ -+// effective_orientation -+//============================================================ -+ -+bool effective_orientation(running_machine &machine) -+{ -+ config_settings *cs = &machine.switchres.cs; -+ const game_driver *game = &machine.system(); -+ emu_options &options = machine.options(); -+ render_target *target = machine.render().first_target(); -+ bool game_orientation = ((game->flags & machine_flags::MASK_ORIENTATION) & ORIENTATION_SWAP_XY); -+ -+ if (target) -+ cs->monitor_orientation = ((target->orientation() & machine_flags::MASK_ORIENTATION) & ORIENTATION_SWAP_XY? 1:0) ^ cs->desktop_rotated; -+ else if (!strcmp(options.orientation(), "horizontal")) -+ cs->monitor_orientation = 0; -+ else if (!strcmp(options.orientation(), "vertical")) -+ cs->monitor_orientation = 1; -+ else if (!strcmp(options.orientation(), "rotate") || !strcmp(options.orientation(), "rotate_r")) -+ { -+ cs->monitor_orientation = game_orientation; -+ cs->monitor_rotates_cw = 0; -+ } -+ else if (!strcmp(options.orientation(), "rotate_l")) -+ { -+ cs->monitor_orientation = game_orientation; -+ cs->monitor_rotates_cw = 1; -+ } -+ -+ return game_orientation ^ cs->monitor_orientation; -+} -+ -+//============================================================ -+// switchres_check_resolution_change -+//============================================================ -+ -+bool switchres_check_resolution_change(running_machine &machine) -+{ -+ game_info *game = &machine.switchres.game; -+ config_settings *cs = &machine.switchres.cs; -+ -+ int new_width = game->width; -+ int new_height = game->height; -+ float new_vfreq = game->refresh; -+ bool new_orientation = effective_orientation(machine); -+ -+ screen_device_iterator scriter(machine.root_device()); -+ if (scriter.count()) -+ { -+ screen_device *screen = scriter.first(); -+ if (screen->frame_number()) -+ { -+ const rectangle &visarea = screen->visible_area(); -+ new_width = new_orientation? visarea.height() : visarea.width(); -+ new_height = new_orientation? visarea.width() : visarea.height(); -+ new_vfreq = ATTOSECONDS_TO_HZ(screen->frame_period().m_attoseconds); -+ } -+ } -+ -+ if (game->width != new_width || game->height != new_height || new_vfreq != game->refresh || cs->effective_orientation != new_orientation) -+ { -+ osd_printf_verbose("SwitchRes: Resolution change from %dx%d@%f %s to %dx%d@%f %s\n", -+ game->width, game->height, game->refresh, cs->effective_orientation?"rotated":"normal", new_width, new_height, new_vfreq, new_orientation?"rotated":"normal"); -+ -+ game->width = new_width; -+ game->height = new_height; -+ game->refresh = new_vfreq; -+ -+ return true; -+ } -+ return false; -+} -+ -+//============================================================ -+// switchres_set_options -+//============================================================ -+ -+void switchres_set_options(running_machine &machine) -+{ -+ config_settings *cs = &machine.switchres.cs; -+ bool native_orientation = ((machine.system().flags & machine_flags::MASK_ORIENTATION) & ORIENTATION_SWAP_XY); -+ bool must_rotate = effective_orientation(machine) ^ cs->desktop_rotated; -+ modeline *best_mode = &machine.switchres.best_mode; -+ -+ // Set rotation options -+ set_option(machine, OPTION_ROTATE, true); -+ if (cs->monitor_rotates_cw) -+ { -+ set_option(machine, OPTION_ROL, (!native_orientation & must_rotate)); -+ set_option(machine, OPTION_AUTOROL, !must_rotate); -+ set_option(machine, OPTION_ROR, false); -+ set_option(machine, OPTION_AUTOROR, false); -+ } -+ else -+ { -+ set_option(machine, OPTION_ROR, (!native_orientation & must_rotate)); -+ set_option(machine, OPTION_AUTOROR, !must_rotate); -+ set_option(machine, OPTION_ROL, false); -+ set_option(machine, OPTION_AUTOROL, false); -+ } -+ -+ // Set scaling/stretching options -+ set_option(machine, OPTION_KEEPASPECT, true); -+ set_option(machine, OPTION_UNEVENSTRETCH, best_mode->result.weight & R_RES_STRETCH); -+ set_option(machine, OPTION_UNEVENSTRETCHX, (!(best_mode->result.weight & R_RES_STRETCH) && (best_mode->width >= machine.options().super_width()))); -+ -+ // Update target if it's already initialized -+ render_target *target = machine.render().first_target(); -+ if (target) -+ { -+ if (machine.options().uneven_stretch()) -+ target->set_scale_mode(SCALE_FRACTIONAL); -+ else if(machine.options().uneven_stretch_x()) -+ target->set_scale_mode(SCALE_FRACTIONAL_X); -+ else if(machine.options().uneven_stretch_y()) -+ target->set_scale_mode(SCALE_FRACTIONAL_Y); -+ else -+ target->set_scale_mode(SCALE_INTEGER); -+ } -+} -+ -+//============================================================ -+// set_option - option setting wrapper -+//============================================================ -+ -+void set_option(running_machine &machine, const char *option_ID, bool state) -+{ -+ emu_options &options = machine.options(); -+ -+ options.set_value(option_ID, state, OPTION_PRIORITY_SWITCHRES); -+ osd_printf_verbose("SwitchRes: Setting option -%s%s\n", machine.options().bool_value(option_ID)?"":"no", option_ID); -+} -diff --git a/src/emu/switchres/switchres.h b/src/emu/switchres/switchres.h -new file mode 100644 -index 00000000000..b162ed70125 ---- /dev/null -+++ b/src/emu/switchres/switchres.h -@@ -0,0 +1,80 @@ -+/************************************************************** -+ -+ switchres.h - SwichRes general header -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+#ifndef __SWITCHRES_H__ -+#define __SWITCHRES_H__ -+ -+//============================================================ -+// CONSTANTS -+//============================================================ -+ -+#define SWITCHRES_VERSION "0.017p" -+ -+//============================================================ -+// TYPE DEFINITIONS -+//============================================================ -+ -+typedef struct game_info -+{ -+ char name[32]; -+ int width; -+ int height; -+ float refresh; -+ bool orientation; -+ bool vector; -+ bool changeres; -+ int screens; -+} game_info; -+ -+typedef struct config_settings -+{ -+ char connector[32]; -+ char monitor[32]; -+ bool modeline_generation; -+ bool monitor_orientation; -+ bool effective_orientation; -+ bool desktop_rotated; -+ bool monitor_rotates_cw; -+ float monitor_aspect; -+ int monitor_count; -+ int pclock_min; -+ int pclock_align; -+ int interlace; -+ int doublescan; -+ int width; -+ int height; -+ int refresh; -+ int super_width; -+ bool lock_unsupported_modes; -+ bool lock_system_modes; -+ bool refresh_dont_care; -+ float sync_refresh_tolerance; -+} config_settings; -+ -+#include "monitor.h" -+#include "modeline.h" -+ -+typedef struct switchres_manager -+{ -+ struct config_settings cs; -+ struct game_info game; -+ struct modeline best_mode; -+ struct modeline user_mode; -+ struct monitor_range range[MAX_RANGES]; -+ struct modeline video_modes[MAX_MODELINES]; -+} switchres; -+ -+#endif -diff --git a/src/emu/switchres/switchres_proto.h b/src/emu/switchres/switchres_proto.h -new file mode 100644 -index 00000000000..de9185e6810 ---- /dev/null -+++ b/src/emu/switchres/switchres_proto.h -@@ -0,0 +1,42 @@ -+/************************************************************** -+ -+ switchres_proto.h - SwichRes prototypes header -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+#ifndef __SWITCHRES_H_PROTO__ -+#define __SWITCHRES_H_PROTO__ -+ -+//============================================================ -+// PROTOTYPES -+//============================================================ -+ -+// util.cpp -+int normalize(int a, int b); -+int real_res(int x); -+ -+// switchres.cpp -+bool switchres_get_video_mode(running_machine &machine); -+int switchres_get_monitor_specs(running_machine &machine); -+void switchres_init(running_machine &machine); -+void switchres_get_game_info(running_machine &machine); -+bool switchres_check_resolution_change(running_machine &machine); -+void switchres_set_options(running_machine &machine); -+bool effective_orientation(running_machine &machine); -+ -+// OSD - switchres.cpp -+bool switchres_init_osd(running_machine &machine); -+bool switchres_modeline_setup(running_machine &machine); -+bool switchres_modeline_remove(running_machine &machine); -+ -+#endif -diff --git a/src/emu/switchres/util.cpp b/src/emu/switchres/util.cpp -new file mode 100644 -index 00000000000..c0def9124d0 ---- /dev/null -+++ b/src/emu/switchres/util.cpp -@@ -0,0 +1,34 @@ -+/************************************************************** -+ -+ util.cpp - Utility functions -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+//============================================================ -+// normalize -+//============================================================ -+ -+int normalize(int a, int b) -+{ -+ int c, d; -+ c = a % b; -+ d = a / b; -+ if (c) d++; -+ return d * b; -+} -+ -+//============================================================ -+// real_res -+//============================================================ -+ -+int real_res(int x) {return (int) (x / 8) * 8;} -diff --git a/src/emu/video.cpp b/src/emu/video.cpp -index 8da14f03b85..5deeb91d39f 100644 ---- a/src/emu/video.cpp -+++ b/src/emu/video.cpp -@@ -51,7 +51,7 @@ const bool video_manager::s_skiptable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS] = - { false, true , true , true , true , true , true , true , true , true , true , true } - }; - -- -+int video_manager::s_fd_speeds[FD_BINS] = { 0,0,0,0,0,0,0,0,0,0 }; - - //************************************************************************** - // VIDEO MANAGER -@@ -86,6 +86,8 @@ video_manager::video_manager(running_machine &machine) - , m_overall_valid_counter(0) - , m_throttled(machine.options().throttle()) - , m_throttle_rate(1.0f) -+ , m_syncrefresh(machine.options().sync_refresh()) -+ , m_framedelay(machine.options().frame_delay()) - , m_fastforward(false) - , m_seconds_to_run(machine.options().seconds_to_run()) - , m_auto_frameskip(machine.options().auto_frameskip()) -@@ -237,6 +239,14 @@ void video_manager::frame_update(bool from_debugger) - machine().osd().update(!from_debugger && skipped_it); - g_profiler.stop(); - -+ // manage black frame insertion -+ if (machine().options().black_frame_insertion() && machine().options().sync_refresh()) -+ { -+ render_container *container = &machine().render().ui_container(); -+ container->add_rect(0, 0, 1, 1, 0xff000000, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); -+ machine().osd().update(!from_debugger && skipped_it); -+ } -+ - // we synchronize after rendering instead of before, if low latency mode is enabled - if (!from_debugger && !skipped_it && m_low_latency && effective_throttle()) - update_throttle(current_time); -@@ -523,6 +533,23 @@ void video_manager::exit() - osd_ticks_t tps = osd_ticks_per_second(); - double final_real_time = (double)m_overall_real_seconds + (double)m_overall_real_ticks / (double)tps; - double final_emu_time = m_overall_emutime.as_double(); -+ -+ if (!m_throttled) -+ { -+ int i; -+ float sum = 0; -+ -+ osd_printf_info("Frame delay/percentage:"); -+ -+ for (i = 0; i < FD_BINS; i++) -+ sum += s_fd_speeds[i]; -+ -+ for (i = 0; i < FD_BINS; i++) -+ if (s_fd_speeds[i]) -+ osd_printf_info(" %d/%.2f%%", i, (float) s_fd_speeds[i] / sum * 100.f); -+ osd_printf_info("\n"); -+ } -+ - osd_printf_info("Average speed: %.2f%% (%d seconds)\n", 100 * final_emu_time / final_real_time, (m_overall_emutime + attotime(0, ATTOSECONDS_PER_SECOND / 2)).seconds()); - } - } -@@ -728,6 +755,20 @@ void video_manager::update_throttle(attotime emutime) - 3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7, 4,5,5,6,5,6,6,7, 5,6,6,7,6,7,7,8 - }; - -+ // if we're only syncing to the refresh, bail now -+ if (m_syncrefresh) -+ { -+ modeline *mode = &machine().switchres.best_mode; -+ if (m_framedelay == 0 || m_framedelay > 9 || mode->hactive == 0) -+ return; -+ -+ osd_ticks_t now = osd_ticks(); -+ osd_ticks_t ticks_per_second = osd_ticks_per_second(); -+ attoseconds_t attoseconds_per_tick = ATTOSECONDS_PER_SECOND / ticks_per_second * m_throttle_rate; -+ throttle_until_ticks(now + HZ_TO_ATTOSECONDS(mode->vfreq / mode->result.v_scale) / attoseconds_per_tick * m_framedelay / 10); -+ return; -+ } -+ - // outer scope so we can break out in case of a resync - while (1) - { -@@ -999,6 +1040,21 @@ void video_manager::recompute_speed(const attotime &emutime) - osd_ticks_t tps = osd_ticks_per_second(); - m_speed_percent = delta_emutime.as_double() * (double)tps / (double)delta_realtime; - -+ // adjust speed for audio resampling -+ if (m_syncrefresh && m_throttled) -+ { -+ if (m_speed_percent >= 0.8 && m_speed_percent <= 1.2) -+ m_speed = m_speed_percent * 1000; -+ } -+ -+ // log speed for frame delay statistic -+ if (!m_throttled) -+ { -+ int bin = (float) FD_BINS - 10.f/m_speed_percent; -+ bin = bin > (FD_BINS - 1) ? (FD_BINS - 1) : bin < 0 ? 0 : bin; -+ s_fd_speeds[bin]++; -+ } -+ - // remember the last times - m_speed_last_realtime = realtime; - m_speed_last_emutime = emutime; -diff --git a/src/emu/video.h b/src/emu/video.h -index 2fe7786afb5..f205fa7fa62 100644 ---- a/src/emu/video.h -+++ b/src/emu/video.h -@@ -28,6 +28,7 @@ - constexpr int FRAMESKIP_LEVELS = 12; - constexpr int MAX_FRAMESKIP = FRAMESKIP_LEVELS - 2; - -+constexpr int FD_BINS = 10; - - //************************************************************************** - // TYPE DEFINITIONS -@@ -50,6 +51,8 @@ public: - int frameskip() const { return m_auto_frameskip ? -1 : m_frameskip_level; } - bool throttled() const { return m_throttled; } - float throttle_rate() const { return m_throttle_rate; } -+ bool sync_refresh() const { return m_syncrefresh; } -+ int32_t framedelay() const { return m_framedelay; } - bool fastforward() const { return m_fastforward; } - bool is_recording() const; - -@@ -59,6 +62,7 @@ public: - void set_throttle_rate(float throttle_rate) { m_throttle_rate = throttle_rate; } - void set_fastforward(bool ffwd = true) { m_fastforward = ffwd; } - void set_output_changed() { m_output_changed = true; } -+ void set_framedelay(int framedelay) { m_framedelay = framedelay; } - - // misc - void toggle_throttle(); -@@ -148,6 +152,8 @@ private: - // configuration - bool m_throttled; // flag: true if we're currently throttled - float m_throttle_rate; // target rate for throttling -+ bool m_syncrefresh; // flag: TRUE if we're currently refresh-synced -+ int32_t m_framedelay; // tenths of frame to delay emulation start - bool m_fastforward; // flag: true if we're currently fast-forwarding - u32 m_seconds_to_run; // number of seconds to run before quitting - bool m_auto_frameskip; // flag: true if we're automatically frameskipping -@@ -172,6 +178,9 @@ private: - // movie recordings - std::vector<movie_recording::ptr> m_movie_recordings; - -+ // frame delay statistics -+ static int s_fd_speeds[FD_BINS]; -+ - static const bool s_skiptable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS]; - - static const attoseconds_t ATTOSECONDS_PER_SPEED_UPDATE = ATTOSECONDS_PER_SECOND / 4; -diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp -index aa5ec7606b8..f93231fa84b 100644 ---- a/src/frontend/mame/clifront.cpp -+++ b/src/frontend/mame/clifront.cpp -@@ -1732,6 +1732,7 @@ - osd_printf_info( - "%3$s v%2$s\n" - "%5$s\n" -+ "GroovyMAME - SwitchRes version %6$s\n" - "\n" - "This software reproduces, more or less faithfully, the behaviour of a wide range\n" - "of machines. But hardware is useless without software, so images of the ROMs and\n" -@@ -1749,5 +1750,6 @@ - build_version, - emulator_info::get_appname(), - emulator_info::get_configname(), -- emulator_info::get_copyright_info()); -+ emulator_info::get_copyright_info(), -+ SWITCHRES_VERSION); - } -diff --git a/src/frontend/mame/mameopts.h b/src/frontend/mame/mameopts.h -index 2b178fb2ead..502d20f76d0 100644 ---- a/src/frontend/mame/mameopts.h -+++ b/src/frontend/mame/mameopts.h -@@ -29,6 +29,7 @@ enum - - // INI-based options are NORMAL priority, in increasing order: - OPTION_PRIORITY_MAME_INI = OPTION_PRIORITY_NORMAL + 1, -+ OPTION_PRIORITY_SWITCHRES, - OPTION_PRIORITY_DEBUG_INI, - OPTION_PRIORITY_ORIENTATION_INI, - OPTION_PRIORITY_SYSTYPE_INI, -diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp -index 76b2f012731..dc6bf8532a6 100644 ---- a/src/frontend/mame/ui/info.cpp -+++ b/src/frontend/mame/ui/info.cpp -@@ -420,6 +420,15 @@ std::string machine_info::game_info_string() const - } - } - -+ // display SwitchRes information -+ modeline *mode = &m_machine.switchres.best_mode; -+ if (mode->hactive) -+ { -+ buf << _("\nSwitchres:\n"); -+ util::stream_format(buf, "%d " UTF8_MULTIPLY " %d%s%s %2.3f Hz %2.3f kHz\n", -+ mode->hactive, mode->vactive, mode->interlace?"i":"p", mode->doublescan?"d":"", mode->vfreq, mode->hfreq/1000); -+ } -+ - return buf.str(); - } - -diff --git a/src/frontend/mame/ui/submenu.cpp b/src/frontend/mame/ui/submenu.cpp -index 207ac56d057..efee8fc4047 100644 ---- a/src/frontend/mame/ui/submenu.cpp -+++ b/src/frontend/mame/ui/submenu.cpp -@@ -107,7 +107,7 @@ std::vector<submenu::option> const submenu::video_options = { - { submenu::option_type::OSD, __("Window Mode"), OSDOPTION_WINDOW }, - { submenu::option_type::EMU, __("Enforce Aspect Ratio"), OPTION_KEEPASPECT }, - { submenu::option_type::OSD, __("Start Out Maximized"), OSDOPTION_MAXIMIZE }, -- { submenu::option_type::OSD, __("Synchronized Refresh"), OSDOPTION_SYNCREFRESH }, -+ { submenu::option_type::OSD, __("Synchronized Refresh"), OPTION_SYNCREFRESH }, - { submenu::option_type::OSD, __("Wait Vertical Sync"), OSDOPTION_WAITVSYNC } - }; - -diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp -index bfcfd10bd97..885e8a825a0 100644 ---- a/src/frontend/mame/ui/ui.cpp -+++ b/src/frontend/mame/ui/ui.cpp -@@ -31,6 +31,7 @@ - #include "ui/viewgfx.h" - #include "imagedev/cassette.h" - #include "../osd/modules/lib/osdobj_common.h" -+#include "config.h" - - - /*************************************************************************** -@@ -193,6 +194,9 @@ void mame_ui_manager::init() - // request a callback upon exiting - machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&mame_ui_manager::exit, this)); - -+ // register callbacks -+ machine().configuration().config_register("sliders", config_load_delegate(&mame_ui_manager::config_load, this), config_save_delegate(&mame_ui_manager::config_save, this)); -+ - // create mouse bitmap - uint32_t *dst = &m_mouse_bitmap.pix32(0); - memcpy(dst,mouse_bitmap,32*32*sizeof(uint32_t)); -@@ -1351,6 +1355,9 @@ std::vector<ui::menu_item> mame_ui_manager::slider_init(running_machine &machine - // add overall volume - m_sliders.push_back(slider_alloc(SLIDER_ID_VOLUME, _("Master Volume"), -32, 0, 0, 1, nullptr)); - -+ // add frame delay -+ m_sliders.push_back(slider_alloc(SLIDER_ID_FRAMEDELAY, _("Frame Delay"), 0, machine.options().frame_delay(), 9, 1, nullptr)); -+ - // add per-channel volume - mixer_input info; - for (int item = 0; machine.sound().indexed_mixer_input(item, info); item++) -@@ -1495,6 +1502,8 @@ std::vector<ui::menu_item> mame_ui_manager::slider_init(running_machine &machine - } - #endif - -+ config_apply(); -+ - std::vector<ui::menu_item> items; - for (auto &slider : m_sliders) - { -@@ -1518,6 +1527,8 @@ int32_t mame_ui_manager::slider_changed(running_machine &machine, void *arg, int - { - if (id == SLIDER_ID_VOLUME) - return slider_volume(machine, arg, id, str, newval); -+ else if (id == SLIDER_ID_FRAMEDELAY) -+ return slider_framedelay(machine, arg, id, str, newval); - else if (id >= SLIDER_ID_MIXERVOL && id <= SLIDER_ID_MIXERVOL_LAST) - return slider_mixervol(machine, arg, id, str, newval); - else if (id >= SLIDER_ID_ADJUSTER && id <= SLIDER_ID_ADJUSTER_LAST) -@@ -1581,6 +1592,21 @@ int32_t mame_ui_manager::slider_volume(running_machine &machine, void *arg, int - } - - -+//------------------------------------------------- -+// slider_framedelay - global frame delay slider -+// callback -+//------------------------------------------------- -+ -+int32_t mame_ui_manager::slider_framedelay(running_machine &machine, void *arg, int id, std::string *str, int32_t newval) -+{ -+ if (newval != SLIDER_NOCHANGE) -+ machine.video().set_framedelay(newval); -+ if (str) -+ *str = string_format(_("%1$3d"), machine.video().framedelay()); -+ return machine.video().framedelay(); -+} -+ -+ - //------------------------------------------------- - // slider_mixervol - single channel volume - // slider callback -@@ -2198,3 +2224,83 @@ void ui_colors::refresh(const ui_options &options) - m_dipsw_color = options.dipsw_color(); - m_slider_color = options.slider_color(); - } -+ -+//------------------------------------------------- -+// config_load - read data from the -+// configuration file -+//------------------------------------------------- -+ -+void mame_ui_manager::config_load(config_type cfg_type, util::xml::data_node const *parentnode) -+{ -+ // we only care about game files -+ if (cfg_type != config_type::GAME) -+ return; -+ -+ // might not have any data -+ if (parentnode == nullptr) -+ return; -+ -+ // iterate over slider nodes -+ for (util::xml::data_node const *slider_node = parentnode->get_child("slider"); slider_node; slider_node = slider_node->get_next_sibling("slider")) -+ { -+ const char *desc = slider_node->get_attribute_string("desc", ""); -+ int32_t saved_val = slider_node->get_attribute_int("value", 0); -+ -+ // create a dummy slider to store the saved value -+ m_sliders_saved.push_back(slider_alloc(0, desc, 0, saved_val, 0, 0, 0)); -+ } -+} -+ -+ -+//------------------------------------------------- -+// config_appy - apply data from the conf. file -+// This currently needs to be done on a separate -+// step because sliders are not created yet when -+// configuration file is loaded -+//------------------------------------------------- -+ -+void mame_ui_manager::config_apply(void) -+{ -+ // iterate over sliders and restore saved values -+ for (auto &slider : m_sliders) -+ { -+ for (auto &slider_saved : m_sliders_saved) -+ { -+ if (!strcmp(slider->description.c_str(), slider_saved->description.c_str())) -+ { -+ std::string tempstring; -+ slider->update(machine(), slider->arg, slider->id, &tempstring, slider_saved->defval); -+ break; -+ -+ } -+ } -+ } -+} -+ -+ -+//------------------------------------------------- -+// config_save - save data to the configuration -+// file -+//------------------------------------------------- -+ -+void mame_ui_manager::config_save(config_type cfg_type, util::xml::data_node *parentnode) -+{ -+ // we only care about game files -+ if (cfg_type != config_type::GAME) -+ return; -+ -+ std::string tempstring; -+ util::xml::data_node *slider_node; -+ -+ // save UI sliders -+ for (auto &slider : m_sliders) -+ { -+ int32_t curval = slider->update(machine(), slider->arg, slider->id, &tempstring, SLIDER_NOCHANGE); -+ if (curval != slider->defval) -+ { -+ slider_node = parentnode->add_child("slider", nullptr); -+ slider_node->set_attribute("desc", slider->description.c_str()); -+ slider_node->set_attribute_int("value", curval); -+ } -+ } -+} -\ No newline at end of file -diff --git a/src/frontend/mame/ui/ui.h b/src/frontend/mame/ui/ui.h -index 71f6a5ab8b8..f4ae6e2c962 100644 ---- a/src/frontend/mame/ui/ui.h -+++ b/src/frontend/mame/ui/ui.h -@@ -53,6 +53,7 @@ class machine_info; - enum - { - SLIDER_ID_VOLUME = 0, -+ SLIDER_ID_FRAMEDELAY, - SLIDER_ID_MIXERVOL, - SLIDER_ID_MIXERVOL_LAST = SLIDER_ID_MIXERVOL + SLIDER_DEVICE_SPACING, - SLIDER_ID_ADJUSTER, -@@ -234,6 +235,11 @@ public: - void start_save_state(); - void start_load_state(); - -+ // config callbacks -+ void config_load(config_type cfg_type, util::xml::data_node const *parentnode); -+ void config_save(config_type cfg_type, util::xml::data_node *parentnode); -+ void config_apply(void); -+ - // slider controls - std::vector<ui::menu_item>& get_slider_list(void); - -@@ -300,6 +306,7 @@ private: - virtual int32_t slider_changed(running_machine &machine, void *arg, int id, std::string *str, int32_t newval) override; - - int32_t slider_volume(running_machine &machine, void *arg, int id, std::string *str, int32_t newval); -+ int32_t slider_framedelay(running_machine &machine, void *arg, int id, std::string *str, int32_t newval); - int32_t slider_mixervol(running_machine &machine, void *arg, int id, std::string *str, int32_t newval); - int32_t slider_adjuster(running_machine &machine, void *arg, int id, std::string *str, int32_t newval); - int32_t slider_overclock(running_machine &machine, void *arg, int id, std::string *str, int32_t newval); -@@ -326,6 +333,7 @@ private: - #endif - - std::vector<std::unique_ptr<slider_state>> m_sliders; -+ std::vector<std::unique_ptr<slider_state>> m_sliders_saved; - }; - - -diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp -index 25d4b979e87..6f7c512dcc3 100644 ---- a/src/osd/modules/lib/osdobj_common.cpp -+++ b/src/osd/modules/lib/osdobj_common.cpp -@@ -59,7 +59,6 @@ const options_entry osd_options::s_option_entries[] = - { OSDOPTION_WINDOW ";w", "0", OPTION_BOOLEAN, "enable window mode; otherwise, full screen mode is assumed" }, - { OSDOPTION_MAXIMIZE ";max", "1", OPTION_BOOLEAN, "default to maximized windows" }, - { OSDOPTION_WAITVSYNC ";vs", "0", OPTION_BOOLEAN, "enable waiting for the start of VBLANK before flipping screens (reduces tearing effects)" }, -- { OSDOPTION_SYNCREFRESH ";srf", "0", OPTION_BOOLEAN, "enable using the start of VBLANK for throttling instead of the game time" }, - { OSD_MONITOR_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "monitor discovery method: " }, - - // per-window options -@@ -91,10 +90,10 @@ const options_entry osd_options::s_option_entries[] = - - // full screen options - { nullptr, nullptr, OPTION_HEADER, "OSD FULL SCREEN OPTIONS" }, -- { OSDOPTION_SWITCHRES, "0", OPTION_BOOLEAN, "enable resolution switching" }, -+ { OSDOPTION_SWITCHRES, "1", OPTION_BOOLEAN, "enable resolution switching" }, - - { nullptr, nullptr, OPTION_HEADER, "OSD ACCELERATED VIDEO OPTIONS" }, -- { OSDOPTION_FILTER ";glfilter;flt", "1", OPTION_BOOLEAN, "use bilinear filtering when scaling emulated video" }, -+ { OSDOPTION_FILTER ";glfilter;flt", "0", OPTION_BOOLEAN, "use bilinear filtering when scaling emulated video" }, - { OSDOPTION_PRESCALE "(1-8)", "1", OPTION_INTEGER, "scale emulated video by this factor before applying filters/shaders" }, - - #if USE_OPENGL -@@ -129,7 +128,7 @@ const options_entry osd_options::s_option_entries[] = - - { nullptr, nullptr, OPTION_HEADER, "OSD SOUND OPTIONS" }, - { OSDOPTION_SOUND, OSDOPTVAL_AUTO, OPTION_STRING, "sound output method: " }, -- { OSDOPTION_AUDIO_LATENCY "(1-5)", "2", OPTION_INTEGER, "set audio latency (increase to reduce glitches, decrease for responsiveness)" }, -+ { OSDOPTION_AUDIO_LATENCY "(0.1-5.0)", "2.0", OPTION_FLOAT, "set audio latency (increase to reduce glitches, decrease for responsiveness)" }, - - #ifndef NO_USE_PORTAUDIO - { nullptr, nullptr, OPTION_HEADER, "PORTAUDIO OPTIONS" }, -diff --git a/src/osd/modules/lib/osdobj_common.h b/src/osd/modules/lib/osdobj_common.h -index 9fb1b1eef6b..756b15f1b0a 100644 ---- a/src/osd/modules/lib/osdobj_common.h -+++ b/src/osd/modules/lib/osdobj_common.h -@@ -50,7 +50,6 @@ - #define OSDOPTION_WINDOW "window" - #define OSDOPTION_MAXIMIZE "maximize" - #define OSDOPTION_WAITVSYNC "waitvsync" --#define OSDOPTION_SYNCREFRESH "syncrefresh" - - #define OSDOPTION_SCREEN "screen" - #define OSDOPTION_ASPECT "aspect" -@@ -122,7 +121,6 @@ public: - bool window() const { return bool_value(OSDOPTION_WINDOW); } - bool maximize() const { return bool_value(OSDOPTION_MAXIMIZE); } - bool wait_vsync() const { return bool_value(OSDOPTION_WAITVSYNC); } -- bool sync_refresh() const { return bool_value(OSDOPTION_SYNCREFRESH); } - - // per-window options - const char *screen() const { return value(OSDOPTION_SCREEN); } -@@ -153,7 +151,7 @@ public: - - // sound options - const char *sound() const { return value(OSDOPTION_SOUND); } -- int audio_latency() const { return int_value(OSDOPTION_AUDIO_LATENCY); } -+ float audio_latency() const { return float_value(OSDOPTION_AUDIO_LATENCY); } - - // CoreAudio specific options - const char *audio_output() const { return value(OSDOPTION_AUDIO_OUTPUT); } -diff --git a/src/osd/modules/osdwindow.h b/src/osd/modules/osdwindow.h -index 3fe020c56fe..6479d544e43 100644 ---- a/src/osd/modules/osdwindow.h -+++ b/src/osd/modules/osdwindow.h -@@ -215,9 +215,13 @@ public: - virtual void record() { }; - virtual void toggle_fsfx() { }; - virtual bool sliders_dirty() { return m_sliders_dirty; } -+ virtual int restart() { return 0; } - - static std::unique_ptr<osd_renderer> make_for_type(int mode, std::shared_ptr<osd_window> window, int extra_flags = FLAG_NONE); - -+ // SwitchRes mode -+ modeline * m_switchres_mode; -+ - protected: - virtual void build_slider_list() { } - -@@ -262,6 +266,7 @@ struct osd_video_config - int waitvsync; // spin until vsync - int syncrefresh; // sync only to refresh rate - int switchres; // switch resolutions -+ int framedelay; // frame delay - - // d3d, accel, opengl - int filter; // enable filtering -diff --git a/src/osd/modules/render/d3d/d3dhlsl.h b/src/osd/modules/render/d3d/d3dhlsl.h -index 7f7dacc4538..e700a36f36f 100644 ---- a/src/osd/modules/render/d3d/d3dhlsl.h -+++ b/src/osd/modules/render/d3d/d3dhlsl.h -@@ -302,7 +302,7 @@ public: - - bool init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *renderer); - -- bool enabled() { return post_fx_enable && d3dintf->post_fx_available; } -+ bool enabled() { return (this != nullptr) && post_fx_enable && d3dintf->post_fx_available; } - void toggle() { post_fx_enable = initialized && !post_fx_enable; } - - void begin_draw(); -diff --git a/src/osd/modules/render/drawd3d.cpp b/src/osd/modules/render/drawd3d.cpp -index 56c905636a4..2d503662083 100644 ---- a/src/osd/modules/render/drawd3d.cpp -+++ b/src/osd/modules/render/drawd3d.cpp -@@ -45,7 +45,7 @@ enum - // INLINES - //============================================================ - --static inline BOOL GetClientRectExceptMenu(HWND hWnd, PRECT pRect, BOOL fullscreen) -+inline BOOL renderer_d3d9::GetClientRectExceptMenu(HWND hWnd, PRECT pRect, BOOL fullscreen) - { - static HMENU last_menu; - static RECT last_rect; -@@ -53,6 +53,12 @@ static inline BOOL GetClientRectExceptMenu(HWND hWnd, PRECT pRect, BOOL fullscre - HMENU menu = GetMenu(hWnd); - BOOL result = GetClientRect(hWnd, pRect); - -+ if (m_switchres_mode && m_switchres_mode->hactive) -+ { -+ pRect->right = m_switchres_mode->type & MODE_ROTATED? m_switchres_mode->vactive : m_switchres_mode->hactive; -+ pRect->bottom = m_switchres_mode->type & MODE_ROTATED? m_switchres_mode->hactive : m_switchres_mode->vactive; -+ } -+ - if (!fullscreen || !menu) - return result; - -@@ -184,7 +190,14 @@ render_primitive_list *renderer_d3d9::get_primitives() - GetClientRectExceptMenu(hWnd, &client, win->fullscreen()); - if (rect_width(&client) > 0 && rect_height(&client) > 0) - { -- win->target()->set_bounds(rect_width(&client), rect_height(&client), win->pixel_aspect()); -+ // handle aspect correction for magic resolutions -+ float aspect_corrector = 1.0f; -+ if (m_switchres_mode && m_switchres_mode->hactive) -+ { -+ aspect_corrector = ((float)m_switchres_mode->width / (float)m_switchres_mode->height) / ((float)m_switchres_mode->hactive / (float)m_switchres_mode->vactive); -+ if (m_switchres_mode->type & MODE_ROTATED) aspect_corrector = 1.0 / aspect_corrector; -+ } -+ win->target()->set_bounds(rect_width(&client), rect_height(&client), win->pixel_aspect() * aspect_corrector); - win->target()->set_max_update_rate((get_refresh() == 0) ? get_origmode().RefreshRate : get_refresh()); - } - if (m_shaders != nullptr) -@@ -733,12 +746,111 @@ void renderer_d3d9::end_frame() - if (FAILED(result)) - osd_printf_verbose("Direct3D: Error %08lX during device end_scene call\n", result); - -+ if (m_frame_delay != video_config.framedelay) -+ { -+ m_frame_delay = video_config.framedelay; -+ update_break_scanlines(); -+ } -+ -+ D3DRASTER_STATUS raster_status; -+ memset (&raster_status, 0, sizeof(D3DRASTER_STATUS)); -+ -+ // sync to VBLANK-BEGIN -+ if (video_config.framedelay && video_config.syncrefresh) -+ { -+ // check if retrace has been missed -+ if (m_device->GetRasterStatus(0, &raster_status) == D3D_OK) -+ { -+ if (raster_status.ScanLine < m_delay_scanline && !raster_status.InVBlank) -+ { -+ static const double tps = (double)osd_ticks_per_second(); -+ static const double time_start = (double)osd_ticks() / tps; -+ osd_printf_verbose("renderer::end_frame(), probably missed retrace, entered at scanline %d, should break at %d, realtime is %f.\n", raster_status.ScanLine, m_break_scanline, (double)osd_ticks() / tps - time_start); -+ } -+ } -+ -+ do -+ { -+ if (m_device->GetRasterStatus(0, &raster_status) != D3D_OK) -+ break; -+ } while (!raster_status.InVBlank && raster_status.ScanLine < m_break_scanline); -+ } -+ - // present the current buffers - result = m_device->Present(nullptr, nullptr, nullptr, nullptr); - if (FAILED(result)) - osd_printf_verbose("Direct3D: Error %08lX during device present call\n", result); -+ -+ // sync to VBLANK-END -+ if (video_config.framedelay && video_config.syncrefresh) -+ { -+ do -+ { -+ if (m_device->GetRasterStatus(0, &raster_status) != D3D_OK) -+ break; -+ } while (!raster_status.InVBlank); -+ } -+} -+ -+void renderer_d3d9::device_flush() -+{ -+ HRESULT result; -+ -+ if(m_device) -+ { -+ if(m_query != nullptr) -+ { -+ m_query->Issue(D3DISSUE_END); -+ do -+ { -+ result = m_query->GetData(NULL, 0, D3DGETDATA_FLUSH); -+ if (result == D3DERR_DEVICELOST) -+ return; -+ } while(result == S_FALSE); -+ } -+ } -+} -+ -+void renderer_d3d9::update_break_scanlines() -+{ -+ switch (m_vendor_id) -+ { -+ case 0x1002: // ATI -+ m_first_scanline = m_switchres_mode && m_switchres_mode->vtotal ? -+ (m_switchres_mode->vtotal - m_switchres_mode->vbegin) / (m_switchres_mode->interlace ? 2 : 1) : -+ 1; -+ -+ m_last_scanline = m_switchres_mode && m_switchres_mode->vtotal ? -+ m_switchres_mode->vactive + (m_switchres_mode->vtotal - m_switchres_mode->vbegin) / (m_switchres_mode->interlace ? 2 : 1) : -+ m_height; -+ break; -+ -+ case 0x8086: // Intel -+ m_first_scanline = 1; -+ -+ m_last_scanline = m_switchres_mode && m_switchres_mode->vtotal ? -+ m_switchres_mode->vactive / (m_switchres_mode->interlace ? 2 : 1) : -+ m_height; -+ break; -+ -+ default: // NVIDIA (0x10DE) + others (?) -+ m_first_scanline = 0; -+ -+ m_last_scanline = m_switchres_mode && m_switchres_mode->vtotal ? -+ (m_switchres_mode->vactive - 1) / (m_switchres_mode->interlace ? 2 : 1) : -+ m_height - 1; -+ break; -+ } -+ -+ auto win = assert_window(); -+ m_break_scanline = m_last_scanline - win->machine().options().vsync_offset(); -+ m_break_scanline = m_break_scanline > m_first_scanline ? m_break_scanline : m_last_scanline; -+ m_delay_scanline = m_first_scanline + m_height * (float)video_config.framedelay / 10; -+ -+ osd_printf_verbose("Direct3D: Frame delay: %d, First scanline: %d, Last scanline: %d, Break scanline: %d, Delay scanline: %d\n", video_config.framedelay, m_first_scanline, m_last_scanline, m_break_scanline, m_delay_scanline); - } - -+ - void renderer_d3d9::update_presentation_parameters() - { - auto win = assert_window(); -@@ -747,7 +859,7 @@ void renderer_d3d9::update_presentation_parameters() - m_presentation.BackBufferWidth = m_width; - m_presentation.BackBufferHeight = m_height; - m_presentation.BackBufferFormat = m_pixformat; -- m_presentation.BackBufferCount = video_config.triplebuf ? 2 : 1; -+ m_presentation.BackBufferCount = 1; - m_presentation.MultiSampleType = D3DMULTISAMPLE_NONE; - m_presentation.SwapEffect = D3DSWAPEFFECT_DISCARD; - m_presentation.hDeviceWindow = std::static_pointer_cast<win_window_info>(win)->platform_window(); -@@ -756,10 +868,10 @@ void renderer_d3d9::update_presentation_parameters() - m_presentation.AutoDepthStencilFormat = D3DFMT_D16; - m_presentation.Flags = 0; - m_presentation.FullScreen_RefreshRateInHz = m_refresh; -- m_presentation.PresentationInterval = ( -- (video_config.triplebuf && win->fullscreen()) -+ m_presentation.PresentationInterval = (video_config.framedelay == 0 && -+ ((video_config.triplebuf && win->fullscreen()) - || video_config.waitvsync -- || video_config.syncrefresh) -+ || video_config.syncrefresh)) - ? D3DPRESENT_INTERVAL_ONE - : D3DPRESENT_INTERVAL_IMMEDIATE; - } -@@ -1184,6 +1296,34 @@ int renderer_d3d9::device_test_cooperative() - } - - -+//============================================================ -+// restart -+//============================================================ -+ -+int renderer_d3d9::restart() -+{ -+ // free all existing resources -+ device_delete_resources(); -+ -+ // configure new video mode -+ pick_best_mode(); -+ update_presentation_parameters(); -+ -+ // reset the device -+ HRESULT result = m_device->Reset(&m_presentation); -+ if (FAILED(result)) -+ { -+ osd_printf_error("Unable to reset, result %08lX\n", result); -+ return 1; -+ } -+ -+ // create the resources again -+ device_create_resources(); -+ -+ return 0; -+} -+ -+ - //============================================================ - // config_adapter_mode - //============================================================ -@@ -1203,6 +1343,9 @@ int renderer_d3d9::config_adapter_mode() - } - - osd_printf_verbose("Direct3D: Configuring adapter #%d = %s\n", m_adapter, id.Description); -+ osd_printf_verbose("Direct3D: Adapter has Vendor ID: %lX and Device ID: %lX\n", id.VendorId, id.DeviceId); -+ -+ m_vendor_id = id.VendorId; - - // get the current display mode - result = d3dintf->d3dobj->GetAdapterDisplayMode(m_adapter, &m_origmode); -@@ -1219,6 +1362,9 @@ int renderer_d3d9::config_adapter_mode() - { - RECT client; - -+ // Disable SwitchRes -+ m_switchres_mode = 0; -+ - // bounds are from the window client rect - GetClientRectExceptMenu(std::static_pointer_cast<win_window_info>(win)->platform_window(), &client, win->fullscreen()); - m_width = client.right - client.left; -@@ -1302,6 +1448,20 @@ void renderer_d3d9::pick_best_mode() - - auto win = assert_window(); - -+ // only link window #0 to SwitchRes -+ if (win->m_index == 0) -+ { -+ m_switchres_mode = &win->machine().switchres.best_mode; -+ if (m_switchres_mode) -+ { -+ m_width = m_switchres_mode->type & MODE_ROTATED? m_switchres_mode->height : m_switchres_mode->width; -+ m_height = m_switchres_mode->type & MODE_ROTATED? m_switchres_mode->width : m_switchres_mode->height; -+ m_refresh = (int)m_switchres_mode->refresh; -+ m_interlace = m_switchres_mode->interlace; -+ return; -+ } -+ } -+ - // determine the refresh rate of the primary screen - const screen_device *primary_screen = screen_device_iterator(win->machine().root_device()).first(); - if (primary_screen != nullptr) -@@ -1343,10 +1503,6 @@ void renderer_d3d9::pick_best_mode() - if (mode.Width < minwidth || mode.Height < minheight) - size_score *= 0.01f; - -- // if mode is smaller than we'd like, it only scores up to 0.1 -- if (mode.Width < target_width || mode.Height < target_height) -- size_score *= 0.1f; -- - // if we're looking for a particular mode, that's a winner - if (mode.Width == win->m_win_config.width && mode.Height == win->m_win_config.height) - size_score = 2.0f; -@@ -1354,10 +1510,6 @@ void renderer_d3d9::pick_best_mode() - // compute refresh score - float refresh_score = 1.0f / (1.0f + fabs((double)mode.RefreshRate - target_refresh)); - -- // if refresh is smaller than we'd like, it only scores up to 0.1 -- if ((double)mode.RefreshRate < target_refresh) -- refresh_score *= 0.1f; -- - // if we're looking for a particular refresh, make sure it matches - if (mode.RefreshRate == win->m_win_config.refresh) - refresh_score = 2.0f; -diff --git a/src/osd/modules/render/drawd3d.h b/src/osd/modules/render/drawd3d.h -index 03527d7374e..5f0637698d0 100644 ---- a/src/osd/modules/render/drawd3d.h -+++ b/src/osd/modules/render/drawd3d.h -@@ -67,6 +67,8 @@ public: - virtual void add_audio_to_recording(const int16_t *buffer, int samples_this_frame) override; - virtual std::vector<ui::menu_item> get_slider_list() override; - virtual void set_sliders_dirty() override; -+ virtual int restart() override; -+ inline BOOL GetClientRectExceptMenu(HWND hWnd, PRECT pRect, BOOL fullscreen); - - int initialize(); - -@@ -74,6 +76,8 @@ public: - int device_create_resources(); - void device_delete(); - void device_delete_resources(); -+ void device_flush(); -+ void update_break_scanlines(); - void update_presentation_parameters(); - void update_gamma_ramp(); - -@@ -134,9 +138,16 @@ public: - - private: - int m_adapter; // ordinal adapter number -+ int m_vendor_id; // adapter vendor id - int m_width; // current width - int m_height; // current height - int m_refresh; // current refresh rate -+ bool m_interlace; // current interlace -+ int m_frame_delay; // current frame delay value -+ int m_first_scanline; // first scanline number (visible) -+ int m_last_scanline; // last scanline number (visible) -+ int m_delay_scanline; // scanline number supposed to be after frame delay -+ int m_break_scanline; // break scanline number, for vsync offset - int m_create_error_count; // number of consecutive create errors - - IDirect3DDevice9 * m_device; // pointer to the Direct3DDevice object -@@ -144,6 +155,7 @@ private: - D3DPRESENT_PARAMETERS m_presentation; // set of presentation parameters - D3DDISPLAYMODE m_origmode; // original display mode for the adapter - D3DFORMAT m_pixformat; // pixel format we are using -+ IDirect3DQuery9 * m_query; - - IDirect3DVertexBuffer9 *m_vertexbuf; // pointer to the vertex buffer object - vertex * m_lockedbuf; // pointer to the locked vertex buffer -diff --git a/src/osd/modules/render/drawogl.cpp b/src/osd/modules/render/drawogl.cpp -index ae030224e74..02934712fea 100644 ---- a/src/osd/modules/render/drawogl.cpp -+++ b/src/osd/modules/render/drawogl.cpp -@@ -40,6 +40,13 @@ - #include "modules/opengl/gl_shader_tool.h" - #include "modules/opengl/gl_shader_mgr.h" - -+#ifdef SDLMAME_X11 -+// DRM -+#include <xf86drm.h> -+#include <xf86drmMode.h> -+#include <fcntl.h> -+#endif -+ - #if defined(SDLMAME_MACOSX) || defined(OSD_MAC) - #include <cstring> - #include <cstdio> -@@ -245,6 +252,10 @@ void renderer_ogl::set_blendmode(int blendmode) - // STATIC VARIABLES - //============================================================ - -+#ifdef SDLMAME_X11 -+static int drawogl_drm_open(void); -+#endif -+ - // OGL 1.3 - #if defined(GL_ARB_multitexture) && !defined(OSD_MAC) - static PFNGLACTIVETEXTUREARBPROC pfn_glActiveTexture = nullptr; -@@ -578,7 +589,11 @@ int renderer_ogl::create() - osd_printf_error("%s\n", m_gl_context->LastErrorMsg()); - return 1; - } -- m_gl_context->SetSwapInterval(video_config.waitvsync ? 1 : 0); -+#ifdef SDLMAME_X11 -+ // Try to open DRM device -+ m_fd = drawogl_drm_open(); -+#endif -+ m_gl_context->SetSwapInterval((video_config.waitvsync && m_fd == 0) ? 1 : 0); - - - m_blittimer = 0; -@@ -605,6 +620,26 @@ int renderer_ogl::create() - return 0; - } - -+#ifdef SDLMAME_X11 -+//============================================================ -+// drawogl_drm_open -+//============================================================ -+ -+static int drawogl_drm_open(void) -+{ -+ int fd = 0; -+ const char *node = {"/dev/dri/card0"}; -+ -+ fd = open(node, O_RDWR | O_CLOEXEC); -+ if (fd < 0) -+ { -+ fprintf(stderr, "cannot open %s\n", node); -+ return 0; -+ } -+ osd_printf_verbose("%s successfully opened\n", node); -+ return fd; -+} -+#endif - - //============================================================ - // drawsdl_xy_to_render_target -@@ -1419,6 +1454,19 @@ int renderer_ogl::draw(const int update) - win->m_primlist->release_lock(); - m_init_context = 0; - -+#ifdef SDLMAME_X11 -+ // wait for vertical retrace -+ if (video_config.waitvsync && m_fd) -+ { -+ drmVBlank vbl; -+ memset(&vbl, 0, sizeof(vbl)); -+ vbl.request.type = DRM_VBLANK_RELATIVE; -+ vbl.request.sequence = 1; -+ if (drmWaitVBlank(m_fd, &vbl) != 0) -+ osd_printf_verbose("drmWaitVBlank failed\n"); -+ } -+#endif -+ - m_gl_context->SwapBuffer(); - - return 0; -@@ -1645,6 +1693,7 @@ void renderer_ogl::texture_compute_size_type(const render_texinfo *texsource, og - texture->rawheight_create = finalheight_create; - } - -+ - //============================================================ - // texture_create - //============================================================ -diff --git a/src/osd/modules/render/drawogl.h b/src/osd/modules/render/drawogl.h -index 525ba0c3ffa..165703f9c67 100644 ---- a/src/osd/modules/render/drawogl.h -+++ b/src/osd/modules/render/drawogl.h -@@ -125,6 +125,7 @@ public: - , m_last_vofs(0.0f) - , m_surf_w(0) - , m_surf_h(0) -+ , m_fd(0) - { - for (int i=0; i < HASH_SIZE + OVERFLOW_SIZE; i++) - m_texhash[i] = nullptr; -@@ -237,6 +238,8 @@ private: - - static bool s_shown_video_info; - static bool s_dll_loaded; -+ // DRM file handle -+ int m_fd; - }; - - #endif // __DRAWOGL__ -diff --git a/src/osd/modules/sound/direct_sound.cpp b/src/osd/modules/sound/direct_sound.cpp -index 05333674541..1ef1a76ad51 100644 ---- a/src/osd/modules/sound/direct_sound.cpp -+++ b/src/osd/modules/sound/direct_sound.cpp -@@ -432,6 +432,7 @@ HRESULT sound_direct_sound::dsound_init() - stream_buffer_size = std::max(DWORD(1024), (stream_buffer_size / 1024) * 1024); - - LOG(("stream_buffer_size = %u\n", (unsigned)stream_buffer_size)); -+ osd_printf_verbose("stream_buffer_size = %u\n", (unsigned)stream_buffer_size); - - // create the buffers - m_bytes_per_sample = stream_format.nBlockAlign; -diff --git a/src/osd/modules/sound/sdl_sound.cpp b/src/osd/modules/sound/sdl_sound.cpp -index 5ff8f2e6821..8c8d80cdf94 100644 ---- a/src/osd/modules/sound/sdl_sound.cpp -+++ b/src/osd/modules/sound/sdl_sound.cpp -@@ -333,7 +333,7 @@ void sound_sdl::sdl_callback(void *userdata, Uint8 *stream, int len) - int sound_sdl::init(const osd_options &options) - { - int n_channels = 2; -- int audio_latency; -+ float audio_latency; - SDL_AudioSpec aspec, obtained; - char audio_driver[16] = ""; - -diff --git a/src/osd/osdcore.cpp b/src/osd/osdcore.cpp -index fd696706e6b..fee08261a4f 100644 ---- a/src/osd/osdcore.cpp -+++ b/src/osd/osdcore.cpp -@@ -133,13 +133,20 @@ void osd_vprintf_debug(util::format_argument_pack<std::ostream> const &args) - } - - -+#ifdef OSD_WINDOWS -+ typedef std::chrono::steady_clock s_clock; -+#else -+ typedef std::chrono::high_resolution_clock s_clock; -+#endif -+ -+ - //============================================================ - // osd_ticks - //============================================================ - - osd_ticks_t osd_ticks() - { -- return std::chrono::high_resolution_clock::now().time_since_epoch().count(); -+ return s_clock::now().time_since_epoch().count(); - } - - -@@ -149,7 +156,7 @@ osd_ticks_t osd_ticks() - - osd_ticks_t osd_ticks_per_second() - { -- return std::chrono::high_resolution_clock::period::den / std::chrono::high_resolution_clock::period::num; -+ return s_clock::period::den / s_clock::period::num; - } - - //============================================================ -@@ -162,7 +169,7 @@ void osd_sleep(osd_ticks_t duration) - // sleep_for appears to oversleep on Windows with gcc 8 - Sleep(duration / (osd_ticks_per_second() / 1000)); - #else -- std::this_thread::sleep_for(std::chrono::high_resolution_clock::duration(duration)); -+ std::this_thread::sleep_for(s_clock::duration(duration)); - #endif - } - -diff --git a/src/osd/sdl/osdsdl.h b/src/osd/sdl/osdsdl.h -index 4cbec2d9d14..48788a90aae 100644 ---- a/src/osd/sdl/osdsdl.h -+++ b/src/osd/sdl/osdsdl.h -@@ -22,7 +22,6 @@ - #define SDLOPTION_SCALEMODE "scalemode" - - #define SDLOPTION_WAITVSYNC "waitvsync" --#define SDLOPTION_SYNCREFRESH "syncrefresh" - #define SDLOPTION_KEYMAP "keymap" - #define SDLOPTION_KEYMAP_FILE "keymap_file" - -@@ -143,6 +142,8 @@ public: - bool should_hide_mouse(); - void process_events_buf(); - -+ void extract_video_config(); -+ - virtual sdl_options &options() override { return m_options; } - - protected: -@@ -152,7 +153,6 @@ protected: - private: - virtual void osd_exit() override; - -- void extract_video_config(); - void output_oslog(const char *buffer); - - sdl_options &m_options; -diff --git a/src/osd/sdl/sdlmain.cpp b/src/osd/sdl/sdlmain.cpp -index 37d1434a2e8..0ac77667cdc 100644 ---- a/src/osd/sdl/sdlmain.cpp -+++ b/src/osd/sdl/sdlmain.cpp -@@ -62,6 +62,10 @@ - #endif // INI_PATH - - -+extern bool switchres_modeline_setup(running_machine &machine); -+extern bool switchres_modeline_reset(running_machine &machine); -+extern bool switchres_modeline_remove(running_machine &machine); -+ - //============================================================ - // Global variables - //============================================================ -@@ -257,6 +261,10 @@ void sdl_osd_interface::osd_exit() - osd_common_t::osd_exit(); - - SDL_QuitSubSystem(SDL_INIT_VIDEO); -+ -+ // SwitchRes modeline removal -+ switchres_modeline_reset(machine()); -+ switchres_modeline_remove(machine()); - } - - //============================================================ -@@ -415,6 +423,10 @@ void sdl_osd_interface::init(running_machine &machine) - - const char *stemp; - -+ // Switchres -+ switchres_init_osd(machine); -+ switchres_modeline_setup(machine); -+ - // determine if we are benchmarking, and adjust options appropriately - int bench = options().bench(); - if (bench > 0) -diff --git a/src/osd/sdl/switchres_sdl.cpp b/src/osd/sdl/switchres_sdl.cpp -new file mode 100644 -index 00000000000..19e0582d131 ---- /dev/null -+++ b/src/osd/sdl/switchres_sdl.cpp -@@ -0,0 +1,606 @@ -+/************************************************************** -+ -+ switchres_sdl.cpp - SDL OSD SwitchRes core routines -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2017 - Chris Kennedy, Antonio Giner, Alexandre W -+ -+ **************************************************************/ -+ -+// SDL headers -+#include "SDL_syswm.h" -+ -+// MAME headers -+#include "osdepend.h" -+#include "emu.h" -+#include "emuopts.h" -+#include "../../frontend/mame/mameopts.h" -+ -+// MAMEOS headers -+#include "video.h" -+#include "input.h" -+#include "output.h" -+#include "osdsdl.h" -+#include "window.h" -+ -+// X11 Xrandr headers -+#include <X11/extensions/Xrandr.h> -+ -+#define XRANDR_ARGS "" -+#define min(a,b)({ __typeof__ (a) _a = (a);__typeof__ (b) _b = (b);_a < _b ? _a : _b; }) -+ -+#define XRANDR_TIMING 0x00000020 -+extern int fd; -+ -+//============================================================ -+// PROTOTYPES -+//============================================================ -+ -+bool switchres_init_osd(running_machine &machine); -+bool switchres_modeline_setup(running_machine &machine); -+bool switchres_modeline_remove(running_machine &machine); -+bool switchres_modeline_reset(running_machine &machine); -+bool switchres_resolution_change(sdl_window_info *window); -+static bool add_custom_video_mode(modeline *mode, char *connector); -+static bool set_custom_video_mode(modeline *mode, char *connector); -+static int del_custom_video_mode(modeline *mode, char *connector); -+static void set_option_osd(running_machine &machine, const char *option_ID, bool state); -+ -+//============================================================ -+// LOCAL VARIABLES -+//============================================================ -+ -+int mode_count = 1; -+ -+//============================================================ -+// XRANDR -+//============================================================ -+ -+static Display *dpy; -+static Window root; -+ -+static short original_rate; -+static Rotation original_rotation; -+static SizeID original_size_id; -+static int width = 0; -+static int height = 0; -+ -+static int gmoutput_primary = 0; -+static int gmoutput_mode = 0; -+ -+static int (*old_error_handler)(Display *, XErrorEvent *); -+ -+static int xerrors = 0; -+ -+static int error_handler (Display *dpy, XErrorEvent *err) -+{ -+ xerrors++; -+ return 0; -+} /* xorg_error_handler() */ -+ -+//============================================================ -+// switchres_init_osd -+//============================================================ -+ -+bool switchres_init_osd(running_machine &machine) -+{ -+ config_settings *cs = &machine.switchres.cs; -+ game_info *game = &machine.switchres.game; -+ modeline *mode_table = machine.switchres.video_modes; -+ modeline *user_mode = &machine.switchres.user_mode; -+ monitor_range *range = machine.switchres.range; -+ const char * aspect; -+ char *connector = machine.switchres.cs.connector; -+ char resolution[32]={'\x00'}; -+ -+ sdl_options &options = downcast<sdl_options &>(machine.options()); -+ -+ // Initialize structures and config settings -+ memset(cs, 0, sizeof(struct config_settings)); -+ memset(game, 0, sizeof(struct game_info)); -+ -+ // Init Switchres common info -+ switchres_init(machine); -+ -+ // Complete config settings -+ strcpy(resolution, options.resolution()); -+ cs->monitor_count = options.numscreens(); -+ -+ // Get current resolution -+ int screen = -1; -+ -+ // dpy is global to reduce open/close calls, resource is freed when modeline is reset -+ dpy = XOpenDisplay(NULL); -+ int major_version, minor_version; -+ XRRQueryVersion(dpy, &major_version, &minor_version); -+ osd_printf_verbose("SwitchRes: xrandr version %d.%d\n",major_version,minor_version); -+ -+ // select current display and root window -+ // root is global to reduce open/close calls, resource is freed when modeline is reset -+ screen = DefaultScreen(dpy); // multiple screen ScreenCount (dpy) -+ root = RootWindow(dpy, screen); -+ XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root); -+ -+ // get screen size, rate and rotation from screen configuration -+ XRRScreenConfiguration *sc = XRRGetScreenInfo(dpy, root); -+ original_rate = XRRConfigCurrentRate(sc); -+ original_size_id = XRRConfigCurrentConfiguration(sc, &original_rotation); -+ XRRFreeScreenConfigInfo(sc); -+ -+ Rotation current_rotation = 0; -+ for (int o = 0; o < res->noutput && !gmoutput_mode; o++) -+ { -+ XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]); -+ if (!output_info) -+ osd_printf_error("SwitchRes: error could not get output 0x%x information\n", (uint) res->outputs[o]); -+ -+ // first connected output -+ if (output_info->connection == RR_Connected) -+ { -+ for (int j = 0; j < output_info->nmode && !gmoutput_mode; j++) -+ { -+ if ( output_info->crtc ) -+ { -+ XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(dpy, res, output_info->crtc); -+ current_rotation = crtc_info->rotation; -+ if (!strcmp(cs->connector, "auto") || !strcmp(cs->connector,output_info->name)) -+ { -+ // connector name is kept but not necessary due to global gmoutput_primary varial, optimization can happen here -+ sprintf(connector,"%s", output_info->name); -+ osd_printf_verbose("SwitchRes: Found output connector '%s'\n", connector); -+ gmoutput_primary = o; -+ } -+ for (int m = 0; m < res->nmode && !gmoutput_mode; m++) -+ { -+ XRRModeInfo *mode = &res->modes[m]; -+ // get screen mode -+ if (crtc_info->mode == mode->id) -+ { -+ gmoutput_mode = mode->id; -+ width = crtc_info->x + crtc_info->width; -+ height = crtc_info->y + crtc_info->height; -+ } -+ } -+ } -+ if (current_rotation & 0xe) // screen rotation is left or right -+ { -+ osd_printf_verbose("Switchres: desktop rotation is %s\n",(current_rotation & 0x2)?"left":((current_rotation & 0x8)?"right":"inverted")); -+ cs->desktop_rotated = 1; -+ } -+ } -+ } -+ XRRFreeOutputInfo(output_info); -+ } -+ XRRFreeScreenResources(res); -+ -+ // Get per window resolution -+ strcpy(resolution, strcmp(options.resolution(0), "auto")? options.resolution(0) : options.resolution()); -+ -+ // Get monitor aspect -+ aspect = strcmp(options.aspect(0), "auto")? options.aspect(0) : options.aspect(); -+ if (strcmp(aspect, "auto")) -+ { -+ float num, den; -+ sscanf(aspect, "%f:%f", &num, &den); -+ cs->monitor_aspect = cs->desktop_rotated? den/num : num/den; -+ } -+ else -+ cs->monitor_aspect = STANDARD_CRT_ASPECT; -+ -+ // Create dummy mode table -+ mode_table[1].width = mode_table[1].height = 1; -+ mode_table[1].refresh = 60; -+ mode_table[1].vfreq = mode_table[1].refresh; -+ mode_table[1].hactive = mode_table[1].vactive = 1; -+ mode_table[1].type = XYV_EDITABLE | XRANDR_TIMING | (cs->desktop_rotated? MODE_ROTATED : MODE_OK); -+ -+ if (user_mode->hactive) -+ { -+ user_mode->width = user_mode->hactive; -+ user_mode->height = user_mode->vactive; -+ user_mode->refresh = int(user_mode->refresh); -+ user_mode->type = XRANDR_TIMING | MODE_USER_DEF | (cs->desktop_rotated? MODE_ROTATED : MODE_OK); -+ } -+ -+ // Create automatic specs and force resolution for LCD monitors -+ if (!strcmp(cs->monitor, "lcd")) -+ { -+ modeline current; -+ memset(¤t, 0, sizeof(struct modeline)); -+ -+ osd_printf_verbose("SwitchRes: Creating automatic specs for LCD based on VESA GTF\n"); -+ current.width = width; -+ current.height = height; -+ current.refresh = 60; -+ modeline_vesa_gtf(¤t); -+ modeline_to_monitor_range(range, ¤t); -+ monitor_show_range(range); -+ -+ sprintf(resolution, "%dx%d@%d", current.width, current.height, current.refresh); -+ } -+ // Otherwise (non-LCD), convert the user defined modeline into a -resolution option -+ else if (user_mode->hactive) -+ sprintf(resolution, "%dx%d", user_mode->hactive, user_mode->vactive); -+ -+ // Get resolution from ini -+ if (strcmp(resolution, "auto")) -+ { -+ osd_printf_verbose("SwitchRes: -resolution was set at command line or in .ini file as %s\n", resolution); -+ -+ if ((sscanf(resolution, "%dx%d@%d", &cs->width, &cs->height, &cs->refresh) < 3) && -+ ((!strstr(resolution, "x") || (sscanf(resolution, "%dx%d", &cs->width, &cs->height) != 2)))) -+ osd_printf_info("SwitchRes: illegal -resolution value: %s\n", resolution); -+ else -+ { -+ // Add the user's resolution to our table -+ if (!user_mode->hactive) -+ { -+ mode_table[1].width = mode_table[1].hactive = cs->width? cs->width : 1; -+ mode_table[1].height = mode_table[1].vactive = cs->height? cs->height : 1; -+ mode_table[1].refresh = cs->refresh? int(cs->refresh) : 60; -+ mode_table[1].vfreq = mode_table[1].refresh; -+ mode_table[1].type |= MODE_USER_DEF; -+ if (cs->width) mode_table[1].type &= ~X_RES_EDITABLE; -+ if (cs->height) mode_table[1].type &= ~Y_RES_EDITABLE; -+ } -+ } -+ } -+ // Get game info -+ switchres_get_game_info(machine); -+ -+ return true; -+} -+ -+//============================================================ -+// switchres_modeline_setup -+//============================================================ -+ -+bool switchres_modeline_setup(running_machine &machine) -+{ -+ modeline *best_mode = &machine.switchres.best_mode; -+ modeline *mode_table = machine.switchres.video_modes; -+ char *connector = machine.switchres.cs.connector; -+ sdl_options &options = downcast<sdl_options &>(machine.options()); -+ sdl_osd_interface &osd = downcast<sdl_osd_interface &>(machine.osd()); -+ std::string error_string; -+ -+ osd_printf_verbose("\nSwitchRes: Entering switchres_modeline_setup\n"); -+ -+ // Find most suitable video mode and generate a modeline for it if we're allowed -+ if (!switchres_get_video_mode(machine)) -+ { -+ set_option_osd(machine, OSDOPTION_SWITCHRES, false); -+ return false; -+ } -+ -+ // Make the new modeline available to the system -+ if (machine.options().modeline_generation()) -+ { -+ // Lock mode before adding it to mode table -+ best_mode->type |= MODE_DISABLED; -+ -+ // Check if the same mode had been created already -+ int i; -+ bool found = false; -+ for (i = 2; i <= mode_count; i++) -+ if (!memcmp(&mode_table[i], best_mode, sizeof(modeline) - sizeof(mode_result))) -+ found = true; -+ -+ // Create the new mode and store it in our table -+ if (!found) -+ { -+ mode_count++; -+ memcpy(&mode_table[mode_count], best_mode, sizeof(modeline)); -+ add_custom_video_mode(best_mode, connector); -+ } -+ -+ // Switch to the new mode -+ set_custom_video_mode(best_mode, connector); -+ } -+ -+ // Set MAME common options -+ switchres_set_options(machine); -+ -+ // Black frame insertion / multithreading -+ bool black_frame_insertion = options.black_frame_insertion() && best_mode->result.v_scale > 1 && best_mode->vfreq > 100; -+ set_option_osd(machine, OPTION_BLACK_FRAME_INSERTION, black_frame_insertion); -+ -+ // Set MAME OSD specific options -+ -+ // Vertical synchronization management (autosync) -+ // Disable -syncrefresh if our vfreq is scaled or out of syncrefresh_tolerance -+ bool sync_refresh_effective = black_frame_insertion || !((best_mode->result.weight & R_V_FREQ_OFF) || best_mode->result.v_scale > 1); -+ set_option_osd(machine, OPTION_SYNCREFRESH, options.autosync()? sync_refresh_effective : options.sync_refresh()); -+ set_option_osd(machine, OSDOPTION_WAITVSYNC, options.sync_refresh()? options.sync_refresh() : options.wait_vsync()); -+ -+ // Set filter options -+ set_option_osd(machine, OSDOPTION_FILTER, ((best_mode->result.weight & R_RES_STRETCH || best_mode->interlace))); -+ -+ // Refresh video options -+ osd.extract_video_config(); -+ -+ return true; -+} -+ -+//============================================================ -+// switchres_modeline_remove -+//============================================================ -+ -+bool switchres_modeline_remove(running_machine &machine) -+{ -+ return true; -+} -+ -+//============================================================ -+// switchres_modeline_reset -+//============================================================ -+ -+bool switchres_modeline_reset(running_machine &machine) -+{ -+ config_settings *cs = &machine.switchres.cs; -+ modeline *mode_table = machine.switchres.video_modes; -+ -+ // Restore desktop resolution -+ XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root); -+ XRRScreenConfiguration *sc = XRRGetScreenInfo(dpy, root); -+ -+ XRRSetScreenConfigAndRate(dpy, sc, root, original_size_id, original_rotation, original_rate, CurrentTime); -+ XRRFreeScreenConfigInfo(sc); -+ XRRFreeScreenResources(res); -+ -+ osd_printf_verbose("SwitchRes: xrandr original video mode restored.\n"); -+ -+ // Remove modelines -+ while (mode_count > 1) -+ { -+ del_custom_video_mode(&mode_table[mode_count], cs->connector); -+ mode_count--; -+ } -+ -+ XCloseDisplay(dpy); -+ return true; -+} -+ -+//============================================================ -+// switchres_resolution_change -+//============================================================ -+ -+bool switchres_resolution_change(sdl_window_info *window) -+{ -+ running_machine &machine = window->machine(); -+ modeline *best_mode = &machine.switchres.best_mode; -+ modeline previous_mode; -+ -+ // If there's no pending change, just exit -+ if (!switchres_check_resolution_change(machine)) -+ return false; -+ -+ // Get the new resolution -+ previous_mode = *best_mode; -+ switchres_modeline_setup(machine); -+ -+ // Only change resolution if the new one is actually different -+ if (memcmp(&previous_mode, best_mode, offsetof(modeline, result))) -+ return true; -+ -+ return false; -+} -+ -+//============================================================ -+// add_custom_video_mode -+//============================================================ -+ -+static bool add_custom_video_mode(modeline *mode, char *connector) -+{ -+ if (!mode) -+ return false; -+ -+ // Add modeline to interface -+ char name[48]; -+ sprintf(name,"GM-%dx%d_%.6f",mode->hactive, mode->vactive, mode->vfreq); // add ID -+ -+ // Setup the xrandr mode structure -+ XRRModeInfo xmode; -+ xmode.name = name; -+ xmode.nameLength = strlen(name); -+ xmode.dotClock = float(mode->pclock); -+ xmode.width = mode->hactive; -+ xmode.hSyncStart = mode->hbegin; -+ xmode.hSyncEnd = mode->hend; -+ xmode.hTotal = mode->htotal; -+ xmode.height = mode->vactive; -+ xmode.vSyncStart = mode->vbegin; -+ xmode.vSyncEnd = mode->vend; -+ xmode.vTotal = mode->vtotal; -+ xmode.modeFlags = (mode->interlace?RR_Interlace:0) | (mode->doublescan?RR_DoubleScan:0) | (mode->hsync?RR_HSyncPositive:RR_HSyncNegative) | (mode->vsync?RR_VSyncPositive:RR_VSyncNegative); -+ -+ // Create the modeline -+ XSync(dpy, False); -+ xerrors = 0; -+ old_error_handler = XSetErrorHandler(error_handler); -+ RRMode gmid = XRRCreateMode(dpy, root, &xmode); -+ XSync(dpy, False); -+ XSetErrorHandler(old_error_handler); -+ if (xerrors) -+ osd_printf_error("Switchres: xrandr error in %s\n","XRRCreateMode"); -+ -+ // Add new modeline to primary output -+ XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root); -+ -+ XSync(dpy, False); -+ xerrors = 0; -+ old_error_handler = XSetErrorHandler(error_handler); -+ XRRAddOutputMode(dpy, res->outputs[gmoutput_primary], gmid); -+ XSync(dpy, False); -+ XSetErrorHandler(old_error_handler); -+ if (xerrors) -+ osd_printf_error("Switchres: xrandr error in %s\n","XRRAddOutputMode"); -+ -+ XRRFreeScreenResources(res); -+ return true; -+} -+ -+//============================================================ -+// set_custom_video_mode -+//============================================================ -+ -+static bool set_custom_video_mode(modeline *mode, char *connector) -+{ -+ // Use xrandr to switch to new mode. SDL_SetVideoMode doesn't work when (new_width, new_height)==(old_width, old_height) -+ char name[48]; -+ sprintf(name,"GM-%dx%d_%.6f",mode->hactive, mode->vactive, mode->vfreq); // add ID -+ -+ XRRScreenResources *res = XRRGetScreenResourcesCurrent(dpy, root); -+ XRROutputInfo *output_info = XRRGetOutputInfo(dpy, res, res->outputs[gmoutput_primary]); -+ XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(dpy, res, output_info->crtc); -+ -+ // Select corresponding mode from modeline, can be enhanced by saving mode index to modeline structure -+ XRRModeInfo *xmode=0; -+ for (int m = 0; m < res->nmode; m++) -+ { -+ XRRModeInfo *tmp_mode = &res->modes[m]; -+ if (!strcmp(name, tmp_mode->name)) -+ { -+ xmode = &res->modes[m]; -+ } -+ } -+ -+ // Grab X server to prevent unwanted interaction from the window manager -+ XGrabServer(dpy); -+ -+ // Disable all CRTCs -+ for (int i = 0; i < output_info->ncrtc; i++) -+ { -+ if (XRRSetCrtcConfig(dpy, res, output_info->crtcs[i], CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0) != RRSetConfigSuccess) -+ osd_printf_error("Switchres: xrandr error when disabling CRTC.\n"); -+ } -+ osd_printf_verbose("Switchres: CRTC %d: mode %#lx, %ux%u+%d+%d.\n", 0, crtc_info->mode,crtc_info->width, crtc_info->height, crtc_info->x, crtc_info->y); -+ -+ // Check if framebuffer size is correct -+ int change_resolution = 0; -+ if (width < crtc_info->x + mode->hactive) -+ { -+ width = crtc_info->x + mode->hactive; -+ change_resolution = 1; -+ } -+ if (height < crtc_info->y + mode->vactive) -+ { -+ height = crtc_info->y + mode->vactive; -+ change_resolution = 1; -+ } -+ -+ // Enlarge the screen size for the new mode -+ if (change_resolution) -+ { -+ osd_printf_verbose("Switchres: xrandr change screen size.\n"); -+ XSync(dpy, False); -+ xerrors = 0; -+ old_error_handler = XSetErrorHandler(error_handler); -+ XRRSetScreenSize(dpy, root, width, height, (25.4 * width) / 96.0, (25.4 * height) / 96.0); -+ XSync(dpy, False); -+ XSetErrorHandler(old_error_handler); -+ if (xerrors) -+ osd_printf_error("Switchres: xrandr error in %s\n","XRRSetScreenSize"); -+ } -+ -+ // Switch to new modeline -+ XSync(dpy, False); -+ xerrors = 0; -+ old_error_handler = XSetErrorHandler(error_handler); -+ XRRSetCrtcConfig(dpy, res, output_info->crtc, CurrentTime , crtc_info->x, crtc_info->y, xmode->id, original_rotation, crtc_info->outputs, crtc_info->noutput); -+ XSync(dpy, False); -+ XSetErrorHandler(old_error_handler); -+ -+ XRRFreeCrtcInfo(crtc_info); -+ -+ if (xerrors) -+ osd_printf_error("Switchres: xrandr error in %s\n","XRRSetCrtcConfig"); -+ -+ // Release X server, events can be processed now -+ XUngrabServer(dpy); -+ -+ crtc_info = XRRGetCrtcInfo(dpy, res, output_info->crtc); // recall crtc to settle parameters -+ -+ // If the crtc config modeline change fails, revert to original mode (prevents ending with black screen due to all crtc disabled) -+ if (crtc_info->mode == 0) -+ { -+ osd_printf_error("Switchres: xrandr resolution switch error, original mode restored\n"); -+ XRRScreenConfiguration *sc = XRRGetScreenInfo(dpy, root); -+ XRRSetScreenConfigAndRate(dpy, sc, root, original_size_id, original_rotation, original_rate, CurrentTime); -+ XRRFreeScreenConfigInfo(sc); -+ } -+ -+ // check, verify current active mode -+ for (int m = 0; m < res->nmode; m++) -+ { -+ XRRModeInfo *mode = &res->modes[m]; -+ if (mode->id == crtc_info->mode) -+ osd_printf_verbose("Switchres: xrandr mode (%s) (0x%x) %6.6fMHz\n", mode->name, (int)mode->id,(double)mode->dotClock / 1000000.0); -+ } -+ -+ XRRFreeCrtcInfo(crtc_info); -+ XRRFreeOutputInfo(output_info); -+ XRRFreeScreenResources(res); -+ -+ return true; -+} -+ -+//============================================================ -+// del_custom_video_mode -+//============================================================ -+ -+static int del_custom_video_mode(modeline *mode, char *connector) -+{ -+ if (!mode) -+ return false; -+ -+ char name[48]; -+ sprintf(name,"GM-%dx%d_%.6f",mode->hactive, mode->vactive, mode->vfreq); // add ID -+ -+ XRRScreenResources *res = XRRGetScreenResourcesCurrent (dpy, root); -+ -+ // Delete modeline -+ for (int m = 0; m < res->nmode; m++) -+ { -+ XRRModeInfo *xmode = &res->modes[m]; -+ if (!strcmp(name, xmode->name)) -+ { -+ XSync(dpy, False); -+ xerrors = 0; -+ old_error_handler = XSetErrorHandler(error_handler); -+ XRRDeleteOutputMode (dpy, res->outputs[gmoutput_primary], xmode->id); -+ if (xerrors) -+ osd_printf_error("Switchres: xrandr error in %s\n","XRRDeleteOutputMode"); -+ -+ xerrors = 0; -+ XRRDestroyMode (dpy, xmode->id); -+ XSync(dpy, False); -+ XSetErrorHandler(old_error_handler); -+ if (xerrors) -+ osd_printf_error("Switchres: xrandr error in %s\n","XRRDestroyMode"); -+ } -+ } -+ -+ XRRFreeScreenResources(res); -+ -+ return true; -+} -+ -+//============================================================ -+// set_option_osd - option setting wrapper -+//============================================================ -+ -+static void set_option_osd(running_machine &machine, const char *option_ID, bool state) -+{ -+ sdl_options &options = downcast<sdl_options &>(machine.options()); -+ -+ options.set_value(option_ID, state, OPTION_PRIORITY_SWITCHRES); -+ osd_printf_verbose("SwitchRes: Setting option -%s%s\n", machine.options().bool_value(option_ID)?"":"no", option_ID); -+} -diff --git a/src/osd/sdl/video.cpp b/src/osd/sdl/video.cpp -index e7af55e56ba..8d1eeb1eaa8 100644 ---- a/src/osd/sdl/video.cpp -+++ b/src/osd/sdl/video.cpp -@@ -247,12 +247,7 @@ void sdl_osd_interface::extract_video_config() - video_config.centerh = options().centerh(); - video_config.centerv = options().centerv(); - video_config.waitvsync = options().wait_vsync(); -- video_config.syncrefresh = options().sync_refresh(); -- if (!video_config.waitvsync && video_config.syncrefresh) -- { -- osd_printf_warning("-syncrefresh specified without -waitvsync. Reverting to -nosyncrefresh\n"); -- video_config.syncrefresh = 0; -- } -+ video_config.syncrefresh = machine().options().sync_refresh(); - - if (video_config.prescale < 1 || video_config.prescale > 8) - { -diff --git a/src/osd/sdl/window.cpp b/src/osd/sdl/window.cpp -index 70886d76a73..83f6c5f035d 100644 ---- a/src/osd/sdl/window.cpp -+++ b/src/osd/sdl/window.cpp -@@ -80,6 +80,7 @@ public: - // PROTOTYPES - //============================================================ - -+extern bool switchres_resolution_change(sdl_window_info *window); - - //============================================================ - // window_init -@@ -352,6 +353,23 @@ void sdl_window_info::modify_prescale(int dir) - } - } - -+void sdl_window_info::reset_fullscreen_renderer() -+{ -+#if (SDLMAME_SDL2) -+ if (this->fullscreen() && video_config.switchres) -+ { -+ complete_destroy(); -+ SDL_QuitSubSystem(SDL_INIT_VIDEO); -+ SDL_InitSubSystem(SDL_INIT_VIDEO); -+ complete_create(); -+ } -+#else -+ if (this->fullscreen() && video_config.switchres) -+ this->window_resize(window->minwidth, window->minheight); -+#endif -+} -+ -+ - //============================================================ - // sdlwindow_update_cursor_state - // (main or window thread) -@@ -491,6 +509,14 @@ osd_dim sdl_window_info::pick_best_mode() - float size_score, best_score = 0.0f; - osd_dim ret(0,0); - -+ // check if we already have a best mode -+ modeline *mode = &this->machine().switchres.best_mode; -+ if (mode->hactive) -+ { -+ ret = osd_dim(mode->type & MODE_ROTATED? mode->vactive : mode->hactive, mode->type & MODE_ROTATED? mode->hactive : mode->vactive); -+ return ret; -+ } -+ - // determine the minimum width/height for the selected target - m_target->compute_minimum_size(minimum_width, minimum_height); - -@@ -584,8 +610,15 @@ void sdl_window_info::update() - } - else if (video_config.switchres) - { -- osd_dim tmp = this->pick_best_mode(); -- resize(tmp.width(), tmp.height()); -+ // check resolution change -+ if (renderer().m_switchres_mode != nullptr && video_config.switchres && machine().options().changeres()) -+ { -+ if (switchres_resolution_change(this)) -+ { -+ reset_fullscreen_renderer(); -+ return; -+ } -+ } - } - } - -diff --git a/src/osd/sdl/window.h b/src/osd/sdl/window.h -index d6010e91ed2..9b2ef28371b 100644 ---- a/src/osd/sdl/window.h -+++ b/src/osd/sdl/window.h -@@ -73,7 +73,6 @@ public: - // Pointer to next window - sdl_window_info * m_next; - --private: - // window handle and info - char m_title[256]; - int m_startmaximized; -@@ -105,6 +104,7 @@ private: - void update_cursor_state(); - osd_dim pick_best_mode(); - void set_fullscreen(int afullscreen) { m_fullscreen = afullscreen; } -+ void reset_fullscreen_renderer(); - - // Pointer to machine - running_machine & m_machine; -diff --git a/src/osd/windows/custom_video.cpp b/src/osd/windows/custom_video.cpp -new file mode 100644 -index 00000000000..a07fb6dc95c ---- /dev/null -+++ b/src/osd/windows/custom_video.cpp -@@ -0,0 +1,359 @@ -+/************************************************************** -+ -+ custom_video.cpp - Custom video library -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+// standard windows headers -+#include <windows.h> -+ -+#include "emu.h" -+#include "custom_video.h" -+#include "custom_video_ati.h" -+#include "custom_video_adl.h" -+#include "custom_video_pstrip.h" -+ -+extern bool ati_is_legacy(int vendor, int device); -+ -+//============================================================ -+// LOCAL VARIABLES -+//============================================================ -+ -+static int custom_method; -+static modeline m_user_mode; -+static modeline m_backup_mode; -+static modeline *m_mode_table; -+static char m_device_name[32]; -+static char m_device_key[128]; -+static char ps_timing[256]; -+ -+//============================================================ -+// custom_video_init -+//============================================================ -+ -+bool custom_video_init(char *device_name, char *device_id, modeline *desktop_mode, modeline *user_mode, modeline *mode_table, int method, char *s_param) -+{ -+ memset(&m_backup_mode, 0, sizeof(modeline)); -+ memcpy(&m_user_mode, user_mode, sizeof(modeline)); -+ memcpy(m_device_name, device_name, sizeof(m_device_name)); -+ m_mode_table = mode_table; -+ -+ if ((method == CUSTOM_VIDEO_TIMING_POWERSTRIP) && ps_init(ps_monitor_index(m_device_name), &m_backup_mode)) -+ { -+ custom_method = CUSTOM_VIDEO_TIMING_POWERSTRIP; -+ m_backup_mode.type |= CUSTOM_VIDEO_TIMING_POWERSTRIP; -+ -+ // If we have a -ps_timing string defined, use it as user defined modeline -+ memcpy(ps_timing, s_param, sizeof(ps_timing)); -+ if (strcmp(ps_timing, "auto")) -+ { -+ MonitorTiming timing; -+ if (ps_read_timing_string(ps_timing, &timing)) -+ { -+ ps_pstiming_to_modeline(&timing, &m_user_mode); -+ m_user_mode.type |= CUSTOM_VIDEO_TIMING_POWERSTRIP; -+ memcpy(user_mode, &m_user_mode, sizeof(modeline)); -+ -+ char modeline_txt[256]={'\x00'}; -+ osd_printf_verbose("SwitchRes: ps_string: %s (%s)\n", ps_timing, modeline_print(&m_user_mode, modeline_txt, MS_PARAMS)); -+ } -+ else osd_printf_verbose("Switchres: ps_timing string with invalid format\n"); -+ } -+ return true; -+ } -+ else -+ { -+ int vendor, device; -+ custom_video_parse_pci_id(device_id, &vendor, &device); -+ -+ if (vendor == 0x1002) // ATI/AMD -+ { -+ if (ati_is_legacy(vendor, device)) -+ { -+ memcpy(m_device_key, s_param, sizeof(m_device_key)); -+ if (ati_init(m_device_name, m_device_key, device_id)) -+ { -+ custom_method = CUSTOM_VIDEO_TIMING_ATI_LEGACY; -+ return true; -+ } -+ } -+ else -+ { -+ memcpy(m_device_key, s_param, sizeof(m_device_key)); -+ if (adl_init(m_device_name, m_device_key, device_id)) -+ { -+ custom_method = CUSTOM_VIDEO_TIMING_ATI_ADL; -+ return true; -+ } -+ } -+ } -+ else -+ osd_printf_info("Video chipset is not compatible.\n"); -+ } -+ -+ return false; -+} -+ -+//============================================================ -+// custom_video_close -+//============================================================ -+ -+void custom_video_close() -+{ -+ switch (custom_method) -+ { -+ case CUSTOM_VIDEO_TIMING_ATI_LEGACY: -+ break; -+ -+ case CUSTOM_VIDEO_TIMING_ATI_ADL: -+ adl_close(); -+ break; -+ -+ case CUSTOM_VIDEO_TIMING_POWERSTRIP: -+ break; -+ } -+} -+ -+//============================================================ -+// custom_video_get_timing -+//============================================================ -+ -+bool custom_video_get_timing(modeline *mode) -+{ -+ char modeline_txt[256]={'\x00'}; -+ -+ switch (custom_method) -+ { -+ case CUSTOM_VIDEO_TIMING_ATI_LEGACY: -+ if (ati_get_modeline(mode)) -+ { -+ osd_printf_verbose("ATI legacy timing %s\n", modeline_print(mode, modeline_txt, MS_FULL)); -+ mode->type |= CUSTOM_VIDEO_TIMING_ATI_LEGACY | (!(mode->type & MODE_DESKTOP)? V_FREQ_EDITABLE | (mode->width == DUMMY_WIDTH? X_RES_EDITABLE:0):0); -+ return true; -+ } -+ break; -+ -+ case CUSTOM_VIDEO_TIMING_ATI_ADL: -+ if (adl_get_modeline(m_device_name, mode)) -+ { -+ osd_printf_verbose("ATI ADL timing %s\n", modeline_print(mode, modeline_txt, MS_FULL)); -+ mode->type |= CUSTOM_VIDEO_TIMING_ATI_ADL | (!(mode->type & MODE_DESKTOP)? V_FREQ_EDITABLE :0); -+ return true; -+ } -+ break; -+ -+ case CUSTOM_VIDEO_TIMING_POWERSTRIP: -+ if ((mode->type & MODE_DESKTOP) && ps_get_modeline(ps_monitor_index(m_device_name), mode)) -+ osd_printf_verbose("Powerstrip timing %s\n", modeline_print(mode, modeline_txt, MS_FULL)); -+ else -+ osd_printf_verbose("Not current mode\n"); -+ -+ mode->type |= CUSTOM_VIDEO_TIMING_POWERSTRIP | V_FREQ_EDITABLE; -+ return true; -+ } -+ -+ osd_printf_verbose("system mode\n"); -+ mode->type |= CUSTOM_VIDEO_TIMING_SYSTEM; -+ return false; -+} -+ -+//============================================================ -+// custom_video_set_timing -+//============================================================ -+ -+bool custom_video_set_timing(modeline *mode) -+{ -+ char modeline_txt[256]={'\x00'}; -+ -+ switch (custom_method) -+ { -+ case CUSTOM_VIDEO_TIMING_ATI_LEGACY: -+ if (ati_set_modeline(mode)) -+ { -+ osd_printf_verbose("ATI legacy timing %s\n", modeline_print(mode, modeline_txt, MS_FULL)); -+ return true; -+ } -+ break; -+ -+ case CUSTOM_VIDEO_TIMING_ATI_ADL: -+ if (adl_set_modeline(m_device_name, mode, mode->interlace != m_backup_mode.interlace? MODELINE_UPDATE_LIST : MODELINE_UPDATE)) -+ { -+ osd_printf_verbose("ATI ADL timing %s\n", modeline_print(mode, modeline_txt, MS_FULL)); -+ return true; -+ } -+ break; -+ -+ case CUSTOM_VIDEO_TIMING_POWERSTRIP: -+ // In case -ps_timing is provided, pass it as raw string -+ if (m_user_mode.type & CUSTOM_VIDEO_TIMING_POWERSTRIP) -+ ps_set_monitor_timing_string(ps_monitor_index(m_device_name), (char*)ps_timing); -+ // Otherwise pass it as modeline -+ else -+ ps_set_modeline(ps_monitor_index(m_device_name), mode); -+ -+ osd_printf_verbose("Powerstrip timing %s\n", modeline_print(mode, modeline_txt, MS_FULL)); -+ Sleep(100); -+ return true; -+ break; -+ -+ default: -+ break; -+ } -+ return false; -+} -+ -+//============================================================ -+// custom_video_restore_timing -+//============================================================ -+ -+bool custom_video_restore_timing() -+{ -+ if (!m_backup_mode.hactive) -+ return false; -+ -+ // Restore backup mode -+ return custom_video_update_timing(0); -+} -+ -+//============================================================ -+// custom_video_refresh_timing -+//============================================================ -+ -+void custom_video_refresh_timing() -+{ -+ switch (custom_method) -+ { -+ case CUSTOM_VIDEO_TIMING_ATI_LEGACY: -+ ati_refresh_timings(); -+ break; -+ -+ case CUSTOM_VIDEO_TIMING_ATI_ADL: -+ break; -+ -+ case CUSTOM_VIDEO_TIMING_POWERSTRIP: -+ break; -+ } -+} -+ -+//============================================================ -+// custom_video_update_timing -+//============================================================ -+ -+bool custom_video_update_timing(modeline *mode) -+{ -+ switch (custom_method) -+ { -+ case CUSTOM_VIDEO_TIMING_ATI_LEGACY: -+ case CUSTOM_VIDEO_TIMING_ATI_ADL: -+ -+ // Restore old video timing -+ if (m_backup_mode.hactive) -+ { -+ osd_printf_verbose("Switchres: restoring "); -+ custom_video_set_timing(&m_backup_mode); -+ } -+ -+ // Update with new video timing -+ if (mode) -+ { -+ // Backup current timing -+ int found = 0; -+ for (int i = 0; i <= MAX_MODELINES; i++) -+ { -+ if (m_mode_table[i].width == mode->width && m_mode_table[i].height == mode->height && m_mode_table[i].refresh == mode->refresh) -+ { -+ memcpy(&m_backup_mode, &m_mode_table[i], sizeof(modeline)); -+ found = 1; -+ break; -+ } -+ } -+ if (!found) -+ { -+ osd_printf_verbose("Switchres: mode not found in mode_table\n"); -+ return false; -+ } -+ osd_printf_verbose("Switchres: saving "); -+ custom_video_get_timing(&m_backup_mode); -+ -+ // Apply new timing now -+ osd_printf_verbose("Switchres: updating "); -+ if (!custom_video_set_timing(mode)) goto error; -+ } -+ custom_video_refresh_timing(); -+ break; -+ -+ case CUSTOM_VIDEO_TIMING_POWERSTRIP: -+ // We only backup/restore the desktop mode with Powerstrip -+ if (!mode) -+ ps_reset(ps_monitor_index(m_device_name)); -+ else -+ { -+ osd_printf_verbose("Switchres: updating "); -+ custom_video_set_timing(mode); -+ } -+ break; -+ } -+ return true; -+ -+error: -+ osd_printf_verbose(": error updating video timings\n"); -+ return false; -+} -+ -+//============================================================ -+// custom_video_parse_timing -+//============================================================ -+ -+bool custom_video_parse_timing(char *timing_string, modeline *user_mode) -+{ -+ char modeline_txt[256]={'\x00'}; -+ -+ if (!strcmp(timing_string, "auto")) -+ return false; -+ -+ if (strstr(timing_string, "=")) -+ { -+ // Powerstrip timing string -+ MonitorTiming timing; -+ ps_read_timing_string(timing_string, &timing); -+ ps_pstiming_to_modeline(&timing, user_mode); -+ user_mode->type |= CUSTOM_VIDEO_TIMING_POWERSTRIP; -+ osd_printf_verbose("SwitchRes: ps_string: %s (%s)\n", timing_string, modeline_print(user_mode, modeline_txt, MS_PARAMS)); -+ } -+ else -+ { -+ // Normal modeline -+ modeline_parse(timing_string, user_mode); -+ osd_printf_verbose("SwitchRes: modeline: %s \n", modeline_print(user_mode, modeline_txt, MS_PARAMS)); -+ } -+ -+ return true; -+} -+ -+//============================================================ -+// custom_video_parse_pci_id -+//============================================================ -+ -+int custom_video_parse_pci_id(char *device_id, int *vendor, int *device) -+{ -+ return sscanf(device_id, "PCI\\VEN_%x&DEV_%x", vendor, device); -+} -+ -+//============================================================ -+// custom_get_backup_mode -+//============================================================ -+ -+modeline *custom_video_get_backup_mode() -+{ -+ return &m_backup_mode; -+} -diff --git a/src/osd/windows/custom_video.h b/src/osd/windows/custom_video.h -new file mode 100644 -index 00000000000..4e0fe242d75 ---- /dev/null -+++ b/src/osd/windows/custom_video.h -@@ -0,0 +1,31 @@ -+/************************************************************** -+ -+ custom_video.h - Custom video library header -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+#define CUSTOM_VIDEO_TIMING_MASK 0x00000ff0 -+#define CUSTOM_VIDEO_TIMING_SYSTEM 0x00000010 -+#define CUSTOM_VIDEO_TIMING_XRANDR 0x00000020 -+#define CUSTOM_VIDEO_TIMING_POWERSTRIP 0x00000040 -+#define CUSTOM_VIDEO_TIMING_ATI_LEGACY 0x00000080 -+#define CUSTOM_VIDEO_TIMING_ATI_ADL 0x00000100 -+ -+bool custom_video_init(char *device_name, char *device_id, modeline *desktop_mode, modeline *user_mode, modeline *mode_table, int method, char *s_param); -+void custom_video_close(); -+bool custom_video_get_timing(modeline *mode); -+bool custom_video_set_timing(modeline *mode); -+bool custom_video_restore_timing(); -+bool custom_video_update_timing(modeline *mode); -+int custom_video_parse_pci_id(char *device_id, int *vendor, int *device); -+modeline *custom_video_get_backup_mode(); -diff --git a/src/osd/windows/custom_video_adl.cpp b/src/osd/windows/custom_video_adl.cpp -new file mode 100644 -index 00000000000..5d90fc127b1 ---- /dev/null -+++ b/src/osd/windows/custom_video_adl.cpp -@@ -0,0 +1,376 @@ -+/************************************************************** -+ -+ custom_video_adl.cpp - ATI/AMD ADL library -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+// Constants and structures ported from AMD ADL SDK files -+ -+#include <windows.h> -+#include "emu.h" -+#include "custom_video_adl.h" -+ -+bool enum_displays(HINSTANCE h_dll); -+ -+typedef void* (__stdcall *ADL_MAIN_MALLOC_CALLBACK)(int); -+typedef int (*ADL_MAIN_CONTROL_CREATE)(ADL_MAIN_MALLOC_CALLBACK, int); -+typedef int (*ADL_MAIN_CONTROL_DESTROY)(); -+typedef int (*ADL_ADAPTER_NUMBEROFADAPTERS_GET) (int*); -+typedef int (*ADL_ADAPTER_ADAPTERINFO_GET) (LPAdapterInfo, int); -+typedef int (*ADL_DISPLAY_DISPLAYINFO_GET) (int, int *, ADLDisplayInfo **, int); -+typedef int (*ADL_DISPLAY_MODETIMINGOVERRIDE_GET) (int iAdapterIndex, int iDisplayIndex, ADLDisplayMode *lpModeIn, ADLDisplayModeInfo *lpModeInfoOut); -+typedef int (*ADL_DISPLAY_MODETIMINGOVERRIDE_SET) (int iAdapterIndex, int iDisplayIndex, ADLDisplayModeInfo *lpMode, int iForceUpdate); -+typedef int (*ADL_DISPLAY_MODETIMINGOVERRIDELIST_GET) (int iAdapterIndex, int iDisplayIndex, int iMaxNumOfOverrides, ADLDisplayModeInfo *lpModeInfoList, int *lpNumOfOverrides); -+ -+ADL_ADAPTER_NUMBEROFADAPTERS_GET ADL_Adapter_NumberOfAdapters_Get; -+ADL_ADAPTER_ADAPTERINFO_GET ADL_Adapter_AdapterInfo_Get; -+ADL_DISPLAY_DISPLAYINFO_GET ADL_Display_DisplayInfo_Get; -+ADL_DISPLAY_MODETIMINGOVERRIDE_GET ADL_Display_ModeTimingOverride_Get; -+ADL_DISPLAY_MODETIMINGOVERRIDE_SET ADL_Display_ModeTimingOverride_Set; -+ADL_DISPLAY_MODETIMINGOVERRIDELIST_GET ADL_Display_ModeTimingOverrideList_Get; -+ -+HINSTANCE hDLL; -+LPAdapterInfo lpAdapterInfo = NULL; -+LPAdapterList lpAdapter; -+int iNumberAdapters; -+int cat_version, sub_version; -+ -+int invert_pol(bool on_read) { return ((cat_version <= 12) || (cat_version >= 15 && on_read)); } -+int interlace_factor(bool interlace, bool on_read) { return interlace && ((cat_version <= 12) || (cat_version >= 15 && on_read))? 2 : 1; } -+ -+ -+//============================================================ -+// memory allocation callbacks -+//============================================================ -+ -+void* __stdcall ADL_Main_Memory_Alloc(int iSize) -+{ -+ void* lpBuffer = malloc(iSize); -+ return lpBuffer; -+} -+ -+void __stdcall ADL_Main_Memory_Free(void** lpBuffer) -+{ -+ if (NULL != *lpBuffer) -+ { -+ free(*lpBuffer); -+ *lpBuffer = NULL; -+ } -+} -+ -+//============================================================ -+// adl_get_driver_version -+//============================================================ -+ -+bool adl_get_driver_version(char *device_key) -+{ -+ HKEY hkey; -+ bool found = false; -+ -+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, device_key, 0, KEY_READ , &hkey) == ERROR_SUCCESS) -+ { -+ BYTE cat_ver[32]; -+ DWORD length = sizeof(cat_ver); -+ if ((RegQueryValueExA(hkey, "Catalyst_Version", NULL, NULL, cat_ver, &length) == ERROR_SUCCESS) || -+ (RegQueryValueExA(hkey, "RadeonSoftwareVersion", NULL, NULL, cat_ver, &length) == ERROR_SUCCESS)) -+ { -+ found = true; -+ sscanf((char *)cat_ver, "%d.%d", &cat_version, &sub_version); -+ osd_printf_verbose("AMD driver version %d.%d\n", cat_version, sub_version); -+ } -+ RegCloseKey(hkey); -+ } -+ return found; -+} -+ -+//============================================================ -+// adl_open -+//============================================================ -+ -+int adl_open() -+{ -+ ADL_MAIN_CONTROL_CREATE ADL_Main_Control_Create; -+ int ADL_Err = ADL_ERR; -+ -+ hDLL = LoadLibraryA("atiadlxx.dll"); -+ if (hDLL == NULL) hDLL = LoadLibraryA("atiadlxy.dll"); -+ -+ if (hDLL != NULL) -+ { -+ ADL_Main_Control_Create = (ADL_MAIN_CONTROL_CREATE)GetProcAddress(hDLL, "ADL_Main_Control_Create"); -+ if (ADL_Main_Control_Create != NULL) -+ ADL_Err = ADL_Main_Control_Create(ADL_Main_Memory_Alloc, 1); -+ } -+ else -+ { -+ osd_printf_verbose("ADL Library not found!\n"); -+ } -+ -+ return ADL_Err; -+} -+ -+//============================================================ -+// adl_close -+//============================================================ -+ -+void adl_close() -+{ -+ ADL_MAIN_CONTROL_DESTROY ADL_Main_Control_Destroy; -+ -+ osd_printf_verbose("ATI/AMD ADL close\n"); -+ -+ for (int i = 0; i <= iNumberAdapters - 1; i++) -+ ADL_Main_Memory_Free((void **)&lpAdapter[i].m_display_list); -+ -+ ADL_Main_Memory_Free((void **)&lpAdapterInfo); -+ ADL_Main_Memory_Free((void **)&lpAdapter); -+ -+ ADL_Main_Control_Destroy = (ADL_MAIN_CONTROL_DESTROY)GetProcAddress(hDLL, "ADL_Main_Control_Destroy"); -+ if (ADL_Main_Control_Destroy != NULL) -+ ADL_Main_Control_Destroy(); -+ -+ FreeLibrary(hDLL); -+} -+ -+//============================================================ -+// adl_init -+//============================================================ -+ -+bool adl_init(char *device_name, char *device_key, char *device_id) -+{ -+ int ADL_Err = ADL_ERR; -+ -+ osd_printf_verbose("ATI/AMD ADL init\n"); -+ -+ ADL_Err = adl_open(); -+ if (ADL_Err != ADL_OK) -+ { -+ osd_printf_verbose("ERROR: ADL Initialization error!\n"); -+ return false; -+ } -+ -+ ADL_Adapter_NumberOfAdapters_Get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET)GetProcAddress(hDLL,"ADL_Adapter_NumberOfAdapters_Get"); -+ if (ADL_Adapter_NumberOfAdapters_Get == NULL) -+ { -+ osd_printf_verbose("ERROR: ADL_Adapter_NumberOfAdapters_Get not available!"); -+ return false; -+ } -+ ADL_Adapter_AdapterInfo_Get = (ADL_ADAPTER_ADAPTERINFO_GET)GetProcAddress(hDLL,"ADL_Adapter_AdapterInfo_Get"); -+ if (ADL_Adapter_AdapterInfo_Get == NULL) -+ { -+ osd_printf_verbose("ERROR: ADL_Adapter_AdapterInfo_Get not available!"); -+ return false; -+ } -+ ADL_Display_DisplayInfo_Get = (ADL_DISPLAY_DISPLAYINFO_GET)GetProcAddress(hDLL,"ADL_Display_DisplayInfo_Get"); -+ if (ADL_Display_DisplayInfo_Get == NULL) -+ { -+ osd_printf_verbose("ERROR: ADL_Display_DisplayInfo_Get not available!"); -+ return false; -+ } -+ ADL_Display_ModeTimingOverride_Get = (ADL_DISPLAY_MODETIMINGOVERRIDE_GET)GetProcAddress(hDLL,"ADL_Display_ModeTimingOverride_Get"); -+ if (ADL_Display_ModeTimingOverride_Get == NULL) -+ { -+ osd_printf_verbose("ERROR: ADL_Display_ModeTimingOverride_Get not available!"); -+ return false; -+ } -+ ADL_Display_ModeTimingOverride_Set = (ADL_DISPLAY_MODETIMINGOVERRIDE_SET)GetProcAddress(hDLL,"ADL_Display_ModeTimingOverride_Set"); -+ if (ADL_Display_ModeTimingOverride_Set == NULL) -+ { -+ osd_printf_verbose("ERROR: ADL_Display_ModeTimingOverride_Set not available!"); -+ return false; -+ } -+ ADL_Display_ModeTimingOverrideList_Get = (ADL_DISPLAY_MODETIMINGOVERRIDELIST_GET)GetProcAddress(hDLL,"ADL_Display_ModeTimingOverrideList_Get"); -+ if (ADL_Display_ModeTimingOverrideList_Get == NULL) -+ { -+ osd_printf_verbose("ERROR: ADL_Display_ModeTimingOverrideList_Get not available!"); -+ return false; -+ } -+ -+ if (!enum_displays(hDLL)) -+ { -+ osd_printf_error("ADL error enumerating displays.\n"); -+ return false; -+ } -+ -+ adl_get_driver_version(device_key); -+ -+ osd_printf_verbose("ADL functions retrieved successfully.\n"); -+ return true; -+} -+ -+//============================================================ -+// enum_displays -+//============================================================ -+ -+bool enum_displays(HINSTANCE h_dll) -+{ -+ ADL_Adapter_NumberOfAdapters_Get(&iNumberAdapters); -+ -+ lpAdapterInfo = (LPAdapterInfo)malloc(sizeof(AdapterInfo) * iNumberAdapters); -+ memset(lpAdapterInfo, '\0', sizeof(AdapterInfo) * iNumberAdapters); -+ ADL_Adapter_AdapterInfo_Get(lpAdapterInfo, sizeof(AdapterInfo) * iNumberAdapters); -+ -+ lpAdapter = (LPAdapterList)malloc(sizeof(AdapterList) * iNumberAdapters); -+ for (int i = 0; i <= iNumberAdapters - 1; i++) -+ { -+ lpAdapter[i].m_index = lpAdapterInfo[i].iAdapterIndex; -+ lpAdapter[i].m_bus = lpAdapterInfo[i].iBusNumber; -+ memcpy(&lpAdapter[i].m_name, &lpAdapterInfo[i].strAdapterName, ADL_MAX_PATH); -+ memcpy(&lpAdapter[i].m_display_name, &lpAdapterInfo[i].strDisplayName, ADL_MAX_PATH); -+ lpAdapter[i].m_num_of_displays = 0; -+ lpAdapter[i].m_display_list = 0; -+ ADL_Display_DisplayInfo_Get(lpAdapter[i].m_index, &lpAdapter[i].m_num_of_displays, &lpAdapter[i].m_display_list, 1); -+ } -+ return true; -+} -+ -+//============================================================ -+// get_device_mapping_from_display_name -+//============================================================ -+ -+bool get_device_mapping_from_display_name(char *target_display, int *adapter_index, int *display_index) -+{ -+ for (int i = 0; i <= iNumberAdapters -1; i++) -+ { -+ if (!strcmp(target_display, lpAdapter[i].m_display_name)) -+ { -+ ADLDisplayInfo *display_list; -+ display_list = lpAdapter[i].m_display_list; -+ -+ for (int j = 0; j <= lpAdapter[i].m_num_of_displays - 1; j++) -+ { -+ if (lpAdapter[i].m_index == display_list[j].displayID.iDisplayLogicalAdapterIndex) -+ { -+ *adapter_index = lpAdapter[i].m_index; -+ *display_index = display_list[j].displayID.iDisplayLogicalIndex; -+ return true; -+ } -+ } -+ } -+ } -+ return false; -+} -+ -+//============================================================ -+// ADL_display_mode_info_to_modeline -+//============================================================ -+ -+bool adl_display_mode_info_to_modeline(ADLDisplayModeInfo *dmi, modeline *m) -+{ -+ if (dmi->sDetailedTiming.sHTotal == 0) return false; -+ -+ ADLDetailedTiming dt; -+ memcpy(&dt, &dmi->sDetailedTiming, sizeof(ADLDetailedTiming)); -+ -+ if (dt.sHTotal == 0) return false; -+ -+ m->htotal = dt.sHTotal; -+ m->hactive = dt.sHDisplay; -+ m->hbegin = dt.sHSyncStart; -+ m->hend = dt.sHSyncWidth + m->hbegin; -+ m->vtotal = dt.sVTotal; -+ m->vactive = dt.sVDisplay; -+ m->vbegin = dt.sVSyncStart; -+ m->vend = dt.sVSyncWidth + m->vbegin; -+ m->interlace = (dt.sTimingFlags & ADL_DL_TIMINGFLAG_INTERLACED)? 1 : 0; -+ m->hsync = ((dt.sTimingFlags & ADL_DL_TIMINGFLAG_H_SYNC_POLARITY)? 1 : 0) ^ invert_pol(1); -+ m->vsync = ((dt.sTimingFlags & ADL_DL_TIMINGFLAG_V_SYNC_POLARITY)? 1 : 0) ^ invert_pol(1) ; -+ m->pclock = dt.sPixelClock * 10000; -+ -+ m->height = m->height? m->height : dmi->iPelsHeight; -+ m->width = m->width? m->width : dmi->iPelsWidth; -+ m->refresh = m->refresh? m->refresh : dmi->iRefreshRate / interlace_factor(m->interlace, 1);; -+ m->hfreq = float(m->pclock / m->htotal); -+ m->vfreq = float(m->hfreq / m->vtotal) * (m->interlace? 2 : 1); -+ -+ return true; -+} -+ -+//============================================================ -+// ADL_get_modeline -+//============================================================ -+ -+bool adl_get_modeline(char *target_display, modeline *m) -+{ -+ int adapter_index = 0; -+ int display_index = 0; -+ ADLDisplayMode mode_in; -+ ADLDisplayModeInfo mode_info_out; -+ modeline m_temp = *m; -+ -+ //modeline to ADLDisplayMode -+ mode_in.iPelsHeight = m->height; -+ mode_in.iPelsWidth = m->width; -+ mode_in.iBitsPerPel = 32; -+ mode_in.iDisplayFrequency = m->refresh * interlace_factor(m->interlace, 1); -+ -+ if (!get_device_mapping_from_display_name(target_display, &adapter_index, &display_index)) return false; -+ if (ADL_Display_ModeTimingOverride_Get(adapter_index, display_index, &mode_in, &mode_info_out) != ADL_OK) return false; -+ if (adl_display_mode_info_to_modeline(&mode_info_out, &m_temp)) -+ { -+ if (m_temp.interlace == m->interlace) -+ { -+ memcpy(m, &m_temp, sizeof(modeline)); -+ return true; -+ } -+ } -+ return false; -+} -+ -+//============================================================ -+// ADL_set_modeline -+//============================================================ -+ -+bool adl_set_modeline(char *target_display, modeline *m, int update_mode) -+{ -+ int adapter_index = 0; -+ int display_index = 0; -+ ADLDisplayModeInfo mode_info; -+ ADLDetailedTiming *dt; -+ modeline m_temp; -+ -+ //modeline to ADLDisplayModeInfo -+ mode_info.iTimingStandard = (update_mode & MODELINE_DELETE)? ADL_DL_MODETIMING_STANDARD_DRIVER_DEFAULT : ADL_DL_MODETIMING_STANDARD_CUSTOM; -+ mode_info.iPossibleStandard = 0; -+ mode_info.iRefreshRate = m->refresh * interlace_factor(m->interlace, 0); -+ mode_info.iPelsWidth = m->width; -+ mode_info.iPelsHeight = m->height; -+ -+ //modeline to ADLDetailedTiming -+ dt = &mode_info.sDetailedTiming; -+ dt->sTimingFlags = (m->interlace? ADL_DL_TIMINGFLAG_INTERLACED : 0) | -+ (m->hsync ^ invert_pol(0)? ADL_DL_TIMINGFLAG_H_SYNC_POLARITY : 0) | -+ (m->vsync ^ invert_pol(0)? ADL_DL_TIMINGFLAG_V_SYNC_POLARITY : 0); -+ dt->sHTotal = m->htotal; -+ dt->sHDisplay = m->hactive; -+ dt->sHSyncStart = m->hbegin; -+ dt->sHSyncWidth = m->hend - m->hbegin; -+ dt->sVTotal = m->vtotal; -+ dt->sVDisplay = m->vactive; -+ dt->sVSyncStart = m->vbegin; -+ dt->sVSyncWidth = m->vend - m->vbegin; -+ dt->sPixelClock = m->pclock / 10000; -+ dt->sHOverscanRight = 0; -+ dt->sHOverscanLeft = 0; -+ dt->sVOverscanBottom = 0; -+ dt->sVOverscanTop = 0; -+ -+ if (!get_device_mapping_from_display_name(target_display, &adapter_index, &display_index)) return false; -+ if (ADL_Display_ModeTimingOverride_Set(adapter_index, display_index, &mode_info, (update_mode & MODELINE_UPDATE_LIST)? 1 : 0) != ADL_OK) return false; -+ -+ // read modeline to trigger timing refresh on modded drivers -+ memcpy(&m_temp, m, sizeof(modeline)); -+ if (update_mode & MODELINE_UPDATE) adl_get_modeline(target_display, &m_temp); -+ -+ return true; -+} -diff --git a/src/osd/windows/custom_video_adl.h b/src/osd/windows/custom_video_adl.h -new file mode 100644 -index 00000000000..390041aa8c6 ---- /dev/null -+++ b/src/osd/windows/custom_video_adl.h -@@ -0,0 +1,130 @@ -+/************************************************************** -+ -+ custom_video_adl.h - ATI/AMD ADL library header -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+// Constants and structures ported from AMD ADL SDK files -+ -+#define ADL_MAX_PATH 256 -+#define ADL_OK 0 -+#define ADL_ERR -1 -+ -+//ADL_DETAILED_TIMING.sTimingFlags -+#define ADL_DL_TIMINGFLAG_DOUBLE_SCAN 0x0001 -+#define ADL_DL_TIMINGFLAG_INTERLACED 0x0002 -+#define ADL_DL_TIMINGFLAG_H_SYNC_POLARITY 0x0004 -+#define ADL_DL_TIMINGFLAG_V_SYNC_POLARITY 0x0008 -+ -+//ADL_DISPLAY_MODE_INFO.iTimingStandard -+#define ADL_DL_MODETIMING_STANDARD_CVT 0x00000001 // CVT Standard -+#define ADL_DL_MODETIMING_STANDARD_GTF 0x00000002 // GFT Standard -+#define ADL_DL_MODETIMING_STANDARD_DMT 0x00000004 // DMT Standard -+#define ADL_DL_MODETIMING_STANDARD_CUSTOM 0x00000008 // User-defined standard -+#define ADL_DL_MODETIMING_STANDARD_DRIVER_DEFAULT 0x00000010 // Remove Mode from overriden list -+#define ADL_DL_MODETIMING_STANDARD_CVT_RB 0x00000020 // CVT-RB Standard -+ -+typedef struct AdapterInfo -+{ -+ int iSize; -+ int iAdapterIndex; -+ char strUDID[ADL_MAX_PATH]; -+ int iBusNumber; -+ int iDeviceNumber; -+ int iFunctionNumber; -+ int iVendorID; -+ char strAdapterName[ADL_MAX_PATH]; -+ char strDisplayName[ADL_MAX_PATH]; -+ int iPresent; -+ int iExist; -+ char strDriverPath[ADL_MAX_PATH]; -+ char strDriverPathExt[ADL_MAX_PATH]; -+ char strPNPString[ADL_MAX_PATH]; -+ int iOSDisplayIndex; -+} AdapterInfo, *LPAdapterInfo; -+ -+typedef struct ADLDisplayID -+{ -+ int iDisplayLogicalIndex; -+ int iDisplayPhysicalIndex; -+ int iDisplayLogicalAdapterIndex; -+ int iDisplayPhysicalAdapterIndex; -+} ADLDisplayID, *LPADLDisplayID; -+ -+ -+typedef struct ADLDisplayInfo -+{ -+ ADLDisplayID displayID; -+ int iDisplayControllerIndex; -+ char strDisplayName[ADL_MAX_PATH]; -+ char strDisplayManufacturerName[ADL_MAX_PATH]; -+ int iDisplayType; -+ int iDisplayOutputType; -+ int iDisplayConnector; -+ int iDisplayInfoMask; -+ int iDisplayInfoValue; -+} ADLDisplayInfo, *LPADLDisplayInfo; -+ -+typedef struct ADLDisplayMode -+{ -+ int iPelsHeight; -+ int iPelsWidth; -+ int iBitsPerPel; -+ int iDisplayFrequency; -+} ADLDisplayMode; -+ -+typedef struct ADLDetailedTiming -+{ -+ int iSize; -+ short sTimingFlags; -+ short sHTotal; -+ short sHDisplay; -+ short sHSyncStart; -+ short sHSyncWidth; -+ short sVTotal; -+ short sVDisplay; -+ short sVSyncStart; -+ short sVSyncWidth; -+ unsigned short sPixelClock; -+ short sHOverscanRight; -+ short sHOverscanLeft; -+ short sVOverscanBottom; -+ short sVOverscanTop; -+ short sOverscan8B; -+ short sOverscanGR; -+} ADLDetailedTiming; -+ -+typedef struct ADLDisplayModeInfo -+{ -+ int iTimingStandard; -+ int iPossibleStandard; -+ int iRefreshRate; -+ int iPelsWidth; -+ int iPelsHeight; -+ ADLDetailedTiming sDetailedTiming; -+} ADLDisplayModeInfo; -+ -+typedef struct AdapterList -+{ -+ int m_index; -+ int m_bus; -+ char m_name[ADL_MAX_PATH]; -+ char m_display_name[ADL_MAX_PATH]; -+ int m_num_of_displays; -+ ADLDisplayInfo *m_display_list; -+} AdapterList, *LPAdapterList; -+ -+bool adl_init(char *device_name, char *device_key, char *device_id); -+void adl_close(); -+bool adl_get_modeline(char *target_display, modeline *m); -+bool adl_set_modeline(char *target_display, modeline *m, int update_mode); -diff --git a/src/osd/windows/custom_video_ati.cpp b/src/osd/windows/custom_video_ati.cpp -new file mode 100644 -index 00000000000..3bf863afd0a ---- /dev/null -+++ b/src/osd/windows/custom_video_ati.cpp -@@ -0,0 +1,309 @@ -+/************************************************************** -+ -+ custom_video_ati.cpp - ATI legacy library -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+#include <windows.h> -+ -+#include "emu.h" -+#include "custom_video_ati.h" -+ -+#define CRTC_DOUBLE_SCAN 0x0001 -+#define CRTC_INTERLACED 0x0002 -+#define CRTC_H_SYNC_POLARITY 0x0004 -+#define CRTC_V_SYNC_POLARITY 0x0008 -+ -+static int get_DWORD(int i, char *lp_data); -+static int get_DWORD_BCD(int i, char *lp_data); -+static void set_DWORD(char *data_string, UINT32 data_word, int offset); -+static void set_DWORD_BCD(char *data_string, UINT32 data_word, int offset); -+static int os_version(void); -+static bool is_elevated(); -+static int win_interlace_factor(modeline *mode); -+ -+char m_device_name[32]; -+char m_device_key[256]; -+int win_version; -+ -+//============================================================ -+// ati_custom_video_init -+//============================================================ -+ -+bool ati_init(char *device_name, char *device_key, char *device_id) -+{ -+ osd_printf_verbose("ATI legacy init\n"); -+ -+ // Get Windows version -+ win_version = os_version(); -+ -+ if (win_version > 5 && !is_elevated()) -+ { -+ osd_printf_error("ATI legacy error: the program needs administrator rights.\n"); -+ return false; -+ } -+ -+ memcpy(m_device_name, device_name, sizeof(m_device_name)); -+ memcpy(m_device_key, device_key, sizeof(m_device_key)); -+ -+ return true; -+} -+ -+//============================================================ -+// ati_get_modeline -+//============================================================ -+ -+bool ati_get_modeline(modeline *mode) -+{ -+ HKEY hKey; -+ char lp_name[1024]; -+ char lp_data[68]; -+ DWORD length; -+ bool found = false; -+ int refresh_label = mode->refresh_label? mode->refresh_label : mode->refresh * win_interlace_factor(mode); -+ int vfreq_incr = 0; -+ -+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, m_device_key, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) -+ { -+ sprintf(lp_name, "DALDTMCRTBCD%dx%dx0x%d", mode->width, mode->height, refresh_label); -+ length = sizeof(lp_data); -+ -+ if (RegQueryValueExA(hKey, lp_name, NULL, NULL, (LPBYTE)lp_data, &length) == ERROR_SUCCESS && length == sizeof(lp_data)) -+ found = true; -+ else if (win_version > 5 && mode->interlace) -+ { -+ vfreq_incr = 1; -+ sprintf(lp_name, "DALDTMCRTBCD%dx%dx0x%d", mode->width, mode->height, refresh_label + vfreq_incr); -+ if (RegQueryValueExA(hKey, lp_name, NULL, NULL, (LPBYTE)lp_data, &length) == ERROR_SUCCESS && length == sizeof(lp_data)) -+ found = true; -+ } -+ if (found) -+ { -+ mode->pclock = get_DWORD_BCD(36, lp_data) * 10000; -+ mode->hactive = get_DWORD_BCD(8, lp_data); -+ mode->hbegin = get_DWORD_BCD(12, lp_data); -+ mode->hend = get_DWORD_BCD(16, lp_data) + mode->hbegin; -+ mode->htotal = get_DWORD_BCD(4, lp_data); -+ mode->vactive = get_DWORD_BCD(24, lp_data); -+ mode->vbegin = get_DWORD_BCD(28, lp_data); -+ mode->vend = get_DWORD_BCD(32, lp_data) + mode->vbegin; -+ mode->vtotal = get_DWORD_BCD(20, lp_data); -+ mode->interlace = (get_DWORD(0, lp_data) & CRTC_INTERLACED)?1:0; -+ mode->hsync = (get_DWORD(0, lp_data) & CRTC_H_SYNC_POLARITY)?0:1; -+ mode->vsync = (get_DWORD(0, lp_data) & CRTC_V_SYNC_POLARITY)?0:1; -+ mode->hfreq = mode->pclock / mode->htotal; -+ mode->vfreq = mode->hfreq / mode->vtotal * (mode->interlace?2:1); -+ mode->refresh_label = refresh_label; -+ -+ int checksum = 65535 - get_DWORD(0, lp_data) - mode->htotal - mode->hactive - mode->hend -+ - mode->vtotal - mode->vactive - mode->vend - mode->pclock/10000; -+ if (checksum != get_DWORD(64, lp_data)) -+ osd_printf_verbose("bad checksum! "); -+ } -+ RegCloseKey(hKey); -+ return (found); -+ } -+ osd_printf_info("Failed opening registry entry for mode.\n"); -+ return false; -+} -+ -+//============================================================ -+// ati_set_modeline -+//============================================================ -+ -+bool ati_set_modeline(modeline *mode) -+{ -+ HKEY hKey; -+ char lp_name[1024]; -+ char lp_data[68]; -+ long checksum; -+ bool found = false; -+ int refresh_label = mode->refresh_label? mode->refresh_label : mode->refresh * win_interlace_factor(mode); -+ int vfreq_incr = 0; -+ -+ memset(lp_data, 0, sizeof(lp_data)); -+ set_DWORD_BCD(lp_data, (int)mode->pclock/10000, 36); -+ set_DWORD_BCD(lp_data, mode->hactive, 8); -+ set_DWORD_BCD(lp_data, mode->hbegin, 12); -+ set_DWORD_BCD(lp_data, mode->hend - mode->hbegin, 16); -+ set_DWORD_BCD(lp_data, mode->htotal, 4); -+ set_DWORD_BCD(lp_data, mode->vactive, 24); -+ set_DWORD_BCD(lp_data, mode->vbegin, 28); -+ set_DWORD_BCD(lp_data, mode->vend - mode->vbegin, 32); -+ set_DWORD_BCD(lp_data, mode->vtotal, 20); -+ set_DWORD(lp_data, (mode->interlace?CRTC_INTERLACED:0) | (mode->hsync?0:CRTC_H_SYNC_POLARITY) | (mode->vsync?0:CRTC_V_SYNC_POLARITY), 0); -+ -+ checksum = 65535 - get_DWORD(0, lp_data) - mode->htotal - mode->hactive - mode->hend -+ - mode->vtotal - mode->vactive - mode->vend - mode->pclock/10000; -+ set_DWORD(lp_data, checksum, 64); -+ -+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, m_device_key, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) -+ { -+ sprintf (lp_name, "DALDTMCRTBCD%dx%dx0x%d", mode->width, mode->height, refresh_label); -+ -+ if (RegQueryValueExA(hKey, lp_name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) -+ found = true; -+ else if (win_version > 5 && mode->interlace) -+ { -+ vfreq_incr = 1; -+ sprintf(lp_name, "DALDTMCRTBCD%dx%dx0x%d", mode->width, mode->height, refresh_label + vfreq_incr); -+ if (RegQueryValueExA(hKey, lp_name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) -+ found = true; -+ } -+ -+ if (!(found && RegSetValueExA(hKey, lp_name, 0, REG_BINARY, (LPBYTE)lp_data, 68) == ERROR_SUCCESS)) -+ osd_printf_info("Failed saving registry entry %s\n", lp_name); -+ -+ RegCloseKey(hKey); -+ return (found); -+ } -+ -+ osd_printf_info("Failed updating registry entry for mode.\n"); -+ return 0; -+} -+ -+//============================================================ -+// ati_refresh_timings -+//============================================================ -+ -+void ati_refresh_timings(void) -+{ -+ int iModeNum = 0; -+ DEVMODEA lpDevMode; -+ -+ memset(&lpDevMode, 0, sizeof(DEVMODEA)); -+ lpDevMode.dmSize = sizeof(DEVMODEA); -+ -+ while (EnumDisplaySettingsExA(m_device_name, iModeNum, &lpDevMode, 0) != 0) -+ iModeNum++; -+} -+ -+//============================================================ -+// get_DWORD -+//============================================================ -+ -+static int get_DWORD(int i, char *lp_data) -+{ -+ char out[32] = ""; -+ UINT32 x; -+ -+ sprintf(out, "%02X%02X%02X%02X", lp_data[i]&0xFF, lp_data[i+1]&0xFF, lp_data[i+2]&0xFF, lp_data[i+3]&0xFF); -+ sscanf(out, "%08X", &x); -+ return x; -+} -+ -+//============================================================ -+// get_DWORD_BCD -+//============================================================ -+ -+static int get_DWORD_BCD(int i, char *lp_data) -+{ -+ char out[32] = ""; -+ UINT32 x; -+ -+ sprintf(out, "%02X%02X%02X%02X", lp_data[i]&0xFF, lp_data[i+1]&0xFF, lp_data[i+2]&0xFF, lp_data[i+3]&0xFF); -+ sscanf(out, "%d", &x); -+ return x; -+} -+ -+//============================================================ -+// set_DWORD -+//============================================================ -+ -+static void set_DWORD(char *data_string, UINT32 data_dword, int offset) -+{ -+ char *p_dword = (char*)&data_dword; -+ -+ data_string[offset] = p_dword[3]&0xFF; -+ data_string[offset+1] = p_dword[2]&0xFF; -+ data_string[offset+2] = p_dword[1]&0xFF; -+ data_string[offset+3] = p_dword[0]&0xFF; -+} -+ -+//============================================================ -+// set_DWORD_BCD -+//============================================================ -+ -+static void set_DWORD_BCD(char *data_string, UINT32 data_dword, int offset) -+{ -+ if (data_dword < 100000000) -+ { -+ int low_word, high_word; -+ int a, b, c, d; -+ char out[32] = ""; -+ -+ low_word = data_dword % 10000; -+ high_word = data_dword / 10000; -+ -+ sprintf(out, "%d %d %d %d", high_word / 100, high_word % 100 , low_word / 100, low_word % 100); -+ sscanf(out, "%02X %02X %02X %02X", &a, &b, &c, &d); -+ -+ data_string[offset] = a; -+ data_string[offset+1] = b; -+ data_string[offset+2] = c; -+ data_string[offset+3] = d; -+ } -+} -+ -+//============================================================ -+// os_version -+//============================================================ -+ -+static int os_version(void) -+{ -+ OSVERSIONINFOA lpVersionInfo; -+ -+ memset(&lpVersionInfo, 0, sizeof(OSVERSIONINFOA)); -+ lpVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); -+ GetVersionExA (&lpVersionInfo); -+ -+ return lpVersionInfo.dwMajorVersion; -+} -+ -+//============================================================ -+// is_elevated -+//============================================================ -+ -+static bool is_elevated() -+{ -+ HANDLE htoken; -+ bool result = false; -+ -+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &htoken)) -+ return false; -+ -+ TOKEN_ELEVATION te = {0}; -+ DWORD dw_return_length; -+ -+ if (GetTokenInformation(htoken, TokenElevation, &te, sizeof(te), &dw_return_length)) -+ { -+ if (te.TokenIsElevated) -+ { -+ result = true; -+ } -+ } -+ -+ CloseHandle(htoken); -+ return (result); -+} -+ -+//============================================================ -+// win_interlace_factor -+//============================================================ -+ -+static int win_interlace_factor(modeline *mode) -+{ -+ if (win_version > 5 && mode->interlace) -+ return 2; -+ -+ return 1; -+} -diff --git a/src/osd/windows/custom_video_ati.h b/src/osd/windows/custom_video_ati.h -new file mode 100644 -index 00000000000..25061d53340 ---- /dev/null -+++ b/src/osd/windows/custom_video_ati.h -@@ -0,0 +1,20 @@ -+/************************************************************** -+ -+ custom_video_ati.h - ATI legacy library header -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+bool ati_init(char *device_name, char *device_key, char *device_id); -+bool ati_get_modeline(modeline *mode); -+bool ati_set_modeline(modeline *mode); -+void ati_refresh_timings(void); -diff --git a/src/osd/windows/custom_video_ati_family.cpp b/src/osd/windows/custom_video_ati_family.cpp -new file mode 100644 -index 00000000000..0e0ac8c706a ---- /dev/null -+++ b/src/osd/windows/custom_video_ati_family.cpp -@@ -0,0 +1,850 @@ -+/************************************************************** -+ -+ custom_video_ati_family.cpp - ATI/AMD Radeon family -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+/* Constants and structures ported from Linux open source drivers: -+ drivers\gpu\drm\radeon\radeon.h -+ drivers\gpu\drm\radeon\radeon_family.h -+ include\drm\drm_pciids.h -+*/ -+ -+#ifndef RADEON_FAMILY_H -+#define RADEON_FAMILY_H -+ -+struct pci_device_id -+{ -+ int vendor, device; -+ int subvendor, subdevice; -+ int _class, _class_mask; -+ int driver_data; -+}; -+ -+enum radeon_family -+{ -+ CHIP_R100 = 0, -+ CHIP_RV100, -+ CHIP_RS100, -+ CHIP_RV200, -+ CHIP_RS200, -+ CHIP_R200, -+ CHIP_RV250, -+ CHIP_RS300, -+ CHIP_RV280, -+ CHIP_R300, -+ CHIP_R350, -+ CHIP_RV350, -+ CHIP_RV380, -+ CHIP_R420, -+ CHIP_R423, -+ CHIP_RV410, -+ CHIP_RS400, -+ CHIP_RS480, -+ CHIP_RS600, -+ CHIP_RS690, -+ CHIP_RS740, -+ CHIP_RV515, -+ CHIP_R520, -+ CHIP_RV530, -+ CHIP_RV560, -+ CHIP_RV570, -+ CHIP_R580, -+ CHIP_R600, -+ CHIP_RV610, -+ CHIP_RV630, -+ CHIP_RV670, -+ CHIP_RV620, -+ CHIP_RV635, -+ CHIP_RS780, -+ CHIP_RS880, -+ CHIP_RV770, -+ CHIP_RV730, -+ CHIP_RV710, -+ CHIP_RV740, -+ CHIP_CEDAR, -+ CHIP_REDWOOD, -+ CHIP_JUNIPER, -+ CHIP_CYPRESS, -+ CHIP_HEMLOCK, -+ CHIP_PALM, -+ CHIP_SUMO, -+ CHIP_SUMO2, -+ CHIP_BARTS, -+ CHIP_TURKS, -+ CHIP_CAICOS, -+ CHIP_CAYMAN, -+ CHIP_ARUBA, -+ CHIP_TAHITI, -+ CHIP_PITCAIRN, -+ CHIP_VERDE, -+ CHIP_OLAND, -+ CHIP_HAINAN, -+ CHIP_BONAIRE, -+ CHIP_KAVERI, -+ CHIP_KABINI, -+ CHIP_HAWAII, -+ CHIP_MULLINS, -+ CHIP_LAST, -+}; -+ -+enum radeon_chip_flags -+{ -+ RADEON_FAMILY_MASK = 0x0000ffffUL, -+ RADEON_FLAGS_MASK = 0xffff0000UL, -+ RADEON_IS_MOBILITY = 0x00010000UL, -+ RADEON_IS_IGP = 0x00020000UL, -+ RADEON_SINGLE_CRTC = 0x00040000UL, -+ RADEON_IS_AGP = 0x00080000UL, -+ RADEON_HAS_HIERZ = 0x00100000UL, -+ RADEON_IS_PCIE = 0x00200000UL, -+ RADEON_NEW_MEMMAP = 0x00400000UL, -+ RADEON_IS_PCI = 0x00800000UL, -+ RADEON_IS_IGPGART = 0x01000000UL, -+ RADEON_IS_PX = 0x02000000UL, -+}; -+ -+#define PCI_ANY_ID (~0) -+ -+#define radeon_PCI_IDS \ -+ {0x1002, 0x1304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1305, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1306, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1309, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x130A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x130B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x130C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x130D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x130E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x130F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1313, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1316, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1317, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x1318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x131B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x131C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x131D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x3151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x3155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \ -+ {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \ -+ {0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ -+ {0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ -+ {0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ -+ {0x1002, 0x4147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ -+ {0x1002, 0x4148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ -+ {0x1002, 0x4149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ -+ {0x1002, 0x414A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ -+ {0x1002, 0x414B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ -+ {0x1002, 0x4150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ -+ {0x1002, 0x4151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ -+ {0x1002, 0x4152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ -+ {0x1002, 0x4153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ -+ {0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ -+ {0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ -+ {0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ -+ {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \ -+ {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ -+ {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ -+ {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ -+ {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4B48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4C6E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ -+ {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ -+ {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ -+ {0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ -+ {0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ -+ {0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ -+ {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ -+ {0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ -+ {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ -+ {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ -+ {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ -+ {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ -+ {0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ -+ {0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ -+ {0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ -+ {0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \ -+ {0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \ -+ {0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ -+ {0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ -+ {0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_SINGLE_CRTC}, \ -+ {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5657, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \ -+ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x5974, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x5975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ -+ {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ -+ {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ -+ {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ -+ {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ -+ {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_SINGLE_CRTC}, \ -+ {0x1002, 0x5a41, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x5a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ -+ {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6600, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6602, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6603, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6604, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6605, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6606, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6607, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6620, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6623, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6631, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x665c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x665d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6664, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6665, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6667, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x666F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAINAN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6703, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6704, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6705, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6706, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6707, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6708, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6709, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6718, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6719, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x671c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x671d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x671f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6721, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6722, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6723, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6725, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6726, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6727, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6728, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6729, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6739, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x673e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6740, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6741, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6742, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6743, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6744, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6745, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6746, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6747, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6748, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x674A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6759, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x675B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x675D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x675F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6761, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6762, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6763, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6764, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6765, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6766, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6771, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x677B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6784, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6788, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x678A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6790, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6791, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6792, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x679B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67A8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67A9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67AA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67B0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67B8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67B9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67BA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x67BE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HAWAII|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6816, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6817, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6818, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6821, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6822, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6823, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6824, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6826, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6827, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x682A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x682C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x683B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x683D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x683F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6842, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6843, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6849, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x684C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6888, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6889, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x688A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x688C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x688D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6898, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x6899, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x689b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x689c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x689d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x689e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68a0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68a8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68a9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68ba, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68be, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68bf, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68c7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68c8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68c9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68d9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68de, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68e0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68e1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68e4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68e5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68e8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68e9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68f1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68f2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68f8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68f9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68fa, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x68fe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x710A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x710B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x710C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x710E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x710F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7143, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x714A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x714B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x714C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x714D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x714E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x714F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x715E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x715F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7183, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7186, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7187, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7188, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x718A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x718B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x718C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x718D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x718F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7193, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x719B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x719F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71C3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71D2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71D4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71D5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71D6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x71DE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7244, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7245, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7247, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7248, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x724A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x724B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x724C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x724D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x724E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x724F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7280, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7283, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7284, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x728B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x728C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7291, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7293, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7297, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x791f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x793f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7941, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x7942, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x796c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x796d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x796e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x796f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ -+ {0x1002, 0x9400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9402, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9403, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x940A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x940B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x940F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94A3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94B3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94B5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94B9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9442, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9444, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x944A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x944B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x944C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x944E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9452, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9456, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x945A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x945B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x945E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x946A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x946B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x947A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x947B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9487, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9488, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9489, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x948A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x948F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9490, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9491, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9495, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9498, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x949C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x949E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x949F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94C3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94C8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x94CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9504, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9505, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9506, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9507, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9508, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9509, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x950F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9515, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9517, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9519, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9540, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9541, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9542, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x954E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x954F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9553, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9555, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9557, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x955f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9580, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9581, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9583, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9586, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9587, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9588, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9589, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x958A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x958B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x958C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x958D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x958E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x958F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9590, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9593, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9595, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9596, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9597, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9599, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x959B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x95CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ -+ {0x1002, 0x9610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9612, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9614, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9615, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9616, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9642, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ -+ {0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ -+ {0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ -+ {0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x964e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ -+ {0x1002, 0x964f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ -+ {0x1002, 0x9710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9714, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9715, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9804, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9807, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x980A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9832, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9833, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x983a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x983b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x983c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x983d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x983e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x983f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KABINI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9851, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9852, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9853, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9854, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9855, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9856, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9857, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x985A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x985B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x985C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x985D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x985E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9904, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9905, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9906, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9908, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9909, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x990A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x990B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x990C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x990D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x990E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x990F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9910, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9913, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9917, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9990, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9991, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9993, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9994, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9995, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9996, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9997, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9998, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9999, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x999A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x999B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x999C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x999D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x99A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x99A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x99A4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0, 0, 0} -+ -+static struct pci_device_id pciidlist[] = {radeon_PCI_IDS}; -+ -+//============================================================ -+// ati_family -+//============================================================ -+ -+int ati_family(int vendor, int device) -+{ -+ int i = 0; -+ while (pciidlist[i].vendor) -+ { -+ if (pciidlist[i].vendor == vendor && pciidlist[i].device == device) -+ return (pciidlist[i].driver_data & RADEON_FAMILY_MASK); -+ i++; -+ } -+ // Not found, must be newer -+ if (vendor == 0x1002) -+ return CHIP_LAST; -+ -+ return 0; -+} -+ -+//============================================================ -+// ati_is_legacy -+//============================================================ -+ -+bool ati_is_legacy(int vendor, int device) -+{ -+ return (ati_family(vendor, device) < CHIP_CEDAR); -+} -+ -+#endif -\ No newline at end of file -diff --git a/src/osd/windows/custom_video_pstrip.cpp b/src/osd/windows/custom_video_pstrip.cpp -new file mode 100644 -index 00000000000..151b6daf63a ---- /dev/null -+++ b/src/osd/windows/custom_video_pstrip.cpp -@@ -0,0 +1,529 @@ -+/************************************************************** -+ -+ custom_video_pstrip.cpp - PowerStrip interface routines -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+/* 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) */ -+ -+// standard windows headers -+#include <windows.h> -+#include <stdio.h> -+ -+// MAME headers -+#include "emu.h" -+ -+// PowerStrip header -+#include "custom_video_pstrip.h" -+ -+//============================================================ -+// GLOBALS -+//============================================================ -+ -+static HWND hPSWnd; -+static MonitorTiming timing_backup; -+ -+//============================================================ -+// 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 -+ -+//============================================================ -+// ps_init -+//============================================================ -+ -+int ps_init(int monitor_index, modeline *modeline) -+{ -+ hPSWnd = FindWindowA("TPShidden", NULL); -+ -+ if (hPSWnd) -+ { -+ osd_printf_verbose("PStrip: PowerStrip found!\n"); -+ if (ps_get_monitor_timing(monitor_index, &timing_backup) && modeline) -+ { -+ ps_pstiming_to_modeline(&timing_backup, modeline); -+ return 1; -+ } -+ } -+ else -+ osd_printf_verbose("PStrip: Could not get PowerStrip API interface\n"); -+ -+ return 0; -+} -+ -+//============================================================ -+// ps_reset -+//============================================================ -+ -+int ps_reset(int monitor_index) -+{ -+ return ps_set_monitor_timing(monitor_index, &timing_backup); -+} -+ -+//============================================================ -+// ps_get_modeline -+//============================================================ -+ -+int ps_get_modeline(int monitor_index, modeline *modeline) -+{ -+ MonitorTiming timing = {0}; -+ -+ if (ps_get_monitor_timing(monitor_index, &timing)) -+ { -+ ps_pstiming_to_modeline(&timing, modeline); -+ return 1; -+ } -+ else return 0; -+} -+ -+//============================================================ -+// ps_set_modeline -+//============================================================ -+ -+int ps_set_modeline(int monitor_index, modeline *modeline) -+{ -+ MonitorTiming timing = {0}; -+ -+ ps_modeline_to_pstiming(modeline, &timing); -+ -+ timing.PixelClockInKiloHertz = ps_best_pclock(monitor_index, &timing, timing.PixelClockInKiloHertz); -+ -+ if (ps_set_monitor_timing(monitor_index, &timing)) -+ return 1; -+ else -+ return 0; -+} -+ -+//============================================================ -+// ps_get_monitor_timing -+//============================================================ -+ -+int ps_get_monitor_timing(int monitor_index, MonitorTiming *timing) -+{ -+ LRESULT lresult; -+ char in[256]; -+ -+ if (!hPSWnd) return 0; -+ -+ lresult = SendMessage(hPSWnd, UM_GETTIMING, monitor_index, 0); -+ -+ if (lresult == -1) -+ { -+ osd_printf_verbose("PStrip: Could not get PowerStrip timing string\n"); -+ return 0; -+ } -+ -+ if (!GlobalGetAtomNameA(lresult, in, sizeof(in))) -+ { -+ osd_printf_verbose("PStrip: GlobalGetAtomName failed\n"); -+ return 0; -+ } -+ -+ osd_printf_verbose("PStrip: ps_get_monitor_timing(%d): %s\n", monitor_index, in); -+ -+ ps_read_timing_string(in, timing); -+ -+ GlobalDeleteAtom(lresult); // delete atom created by PowerStrip -+ -+ return 1; -+} -+ -+//============================================================ -+// ps_set_monitor_timing -+//============================================================ -+ -+int ps_set_monitor_timing(int monitor_index, 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, monitor_index, atom); -+ -+ if (lresult < 0) -+ { -+ osd_printf_verbose("PStrip: SendMessage failed\n"); -+ GlobalDeleteAtom(atom); -+ } -+ else -+ { -+ osd_printf_verbose("PStrip: ps_set_monitor_timing(%d): %s\n", monitor_index, out); -+ return 1; -+ } -+ } -+ else osd_printf_verbose("PStrip: ps_set_monitor_timing atom creation failed\n"); -+ -+ return 0; -+} -+ -+//============================================================ -+// ps_set_monitor_timing_string -+//============================================================ -+ -+int ps_set_monitor_timing_string(int monitor_index, char *in) -+{ -+ MonitorTiming timing; -+ -+ ps_read_timing_string(in, &timing); -+ return ps_set_monitor_timing(monitor_index, &timing); -+} -+ -+//============================================================ -+// ps_set_refresh -+//============================================================ -+ -+int ps_set_refresh(int monitor_index, double vfreq) -+{ -+ MonitorTiming timing = {0}; -+ int hht, vvt, new_vvt; -+ int desired_pClock; -+ int best_pClock; -+ -+ memcpy(&timing, &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(monitor_index, &timing, desired_pClock); -+ -+ new_vvt = best_pClock * 1000 / (vfreq * hht); -+ -+ timing.VerticalBackPorch += (new_vvt - vvt); -+ timing.PixelClockInKiloHertz = best_pClock; -+ -+ ps_set_monitor_timing(monitor_index, &timing); -+ ps_get_monitor_timing(monitor_index, &timing); -+ -+ return 1; -+} -+ -+//============================================================ -+// ps_best_pclock -+//============================================================ -+ -+int ps_best_pclock(int monitor_index, MonitorTiming *timing, int desired_pclock) -+{ -+ MonitorTiming timing_read; -+ int best_pclock = 0; -+ -+ osd_printf_verbose("PStrip: ps_best_pclock(%d), getting stable dotclocks for %d...\n", monitor_index, desired_pclock); -+ -+ for (int i = -50; i <= 50; i += 25) -+ { -+ timing->PixelClockInKiloHertz = desired_pclock + i; -+ -+ ps_set_monitor_timing(monitor_index, timing); -+ ps_get_monitor_timing(monitor_index, &timing_read); -+ -+ if (abs(timing_read.PixelClockInKiloHertz - desired_pclock) < abs(desired_pclock - best_pclock)) -+ best_pclock = timing_read.PixelClockInKiloHertz; -+ } -+ -+ osd_printf_verbose("PStrip: ps_best_pclock(%d), new dotclock: %d\n", monitor_index, best_pclock); -+ -+ return best_pclock; -+} -+ -+//============================================================ -+// ps_create_resolution -+//============================================================ -+ -+int ps_create_resolution(int monitor_index, modeline *modeline) -+{ -+ LRESULT lresult; -+ ATOM atom; -+ char out[256]; -+ MonitorTiming timing = {0}; -+ -+ 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, monitor_index, atom); -+ -+ if (lresult < 0) -+ { -+ osd_printf_verbose("PStrip: SendMessage failed\n"); -+ GlobalDeleteAtom(atom); -+ } -+ else -+ { -+ osd_printf_verbose("PStrip: ps_create_resolution(%d): %dx%d succeded \n", -+ modeline->width, modeline->height, monitor_index); -+ return 1; -+ } -+ } -+ else osd_printf_verbose("PStrip: ps_create_resolution atom creation failed\n"); -+ -+ return 0; -+} -+ -+//============================================================ -+// ps_read_timing_string -+//============================================================ -+ -+bool 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; -+} -+ -+//============================================================ -+// ps_fill_timing_string -+//============================================================ -+ -+void 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); -+} -+ -+//============================================================ -+// ps_modeline_to_pstiming -+//============================================================ -+ -+int ps_modeline_to_pstiming(modeline *modeline, MonitorTiming *timing) -+{ -+ 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 0; -+} -+ -+//============================================================ -+// ps_pstiming_to_modeline -+//============================================================ -+ -+int 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); -+ -+ return 0; -+} -+ -+//============================================================ -+// ps_monitor_index -+//============================================================ -+ -+int 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; -+} -diff --git a/src/osd/windows/custom_video_pstrip.h b/src/osd/windows/custom_video_pstrip.h -new file mode 100644 -index 00000000000..b73deb98eca ---- /dev/null -+++ b/src/osd/windows/custom_video_pstrip.h -@@ -0,0 +1,63 @@ -+/************************************************************** -+ -+ custom_video_powerstrip.h - PowerStrip interface routines -+ -+ --------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+//============================================================ -+// TYPE DEFINITIONS -+//============================================================ -+ -+typedef struct -+{ -+ int HorizontalActivePixels; -+ int HorizontalFrontPorch; -+ int HorizontalSyncWidth; -+ int HorizontalBackPorch; -+ int VerticalActivePixels; -+ int VerticalFrontPorch; -+ int VerticalSyncWidth; -+ int VerticalBackPorch; -+ int PixelClockInKiloHertz; -+ union -+ { -+ int w; -+ struct -+ { -+ unsigned :1; -+ unsigned HorizontalPolarityNegative:1; -+ unsigned VerticalPolarityNegative:1; -+ unsigned :29; -+ } b; -+ } TimingFlags; -+} MonitorTiming; -+ -+//============================================================ -+// PROTOTYPES -+//============================================================ -+ -+int ps_init(int monitor_index, modeline *modeline); -+int ps_reset(int monitor_index); -+int ps_get_modeline(int monitor_index, modeline *modeline); -+int ps_set_modeline(int monitor_index, modeline *modeline); -+int ps_get_monitor_timing(int monitor_index, MonitorTiming *timing); -+int ps_set_monitor_timing(int monitor_index, MonitorTiming *timing); -+int ps_set_monitor_timing_string(int monitor_index, char *in); -+int ps_set_refresh(int monitor_index, double vfreq); -+int ps_best_pclock(int monitor_index, MonitorTiming *timing, int desired_pclock); -+int ps_create_resolution(int monitor_index, modeline *modeline); -+bool ps_read_timing_string(char *in, MonitorTiming *timing); -+void ps_fill_timing_string(char *out, MonitorTiming *timing); -+int ps_modeline_to_pstiming(modeline *modeline, MonitorTiming *timing); -+int ps_pstiming_to_modeline(MonitorTiming *timing, modeline *modeline); -+int ps_monitor_index (const char *display_name); -diff --git a/src/osd/windows/switchres_windows.cpp b/src/osd/windows/switchres_windows.cpp -new file mode 100644 -index 00000000000..5a0c052f49a ---- /dev/null -+++ b/src/osd/windows/switchres_windows.cpp -@@ -0,0 +1,516 @@ -+/************************************************************** -+ -+ switchres_windows.cpp - Windows OSD SwitchRes core routines -+ -+ ----------------------------------------------------------- -+ -+ SwitchRes Modeline generation engine for emulation -+ -+ GroovyMAME Integration of SwitchRes into the MAME project -+ Some reworked patches from SailorSat's CabMAME -+ -+ License GPL-2.0+ -+ Copyright 2010-2016 - Chris Kennedy, Antonio Giner -+ -+ **************************************************************/ -+ -+// standard windows headers -+#include <windows.h> -+ -+// MAME headers -+#include "emu.h" -+#include "emuopts.h" -+#include "../../frontend/mame/mameopts.h" -+ -+// MAMEOS headers -+#include "winmain.h" -+#include "window.h" -+ -+// Custom video headers -+#include "custom_video.h" -+ -+#ifdef _MSC_VER -+#define min(a, b) ((a) < (b) ? (a) : (b)) -+#else -+#define min(a,b)({ __typeof__ (a) _a = (a);__typeof__ (b) _b = (b);_a < _b ? _a : _b; }) -+#endif -+ -+//============================================================ -+// PROTOTYPES -+//============================================================ -+ -+int display_get_device_info(const char *screen_option, char *device_name, char *device_id, char *device_key); -+int display_get_available_video_modes(const char *device_name, modeline *mode, modeline *current, config_settings *cs); -+int display_get_desktop_mode(const char *device_name, modeline *current); -+int display_set_desktop_mode(modeline *mode, int flags); -+int display_restore_desktop_mode(int flags); -+ -+static void set_option_osd(running_machine &machine, const char *option_ID, bool state); -+static int copy_to_clipboard(char *txt); -+ -+//============================================================ -+// PARAMETERS -+//============================================================ -+ -+// display modes -+#define DM_INTERLACED 0x00000002 -+#define DISPLAY_MAX 16 -+ -+//============================================================ -+// LOCAL VARIABLES -+//============================================================ -+ -+static char m_device_name[32]; -+static char m_device_id[128]; -+static char m_device_key[128]; -+static DEVMODEA desktop_devmode; -+ -+//============================================================ -+// switchres_init_osd -+//============================================================ -+ -+bool switchres_init_osd(running_machine &machine) -+{ -+ config_settings *cs = &machine.switchres.cs; -+ game_info *game = &machine.switchres.game; -+ modeline *mode_table = machine.switchres.video_modes; -+ modeline *user_mode = &machine.switchres.user_mode; -+ monitor_range *range = machine.switchres.range; -+ const char * screen, * aspect; -+ char resolution[32]={'\x00'}; -+ modeline desktop_mode; -+ -+ windows_options &options = downcast<windows_options &>(machine.options()); -+ -+ // Initialize structures and config settings -+ memset(&desktop_mode, 0, sizeof(struct modeline)); -+ memset(cs, 0, sizeof(struct config_settings)); -+ memset(game, 0, sizeof(struct game_info)); -+ -+ // Init Switchres common info -+ switchres_init(machine); -+ -+ // Complete config settings -+ cs->monitor_count = options.numscreens(); -+ cs->doublescan = 0; -+ -+ // Get device info -+ screen = strcmp(options.screen(0), "auto")? options.screen(0) : options.screen(); -+ display_get_device_info(screen, m_device_name, m_device_id, m_device_key); -+ -+ // Get current desktop resolution -+ display_get_desktop_mode(m_device_name, &desktop_mode); -+ -+ // Initialize custom video -+ custom_video_init(m_device_name, m_device_id, &desktop_mode, user_mode, mode_table, -+ options.powerstrip()? CUSTOM_VIDEO_TIMING_POWERSTRIP : 0, -+ options.powerstrip()? (char *)options.ps_timing() : m_device_key); -+ -+ // Get per window resolution -+ strcpy(resolution, strcmp(options.resolution(0), "auto")? options.resolution(0) : options.resolution()); -+ -+ // Get list of available video modes -+ if (!display_get_available_video_modes(m_device_name, mode_table, &desktop_mode, cs)) -+ { -+ set_option_osd(machine, OSDOPTION_SWITCHRES, false); -+ return false; -+ } -+ -+ // Get per window aspect -+ aspect = strcmp(options.aspect(0), "auto")? options.aspect(0) : options.aspect(); -+ if (strcmp(aspect, "auto")) -+ { -+ float num, den; -+ sscanf(aspect, "%f:%f", &num, &den); -+ cs->monitor_aspect = cs->desktop_rotated? den/num : num/den; -+ } -+ else -+ cs->monitor_aspect = STANDARD_CRT_ASPECT; -+ -+ // If monitor is LCD, create automatic specs and force resolution -+ if (!strcmp(cs->monitor, "lcd")) -+ { -+ osd_printf_verbose("SwitchRes: Creating automatic specs for LCD based on %s\n", desktop_mode.hactive? "current timings" : "VESA GTF"); -+ if (!desktop_mode.hactive) modeline_vesa_gtf(&desktop_mode); -+ modeline_to_monitor_range(range, &desktop_mode); -+ monitor_show_range(range); -+ sprintf(resolution, "%dx%d@%d", desktop_mode.width, desktop_mode.height, desktop_mode.refresh); -+ } -+ // Otherwise (non-LCD), convert the user defined modeline into a -resolution option -+ else if (user_mode->hactive) -+ sprintf(resolution, "%dx%d", user_mode->hactive, user_mode->vactive); -+ -+ // Filter the mode table according the -resolution option -+ if (strcmp(resolution, "auto")) -+ { -+ int i = 1; -+ bool found = false; -+ osd_printf_verbose("SwitchRes: -resolution was forced as %s\n", resolution); -+ -+ if ((sscanf(resolution, "%dx%d@%d", &cs->width, &cs->height, &cs->refresh) < 3) && -+ ((!strstr(resolution, "x") || (sscanf(resolution, "%dx%d", &cs->width, &cs->height) != 2)))) -+ osd_printf_info("SwitchRes: illegal -resolution value: %s\n", resolution); -+ -+ else while (mode_table[i].width && i < MAX_MODELINES) -+ { -+ // Lock all modes that don't match the user's -resolution rules -+ if (!( (mode_table[i].width == cs->width || (mode_table[i].type & X_RES_EDITABLE && cs->width <= DUMMY_WIDTH) || cs->width == 0) -+ && (mode_table[i].height == cs->height || cs->height == 0) -+ && (mode_table[i].refresh == cs->refresh || cs->refresh == 0) )) -+ mode_table[i].type |= MODE_DISABLED; -+ -+ else -+ { -+ // If we have an user defined modeline, link its label to current item in mode table -+ if (user_mode->hactive && !found) -+ { -+ user_mode->width = mode_table[i].width; -+ user_mode->height = mode_table[i].height; -+ user_mode->refresh = mode_table[i].refresh; -+ user_mode->type = mode_table[i].type & ~V_FREQ_EDITABLE & ~X_RES_EDITABLE; -+ } -+ mode_table[i].type &= ~MODE_DISABLED; -+ mode_table[i].type |= MODE_USER_DEF; -+ found = true; -+ } -+ i++; -+ } -+ if (!found) -+ osd_printf_info("SwitchRes: -resolution value not available: %s\n", resolution); -+ } -+ -+ // Get game info -+ switchres_get_game_info(machine); -+ -+ return true; -+} -+ -+//============================================================ -+// switchres_modeline_setup -+//============================================================ -+ -+bool switchres_modeline_setup(running_machine &machine) -+{ -+ modeline *best_mode = &machine.switchres.best_mode; -+ windows_options &options = downcast<windows_options &>(machine.options()); -+ windows_osd_interface &osd = downcast<windows_osd_interface &>(machine.osd()); -+ char modeline_txt[256]={'\x00'}; -+ -+ osd_printf_verbose("\nSwitchRes: Entering switchres_modeline_setup\n"); -+ -+ // Find most suitable video mode and generate a modeline for it if we're allowed -+ if (!switchres_get_video_mode(machine)) -+ { -+ set_option_osd(machine, OSDOPTION_SWITCHRES, false); -+ return false; -+ } -+ -+ // Make the new video timings available to the system -+ if (options.modeline_generation()) -+ { -+ if(!custom_video_update_timing(best_mode)) -+ { -+ set_option_osd(machine, OSDOPTION_SWITCHRES, false); -+ return false; -+ } -+ -+ if (options.verbose()) -+ { -+ modeline_print(best_mode, modeline_txt, MS_FULL); -+ copy_to_clipboard(modeline_txt); -+ } -+ } -+ -+ // Set MAME common options -+ switchres_set_options(machine); -+ -+ // Set MAME OSD specific options -+ -+ // Set fullscreen resolution for the OpenGL case -+ if (options.switch_res() && (!strcmp(options.video(), "opengl"))) display_set_desktop_mode(best_mode, CDS_FULLSCREEN); -+ -+ // Black frame insertion / multithreading -+ bool black_frame_insertion = options.black_frame_insertion() && best_mode->result.v_scale > 1 && best_mode->vfreq > 100; -+ set_option_osd(machine, OPTION_BLACK_FRAME_INSERTION, black_frame_insertion); -+ -+ // Vertical synchronization management (autosync) -+ // Disable -syncrefresh if our vfreq is scaled or out of syncrefresh_tolerance (-triplebuffer will be used instead) -+ // Forcing -syncrefresh will override the -triplebuffer setting -+ bool sync_refresh_effective = black_frame_insertion || !((best_mode->result.weight & R_V_FREQ_OFF) || best_mode->result.v_scale > 1); -+ set_option_osd(machine, OPTION_SYNCREFRESH, options.autosync()? sync_refresh_effective : options.sync_refresh()); -+ set_option_osd(machine, WINOPTION_TRIPLEBUFFER, options.autosync()? !sync_refresh_effective : (options.triple_buffer() && !options.sync_refresh())); -+ set_option_osd(machine, OSDOPTION_WAITVSYNC, options.sync_refresh() || options.triple_buffer()); -+ -+ // Set filter options -+ set_option_osd(machine, OSDOPTION_FILTER, ((best_mode->result.weight & R_RES_STRETCH || best_mode->interlace) && (!strcmp(options.video(), "auto") || !strcmp(options.video(), "d3d")))); -+ -+ // Refresh video options -+ osd.extract_video_config(); -+ -+ return true; -+} -+ -+//============================================================ -+// switchres_modeline_remove -+//============================================================ -+ -+bool switchres_modeline_remove(running_machine &machine) -+{ -+ windows_options &options = downcast<windows_options &>(machine.options()); -+ -+ // Restore original video timings -+ if (options.modeline_generation()) custom_video_restore_timing(); -+ -+ // Set destop resolution for the OpenGL case -+ if (options.switch_res() && !strcmp(options.video(), "opengl")) display_restore_desktop_mode(0); -+ -+ // Free custom video api -+ custom_video_close(); -+ -+ return true; -+} -+ -+//============================================================ -+// switchres_resolution_change -+//============================================================ -+ -+bool switchres_resolution_change(win_window_info *window) -+{ -+ running_machine &machine = window->machine(); -+ modeline *best_mode = &machine.switchres.best_mode; -+ modeline previous_mode; -+ -+ // If there's no pending change, just exit -+ if (!switchres_check_resolution_change(machine)) -+ return false; -+ -+ // Get the new resolution -+ previous_mode = *best_mode; -+ switchres_modeline_setup(machine); -+ -+ // Only change resolution if the new one is actually different -+ if (memcmp(&previous_mode, best_mode, offsetof(modeline, result))) -+ { -+ window->m_win_config.width = best_mode->width; -+ window->m_win_config.height = best_mode->height; -+ return true; -+ } -+ -+ return false; -+} -+ -+//============================================================ -+// display_get_desktop_mode -+//============================================================ -+ -+int display_get_desktop_mode(const char *device_name, modeline *current) -+{ -+ memset(&desktop_devmode, 0, sizeof(DEVMODEA)); -+ desktop_devmode.dmSize = sizeof(DEVMODEA); -+ -+ if (EnumDisplaySettingsExA(!strcmp(device_name, "auto")?NULL:device_name, ENUM_CURRENT_SETTINGS, &desktop_devmode, 0)) -+ { -+ if (current) -+ { -+ current->width = desktop_devmode.dmDisplayOrientation == DMDO_DEFAULT || desktop_devmode.dmDisplayOrientation == DMDO_180? desktop_devmode.dmPelsWidth:desktop_devmode.dmPelsHeight; -+ current->height = desktop_devmode.dmDisplayOrientation == DMDO_DEFAULT || desktop_devmode.dmDisplayOrientation == DMDO_180? desktop_devmode.dmPelsHeight:desktop_devmode.dmPelsWidth; -+ current->refresh = desktop_devmode.dmDisplayFrequency; -+ current->interlace = (desktop_devmode.dmDisplayFlags & DM_INTERLACED)?1:0; -+ } -+ return true; -+ } -+ return false; -+} -+ -+//============================================================ -+// display_restore_desktop_mode -+//============================================================ -+ -+int display_restore_desktop_mode(int flags) -+{ -+ if (ChangeDisplaySettingsExA(m_device_name, &desktop_devmode, NULL, 0, 0) == DISP_CHANGE_SUCCESSFUL) -+ return true; -+ -+ return false; -+} -+ -+//============================================================ -+// display_set_desktop_mode -+//============================================================ -+ -+int display_set_desktop_mode(modeline *mode, int flags) -+{ -+ modeline *backup_mode = custom_video_get_backup_mode(); -+ modeline *mode_to_check_interlace = backup_mode->hactive? backup_mode : mode; -+ DEVMODEA lpDevMode; -+ -+ display_get_desktop_mode(m_device_name, NULL); -+ -+ if (mode) -+ { -+ memset(&lpDevMode, 0, sizeof(DEVMODEA)); -+ lpDevMode.dmSize = sizeof(DEVMODEA); -+ lpDevMode.dmPelsWidth = mode->type & MODE_ROTATED? mode->height : mode->width; -+ lpDevMode.dmPelsHeight = mode->type & MODE_ROTATED? mode->width : mode->height; -+ lpDevMode.dmDisplayFrequency = (int)mode->refresh; -+ lpDevMode.dmDisplayFlags = mode_to_check_interlace->interlace?DM_INTERLACED:0; -+ lpDevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; -+ -+ if (ChangeDisplaySettingsExA(m_device_name, &lpDevMode, NULL, flags, 0) == DISP_CHANGE_SUCCESSFUL) -+ return true; -+ } -+ -+ return false; -+} -+ -+//============================================================ -+// display_get_available_video_modes -+//============================================================ -+ -+int display_get_available_video_modes(const char *device_name, modeline *mode, modeline *current, config_settings *cs) -+{ -+ int iModeNum = 0, i = 0, j = 0, k = 1; -+ DEVMODEA lpDevMode; -+ -+ if (!strcmp(device_name, "auto")) -+ device_name = NULL; -+ -+ -+ memset(&lpDevMode, 0, sizeof(DEVMODEA)); -+ lpDevMode.dmSize = sizeof(DEVMODEA); -+ -+ osd_printf_verbose("Switchres: Searching for custom video modes...\n"); -+ -+ while (EnumDisplaySettingsExA(device_name, iModeNum, &lpDevMode, cs->lock_unsupported_modes?0:EDS_RAWMODE) != 0) -+ { -+ if (k == MAX_MODELINES) -+ { -+ osd_printf_verbose("SwitchRes: Warning, too many active modelines for storage %d\n", k); -+ break; -+ } -+ else if (lpDevMode.dmBitsPerPel == 32 && lpDevMode.dmDisplayFixedOutput == DMDFO_DEFAULT) -+ { -+ modeline *m = &mode[k]; -+ memset(m, 0, sizeof(struct modeline)); -+ m->interlace = (lpDevMode.dmDisplayFlags & DM_INTERLACED)?1:0; -+ m->width = lpDevMode.dmDisplayOrientation == DMDO_DEFAULT || lpDevMode.dmDisplayOrientation == DMDO_180? lpDevMode.dmPelsWidth:lpDevMode.dmPelsHeight; -+ m->height = lpDevMode.dmDisplayOrientation == DMDO_DEFAULT || lpDevMode.dmDisplayOrientation == DMDO_180? lpDevMode.dmPelsHeight:lpDevMode.dmPelsWidth; -+ m->refresh = lpDevMode.dmDisplayFrequency; -+ m->hactive = m->width; -+ m->vactive = m->height; -+ m->vfreq = m->refresh; -+ m->type |= lpDevMode.dmDisplayOrientation == DMDO_90 || lpDevMode.dmDisplayOrientation == DMDO_270? MODE_ROTATED : MODE_OK; -+ -+ for (i = 0; i < k; i++) if (mode[i].width == m->width && mode[i].height == m->height && mode[i].refresh == m->refresh) goto found; -+ -+ if (current && m->width == current->width && m->height == current->height && m->refresh == current->refresh) -+ { -+ m->type |= MODE_DESKTOP; -+ if (m->type & MODE_ROTATED) cs->desktop_rotated = true; -+ } -+ -+ osd_printf_verbose("Switchres: [%3d] %4dx%4d @%3d%s %s: ", k, m->width, m->height, m->refresh, m->type & MODE_DESKTOP?"*":"", m->type & MODE_ROTATED?"rot":""); -+ -+ if (custom_video_get_timing(m)) -+ { -+ j++; -+ if (m->type & MODE_DESKTOP) memcpy(current, m, sizeof(modeline)); -+ } -+ k++; -+ } -+ found: -+ iModeNum++; -+ } -+ k--; -+ osd_printf_verbose("SwitchRes: Found %d custom of %d active video modes\n", j, k); -+ return k; -+} -+ -+//============================================================ -+// display_get_device_info -+//============================================================ -+ -+int display_get_device_info(const char *screen_option, char *device_name, char *device_id, char *device_key) -+{ -+ DISPLAY_DEVICEA lpDisplayDevice[DISPLAY_MAX]; -+ int idev = 0; -+ int found = -1; -+ -+ while (idev < DISPLAY_MAX) -+ { -+ memset(&lpDisplayDevice[idev], 0, sizeof(DISPLAY_DEVICEA)); -+ lpDisplayDevice[idev].cb = sizeof(DISPLAY_DEVICEA); -+ -+ if (EnumDisplayDevicesA(NULL, idev, &lpDisplayDevice[idev], 0) == FALSE) -+ break; -+ -+ if ((!strcmp(screen_option, "auto") && (lpDisplayDevice[idev].StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) -+ || !strcmp(screen_option, lpDisplayDevice[idev].DeviceName)) -+ found = idev; -+ -+ idev++; -+ } -+ if (found != -1) -+ { -+ strncpy(device_name, lpDisplayDevice[found].DeviceName, sizeof(m_device_name)); -+ strncpy(device_id, lpDisplayDevice[found].DeviceID, sizeof(m_device_id)); -+ osd_printf_verbose("SwitchRes: %s: %s (%s)\n", device_name, lpDisplayDevice[found].DeviceString, device_id); -+ -+ char *pch; -+ int i; -+ for (i = 0; i < idev; i++) -+ { -+ pch = strstr(lpDisplayDevice[i].DeviceString, lpDisplayDevice[found].DeviceString); -+ if (pch) -+ { -+ found = i; -+ break; -+ } -+ } -+ -+ char *chsrc, *chdst; -+ chdst = device_key; -+ -+ for (chsrc = lpDisplayDevice[i].DeviceKey + 18; *chsrc != 0; chsrc++) -+ *chdst++ = *chsrc; -+ -+ *chdst = 0; -+ } -+ else -+ { -+ osd_printf_verbose("SwitchRes: Failed obtaining default video registry key\n"); -+ return -1; -+ } -+ -+ osd_printf_verbose("SwitchRes: Device key: %s\n", device_key); -+ return 0; -+} -+ -+//============================================================ -+// set_option_osd - option setting wrapper -+//============================================================ -+ -+static void set_option_osd(running_machine &machine, const char *option_ID, bool state) -+{ -+ windows_options &options = downcast<windows_options &>(machine.options()); -+ -+ options.set_value(option_ID, state, OPTION_PRIORITY_SWITCHRES); -+ osd_printf_verbose("SwitchRes: Setting option -%s%s\n", machine.options().bool_value(option_ID)?"":"no", option_ID); -+} -+ -+//============================================================ -+// copy_to_clipboard -+//============================================================ -+ -+static int copy_to_clipboard(char *txt) -+{ -+ HGLOBAL hglb; -+ hglb = GlobalAlloc(GMEM_MOVEABLE, 256); -+ memcpy(GlobalLock(hglb), txt, strlen(txt) + 1); -+ GlobalUnlock(hglb); -+ OpenClipboard(NULL); -+ EmptyClipboard(); -+ SetClipboardData(CF_TEXT, hglb); -+ CloseClipboard(); -+ return 1; -+} -diff --git a/src/osd/windows/video.cpp b/src/osd/windows/video.cpp -index c6f4d3a0a89..5f5dbd64971 100644 ---- a/src/osd/windows/video.cpp -+++ b/src/osd/windows/video.cpp -@@ -190,9 +190,10 @@ void windows_osd_interface::extract_video_config() - video_config.mode = VIDEO_MODE_GDI; - } - video_config.waitvsync = options().wait_vsync(); -- video_config.syncrefresh = options().sync_refresh(); -+ video_config.syncrefresh = machine().options().sync_refresh(); - video_config.triplebuf = options().triple_buffer(); - video_config.switchres = options().switch_res(); -+ video_config.framedelay = options().frame_delay(); - - if (video_config.prescale < 1 || video_config.prescale > 8) - { -diff --git a/src/osd/windows/window.cpp b/src/osd/windows/window.cpp -index 8e723ea6246..16f0ba16a23 100644 ---- a/src/osd/windows/window.cpp -+++ b/src/osd/windows/window.cpp -@@ -55,6 +55,8 @@ using namespace Windows::UI::Core; - #define MAKE_DI_SCAN(scan, isextended) (scan & 0x7f) | (isextended ? 0x80 : 0x00) - #define WINOSD(machine) downcast<windows_osd_interface*>(&machine.osd()) - -+extern bool switchres_resolution_change(win_window_info *window); -+ - //============================================================ - // PARAMETERS - //============================================================ -@@ -88,7 +90,7 @@ using namespace Windows::UI::Core; - - static DWORD main_threadid; - -- -+static BOOL multithreading_enabled = FALSE; - - //============================================================ - // LOCAL VARIABLES -@@ -804,6 +806,11 @@ void win_window_info::create(running_machine &machine, int index, std::shared_pt - // handle error conditions - if (window->m_init_state == -1) - fatalerror("Unable to complete window creation\n"); -+ -+ // create blitting thread -+ multithreading_enabled = options.triple_buffer(); -+ if (multithreading_enabled) -+ window->blit_loop_create(); - } - - std::shared_ptr<osd_monitor_info> win_window_info::monitor_from_rect(const osd_rect* proposed) const -@@ -838,6 +845,10 @@ void win_window_info::destroy() - { - assert(GetCurrentThreadId() == main_threadid); - -+ // destroy blitting thread -+ if (multithreading_enabled) -+ blit_loop_destroy(); -+ - // remove us from the list - osd_common_t::s_window_list.remove(shared_from_this()); - -@@ -851,6 +862,97 @@ void win_window_info::destroy() - - - -+//============================================================ -+// blit_loop_create -+// (blitting thread) -+//============================================================ -+ -+void win_window_info::blit_loop_create() -+{ -+ // set loop as active and lock it until ready -+ m_blitting_active = TRUE; -+ m_blit_lock = TRUE; -+ -+ // create blitting events -+ m_blit_pending = CreateEvent(NULL, FALSE, FALSE, NULL); -+ m_blit_done = CreateEvent(NULL, FALSE, FALSE, NULL); -+ -+ // create blitting thread -+ CreateThread (NULL, 0, blit_loop, (LPVOID)this, 0, &m_blit_threadid); -+ osd_printf_verbose("Blitting thread created\n"); -+} -+ -+//============================================================ -+// blit_loop_destroy -+// (blitting thread) -+//============================================================ -+ -+void win_window_info::blit_loop_destroy() -+{ -+ // turn off blitting flag and wait until thread ends -+ m_blitting_active = FALSE; -+ WaitForSingleObject(m_blit_done, 100); -+ -+ // close blitting events -+ if (m_blit_done) CloseHandle(m_blit_done); -+ if (m_blit_pending) CloseHandle(m_blit_pending); -+ -+ osd_printf_verbose("Blitting thread destroyed\n"); -+} -+ -+//============================================================ -+// blit_loop -+// (blitting thread) -+//============================================================ -+ -+DWORD WINAPI win_window_info::blit_loop(LPVOID lpParameter) -+{ -+ return ((win_window_info *)lpParameter)->blit_loop_wt(); -+} -+ -+DWORD win_window_info::blit_loop_wt() -+{ -+ bool m_throttled; -+ osd_printf_verbose("Blitting thread started\n"); -+ -+ do { -+ WaitForSingleObject(m_blit_pending, INFINITE); -+ m_throttled = machine().video().throttled(); -+ if (!m_blit_lock && has_renderer()) draw_video_contents(NULL, FALSE); -+ if (m_throttled) SetEvent(m_blit_done); -+ } while (m_blitting_active); -+ -+ osd_printf_verbose("Blitting thread ended\n"); -+ -+ return -1; -+} -+ -+//============================================================ -+// blit_lock_set -+// (window thread) -+//============================================================ -+ -+void win_window_info::blit_lock_set() -+{ -+ m_blit_lock = TRUE; -+ osd_printf_verbose("blit_lock = TRUE\n"); -+ Sleep(20); -+} -+ -+//============================================================ -+// blit_lock_release -+// (window thread) -+//============================================================ -+ -+void win_window_info::blit_lock_release() -+{ -+ Sleep(20); -+ m_blit_lock = FALSE; -+ osd_printf_verbose("blit_lock = FALSE\n"); -+} -+ -+ -+ - //============================================================ - // winwindow_video_window_update - // (main thread) -@@ -860,6 +962,7 @@ void win_window_info::update() - { - int targetview, targetorient; - render_layer_config targetlayerconfig; -+ static int frame_count = 0; - - assert(GetCurrentThreadId() == main_threadid); - -@@ -888,11 +991,7 @@ void win_window_info::update() - { - bool got_lock = true; - -- // only block if we're throttled -- if (machine().video().throttled() || timeGetTime() - last_update_time > 250) -- m_render_lock.lock(); -- else -- got_lock = m_render_lock.try_lock(); -+ got_lock = m_render_lock.try_lock(); - - // only render if we were able to get the lock - if (got_lock) -@@ -902,6 +1001,33 @@ void win_window_info::update() - // don't hold the lock; we just used it to see if rendering was still happening - m_render_lock.unlock(); - -+ // check if frame delay has changed -+ static int frame_delay = 0; -+ int new_frame_delay = machine().video().framedelay(); -+ if (new_frame_delay != frame_delay) -+ { -+ video_config.framedelay = new_frame_delay; -+ -+ bool reset_required = ((bool)frame_delay != (bool)new_frame_delay); -+ frame_delay = new_frame_delay; -+ -+ if (reset_required) -+ { -+ reset_fullscreen_renderer(); -+ return; -+ } -+ } -+ -+ // check resolution change -+ if (renderer().m_switchres_mode != nullptr && video_config.switchres && machine().options().changeres()) -+ { -+ if (switchres_resolution_change(this)) -+ { -+ reset_fullscreen_renderer(); -+ return; -+ } -+ } -+ - // ensure the target bounds are up-to-date, and then get the primitives - primlist = renderer().get_primitives(); - -@@ -919,7 +1045,20 @@ void win_window_info::update() - } - else - { -- SendMessage(platform_window(), WM_USER_REDRAW, 0, (LPARAM)primlist); -+ if (multithreading_enabled && !m_blit_lock && video_config.mode != VIDEO_MODE_GDI) -+ { -+ m_primlist = primlist; -+ SetEvent(m_blit_pending); -+ if ((video_config.syncrefresh && machine().video().throttled())) -+ WaitForSingleObject(m_blit_done, 1000); -+ frame_count = 0; -+ } -+ else -+ { -+ m_primlist = primlist; -+ draw_video_contents(NULL, FALSE); -+ if (multithreading_enabled && frame_count++ > 5) blit_lock_release(); -+ } - } - } - } -@@ -1196,8 +1335,7 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR - case WM_PAINT: - { - PAINTSTRUCT pstruct; -- HDC hdc = BeginPaint(wnd, &pstruct); -- window->draw_video_contents(hdc, true); -+ BeginPaint(wnd, &pstruct); - if (window->win_has_menu()) - DrawMenuBar(window->platform_window()); - EndPaint(wnd, &pstruct); -@@ -1340,6 +1478,11 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR - return DefWindowProc(wnd, message, wparam, lparam); - } - -+ case WM_ACTIVATE: -+ if (window->has_renderer() && window->fullscreen() && (LOWORD(wparam) == WA_INACTIVE) && !is_mame_window(HWND(lparam))) -+ if (osd_common_t::s_window_list.size()) winwindow_toggle_full_screen(); -+ break; -+ - // close: cause MAME to exit - case WM_CLOSE: - window->machine().schedule_exit(); -@@ -1797,6 +1940,7 @@ void win_window_info::adjust_window_position_after_major_change() - } - - -+ - //============================================================ - // set_fullscreen - // (window thread) -@@ -1815,6 +1959,10 @@ void win_window_info::set_fullscreen(int fullscreen) - // FIXME: this cause crash if called when running_machine.m_ui not yet initialised. e.g. when trying to show error/warning messagebox at startup (during auto-switch from full screen to windowed mode). - machine().ui().menu_reset(); - -+ // pause blitting thread; -+ if (multithreading_enabled) -+ blit_lock_set(); -+ - // kill off the drawers - renderer_reset(); - -@@ -1883,6 +2031,49 @@ void win_window_info::set_fullscreen(int fullscreen) - } - - -+//============================================================ -+// reset_fullscreen_renderer -+//============================================================ -+ -+void win_window_info::reset_fullscreen_renderer() -+{ -+ // if we're in the right state, punt -+ if (!m_fullscreen) -+ return; -+ -+ // pause blitting thread; -+ if (multithreading_enabled) -+ blit_lock_set(); -+ -+ if (video_config.mode == VIDEO_MODE_D3D) -+ { -+ renderer().restart(); -+ return; -+ } -+ -+ // kill off the drawers -+ renderer_reset(); -+ -+ // hide ourself -+ ShowWindow(platform_window(), SW_HIDE); -+ -+ // adjust the style -+ SetWindowLong(platform_window(), GWL_STYLE, WINDOW_STYLE); -+ SetWindowLong(platform_window(), GWL_EXSTYLE, WINDOW_STYLE_EX); -+ SetWindowPos(platform_window(), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); -+ -+ SetWindowLong(platform_window(), GWL_STYLE, FULLSCREEN_STYLE); -+ SetWindowLong(platform_window(), GWL_EXSTYLE, FULLSCREEN_STYLE_EX); -+ SetWindowPos(platform_window(), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); -+ -+ ShowWindow(platform_window(), SW_SHOW); -+ -+ set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this())); -+ if (renderer().create()) -+ exit(1); -+} -+ -+ - //============================================================ - // focus - // (main or window thread) -diff --git a/src/osd/windows/window.h b/src/osd/windows/window.h -index b04e35aa110..455522781a0 100644 ---- a/src/osd/windows/window.h -+++ b/src/osd/windows/window.h -@@ -96,6 +96,7 @@ public: - // static - - static void create(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config *config); -+ static DWORD WINAPI blit_loop(LPVOID lpParameter); - - // static callbacks - -@@ -131,6 +132,13 @@ public: - int m_lastclickx; - int m_lastclicky; - -+ // blitting thread -+ HANDLE m_blit_pending; -+ HANDLE m_blit_done; -+ DWORD m_blit_threadid; -+ BOOL m_blitting_active; -+ BOOL m_blit_lock; -+ - private: - void draw_video_contents(HDC dc, bool update); - int complete_create(); -@@ -146,6 +154,12 @@ private: - void adjust_window_position_after_major_change(); - void set_fullscreen(int fullscreen); - std::shared_ptr<osd_monitor_info> monitor_from_rect(const osd_rect* proposed) const; -+ void reset_fullscreen_renderer(); -+ void blit_loop_create(); -+ void blit_loop_destroy(); -+ DWORD blit_loop_wt(); -+ void blit_lock_set(); -+ void blit_lock_release(); - - static POINT s_saved_cursor_pos; - -diff --git a/src/osd/windows/winmain.cpp b/src/osd/windows/winmain.cpp -index 05888769c0d..3eab0ca4867 100644 ---- a/src/osd/windows/winmain.cpp -+++ b/src/osd/windows/winmain.cpp -@@ -43,6 +43,9 @@ using namespace Windows::UI::Popups; - - #define DEBUG_SLOW_LOCKS 0 - -+extern bool switchres_modeline_setup(running_machine &machine); -+extern bool switchres_modeline_remove(running_machine &machine); -+ - //************************************************************************** - // MACROS - //************************************************************************** -@@ -525,6 +528,10 @@ void windows_osd_interface::init(running_machine &machine) - const char *stemp; - auto &options = downcast<windows_options &>(machine.options()); - -+ // Switchres -+ switchres_init_osd(machine); -+ switchres_modeline_setup(machine); -+ - // determine if we are benchmarking, and adjust options appropriately - int bench = options.bench(); - if (bench > 0) -@@ -603,6 +610,9 @@ void windows_osd_interface::init(running_machine &machine) - - void windows_osd_interface::osd_exit() - { -+ // Remove Switchres -+ switchres_modeline_remove(machine()); -+ - // no longer have a machine - g_current_machine = nullptr; - |