이전글인 1프레임 안에서 일어나는 일 이후를 다루고 있습니다.
gl.finish()는 GPU 작업 완료를 보장하지 않고, 일부 구현에서는 명령이 큐에 들어간 것만 확인하고 리턴한다.Commit 이후로 밀리게 되어 다음 프레임에 반영될 수 있습니다WebGL에서 gl.drawArrays() 또는 gl.drawElements() 같은 명령을 호출하면, 명령은 GPU의 커맨드 큐 에 쌓일 뿐, 실제로 GPU가 바로 실행하는 것이 아닙니다.
대부분의 WebGL 명령은 비동기 처리 가 기본이기 때문에, 명령이 큐에 추가되는 것만 확인되고 바로 GPU에서 실행되지는 않습니다.
gl.finish()는 "GPU의 모든 작업이 완료될 때까지 기다리는 함수"로 정의되어 있지만, 실제로는 브라우저의 구현체에 따라 다르게 동작합니다. 특히 Chromium 엔진에서 사용되는 ANGLE와 D3D/Metal에서는, gl.finish()가 GPU 작업이 큐에 들어간 것만 확인 하고 리턴할 수 있습니다.
따라서 gl.finish()는 GPU가 실제로 연산을 마쳤는지를 보장하지 않으며, GPU의 작업이 여전히 진행 중일 수 있습니다. 정확한 GPU 동기화가 필요하다면 WebGL2의 gl.fenceSync() + clientWaitSync() 조합을 사용하는 것이 더 안전합니다.
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이 발생되었을 경우에도, 1프레임 늦게 화면에 반영되는 경우도 생깁니다.
ex) css보다 늦게 반영되는 canvas2d나 webgl의
drawCall
이는 더블버퍼링 또는 브라우저 내부의 우선순위가 작용해서 이런 현상이 나타나는 것으로 추측되지만, 확실한 이유는 크롬 엔진 코드를 읽어봐야 알 것 같습니다 😢
브라우저의 렌더링 파이프라인은 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
안녕하세요, 하늘 인편 보고 댓글 남깁니다!! 병 858기로 입대해서 하늘 인편을 통해 처음이자 마지막으로 받았던 인편을 줄곧 감상하곤 있는데 이젠 접속이 안 되는 거 같아서요!! 혹시 서버는 폐기 처리 하신 걸까요..? 더 이상 인편을 볼 수 없는 거 같아 아쉽네요 ㅜㅜ