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

يجب تضمين جميع تنسيقات البكسل الجديدة التي تمت إضافتها إلى Android في لغة تعريف واجهة Android (AIDL) وفي مخزن Android للأجهزة (AHB). يفرض كل من AIDL وAHB متطلبات صارمة بشأن الثبات والتوحيد القياسي، ما يستلزم اتّباع عملية دقيقة عند توسيع الوظائف. يجب أن تتوفّر جميع تنسيقات وحدات البكسل الجديدة في مشروع Android مفتوح المصدر (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-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، أضِف تنسيق البكسل الجديد كإدخال جديد في نهاية التعداد 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-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"

لاستخدام تنسيق البكسل الجديد كتنسيق لإطار مخزن مؤقت في واجهة برمجة تطبيقات رسومات، أضِفه إلى Window System Integration (WSI) المناسب لواجهة برمجة تطبيقات الرسومات ذات الصلة. بالنسبة إلى تطبيق أو عملية نظام تستخدم Vulkan API، يجب تعديل 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 enum، كما هو موضّح أدناه:
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

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

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