From bf52d118267c0326c74fec648d789731d05ae304 Mon Sep 17 00:00:00 2001 From: Brad Hughes Date: Tue, 13 Sep 2016 12:12:45 -0400 Subject: [PATCH] Convert OSD monitor info to modules plus add DXGI implementation --- scripts/src/osd/modules.lua | 6 + scripts/src/osd/sdl.lua | 1 - src/osd/modules/debugger/win/debugwininfo.cpp | 1 + src/osd/modules/input/input_windows.h | 1 + src/osd/modules/lib/osdobj_common.cpp | 20 +- src/osd/modules/lib/osdobj_common.h | 18 +- src/osd/modules/monitor/monitor_common.cpp | 116 +++++++++ src/osd/modules/monitor/monitor_common.h | 43 ++++ src/osd/modules/monitor/monitor_dxgi.cpp | 172 ++++++++++++++ src/osd/modules/monitor/monitor_module.h | 97 ++++++++ src/osd/modules/monitor/monitor_sdl.cpp | 161 +++++++++++++ src/osd/modules/monitor/monitor_win32.cpp | 142 +++++++++++ src/osd/modules/osdwindow.cpp | 5 + src/osd/modules/osdwindow.h | 50 +--- src/osd/modules/render/drawd3d.cpp | 7 +- src/osd/modules/render/drawsdl.cpp | 3 +- src/osd/sdl/video.cpp | 168 +------------ src/osd/sdl/video.h | 39 ---- src/osd/sdl/window.cpp | 5 +- src/osd/windows/video.cpp | 220 +----------------- src/osd/windows/video.h | 30 +-- src/osd/windows/window.cpp | 86 ++++--- src/osd/windows/window.h | 4 +- src/osd/windows/winmain.cpp | 1 + 24 files changed, 832 insertions(+), 564 deletions(-) create mode 100644 src/osd/modules/monitor/monitor_common.cpp create mode 100644 src/osd/modules/monitor/monitor_common.h create mode 100644 src/osd/modules/monitor/monitor_dxgi.cpp create mode 100644 src/osd/modules/monitor/monitor_module.h create mode 100644 src/osd/modules/monitor/monitor_sdl.cpp create mode 100644 src/osd/modules/monitor/monitor_win32.cpp delete mode 100644 src/osd/sdl/video.h diff --git a/scripts/src/osd/modules.lua b/scripts/src/osd/modules.lua index 59cbc8c1d32..7fb7a81f90b 100644 --- a/scripts/src/osd/modules.lua +++ b/scripts/src/osd/modules.lua @@ -60,6 +60,7 @@ function osdmodulesbuild() MAME_DIR .. "src/osd/modules/netdev/netdev_module.h", MAME_DIR .. "src/osd/modules/sound/sound_module.h", MAME_DIR .. "src/osd/modules/diagnostics/diagnostics_module.h", + MAME_DIR .. "src/osd/modules/monitor/monitor_module.h", MAME_DIR .. "src/osd/modules/lib/osdobj_common.cpp", MAME_DIR .. "src/osd/modules/lib/osdobj_common.h", MAME_DIR .. "src/osd/modules/diagnostics/none.cpp", @@ -118,6 +119,11 @@ function osdmodulesbuild() MAME_DIR .. "src/osd/modules/ipc/rtc_tcp_connection.h", MAME_DIR .. "src/osd/modules/ipc/rtc_tcp_server.cpp", MAME_DIR .. "src/osd/modules/ipc/rtc_tcp_server.h", + MAME_DIR .. "src/osd/modules/monitor/monitor_common.h", + MAME_DIR .. "src/osd/modules/monitor/monitor_common.cpp", + MAME_DIR .. "src/osd/modules/monitor/monitor_win32.cpp", + MAME_DIR .. "src/osd/modules/monitor/monitor_dxgi.cpp", + MAME_DIR .. "src/osd/modules/monitor/monitor_sdl.cpp", } includedirs { ext_includedir("uv"), diff --git a/scripts/src/osd/sdl.lua b/scripts/src/osd/sdl.lua index 44b957d8dde..af6ff1b98ce 100644 --- a/scripts/src/osd/sdl.lua +++ b/scripts/src/osd/sdl.lua @@ -422,7 +422,6 @@ project ("osd_" .. _OPTIONS["osd"]) MAME_DIR .. "src/osd/sdl/sdlmain.cpp", MAME_DIR .. "src/osd/osdepend.h", MAME_DIR .. "src/osd/sdl/video.cpp", - MAME_DIR .. "src/osd/sdl/video.h", MAME_DIR .. "src/osd/sdl/window.cpp", MAME_DIR .. "src/osd/sdl/window.h", MAME_DIR .. "src/osd/modules/osdwindow.cpp", diff --git a/src/osd/modules/debugger/win/debugwininfo.cpp b/src/osd/modules/debugger/win/debugwininfo.cpp index 61f57511d6e..fda0a1144fc 100644 --- a/src/osd/modules/debugger/win/debugwininfo.cpp +++ b/src/osd/modules/debugger/win/debugwininfo.cpp @@ -16,6 +16,7 @@ #include "winutf8.h" #include "winutil.h" +#include "modules/lib/osdobj_common.h" bool debugwin_info::s_window_class_registered = false; diff --git a/src/osd/modules/input/input_windows.h b/src/osd/modules/input/input_windows.h index 3a4cad97613..0a0e30ac808 100644 --- a/src/osd/modules/input/input_windows.h +++ b/src/osd/modules/input/input_windows.h @@ -15,6 +15,7 @@ #undef interface #include "window.h" +#include "winmain.h" //============================================================ // TYPEDEFS diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp index 745b71f4d1a..351b87aa269 100644 --- a/src/osd/modules/lib/osdobj_common.cpp +++ b/src/osd/modules/lib/osdobj_common.cpp @@ -56,6 +56,7 @@ const options_entry osd_options::s_option_entries[] = { OSDOPTION_MAXIMIZE ";max", "1", OPTION_BOOLEAN, "default to maximized windows; otherwise, windows will be minimized" }, { 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 { nullptr, nullptr, OPTION_HEADER, "OSD PER-WINDOW VIDEO OPTIONS" }, @@ -179,6 +180,7 @@ osd_common_t::osd_common_t(osd_options &options) m_lightgun_input(nullptr), m_joystick_input(nullptr), m_output(nullptr), + m_monitor_module(nullptr), m_watchdog(nullptr) { osd_output::push(this); @@ -213,6 +215,10 @@ void osd_common_t::register_options() REGISTER_MODULE(m_mod_man, SOUND_SDL); REGISTER_MODULE(m_mod_man, SOUND_NONE); + REGISTER_MODULE(m_mod_man, MONITOR_SDL); + REGISTER_MODULE(m_mod_man, MONITOR_WIN32); + REGISTER_MODULE(m_mod_man, MONITOR_DXGI); + #ifdef SDLMAME_MACOSX REGISTER_MODULE(m_mod_man, DEBUG_OSX); #endif @@ -265,8 +271,15 @@ void osd_common_t::register_options() const char *names[20]; int num; - m_mod_man.get_module_names(OSD_FONT_PROVIDER, 20, &num, names); std::vector dnames; + + m_mod_man.get_module_names(OSD_MONITOR_PROVIDER, 20, &num, names); + for (int i = 0; i < num; i++) + dnames.push_back(names[i]); + update_option(OSD_MONITOR_PROVIDER, dnames); + + m_mod_man.get_module_names(OSD_FONT_PROVIDER, 20, &num, names); + dnames.clear(); for (int i = 0; i < num; i++) dnames.push_back(names[i]); update_option(OSD_FONT_PROVIDER, dnames); @@ -618,6 +631,11 @@ static void output_notifier_callback(const char *outname, INT32 value, void *par void osd_common_t::init_subsystems() { + // monitors have to be initialized before video init + m_monitor_module = select_module_options(options(), OSD_MONITOR_PROVIDER); + assert(m_monitor_module != nullptr); + m_monitor_module->init(options()); + if (!video_init()) { video_exit(); diff --git a/src/osd/modules/lib/osdobj_common.h b/src/osd/modules/lib/osdobj_common.h index 7d4238fcbbd..55f14d803f5 100644 --- a/src/osd/modules/lib/osdobj_common.h +++ b/src/osd/modules/lib/osdobj_common.h @@ -23,6 +23,7 @@ #include "modules/netdev/netdev_module.h" #include "modules/midi/midi_module.h" #include "modules/output/output_module.h" +#include "modules/monitor/monitor_module.h" #include "emuopts.h" #include "../frontend/mame/ui/menuitem.h" @@ -278,14 +279,15 @@ private: } protected: - sound_module* m_sound; - debug_module* m_debugger; - midi_module* m_midi; - input_module* m_keyboard_input; - input_module* m_mouse_input; - input_module* m_lightgun_input; - input_module* m_joystick_input; - output_module* m_output; + sound_module* m_sound; + debug_module* m_debugger; + midi_module* m_midi; + input_module* m_keyboard_input; + input_module* m_mouse_input; + input_module* m_lightgun_input; + input_module* m_joystick_input; + output_module* m_output; + monitor_module* m_monitor_module; std::unique_ptr m_watchdog; std::vector m_sliders; diff --git a/src/osd/modules/monitor/monitor_common.cpp b/src/osd/modules/monitor/monitor_common.cpp new file mode 100644 index 00000000000..5a1a5fa8377 --- /dev/null +++ b/src/osd/modules/monitor/monitor_common.cpp @@ -0,0 +1,116 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Hughes, Aaron Giles, Olivier Galibert, R. Belmont +/* +* monitor_common.cpp +* +*/ + +#include + +#include "monitor_common.h" +#include "modules/osdwindow.h" + +std::shared_ptr monitor_module_base::pick_monitor(osd_options& options, int index) +{ + // get the aspect ratio + float aspect = get_aspect(options.aspect(), options.aspect(index), TRUE); + + auto monitor = pick_monitor_internal(options, index); + if (aspect != 0) + { + monitor->set_aspect(aspect); + } + + return monitor; +} + +std::shared_ptr monitor_module_base::monitor_from_handle(std::uint64_t handle) +{ + if (!m_initialized) + return nullptr; + + auto monitor = m_monitor_index[handle]; + + // If we have been initialized, make sure we can find the monitor + assert(monitor != nullptr); + + return monitor; +} + +void monitor_module_base::add_monitor(std::shared_ptr monitor) +{ + list().push_back(monitor); + m_monitor_index[monitor->oshandle()] = monitor; +} + +std::shared_ptr monitor_module_base::pick_monitor_internal(osd_options& options, int index) +{ + std::string scrname, scrname2; + + // get the screen option + scrname = options.screen(); + scrname2 = options.screen(index); + + // decide which one we want to use + if (scrname2 != "auto") + scrname = scrname2; + + // look for a match in the name first + if (!scrname.empty()) + { + auto mon = std::find_if(std::begin(list()), std::end(list()), [&scrname](auto m) + { + return m->devicename() == scrname; + }); + + if (mon != std::end(list())) + { + return *mon; + } + } + + // didn't find it; alternate monitors until we hit the jackpot + // this allows for more screens than monitors but will put one on each monitor first + index %= list().size(); + auto next_monitor = list()[index]; + return next_monitor; +} + +float monitor_module_base::get_aspect(const char* defdata, const char* data, int report_error) +{ + int num = 0, den = 1; + + if (strcmp(data, OSDOPTVAL_AUTO) == 0) + { + if (strcmp(defdata, OSDOPTVAL_AUTO) == 0) + return 0; + data = defdata; + } + if (sscanf(data, "%d:%d", &num, &den) != 2 && report_error) + osd_printf_error("Illegal aspect ratio value = %s\n", data); + + return float(num) / float(den); +} + +int monitor_module_base::init(const osd_options& options) +{ + if (!m_initialized) + { + int result = init_internal(options); + + if (result == 0) + m_initialized = true; + + return result; + } + + return 0; +} + +void monitor_module_base::exit() +{ + // free all of our monitor information + list().clear(); + m_monitor_index.clear(); + m_initialized = false; +} diff --git a/src/osd/modules/monitor/monitor_common.h b/src/osd/modules/monitor/monitor_common.h new file mode 100644 index 00000000000..c021ebcfcb7 --- /dev/null +++ b/src/osd/modules/monitor/monitor_common.h @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Hughes +/* +* monitor_common.h +* +*/ + +#include "modules/lib/osdobj_common.h" +#include + +//============================================================ +// monitor_module_base +//============================================================ + +class monitor_module_base : public monitor_module +{ +private: + std::map> m_monitor_index; + +protected: + bool m_initialized; + +public: + monitor_module_base(const char* type, const char* name) + : monitor_module(type, name), + m_initialized(false) + { + } + + std::shared_ptr pick_monitor(osd_options& options, int index) override; + std::shared_ptr monitor_from_handle(std::uint64_t handle) override; + + int init(const osd_options& options) override; + void exit() override; + +protected: + virtual int init_internal(const osd_options& options) = 0; + void add_monitor(std::shared_ptr monitor); + +private: + std::shared_ptr pick_monitor_internal(osd_options& options, int index); + static float get_aspect(const char *defdata, const char *data, int report_error); +}; diff --git a/src/osd/modules/monitor/monitor_dxgi.cpp b/src/osd/modules/monitor/monitor_dxgi.cpp new file mode 100644 index 00000000000..6619bdc23f3 --- /dev/null +++ b/src/osd/modules/monitor/monitor_dxgi.cpp @@ -0,0 +1,172 @@ +// license:BSD-3-Clause +// copyright-holders: Brad Hughes +/* +* monitor_dxgi.cpp +* +*/ + +#include "modules/osdmodule.h" +#include "monitor_module.h" + +#if defined(OSD_WINDOWS) + +// standard windows headers +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#undef interface +#undef min +#undef max + +#include "strconv.h" +#include "modules/lib/osdlib.h" +#include "monitor_common.h" +#include "window.h" +#include "windows/video.h" + +using namespace Microsoft::WRL; + +class dxgi_monitor_info : public osd_monitor_info +{ +private: + ComPtr m_output; // The output interface + +public: + dxgi_monitor_info(monitor_module& module, HMONITOR handle, const char* monitor_device, float aspect, ComPtr output) + : osd_monitor_info(module, reinterpret_cast(handle), monitor_device, aspect), + m_output(output) + { + dxgi_monitor_info::refresh(); + } + + void refresh() override + { + DXGI_OUTPUT_DESC desc; + m_output->GetDesc(&desc); + + // fetch the latest info about the monitor + m_name = utf8_from_wstring(desc.DeviceName); + + m_pos_size = RECT_to_osd_rect(desc.DesktopCoordinates); + m_usuable_pos_size = RECT_to_osd_rect(desc.DesktopCoordinates); + m_is_primary = desc.AttachedToDesktop; + } +}; + +typedef DWORD(WINAPI *dxgi_create_factory_fn)(REFIID, void**); + +class dxgi_monitor_module : public monitor_module_base +{ +private: + osd::dynamic_module::ptr m_dxgi_module; + dxgi_create_factory_fn m_create_factory_fn; + +public: + dxgi_monitor_module() + : monitor_module_base(OSD_MONITOR_PROVIDER, "dxgi"), + m_dxgi_module(osd::dynamic_module::open({"dxgi.dll"})), + m_create_factory_fn(nullptr) + { + } + + bool probe() override + { + m_create_factory_fn = m_dxgi_module->bind("CreateDXGIFactory1"); + if (m_create_factory_fn == nullptr) + return false; + + return true; + } + + // Currently this method implementation is duplicated from the win32 module + // however it needs to also handle being able to do this for UWP + std::shared_ptr monitor_from_rect(const osd_rect& rect) override + { + if (!m_initialized) + return nullptr; + + RECT p; + p.top = rect.top(); + p.left = rect.left(); + p.bottom = rect.bottom(); + p.right = rect.right(); + + auto nearest = monitor_from_handle(reinterpret_cast(MonitorFromRect(&p, MONITOR_DEFAULTTONEAREST))); + assert(nearest != nullptr); + return nearest; + } + + // Currently this method implementation is duplicated from the win32 module + // however it needs to also handle being able to do this for UWP + std::shared_ptr monitor_from_window(const osd_window& window) override + { + if (!m_initialized) + return nullptr; + + auto nearest = monitor_from_handle(reinterpret_cast(MonitorFromWindow(window.platform_window(), MONITOR_DEFAULTTONEAREST))); + assert(nearest != nullptr); + return nearest; + } + +protected: + int init_internal(const osd_options& options) override + { + HRESULT result; + ComPtr dxgiDevice; + ComPtr factory; + ComPtr adapter; + + result = m_create_factory_fn(__uuidof(IDXGIFactory2), reinterpret_cast(factory.GetAddressOf())); + if (result != ERROR_SUCCESS) + { + osd_printf_error("CreateDXGIFactory1 failed with error 0x%x\n", static_cast(result)); + return 1; + } + + UINT iAdapter = 0; + while (!factory->EnumAdapters(iAdapter, adapter.ReleaseAndGetAddressOf())) + { + UINT i = 0; + ComPtr output; + DXGI_OUTPUT_DESC desc; + while (!adapter->EnumOutputs(i, output.GetAddressOf())) + { + output->GetDesc(&desc); + + // guess the aspect ratio assuming square pixels + RECT * coords = &desc.DesktopCoordinates; + float aspect = float(coords->right - coords->left) / float(coords->bottom - coords->top); + + // allocate a new monitor info + std::string devicename = utf8_from_wstring(desc.DeviceName); + + // allocate a new monitor info + auto monitor = std::make_shared(*this, desc.Monitor, devicename.c_str(), aspect, output); + + // hook us into the list + add_monitor(monitor); + + i++; + } + + iAdapter++; + } + + // if we're verbose, print the list of monitors + { + for (auto monitor : list()) + { + osd_printf_verbose("Video: Monitor %I64u = \"%s\" %s\n", monitor->oshandle(), monitor->devicename().c_str(), monitor->is_primary() ? "(primary)" : ""); + } + } + + return 0; + } +}; + +#else +MODULE_NOT_SUPPORTED(dxgi_monitor_module, OSD_MONITOR_PROVIDER, "dxgi") +#endif + +MODULE_DEFINITION(MONITOR_DXGI, dxgi_monitor_module) \ No newline at end of file diff --git a/src/osd/modules/monitor/monitor_module.h b/src/osd/modules/monitor/monitor_module.h new file mode 100644 index 00000000000..3244e7fd42b --- /dev/null +++ b/src/osd/modules/monitor/monitor_module.h @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Hughes, Aaron Giles, Olivier Galibert, R. Belmont +/* + * monitor_module.h + * + */ + +#ifndef MAME_OSD_MODULES_MONITOR_MONITORMODULE_H +#define MAME_OSD_MODULES_MONITOR_MONITORMODULE_H + +#include + +#include "modules/osdmodule.h" +#include "modules/osdhelper.h" + +//============================================================ +// CONSTANTS +//============================================================ + +#define OSD_MONITOR_PROVIDER "monitorprovider" + +class monitor_module; +class osd_window; + +//============================================================ +// osd_monitor_info +//============================================================ + +class osd_monitor_info +{ +public: + osd_monitor_info(monitor_module &module, std::uint64_t handle, const char *monitor_device, float aspect) + : m_is_primary(false), m_name(monitor_device), m_module(module), m_handle(handle), m_aspect(aspect) + { + } + + virtual ~osd_monitor_info() { } + + virtual void refresh() = 0; + + std::uint64_t oshandle() const { return m_handle; } + monitor_module& module() const { return m_module; } + + const osd_rect &position_size() const { return m_pos_size; } + const osd_rect &usuable_position_size() const { return m_usuable_pos_size; } + + const std::string &devicename() const + { + static std::string s_unknown = std::string("UNKNOWN"); + return m_name.length() ? m_name : s_unknown; + } + + float aspect() const { return m_aspect; } + float pixel_aspect() const { return m_aspect / (float(m_pos_size.width()) / float(m_pos_size.height())); } + + void update_resolution(const int new_width, const int new_height) const { m_pos_size.resize(new_width, new_height); } + void set_aspect(const float a) { m_aspect = a; } + bool is_primary() const { return m_is_primary; } + +protected: + osd_rect m_pos_size; + osd_rect m_usuable_pos_size; + bool m_is_primary; + std::string m_name; +private: + monitor_module& m_module; + std::uint64_t m_handle; // handle to the monitor + float m_aspect; // computed/configured aspect ratio of the physical device +}; + +//============================================================ +// monitor_module +//============================================================ + +class monitor_module : public osd_module +{ +private: + std::vector> m_list; + +public: + monitor_module(const char *type, const char *name) + : osd_module(type, name) + { + } + + virtual ~monitor_module() { } + + std::vector> & list() { return m_list; } + + virtual std::shared_ptr monitor_from_handle(std::uint64_t handle) = 0; + virtual std::shared_ptr monitor_from_rect(const osd_rect &rect) = 0; + virtual std::shared_ptr monitor_from_window(const osd_window &window) = 0; + + virtual std::shared_ptr pick_monitor(osd_options &options, int index) = 0; +}; + +#endif // MAME_OSD_MODULES_MONITOR_MONITORMODULE_H diff --git a/src/osd/modules/monitor/monitor_sdl.cpp b/src/osd/modules/monitor/monitor_sdl.cpp new file mode 100644 index 00000000000..ade1a3b1140 --- /dev/null +++ b/src/osd/modules/monitor/monitor_sdl.cpp @@ -0,0 +1,161 @@ +// license:BSD-3-Clause +// copyright-holders: Brad Hughes, Olivier Galibert, R. Belmont +/* + * monitor_sdl.cpp + * + */ + +#include "modules/osdmodule.h" +#include "monitor_module.h" + +#if defined(OSD_SDL) + +#include +#include + +#include "modules/osdwindow.h" +#include "monitor_common.h" + +inline osd_rect SDL_Rect_to_osd_rect(const SDL_Rect &r) +{ + return osd_rect(r.x, r.y, r.w, r.h); +} + + //============================================================ + // sdl_monitor_info + //============================================================ + +class sdl_monitor_info : public osd_monitor_info +{ +public: + sdl_monitor_info(monitor_module &module, std::uint64_t handle, const char *monitor_device, float aspect) + : osd_monitor_info(module, handle, monitor_device, aspect) + { + sdl_monitor_info::refresh(); + } + +private: + void refresh() override + { + SDL_DisplayMode dmode; + +#if defined(SDLMAME_WIN32) + SDL_GetDesktopDisplayMode(oshandle(), &dmode); +#else + SDL_GetCurrentDisplayMode(oshandle(), &dmode); +#endif + SDL_Rect dimensions; + SDL_GetDisplayBounds(oshandle(), &dimensions); + + m_pos_size = SDL_Rect_to_osd_rect(dimensions); + m_usuable_pos_size = SDL_Rect_to_osd_rect(dimensions); + m_is_primary = (oshandle() == 0); + } +}; + +//============================================================ +// sdl_monitor_module +//============================================================ + +class sdl_monitor_module : public monitor_module_base +{ +public: + sdl_monitor_module() + : monitor_module_base(OSD_MONITOR_PROVIDER, "sdl") + { + } + + // + // Given a proposed rect, returns the monitor whose bounds intersect the most with it + // + // Windows OSD uses this kind of mechanism to constrain resizing but SDL does not + // The method below will allow this but isn't used by SDL OSD yet + // + std::shared_ptr monitor_from_rect(const osd_rect& proposed) override + { + if (!m_initialized) + return nullptr; + + // Determines whether the first intersects less with the proposed rect than the second + auto intersects_less = [&proposed](std::shared_ptr mon1, std::shared_ptr mon2) + { + int value1 = compute_intersection(mon1->usuable_position_size(), proposed); + int value2 = compute_intersection(mon2->usuable_position_size(), proposed); + + return value1 < value2; + }; + + // Find the one that intersects with the proposed rect the most + auto monitor = std::max_element(std::begin(list()), std::end(list()), intersects_less); + return *monitor; + } + + std::shared_ptr monitor_from_window(const osd_window& window) override + { + if (!m_initialized) + return nullptr; + + std::uint64_t display = SDL_GetWindowDisplayIndex(window.platform_window()); + return monitor_from_handle(display); + } + +protected: + int init_internal(const osd_options& options) override + { + // make a list of monitors + { + int i; + + osd_printf_verbose("Enter init_monitors\n"); + + for (i = 0; i < SDL_GetNumVideoDisplays(); i++) + { + char temp[64]; + snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, i); + + // allocate a new monitor info + std::shared_ptr monitor = std::make_shared(*this, i, temp, 1.0f); + + osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename().c_str(), + monitor->position_size().width(), monitor->position_size().height()); + + // guess the aspect ratio assuming square pixels + monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); + + // hook us into the list + add_monitor(monitor); + } + } + osd_printf_verbose("Leave init_monitors\n"); + + return 0; + } + +private: + static void osdrect_to_sdlrect(const osd_rect &osd, SDL_Rect &sdl) + { + sdl.h = osd.height(); + sdl.w = osd.width(); + sdl.x = osd.left(); + sdl.y = osd.top(); + } + + static int compute_intersection(const osd_rect &rect1, const osd_rect &rect2) + { + SDL_Rect sdl1, sdl2; + osdrect_to_sdlrect(rect1, sdl1); + osdrect_to_sdlrect(rect2, sdl2); + + SDL_Rect intersection; + if (SDL_IntersectRect(&sdl1, &sdl2, &intersection)) + return intersection.w + intersection.h; + + return 0; + } +}; + +#else +MODULE_NOT_SUPPORTED(sdl_monitor_module, OSD_MONITOR_PROVIDER, "sdl") +#endif + +MODULE_DEFINITION(MONITOR_SDL, sdl_monitor_module) \ No newline at end of file diff --git a/src/osd/modules/monitor/monitor_win32.cpp b/src/osd/modules/monitor/monitor_win32.cpp new file mode 100644 index 00000000000..01fe69e9629 --- /dev/null +++ b/src/osd/modules/monitor/monitor_win32.cpp @@ -0,0 +1,142 @@ +// license:BSD-3-Clause +// copyright-holders: Brad Hughes, Aaron Giles +/* + * monitor_win32.cpp + * + */ + +#include "modules/osdmodule.h" +#include "monitor_module.h" + +#if defined(OSD_WINDOWS) + +// standard windows headers +#define WIN32_LEAN_AND_MEAN +#include +#undef interface +#undef min +#undef max + +#include "strconv.h" +#include "windows/video.h" +#include "window.h" +#include "monitor_common.h" + +class win32_monitor_module; + +class win32_monitor_info : public osd_monitor_info +{ +private: + MONITORINFOEX m_info; + +public: + win32_monitor_info(monitor_module& module, const HMONITOR handle, const char* monitor_device, float aspect) + : osd_monitor_info(module, std::intptr_t(handle), monitor_device, aspect) + { + win32_monitor_info::refresh(); + } + + void refresh() override + { + BOOL result; + + // fetch the latest info about the monitor + m_info.cbSize = sizeof(m_info); + result = GetMonitorInfo(reinterpret_cast(oshandle()), static_cast(&m_info)); + assert(result); + + m_name = utf8_from_tstring(m_info.szDevice); + + m_pos_size = RECT_to_osd_rect(m_info.rcMonitor); + m_usuable_pos_size = RECT_to_osd_rect(m_info.rcWork); + m_is_primary = ((m_info.dwFlags & MONITORINFOF_PRIMARY) != 0); + (void)result; // to silence gcc 4.6 + } +}; + +class win32_monitor_module : public monitor_module_base +{ +public: + win32_monitor_module() + : monitor_module_base(OSD_MONITOR_PROVIDER, "win32") + { + } + + std::shared_ptr monitor_from_rect(const osd_rect& rect) override + { + if (!m_initialized) + return nullptr; + + RECT p; + p.top = rect.top(); + p.left = rect.left(); + p.bottom = rect.bottom(); + p.right = rect.right(); + + auto nearest = monitor_from_handle(reinterpret_cast(MonitorFromRect(&p, MONITOR_DEFAULTTONEAREST))); + assert(nearest != nullptr); + return nearest; + } + + std::shared_ptr monitor_from_window(const osd_window& window) override + { + if (!m_initialized) + return nullptr; + + auto nearest = monitor_from_handle(reinterpret_cast(MonitorFromWindow(window.platform_window(), MONITOR_DEFAULTTONEAREST))); + assert(nearest != nullptr); + return nearest; + } + +protected: + int init_internal(const osd_options& options) override + { + // make a list of monitors + EnumDisplayMonitors(nullptr, nullptr, monitor_enum_callback, reinterpret_cast(this)); + + // if we're verbose, print the list of monitors + { + for (auto monitor : list()) + { + osd_printf_verbose("Video: Monitor %I64u = \"%s\" %s\n", monitor->oshandle(), monitor->devicename().c_str(), monitor->is_primary() ? "(primary)" : ""); + } + } + + return 0; + } + +private: + static BOOL CALLBACK monitor_enum_callback(HMONITOR handle, HDC dc, LPRECT rect, LPARAM data) + { + win32_monitor_module* self = reinterpret_cast(data); + MONITORINFOEX info; + BOOL result; + + // get the monitor info + info.cbSize = sizeof(info); + result = GetMonitorInfo(handle, static_cast(&info)); + assert(result); + (void)result; // to silence gcc 4.6 + + // guess the aspect ratio assuming square pixels + float aspect = static_cast(info.rcMonitor.right - info.rcMonitor.left) / static_cast(info.rcMonitor.bottom - info.rcMonitor.top); + + // allocate a new monitor info + auto temp = utf8_from_tstring(info.szDevice); + + // copy in the data + auto monitor = std::make_shared(*self, handle, temp.c_str(), aspect); + + // hook us into the list + self->add_monitor(monitor); + + // enumerate all the available monitors so to list their names in verbose mode + return TRUE; + } +}; + +#else +MODULE_NOT_SUPPORTED(win32_monitor_module, OSD_MONITOR_PROVIDER, "win32") +#endif + +MODULE_DEFINITION(MONITOR_WIN32, win32_monitor_module) \ No newline at end of file diff --git a/src/osd/modules/osdwindow.cpp b/src/osd/modules/osdwindow.cpp index c7afccb029c..16fc8817184 100644 --- a/src/osd/modules/osdwindow.cpp +++ b/src/osd/modules/osdwindow.cpp @@ -21,6 +21,11 @@ #include "render/drawsdl.h" #endif +float osd_window::pixel_aspect() const +{ + return monitor()->pixel_aspect(); +} + std::unique_ptr osd_renderer::make_for_type(int mode, std::shared_ptr window, int extra_flags) { switch(mode) diff --git a/src/osd/modules/osdwindow.h b/src/osd/modules/osdwindow.h index 3fa62babfbf..ca6ddbd375e 100644 --- a/src/osd/modules/osdwindow.h +++ b/src/osd/modules/osdwindow.h @@ -41,7 +41,7 @@ enum VIDEO_MODE_NONE = 0, VIDEO_MODE_GDI, VIDEO_MODE_BGFX, -#if (USE_OPENGL) +#if defined(USE_OPENGL) && USE_OPENGL VIDEO_MODE_OPENGL, #endif VIDEO_MODE_SDL2ACCEL, @@ -51,46 +51,6 @@ enum VIDEO_MODE_COUNT }; -class osd_monitor_info -{ -public: - osd_monitor_info(void *handle, const char *monitor_device, float aspect) - : m_is_primary(false), m_name(monitor_device), m_handle(handle), m_aspect(aspect) - { - } - - virtual ~osd_monitor_info() { } - - virtual void refresh() = 0; - - const void *oshandle() const { return m_handle; } - - const osd_rect &position_size() const { return m_pos_size; } - const osd_rect &usuable_position_size() const { return m_usuable_pos_size; } - - const char *devicename() const { return m_name.length() ? m_name.c_str() : "UNKNOWN"; } - - float aspect() const { return m_aspect; } - float pixel_aspect() const { return m_aspect / ((float)m_pos_size.width() / (float)m_pos_size.height()); } - - void update_resolution(const int new_width, const int new_height) const { m_pos_size.resize(new_width, new_height); } - void set_aspect(const float a) { m_aspect = a; } - bool is_primary() const { return m_is_primary; } - - static std::shared_ptr pick_monitor(osd_options &options, int index); - - static std::list> list; - -protected: - osd_rect m_pos_size; - osd_rect m_usuable_pos_size; - bool m_is_primary; - std::string m_name; -private: - void * m_handle; // handle to the monitor - float m_aspect; // computed/configured aspect ratio of the physical device -}; - class osd_window_config { public: @@ -104,6 +64,7 @@ public: }; class osd_renderer; +class osd_monitor_info; class osd_window : public std::enable_shared_from_this { @@ -126,15 +87,17 @@ public: virtual int fullscreen() const = 0; virtual running_machine &machine() const = 0; + bool has_renderer() const { return m_renderer != nullptr; } osd_renderer &renderer() const { return *m_renderer; } void set_renderer(std::unique_ptr renderer) { m_renderer = std::move(renderer); } + void renderer_reset() { m_renderer.reset(); } int prescale() const { return m_prescale; }; - float pixel_aspect() const { return monitor()->pixel_aspect(); } + float pixel_aspect() const; bool swap_xy() { @@ -173,11 +136,8 @@ public: virtual void update() = 0; virtual void destroy() = 0; - void renderer_reset() { m_renderer.reset(); } #ifndef OSD_SDL virtual bool win_has_menu() = 0; - // FIXME: cann we replace winwindow_video_window_monitor(nullptr) with monitor() ? - virtual std::shared_ptr winwindow_video_window_monitor(const osd_rect *proposed) = 0; HDC m_dc; // only used by GDI renderer! diff --git a/src/osd/modules/render/drawd3d.cpp b/src/osd/modules/render/drawd3d.cpp index 17d77dd4446..61371a05184 100644 --- a/src/osd/modules/render/drawd3d.cpp +++ b/src/osd/modules/render/drawd3d.cpp @@ -19,6 +19,7 @@ #include "window.h" #include "drawd3d.h" #include "modules/render/d3d/d3dhlsl.h" +#include "modules/monitor/monitor_module.h" #undef min #undef max #include @@ -1227,7 +1228,7 @@ int renderer_d3d9::config_adapter_mode() // make sure it's a pixel format we can get behind if (m_pixformat != D3DFMT_X1R5G5B5 && m_pixformat != D3DFMT_R5G6B5 && m_pixformat != D3DFMT_X8R8G8B8) { - osd_printf_error("Device %s currently in an unsupported mode\n", win->monitor()->devicename()); + osd_printf_error("Device %s currently in an unsupported mode\n", win->monitor()->devicename().c_str()); return 1; } } @@ -1250,7 +1251,7 @@ int renderer_d3d9::config_adapter_mode() result = d3dintf->d3dobj->CheckDeviceType(m_adapter, D3DDEVTYPE_HAL, m_pixformat, m_pixformat, !win->fullscreen()); if (FAILED(result)) { - osd_printf_error("Proposed video mode not supported on device %s\n", win->monitor()->devicename()); + osd_printf_error("Proposed video mode not supported on device %s\n", win->monitor()->devicename().c_str()); return 1; } return 0; @@ -1274,7 +1275,7 @@ int renderer_d3d9::get_adapter_for_monitor() HMONITOR curmonitor = d3dintf->d3dobj->GetAdapterMonitor(adapternum); // if we match the proposed monitor, this is it - if (curmonitor == *((HMONITOR *)win->monitor()->oshandle())) + if (curmonitor == reinterpret_cast(win->monitor()->oshandle())) { return adapternum; } diff --git a/src/osd/modules/render/drawsdl.cpp b/src/osd/modules/render/drawsdl.cpp index 4a0c3c0fea1..7b937086bf8 100644 --- a/src/osd/modules/render/drawsdl.cpp +++ b/src/osd/modules/render/drawsdl.cpp @@ -27,6 +27,7 @@ #include "window.h" #include "drawsdl.h" +#include "modules/monitor/monitor_module.h" //============================================================ // DEBUGGING @@ -108,7 +109,7 @@ void renderer_sdl1::setup_texture(const osd_dim &size) auto win = assert_window(); // Determine preferred pixelformat and set up yuv if necessary - SDL_GetCurrentDisplayMode(*((UINT64 *)win->monitor()->oshandle()), &mode); + SDL_GetCurrentDisplayMode(win->monitor()->oshandle(), &mode); if (m_yuv_bitmap) { diff --git a/src/osd/sdl/video.cpp b/src/osd/sdl/video.cpp index 38204017290..5ec47a105a0 100644 --- a/src/osd/sdl/video.cpp +++ b/src/osd/sdl/video.cpp @@ -34,10 +34,6 @@ osd_video_config video_config; -// monitor info -std::list> osd_monitor_info::list; - - //============================================================ // LOCAL VARIABLES //============================================================ @@ -49,7 +45,6 @@ std::list> osd_monitor_info::list; static void check_osd_inputs(running_machine &machine); -static float get_aspect(const char *defdata, const char *data, int report_error); static void get_resolution(const char *defdata, const char *data, osd_window_config *config, int report_error); @@ -64,9 +59,6 @@ bool sdl_osd_interface::video_init() // extract data from the options extract_video_config(); - // set up monitors first - sdl_monitor_info::init(); - // we need the beam width in a float, contrary to what the core does. video_config.beamwidth = options().beam_width_min(); @@ -82,7 +74,7 @@ bool sdl_osd_interface::video_init() get_resolution(options().resolution(), options().resolution(index), &conf, TRUE); // create window ... - std::shared_ptr win = std::make_shared(machine(), index, osd_monitor_info::pick_monitor(reinterpret_cast(options()), index), &conf); + std::shared_ptr win = std::make_shared(machine(), index, m_monitor_module->pick_monitor(reinterpret_cast(options()), index), &conf); if (win->window_init()) return false; @@ -98,34 +90,6 @@ bool sdl_osd_interface::video_init() void sdl_osd_interface::video_exit() { window_exit(); - sdl_monitor_info::exit(); -} - - -//============================================================ -// sdlvideo_monitor_refresh -//============================================================ - -inline osd_rect SDL_Rect_to_osd_rect(const SDL_Rect &r) -{ - return osd_rect(r.x, r.y, r.w, r.h); -} - -void sdl_monitor_info::refresh() -{ - SDL_DisplayMode dmode; - - #if defined(SDLMAME_WIN32) - SDL_GetDesktopDisplayMode(m_handle, &dmode); - #else - SDL_GetCurrentDisplayMode(m_handle, &dmode); - #endif - SDL_Rect dimensions; - SDL_GetDisplayBounds(m_handle, &dimensions); - - m_pos_size = SDL_Rect_to_osd_rect(dimensions); - m_usuable_pos_size = SDL_Rect_to_osd_rect(dimensions); - m_is_primary = (m_handle == 0); } //============================================================ @@ -154,116 +118,6 @@ void sdl_osd_interface::update(bool skip_redraw) debugger_update(); } - -//============================================================ -// init_monitors -//============================================================ - -void sdl_monitor_info::init() -{ - // make a list of monitors - { - int i; - - osd_printf_verbose("Enter init_monitors\n"); - - for (i = 0; i < SDL_GetNumVideoDisplays(); i++) - { - char temp[64]; - snprintf(temp, sizeof(temp)-1, "%s%d", OSDOPTION_SCREEN,i); - - // allocate a new monitor info - - std::shared_ptr monitor = std::make_shared(i, temp, 1.0f); - - osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename(), - monitor->position_size().width(), monitor->position_size().height()); - - // guess the aspect ratio assuming square pixels - monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); - - // hook us into the list - osd_monitor_info::list.push_back(monitor); - } - } - osd_printf_verbose("Leave init_monitors\n"); -} - -void sdl_monitor_info::exit() -{ - // free all of our monitor information - while (!osd_monitor_info::list.empty()) - { - osd_monitor_info::list.remove(osd_monitor_info::list.front()); - } -} - - -//============================================================ -// pick_monitor -//============================================================ - -std::shared_ptr osd_monitor_info::pick_monitor(osd_options &generic_options, int index) -{ - sdl_options &options = reinterpret_cast(generic_options); - std::shared_ptr monitor; - const char *scrname, *scrname2; - int moncount = 0; - float aspect; - - // get the screen option - scrname = options.screen(); - scrname2 = options.screen(index); - - // decide which one we want to use - if (strcmp(scrname2, "auto") != 0) - scrname = scrname2; - - // get the aspect ratio - aspect = get_aspect(options.aspect(), options.aspect(index), TRUE); - - // look for a match in the name first - if (scrname != nullptr && (scrname[0] != 0)) - { - for (auto mon : osd_monitor_info::list) - { - moncount++; - if (strcmp(scrname, mon->devicename()) == 0) - { - monitor = mon; - goto finishit; - } - } - } - - // didn't find it; alternate monitors until we hit the jackpot - index %= moncount; - for (auto mon : osd_monitor_info::list) - if (index-- == 0) - { - monitor = mon; - goto finishit; - } - - // return the primary just in case all else fails - for (auto mon : osd_monitor_info::list) - if (mon->is_primary()) - { - monitor = mon; - goto finishit; - } - - // FIXME: FatalError? -finishit: - if (aspect != 0) - { - monitor->set_aspect(aspect); - } - - return monitor; -} - - //============================================================ // check_osd_inputs //============================================================ @@ -479,26 +333,6 @@ void sdl_osd_interface::extract_video_config() } -//============================================================ -// get_aspect -//============================================================ - -static float get_aspect(const char *defdata, const char *data, int report_error) -{ - int num = 0, den = 1; - - if (strcmp(data, OSDOPTVAL_AUTO) == 0) - { - if (strcmp(defdata,OSDOPTVAL_AUTO) == 0) - return 0; - data = defdata; - } - if (sscanf(data, "%d:%d", &num, &den) != 2 && report_error) - osd_printf_error("Illegal aspect ratio value = %s\n", data); - return (float)num / (float)den; -} - - //============================================================ // get_resolution //============================================================ diff --git a/src/osd/sdl/video.h b/src/osd/sdl/video.h deleted file mode 100644 index 82db031aba1..00000000000 --- a/src/osd/sdl/video.h +++ /dev/null @@ -1,39 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont -//============================================================ -// -// video.h - SDL implementation of MAME video routines -// -// SDLMAME by Olivier Galibert and R. Belmont -// -//============================================================ - -#ifndef __SDLVIDEO__ -#define __SDLVIDEO__ - -#include "osdsdl.h" -#include "modules/osdwindow.h" - -//============================================================ -// TYPE DEFINITIONS -//============================================================ - -class sdl_monitor_info : public osd_monitor_info -{ -public: - sdl_monitor_info(const UINT64 handle, const char *monitor_device, float aspect) - : osd_monitor_info(&m_handle, monitor_device, aspect), m_handle(handle) - { - sdl_monitor_info::refresh(); - } - - // STATIC - static void init(); - static void exit(); -private: - void virtual refresh() override; - - UINT64 m_handle; // handle to the monitor -}; - -#endif diff --git a/src/osd/sdl/window.cpp b/src/osd/sdl/window.cpp index 450b4b59550..83c967e4306 100644 --- a/src/osd/sdl/window.cpp +++ b/src/osd/sdl/window.cpp @@ -38,6 +38,7 @@ #include "modules/render/drawbgfx.h" #include "modules/render/drawsdl.h" #include "modules/render/draw13.h" +#include "modules/monitor/monitor_common.h" #if (USE_OPENGL) #include "modules/render/drawogl.h" #endif @@ -502,7 +503,7 @@ osd_dim sdl_window_info::pick_best_mode() } // FIXME: this should be provided by monitor ! - num = SDL_GetNumDisplayModes(*((UINT64 *)m_monitor->oshandle())); + num = SDL_GetNumDisplayModes(m_monitor->oshandle()); if (num == 0) { @@ -514,7 +515,7 @@ osd_dim sdl_window_info::pick_best_mode() for (i = 0; i < num; ++i) { SDL_DisplayMode mode; - SDL_GetDisplayMode(*((UINT64 *)m_monitor->oshandle()), i, &mode); + SDL_GetDisplayMode(m_monitor->oshandle(), i, &mode); // compute initial score based on difference between target and current size_score = 1.0f / (1.0f + abs((INT32)mode.w - target_width) + abs((INT32)mode.h - target_height)); diff --git a/src/osd/windows/video.cpp b/src/osd/windows/video.cpp index 0d4232fcd1c..f752d28e29c 100644 --- a/src/osd/windows/video.cpp +++ b/src/osd/windows/video.cpp @@ -18,7 +18,6 @@ // MAMEOS headers #include "winmain.h" -#include "video.h" #include "window.h" #include "strconv.h" @@ -35,22 +34,11 @@ osd_video_config video_config; -// monitor info -std::list> osd_monitor_info::list; - - -//============================================================ -// LOCAL VARIABLES -//============================================================ - //============================================================ // PROTOTYPES //============================================================ -static void init_monitors(void); - -static float get_aspect(const char *defdata, const char *data, int report_error); static void get_resolution(const char *defdata, const char *data, osd_window_config *config, int report_error); @@ -66,9 +54,6 @@ bool windows_osd_interface::video_init() // extract data from the options extract_video_config(); - // set up monitors first - init_monitors(); - // initialize the window system so we can make windows window_init(); @@ -76,7 +61,7 @@ bool windows_osd_interface::video_init() windows_options &options = downcast(machine().options()); for (int index = 0; index < video_config.numscreens; index++) { - win_window_info::create(machine(), index, osd_monitor_info::pick_monitor(options, index), &windows[index]); + win_window_info::create(machine(), index, m_monitor_module->pick_monitor(options, index), &windows[index]); } if (video_config.mode != VIDEO_MODE_NONE) @@ -92,65 +77,8 @@ bool windows_osd_interface::video_init() void windows_osd_interface::video_exit() { window_exit(); - - // free all of our monitor information - while (!osd_monitor_info::list.empty()) - { - osd_monitor_info::list.remove(osd_monitor_info::list.front()); - } } - - -win_monitor_info::win_monitor_info(const HMONITOR handle, const char *monitor_device, float aspect) - : osd_monitor_info(&m_handle, monitor_device, aspect), m_handle(handle) -{ - win_monitor_info::refresh(); -} - -win_monitor_info::~win_monitor_info() -{ -} - -//============================================================ -// winvideo_monitor_refresh -//============================================================ - -void win_monitor_info::refresh() -{ - BOOL result; - - // fetch the latest info about the monitor - m_info.cbSize = sizeof(m_info); - result = GetMonitorInfo(m_handle, static_cast(&m_info)); - assert(result); - - m_name = utf8_from_tstring(m_info.szDevice); - - m_pos_size = RECT_to_osd_rect(m_info.rcMonitor); - m_usuable_pos_size = RECT_to_osd_rect(m_info.rcWork); - m_is_primary = ((m_info.dwFlags & MONITORINFOF_PRIMARY) != 0); - (void)result; // to silence gcc 4.6 -} - - - -//============================================================ -// winvideo_monitor_from_handle -//============================================================ - -std::shared_ptr win_monitor_info::monitor_from_handle(HMONITOR hmonitor) -{ - // find the matching monitor - for (auto monitor : osd_monitor_info::list) - if (*((HMONITOR*)monitor->oshandle()) == hmonitor) - return monitor; - - return nullptr; -} - - - //============================================================ // update //============================================================ @@ -178,131 +106,6 @@ void windows_osd_interface::update(bool skip_redraw) } - - - -//============================================================ -// monitor_enum_callback -//============================================================ - -BOOL CALLBACK win_monitor_info::monitor_enum_callback(HMONITOR handle, HDC dc, LPRECT rect, LPARAM data) -{ - MONITORINFOEX info; - BOOL result; - - // get the monitor info - info.cbSize = sizeof(info); - result = GetMonitorInfo(handle, (LPMONITORINFO)&info); - assert(result); - (void)result; // to silence gcc 4.6 - - // guess the aspect ratio assuming square pixels - float aspect = static_cast(info.rcMonitor.right - info.rcMonitor.left) / static_cast(info.rcMonitor.bottom - info.rcMonitor.top); - - // allocate a new monitor info - auto temp = utf8_from_tstring(info.szDevice); - - // copy in the data - auto monitor = std::make_shared(handle, temp.c_str(), aspect); - - // hook us into the list - osd_monitor_info::list.push_back(monitor); - - // enumerate all the available monitors so to list their names in verbose mode - return TRUE; -} - - -//============================================================ -// init_monitors -//============================================================ - -static void init_monitors(void) -{ - osd_monitor_info **tailptr; - - // make a list of monitors - EnumDisplayMonitors(nullptr, nullptr, win_monitor_info::monitor_enum_callback, (LPARAM)&tailptr); - - // if we're verbose, print the list of monitors - { - for (auto monitor : osd_monitor_info::list) - { - osd_printf_verbose("Video: Monitor %p = \"%s\" %s\n", monitor->oshandle(), monitor->devicename(), monitor->is_primary() ? "(primary)" : ""); - } - } -} - - -//============================================================ -// pick_monitor -//============================================================ - -std::shared_ptr osd_monitor_info::pick_monitor(osd_options &osdopts, int index) -{ - windows_options &options = reinterpret_cast(osdopts); - std::shared_ptr monitor; - const char *scrname, *scrname2; - int moncount = 0; - float aspect; - - // get the screen option - scrname = options.screen(); - scrname2 = options.screen(index); - - // decide which one we want to use - if (strcmp(scrname2, "auto") != 0) - scrname = scrname2; - - // get the aspect ratio - aspect = get_aspect(options.aspect(), options.aspect(index), TRUE); - - // look for a match in the name first - if (scrname != nullptr && (scrname[0] != 0)) - { - for (auto mon : osd_monitor_info::list) - { - moncount++; - if (strcmp(scrname, mon->devicename()) == 0) - { - monitor = mon; - goto finishit; - } - } - } - - // didn't find it; alternate monitors until we hit the jackpot - index %= moncount; - for (auto mon : osd_monitor_info::list) - { - if (index-- == 0) - { - monitor = mon; - goto finishit; - } - } - - // return the primary just in case all else fails - for (auto mon : osd_monitor_info::list) - { - if (mon->is_primary()) - { - monitor = mon; - goto finishit; - } - } - - // FIXME: FatalError? -finishit: - if (aspect != 0) - { - monitor->set_aspect(aspect); - } - - return monitor; -} - - //============================================================ // check_osd_inputs //============================================================ @@ -451,27 +254,6 @@ void windows_osd_interface::extract_video_config() } - -//============================================================ -// get_aspect -//============================================================ - -static float get_aspect(const char *defdata, const char *data, int report_error) -{ - int num = 0, den = 1; - - if (strcmp(data, OSDOPTVAL_AUTO) == 0) - { - if (strcmp(defdata,OSDOPTVAL_AUTO) == 0) - return 0; - data = defdata; - } - if (sscanf(data, "%d:%d", &num, &den) != 2 && report_error) - osd_printf_error("Illegal aspect ratio value = %s\n", data); - return (float)num / (float)den; -} - - //============================================================ // get_resolution //============================================================ diff --git a/src/osd/windows/video.h b/src/osd/windows/video.h index 59d14fa20d5..3f4b49efbe4 100644 --- a/src/osd/windows/video.h +++ b/src/osd/windows/video.h @@ -9,39 +9,11 @@ #ifndef __WIN_VIDEO__ #define __WIN_VIDEO__ -#include "render.h" -#include "winmain.h" -#include "modules/osdwindow.h" - -//============================================================ -// TYPE DEFINITIONS -//============================================================ +#include "modules/osdhelper.h" inline osd_rect RECT_to_osd_rect(const RECT &r) { return osd_rect(r.left, r.top, r.right - r.left, r.bottom - r.top); } -class win_monitor_info : public osd_monitor_info -{ -public: - win_monitor_info(const HMONITOR handle, const char *monitor_device, float aspect); - virtual ~win_monitor_info(); - - virtual void refresh() override; - - // static - - static BOOL CALLBACK monitor_enum_callback(HMONITOR handle, HDC dc, LPRECT rect, LPARAM data); - static std::shared_ptr monitor_from_handle(HMONITOR monitor); - - HMONITOR handle() const { return m_handle; } - -private: - HMONITOR m_handle; // handle to the monitor -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - MONITORINFOEX m_info; // most recently retrieved info -#endif -}; - #endif diff --git a/src/osd/windows/window.cpp b/src/osd/windows/window.cpp index 12832f8580d..a17fa3006ea 100644 --- a/src/osd/windows/window.cpp +++ b/src/osd/windows/window.cpp @@ -32,6 +32,8 @@ #include "winutil.h" +#include "modules/monitor/monitor_common.h" + #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #include using namespace Windows::UI::Core; @@ -211,7 +213,7 @@ void windows_osd_interface::update_slider_list() for (auto window : osd_common_t::s_window_list) { // check if any window has dirty sliders - if (window->renderer().sliders_dirty()) + if (window->has_renderer() && window->renderer().sliders_dirty()) { build_slider_list(); return; @@ -230,9 +232,12 @@ void windows_osd_interface::build_slider_list() for (auto window : osd_common_t::s_window_list) { - // take the sliders of the first window - std::vector window_sliders = window->renderer().get_slider_list(); - m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end()); + if (window->has_renderer()) + { + // take the sliders of the first window + std::vector window_sliders = window->renderer().get_slider_list(); + m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end()); + } } } @@ -782,7 +787,28 @@ void win_window_info::create(running_machine &machine, int index, std::shared_pt fatalerror("Unable to complete window creation\n"); } +std::shared_ptr win_window_info::monitor_from_rect(const osd_rect* proposed) const +{ + std::shared_ptr monitor; + // in window mode, find the nearest + if (!fullscreen()) + { + if (proposed != nullptr) + { + monitor = m_monitor->module().monitor_from_rect(*proposed); + } + else + monitor = m_monitor->module().monitor_from_window(*this); + } + else + { + // in full screen, just use the configured monitor + monitor = m_monitor; + } + + return monitor; +} //============================================================ // winwindow_video_window_destroy @@ -839,7 +865,7 @@ void win_window_info::update() } // if we're visible and running and not in the middle of a resize, draw - if (platform_window() != nullptr && m_target != nullptr) + if (platform_window() != nullptr && m_target != nullptr && has_renderer()) { bool got_lock = true; @@ -868,44 +894,6 @@ void win_window_info::update() } } - - -//============================================================ -// winwindow_video_window_monitor -// (window thread) -//============================================================ - -std::shared_ptr win_window_info::winwindow_video_window_monitor(const osd_rect *proposed) -{ - std::shared_ptr monitor; - - // in window mode, find the nearest - if (!fullscreen()) - { - if (proposed != nullptr) - { - RECT p; - p.top = proposed->top(); - p.left = proposed->left(); - p.bottom = proposed->bottom(); - p.right = proposed->right(); - monitor = win_monitor_info::monitor_from_handle(MonitorFromRect(&p, MONITOR_DEFAULTTONEAREST)); - } - else - monitor = win_monitor_info::monitor_from_handle(MonitorFromWindow(platform_window(), MONITOR_DEFAULTTONEAREST)); - } - - // in full screen, just use the configured monitor - else - monitor = m_monitor; - - // make sure we're up-to-date - //monitor->refresh(); - return monitor; -} - - - //============================================================ // create_window_class // (main thread) @@ -1418,6 +1406,8 @@ void win_window_info::draw_video_contents(HDC dc, int update) osd_rect win_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int adjustment) { + assert(GetCurrentThreadId() == window_threadid); + INT32 extrawidth = wnd_extra_width(); INT32 extraheight = wnd_extra_height(); INT32 propwidth, propheight; @@ -1426,9 +1416,13 @@ osd_rect win_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int ad INT32 viswidth, visheight; INT32 adjwidth, adjheight; float pixel_aspect; - std::shared_ptr monitor = winwindow_video_window_monitor(&rect); + + auto monitor = monitor_from_rect(&rect); - assert(GetCurrentThreadId() == window_threadid); + // Sometimes this gets called when monitors have already been torn down + // In that the case, just return the unmodified rect + if (monitor == nullptr) + return rect; // do not constrain aspect ratio for integer scaled views if (m_target->scale_mode() != SCALE_FRACTIONAL) @@ -1727,7 +1721,7 @@ void win_window_info::adjust_window_position_after_major_change() // in full screen, make sure it covers the primary display else { - std::shared_ptr monitor = winwindow_video_window_monitor(nullptr); + std::shared_ptr monitor = monitor_from_rect(nullptr); newrect = monitor->position_size(); } diff --git a/src/osd/windows/window.h b/src/osd/windows/window.h index 31fd920e40f..e58dfcae44d 100644 --- a/src/osd/windows/window.h +++ b/src/osd/windows/window.h @@ -20,7 +20,6 @@ #include #include -#include "video.h" #include "render.h" #include "modules/osdwindow.h" @@ -56,8 +55,6 @@ public: void update() override; - virtual std::shared_ptr winwindow_video_window_monitor(const osd_rect *proposed) override; - virtual bool win_has_menu() override { #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) @@ -139,6 +136,7 @@ private: void maximize_window(); void adjust_window_position_after_major_change(); void set_fullscreen(int fullscreen); + std::shared_ptr monitor_from_rect(const osd_rect* proposed) const; static POINT s_saved_cursor_pos; diff --git a/src/osd/windows/winmain.cpp b/src/osd/windows/winmain.cpp index bbb3a56860d..b660000108c 100644 --- a/src/osd/windows/winmain.cpp +++ b/src/osd/windows/winmain.cpp @@ -32,6 +32,7 @@ #include "winutil.h" #include "winfile.h" #include "modules/diagnostics/diagnostics_module.h" +#include "modules/monitor/monitor_common.h" #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) using namespace Windows::ApplicationModel;