CPU Rendering (програмний рендеринг) — це процес формування зображення центральним процесором без використання GPU. У цьому режимі всі обчислення трансформації, растеризації та текстурування виконуються на CPU через програмні алгоритми, а не через графічний конвеєр. За даними Apple Developer Documentation (2025), програмний рендеринг застосовується у 100% випадків під час запуску додатка до ініціалізації GPU-контексту і залишається основним режимом для UI-фреймворків на iOS. Розробники обирають CPU Rendering для завдань, критичних до сумісності та детермінованості.
Головне
CPU Rendering — метод формування зображення, при якому всі етапи графічного конвеєра виконуються на центральному процесорі за допомогою математичних розрахунків. На відміну від GPU, де растеризація та текстурування зашиті в спеціалізовані блоки, CPU виконує їх через універсальні інструкції SSE/NEON.
Історично весь рендеринг був програмним — перші графічні інтерфейси (Xerox Alto, 1973) та 3D-ігри (Quake, 1996) рендерилися на CPU. Термін «software renderer» закріпився як синонім CPU Rendering. Перехід на апаратне прискорення почався з появою доступних 3D-прискорювачів наприкінці 1990-х, але програмний рендеринг зберігся як fallback-механізм.
За даними Akamai (2025), CPU Rendering використовується у 35% мобільних веб-сесій як основний режим відрисовки — на слабких пристроях, в емуляторах та при вимкненому GPU-прискоренні. На платформах iOS та Android UI-фреймворки (UIKit, Android View) перші кілька кадрів завжди рендеряться на CPU до ініціалізації GPU-команд.
Сучасні процесори підтримують SIMD-інструкції (SSE4.2, AVX-512, ARM NEON), які частково імітують паралелізм GPU. Однак фізична кількість ядер (4–12) та відсутність спеціалізованих блоків растеризації обмежують продуктивність CPU Rendering при складній графіці.
Програмний конвеєр включає ті ж етапи, що й апаратний: трансформація вершин, відсікання, растеризація, текстурування та виведення пікселів. Різниця в тому, що кожен етап реалізований програмно через C++ або асемблерний код, а не через фіксовані блоки GPU.
Трансформація вершин у CPU Rendering виконується через множення матриць — 4x4 для проекції та моделювання. При 10 000 полігонів це 40 000 множень векторів на кадр — навантаження, з яким CPU справляється за 5–10 мс при оптимізованому коді. Растеризація — найважчий етап, що вимагає розрахунку покриття пікселів для кожного трикутника.
У мобільних процесорах ARM NEON прискорює програмний рендеринг за рахунок векторних інструкцій шириною 128 біт. За даними ARM (2025), NEON-оптимізований software renderer працює в 3–4 рази швидше за скалярну реалізацію на Cortex-X4 при однаковій тактовій частоті.
Програмний рендеринг починається з підготовки сцени на CPU: геометрія (вершини, полігони) перетворюється зі світових координат в екранні через матричні операції. Потім виконується відсікання — видалення геометрії поза полем зору камери.
Растеризація CPU розбиває кожен трикутник на пікселі через алгоритм сканувальних рядків (scanline) або barycentric-координати. Для кожного пікселя обчислюється колір з урахуванням текстур, освітлення та прозорості. Результат записується у framebuffer — масив пікселів в оперативній пам’яті.
Ключова відмінність від GPU-рендерингу — відсутність паралелізму на рівні пікселів. CPU обробляє пікселі послідовно або з невеликим паралелізмом через 4–8 ядер. Для кадру 1080p (2 млн пікселів) з текстуруванням це потребує 15–30 мс на CPU проти 2–5 мс на GPU.
// Спрощена CPU растеризація одного трикутника
void rasterizeTriangle(uint32_t* buffer, int width,
Vertex v0, Vertex v1, Vertex v2) {
int minX = max(0, min(v0.x, v1.x, v2.x));
int maxX = min(width, max(v0.x, v1.x, v2.x));
int minY = max(0, min(v0.y, v1.y, v2.y));
for (int y = minY; y <= maxY; y++) {
for (int x = minX; x <= maxX; x++) {
if (pixelInTriangle(x, y, v0, v1, v2)) {
buffer[y * width + x] = 0xFF3498DB;
}
}
}
}
Функція обходить bounding box трикутника і перевіряє кожен піксель на приналежність через barycentric-координати. Для мільйонів пікселів такий цикл виконується за мілісекунди на CPU, але для складних сцен із тисячами трикутників час зростає лінійно.
Різниця між CPU Rendering та GPU Rendering визначається архітектурою процесорів. CPU оптимізований для послідовних завдань з передбаченням розгалужень, GPU — для масового паралелізму з тисячами потоків. Ця фундаментальна різниця визначає області застосування кожного підходу.
| Параметр | CPU Rendering | GPU Rendering |
|---|---|---|
| Паралелізм | 4–12 потоків | 512–4096 потоків |
| FLOPS | 50–200 GFLOPS | 500–2400 GFLOPS |
| Енергоспоживання | 2–8 Вт на рендеринг | 2–8 Вт на рендеринг |
| Детермінізм | Повний | Залежить від драйвера |
| Налагодження | Легке (GDB, LLDB) | Складне (RenderDoc, XCode) |
| Текстури | В оперативній пам’яті | У відеопам’яті (VRAM) |
CPU Rendering виграє в детермінованості — однакові вхідні дані завжди дають однаковий результат. Це критично для UI-фреймворків, де кожен піксель повинен збігатися з макетом. GPU може вносити похибки через особливості floating-point округлення в різних драйверах.
Для 2D-графіки з низькою складністю (100–500 примітивів) CPU Rendering часто швидший за GPU через відсутність накладних витрат на передачу даних через шину та компіляцію шейдерів. За даними Google Android Team (2025), програмний рендеринг у View-системі Android займає 2–3 мс для типового екрану проти 3–5 мс з апаратним прискоренням на GPU.
Програмний рендеринг залишається затребуваним у сценаріях, де GPU недоступний, зайвий або не забезпечує потрібної детермінованості. Розглянемо основні області застосування CPU Rendering у сучасній розробці.
Android View система рендерить всі UI-елементи на CPU, а потім передає результат GPU для композитингу. Кожен View викликає onDraw(Canvas), який малює на Bitmap через CPU. Тільки після цього HWUI компізує шари на GPU. Це забезпечує детерміновану поведінку UI незалежно від GPU-драйвера.
UIKit в iOS також починається з CPU-рендерингу. Core Animation рендерить CALayer у backing store на CPU, а потім відправляє текстури в GPU. За даними WWDC 2024, програмна фаза займає 30–50% часу відрисовки кадру, решта — GPU-композитинг.
SVG-рендеринг традиційно виконується на CPU, оскільки потребує побудови складних кривих Безьє та їх заливки. Бібліотеки на кшталт librsvg та Skia обробляють SVG на CPU, розбиваючи криві на трикутники та зафарбовуючи їх. За даними Google Chrome Team (2025), Skia на CPU рендерить SVG-іконки за 0.3–1.5 мс на сучасних мобільних процесорах.
PDF-документи містять складну вкладену графіку: шрифти, векторні елементи, растрові зображення та трансформації. Мобільні додатки рендерять PDF на CPU через фреймворки на кшталт PDFKit (iOS) та PdfRenderer (Android). Точність відображення та підтримка стандарту PDF 2.0 потребують програмної обробки кожного елемента.
Мобільні платформи реалізують CPU Rendering з урахуванням архітектури ARM та обмеженого енергоспоживання. Розглянемо, як програмний рендеринг працює на Android та iOS.
Android Canvas при вимкненому апаратному прискоренні працює повністю на CPU. Клас Canvas містить методи для малювання примітивів, які виконуються через Skia — 2D-бібліотеку Google. Skia підтримує програмні та GPU-бекенди, перемикаючись за флагом hardwareAccelerated.
Програмний Canvas створює Bitmap в оперативній пам’яті, малює на ньому команди через Skia Software Renderer і потім виводить на екран. Всі операції виконуються на CPU з використанням NEON-інструкцій для оптимізації. За даними Skia Team (2025), NEON-прискорення дає приріст 40–60% для операцій blend та маскування.
// Програмний рендеринг через Bitmap
val bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
val paint = Paint().apply {
color = Color.RED
textSize = 24f
}
canvas.drawText("CPU Render", 10f, 50f, paint)
imageView.setImageBitmap(bitmap)
Bitmap створюється в пам’яті CPU, на ньому виконуються команди відрисовки, потім готове зображення відображається через ImageView. Такий підхід використовується для watermarking, графіків та динамічних зображень, де важливий повний контроль над кожним пікселем.
Core Graphics — фреймворк Apple для растрової та векторної графіки, що працює переважно на CPU. CGContext виконує всі операції малювання в програмному режимі, використовуючи високооптимізовані бібліотеки від Apple. Core Graphics підтримує Quartz 2D — двигун з 25-річною історією.
На iOS Core Graphics передає результат у Core Animation для композитингу на GPU. За даними Apple Engineering (2025), Core Graphics обробляє 80% UI-малювання на CPU в UIKit, а Metal-композитинг збирає готові текстури на GPU. UIGraphicsImageRenderer — сучасна обгортка для CPU-рендерингу растрових зображень.
Оптимізація CPU Rendering критична для продуктивності, оскільки програмний рендеринг — основний споживач CPU-циклів у UI-фреймворках. Розглянемо ключові методи прискорення програмної відрисовки.
Найефективніший метод — не перемальовувати те, що не змінилося. Якщо контент статичний, відрендеріть його один раз у Bitmap або CGLayer і копіюйте готовий результат. В Android це реалізовано через View.setLayerType(LAYER_TYPE_SOFTWARE) з кешованим Bitmap. В iOS — через drawsAsynchronously та CALayer.shouldRasterize.
Використовуйте dirty rectangles — відстежуйте, які області екрану змінилися, і перемальовуйте тільки їх. Android ViewSystem автоматично обчислює invalidated region. iOS CALayer використовує setNeedsDisplayInRect для обмеження області перемальовування.
Для операцій з пікселями (blend, маскування) використовуйте SIMD-інструкції CPU. Android Skia автоматично використовує NEON для ARM-процесорів. iOS Core Graphics векторизований через Accelerate framework. За даними Google (2025), NEON-оптимізовані blend-операції в Skia виконуються в 3–5 разів швидше за скалярний код.
// NEON-оптимізоване змішування пікселів (ARM)
#include <arm_neon.h>
void blendNEON(uint32_t* dst, const uint32_t* src, int count) {
for (int i = 0; i < count; i += 4) {
uint8x16_t a = vld1q_u8((uint8_t*)(src + i));
uint8x16_t b = vld1q_u8((uint8_t*)(dst + i));
uint8x16_t r = vhaddq_u8(a, b);
vst1q_u8((uint8_t*)(dst + i), r);
}
}
NEON-інструкції обробляють 16 пікселів (128 біт) за одну операцію. У поєднанні з конвеєризацією ARM Cortex-X4 це дає пропускну здатність до 500 млн пікселів на секунду при програмному копіюванні та змішуванні — достатньо для FullHD-екрану з 60 FPS.
Часті запитання
CPU Rendering швидший за GPU при малій кількості примітивів (до 500) через відсутність накладних витрат на передачу даних та компіляцію шейдерів. Для UI-екранів з 50–100 View програмний рендеринг часто займає менше часу, ніж GPU-конвеєр.
Android View-система малює на CPU для детермінованої відрисовки — кожен піксель точно відповідає коду без GPU-похибок. Після відрисовки шари передаються в HWUI для GPU-композитингу, що поєднує точність CPU з продуктивністю GPU.
Для 3D-графіки в реальному часі CPU Rendering неефективний. GPU рендерить 100 млн трикутників на секунду, CPU — 5–10 млн. Виняток — рендеринг окремих кадрів для прев’ю або експорту, де детермінізм важливіший за швидкість.
На Android використовуйте Profile GPU Rendering у Developer Options. На iOS — Core Animation profiler в Instruments. Зелена смужка вище 16 мс вказує на затримки CPU-рендерингу. Також перевірте флаг hardwareAccelerated у маніфесті Android.
Skia — 2D-графічна бібліотека Google, що використовується в Android, Chrome та Flutter. Skia підтримує програмний та GPU-бекенд. У режимі CPU вона виконує всі операції через оптимізований Software Renderer з використанням NEON-інструкцій.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також