비동기식 힌트를 사용한 짧은 지연 시간 렌더링

Joe Medley
Joe Medley

스타일러스 렌더링의 차이

웹용으로 빌드된 스타일러스 기반 그리기 애플리케이션은 웹페이지에서 그래픽 업데이트를 DOM과 동기화해야 하므로 오랜 시간 지연 문제가 있었습니다. 그리기 애플리케이션에서 지연 시간이 50밀리초를 초과하면 사용자의 손과 눈의 협응이 방해를 받아 애플리케이션을 사용하기 어려워질 수 있습니다.

canvas.getContext()desynchronized 힌트는 일반적인 DOM 업데이트 메커니즘을 우회하는 다른 코드 경로를 호출합니다. 대신 힌트는 기본 시스템에 최대한 많은 합성을 건너뛰라고 지시하며 경우에 따라 캔버스의 기본 버퍼가 화면의 디스플레이 컨트롤러로 직접 전송됩니다. 이렇게 하면 렌더러 컴포저이터 대기열을 사용할 때 발생하는 지연 시간이 제거됩니다.

마음에 드셨나요?

Sintel 동시 렌더링

코드로 이동하려면 앞으로 스크롤하세요. 작동하는 모습을 보려면 터치 스크린이 있는 기기와 스타일러스가 필요합니다. 손가락을 사용해도 됩니다. 있다면 2d 또는 webgl 샘플을 사용해 보세요. 이 기능을 구현한 엔지니어 중 한 명인 미구엘 카사스님의 데모를 확인해 보세요. 데모를 열고 재생을 누른 다음 슬라이더를 무작위로 빠르게 앞뒤로 이동합니다.

이 예에서는 Blender 오픈 영화 프로젝트인 Durian의 단편 영화 Sintel의 1분 21초 클립을 사용합니다. 이 예시에서 영화는 콘텐츠가 동시에 <canvas> 요소에 렌더링되는 <video> 요소에서 재생됩니다. 많은 기기에서 테어링 없이 이 작업을 실행할 수 있지만, 예를 들어 ChromeOS와 같이 전면 버퍼 렌더링이 있는 기기에서는 테어링이 발생할 수 있습니다. (영화는 훌륭하지만 가슴 아픈 내용입니다. 그걸 본 후 한 시간 동안은 아무것도 할 수 없었습니다. 나는 분명히 경고했어.)

힌트 사용

canvas.getContext()desynchronized를 추가하는 것보다 짧은 지연 시간을 사용하는 데는 더 많은 것이 있습니다. 문제를 하나씩 살펴보겠습니다.

캔버스 만들기

다른 API에서는 먼저 기능 감지를 설명하겠습니다. desynchronized 힌트의 경우 먼저 캔버스를 만들어야 합니다. canvas.getContext()를 호출하고 값이 true인 새 desynchronized 힌트를 전달합니다.

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('2d', {
  desynchronized: true,
  // Other options. See below.
});

기능 감지

그런 다음 getContextAttributes()를 호출합니다. 반환된 속성 객체에 desynchronized 속성이 있으면 테스트합니다.

if (ctx.getContextAttributes().desynchronized) {
  console.log('Low latency canvas supported. Yay!');
} else {
  console.log('Low latency canvas not supported. Boo!');
}

깜박임 방지

코딩을 올바르게 하지 않으면 플리커링이 발생할 수 있는 두 가지 경우가 있습니다.

Chrome을 비롯한 일부 브라우저는 프레임 간에 WebGL 캔버스를 지웁니다. 디스플레이 컨트롤러가 버퍼가 비어 있는 동안 버퍼를 읽어 이미지가 깜박이게 할 수 있습니다. 이를 방지하려면 preserveDrawingBuffertrue로 설정합니다.

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('webgl', {
  desynchronized: true,
  preserveDrawingBuffer: true
});

자체 그리기 코드에서 화면 컨텍스트를 지울 때도 플리커링이 발생할 수 있습니다. 지워야 하는 경우 오프스크린 프레임버퍼에 그린 다음 화면에 복사합니다.

알파 채널

알파가 true로 설정된 반투명 캔버스 요소는 여전히 동기화 해제할 수 있지만 그 위에 다른 DOM 요소가 없어야 합니다.

하나만 있을 수 있음

canvas.getContext()를 처음 호출한 후에는 컨텍스트 속성을 변경할 수 없습니다. 이는 항상 사실이었지만, 모르거나 잊어버린 경우 반복해서 알려 드리면 불편을 덜 수 있습니다 .

예를 들어 컨텍스트를 가져와서 알파를 false로 지정한 다음 코드의 뒷부분에서 아래와 같이 알파를 true로 설정하여 canvas.getContext()를 두 번째로 호출한다고 가정해 보겠습니다.

const canvas = document.querySelector('myCanvas');
const ctx1 = canvas.getContext('2d', {
  alpha: false,
  desynchronized: true,
});

//Some time later, in another corner of code.
const ctx2 = canvas.getContext('2d', {
  alpha: true,
  desynchronized: true,
});

ctx1ctx2가 동일한 객체라는 것은 분명하지 않습니다. 알파는 여전히 false이며 알파가 true인 컨텍스트는 생성되지 않습니다.

지원되는 캔버스 유형

getContext()에 전달되는 첫 번째 매개변수는 contextType입니다. 이미 getContext()에 익숙한 경우 '2d' 컨텍스트 유형 외에도 지원되는 유형이 있는지 궁금할 것입니다. 아래 표에는 desynchronized를 지원하는 컨텍스트 유형이 나와 있습니다.

contextType 컨텍스트 유형 객체

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

결론

더 많은 샘플을 확인하려면 샘플을 확인하세요. 이미 설명된 동영상 예 외에도 '2d''webgl' 컨텍스트를 모두 보여주는 예시가 있습니다.