// license:BSD-3-Clause // copyright-holders: Brad Hughes /* * monitor_dxgi.cpp * */ #include "modules/osdmodule.h" #include "monitor_module.h" #if defined(OSD_WINDOWS) || defined(OSD_UWP) // standard windows headers #include #include #include #undef interface #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 = osd::text::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; } }; class dxgi_monitor_module : public monitor_module_base { private: OSD_DYNAMIC_API(dxgi, "dxgi.dll"); OSD_DYNAMIC_API_FN(dxgi, DWORD, WINAPI, CreateDXGIFactory1, REFIID, void**); public: dxgi_monitor_module() : monitor_module_base(OSD_MONITOR_PROVIDER, "dxgi") { } bool probe() override { if(!OSD_DYNAMIC_API_TEST(CreateDXGIFactory1)) 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; #if defined(OSD_WINDOWS) 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; #elif defined(OSD_UWP) if (list().size() == 0) return nullptr; // For now just return first monitor return list()[0]; #endif } // 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; #if defined(OSD_WINDOWS) auto nearest = monitor_from_handle(reinterpret_cast(MonitorFromWindow(static_cast(window).platform_window(), MONITOR_DEFAULTTONEAREST))); assert(nearest != nullptr); return nearest; #elif defined(OSD_UWP) if (list().size() == 0) return nullptr; // For now just return first monitor return list()[0]; #endif } protected: int init_internal(const osd_options& options) override { HRESULT result; ComPtr dxgiDevice; ComPtr factory; ComPtr adapter; result = OSD_DYNAMIC_CALL(CreateDXGIFactory1, __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 = osd::text::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)