Godot에서 Windows 환경의 고(高) 폴링 레이트 마우스 문제 해결하기
요약
Godot 엔진이 Godot 4.7.2 버전에서 Windows 환경의 고 폴링 레이트 마우스 관련 성능 문제를 해결했습니다. 이 수정 사항은 높은 주사율 모니터와 최신 게이밍 장비 사용 시 발생하는 입력 지연 및 업데이트 불일치 문제를 개선합니다. 이는 게임 개발에 필수적인 일관된 사용자 경험을 제공합니다.
핵심 포인트
- Godot 4.7.2에서 고 폴링 레이트 마우스 문제가 해결됨.
- 고 폴링 레이트는 낮은 입력 지연과 일관성을 보장하는 데 중요함.
- 높은 주사율 모니터 사용 시 마우스 업데이트의 불일치 문제를 개선함.
- 마우스 폴링 레이트가 높아지면서 소프트웨어 개발에 새로운 과제가 생김.
오랫동안 기다려온, Godot 엔진에서 Windows 환경의 고(高) 폴링 레이트 마우스 관련 성능 문제가 최근 출시된 Godot 4.7.2 버전을 기점으로 해결되었습니다. 본 문서는 이 수정 사항이 어떻게 작동하는지, 그리고 오늘날 왜 그렇게 중요한지를 설명합니다.
참고: 여기서 '고 폴링 레이트(high polling rate)'의 정의는 2 kHz 이상의 폴링 레이트로 설정할 수 있는 모든 마우스를 의미합니다. 1 kHz로 폴링하는 마우스는 일반적으로 매우 느린 싱글 코어 성능을 가진 CPU를 제외하고는 성능 문제를 보이지 않았기 때문에, 여기서는 고 폴링 레이트에 해당하지 않습니다.
고 폴링 레이트 마우스란 무엇이며, 왜 유용한가요?
게임이 플레이하기에 좋게 느껴지도록 하려면, 어떤 행동을 수행한 것과 그 결과가 화면에 보이는 시간 지연(입력 지연, input lag)을 가능한 한 낮추고 싶습니다. 또한 입력 간격이 일관되게 유지되어 떨림(jitter)을 피하는 것도 중요합니다.
마우스는 고정된 속도로 폴링됩니다. 역사적으로 이는 USB 표준에 의해 125 Hz로 규정되었습니다. 이는 마우스 입력이 8밀리초마다 폴링됨을 의미하며, 다음과 같은 여러 제한 사항을 야기했습니다:
-
운영 체제에 보고되는 마우스 위치는 초당 125회만 업데이트됩니다. 만약 고주사율 모니터(144Hz 이상)를 사용한다면, 마우스 위치가 매 프레임마다 업데이트되지 않아 마우스 움직임이 끊기는 것처럼 보일 수 있습니다. 이는 운영 체제뿐만 아니라, 캡처된 마우스 모드를 포함하여 마우스 입력을 사용하는 게임에도 영향을 미칩니다.
-
120Hz 이하의 주사율을 가진 모니터에서도, 마우스 위치는 높은 폴링 레이트만큼 화면에 표시되는 프레임마다 일관되지 않을 것입니다. 그 이유는 마우스 업데이트가 디스플레이 리프레시와 맞지 않기 때문입니다. 더 높은 폴링 레이트를 사용하면, 마지막으로 마우스가 업데이트된 시간과 디스플레이 리프레시 사이의 평균 편차가 줄어듭니다.
-
평균적으로, 운영 체제 및 마우스 하드웨어로 인해 발생하는 모든 지연 시간을 제외하더라도, 사용자가 마우스를 움직인 시점부터 업데이트된 위치가 운영 체제에 제공되기까지 4밀리초의 지연이 발생합니다. 이는 처음 들으면 무시할 수 있는 것처럼 느껴질 수 있지만, 일부 사람들에게는 밀리초 단위의 마우스 지연 차이가 감지될 수 있습니다.
2000년대 후반에 제조사들은 250Hz, 500Hz, 그리고 1kHz 폴링 레이트 옵션을 제공하기 시작했습니다. 오랫동안 1kHz는 시장에서 사용 가능한 가장 빠른 폴링 레이트였습니다.

하지만 2020년대 초반부터 제조사들은 무선 모델을 포함하여 1kHz를 넘어서는 폴링 레이트를 추진해 왔습니다. 우리는 2kHz, 4kHz, 심지어 8kHz 마우스가 시장에 출시되는 것을 보았으며, 시간이 지남에 따라 가격도 더욱 저렴해졌습니다. 이러한 높은 폴링 레이트는 입력 지연 시간을 약간 줄일 수 있게 할 뿐만 아니라, 가장 중요하게는 시간 경과에 따른 마우스 업데이트의 일관성을 보장합니다. 현대 디스플레이가 480Hz, 720Hz 또는 더 많은의 주사율에 도달할 수 있게 되면서, 마우스 폴링 레이트를 1kHz 장벽 이상으로 끌어올리는 것이 점점 더 중요해지고 있습니다.
이는 매우 높은 폴링 레이트를 가진 마우스의 빠른 채택으로 이어졌고, 이는 소프트웨어 개발자들에게 문제를 야기합니다.
고폴링 레이트 마우스의 문제는 무엇일까요?
운영체제가 마우스 이벤트를 훨씬 더 자주 받게 되면서, 드롭된 이벤트가 발생하거나(dropped events), 혹은 이벤트 처리가 너무 늦게 처리되는 것(지연 시간 증가를 초래함)을 피하기 위해 이를 적시에 처리해야 합니다. 다시 말해, 높은 폴링 레이트에는 큰 책임이 따릅니다.
안타깝게도 운영체제는 원래 마우스가 언젠가 초당 수천 개의 업데이트를 보낼 수 있다는 사실을 고려하지 않았습니다. 현대 CPU의 처리 능력이 일부 플랫폼에서 이 문제를 무차별적으로 처리하는 것이 가능하게 만들기는 했지만, 이는 Windows에서 특히 심각했습니다.
실제로 이것은 특정 임계치를 초과하여 마우스 업데이트가 발생하기 시작하면 상당한 프레임률 저하로 나타납니다. 이 임계치에 도달하는 속도는 마우스 이동 속도(아주 작은 마우스 움직임으로는 모든 폴마다 업데이트를 보내지 않기 때문에)와 CPU 싱글 코어 성능에 따라 달라집니다. 2026년 기준 그리고 최신 Windows 11 버전에서 대부분의 CPU는 이 한계가 일반적으로 1 kHz에서 2 kHz 사이입니다. 만약 마우스가 이 한계보다 훨씬 더 많은 업데이트를 보낸다면, 프레임률이 한 자릿수로 떨어져 플레이 불가능한 경험을 초래할 수 있습니다:

이 문제는 특히 기술에 익숙하지 않은 사용자들에게는 트러블슈팅하기가 매우 어렵습니다. 일부 마우스는 1 kHz 이상의 폴링 레이트로 _기본 설정_되는 경우가 있기 때문입니다. 이는 특정 마우스 모델 사용과 관련 있는 성능 손실처럼 보이지만, 실제로는 해당 마우스의 폴링 레이트와 관련된 문제입니다.
Godot만이 Windows에서 이 문제에 직면하는 엔진은 아닙니다. 수많은 게임들이 초기 Windows 게이밍 시절부터 오늘날 인기 있는 출시작에 이르기까지 이 문제로 고통받고 있습니다. 비캡처드(non-captured) 마우스 모드를 사용하는 게임들(즉, 마우스 커서가 보이는 상태)은 이러한 상황에서 성능 문제를 피하기 위해 추가적인 주의를 기울여야 하므로 더 취약합니다.
Linux(Wayland와 X11 모두에서)에서는 게임과 관계없이 일반적으로 이 문제의 영향을 받지 않습니다.
Windows에서만 이 문제가 발생하는 이유는 무엇일까요?
Windows는 30년 이상 거슬러 올라가는 오랜 하위 호환성 역사를 가지고 있습니다. 이는 많은 경우 축복이지만, 이 상황에서는 문제가 됩니다.
Windows에는 여러 유형의 마우스 움직임 이벤트가 있습니다:
-
레거시 입력(WM_MOUSEMOVE로 알려짐). 이것은 게임보다는 애플리케이션을 위해 설계된 일반적인 종류의 마우스 움직임 이벤트입니다.
-
Raw input(WM_INPUT으로 알려짐). Raw input은 OS 처리를 무시하고 게임이 마우스 입력을 읽을 수 있도록 허용한 방법으로 Windows XP에 도입되었습니다(마우스 가속도, 즉 “향상된 포인터 정밀도” 옵션으로 알려진 것과 같은).
이는 특히 1인칭 게임에서 바람직한데, 이러한 게임에서는 일반적으로 플레이어가 마우스 가속도를 원하지 않거나(원할 경우 인게임에서 더 잘 구성됨) 합니다.
하지만 Windows 애플리케이션에서 raw input을 요청하더라도 여전히 레거시 입력 이벤트를 동시에 받게 됩니다. 이는 애플리케이션이 현재 캡처된 마우스 모드(예: 마우스 커서가 보이지 않는 1인칭 게임)에 있더라도 마찬가지입니다.
오직 raw input만 요청하고 레거시 입력을 제외하는 것이 가능하지만, 그렇게 하면 사용자가 기대하는 여러 애플리케이션 부분(예: 제목 표시줄을 드래그하여 창 이동)이 작동하지 않게 됩니다. 따라서 우리는 PH3의 Windows에서 고주사율 마우스에 대한 블로그 게시물에서 영감을 받은 다른 솔루션을 구현해야 했습니다.
해결책
해결책은 마우스 움직임 입력을 다른 입력 유형과 분리하여 취급하고, 입력 시스템이 혼잡해지는 것을 방지하는 방식으로 처리하는 것입니다. 이를 달성하기 위해:
-
버퍼링된 읽기(Buffered reads)는
DisplayServerWindows::process_raw_input()함수에서 수행됩니다. -
또한,
DisplayServerWindows::process_events()에서는 Windows API의PeekMessageW()함수가 호출되는데, 이 방식은 원시 입력(raw input,WM_INPUT)이 즉시 디스패치되는 것을 방지합니다 (원래 캡처된 마우스 모드에서 성능 저하를 유발하는 주범). 대신, 해당 입력은process_raw_input()의 다음 버퍼링 읽기까지 대기열에 남아 있게 됩니다. -
레거시 입력(Legacy inputs)(
WM_MOUSEMOVE및WM_NCMOUSEMOVE)은 별도로 처리되지만, 각각 프레임당 최대 한 번만 디스패치됩니다. 이는 비캡처된 마우스 모드에서 높은 폴링 레이트일 때 성능 문제를 방지합니다.
다른 입력(키, 마우스 버튼, 마우스 휠)은 이전과 동일하게 처리되는데, 이들은 기존 방식 하에서도 문제가 될 만큼 자주 전송되지 않기 때문입니다. 비록 폴링 레이트가 1 kHz를 초과하는 키보드가 존재하지만, 현재의 입력 시스템을 포화시킬 수 있는 방식으로 키를 누르거나 떼는 것은 인간적으로 불가능합니다.
게임패드 입력은 Windows에서 별도의 시스템에 의해 계속 처리되며, 이 수정 사항의 영향을 받지 않습니다. 어쨌든 작성 시점을 기준으로 1 kHz 이상으로 폴링할 수 있는 게임패드는 매우 적습니다.
참고로, 프로젝트는 여전히 _input() 및 _unhandled_input() 함수를 최적화하는 데 주의해야 합니다. 특히 InputEventMouseMotion을 위해 호출되는 코드 경로는 더욱 그렇습니다. 이 메서드들은 입력 누적(input accumulation)이 활성화된 경우 (기본값) 프레임당 한 번 호출될 수 있습니다. 예를 들어, V-Sync가 활성화된 480 Hz 모니터의 경우, 시스템이 최소 480 FPS로 렌더링할 만큼 충분히 빠르다고 가정하면 빠른 마우스 움직임 동안 초당 최대 480회 호출될 수 있습니다. 입력 누적이 비활성화되면 이 메서드들은 모든 마우스 업데이트마다 호출될 수 있으며, 이는 8 kHz 폴링 레이트의 마우스를 사용할 경우 잠재적으로 초당 8,000회에 달하는 호출을 의미할 수 있습니다.
벤치마크
테스트를 위해 풀 리퀘스트 설명에서 사용할 수 있는 InputRepro2 테스트 프로젝트를 사용합니다.
PC 사양:
- CPU: AMD Ryzen 9 9950X3D
- GPU: NVIDIA GeForce RTX 5090
- RAM: 64 GB (2×32 GB DDR5-6000 CL30)
- OS: Windows 11 24H2
- 모니터: ASUS ROG PG32UCDP (1080p @ 480 Hz 모드)
참고: 4.7.1.stable 버전에는 본 기사에서 설명하는 수정 사항이 포함되어 있지 않으며, 4.8.dev3가 이를 포함하는 첫 번째 개발 스냅샷입니다. 최근에 출시된 4.7.2.stable에도 이 수정 사항이 포함되어 있습니다.
마우스를 원을 그리며 빠르게 움직일 때의 평균 프레임률:
V-Sync 없음 (무제한 최대 프레임률)
⚠️ [IMG:N] 형식 토큰은 이미지 placeholder 입니다. 번역하지 말고 원래 위치에 그대로 유지하세요.
| Benchmark | 4.7.1.stable | 4.8.dev3 |
|---|---|---|
| No movement | 4097 FPS (0.24 mspf) | 4061 FPS (0.25 mspf) |
| ... | ||
| 과거에는 8 kHz 폴링 레이트로 마우스를 움직일 때 성능이 플레이 불가능한 수준으로 떨어졌습니다. 4 kHz 폴링 레이트에서도 상당한 프레임 시간 편차가 발생하여 움직임이 눈에 띄게 거칠었습니다: |

위의 그래프를 동일한 조건에서 수정 사항을 적용했을 때 기록된 이 프레임 시간 그래프와 비교해 보세요:

1% 낮은 FPS 수치가 여기서는 45.8배 증가했습니다! 이것은 이 수정 사항 덕분에 얼마나 큰 개선이 이루어질 수 있는지 보여주는 단지 하나의 예시일 뿐입니다.
더 느린 CPU에서는 본 기사에서 설명한 수정 사항의 혜택을 더 많이 받을 것입니다. 왜냐하면 테스트에 사용된 CPU는 매우 높은 싱글 코어 성능(초당 처리할 수 있는 입력 메시지의 양을 결정하는 요소)을 가지고 있기 때문입니다. 이 수정 사항이 특정 CPU에서 2 kHz 폴링 레이트일 때 큰 변화는 아니었지만, 데스크톱 CPU보다 싱글 코어 성능이 낮은 느린 프로세서나 노트북 CPU에서는 확실히 유용할 것입니다.
이것이 우리가 지속적으로 높은 프레임률에 도달하는 것을 목표로 하는 시나리오에서는 어떻게 적용될까요? 이 수정 사항을 통해 8 kHz에서도 훨씬 더 실현 가능해졌습니다:
V-Sync 480 Hz
| Benchmark | 4.7.1.stable | 4.8.dev3 |
|---|---|---|
| No movement | 480 FPS (2.08 mspf) | 480 FPS (2.08 mspf) |
| ... | ||
| 과거에는 V-Sync가 비활성화된 테스트 케이스와 유사한 문제를 발견했습니다. 프레임률이 우리가 설정한 480 FPS 목표에 도달하지 못했습니다. 실제로, 가시 마우스 모드(Visible mouse mode)로 8 kHz에서 V-Sync를 활성화했을 때(173 FPS 대신 151 FPS) 더 낮았습니다. 프레임 시간 그래프에서는 육안으로 쉽게 알아챌 수 있는 프레임 시간 스파이크가 있었습니다: |
AI 자동 생성 콘텐츠
본 콘텐츠는 Godot Engine News의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기