إضافة تنسيقات بكسل جديدة إلى Android

يجب تضمين جميع تنسيقات البكسل الجديدة التي تمت إضافتها إلى Android في ملف لغة تعريف واجهة Android (AIDL) ومخازن الأجهزة في Android (AHB). تفرض واجهة برمجة التطبيقات AIDL وواجهة AHB متطلبات صارمة للاستقرار والتوحيد تتطلّب اتّباع عملية دقيقة عند توسيع نطاق الوظائف. يجب أن يتم طرح جميع تنسيقات البكسل الجديدة في AOSP ويجب أن يؤكّد خبراء AIDL وAHB كل التحديثات بشكلٍ فردي. إنّ عملية التأكيد الدقيقة هذه هي عامل مهم في توحيد أيّ تنسيقات جديدة للبكسل على الصعيد المنصة.

توضِّح هذه الصفحة التغييرات اللازمة في رمز AOSP والعملية المطلوبة لإضافة تنسيقات بكسل جديدة على AOSP.

قبل إضافة تنسيق بكسل جديد، نزِّل المصدر وحمِّل الرموز البرمجية كما هو موضّح في مقالة إرسال الرموز البرمجية.

إضافة تنسيق بكسل جديد إلى AIDL

تتطلّب إضافة دعم لتنسيق بكسل جديد إجراء تغييرات على كل من ملفَي PixelFormat.aidl المتوفّرَين ضمن AIDL. اطّلِع على hardware/interfaces/graphics/common/aidl/ للاطّلاع على رمز المصدر لـ AIDL.

لإضافة تنسيق بكسل جديد إلى AIDL، اتّبِع الخطوات التالية:

  1. أضِف تنسيق البكسل الجديد كإدخال جديد في نهاية قائمة القيم الفريدة PixelFormat في PixelFormat.aidl باتّباع اصطلاح الترميز الحالي وضبط القيمة الست عشرية لإدخالك لتكون واحدة أكثر من الإدخال السابق. قارِن التغييرات التي أجريتها على الرمز البرمجي بالإدخالات السابقة. اطّلِع على المثال التالي لإدخال تنسيق 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-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. لإزالة هذا الخطأ، نفِّذ الأمر التالي، كما هو محدّد في رسالة الخطأ، لتغيير 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، أضِف تنسيق البكسل الجديد كإدخال جديد في نهاية قائمة AHardwareBuffer_Format. اتّبِع اصطلاحات الرموز الحالية.

    باستخدام مثال تنسيق RGBA_8888 بكسل، أضِف إدخال تنسيق البكسل الجديد على النحو التالي:

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

    يُرجى العِلم أنّه يتم منح تنسيق البكسل الجديد اسمًا في AHB، والذي يجب أن يبدأ برمز AHARDWAREBUFFER_FORMAT_، متبوعًا بمختصرات القنوات وشدَّة البت، وينتهي بترميز. يجب أن يتضمّن إدخال القائمة المحددة مسبقًا هذا القيمة الست عشرية نفسها الواردة في PixelFormat.aidl.

    من المتوقّع أن يتضمّن تنسيق البكسل تنسيقًا واحدًا أو كليهما من تنسيقَي Vulkan أو OpenGL ES. حدِّد التنسيق المرتبط حيثما كان ذلك مناسبًا. إذا لم يكن هناك تنسيق مرتبط، حدِّد 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. أضِف المزيد من القيم إذا لزم الأمر.

  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. أضِف تنسيق البكسل الجديد إلى حزمة SDK لنظام التشغيل HardwareBuffer فيملف 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;
    

    يجب أن يكون لإدخال القائمة المحددة هذه القيمة الست عشرية نفسها المستخدَمة في PixelFormat.aidl وhardware_buffer.h. اتّباع القواعد الحالية

  8. تؤدي محاولة إنشاء التطبيق باستخدام تغييرات الرمز البرمجي هذه إلى ظهور خطأ في الإنشاء:

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

    لإزالة هذا الخطأ، نفِّذ الأمر التالي كما هو محدّد في رسالة الخطأ، لتغيير 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
      };
    

إضافة تنسيق بكسل جديد إلى عملية دمج نظام النوافذ

لاستخدام تنسيق البكسل الجديد كتنسيق لإطار عرض في واجهة برمجة تطبيقات الرسومات، أضِفه إلى عملية دمج نظام النوافذ (WSI) المناسبة لواجهة برمجة تطبيقات الرسومات ذات الصلة. بالنسبة إلى عملية تطبيق أو نظام تستخدم واجهة برمجة التطبيقات Vulkan، عليك تعديل سلسلة التبديل Vulkan Swapchain. بالنسبة إلى عملية تطبيق أو نظام تستخدِم واجهة برمجة التطبيقات OpenGL ES API، عليك تحديث واجهة برمجة التطبيقات EGL.

تغييرات Vulkan WSI لتنسيقات وحدات البكسل الجديدة

عدِّل Vulkan WSI على النحو التالي:
  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 في ملف ‎"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,
      ...
    };
    

إرسال التعديل

اتّبِع الخطوات التالية للمساهمين لإنشاء قوائم التغييرات ومشاركتها مع الفريق المناسب.