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

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

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

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

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

تتطلّب إضافة دعم لتنسيق بكسل جديد إجراء تغييرات على كلا ملفَّي PixelFormat.aidl الموجودَين ضمن AIDL. يمكنك الاطّلاع على رمز مصدر AIDL في hardware/interfaces/graphics/common/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-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_، متبوعًا باختصارات القنوات وأعماق البتات، وينتهي بالتشفير. يجب أن يتضمّن إدخال التعداد هذا القيمة السداسية العشرية نفسها في 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. أضِف تنسيق البكسل الجديد إلى 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;
    

    يجب أن يتضمّن إدخال التعداد هذا القيمة السداسية العشرية نفسها من 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
      };
    

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

لاستخدام تنسيق البكسل الجديد كتنسيق لمخزن مؤقت للإطارات في واجهة برمجة تطبيقات للرسومات، أضِفه إلى عملية دمج "نظام النوافذ" (WSI) المناسبة لواجهة برمجة التطبيقات ذات الصلة للرسومات. بالنسبة إلى تطبيق أو عملية نظام تستخدم واجهة برمجة تطبيقات Vulkan، عدِّل Vulkan Swapchain. بالنسبة إلى تطبيق أو عملية نظام تستخدم واجهة برمجة تطبيقات OpenGL ES، عدِّل واجهة برمجة تطبيقات 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 الموجود في 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,
      ...
    };
    

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

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