เพิ่มรูปแบบพิกเซลใหม่ลงใน Android

รูปแบบพิกเซลใหม่ทั้งหมดที่เพิ่มลงใน Android ต้องรวมอยู่ใน ภาษาที่ใช้สื่อสารข้อมูลระหว่างคอมโพเนนต์ของ Android (AIDL) และใน บัฟเฟอร์ฮาร์ดแวร์ของ Android (AHB) AIDL และ AHB มีข้อกำหนดด้านความเสถียรและการกำหนดมาตรฐานที่เข้มงวด ซึ่งจำเป็นต้องมี กระบวนการที่รอบคอบเมื่อขยายฟังก์ชันการทำงาน รูปแบบพิกเซลใหม่ทั้งหมดต้องอยู่ใน AOSP และผู้เชี่ยวชาญด้าน AIDL และ AHB ต้องยืนยันการอัปเดตทั้งหมดทีละรายการ กระบวนการยืนยันอย่างรอบคอบนี้เป็นปัจจัยสำคัญในการกำหนดรูปแบบพิกเซลใหม่ๆ บนแพลตฟอร์มให้เป็นมาตรฐาน

หน้านี้อธิบายการเปลี่ยนแปลงโค้ด AOSP ที่จำเป็นและกระบวนการที่ต้องใช้ในการเพิ่มรูปแบบพิกเซลใหม่ใน AOSP

ก่อนเพิ่มรูปแบบพิกเซลใหม่ ให้ดาวน์โหลดแหล่งที่มาและอัปโหลดแพตช์ตามที่ระบุไว้ใน การส่งแพตช์

เพิ่มรูปแบบพิกเซลใหม่ลงใน AIDL

การเพิ่มการรองรับรูปแบบพิกเซลใหม่ต้องมีการเปลี่ยนแปลงทั้งใน PixelFormat.aidl ที่อยู่ใน AIDL ดูซอร์สโค้ด AIDL ได้ที่ hardware/interfaces/graphics/common/aidl/

หากต้องการเพิ่มรูปแบบพิกเซลใหม่ลงใน AIDL ให้ทำตามขั้นตอนต่อไปนี้

  1. ต่อท้ายรูปแบบพิกเซลใหม่เป็นรายการใหม่ที่ส่วนท้ายของ PixelFormat enum ใน PixelFormat.aidl โดยทำตามแบบแผนการเขียนโค้ดที่มีอยู่และตั้งค่าฐานสิบหกสำหรับรายการของคุณให้มากกว่ารายการก่อนหน้า 1 จับคู่การเปลี่ยนแปลงโค้ดกับการป้อนข้อมูลก่อนหน้า ดูตัวอย่างต่อไปนี้ สำหรับ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,
    

    คุณจะเห็นข้อความแสดงข้อผิดพลาดต่อไปนี้เมื่อสร้างโค้ดหลังจากทำการเปลี่ยนแปลงใน 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. หากต้องการล้างข้อผิดพลาดนี้ ให้เรียกใช้คำสั่งต่อไปนี้ตามที่ระบุไว้ในข้อความแสดงข้อผิดพลาดเพื่อเปลี่ยน PixelFormat.aidl ในไดเรกทอรี aidl_api

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

    การเรียกใช้คำสั่งข้างต้นจะอัปเดตไฟล์ที่ถูกต้องเพื่อให้สร้างได้ตามปกติ

เพิ่มรูปแบบพิกเซลใหม่ลงใน AHB

การเพิ่มการรองรับรูปแบบพิกเซลใหม่ต้องมีการเปลี่ยนแปลงใน hardware_buffer.h และ AHardwareBuffer.cpp ดูframeworks/native/libs/nativewindow สำหรับซอร์สโค้ด AHB

หากต้องการเพิ่มรูปแบบพิกเซลใหม่ลงใน AHB ให้ทำตามขั้นตอนต่อไปนี้

  1. ใน hardware_buffer.h ให้เพิ่มรูปแบบพิกเซลใหม่เป็นรายการใหม่ที่ส่วนท้ายของ enum AHardwareBuffer_Format ปฏิบัติตามรูปแบบการเขียนโค้ดที่มีอยู่

    ใช้RGBA_8888ตัวอย่างรูปแบบพิกเซล แล้วเพิ่มรายการรูปแบบพิกเซลใหม่ดังนี้

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

    โปรดทราบว่ารูปแบบพิกเซลใหม่จะมีชื่อใน AHB ซึ่งต้องขึ้นต้นด้วย AHARDWAREBUFFER_FORMAT_ ตามด้วยตัวย่อของช่องและความลึกของบิต และลงท้ายด้วยการเข้ารหัส รายการ enum นี้ต้องมีค่าเลขฐานสิบหกเหมือนกับค่าใน PixelFormat.aidl

    รูปแบบพิกเซลควรมีรูปแบบ Vulkan หรือ OpenGL ES ที่เชื่อมโยงอย่างใดอย่างหนึ่งหรือทั้ง 2 รูปแบบ ระบุรูปแบบที่เกี่ยวข้องหากเหมาะสม หากไม่มีรูปแบบที่เชื่อมโยง ให้ระบุ N/A

  2. เพิ่มรูปแบบพิกเซลลงในการทดสอบที่ไม่บังคับใน CTS หากมีรูปแบบ OpenGL ES ที่เชื่อมโยง โดยให้เพิ่มรูปแบบ GL ใหม่ลงใน AHardwareBufferGLTest.cpp ใน AHBFormatAsString(int32_t format) ด้วย FORMAT_CASE(...) และ GL_FORMAT_CASE(...) สำหรับรูปแบบใหม่ ดังนี้

    const char* AHBFormatAsString(int32_t format) {
      switch (format) {
          ...
          FORMAT_CASE(R8G8B8A8_UNORM);
          ...
          GL_FORMAT_CASE(GL_RGB8);
      }
      return "";
    }
    
  3. จากนั้นเพิ่มการทดสอบใหม่ไปยัง AHardwareBufferGLTest.cpp ดังที่แสดงต่อไปนี้

    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);
    

    ระบุค่า AHardwareBuffer_Desc อย่างน้อย 1 ชุด เพิ่มค่าอื่นๆ หากจำเป็น

  4. ใน AHardwareBuffer.cpp ให้ค้นหาส่วนท้ายของข้อความแบบคงที่ที่พบใน

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

    ต่อท้าย static_assert ใหม่สำหรับรูปแบบพิกเซลใหม่ โดยใช้ enum PixelFormat:: และไม่ใช่ค่าคงที่ HAL_PIXEL_FORMAT ใช้ตัวอย่างเดียวกันสำหรับรูปแบบพิกเซล RGBA_8888 จาก เพิ่มรูปแบบพิกเซลใหม่ลงใน AIDL เพิ่มรายการรูปแบบพิกเซลใหม่ดังนี้

    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. เพิ่มรูปแบบพิกเซลใหม่ลงในการทดสอบที่เหมาะสมโดยต่อท้ายรูปแบบพิกเซลใหม่ที่ส่วนท้าย ของ PrintAhbFormat() ใน AHardwareBufferTest.cpp ทำตามรูปแบบโค้ดที่มีอยู่ ดังที่แสดงด้านล่าง

    void PrintAhbFormat(std::ostream& os, uint64_t format) {
        switch (format) {
            ...
            FORMAT_CASE(R8G8B8A8_UNORM);
            default: os << "unknown"; break;
        }
    }
    
  6. เพิ่มรูปแบบพิกเซลใหม่ลงใน HardwareBuffer SDK ใน HardwareBuffer.java: โดยการเพิ่มรายการใหม่ลงใน @IntDef เช่น รายการสำหรับรูปแบบ RGBA_8888 จะแสดงดังนี้

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

    หากค่าคอมโพเนนต์ไม่ได้เป็นค่าที่ปรับให้เป็นมาตรฐานแบบไม่มีเครื่องหมาย ให้ระบุค่าอย่างชัดเจน ในชื่อตัวแปร เช่น ชื่อตัวแปรสำหรับช่องสีแดงแบบจำนวนเต็ม 16 บิตที่ไม่มีการลงนาม เท่านั้นต้องเป็น R_16UI และรูปแบบเดียวกันที่มีช่องสีเขียวแบบจำนวนเต็ม 16 บิตที่ไม่มีการลงนาม เพิ่มเติมต้องเป็น RG_16UI16UI

  7. เพิ่มรูปแบบพิกเซลใหม่เป็น static int ใน HardwareBuffer.java โดยการต่อท้ายตัวแปรสมาชิกแบบสาธารณะใหม่ที่ส่วนท้ายของ @Format ดังนี้

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

    รายการ enum นี้ต้องมีค่าฐานสิบหกเหมือนกับค่าจาก PixelFormat.aidl และ hardware_buffer.h ปฏิบัติตามแบบแผนที่มีอยู่

  8. การพยายามสร้างด้วยการเปลี่ยนแปลงโค้ดเหล่านี้จะทำให้เกิดข้อผิดพลาดในการสร้าง

    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.
    ******************************
    ...
    

    หากต้องการล้างข้อผิดพลาดนี้ ให้เรียกใช้คำสั่งต่อไปนี้ตามที่ระบุไว้ในข้อความแสดงข้อผิดพลาด เพื่อเปลี่ยน current.txt

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

    การเรียกใช้คำสั่งข้างต้นจะอัปเดตไฟล์ที่ถูกต้องเพื่อให้สร้างได้ตามปกติ

  9. เพิ่มรูปแบบพิกเซลใหม่ลงในการทดสอบ Java โดยต่อท้ายรูปแบบพิกเซลใหม่ที่ส่วนท้ายของ paramsForTestCreateOptionalFormats() ใน HardwareBufferTest.java ดังที่แสดงด้านล่าง

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

เพิ่มรูปแบบพิกเซลใหม่ลงในการผสานรวมระบบหน้าต่าง

หากต้องการใช้รูปแบบพิกเซลใหม่เป็นรูปแบบสำหรับเฟรมบัฟเฟอร์ใน Graphics API ให้เพิ่มรูปแบบดังกล่าวลงในการผสานรวมระบบหน้าต่าง (WSI) ที่เหมาะสมสำหรับ Graphics API ที่เกี่ยวข้อง สำหรับแอปหรือกระบวนการของระบบที่ใช้ Vulkan API ให้อัปเดต Vulkan Swapchain สำหรับกระบวนการของแอปหรือระบบที่ใช้ OpenGL ES API ให้อัปเดต API ของ EGL

การเปลี่ยนแปลง WSI ของ Vulkan สำหรับรูปแบบพิกเซลใหม่

อัปเดต WSI ของ Vulkan ดังนี้
  1. เพิ่มเคสใหม่ลงในฟังก์ชัน GetNativePixelFormat(VkFormat format) ใน 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. ค้นหาส่วนขยาย Vulkan หากรูปแบบพิกเซลต้องใช้ส่วนขยาย Vulkan จึงจะทำงานได้ สำหรับส่วนขยายด้านข้าง ให้ใช้ instance_data ดังที่แสดงต่อไปนี้
    bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    

    สำหรับส่วนขยายฝั่งอุปกรณ์ ให้ใช้สิ่งต่อไปนี้

    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 จะจัดการโครงสร้างพื้นฐานที่จำเป็นในการเปิดเผยอินสแตนซ์หรือส่วนขยายอุปกรณ์ต่อ swapchain.cpp ไม่จำเป็นต้องมีรายการการเปลี่ยนแปลงเริ่มต้นเพื่อ ตั้งค่าส่วนขยายอย่างถูกต้องจากโปรแกรมโหลด Vulkan

  3. จากนั้นแสดงรายการคู่รูปแบบและพื้นที่สี
    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});
    }
    

    คุณต้องมีความรู้เกี่ยวกับคู่รูปแบบและคู่พื้นที่สีที่เข้ากันได้

  4. เพิ่มรูปแบบใหม่ไปยัง dEQP-VK ที่ external/deqp
  5. อัปเดตการทดสอบความสอดคล้องของ Vulkan ใน vktApiExternalMemoryTests.cpp และ vktExternalMemoryUtil.cpp โดยอนุมานการเปลี่ยนแปลงที่จำเป็นจากแหล่งที่มาที่มีอยู่ หรือติดต่อทีมสนับสนุนของ Android เพื่อขอข้อมูล

การเปลี่ยนแปลง EGL สำหรับรูปแบบพิกเซลใหม่

อัปเดต EGL ดังนี้

  1. ในฟังก์ชัน getNativePixelFormat() ให้แก้ไขทรี if-else เพื่อแสดงผล enum AIDL สำหรับรูปแบบพิกเซลใหม่ การใช้ตัวอย่างสำหรับRGBA_8888รูปแบบพิกเซล
    if (a == 0) {
      ...
    } else {
      if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
          if (colorDepth > 24) {
              ...
          } else {
              *format = PixelFormat::RGBA_8888;
          }
      } else {
        ...
      }
    }
    
  2. หากต้องการเพิ่มรูปแบบใหม่ลงใน dEQP ให้เพิ่มรายการใหม่ลงใน androidFormats enum ดังที่แสดงต่อไปนี้
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

ส่งการอัปเดต

ทำตามขั้นตอนต่อไปนี้ สำหรับผู้ร่วมให้ข้อมูล เพื่อสร้างรายการการเปลี่ยนแปลงและแชร์กับทีมที่เหมาะสม