CPU Rendering(ソフトウェアレンダリング)は、GPUを使用せずに中央プロセッサが画像を形成するプロセスです。このモードでは、変換、ラスタライズ、テクスチャリングのすべての計算が、グラフィックスパイプラインではなくソフトウェアアルゴリズムを通じてCPU上で実行されます。Apple Developer Documentation(2025)によると、ソフトウェアレンダリングはGPUコンテキストの初期化前にアプリケーションを起動する際に100%のケースで使用され、iOSのUIフレームワークの主要モードであり続けています。開発者は、互換性と決定性が重要なタスクにCPU Renderingを選択します。
重要ポイント
CPU Renderingは、グラフィックスパイプラインのすべての段階が数学的計算を通じて中央プロセッサ上で実行される画像形成方法です。ラスタライズとテクスチャリングが専用ブロックに組み込まれているGPUとは異なり、CPUは汎用のSSE/NEON命令を通じてこれらを実行します。
歴史的に、すべてのレンダリングはソフトウェアベースでした — 初期のグラフィカルインターフェース(Xerox Alto、1973年)や3Dゲーム(Quake、1996年)はCPU上でレンダリングされていました。“software renderer”という用語はCPU Renderingの同義語として定着しました。ハードウェアアクセラレーションへの移行は、1990年代後半に手頃な価格の3Dアクセラレータの登場とともに始まりましたが、ソフトウェアレンダリングはフォールバックメカニズムとして残りました。
Akamai(2025)によると、CPU Renderingはモバイルウェブセッションの35%で主要なレンダリングモードとして使用されています — 低性能デバイス、エミュレータ、GPUアクセラレーションが無効になっている場合です。iOSおよびAndroidプラットフォームでは、UIフレームワーク(UIKit、Android View)は最初の数フレームをGPUコマンドの初期化前に常にCPU上でレンダリングします。
現代のプロセッサはSIMD命令(SSE4.2、AVX-512、ARM NEON)をサポートしており、GPUの並列性を部分的に模倣します。しかし、物理的なコア数(4–12)と専用ラスタライズブロックの欠如により、複雑なグラフィックスでのCPU Renderingのパフォーマンスは制限されます。
ソフトウェアパイプラインはハードウェアと同じ段階を含みます:頂点変換、クリッピング、ラスタライズ、テクスチャリング、ピクセル出力。違いは、各段階が固定GPUブロックではなくC++またはアセンブリコードを通じてソフトウェアで実装されることです。
CPU Renderingでの頂点変換は、行列乗算を通じて実行されます — 投影とモデリング用の4x4。10,000ポリゴンの場合、1フレームあたり40,000のベクトル乗算となり、最適化されたコードでCPUは5–10ミリ秒で処理します。ラスタライズは最も重い段階であり、各三角形のピクセルカバレッジ計算が必要です。
モバイルプロセッサでは、ARM NEONが128ビット幅のベクトル命令を通じてソフトウェアレンダリングを高速化します。ARM(2025)によると、NEON最適化されたソフトウェアレンダラーは、同じクロック周波数のCortex-X4でスカラー実装よりも3–4倍高速に動作します。
ソフトウェアレンダリングは、CPU上でのシーン準備から始まります:ジオメトリ(頂点、ポリゴン)が行列演算を通じてワールド座標からスクリーン座標に変換されます。次にクリッピングが実行されます — カメラの視野の外にあるジオメトリが除去されます。
CPUラスタライズは、スキャンラインアルゴリズムまたは重心座標を使用して各三角形をピクセルに分割します。各ピクセルについて、テクスチャ、照明、透明度を考慮して色が計算されます。結果はフレームバッファ(RAM内のピクセル配列)に書き込まれます。
GPUレンダリングとの主な違いは、ピクセルレベルでの並列性の欠如です。CPUはピクセルを逐次的に、または4–8コアでの限られた並列性で処理します。テクスチャリングを伴う1080pフレーム(200万ピクセル)の場合、CPUでは15–30ミリ秒かかるのに対し、GPUでは2–5ミリ秒です。
// 単一三角形の簡略化された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;
}
}
}
}
関数は三角形のバウンディングボックスをスキャンし、重心座標を使用して各ピクセルの所属を確認します。数百万ピクセルの場合、このようなループはCPU上でミリ秒単位で実行されますが、数千の三角形を持つ複雑なシーンでは時間が線形に増加します。
CPU RenderingとGPU Renderingの違いは、プロセッサアーキテクチャによって決まります。CPUは分岐予測を伴う逐次タスクに最適化されており、GPUは数千スレッドによる大規模並列処理に最適化されています。この基本的な違いが、各アプローチの適用領域を決定します。
| パラメータ | CPU Rendering | GPU Rendering |
|---|---|---|
| 並列性 | 4–12スレッド | 512–4096スレッド |
| FLOPS | 50–200 GFLOPS | 500–2400 GFLOPS |
| 消費電力 | 2–8 W(レンダリング時) | 2–8 W(レンダリング時) |
| 決定性 | 完全 | ドライバに依存 |
| デバッグ | 容易(GDB、LLDB) | 複雑(RenderDoc、XCode) |
| テクスチャ | RAM内 | ビデオメモリ内(VRAM) |
CPU Renderingは決定性で優れています — 同じ入力データは常に同じ出力を生成します。これは、すべてのピクセルがレイアウトと一致する必要があるUIフレームワークにとって重要です。GPUはドライバ間の浮動小数点丸めの違いにより不正確さを生じる可能性があります。
低複雑性(100–500プリミティブ)の2Dグラフィックスの場合、CPU Renderingはバス経由のデータ転送とシェーダコンパイルのオーバーヘッドがないため、GPUよりも高速であることがよくあります。Google Android Team(2025)によると、AndroidのViewシステムでのソフトウェアレンダリングは、標準的な画面で2–3ミリ秒かかるのに対し、GPUでのハードウェアアクセラレーションでは3–5ミリ秒かかります。
ソフトウェアレンダリングは、GPUが利用できない、不要、または必要な決定性を提供しないシナリオで需要があります。現代の開発におけるCPU Renderingの主な適用分野を見てみましょう。
Android Viewシステムは、すべてのUI要素をCPU上でレンダリングし、結果をGPUに渡してコンポジットします。各ViewはonDraw(Canvas)を呼び出し、CPU経由でBitmapに描画します。その後、HWUIがGPU上でレイヤーをコンポジットします。これにより、GPUドライバに依存しない決定論的なUI動作が保証されます。
iOSのUIKitもCPUレンダリングから始まります。Core AnimationはCPU上のバッキングストアにCALayerをレンダリングし、テクスチャをGPUに送信します。WWDC 2024によると、ソフトウェアフェーズはフレームレンダリング時間の30–50%を占め、残りはGPUコンポジットです。
SVGレンダリングは伝統的にCPU上で実行されます。複雑なベジェ曲線の構築と塗りつぶしが必要だからです。librsvgやSkiaなどのライブラリはCPU上でSVGを処理し、曲線を三角形に分割して塗りつぶします。Google Chrome Team(2025)によると、SkiaはCPU上で最新のモバイルプロセッサ上でSVGアイコンを0.3–1.5ミリ秒でレンダリングします。
PDFドキュメントには、フォント、ベクター要素、ラスター画像、変換などの複雑なネストされたグラフィックスが含まれています。モバイルアプリケーションは、PDFKit(iOS)やPdfRenderer(Android)などのフレームワークを通じてCPU上でPDFをレンダリングします。表示精度とPDF 2.0標準のサポートには、各要素のソフトウェア処理が必要です。
モバイルプラットフォームは、ARMアーキテクチャと限られた消費電力を考慮してCPU Renderingを実装しています。AndroidとiOSでのソフトウェアレンダリングの仕組みを見てみましょう。
Android Canvasはハードウェアアクセラレーションが無効の場合、完全にCPU上で動作します。Canvasクラスには、Googleの2DライブラリであるSkiaを通じて実行されるプリミティブ描画メソッドが含まれています。SkiaはソフトウェアとGPUバックエンドをサポートし、hardwareAcceleratedフラグに基づいて切り替わります。
ソフトウェアCanvasはRAM内にBitmapを作成し、Skia Software Rendererを通じてその上にコマンドを描画し、画面に出力します。すべての操作は、最適化のためにNEON命令を使用してCPU上で実行されます。Skia Team(2025)によると、NEONアクセラレーションはブレンドとマスキング操作で40–60%の向上をもたらします。
// 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を通じて表示されます。このアプローチは、すべてのピクセルを完全に制御することが重要な透かし、グラフ、動的画像に使用されます。
Core Graphicsは、主にCPU上で動作するAppleのラスターおよびベクターグラフィックスフレームワークです。CGContextは、Appleの高度に最適化されたライブラリを使用して、ソフトウェアモードですべての描画操作を実行します。Core GraphicsはQuartz 2D(25年の歴史を持つエンジン)を駆動します。
iOSでは、Core Graphicsは結果をCore Animationに渡してGPU上でコンポジットします。Apple Engineering(2025)によると、Core GraphicsはUIKitでのUI描画の80%をCPU上で処理し、MetalコンポジットはGPU上で準備されたテクスチャを組み立てます。UIGraphicsImageRendererはCPUベースのラスター画像レンダリングのための最新のラッパーです。
CPU Renderingの最適化は、ソフトウェアレンダリングがUIフレームワークでのCPUサイクルの主要な消費者であるため、パフォーマンスにとって重要です。ソフトウェア描画を高速化する主要な方法を見てみましょう。
最も効果的な方法は、変更されていないものを再描画しないことです。コンテンツが静的であれば、BitmapまたはCGLayerに一度レンダリングし、準備された結果をコピーします。Androidでは、キャッシュされたBitmapを使用してView.setLayerType(LAYER_TYPE_SOFTWARE)を通じて実装されます。iOSでは、drawsAsynchronouslyとCALayer.shouldRasterizeを通じて実装されます。
Dirty rectanglesを使用します — 画面のどの領域が変更されたかを追跡し、それらのみを再描画します。Android ViewSystemは自動的に無効領域を計算します。iOS CALayerは再描画領域を制限するためにsetNeedsDisplayInRectを使用します。
ピクセル操作(ブレンド、マスキング)には、CPUのSIMD命令を使用します。Android SkiaはARMプロセッサに対して自動的にNEONを使用します。iOS Core GraphicsはAccelerateフレームワークを通じてベクトル化されます。Google(2025)によると、SkiaでのNEON最適化ブレンド操作はスカラーコードよりも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命令は1回の操作で16ピクセル(128ビット)を処理します。ARM Cortex-X4のパイプライン処理と組み合わせることで、ソフトウェアコピーとブレンドで毎秒最大5億ピクセルのスループットを提供します — 60 FPSのFullHD画面に十分です。
よくある質問
CPU Renderingは、プリミティブの数が少ない場合(最大500)、データ転送とシェーダコンパイルのオーバーヘッドがないため、GPUより高速です。50–100のViewを持つUI画面の場合、ソフトウェアレンダリングはGPUパイプラインよりも時間がかからないことがよくあります。
Android Viewシステムは決定論的レンダリングのためにCPU上で描画します — GPUの不正確さなしに、すべてのピクセルがコードに正確に対応します。描画後、レイヤーはGPUコンポジットのためにHWUIに渡され、CPUの精度とGPUのパフォーマンスを組み合わせます。
リアルタイム3Dグラフィックスの場合、CPU Renderingは非効率的です。GPUは毎秒1億の三角形をレンダリングしますが、CPUは500万–1000万です。例外は、決定性が速度よりも重要であるプレビューやエクスポート用の個別フレームのレンダリングです。
Androidでは、Developer OptionsのProfile GPU Renderingを使用します。iOSでは、InstrumentsのCore Animationプロファイラを使用します。16msを超える緑色のバーはCPUレンダリングの遅延を示します。AndroidマニフェストのhardwareAcceleratedフラグも確認してください。
Skiaは、Android、Chrome、Flutterで使用されるGoogleの2Dグラフィックスライブラリです。SkiaはソフトウェアとGPUバックエンドをサポートしています。CPUモードでは、NEON命令を使用して最適化されたSoftware Rendererを通じてすべての操作を実行します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。