Akceleracja sprzętowa

Począwszy od Androida 3.0 (poziom interfejsu API 11) potok renderowania 2D na Androidzie obsługuje sprzęt przyspieszenie, czyli wszystkie operacje rysowania wykonywane na Obszar roboczy View korzysta z GPU. Ze względu na zwiększoną ilość zasobów wymaganych do akceleracja sprzętowa, aplikacja zużywa więcej pamięci RAM.

Akceleracja sprzętowa jest domyślnie włączona, jeśli docelowy poziom interfejsu API wynosi >=14, ale może też być jawnie włączone. Jeśli Twoja aplikacja korzysta tylko z widoków standardowych Drawable, włączenie tej funkcji globalnie nie powinno spowodować niekorzystnego rysowania efekty. Akceleracja sprzętowa nie jest jednak obsługiwana w przypadku wszystkich rysunków 2D. operacji, jego włączenie może mieć wpływ na niektóre widoki niestandardowe lub wywołania rysowania. Problemy zwykle ujawniają się jako niewidoczne elementy, wyjątki lub nieprawidłowo renderowane piksele. Do Aby temu zaradzić, Android umożliwia włączanie i wyłączanie akceleracji sprzętowej poziomów. Zobacz Sterowanie akceleracją sprzętową.

Jeśli Twoja aplikacja umożliwia rysowanie niestandardowe, przetestuj ją na rzeczywistych urządzeniach sprzętowych. z włączoną akceleracją sprzętową, by wykryć problemy. W sekcji Obsługa operacji rysowania opisano znane problemy z: oraz sposoby obejścia tego problemu.

Zobacz też OpenGL z interfejsami Framework API. i Renderscript

Steruj akceleracją sprzętową

Możesz sterować akceleracją sprzętową na tych poziomach:

  • Zgłoszenie do programu
  • Aktywność
  • Okno
  • Wyświetl

Poziom aplikacji

W pliku manifestu Androida dodaj ten atrybut do <application>, aby włączyć akcelerację sprzętową w całym aplikacja:

<application android:hardwareAccelerated="true" ...>

Poziom aktywności

Jeśli po włączeniu akceleracji sprzętowej globalnie aplikacja nie działa prawidłowo, ale może też kontrolować ją w przypadku poszczególnych działań. Aby włączyć lub wyłączyć akcelerację sprzętową na stronie poziomu aktywności, możesz użyć atrybutu android:hardwareAccelerated do <activity>. Poniższy przykład umożliwia włączenie akceleracji sprzętowej w przypadku całą aplikację, ale wyłącza ją w przypadku jednego działania:

<application android:hardwareAccelerated="true">
    <activity ... />
    <activity android:hardwareAccelerated="false" />
</application>

Poziom okna

Jeśli potrzebujesz bardziej szczegółowej kontroli, możesz włączyć akcelerację sprzętową z następującym kodem:

Kotlin

window.setFlags(
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
)

Java

getWindow().setFlags(
    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

Uwaga: obecnie nie można wyłączyć akceleracji sprzętowej w na poziomie okna.

Poziom widoku

Możesz wyłączyć akcelerację sprzętową dla pojedynczego widoku danych w czasie działania za pomocą ten kod:

Kotlin

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

Java

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Uwaga: obecnie nie można włączyć akceleracji sprzętowej w na poziomie widoku. Oprócz wyłączania akceleracji sprzętowej warstwy widoku danych mają też inne funkcje. Więcej informacji o ich użyciu znajdziesz w artykule Wyświetlanie warstw.

Jak określić, czy widok jest z akceleracją sprzętową

Czasami przydaje się dla aplikacji informacja, czy w danym momencie jest to sprzęt Przyspieszone, szczególnie w przypadku widoków niestandardowych. Jest to szczególnie przydatne, jeśli może wykonywać wiele rysunków niestandardowych i nie wszystkie operacje są poprawnie obsługiwane i potoku renderowania.

Istnieją dwa sposoby sprawdzenia, czy aplikacja ma akcelerację sprzętową:

Jeśli musisz to zrobić w kodzie rysunku, użyj Zamiast tego Canvas.isHardwareAccelerated() View.isHardwareAccelerated(), gdy to możliwe. Po wyświetleniu jest podłączony do okna z akceleracją sprzętową, można go wciąż narysować Obszar roboczy z przyspieszeniem. Dzieje się tak na przykład podczas rysowania widoku do mapy bitowej na potrzeby buforowania w celach informacyjnych.

Modele rysunkowe na Androidzie

Po włączeniu akceleracji sprzętowej platforma Androida używa nowego modelu rysowania, korzysta z list wyświetlanych, by wyświetlać aplikację na ekranie. Aby w pełni zrozumieć i ich wpływie na aplikację, warto zrozumieć, jak Android generuje też widoki bez akceleracji sprzętowej. W sekcjach poniżej znajdziesz opis z oprogramowaniem i z akceleracją sprzętową.

Model rysowania oparty na oprogramowaniu

W modelu rysowania programowego widoki są rysowane w następujących 2 krokach:

  1. Unieważnij hierarchię
  2. Narysuj hierarchię

Gdy aplikacja musi zaktualizować część interfejsu użytkownika, wywołuje funkcję invalidate() (lub jeden z jej wariantów) w dowolnym widoku, który uległ zmianie treści. Komunikaty o unieważnieniu są przekazywane aż do samej hierarchii widoku, aż do obliczenia zabrudzony obszar ekranu, który należy ponownie narysować. System Android rysuje dowolny widok w hierarchii, który przecina obszar zanieczyszczony. Niestety, ma dwie wady tego modelu rysowania:

  • Po pierwsze, ten model wymaga wykonania dużej ilości kodu przy każdym przebiegu pobierania. Na przykład, jeśli aplikacja wywołuje invalidate() po naciśnięciu przycisku i że znajduje się nad innym widokiem, system Android ponownie rysuje go, została zmieniona.
  • Drugim problemem jest to, że model rysowania może ukrywać błędy w aplikacji. Ponieważ System Android ponownie rysuje widoki, gdy krzyżują się z brudnym regionem, czyli widoku, którego zawartość mogą zostać zmienione, nawet jeśli element invalidate() nie został w ten sposób. W takiej sytuacji korzystasz z unieważnienia innego widoku danych, aby uzyskać jego prawidłowe działanie. To zachowanie może się zmieniać za każdym razem, gdy zmodyfikujesz aplikację. Z powodu ten element powinien zawsze wywoływać funkcję invalidate() we własnym zakresie za każdym razem, gdy zmienisz dane lub stan, które mają wpływ na kod rysowania widoku.

Uwaga: widoki na Androida automatycznie wywołują invalidate() po zmianie ich właściwości, np. tła. koloru lub tekstu w elemencie TextView.

Przyspieszenie sprzętowe modelu rysowania

System Android nadal używa interfejsów invalidate() i draw() do wysyłania żądań aktualizacji ekranu i renderowania widoków, ale obsługuje i rysować w inny sposób. Zamiast od razu wykonywać polecenia rysowania, system Android rejestruje je na listach wyświetlania, które zawierają dane wyjściowe hierarchii widoków do rysunków. Kolejna optymalizacja polega na tym, że system Android musi tylko wyświetlaj listy wyświetleń oznaczonych jako „zanieczyszczone” według atrybutu invalidate() . Widoki, które nie zostały unieważnione, można ponownie wykorzystać, ponownie przesyłając zapisanej listy wyświetlacza. Nowy model rysowania składa się z 3 etapów:

  1. Unieważnij hierarchię
  2. Rejestrowanie i aktualizowanie wyświetlanych list
  3. Rysuj listy wyświetlanych

W przypadku tego modelu nie możesz polegać na widoku przecinającym zanieczyszczony region, aby jego metoda draw() została wykonana. Aby system Android zarejestrował wyświetlić listę wyświetlanych elementów, musisz wywołać funkcję invalidate(). Zapominam powoduje, że widok wygląda tak samo nawet po zmianie.

Użycie list w sieci reklamowej również zwiększa wydajność animacji, ponieważ ustawienie określonych właściwości np. alfa czy rotacja, nie wymaga unieważniania docelowego widoku ). Optymalizacja ta dotyczy również widoków z listami w sieci reklamowej (każdy widok, w którym z akceleracją sprzętową). Załóżmy na przykład, że istnieje element LinearLayout zawierający znak ListView powyżej wiersza Button. Wyświetlana lista dla „LinearLayout” wygląda tak to:

  • DrawDisplayList(ListView)
  • DrawDisplayList(przycisk)

Załóżmy, że chcesz zmienić przezroczystość elementu ListView. Po wywoływanie funkcji setAlpha(0.5f) na elemencie: ListView, wyświetla się teraz lista zawiera to:

  • SaveLayerAlpha(0,5)
  • DrawDisplayList(ListView)
  • Przywróć
  • DrawDisplayList(przycisk)

Złożony kod rysowania ListView nie został wykonany. Zamiast tego makro system zaktualizował tylko listę wyświetlania, która jest dużo prostsza w użyciu LinearLayout. W aplikację bez włączonej akceleracji sprzętowej, kod rysowania listy oraz jej element nadrzędny zostanie wykonany ponownie.

Obsługa operacji rysowania

Z akceleracją sprzętową potok renderowania 2D obsługuje najczęściej używane Canvas operacji rysowania oraz wielu rzadziej używanych operacji. Wszystkie operacje rysowania, które służą do renderowania aplikacji wysyłanych z Androidem, domyślnych widżetów i układy, oraz typowe zaawansowane efekty wizualne, takie jak odbicia i tekstury kafelkowe, obsługiwane.

W tabeli poniżej opisano poziom obsługi różnych operacji na różnych poziomach interfejsu API:

Pierwszy obsługiwany poziom interfejsu API
Canvas
DrobitmapMesh() (tablica kolorów) 18
DrawPicture() 23
DrawPosText() 16
DrawTextOnPath() 16
DrawVertices() 29
setDrawFilter() 16
klipPath() 18
klipRegion() 18
klipRect(Region.Op.XOR) 18
klipRect(Region.Op.Różnica) 18
klipRect(Region.Op.ReverseDifference) 18
klipRect() z obrotem/perspektywą 18
Barwiony
setAntiAlias() (dla tekstu) 18
setAntiAlias() (dla linii) 16
setFilterBitmap() 17
setLinearText()
setMaskFilter()
setPathEffect() (dla linii) 28
setShadowLayer() (inne niż tekst) 28
setStrokeCap() (dla linii) 18
setStrokeCap() (dla punktów) 19
setSubpixelText() 28
Xfermode
PorterDuff.Mode.DARKEN (bufor ramki) 28
PorterDuff.Mode.LIGHTEN (bufor ramki) 28
PorterDuff.Mode.OVERLAY (bufor ramki) 28
Efekt cieniowania
ComposeShader w ComposeShader 28
Mechanizmy cieniowania tego samego typu w ComposeShader 28
Lokalna macierz w ComposeShader 18

Skalowanie obszaru roboczego

Najpierw stworzono z akceleracją sprzętową potok renderowania 2D, który obsługuje nieskalowane rysunki, przy czym niektóre operacje rysowania znacznie pogarszają jakość przy wyższych wartościach skali. Te są implementowane jako tekstury rysowane w skali 1.0, przekształcane przez GPU. Uruchamiam w interfejsie API na poziomie 28, wszystkie operacje rysowania mogą być skalowane bez problemów.

W tabeli poniżej pokazujemy, kiedy implementacja została zmieniona, by zapewnić prawidłową obsługę dużych rozmiarów:
Operacja rysowania do skalowania Pierwszy obsługiwany poziom interfejsu API
DrawText() 18
DrawPosText() 28
DrawTextOnPath() 28
Proste kształty* 17
Złożone kształty* 28
DrawPath() 28
Warstwa cienia 28

Uwaga: „Prosty” kształty to drawRect(), drawCircle(), drawOval(), drawRoundRect() i Polecenia drawArc() (z useCenter=false) z atrybutem Paint, które nie ma PathEffect i nie zawiera złączeń innych niż domyślne (przez setStrokeJoin() / setStrokeMiter()). Inne wystąpienia tych poleceń rysowania należą do kategorii „Złożone”, cale powyżej.

Jeśli w Twojej aplikacji występują jakiekolwiek z tych brakujących funkcji lub ograniczeń, możesz wyłącz akcelerację sprzętową tylko dla części aplikacji, której dotyczy problem, przez wywołanie setLayerType(View.LAYER_TYPE_SOFTWARE, null) Dzięki temu możesz: nadal korzystać z akceleracji sprzętowej w innych miejscach. Więcej informacji o tym, jak ją włączyć, znajdziesz w artykule Sterowanie akceleracją sprzętową. i wyłączaj akcelerację sprzętową na różnych poziomach w swojej aplikacji.

Wyświetl warstwy

We wszystkich wersjach Androida wyświetlenia mogły być renderowane w buforach poza ekranem, z pamięci podręcznej rysunku widoku lub przy użyciu funkcji Canvas.saveLayer(). Bufory poza ekranem (w tym warstwy) mają wiele zastosowań. Możesz ich użyć, aby uzyskać działa szybciej podczas animowania złożonych widoków lub stosowania efektów kompozycji. Przykład: możesz zastosować efekty zanikania za pomocą Canvas.saveLayer(), aby tymczasowo renderować widok w warstwę, a potem umieścić na ekranie z określonym współczynnikiem przezroczystości.

Począwszy od Androida 3.0 (poziom interfejsu API 11) będziesz mieć większą kontrolę nad tym, jak i kiedy używać warstw za pomocą metody View.setLayerType(). Ten interfejs API zajmuje 2 razy parametr: typ warstwy, którego chcesz użyć, oraz opcjonalny element Paint opisujący sposób złożenia warstwy. Parametru Paint możesz użyć, aby zastosować filtry kolorów, specjalne tryby mieszania lub przezroczystość do warstwę. Widok może korzystać z jednego z 3 typów warstw:

  • LAYER_TYPE_NONE: widok jest renderowany normalnie i nie ma kopii zapasowej. przez bufor poza ekranem. Jest to jego ustawienie domyślne.
  • LAYER_TYPE_HARDWARE: widok jest renderowany w postaci sprzętowej. tekstury sprzętowej, jeśli aplikacja jest akcelerowana sprzętowo. Jeśli aplikacja nie jest sprzętowa z przyspieszoną, ten typ warstwy działa tak samo jak LAYER_TYPE_SOFTWARE.
  • LAYER_TYPE_SOFTWARE: widok jest renderowany w postaci oprogramowania. bitmapy.

Typ używanej warstwy zależy od Twojego celu:

  • Wydajność: używanie sprzętowego typu warstwy do renderowania widoku sprzętowego. teksturę. Po wyrenderowaniu widoku w warstwę nie trzeba wykonywać jej kodu rysowania dopóki widok nie wywoła invalidate(). Niektóre animacje, np. animacji alfa, można następnie zastosować bezpośrednio w warstwie. dla GPU.
  • Efekty wizualne: użyj typu warstwy sprzętowej lub programowej oraz Paint, aby zastosować do widoku specjalne sekwencje wizualne. Możesz na przykład: do rysowania czarno-białego widoku za pomocą ColorMatrixColorFilter.
  • Zgodność: użyj typu warstwy programowej, aby wymusić renderowanie widoku w i oprogramowaniu. Jeśli widok z akceleracją sprzętową (np. cały film aplikacja jest akredytowana sprzętowo), ma problemy z renderowaniem, to łatwy sposób wokół ograniczeń renderowania sprzętowego potoku.

Wyświetlanie warstw i animacji

Warstwy sprzętowe mogą generować szybsze i płynniejsze animacje, gdy aplikacja jest wspomagany sprzętowo. Uruchomienie animacji z szybkością 60 klatek na sekundę nie zawsze jest możliwe, gdy animowanie złożonych widoków, które wymagają wielu operacji rysowania. Możesz temu złagodzić, stosując: za pomocą warstw sprzętowych, aby renderować widok na teksturze sprzętowej. Tekstura sprzętowa a potem używane do animowania widoku, eliminując potrzebę ciągłego ponownego nadawania widoku obrazu. podczas animacji. Widok nie jest ponownie rysowany, chyba że zmienisz właściwości, które wywołuje invalidate(), lub w przypadku ręcznego wywołania invalidate(). Jeśli używasz animacji w języku: w danej aplikacji i nie uzyskać pożądanych wyników, spróbuj włączyć warstwy sprzętowe ani ich animowanych wyświetleń.

Jeśli widok jest oparty na warstwie sprzętowej, niektóre jego właściwości są obsługiwane jest skomponowana na ekranie. Ustawienie tych właściwości będzie skuteczne, ponieważ nie będzie wymagają, aby widok został unieważniony i użyty ponownie. Poniższa lista właściwości wpływa na sposób warstwa jest skomponowana. Wywołanie metody ustawiającej dla dowolnej z tych właściwości zapewnia optymalną unieważnienie docelowego widoku danych i usunięcie go z nich:

  • alpha: zmienia przezroczystość warstwy
  • x, y, translationX, translationY: Zmienia pozycję warstwy
  • scaleX, scaleY: zmienia rozmiar warstwy
  • rotation, rotationX, rotationY: zmienia wartość orientacja warstwy w przestrzeni 3D
  • pivotX, pivotY: zmienia źródło przekształceń warstwy

Właściwości te to nazwy używane do animowania widoku za pomocą obiektu ObjectAnimator. Jeśli chcesz uzyskać dostęp do tych właściwości, wywołaj odpowiednie polecenie lub seterem. Aby na przykład zmodyfikować właściwość w wersji alfa, wywołaj funkcję setAlpha(). Fragment kodu poniżej pokazuje najskuteczniejszy sposób aby obrócić widok w 3D wokół osi Y:

Kotlin

view.setLayerType(View.LAYER_TYPE_HARDWARE, null)
ObjectAnimator.ofFloat(view, "rotationY", 180f).start()

Java

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator.ofFloat(view, "rotationY", 180).start();

Warstwy sprzętowe zużywają pamięć wideo, dlatego zdecydowanie zalecamy ich włączenie tylko na czas trwania animacji, a potem wyłącz je po jej zakończeniu. Ty można to zrobić za pomocą detektorów animacji:

Kotlin

view.setLayerType(View.LAYER_TYPE_HARDWARE, null)
ObjectAnimator.ofFloat(view, "rotationY", 180f).apply {
    addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            view.setLayerType(View.LAYER_TYPE_NONE, null)
        }
    })
    start()
}

Java

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
animator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        view.setLayerType(View.LAYER_TYPE_NONE, null);
    }
});
animator.start();

Więcej informacji o animacji właściwości znajdziesz w artykule Animacja usługi.

Porady i wskazówki

Przejście na grafikę 2D z akceleracją sprzętową może natychmiast zwiększyć wydajność, ale należy zaprojektować Twoją aplikację pod kątem efektywnego korzystania z GPU, stosując się do tych wskazówek: zalecenia:

Zmniejszanie liczby wyświetleń w aplikacji
Im więcej widoków danych utworzy system, tym wolniej będzie. Dotyczy to oprogramowania potok renderowania. Zmniejszenie liczby wyświetleń to jeden z najprostszych sposobów na optymalizację interfejsu.
Unikaj przeciągania
Nie rysuj na sobie zbyt wielu warstw. Usuń wszystkie widoki, które są całkowicie przesłonięty innymi nieprzezroczystymi widokami. Jeśli chcesz nałożyć na siebie kilka przemieszanych warstw rozważ połączenie ich w jedną warstwę. Dobrą ogólną zasadą jest Sprzęt nie może rysować więcej niż 2,5 raza liczby pikseli na ekranie na klatkę. (przezroczyste piksele w bitmapie).
Nie twórz obiektów renderowania w metodach rysowania
Częstym błędem jest tworzenie nowego elementu Paint lub nowego Path przy każdym wywołaniu metody renderowania. Wymusza to czyszczenia pamięci kolektora, aby działał częściej oraz pomijał pamięć podręczną i optymalizacje sprzętowe potoku.
Nie zmieniaj kształtów zbyt często.
Na przykład złożone kształty, ścieżki lub okręgi są renderowane przy użyciu masek tekstur. Co podczas tworzenia lub modyfikowania ścieżki, potok sprzętowy tworzy nową maskę, którą można drogie.
Nie modyfikuj zbyt często map bitowych
Po każdej zmianie zawartości bitmapy jest ona ponownie przesyłana jako tekstura GPU przy następnym rysowaniu.
Zachowaj ostrożność podczas korzystania z wersji alfa
Gdy ustawisz widok jako półprzezroczysty za pomocą setAlpha(), AlphaAnimation, lub ObjectAnimator, to jest renderowana w buforze poza ekranem, co powoduje podwojenie wymaganego współczynnika wypełnienia. Przy stosowaniu kanału alfa przy bardzo dużych widokach warto ustawić typ warstwy na LAYER_TYPE_HARDWARE