패드나 마우스는 그대로 두고 게임만 다른 걸 했을 뿐인데 한쪽에서만 두드러지게 입력이 훨씬 빠르게 느껴지는 경험을 한 적이 있으실텐데요. 정말로 그런 차이가 생기는 것이 맞는지 직접 실험을 해보았는데 직접 파이썬으로 30만 번 돌려보고 나니 “아 이래서 차이가 느껴졌구나.”라고 납득이 가더군요.
똑같이 1000Hz로 폴링되는 컨트롤러를 사용한다고 가정하더라도 게임이 그 입력을 30fps 렌더링 주기 안에서만 체크하면 평균 지연 시간이 17.1ms까지 연장됐고 144fps로 확인하면 3.9ms까지 감소했습니다. 컨트롤러는 완전히 같은데 게임 쪽 코드가 그 입력을 얼마나 자주 보고있느냐만으로 체감 반응 속도가 4배 넘게 차이가 난 것입니다.
폴링레이트는 하드웨어의 몫
폴링레이트는 마우스나 컨트롤러가 자기 상태를 컴퓨터에 얼마나 자주 전달하는지를 나타내는 값인데요. 마우스 가이드 사이트인 Blur Busters는 이를 구체적인 시간 단위로 설명하는데, 125Hz 폴링레이트를 사용하면 마우스는 8밀리초 간격으로 갱신된다고 밝히고 1000Hz 폴링을 사용하면 추가되는 지연은 1밀리초에 불과하다고 안내합니다.
다시 말해 폴링레이트가 높을 수록 하드웨어가 버튼 입력을 붙잡아 컴퓨터에 넘겨주기까지 걸리는 시간이 짧아진다는 말입니다. 중요한 것은 이 값이 순전히 장치 자체의 세팅이라는 점입니다. 같은 컨트롤러를 꽂아두면 어떤 게임을 실행하든 이 하드웨어 절차는 동일하게 작동합니다.
게임도 한 번 더 체크한다
문제는 하드웨어가 입력을 전달했다고 해서 게임이 그 순간 바로 반응하는 것이 아니라는 데에 있습니다. 유니티(Unity)의 공식 스크립팅 API 문서는 Input.GetkeyDown에 대해 “Update 함수에서 호출해야 한다, 상태가 매 프레임마다 초기화되기 때문이다.”라고 안내합니다. 즉 전통적인 입력 처리 방식은 렌더링 프레임 주기에 맞추어서만 입력 상태를 체크한다는 뜻입니다.
더 최근에 출시된 유니티의 새 Input System은 입력 이벤트마다 정확한 발생 시각을 타임스탬프로 남겨둡니다. 하지만 공식 매뉴얼조차 “이벤트가 게임의 플레이어 루프와는 보통 다른 빈도로 들어오기 때문에 실제 처리는 다음 Update 또는 FixedUpdate 직전에 이루어진다고 말합니다. 정밀한 타임스탬프가 있더라도 그 정보를 실제로 사용하는 코드는 결국에는 프레임 주기에 맞춰 오직 한 번만 확인한다는 이야기입니다. 결국 신호는 하드웨어 폴링 한 번, 게임 코드 확인 한 번, 이렇게 두 단계를 거쳐야 캐릭터를 움직인다고 말할 수 있습니다.
코드로 재현하기
이 두 단계 구조를 그대로 파이썬으로 재현해보는 시간을 가졌습니다. 모든 시나리오에서 컨트롤러의 하드웨어 폴링레이트는 1000Hz로 똑같이 고정하고 버튼을 누르는 시각은 무작위로 30만 번 만들었습니다. 먼저 하드웨어가 그 입력을 붙잡는 가장 가까운 폴링 시각을 계산한 뒤 게임 코드가 그 값을 언제 확인하는지에 따라 시나리오를 분리했습니다. 렌더링 프레임에 맞춰서만 확인하는 경우를 30fps, 60fps, 144fps로 각각 테스트했고 렌더링과는 관계없이 별도로 도는 고정 주기 업데이트도 테스트하였습니다. 이 고정 주기 값으로는 임의의 숫자가 아니라 유니티 엔진의 실제 기본 세팅값인 Fixed Timestep 0.02초, 다시 말해 50Hz를 그대로 이용하였습니다.
실험 결과를 검토해보면 하드웨어 폴링만 있었을 때의 평균 지연 시간은 0.5ms에 불과했습니다. 하지만 여기에 게임 쪽 확인 주기가 더해지자 숫자가 크게 달라졌습니다. 144fps 렌더링에서는 3.9ms, 60fps에서는 8.7ms, 30fps에서는 17.1ms까지 연장되었습니다.
이 실험 결과에서 흥미로운 점은 렌더링과 분리된 고정 50Hz 업데이트의 평균 지연시간이 10.1ms로 60fps 렌더링보다도 더 컸다는 부분입니다.

고정 주기가 항상 유리할까
여기서 “그럼 렌더링과 분리된 고정 주기로 입력을 확인하면 항상 더 유리한 거 아닌가?”라는 궁금증이 생길 수 있습니다.
하지만 방금 실험 결과가 보여주듯이 답은 그렇게 단순하지 않습니다. 고정 50Hz 업데이트는 렌더링 프레임 수가 흔들리더라도 지연 시간이 항상 일정하다는 장점은 있었습니다. 그러나 그 고정된 값 자체가 60fps나 144fps보다 느리게 세팅되어 있으면 오히려 손해입니다.
또한 이번 시뮬레이션은 순수하게 폴링 주기 사이의 시간 간격만 계산한 것에 그치지 않고 실제 환경에서는 운영 체제의 USB 드라이버 처리 지연, 디스플레이 자체의 응답 속도, 화면 출력 파이프라인의 더블 버퍼링같은 추가적인 지연 요소가 더 붙게 됩니다. 다시 말해 이번 실험 결과는 “게임 코드가 입력을 얼마나 확인하는지”라는 한 가지 변수만 따로 떼어낸 이론적인 하한선이지, 플레이어의 체감 지연 시간의 절대값이라고는 말할 수 없습니다.
장비 탓이기 전에 게임 코드의 문제일 수 있다
같은 컨트롤러를 꽂아 사용하더라도 반응 속도가 매번 다르게 체감되는 이유는 입력 신호가 하드웨어 폴링과 게임 코드 확인이라는 두 개의 독립된 관문을 통과해야 하기 때문이었습니다.
이번 실험에서 확인했듯이 둘 중 어느 쪽이든 느린 쪽이 전체 반응 속도의 발목을 잡게 됩니다. 결국 패드 상자가 마우스에 적힌 “1000Hz 폴링레이트”라는 숫자는 이야기의 절반일 뿐이었습니다. 나머지 절반은 그 신호를 받은 게임 코드가 얼마나 부지런히 확인하는지에 달려 있었고 이번 실험에서는 그 차이 하나만으로 지연 시간이 4배 넘게 벌어졌습니다.