Overdraw — to nadmierne przerysowywanie tych samych pikseli kilka razy w ciągu jednej klatki. Gdy na ekranie wyświetlany jest złożony interfejs z wieloma nakładającymi się elementami, GPU jest zmuszony wielokrotnie przetwarzać każdy piksel, co bezpośrednio wpływa na liczbę klatek na sekundę i zużycie energii. Według Google Android Developer Documentation, 2025, zmniejszenie overdraw o 50% może zwiększyć wydajność renderowania nawet o 30%. Optymalizacja overdraw to obowiązkowy etap przy tworzeniu aplikacji z płynnymi animacjami i responsywnym interfejsem.
Najważniejsze
Overdraw — to sytuacja, w której ten sam piksel ekranu jest przerysowywany kilka razy w ciągu jednej klatki renderowania. W idealnym scenariuszu każdy piksel powinien być zapisywany dokładnie raz, ale w rzeczywistych interfejsach z powodu zagnieżdżonych View, obrazów tła i przezroczystych warstw GPU wykonuje wielokrotne zapisy.
Każde dodatkowe przerysowanie zwiększa czas renderowania klatki. Przy standardowej częstotliwości 60 FPS na przetworzenie jednej klatki przypada około 16.6 ms. Jeśli overdraw powoduje przekroczenie tego limitu, liczba klatek spada do 30 FPS lub niżej, co zauważalnie pogarsza płynność interfejsu.
Według Android Performance Patterns od Google, aplikacja ze współczynnikiem overdraw 3x traci trzy razy więcej czasu na shader fragmentów niż aplikacja z overdraw 1x. Na urządzeniach z niską wydajnością GPU prowadzi to do odczuwalnych opóźnień podczas przewijania i animacji.
Dla programistów mobilnych zrozumienie overdraw jest krytycznie ważne: właśnie ten czynnik najczęściej powoduje szarpanie przewijania i niską liczbę klatek na pozornie prostych ekranach z dużą liczbą zagnieżdżonych elementów.
Potok GPU składa się z kilku etapów: shader wierzchołków, rasteryzacja i shader fragmentów. Shader fragmentów — najbardziej kosztowna część, ponieważ jest wykonywany dla każdego piksela każdego prymitywu. Przy overdraw x2 shader fragmentów przetwarza dwa razy więcej pikseli, co bezpośrednio zwiększa czas klatki.
Nowoczesne mobilne GPU, takie jak Qualcomm Adreno i Apple GPU, mają mechanizmy Early-Z Test i Hidden Surface Removal, które częściowo kompensują overdraw. Jednak te optymalizacje działają tylko w określonych warunkach i nie należy polegać wyłącznie na przyspieszeniu sprzętowym.
Na przykład podczas renderowania półprzezroczystych elementów sprzętowy Early-Z jest nieskuteczny, a każdy piksel jest przetwarzany w pełni — overdraw w takich scenariuszach może osiągać 5x i więcej.
Wielowarstwowe tła — jedna z głównych przyczyn overdraw w aplikacjach mobilnych. Gdy Activity lub ViewController ustawia kolor tła, każdy zagnieżdżony View może dodawać własne tło, a piksel jest przerysowywany na każdym poziomie hierarchii.
Badanie Uber Engineering wykazało, że usunięcie nadmiarowych teł w swojej aplikacji na Androida zmniejszyło overdraw o 32%, a czas renderowania ekranu — o 25%. Podobna sytuacja w iOS: ustawienie opaque = true dla nieprzezroczystych View eliminuje mieszanie alfa i zapobiega wielokrotnemu zapisowi pikseli.
Na platformie iOS overdraw często powstaje z powodu używania przezroczystych UIStackView, CALayer z shouldRasterize i nakładających się UIBlurEffect. Apple zaleca sprawdzanie overdraw za pomocą narzędzia Core Animation w XCode — pokazuje ono strefy przerysowania jako nakładkę w kolorze czerwonym.
Debug GPU Overdraw — wbudowane narzędzie Androida, które koloruje ekran w różne kolory w zależności od krotności overdraw. Kolor fioletowy oznacza 1x, niebieski — 2x, zielony — 3x, różowy — 4x, czerwony — 5x i więcej. Idealny ekran powinien być przeważnie fioletowy.
W iOS analogiczną diagnostykę wykonuje narzędzie Core Animation w ramach XCode Instruments. Wizualizuje ono strefy przerysowania i pokazuje dokładną liczbę zapisów na piksel w trybie Color Blended Layers. Zielone warstwy — nieprzezroczyste (optymalne), czerwone — zawierają przezroczystość i powodują overdraw.
Po diagnostyce ważne jest zmierzenie FPS przed i po optymalizacji. Różnica 10–15 FPS przy naprawianiu overdraw to normalny wynik dla złożonego ekranu z listami i animacją.
Usuwanie nadmiarowych teł — najprostsza i najskuteczniejsza metoda. W Androidzie wystarczy ustawić android:windowBackground tylko dla Activity lub motywu, a nie dla każdego View. W iOS opaque = true dla wszystkich nieprzezroczystych UIView zmniejsza overdraw praktycznie do zera dla tych elementów.
Według Google I/O 2019, optymalizacja overdraw w Google Maps pozwoliła zmniejszyć czas renderowania klatki o 40% poprzez łączenie warstw i używanie ClipRect do ograniczania obszaru rysowania. Google zaleca programistom Androida następujące praktyki:
W iOS optymalizacja osiągana jest poprzez konfigurację CALayer: ustawienie masksToBounds = true przycina zawartość poza granicami warstwy, a shouldRasterize włącza buforowanie reprezentacji rastrowej dla statycznych warstw.
Rozważmy praktyczne przykłady w Kotlin i Swift, demonstrujące typowe scenariusze eliminacji overdraw. Pierwszy przykład pokazuje optymalizację przez ClipRect w Androidzie:
class OptimizedView@JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : View(context, attrs) {
override fun onDraw(canvas: Canvas) {
canvas.clipRect(
paddingLeft.toFloat(), paddingTop.toFloat(),
width - paddingRight.toFloat(), height - paddingBottom.toFloat()
)
// Rysuj treść tylko w przyciętym obszarze
super.onDraw(canvas)
}
}
Drugi przykład — w Swift, pokazuje wyłączenie przezroczystości dla warstwy, jeśli element nie powinien być półprzezroczysty:
class OpaqueLabel: UILabel {
override var isOpaque: Bool {
get { true }
set { }
}
override func draw(_ rect: CGRect) {
backgroundColor?.setFill()
UIRectFill(rect)
super.draw(rect)
}
}
Trzeci przykład — użycie ViewStub do opóźnionego ładowania mapy w Androidzie. ViewStub nie jest renderowany dopóki nie stanie się widoczny, co eliminuje overdraw na etapie inicjalizacji ekranu:
<!-- layout/activity_main.xml -->
<ViewStub
android:id="@+id/map_stub"
android:layout_width="match_parent"
android:layout_height="200dp"
android:inflatedId="@+id/map_container"
android:layout="@layout/map_fragment" />
// Rozwijaj na żądanie
ViewStub stub = findViewById(R.id.map_stub)
stub?.inflate()
Często zadawane pytania
Overdraw — to sytuacja, gdy piksel na ekranie jest przerysowywany kilka razy w ciągu jednej klatki. Wyobraź sobie, że malujesz kartkę papieru, a na niej naklejasz kilka przezroczystych folii z rysunkami — dolne warstwy trzeba przerysowywać za każdym razem, gdy zmienia się górna warstwa.
Włącz Debug GPU Overdraw w ustawieniach deweloperskich. Elementy z overdraw 1x są kolorowane na fioletowo, 2x — na niebiesko, 3x — na zielono, 4x — na różowo, 5x+ — na czerwono. Optymalny ekran — przeważnie fioletowy bez czerwonych stref.
Każde dodatkowe przerysowanie piksela wymaga wywołania shadera fragmentów, który przetwarza kolor, teksturę i oświetlenie. Przy 60 FPS na klatkę przypada 16.6 ms — jeśli overdraw zmusza GPU do przetwarzania 2–3 razy więcej pikseli, limit zostaje przekroczony i FPS spada do 30.
Tak, bezpośrednio. GPU wykonujący nadmiarową pracę zużywa więcej energii. Według badań Google, zmniejszenie overdraw z 4x do 1x redukuje zużycie energii GPU o 35–50%, co jest szczególnie zauważalne na urządzeniach z wyświetlaczami o wysokiej rozdzielczości.
Dla prostych ekranów — 1x–1.5x (fioletowy z niewielką ilością niebieskiego). Dla rozbudowanych interfejsów — do 2x. Poziom 3x i wyżej (różowy, czerwony) wymaga optymalizacji. Google zaleca nie przekraczać overdraw 2.5x średnio na ekran.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również