瀏覽代碼

XCB: Implement GetDisplayRefreshRate (#18576)

XCB: Implement GetDisplayRefreshRate

Signed-off-by: Reece Hagan <[email protected]>
Reece Hagan 3 月之前
父節點
當前提交
4672e16b20

+ 121 - 3
Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp

@@ -13,6 +13,7 @@
 #include <AzFramework/XcbNativeWindow.h>
 
 #include <xcb/xcb.h>
+#include <xcb/randr.h>
 
 namespace AzFramework
 {
@@ -354,10 +355,127 @@ namespace AzFramework
     ////////////////////////////////////////////////////////////////////////////////////////////////
     uint32_t XcbNativeWindow::GetDisplayRefreshRate() const
     {
-        // [GFX TODO][GHI - 2678]
-        // Using 60 for now until proper support is added
+        constexpr uint32_t defaultRefreshRate = 60;
+        xcb_generic_error_t* error = nullptr;
+
+        xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(m_xcbConnection));
+        xcb_screen_t* screen = iter.data;
+
+        const xcb_query_extension_reply_t* extReply = xcb_get_extension_data(m_xcbConnection, &xcb_randr_id);
+        if (!extReply || !extReply->present)
+        {
+            AZ_WarningOnce(XcbErrorWindow, extReply != nullptr, "Failed to get extension RandR, defaulting to display rate of %d", defaultRefreshRate);
+            return defaultRefreshRate;
+        }
+
+        int positionX = 0;
+        int positionY = 0;
+
+        //Get the position of the window globally.
+        {
+            xcb_translate_coordinates_cookie_t translateCookie = xcb_translate_coordinates(
+                m_xcbConnection,
+                m_xcbWindow,
+                screen->root,
+                0,
+                0
+                );
+            xcb_translate_coordinates_reply_t* translateReply = xcb_translate_coordinates_reply(
+                m_xcbConnection,
+                translateCookie,
+                &error
+                );
+
+            if (error || translateReply == nullptr)
+            {
+                AZ_Warning(XcbErrorWindow, error != nullptr, "Failed to translate window coordinates.");
+                free(error);
+                free(translateReply);
+                return defaultRefreshRate;
+            }
+
+            positionX = translateReply->dst_x;
+            positionY = translateReply->dst_y;
+            free(translateReply);
+        }
+
+        xcb_randr_get_screen_resources_current_cookie_t resCookie = xcb_randr_get_screen_resources_current(m_xcbConnection, screen->root);
+        xcb_randr_get_screen_resources_current_reply_t* resReply = xcb_randr_get_screen_resources_current_reply(
+            m_xcbConnection,
+            resCookie,
+            &error);
+
+        if (error || resReply == nullptr)
+        {
+            AZ_Warning(XcbErrorWindow, error != nullptr, "Failed to get screen resources.");
+            free(error);
+            return defaultRefreshRate;
+        }
+
+        xcb_randr_crtc_t* crtcs = xcb_randr_get_screen_resources_current_crtcs(resReply);
+        int crtcLength = xcb_randr_get_screen_resources_current_crtcs_length(resReply);
+
+        uint32_t refreshRate = 0;
+
+        for (int i = 0; i < crtcLength; i++)
+        {
+            xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = xcb_randr_get_crtc_info(m_xcbConnection, crtcs[i], XCB_TIME_CURRENT_TIME);
+            xcb_randr_get_crtc_info_reply_t* crtcInfoReply = xcb_randr_get_crtc_info_reply(m_xcbConnection, crtcInfoCookie, &error);
+
+            if (error || crtcInfoReply == nullptr)
+            {
+                free(error);
+                continue;
+            }
+
+            int crtcX = crtcInfoReply->x;
+            int crtcY = crtcInfoReply->y;
+            int crtcW = crtcInfoReply->width;
+            int crtcH = crtcInfoReply->height;
+
+            if (positionX + m_width > crtcX && positionX < crtcX + crtcW &&
+                positionY + m_height > crtcY && positionY < crtcY + crtcH)
+            {
+                const uint32_t modeId = crtcInfoReply->mode;
+
+                xcb_randr_mode_info_t* modes = xcb_randr_get_screen_resources_current_modes(resReply);
+                int modesLength = xcb_randr_get_screen_resources_current_modes_length(resReply);
+
+                for (int mi = 0; mi < modesLength; mi++)
+                {
+                    auto mode = modes[mi];
+                    if (mode.id != modeId)
+                        continue;
+
+                    if(mode.htotal == 0 || mode.vtotal == 0)
+                    {
+                        AZ_WarningOnce(XcbErrorWindow, false, "V/H total is 0");
+                        return defaultRefreshRate;
+                    }
+
+                    double refreshRatePrecise = static_cast<double>(mode.dot_clock) /
+                        (mode.htotal * mode.vtotal);
+
+                    //Most of the time the refresh rate is 159.798 or 59.98
+                    refreshRate = static_cast<uint32_t>(ceil(refreshRatePrecise));
+                }
+
+                free(crtcInfoReply);
+                break;
+            }
+
+            free(crtcInfoReply);
+        }
+
+        if (refreshRate == 0)
+        {
+            AZ_Warning(XcbErrorWindow, refreshRate == 0, "Failed to get CRTC refresh rate for window.");
+            free(resReply);
+            return defaultRefreshRate;
+        }
 
-        return 60;
+        free(resReply);
+        return refreshRate;
     }
 
     bool XcbNativeWindow::GetFullScreenState() const

+ 1 - 0
Code/Framework/AzFramework/Platform/Linux/platform_nativeui_linux.cmake

@@ -23,6 +23,7 @@ if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
             3rdParty::X11::xcb
             3rdParty::X11::xcb_xkb
             3rdParty::X11::xcb_xfixes
+            3rdParty::X11::xcb_randr
             3rdParty::X11::xkbcommon
             3rdParty::X11::xkbcommon_X11
             xcb-xinput

+ 1 - 0
Docker/Dockerfile

@@ -75,6 +75,7 @@ RUN apt-get update \
             libfontconfig1-dev \
             libnvidia-gl-470 \
             libxcb-xkb-dev \
+            libxcb-randr0-dev \
             libxkbcommon-x11-dev \
             libxkbcommon-dev \
             libxcb-xfixes0-dev \

+ 1 - 0
cmake/Platform/Linux/Packaging_linux.cmake

@@ -48,6 +48,7 @@ elseif("$ENV{O3DE_PACKAGE_TYPE}" STREQUAL "DEB")
         libxkbcommon-dev                        # For xcb keyboard input
         libxcb-xfixes0-dev                      # For mouse input
         libxcb-xinput-dev                       # For mouse input
+        libxcb-randr0-dev                       # For xcb display
         libpcre2-16-0
         zlib1g-dev
         mesa-common-dev

+ 1 - 0
scripts/build/build_node/Platform/Linux/package-list.ubuntu-bionic.txt

@@ -21,6 +21,7 @@ libxkbcommon-dev                        # For xcb keyboard input
 libxcb-xfixes0-dev                      # For mouse input
 libxcb-xinput-dev                       # For mouse input
 libxcb-image0-dev                       # For xcb image support
+libxcb-randr0-dev                       # For xcb display info
 xxd
 zlib1g-dev
 mesa-common-dev

+ 1 - 0
scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt

@@ -20,6 +20,7 @@ libxkbcommon-dev                        # For xcb keyboard input
 libxcb-xfixes0-dev                      # For mouse input
 libxcb-xinput-dev                       # For mouse input
 libxcb-image0-dev                       # For xcb image support
+libxcb-randr0-dev                       # For xcb display info
 xxd
 zlib1g-dev
 mesa-common-dev

+ 1 - 0
scripts/build/build_node/Platform/Linux/package-list.ubuntu-jammy.txt

@@ -20,6 +20,7 @@ libxkbcommon-dev                        # For xcb keyboard input
 libxcb-xfixes0-dev                      # For mouse input
 libxcb-xinput-dev                       # For mouse input
 libxcb-image0-dev                       # For xcb image support
+libxcb-randr0-dev                       # For xcb display info
 xxd
 zlib1g-dev
 mesa-common-dev

+ 1 - 0
scripts/build/build_node/Platform/Linux/package-list.ubuntu-noble.txt

@@ -19,6 +19,7 @@ libxkbcommon-x11-dev                    # For xcb keyboard input
 libxkbcommon-dev                        # For xcb keyboard input
 libxcb-xfixes0-dev                      # For mouse input
 libxcb-xinput-dev                       # For mouse input
+libxcb-randr0-dev                       # For xcb display info
 zlib1g-dev
 mesa-common-dev
 ros-jazzy-ackermann-msgs               # ROS2 development tools