RenderScript에서 이전하기

RenderScript API는 Android 12부터 지원 중단됩니다. 계속 작동하지만 기기 및 구성요소 제조업체는 시간이 지남에 따라 하드웨어 가속 지원을 더 이상 제공하지 않을 것으로 예상됩니다. GPU 가속을 최대한 활용하려면 스크립트를 Vulkan으로 이전하거나 대체 도구 키트를 사용하여 내장 기능에서 이전하는 것이 좋습니다.

내장 기능에서 이전하기

RenderScript 내장 기능은 RenderScript를 지원 중단한 후에도 계속 작동하지만 GPU가 아닌 CPU에서만 실행할 수 있습니다.

애플리케이션에서 내장 기능을 사용하는 경우 독립형 대체 라이브러리를 사용할 수 있습니다. 테스트 결과 기존 RenderScript CPU 구현을 사용하는 것보다 더 빠릅니다.

도구 키트에는 다음 기능이 포함됩니다.

  • 혼합
  • 흐리게 처리
  • 색상 매트릭스
  • 컨볼브
  • 히스토그램 및 histogramDot
  • 참고표(LUT) 및 LUT 3D
  • 크기 조절
  • YUV를 RGB로

자세한 내용 및 제한 사항은 도구 키트의 README.mdToolkit.kt 파일을 참고하세요.

다음 단계에 따라 라이브러리를 다운로드하고 추가하고 사용합니다.

  1. GitHub에서 프로젝트를 다운로드합니다.

  2. renderscript-toolkit module을 찾아서 빌드합니다.

  3. 앱의 build.gradle 파일을 수정하여 Android 스튜디오 프로젝트에 라이브러리를 추가합니다.

  4. 도구 키트의 적절한 메서드를 호출합니다.

예: ScriptIntrinsicBlur 함수에서 이전하기

ScriptIntrinsicBlur 함수를 바꾸려면 다음을 따릅니다.

  • 비트맵을 흐리게 처리하려면 Toolkit.blur를 호출합니다.

    var blurredBitmap = Toolkit.blur(myBitmap, radius)
    
  • 바이트 배열로 표현된 이미지를 흐리게 처리하려면 너비, 높이, 픽셀당 바이트 수를 지정합니다.

    val outArray = Toolkit.blur(inputArray, bytesPerPixel, width, height, radius)
    

Android 12(API 수준 31) 이상을 타겟팅하는 경우 Toolkit.blur() 대신 RenderEffect 클래스를 사용하는 것이 좋습니다.

스크립트에서 이전하기

GPU 가속을 최대한 활용하려면 RenderScript 스크립트를 크로스 플랫폼 Vulkan API로 이전하는 것이 좋습니다. 스크립트는 이전하지 않더라도 계속 실행되지만 드라이버 가용성에 따라 GPU 대신 CPU에서 실행될 수 있습니다.

기능을 이전하는 방법을 더 자세히 알아보려면 샘플 앱을 검토하세요. 이 샘플은 RenderScript에서 비트맵을 흐리게 처리하고 색상-매트릭스 변환을 처리하는 방법을 보여주며 Vulkan에서 상응하는 코드를 제공합니다.

다양한 버전을 지원해야 하는 애플리케이션의 경우 Android 9(API 수준 28) 이하를 실행하는 기기에는 RenderScript를 사용하고 Android 10(API 수준 29) 이상의 기기에는 Vulkan을 사용하세요.

Vulkan은 Kotlin 또는 자바 API를 제공하지 않으므로 RenderScript에서 Vulkan으로 직접적으로 매핑되지는 않습니다. Kotlin이나 자바에서 이 코드에 액세스하려면 NDK를 사용하여 Vulkan 코드를 작성하고 JNI 함수를 만들어야 합니다.

다음 섹션에서는 RenderScript에서 이전하는 측면을 다룹니다. 샘플 앱에는 이러한 고려사항이 모두 구현되어 있습니다. 이해를 돕기 위해 RenderScript와 Vulkan의 상응 코드를 비교합니다.

초기화

Kotlin이나 자바에서 RenderScript 컨텍스트 객체를 만드는 대신 다음 단계에 따라 NDK로 Vulkan 컨텍스트를 만듭니다.

  1. Vulkan 인스턴스를 만듭니다.

  2. 컴퓨팅 큐를 지원하는 Vulkan 실제 기기를 선택합니다.

  3. Vulkan 논리 기기를 만들고 컴퓨팅 큐를 가져옵니다.

원하는 경우 Android에서 Vulkan 유효성 검사 계층을 설정하여 Vulkan 애플리케이션 개발 속도를 높일 수 있습니다.

샘플 앱은 VulkanContext.h에서 Vulkan 컨텍스트를 초기화하는 방법을 보여줍니다. 자세한 내용은 Vulkan 사양의 초기화기기 및 큐 섹션을 참고하세요.

할당

RenderScript 할당을 Vulkan 스토리지 이미지 또는 Vulkan 스토리지 버퍼로 이전할 수 있습니다. 읽기 전용 이미지의 성능을 높이려면 가져오기 작업이 포함된 샘플 이미지를 통합 이미지 샘플러로 사용하거나 고유한 샘플러샘플 이미지의 결합을 통해 사용할 수 있습니다.

Vulkan 리소스는 Vulkan 내에서 할당됩니다. 다른 Android 구성요소와 상호작용할 때 메모리 복사 오버헤드가 발생하지 않도록 하려면 VK_ANDROID_external_memory_android_hardware_buffer 확장 프로그램을 사용하여 Android AHardwareBuffer를 가져와야 합니다. 이 확장 프로그램은 Vulkan 1.1을 지원하는 모든 Android 기기에서 사용할 수 있습니다. 자세한 내용은 FEATURE_VULKAN_HARDWARE_VERSION을 참고하세요.

샘플 앱은 VulkanResources.h에서 Vulkan 리소스를 만드는 방법을 보여줍니다. 자세한 내용은 Vulkan 사양의 리소스 만들기리소스 설명어 섹션을 참고하세요.

스크립트

RenderScript 스크립트는 Vulkan 컴퓨팅 셰이더로 변환해야 합니다. RenderScript 전역 변수 사용에 따라 코드를 조정해야 할 수도 있습니다.

Vulkan 컴퓨팅 셰이더 쓰기

Vulkan 컴퓨팅 셰이더는 일반적으로 GLSL(OpenGL Shading Language)로 작성되며 SPIR-V(Standard Portable Intermediate Representation-V) 형식으로 작성됩니다.

셰이더를 앱에 통합하는 방법에 관한 자세한 내용과 안내는 Android의 Vulkan 셰이더 컴파일러를 참고하세요.

스크립트 전역 변수 조정

스크립트 전역 변수의 특성에 따라 셰이더 내에서 수정되지 않는 전역 변수의 특수 상수, 푸시 상수, 균일 버퍼 객체를 사용하는 것이 좋습니다.

  • 특수 상수: 커널 호출 전반에서 거의 일관된 스크립트 전역 변수에 권장됩니다. 특수 상수의 값을 변경하면 컴퓨팅 파이프라인을 다시 만들어야 합니다.
  • 푸시 상수: maxPushConstantsSize보다 작으며(최소 보장 크기: 128바이트) 변경 빈도가 큰 스크립트 전역 변수에 권장됩니다.
  • 균일 버퍼: 푸시 상수 한도보다 크며 변경 빈도가 큰 스크립트 전역 변수에 권장됩니다.

셰이더 내에서 변경되는 전역 변수의 경우 Vulkan 스토리지 이미지 또는 Vulkan 스토리지 버퍼를 사용할 수 있습니다.

계산

GPU가 컴퓨팅 셰이더를 실행하려면 Vulkan 컴퓨팅 파이프라인을 만들어야 합니다.

Vulkan 컴퓨팅 파이프라인 만들기

샘플 앱의 ComputePipeline.h 파일은 Vulkan 컴퓨팅 파이프라인을 만드는 방법을 보여줍니다.

Vulkan에서 컴파일된 SPIR-V 셰이더를 사용하려면 Vulkan 컴퓨팅 파이프라인을 다음과 같이 구성합니다.

  1. 컴파일된 SPIR-V 셰이더로 셰이더 모듈을 만듭니다.
  2. 리소스 결합을 지정하는 설명어 집합 레이아웃을 만듭니다(자세한 내용은 할당 참고).
  3. 설명어 집합 레이아웃에서 설명어 집합을 만듭니다.
  4. 설명어 집합 레이아웃에서 파이프라인 레이아웃을 만듭니다.
  5. 셰이더 모듈과 파이프라인 레이아웃을 사용하여 컴퓨팅 파이프라인을 만듭니다.

자세한 내용은 Vulkan 사양의 컴퓨팅 파이프라인 섹션을 참고하세요.

계산 시작하기

컴퓨팅 파이프라인을 사용하여 계산을 시작하려면 다음을 따릅니다.

  1. Vulkan 리소스로 설명어 집합을 업데이트합니다.
  2. Vulkan 명령어 버퍼를 만들고 다음 명령어를 기록합니다.
    1. 파이프라인과 설명어 집합을 결합합니다.
    2. 컴퓨팅 작업 그룹을 전달합니다.
  3. 명령어 버퍼를 컴퓨팅 큐에 제출합니다.
  4. 큐에서 대기하거나 선택적으로 동기화 펜스를 반환합니다.

여러 커널을 함께 연결하려면(예: ScriptGroup을 사용하여 코드 이전하기) 단일 명령어 버퍼에 기록하고 메모리 배리어와 동기화합니다.

샘플 앱은 두 가지 컴퓨팅 작업을 보여줍니다.

  • HCE 회전: 단일 컴퓨팅 셰이더가 있는 간단한 컴퓨팅 작업. 코드 샘플은 ImageProcessor::rotateHue를 참고하세요.
  • 흐리게 처리: 컴퓨팅 셰이더 두 개를 순차적으로 실행하는 더 복잡한 컴퓨팅 작업입니다. 코드 샘플은 ImageProcessor::blur를 참고하세요.

명령어 버퍼 또는 메모리 배리어에 관한 자세한 내용은 Vulkan 사양의 명령어 버퍼메모리 배리어 섹션을 참고하세요.