Thêm các đị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ó 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à tiêu chuẩn hoá, nên cần phải thực hiện một quy trình cẩn thận khi mở rộng chức năng. Tất cả định dạng pixel mới phải được đưa vào AOSP và tất cả bản cập nhật phải được các chuyên gia AIDL và AHB xác nhận riêng lẻ. Quy trình xác nhận kỹ lưỡng này là một yếu tố quan trọng trong việc chuẩn hoá mọi định dạng pixel mới trên nền tảng.

Trang này trình bày những thay đổi cần thiết về mã AOSP 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 nguồn xuống rồi tải bản vá lên như đã nêu trong phần 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. Hãy xem hardware/interfaces/graphics/common/aidl/ để biết 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. Nối đị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 của bạn lớn hơn một so với mục 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 cho 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-main: 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 một định dạng pixel mới, bạn cần thay đổi hardware_buffer.hAHardwareBuffer.cpp. Hãy xem frameworks/native/libs/nativewindow để biết 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. Hãy tuân theo các quy ước lập trình 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ó cùng giá trị hex như giá trị trong PixelFormat.aidl.

    Định dạng pixel dự kiến phải có một hoặc cả hai định dạng Vulkan hoặc OpenGL ES được 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 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) bằng FORMAT_CASE(...)GL_FORMAT_CASE(...) cho định dạng mới, 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 chương trình 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);
    

    Chỉ định ít nhất một tập hợp 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 câu nhận định 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 enum PixelFormat:: chứ không phả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. Hãy làm theo quy ước lập trình 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 sẽ 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ị của PixelFormat.aidlhardware_buffer.h. Tuân theo 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-main: 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 API đồ hoạ, hãy thêm định dạng đó vào dịch vụ Tích hợp hệ thống cửa sổ (WSI) thích hợp cho API đồ hoạ có liên quan. Đối với một ứng dụng hoặc quy trình hệ thống sử 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 API EGL.

Thay đổi về Vulkan WSI cho các định dạng pixel mới

Cập nhật Vulkan WSI 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. Đối với các tiện ích bên, hãy 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ị cho 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 của EGL đối với các định dạng pixel mới

Cập nhật EGL như sau:

  1. Trong hàm getNativePixelFormat(), hãy sửa đổi 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

Hãy làm theo phần Dành cho cộng tác viên để tạo danh sách thay đổi và chia sẻ với nhóm thích hợp.