← All reports

Backend handoff reworked for remote ImageBuffers

Component: WebKit GPU Process / Remote Rendering | 1a3eac1

가속 canvas와 WebGL 렌더링은 두 프로세스에 나뉘어 처리됩니다. WebProcess 쪽은 RemoteImageBufferProxy만 들고 있고, 실제 픽셀 backing store는 GPU process에 존재합니다. 이 backing store는 대체로 GPU가 뒷받침하는 IOSurface이며, RemoteRenderingBackend와 RemoteImageBuffer 뒤편에 자리합니다. 양쪽의 상태는 IPC로 동기화됩니다. 한편 IOSurface는 성능을 위해 pool에 담아 재사용하는 자원입니다. 그래서 어떤 code path든 살아 있는 reference를 붙들고 있으면 재사용이 막히는데, handle을 WebProcess로 전달하는 것도 여기에 해당합니다.

기존 동작을 먼저 보면, GPU process가 뒷받침하는 ImageBuffer는 생성될 때마다 backend handle을 WebProcess로 전달했습니다. 전달 수단은 비동기 DidCreateBackend 메시지였습니다. 이때 RemoteImageBufferProxy는 backend가 없는 상태로 출발했고, 해당 메시지가 도착할 때까지 backend에 의존하는 작업은 모두 대기 상태에 놓였습니다. 이번 commit은 이 handshake를 다른 방식으로 대체했습니다. backend는 생성 시점에 곧바로 만들어지고, 실제 handle은 호출자가 필요로 하는 순간에만 동기적으로 조회됩니다. 현재 그런 호출자는 PlaceholderRenderingContext와 view transition 두 군데뿐입니다.

  Before:                              After:
  create ImageBuffer                   create ImageBuffer
    └─► GPU: build backend               └─► GPU: build backend (eager)
          └─► async DidCreateBackend            proxy usable immediately
                └─► WebProcess gets handle
                      ▲ pins IOSurface     handle fetched synchronously
                        defeats pool       only by the two consumers
                      ▲ callers must       that need it
                        drain the message

buffer를 만들 때마다 handle을 WebProcess로 미리 전달하던 방식은 IOSurface를 계속 붙들어 두었고, 그 결과 IOSurfacePool이 무력화되었습니다. 가속 2D canvas에서 자기 자신을 대상으로 drawImage()를 반복하는 경우에는 할당과 해제가 계속 반복되는 현상까지 나타났습니다. 성능 측면의 개선만 있는 것은 아닙니다. 호출자가 명시적으로 비워내야 했던 비동기 IPC handshake 한 부류가 통째로 사라졌습니다. 객체는 존재하지만 아직 사용할 수 없는 상태를 두는 state machine은 순서 관련 버그가 반복해서 발생하는 지점인데, 여기서는 그런 상태 자체가 더 이상 남아 있지 않습니다.