WebGL drawCall의 프레임 지연 원인

오유찬·2025년 4월 20일
post-thumbnail

이전글인 1프레임 안에서 일어나는 일 이후를 다루고 있습니다.

🎯 요약

  • WebGL의 drawCall은 GPU에 비동기로 전달되며, 완료 여부를 즉시 알 수 없습니다.
  • gl.finish()는 GPU 작업 완료를 보장하지 않고, 일부 구현에서는 명령이 큐에 들어간 것만 확인하고 리턴한다.
  • 때때로 drawCall이 Commit 이후로 밀리게 되어 다음 프레임에 반영될 수 있습니다
  • GPU가 이전 프레임 작업을 끝내지 못하면 브라우저는 다음 프레임 생성을 지연시킨다.

1. drawCall은 명령을 GPU 큐에 넣는 것

WebGL에서 gl.drawArrays() 또는 gl.drawElements() 같은 명령을 호출하면, 명령은 GPU의 커맨드 큐 에 쌓일 뿐, 실제로 GPU가 바로 실행하는 것이 아닙니다.
대부분의 WebGL 명령은 비동기 처리 가 기본이기 때문에, 명령이 큐에 추가되는 것만 확인되고 바로 GPU에서 실행되지는 않습니다.


2. gl.finish()는 GPU 완료를 보장하지 않는다

gl.finish()는 "GPU의 모든 작업이 완료될 때까지 기다리는 함수"로 정의되어 있지만, 실제로는 브라우저의 구현체에 따라 다르게 동작합니다. 특히 Chromium 엔진에서 사용되는 ANGLE와 D3D/Metal에서는, gl.finish()가 GPU 작업이 큐에 들어간 것만 확인 하고 리턴할 수 있습니다.

따라서 gl.finish()는 GPU가 실제로 연산을 마쳤는지를 보장하지 않으며, GPU의 작업이 여전히 진행 중일 수 있습니다. 정확한 GPU 동기화가 필요하다면 WebGL2의 gl.fenceSync() + clientWaitSync() 조합을 사용하는 것이 더 안전합니다.


3. WebWorker 사용 시 drawCall 지연 발생 구조

WebGL을 WebWorker에서 사용하는 경우, 메인 스레드와 GPU의 작업 처리 순서 타이밍이 엇갈릴 수 있습니다.

0.0ms: [MainThread] pointerEvent 발생 → WebWorker에 draw 요청
0.5ms: [WorkerThread] drawCall을 GPU에 전달
2.0ms: [MainThread] 브라우저가 Commit을 통해 렌더링 트리 전송
2.5ms: [WorkerThread] GPU 드로우 명령 전달 완료

이 시나리오에서는 drawCall이 Commit 이후에 발생했기 때문에, 현재 VSync에는 반영되지 않고 다음 프레임으로 밀릴 가능성이 있습니다.

참고: commit단계에서 composite가 일어나는데, 이때 webgl 프레임버퍼 에서 픽셀값을 읽어옵니다.

commit이전에 drawCall이 되었다면

하지만, commit 이전에 drawCall이 발생되었을 경우에도, 1프레임 늦게 화면에 반영되는 경우도 생깁니다.

ex) css보다 늦게 반영되는 canvas2d나 webgl의 drawCall

이는 더블버퍼링 또는 브라우저 내부의 우선순위가 작용해서 이런 현상이 나타나는 것으로 추측되지만, 확실한 이유는 크롬 엔진 코드를 읽어봐야 알 것 같습니다 😢

4. GPU가 병목일 때 브라우저는 프레임 생성을 의도적으로 막는다

브라우저의 렌더링 파이프라인은 VSync 타이밍에 맞춰 동작합니다.

하지만 이때 GPU가 아직 이전 프레임의 Composite 작업을 끝내지 못했다면, 브라우저는 BeginMainFrame 자체를 스킵할 수 있습니다.

이것이 gpu에게 무거운 작업을 요청하면 프레임 드랍이 생기는 이유입니다.

출처:
https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/finish
https://chromium.googlesource.com/chromium/src/%2B/112.0.5615.165/docs/life_of_a_frame.md

profile
대학생 개발자

3개의 댓글

comment-user-thumbnail
2025년 7월 25일

안녕하세요, 하늘 인편 보고 댓글 남깁니다!! 병 858기로 입대해서 하늘 인편을 통해 처음이자 마지막으로 받았던 인편을 줄곧 감상하곤 있는데 이젠 접속이 안 되는 거 같아서요!! 혹시 서버는 폐기 처리 하신 걸까요..? 더 이상 인편을 볼 수 없는 거 같아 아쉽네요 ㅜㅜ

1개의 답글