디스플레이 노출 영역의 BufferQueue는 보통 삼중 버퍼링을 위해 구성됩니다. 버퍼는 요청 시 할당되므로 생산자가 충분히 느리게 버퍼를 생성한다면(예: 60fps 디스플레이에서 30fps로) 대기열에는 두 개의 버퍼만 할당되어 있을 것입니다.
버퍼를 요청 시에 할당하면 메모리 소모를 최소화하는 데 도움이 됩니다. dumpsys SurfaceFlinger 출력에서 모든 계층과 관련된 버퍼 요약을 확인할 수 있습니다.
대부분의 클라이언트는 OpenGL ES 또는 Vulkan을 사용하여 노출 영역에 렌더링됩니다. 하지만 일부 클라이언트는 캔버스를 사용하여 노출 영역에 렌더링됩니다.
캔버스 렌더링
캔버스 구현은 Skia 그래픽 라이브러리에서 제공합니다.
직사각형을 그리고 싶은 경우 적절히 버퍼에 바이트를 설정하는 Canvas API를 호출합니다. 2개의 클라이언트가 버퍼를 동시에 업데이트하거나 표시되는 도중에 버퍼에 작성하는 일이 없게 하려면 버퍼를 잠그고 액세스합니다. 캔버스 잠금을 사용하려면 다음 명령어를 사용하세요.
lockCanvas()는 CPU에서 렌더링하기 위한 버퍼를 잠그고 그리기에 사용할 수 있도록 캔버스를 반환합니다.
생산자가 BufferQueue에서 처음으로 버퍼를 요청하면 버퍼가 할당되어 0으로 초기화됩니다. 초기화는 실수로 프로세스 간의 데이터를 공유하는 상황을 피하는 데 필요합니다. 하지만 버퍼를 재사용하면 이전 콘텐츠가 계속해서 존재합니다. 아무것도 그리지 않고 lockCanvas() 및 unlockCanvasAndPost()를 반복적으로 호출하면 생산자가 이전에 렌더링된 프레임 간에 순회합니다.
노출 영역 잠금/잠금 해제 코드는 이전에 렌더링된 버퍼 참조를 유지합니다. 노출 영역을 잠글 때 더티 영역을 지정하면 이전 버퍼의 비 더티 픽셀이 복사됩니다. SurfaceFlinger 또는 HWC는 일반적으로 버퍼를 처리하지만 버퍼에서만 읽으면 되므로 독점 액세스를 기다릴 필요는 없습니다.
SurfaceHolder
SurfaceHolder는 시스템이 노출 영역 소유권을 앱과 공유하기 위해 사용하는 인터페이스입니다. 노출 영역을 다루는 일부 클라이언트가 SurfaceHolder를 원하는 이유는 노출 영역 매개변수를 가져와 설정하기 위한 API가 SurfaceHolder를 통해 구현되기 때문입니다. SurfaceView에는 SurfaceHolder가 포함됩니다.
보기와 상호작용하는 대부분의 구성요소는 SurfaceHolder와 관련이 있습니다.
MediaCodec 등의 몇몇 다른 API는 노출 영역 자체에서 작동합니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-27(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-07-27(UTC)"],[],[],null,["# Surface and SurfaceHolder\n\nSurface objects enable apps to render images to be presented on screens.\nSurfaceHolder interfaces enable apps to edit and control surfaces.\n\nSurface\n-------\n\nA [surface](https://developer.android.com/reference/android/view/Surface.html) is an interface for a producer to exchange buffers\nwith a consumer.\n\nThe BufferQueue for a display surface is typically configured for\ntriple-buffering. Buffers are allocated on demand, so if the producer\ngenerates buffers slowly enough, such as at 30 fps on a 60 fps\ndisplay, there might only be two allocated buffers in the queue.\nAllocating buffers on demand helps\nminimize memory consumption. You can see a summary of the buffers associated\nwith every layer in the `dumpsys SurfaceFlinger` output.\n\nMost clients render onto surfaces using [OpenGL ES](/docs/core/graphics/arch-egl-opengl) or [Vulkan](/docs/core/graphics/arch-vulkan). However, some clients render\nonto surfaces using a canvas.\n\n\n### Canvas rendering\n\nThe canvas implementation is provided by the\n[Skia Graphics Library](https://skia.org/).\nIf you want to draw a rectangle, you call the Canvas API, which sets bytes in a\nbuffer appropriately. To ensure that a buffer isn't updated by two clients at\nonce, or written to while being displayed, lock the buffer to access\nit. Use the following commands to work with canvas locks:\n\n- [`lockCanvas()`](https://developer.android.com/reference/android/view/Surface.html#lockCanvas(android.graphics.Rect)) locks the buffer for rendering on the CPU and returns a Canvas to use for drawing.\n- [`unlockCanvasAndPost()`](https://developer.android.com/reference/android/view/Surface.html#unlockCanvasAndPost(android.graphics.Canvas)) unlocks the buffer and sends it to the compositor.\n- [`lockHardwareCanvas()`](https://developer.android.com/reference/android/view/Surface.html#lockHardwareCanvas()) locks the buffer for rendering on the GPU and returns a canvas to use for drawing.\n\n| **Note:** The canvas obtained when an app locks a surface with `lockCanvas()` is never hardware accelerated.\n| **Caution:** You can't draw on a surface with GLES or send it frames from a video decoder if you've ever called `lockCanvas()`. `lockCanvas()` connects the CPU renderer to the producer side of the BufferQueue and doesn't disconnect until the surface is destroyed. The canvas-based CPU renderer can't be disconnected and reconnected to a surface, unlike most producers (like GLES or Vulkan).\n\nThe first time the producer requests a buffer from a BufferQueue, the\nbuffer is\nallocated and initialized to zero. Initialization is necessary to avoid\ninadvertently sharing data between processes. However, if you reuse a buffer,\nthe previous contents are still present. If you repeatedly call\n`lockCanvas()` and `unlockCanvasAndPost()` without\ndrawing anything, the producer cycles between previously rendered frames.\n\nThe surface lock/unlock code keeps a reference to the previously rendered\nbuffer. If you specify a dirty region when locking the surface, it copies\nthe nondirty pixels from the previous buffer. SurfaceFlinger or HWC typically\nhandle the buffer; but because we only need to read from\nthe buffer, there's no need to wait for exclusive access.\n\nSurfaceHolder\n-------------\n\nA [SurfaceHolder](https://developer.android.com/reference/android/view/SurfaceHolder.html) is an interface the system uses to share ownership of\nsurfaces with apps. Some clients that work with surfaces want a SurfaceHolder,\nbecause APIs to get and set surface parameters are implemented through a\nSurfaceHolder. A [SurfaceView](/docs/core/graphics/arch-sv-glsv) contains\na SurfaceHolder.\n\nMost components that interact with a view involve a SurfaceHolder.\nSome other APIs, such as MediaCodec, operate on the surface itself."]]