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

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

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

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

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

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

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

  1. เพิ่มรูปแบบพิกเซลใหม่เป็นรายการใหม่ต่อท้าย PixelFormat enum ใน PixelFormat.aidl โดยทำตามรูปแบบโค้ดที่มีอยู่และตั้งค่าเลขฐาน 16 ของรายการให้มากกว่ารายการก่อนหน้า 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 ดูซอร์สโค้ด AHB ได้ที่ frameworks/native/libs/nativewindow

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

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

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

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

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

    รูปแบบพิกเซลควรมีรูปแบบ Vulkan หรือ OpenGL ES ที่เกี่ยวข้องอย่างน้อย 1 รูปแบบ ระบุรูปแบบที่เกี่ยวข้องตามความเหมาะสม หากไม่มีรูปแบบที่เชื่อมโยง ให้ระบุ 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 ใหม่สำหรับรูปแบบพิกเซลใหม่โดยใช้ลิสต์แบบ 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 นี้ต้องมีค่าฐาน 16 เดียวกันกับค่าจาก 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
      };
    

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

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

การเปลี่ยนแปลง 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 เพื่อแสดงผลรายการ 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 ดังที่แสดงต่อไปนี้
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

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

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