노출 영역 객체는 화면에 표시하려는 이미지를 앱이 렌더링할 수 있게 해줍니다. SurfaceHolder 인터페이스는 앱이 노출 영역을 수정하고 제어할 수 있게 해줍니다.
노출 영역
노출 영역은 생산자가 소비자와 버퍼를 교환할 수 있는 인터페이스입니다.
디스플레이 노출 영역의 BufferQueue는 보통 삼중 버퍼링을 위해 구성됩니다. 버퍼는 요청 시 할당되므로 생산자가 충분히 느리게 버퍼를 생성한다면(예: 60fps 디스플레이에서 30fps로) 대기열에는 두 개의 버퍼만 할당되어 있을 것입니다.
버퍼를 요청 시에 할당하면 메모리 소모를 최소화하는 데 도움이 됩니다. dumpsys SurfaceFlinger
출력에서 모든 계층과 관련된 버퍼 요약을 확인할 수 있습니다.
대부분의 클라이언트는 OpenGL ES 또는 Vulkan을 사용하여 노출 영역에 렌더링됩니다. 하지만 일부 클라이언트는 캔버스를 사용하여 노출 영역에 렌더링됩니다.
캔버스 렌더링
캔버스 구현은 Skia 그래픽 라이브러리에서 제공합니다. 직사각형을 그리고 싶은 경우 적절히 버퍼에 바이트를 설정하는 Canvas API를 호출합니다. 2개의 클라이언트가 버퍼를 동시에 업데이트하거나 표시되는 도중에 버퍼에 작성하는 일이 없게 하려면 버퍼를 잠그고 액세스합니다. 캔버스 잠금을 사용하려면 다음 명령어를 사용하세요.
lockCanvas()
는 CPU에서 렌더링하기 위한 버퍼를 잠그고 그리기에 사용할 수 있도록 캔버스를 반환합니다.unlockCanvasAndPost()
는 버퍼를 잠금 해제하여 컴포지터로 전송합니다.lockHardwareCanvas()
는 GPU에서 렌더링하기 위한 버퍼를 잠그고 그리기에 사용할 수 있도록 캔버스를 반환합니다.
생산자가 BufferQueue에서 처음으로 버퍼를 요청하면 버퍼가 할당되어 0으로 초기화됩니다. 초기화는 실수로 프로세스 간의 데이터를 공유하는 상황을 피하는 데 필요합니다. 하지만 버퍼를 재사용하면 이전 콘텐츠가 계속해서 존재합니다. 아무것도 그리지 않고 lockCanvas()
및 unlockCanvasAndPost()
를 반복적으로 호출하면 생산자가 이전에 렌더링된 프레임 간에 순회합니다.
노출 영역 잠금/잠금 해제 코드는 이전에 렌더링된 버퍼 참조를 유지합니다. 노출 영역을 잠글 때 더티 영역을 지정하면 이전 버퍼의 비 더티 픽셀이 복사됩니다. SurfaceFlinger 또는 HWC는 일반적으로 버퍼를 처리하지만 버퍼에서만 읽으면 되므로 독점 액세스를 기다릴 필요는 없습니다.
SurfaceHolder
SurfaceHolder는 시스템이 노출 영역 소유권을 앱과 공유하기 위해 사용하는 인터페이스입니다. 노출 영역을 다루는 일부 클라이언트가 SurfaceHolder를 원하는 이유는 노출 영역 매개변수를 가져와 설정하기 위한 API가 SurfaceHolder를 통해 구현되기 때문입니다. SurfaceView에는 SurfaceHolder가 포함됩니다.
보기와 상호작용하는 대부분의 구성요소는 SurfaceHolder와 관련이 있습니다. MediaCodec 등의 몇몇 다른 API는 노출 영역 자체에서 작동합니다.