diff --git a/src/common/drm_display.cpp b/src/common/drm_display.cpp index 2cadeef93..a667475ed 100644 --- a/src/common/drm_display.cpp +++ b/src/common/drm_display.cpp @@ -1,6 +1,7 @@ #include "drm_display.h" #include "common/assert.h" #include "common/log.h" +#include "common/scope_guard.h" #include "common/string.h" #include "file_system.h" #include @@ -9,6 +10,11 @@ #include Log_SetChannel(DRMDisplay); +enum +{ + MAX_CARDS_TO_TRY = 10 +}; + DRMDisplay::DRMDisplay(int card /*= 1*/) : m_card_id(card) {} DRMDisplay::~DRMDisplay() @@ -72,7 +78,7 @@ bool DRMDisplay::Initialize(u32 width, u32 height, float refresh_rate) { if (m_card_id < 0) { - for (int i = 0; i < 10; i++) + for (int i = 0; i < MAX_CARDS_TO_TRY; i++) { if (TryOpeningCard(i, width, height, refresh_rate)) return true; @@ -265,3 +271,101 @@ void DRMDisplay::PresentBuffer(u32 fb_id, bool wait_for_vsync) drmHandleEvent(m_card_fd, &event_ctx); } } + +bool DRMDisplay::GetCurrentMode(u32* width, u32* height, float* refresh_rate, int card, int connector) +{ + int card_fd = -1; + if (card < 0) + { + for (int try_card = 0; try_card < MAX_CARDS_TO_TRY; try_card++) + { + card_fd = open(TinyString::FromFormat("/dev/dri/card%d", try_card), O_RDWR); + if (card_fd >= 0) + break; + } + } + else + { + card_fd = open(TinyString::FromFormat("/dev/dri/card%d", card), O_RDWR); + } + + if (card_fd < 0) + { + Log_ErrorPrintf("open(/dev/dri/card%d) failed: %d (%s)", card, errno, strerror(errno)); + return false; + } + + Common::ScopeGuard card_guard([card_fd]() { close(card_fd); }); + + drmModeRes* resources = drmModeGetResources(card_fd); + if (!resources) + { + Log_ErrorPrintf("drmModeGetResources() failed: %d (%s)", errno, strerror(errno)); + return false; + } + + Common::ScopeGuard resources_guard([resources]() { drmModeFreeResources(resources); }); + drmModeConnector* connector_ptr = nullptr; + if (connector < 0) + { + for (int i = 0; i < resources->count_connectors; i++) + { + connector_ptr = drmModeGetConnector(card_fd, resources->connectors[i]); + if (connector_ptr->connection == DRM_MODE_CONNECTED) + break; + + drmModeFreeConnector(connector_ptr); + } + } + else if (connector < resources->count_connectors) + { + connector_ptr = drmModeGetConnector(card_fd, resources->connectors[connector]); + } + + Common::ScopeGuard connector_guard([connector_ptr]() { + if (connector_ptr) + drmModeFreeConnector(connector_ptr); + }); + if (!connector_ptr || connector_ptr->connection != DRM_MODE_CONNECTED) + { + Log_ErrorPrintf("No connector found"); + return false; + } + + drmModeEncoder* encoder = drmModeGetEncoder(card_fd, connector_ptr->encoder_id); + if (!encoder) + { + Log_ErrorPrint("No encoder found"); + return false; + } + + Common::ScopeGuard encoder_guard([encoder]() { drmModeFreeEncoder(encoder); }); + + drmModeCrtc* crtc = drmModeGetCrtc(card_fd, encoder->crtc_id); + if (!crtc) + { + Log_ErrorPrint("No CRTC found"); + return false; + } + + if (!crtc->mode_valid) + { + Log_ErrorPrint("CRTC mode not valid"); + return false; + } + + const u32 current_width = static_cast(crtc->mode.hdisplay); + const u32 current_height = static_cast(crtc->mode.vdisplay); + const float current_refresh_rate = (static_cast(crtc->mode.clock) * 1000.0f) / + (static_cast(crtc->mode.htotal) * static_cast(crtc->mode.vtotal)); + Log_InfoPrintf("Current mode for card %d: %ux%u@%f", card, current_width, current_height, current_refresh_rate); + + if (width) + *width = current_width; + if (height) + *height = current_height; + if (refresh_rate) + *refresh_rate = current_refresh_rate; + + return true; +} \ No newline at end of file diff --git a/src/common/drm_display.h b/src/common/drm_display.h index 39506b7eb..1ef019c33 100644 --- a/src/common/drm_display.h +++ b/src/common/drm_display.h @@ -11,6 +11,8 @@ public: DRMDisplay(int card = -1); ~DRMDisplay(); + static bool GetCurrentMode(u32* width, u32* height, float* refresh_rate, int card = -1, int connector = -1); + bool Initialize(u32 width, u32 height, float refresh_rate); int GetCardID() const { return m_card_id; } diff --git a/src/duckstation-nogui/CMakeLists.txt b/src/duckstation-nogui/CMakeLists.txt index 6fb80fefd..d362c7665 100644 --- a/src/duckstation-nogui/CMakeLists.txt +++ b/src/duckstation-nogui/CMakeLists.txt @@ -29,6 +29,10 @@ if(USE_EVDEV) target_link_libraries(duckstation-nogui PRIVATE ${LIBEVDEV_LIBRARIES}) endif() +if(USE_DRMKMS) + target_compile_definitions(duckstation-nogui PRIVATE "-DWITH_DRMKMS=1") +endif() + if(WIN32) target_sources(duckstation-nogui PRIVATE duckstation-nogui.manifest diff --git a/src/duckstation-nogui/nogui_host_interface.cpp b/src/duckstation-nogui/nogui_host_interface.cpp index ec3e0c702..005860161 100644 --- a/src/duckstation-nogui/nogui_host_interface.cpp +++ b/src/duckstation-nogui/nogui_host_interface.cpp @@ -125,6 +125,7 @@ bool NoGUIHostInterface::CreateDisplay() if (!CreateHostDisplayResources()) Log_WarningPrint("Failed to create host display resources"); + Log_InfoPrintf("Host display initialized at %ux%u resolution", m_display->GetWindowWidth(), m_display->GetWindowHeight()); return true; } diff --git a/src/duckstation-nogui/vty_host_interface.cpp b/src/duckstation-nogui/vty_host_interface.cpp index 2bbd32778..bd2ec1259 100644 --- a/src/duckstation-nogui/vty_host_interface.cpp +++ b/src/duckstation-nogui/vty_host_interface.cpp @@ -10,6 +10,10 @@ #include Log_SetChannel(VTYHostInterface); +#ifdef WITH_DRMKMS +#include "common/drm_display.h" +#endif + VTYHostInterface::VTYHostInterface() = default; VTYHostInterface::~VTYHostInterface() @@ -88,6 +92,15 @@ std::optional VTYHostInterface::GetPlatformWindowInfo() } } +#ifdef WITH_DRMKMS + // set to current mode + if (wi.surface_width == 0) + { + if (!DRMDisplay::GetCurrentMode(&wi.surface_width, &wi.surface_height, &wi.surface_refresh_rate)) + Log_ErrorPrintf("Failed to get current mode, will use default."); + } +#endif + return wi; }