Dodaj nowe formaty pikseli do Androida

Wszystkie nowe formaty pikseli dodane do systemu Android muszą być uwzględnione w języku definicji interfejsu systemu Android (AIDL) i w buforze sprzętowym systemu Android (AHB) . AIDL i AHB mają rygorystyczne wymagania dotyczące stabilności i standaryzacji, które wymagają ostrożnego procesu przy rozszerzaniu funkcjonalności. Wszystkie nowe formaty pikseli muszą trafić do AOSP, a wszystkie aktualizacje muszą zostać indywidualnie potwierdzone przez ekspertów AIDL i AHB. Ten proces dokładnego potwierdzenia jest ważnym czynnikiem standaryzacji wszelkich nowych formatów pikseli na platformie.

Na tej stronie opisano niezbędne zmiany w kodzie AOSP i proces wymagany do dodania nowych formatów pikseli w AOSP.

Przed dodaniem nowego formatu pikseli pobierz źródło i prześlij poprawki zgodnie z opisem w sekcji Przesyłanie poprawek .

Dodaj nowy format pikseli do AIDL

Dodanie obsługi nowego formatu pikseli wymaga zmian w obu plikach PixelFormat.aidl znajdujących się w AIDL. Zobacz hardware/interfaces/graphics/common/aidl/ aby zapoznać się z kodem źródłowym AIDL.

Aby dodać nowy formalny piksel do AIDL, wykonaj następujące kroki:

  1. Dołącz nowy format pikseli jako nowy wpis na końcu wyliczenia PixelFormat w pliku PixelFormat.aidl , postępując zgodnie z istniejącą konwencją kodu i ustawiając wartość szesnastkową wpisu o jeden większą niż poprzedni wpis. Dopasuj zmiany w kodzie do poprzednich wpisów. Zobacz następujący przykład wpisu w formacie pikseli 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,
    

    Podczas tworzenia kodu po wprowadzeniu zmian w PixelFormat.aidl pojawia się następujący komunikat o błędzie:

    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. Aby usunąć ten błąd, uruchom następujące polecenie zgodnie z komunikatem o błędzie, aby zmienić PixelFormat.aidl w katalogu aidl_api :

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

    Uruchomienie powyższego polecenia aktualizuje poprawny plik, aby móc normalnie budować.

Dodaj nowy format pikseli do AHB

Dodanie obsługi nowego formatu pikseli wymaga zmian w hardware_buffer.h i AHardwareBuffer.cpp . Zobacz frameworks/native/libs/nativewindow aby zapoznać się z kodem źródłowym AHB.

Aby dodać nowy piksel formalny do AHB, wykonaj następujące kroki:

  1. W hardware_buffer.h dołącz nowy format pikseli jako nowy wpis na końcu wyliczenia AHardwareBuffer_Format . Postępuj zgodnie z istniejącymi konwencjami kodu.

    Korzystając z przykładowego formatu pikseli RGBA_8888 , dodaj nowy wpis formatu pikseli w następujący sposób:

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

    Należy zauważyć, że nowy format pikseli ma nazwę w AHB, która musi zaczynać się od AHARDWAREBUFFER_FORMAT_ , po której następują skróty kanałów i głębia bitowa, a kończyć na kodowaniu. Ten wpis wyliczeniowy musi mieć tę samą wartość szesnastkową, co w PixelFormat.aidl .

    Oczekuje się, że format pikselowy będzie miał jeden lub oba powiązane formaty Vulkan lub OpenGL ES . W stosownych przypadkach określ powiązany format. Jeśli nie istnieje żaden powiązany format, określ N/A .

  2. Dodaj format pikselowy do opcjonalnych testów w ramach CTS, jeśli jest on powiązany z formatem OpenGL ES. Aby to zrobić, dodaj nowy format GL do AHardwareBufferGLTest.cpp w AHBFormatAsString(int32_t format) z FORMAT_CASE(...) i GL_FORMAT_CASE(...) dla nowego formatu, jak pokazano poniżej:

    const char* AHBFormatAsString(int32_t format) {
      switch (format) {
          ...
          FORMAT_CASE(R8G8B8A8_UNORM);
          ...
          GL_FORMAT_CASE(GL_RGB8);
      }
      return "";
    }
    
  3. Następnie dodaj nowy test do AHardwareBufferGLTest.cpp , jak pokazano poniżej:

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

    Określ co najmniej jeden zestaw wartości AHardwareBuffer_Desc . W razie potrzeby dodaj więcej wartości.

  4. W AHardwareBuffer.cpp znajdź koniec statycznych asercji znajdujących się w:

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

    Dołącz nowy static_assert dla nowego formatu pikseli, używając wyliczenia PixelFormat:: , a nie stałej HAL_PIXEL_FORMAT . Korzystając z tego samego przykładu dla formatu pikseli RGBA_8888 z Add a new pixel format to AIDL , dodaj nowy wpis formatu pikseli w następujący sposób:

    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. Dodaj nowy format pikseli do odpowiednich testów, dołączając nowy format pikseli na końcu PrintAhbFormat() w AHardwareBufferTest.cpp . Postępuj zgodnie z istniejącą konwencją kodu, jak pokazano poniżej:

    void PrintAhbFormat(std::ostream& os, uint64_t format) {
        switch (format) {
            ...
            FORMAT_CASE(R8G8B8A8_UNORM);
            default: os << "unknown"; break;
        }
    }
    
  6. Dodaj nowy format pikseli do zestawu SDK HardwareBuffer w HardwareBuffer.java : dodając nowy wpis do @IntDef . Na przykład wpis dla formatu RGBA_8888 jest pokazany w następujący sposób:

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

    Jeśli wartości komponentów nie są znormalizowane bez znaku, należy jawnie wskazać wartość w nazwie zmiennej. Na przykład nazwa zmiennej dla 16-bitowego formatu tylko kanału czerwonego na liczbach całkowitych bez znaku musi mieć postać R_16UI , a ten sam format z dodatkowym 16-bitowym formatem zielonego kanału na liczbach całkowitych bez znaku musi mieć postać RG_16UI16UI .

  7. Dodaj nowy format pikseli jako static int w HardwareBuffer.java , dołączając nową publiczną zmienną składową na końcu @Format :

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

    Ten wpis wyliczeniowy musi mieć tę samą wartość szesnastkową, co wartość z PixelFormat.aidl i hardware_buffer.h . Postępuj zgodnie z obowiązującymi konwencjami.

  8. Próba kompilacji z tymi zmianami w kodzie generuje błąd kompilacji:

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

    Aby usunąć ten błąd, uruchom następujące polecenie zgodnie z komunikatem o błędzie, aby zmienić current.txt :

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

    Uruchomienie powyższego polecenia aktualizuje poprawny plik, aby móc normalnie budować.

  9. Dodaj nowy format pikseli do testów Java, dołączając nowy format pikseli na końcu paramsForTestCreateOptionalFormats() w HardwareBufferTest.java , jak pokazano poniżej:

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

Dodaj nowy format pikseli do integracji systemu Windows

Aby użyć nowego formatu pikseli jako formatu bufora ramki w graficznym interfejsie API, dodaj go do odpowiedniego modułu Windows System Integration (WSI) dla odpowiedniego graficznego interfejsu API. W przypadku aplikacji lub procesu systemowego korzystającego z interfejsu API Vulkan zaktualizuj Vulkan Swapchain. W przypadku aplikacji lub procesu systemowego korzystającego z interfejsu API OpenGL ES zaktualizuj interfejs API EGL .

Zmiany w Vulkan WSI dla nowych formatów pikseli

Zaktualizuj Vulkan WSI w następujący sposób:
  1. Dodaj nową skrzynkę do funkcji GetNativePixelFormat(VkFormat format) w 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. Zapytaj o rozszerzenie Vulkan, jeśli format piksela wymaga do działania rozszerzenia Vulkan. Na przykład rozszerzenia boczne użyj instance_data , pokazanej poniżej:
    bool colorspace_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
    

    W przypadku rozszerzeń po stronie urządzenia użyj następujących poleceń:

    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 obsługuje infrastrukturę wymaganą do udostępnienia instancji lub rozszerzenia urządzenia swapchain.cpp . Początkowa lista zmian nie jest wymagana do prawidłowej konfiguracji rozszerzeń z poziomu modułu ładującego Vulkan.

  3. Następnie wylicz pary formatu i przestrzeni kolorów:
    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});
    }
    

    Wymagana jest wiedza na temat zgodnych formatów i par przestrzeni kolorów.

  4. Dodaj nowy format do dEQP-VK znajdującego się w external/deqp .
  5. Zaktualizuj testy zgodności Vulkan w vktApiExternalMemoryTests.cpp i vktExternalMemoryUtil.cpp , wnioskując o wymaganych zmianach z istniejącego źródła lub kontaktując się z pomocą techniczną systemu Android w celu uzyskania informacji.

Zmiany EGL dla nowych formatów pikseli

Zaktualizuj EGL w następujący sposób:

  1. W funkcji getNativePixelFormat() zmodyfikuj drzewo if-else , aby zwrócić wyliczenie AIDL dla nowego formatu pikseli. Używając przykładu dla formatu pikseli RGBA_8888 :
    if (a == 0) {
      ...
    } else {
      if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
          if (colorDepth > 24) {
              ...
          } else {
              *format = PixelFormat::RGBA_8888;
          }
      } else {
        ...
      }
    }
    
  2. Aby dodać nowy format do dEQP, dodaj nowy wpis do wyliczenia androidFormats , pokazany poniżej:
    static const GLenum androidFormats[] =
    {
      ...
      GL_RGBA8,
      ...
    };
    

Prześlij swoją aktualizację

Obserwuj Aby współpracownicy mogli uporządkować swoje listy zmian i udostępnić je odpowiedniemu zespołowi.