How can I determine the monitor refresh rate?
Asked Answered
R

5

8

Is there a cross platform way to get the monitor's refresh rate in python (2.6)? I'm using Pygame and PyOpenGL, if that helps.

I don't need to change the refresh rate, I just need to know what it is.

Rosanarosane answered 3/8, 2009 at 23:7 Comment(3)
What are you going to use the refresh rate for, if I might ask? If you are writing a game loop or something, you generally don't need to use the refresh rate.Choe
When my app is running in full screen, v-sync is enabled which caps the fps at the refresh rate. V-sync isn't enabled in windowed mode, and the fps is many times faster. I want it to run at the same speed in windowed and fullscreen, so I want to set the maximum fps as the refresh rate of the monitor.Rosanarosane
You should not tie your game logic and your render rate together as much as you have. Look here for some alternative game loop constructions: dewitters.koonsolo.com/gameloop.htmlChoe
C
11

I am not sure about the platform you use, but on window you can use ctypes or win32api to get details about devices e.g. using win32api

import win32api

def printInfo(device):
    print((device.DeviceName, device.DeviceString))
    settings = win32api.EnumDisplaySettings(device.DeviceName, -1)
    for varName in ['Color', 'BitsPerPel', 'DisplayFrequency']:
        print("%s: %s"%(varName, getattr(settings, varName)))

device = win32api.EnumDisplayDevices()
printInfo(device)

output on my system:

\\.\DISPLAY1 Mobile Intel(R) 945GM Express Chipset Family
Color: 0
BitsPerPel: 8
DisplayFrequency: 60
Capture answered 4/8, 2009 at 4:40 Comment(0)
K
2

I recommend switching to the community edition of pygame. Their website https://pyga.me/. Long story short, the pygame former core developers had challenges contributing to the original development upstream, so they forked the repository and moved to this new distribution that aims to offer more frequent releases, continuous bug fixes and enhancements, and a more democratic governance model (The magic of Open Source). You can easily switch to it by running pip uninstall pygame and then pip install pygame-ce --upgrade. They have the same API as the original pygame (so you still use import pygame and everything remains the same).

They have many nice new features and bug fixes, including methods to get the monitor's refresh rate in the display module:

import pygame

pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
running = True

print(
    "Screen refresh rate for current window:", pygame.display.get_current_refresh_rate()
)  # Must be called after pygame.display.set_mode()
print(
    "Screen refresh rate for all displays:", pygame.display.get_desktop_refresh_rates()
)  # Safe to call before pygame.display.set_mode()

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill("purple")

    pygame.display.flip()
    clock.tick(60)  # limits FPS to 60

pygame.quit()

On my computer, this prints

pygame-ce 2.3.2 (SDL 2.26.5, Python 3.11.4)
Screen refresh rate for current window: 144
Screen refresh rate for all displays: [144]

which is indeed correct.

Kane answered 26/9, 2023 at 12:35 Comment(0)
R
1

On macOS, you can use pyobjc to query the refresh rate of all the attached displays. You'll need the Cocoa (i.e. "AppKit") framework for this:

$ python3 -m venv screen-res
$ . ./screen-res/bin/activate
$ pip install pyobjc-framework-Cocoa

then, in Python:

from AppKit import NSScreen

for each in NSScreen.screens():
    print(f"{each.localizedName()}: {each.maximumFramesPerSecond()}Hz")

On my system, this produces:

LG HDR WQHD+: 120Hz
Built-in Retina Display: 120Hz

(Which is correct, my displays are indeed both set to a 120Hz refresh rate.)

On Linux, you can use python-xlib:

from Xlib import display
from Xlib.ext import randr
d = display.Display()
default_screen = d.get_default_screen()
info = d.screen(default_screen)

resources = randr.get_screen_resources(info.root)
active_modes = set()
for crtc in resources.crtcs:
    crtc_info = randr.get_crtc_info(info.root, crtc, resources.config_timestamp)
    if crtc_info.mode:
        active_modes.add(crtc_info.mode)

for mode in resources.modes:
    if mode.id in active_modes:
        print(mode.dot_clock / (mode.h_total * mode.v_total))

Associating the appropriate screen index number with the place you want your PyOpenGL window to open up on is left as an exercise for the reader :).

(I won't duplicate Anurag's answer for Windows here, especially since I can't test it, but that's how you would do it on that platform.)

Rosaline answered 4/2, 2022 at 23:50 Comment(0)
D
0

You can use DEVMODEW, but this only works on Windows Machines.

Install 'wmi' using pip with "pip install wmi"

import ctypes
import wmi
from time import sleep

class DEVMODEW(ctypes.Structure): # Defines the DEVMODEW Structure
_fields_ = [
    ("dmDeviceName", ctypes.c_wchar * 32),
    ("dmSpecVersion", ctypes.c_uint16),
    ("dmDriverVersion", ctypes.c_uint16),
    ("dmSize", ctypes.c_uint32),
    ("dmDriverExtra", ctypes.c_uint16),
    ("dmFields", ctypes.c_uint32),
    ("dmPosition", ctypes.c_int32 * 2),
    ("dmDisplayOrientation", ctypes.c_uint32),
    ("dmDisplayFixedOutput", ctypes.c_uint32),
    ("dmColor", ctypes.c_short),
    ("dmDuplex", ctypes.c_short),
    ("dmYResolution", ctypes.c_short),
    ("dmTTOption", ctypes.c_short),
    ("dmCollate", ctypes.c_short),
    ("dmFormName", ctypes.c_wchar * 32),
    ("dmLogPixels", ctypes.c_uint16),
    ("dmBitsPerPel", ctypes.c_uint32),
    ("dmPelsWidth", ctypes.c_uint32),
    ("dmPelsHeight", ctypes.c_uint32),
    ("dmDisplayFlags", ctypes.c_uint32),
    ("dmDisplayFrequency", ctypes.c_uint32),
    ("dmICMMethod", ctypes.c_uint32),
    ("dmICMIntent", ctypes.c_uint32),
    ("dmMediaType", ctypes.c_uint32),
    ("dmDitherType", ctypes.c_uint32),
    ("dmReserved1", ctypes.c_uint32),
    ("dmReserved2", ctypes.c_uint32),
    ("dmPanningWidth", ctypes.c_uint32),
    ("dmPanningHeight", ctypes.c_uint32)
]

def get_monitor_refresh_rate():
    c = wmi.WMI()
    for monitor in c.Win32_VideoController():
        return monitor.MaxRefreshRate
    return None

refresh_rate = get_monitor_refresh_rate()
if refresh_rate is not None:
    print(f"Monitor refresh rate: {refresh_rate} Hz")
else:
    print("Cannot Detremine the Monitor Refresh Rate.")
sleep(10)
Dirac answered 15/4, 2023 at 16:36 Comment(0)
N
-4

You can use the pygame clock

fps = 60
clock = pygame.time.Clock()

At the end of the code: clock.tick(fps)

Nice answered 18/8, 2020 at 13:2 Comment(1)
the question is about getting the monitors refresh rate, not setting the game's frame rate.Bickerstaff

© 2022 - 2025 — McMap. All rights reserved.