Thêm định dạng pixel mới vào Android

Tất cả các định dạng pixel mới được thêm vào Android phải được bao gồm trong Ngôn ngữ định nghĩa giao diện Android (AIDL) và trong Vùng đệm phần cứng Android (AHB). AIDL và AHB có các yêu cầu nghiêm ngặt về độ ổn định và chuẩn hoá, đòi hỏi một quy trình cẩn thận khi mở rộng chức năng. Tất cả các định dạng pixel mới phải có trong AOSP (Dự án nguồn mở Android) đồng thời mọi nội dung cập nhật đều phải được các chuyên gia AIDL và AHB xác nhận riêng. Đây là quá trình xem xét kỹ là một yếu tố quan trọng trong việc chuẩn hoá bất kỳ định dạng pixel mới nào trên chủ.

Trang này trình bày AOSP cần thiết thay đổi mã và quy trình cần thiết để thêm định dạng pixel mới trên AOSP.

Trước khi thêm định dạng pixel mới, hãy tải xuống nguồn và tải bản vá lên như được nêu trong Gửi bản vá.

Thêm định dạng pixel mới vào AIDL

Để thêm tính năng hỗ trợ cho một định dạng pixel mới, bạn cần thay đổi cả hai tệp PixelFormat.aidl nằm trong AIDL. Xem hardware/interfaces/graphics/common/aidl/ cho mã nguồn AIDL.

Để thêm một pixel mới vào AIDL, hãy làm theo các bước sau:

  1. Thêm định dạng pixel mới dưới dạng một mục mới vào cuối enum PixelFormat trong PixelFormat.aidl bằng cách làm theo quy ước mã hiện có và đặt giá trị hex cho mục nhập của bạn là một so với mục nhập trước đó. So khớp các thay đổi về mã với các mục nhập trước đó. Hãy xem ví dụ sau đây về mục nhập định dạng pixel RGBA_8888:
    /**
     * 32-bit format that has 8-bit R, G, B, and A components, in that order,
     * from the lowest memory address to the highest memory address.
     *
     * The component values are unsigned normalized to the range [0, 1], whose
     * interpretation is defined by the dataspace.
     */
    RGBA_8888 = 0x1,
    

    Bạn sẽ thấy thông báo lỗi sau đây khi tạo mã sau khi thực hiện các thay đổi đối với PixelFormat.aidl:

    android_developer:~/android/aosp-android-latest-release: m
    ...
    ###############################################################################
    # ERROR: AIDL API change detected                                             #
    ###############################################################################
    Above AIDL file(s) has changed. Run `m android.hardware.graphics.common-update-api` to reflect the changes
    to the current version so that it is reviewed by
    android-aidl-api-council@google.com
    And then you need to change dependency on android.hardware.graphics.common-V(n)-* to android.hardware.graphics.common-V(n+1)-* to use
    new APIs.
    
  2. Để xoá lỗi này, hãy chạy lệnh sau, như được chỉ định trong thông báo lỗi, để thay đổi PixelFormat.aidl trong thư mục aidl_api:

    m android.hardware.graphics.common-update-api
    

    Việc chạy lệnh trên sẽ cập nhật đúng tệp để có thể tạo bản dựng bình thường.

Thêm định dạng pixel mới vào AHB

Để thêm tính năng hỗ trợ cho định dạng pixel mới, bạn phải thay đổi thành hardware_buffer.hAHardwareBuffer.cpp. Xem frameworks/native/libs/nativewindow cho mã nguồn AHB.

Để thêm một pixel mới vào AHB, hãy làm theo các bước sau:

  1. Trong hardware_buffer.h, hãy thêm định dạng pixel mới dưới dạng một mục mới vào cuối enum AHardwareBuffer_Format. Tuân theo các quy ước mã hiện có.

    Sử dụng ví dụ về định dạng pixel RGBA_8888, hãy thêm mục nhập định dạng pixel mới như sau:

    /**
     * Corresponding formats:
     *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
     *   OpenGL ES: GL_RGBA8
     */
    AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1,
    

    Xin lưu ý rằng định dạng pixel mới được đặt tên trong AHB, tên này phải bắt đầu bằng AHARDWAREBUFFER_FORMAT_, theo sau là các chữ viết tắt của kênh và độ sâu bit, rồi kết thúc bằng mã hoá. Mục nhập enum này phải có giá trị thập lục phân giống như giá trị trong PixelFormat.aidl.

    Định dạng pixel dự kiến sẽ có một hoặc cả hai định dạng Vulkan hoặc OpenGL ES liên kết. Chỉ định định dạng được liên kết khi thích hợp. Nếu không có định dạng được liên kết nào, hãy chỉ định N/A.

  2. Thêm định dạng pixel vào quy trình kiểm thử không bắt buộc trong CTS, nếu định dạng đó có liên kết với định dạng OpenGL ES. Để thực hiện việc này, hãy thêm định dạng GL mới vào AHardwareBufferGLTest.cpp trong AHBFormatAsString(int32_t format) với FORMAT_CASE(...)GL_FORMAT_CASE(...) cho định dạng mới, được minh hoạ như sau:

    const char* AHBFormatAsString(int32_t format) {
      switch (format) {
          ...
          FORMAT_CASE(R8G8B8A8_UNORM);
          ...
          GL_FORMAT_CASE(GL_RGB8);
      }
      return "";
    }
    
  3. Tiếp theo, hãy thêm một kiểm thử mới vào AHardwareBufferGLTest.cpp, như sau:

    class RGBA8Test : public AHardwareBufferGLTest {};
    
    // Verify that if we can allocate an RGBA8 AHB we can render to it.
    TEST_P(RGBA8Test, Write) {
        AHardwareBuffer_Desc desc = GetParam();
        desc.usage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
        if (!SetUpBuffer(desc)) {
            return;
        }
    
        ASSERT_NO_FATAL_FAILURE(SetUpFramebuffer(desc.width, desc.height, 0, kBufferAsRenderbuffer));
        ASSERT_NO_FATAL_FAILURE(
            SetUpProgram(kVertexShader, kColorFragmentShader, kPyramidPositions, 0.5f));
    
        glDrawArrays(GL_TRIANGLES, 0, kPyramidVertexCount);
        ASSERT_EQ(GLenum{GL_NO_ERROR}, glGetError());
    }
    
    INSTANTIATE_TEST_CASE_P(
        SingleLayer, RGBA8Test,
        ::testing::Values(
            AHardwareBuffer_Desc{57, 33, 1, AHARDWAREBUFFER_FORMAT_R16G16_UINT, 0, 0, 0, 0}),
        &GetTestName);
    

    Hãy chỉ định ít nhất một nhóm giá trị AHardwareBuffer_Desc. Thêm các giá trị khác nếu cần.

  4. Trong AHardwareBuffer.cpp, hãy tìm phần cuối của các xác nhận tĩnh có trong:

    // ----------------------------------------------------------------------------
    // Validate hardware_buffer.h and PixelFormat.aidl agree
    // ----------------------------------------------------------------------------
    

    Thêm static_assert mới cho định dạng pixel mới, sử dụng phương thức enum PixelFormat:: chứ không phải với hằng số HAL_PIXEL_FORMAT. Sử dụng cùng một ví dụ cho định dạng pixel RGBA_8888 từ phần Thêm định dạng pixel mới vào AIDL, thêm mục nhập định dạng pixel mới như sau:

    static_assert(static_cast(aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888) ==
      AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
    "HAL and AHardwareBuffer pixel format don't match");
    
  5. Thêm định dạng pixel mới vào các bài kiểm thử thích hợp bằng cách thêm định dạng pixel mới vào cuối PrintAhbFormat() trong AHardwareBufferTest.cpp. Tuân theo quy ước mã hiện có, như minh hoạ dưới đây:

    void PrintAhbFormat(std::ostream& os, uint64_t format) {
        switch (format) {
            ...
            FORMAT_CASE(R8G8B8A8_UNORM);
            default: os << "unknown"; break;
        }
    }
    
  6. Thêm định dạng pixel mới vào SDK HardwareBuffer trong HardwareBuffer.java: bằng cách thêm một mục mới vào @IntDef. Ví dụ: mục nhập cho Định dạng RGBA_8888 được hiển thị như sau:

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = { "RGB", "BLOB", "YCBCR_", "D_", "DS_", "S_" }, value = {
      ...
      RGBA_8888,
    })
    

    Nếu giá trị thành phần không được chuẩn hoá chưa ký, hãy chỉ định giá trị một cách rõ ràng trong tên biến. Ví dụ: tên biến cho định dạng chỉ kênh màu đỏ 16 bit số nguyên chưa ký phải là R_16UI và cùng định dạng với định dạng kênh màu xanh lục 16 bit số nguyên chưa ký bổ sung phải là RG_16UI16UI.

  7. Thêm định dạng pixel mới dưới dạng static int trong HardwareBuffer.java bằng cách thêm một biến thành viên công khai mới vào cuối @Format:

    @Format
    ...
    /** Format: 8 bits each red, green, blue, alpha */
    public static final int RGBA_8888 = 0x1;
    

    Mục nhập enum này phải có cùng giá trị hex với giá trị trong PixelFormat.aidlhardware_buffer.h. Tuân thủ các quy ước hiện có.

  8. Nếu cố gắng tạo bản dựng bằng các thay đổi mã này, bạn sẽ gặp lỗi bản dựng:

    android_developer:~/android/aosp-android-latest-release: m
    ...
    ******************************
    You have tried to change the API from what has been previously approved.
    
    To make these errors go away, you have two choices:
       1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)
          to the new methods, etc. shown in the above diff.
    
       2. You can update current.txt and/or removed.txt by executing the following command:
             m api-stubs-docs-non-updatable-update-current-api
    
          To submit the revised current.txt to the main Android repository,
          you will need approval.
    ******************************
    ...
    

    Để xoá lỗi này, hãy chạy lệnh sau, như được chỉ định trong thông báo lỗi, để thay đổi current.txt:

    m api-stubs-docs-non-updatable-update-current-api
    

    Việc chạy lệnh trên sẽ cập nhật đúng tệp để có thể tạo bản dựng bình thường.

  9. Thêm định dạng pixel mới vào các chương trình kiểm thử Java bằng cách thêm định dạng pixel mới vào cuối paramsForTestCreateOptionalFormats() trong HardwareBufferTest.java, như sau:

    private static Object[] paramsForTestCreateOptionalFormats() {
      return new Integer[]{
          HardwareBuffer.RGBA_8888
      };
    

Thêm định dạng pixel mới vào tính năng tích hợp Hệ thống cửa sổ

Để sử dụng định dạng pixel mới làm định dạng cho vùng đệm khung trong Graphics API (API đồ hoạ), hãy thêm API này vào công cụ Tích hợp hệ thống cửa sổ (WSI) thích hợp để Graphics API (API đồ hoạ). Đối với ứng dụng hoặc quy trình hệ thống dùng API Vulkan, hãy cập nhật Chuỗi hoán đổi Vulkan. Đối với ứng dụng hoặc quy trình hệ thống sử dụng API OpenGL ES, hãy cập nhật EGL.

Các thay đổi đối với Vulkan WSI đối với các định dạng pixel mới

Cập nhật WSI trong Vulkan như sau:
  1. Thêm một trường hợp mới vào hàm GetNativePixelFormat(VkFormat format) trong swapchain.cpp:

    android::PixelFormat GetNativePixelFormat(VkFormat format) {
      ...
      switch (format) {
          ...
          case VK_FORMAT_R8G8B8A8_UNORM:
              native_format = PixelFormat::RGBA_8888;
              break;
          ...
          default:
              ALOGV("unsupported swapchain format %d", format);
              break;
      }
      return native_format;
    }
    
  2. Truy vấn tiện ích Vulkan nếu định dạng pixel yêu cầu tiện ích Vulkan để hoạt động. Ví dụ: các tiện ích bên, sử dụng instance_data, như sau:
    bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    

    Đối với các tiện ích phía thiết bị, hãy sử dụng các thông tin sau:

    bool rgba10x6_formats_ext = false;
    uint32_t exts_count;
    const auto& driver = GetData(pdev).driver;
    driver.EnumerateDeviceExtensionProperties(pdev, nullptr, &exts_count,
                                              nullptr);
    std::vector props(exts_count);
    driver.EnumerateDeviceExtensionProperties(pdev, nullptr, &exts_count,
                                              props.data());
    for (uint32_t i = 0; i < exts_count; i++) {
        VkExtensionProperties prop = props[i];
        if (strcmp(prop.extensionName,
                   VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME) == 0) {
            rgba10x6_formats_ext = true;
        }
    }
    

    Google xử lý cơ sở hạ tầng cần thiết để hiển thị một thực thể hoặc tiện ích thiết bị thành swapchain.cpp. Bạn không cần danh sách thay đổi ban đầu để thiết lập đúng cách các tiện ích từ trình tải Vulkan.

  3. Tiếp theo, hãy liệt kê các cặp định dạng và không gian màu:
    desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM;
    if (AHardwareBuffer_isSupported(&desc) && rgba10x6_formats_ext) {
      all_formats.emplace_back(
          VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
                             VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
      if (colorspace_ext) {
        all_formats.emplace_back(
            VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
                               VK_COLOR_SPACE_PASS_THROUGH_EXT});
        all_formats.emplace_back(
            VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
                               VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
    }
    

    Bạn phải có kiến thức về các cặp định dạng và không gian màu tương thích.

  4. Thêm định dạng mới vào dEQP-VK nằm tại external/deqp.
  5. Cập nhật quy trình Kiểm thử tuân thủ Vulkan trong vktApiExternalMemoryTests.cppvktExternalMemoryUtil.cpp bằng cách suy luận các thay đổi bắt buộc từ nguồn hiện có hoặc liên hệ với nhóm hỗ trợ Android để biết thông tin.

Thay đổi EGL cho các định dạng pixel mới

Cập nhật EGL như sau:

  1. Trong getNativePixelFormat() hãy chỉnh sửa cây if-else để trả về enum AIDL cho định dạng pixel mới. Sử dụng ví dụ cho định dạng pixel RGBA_8888:
    if (a == 0) {
      ...
    } else {
      if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
          if (colorDepth > 24) {
              ...
          } else {
              *format = PixelFormat::RGBA_8888;
          }
      } else {
        ...
      }
    }
    
  2. Để thêm định dạng mới vào dEQP, hãy thêm một mục mới vào enum androidFormats, như sau:
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

Gửi nội dung cập nhật

Theo dõi Dành cho người đóng góp để tổng hợp danh sách thay đổi của bạn và chia sẻ chúng với nhóm phù hợp.