Optimizing Graphics for Mobile Platforms

Our video game development company runs independent projects, jointly creates games with the client and provides additional operational services. Expertise of our team allows us to cover all gaming platforms and develop an amazing product that matches the customer’s vision and players preferences.

From immersive apps to game worlds and 3D scenes

Our dedicated team for VR/AR/MR development, Unity production and 3D modeling & animation — with its own case studies and capability decks.

Visit the dedicated studio
Showing 1 of 1All 242 services
Optimizing Graphics for Mobile Platforms
Complex
from 3 days to 2 weeks
Frequently Asked Questions

Our competencies

What are the stages of Game Development?

Latest works

  • image_games_mortal_motors_495_0.webp
    Game development for Mortal Motors
    1420
  • image_games_a_turnbased_strategy_game_set_in_a_fantasy_setting_with_fire_and_sword_603_0.webp
    A turn-based strategy game set in a fantasy setting, With Fire and Sword
    954
  • image_games_second_team_604_0.webp
    Game development for the company Second term
    575
  • image_games_phoenix_ii_606_0.webp
    3D animation - teaser for the game Phoenix 2.
    637

On an Android mid-range device, GPU Profiler shows 18 ms per frame against a target of 16.6 ms — the game cannot hold 60 FPS. A combination of 340 draw calls, overdraw-heavy effects, and 2048×2048 textures that on screen occupy 64×64 pixels — each factor individually tolerable, together a disaster.

Why comprehensive mobile game graphics optimization requires a comprehensive approach?

Mobile GPUs are tile-based: they split a frame into tiles and render sequentially. This makes them sensitive to overdraw and fill rate. Unlike desktop immediate mode GPUs that forgive more, on mobile every extra draw call or pixel shader hits performance. We combine profiling, texture compression, batching and shader tuning into a single process — otherwise there's no result.

How to measure and reduce draw calls?

A Draw Call is a CPU command to render a group of triangles with specific settings. Each draw call requires CPU-GPU synchronization and data transfer. On mobile tile-based GPUs (PowerVR, Mali, Adreno) it's more expensive than on desktop immediate mode GPUs.

Tools: Unity Profiler (GPU Usage), Frame Debugger, and for deep analysis RenderDoc on Android or Xcode Instruments on iOS. GPU Profiler right inside the editor shows batch count and SetPass calls. A good target for mobile projects is under 100 draw calls per frame, realistic for mid-core is 150–200.

Main sources of extra draw calls:

  • Static Batching combines static objects with the same material into one mesh at scene start. Condition: objects must be marked Static in Inspector and use the same Material asset — identical settings but different Material Instance doesn't work.
  • GPU Instancing scales better with many copies of the same object (trees, rocks, enemies of one type). Dynamic Batching works automatically for small objects (under 900 vertices), but in practice it's disabled in favor of Instancing. Unity batching techniques are essential for reducing draw calls.
  • Canvas Overlay mode in uGUI: Canvas in Screen Space - Overlay renders on top of everything, and any change in any UI element marks the entire Canvas Dirty, recalculates mesh and creates a separate draw call. For UI with animated elements, always separate static and dynamic elements into different Canvases.

How do textures affect mobile game performance?

Mobile devices use Unified Memory Architecture: GPU and CPU share the same memory. 512 MB RAM is common on budget Android devices. An uncompressed RGBA32 2048×2048 texture = 16 MB. 10 such textures on a level = 160 MB just for textures.

Hardware-supported compression formats

Format Bits per pixel Support
ETC2 without alpha 4 bpp Android, iOS (via ASTC?)
ETC2 with alpha 8 bpp Android
ASTC 4×4 8 bpp iOS, Android (Adreno 400+, Mali G7x+)
ASTC 6×6 3.5 bpp iOS, Android (newer)
ASTC 8×8 2 bpp iOS, Android (high compression)
DXT5 (BC3) 8 bpp PC

ASTC is the best choice for iOS and modern Android (Adreno 400+ series, Mali G7x and above). On old Android devices with OpenGL ES 2.0, ASTC is not supported — you need ETC2 fallback. Unity allows different formats per platform via Texture Importer.

Mipmaps are mandatory for 3D objects, not needed for UI. Mipmaps add 33% size in memory, but for UI elements that always render at native resolution, it's a waste. Check via Texture Importer → Generate Mipmaps → disable for all UI sprites.

Real-world case: solving OOM on mobile devices In one project — a mobile 3D strategy — the game crashed with OOM on 512 MB RAM devices when starting a campaign. Memory Profiler showed 380 MB just for textures. Audit revealed: 60% of texture budget was taken by terrain and environment textures in RGBA32 format without compression (the developer turned off compression during prototyping and forgot to revert), another 15% — UI textures with mipmaps enabled. Solution: convert all terrain/environment to ASTC 6×6, UI to ASTC 8×8 without mipmaps, for effects with alpha — ASTC 4×4. Result: 142 MB. OOM crashes stopped, 240 MB freed for gameplay logic and audio.

Why is overdraw especially critical on mobile GPUs?

Overdraw is rendering the same pixel multiple times. Semi-transparent particles, complex post-processing effects, overlapping UI elements — all contribute to overdraw. On tile-based mobile GPUs overdraw is especially expensive: every time a tile buffer is read and written again, it's extra work.

Visualize overdraw in Unity: Scene View → Render Mode → Overdraw. White areas indicate problems. Pay special attention to particle systems — particles often render dozens of semi-transparent quads on top of each other at the same point.

For particle systems: limit Max Particles, use opaque or cutout shaders where visually acceptable (cutout is more expensive in fill rate but cheaper in overdraw depth), sort particles by Sorting Layer to minimize overlap with geometry.

For shaders: simple Unlit shaders are 3–5 times cheaper than Lit on mobile devices. For background decorations, ground shadows, billboard objects, Unlit is sufficient. Lit shader with per-pixel lighting only for close-up and key objects.

What tools to use for profiling?

Start with Unity Profiler connected to a device via USB (Build → Development Build + Autoconnect Profiler). GPU Usage Profiler shows render time by category. Frame Debugger gives a detailed breakdown of draw calls. Memory Profiler provides a memory snapshot by category.

For Android additionally: Android GPU Inspector (AGI) for Adreno devices, Mali Performance Counters for Mali GPUs. They show fill rate utilization, texture bandwidth and cache hit rate — metrics not available in Unity Profiler. Check ASTC support on a device via SystemInfo.SupportsTextureFormat(TextureFormat.ASTC_6x6).

Step-by-step optimization process for FPS optimization:

  1. Profile with Unity Profiler and Frame Debugger to identify bottlenecks.
  2. Analyze draw calls: apply static batching and GPU instancing.
  3. Optimize textures: compress with ASTC/ETC2, disable mipmaps on UI.
  4. Reduce overdraw: limit particles, use opaque shaders.
  5. Tune shaders: prefer Unlit over Lit where possible.
  6. Test on target device; repeat if needed.
Task Duration Cost (approx.)
Performance audit + report with recommendations 2–5 days $500–$1000
Texture and material optimization (single scene) 3–7 days $1000–$2000
Comprehensive graphics optimization (full project) 2–6 weeks $3000–$8000
Optimization for a specific minimum device 1–3 weeks $2000–$4000

What’s included in our optimization work (deliverables):

  • Detailed performance audit with full report and recommendations
  • Texture recompression with optimal format selection per platform
  • Batching, instancing, and shader configuration
  • Profiling and elimination of bottlenecks (draw calls, overdraw, memory)
  • Documentation of changes and access to optimized project files
  • Training session for the client's team on best practices
  • Result guarantee: FPS and stability on target devices

We have over 5 years of experience optimizing mobile games and have completed 20+ projects on Unity and Unreal Engine. Contact us for an audit of your project. Order optimization and get stable FPS on target devices.

Android Developers: ASTC texture compression - developer.android.com/games/optimize/astc

What Are the Typical Game Performance Problems and How Optimization Solves Them?

A project runs smoothly on developer devices. On a five-year-old mid-range Android, it hits 20 fps and overheats after five minutes. On iPhone 11 it maintains 60 fps, but on iPhone XR it drops in heavy scenes. We encounter this every day. Optimization is not a later task—it is an architectural decision from the first commit. With eight years of experience, we have optimized over fifty games, from hypercasual to AAA on consoles. We guarantee: after our audit, you get not just a list of problems, but a concrete plan with measurable goals and deadlines. Order a performance audit — we evaluate your project in three days and show how to reduce draw calls by 40% without losing quality.

How to Profile Game Performance? Tools and Best Practices

Before any optimization, measure. Optimization without profiling is guesswork.

Tool Purpose
Unity Profiler CPU/GPU time per system, GC allocations, audio
Frame Debugger Inspect each draw call in a frame
Memory Profiler Memory snapshot, asset dependency graph
RenderDoc Deep GPU state analysis, relevant for PC/Console
Android GPU Inspector GPU profiling on real Android devices
Xcode Instruments GPU + memory on iOS (Metal Performance HUD)
Snapdragon Profiler Qualcomm GPU—detailed shader statistics

Profile on target hardware, not in the editor. The editor adds overhead — Play Mode numbers are not representative. Distinguish between GPU and CPU bottlenecks: CPU may cause many draw calls or heavy logic, GPU may have complex shaders or overdraw. Unity Documentation: profiling on device is mandatory for mobile games. Typical profiling time for one scenario is five to eight hours, including metrics collection on three to five devices of different generations.

Additional profiling tips
  • Use the Profiler Capture tool with deep profile only when needed – it adds up to 50% overhead.
  • Run at least three captures per scenario to get reliable averages.
  • Record timeline markers for custom systems (AI, animation, network) to correlate spikes.

How Does Game Performance Optimization Reduce Draw Calls? Static Batching to SRP Batcher

A draw call is a command from CPU to GPU to “draw this.” Each call has overhead regardless of geometry complexity. On mobile, 200–300 draw calls per frame is typical. The goal is to minimize their number by combining geometry that shares the same material.

Static Batching combines stationary meshes during build. Requirement: Static flag on objects and the same material. Effective for static environments but increases memory usage – the combined mesh is stored separately. In scenes with thousands of static objects, monitor memory via Memory Profiler.

Dynamic Batching combines meshes at runtime with strict limits: fewer than 900 vertex attributes per mesh, same material and scale. In practice, it works only for small objects (particles, UI). Disabled by default in URP – replaced by SRP Batcher.

SRP Batcher is not classic batching – it optimizes CPU overhead when preparing draw calls. Instead of reloading shader uniform data each frame, SRP Batcher caches it in GPU memory and updates only when changed. Draw calls remain the same in number, but each takes less CPU time – sometimes 2–3 times less on render CPU time compared to standard batching. Requirement: shader must be compatible with SRP Batcher (declare per-object properties in UnityPerDraw CBUFFER). Standard URP Lit/Unlit shaders are compatible. Custom ones – check in Material Inspector: SRP Batcher compatible: Yes/No. To enable, ensure the SRP Batcher option is active in URP Asset, and for custom shaders use UNITY_INSTANCING_BUFFER macro and declare per-object properties in CBUFFER_START(UnityPerDraw). After enabling, the RenderLoop.Draw CPU time should decrease in Profiler.

GPU Instancing is for many copies of the same mesh with the same material (trees, grass, NPCs). It sends one draw call with an array of per-instance data. Enable on material: Enable GPU Instancing. Limitation: all instances in one batch must have the same material and mesh. Graphics.DrawMeshInstanced / Graphics.DrawMeshInstancedIndirect enable procedural rendering without GameObject overhead.

The choice of method depends on scenario. Static Batching for static environments. SRP Batcher wins in projects with many unique materials. GPU Instancing is indispensable for mass objects (forests, crowds). Dynamic Batching only for small and rare cases. In practice, we combine all methods, starting with profiling.

Method Object Type CPU Impact GPU Impact RAM Consumption
Static Batching Static Moderate reduction No change Increases
Dynamic Batching Small (≤900 verts) Reduction No change No change
SRP Batcher Any (compatible shaders) Significant reduction (2–3×) No change No change
GPU Instancing Copies of same mesh Minimal Significant reduction Slight

For more details on the technology, see Geometry instancing (Wikipedia).

Why Is Memory Optimization Critical for Mobile Games?

Mobile platforms have strict RAM limits. iOS kills apps without warning on memory pressure. Android does similarly with onLowMemory callback. Target budgets: iOS <1 GB for modern devices, <512 MB for iPhone 8/X support; Android <800 MB for broad compatibility (OS uses 400–600 MB). Typical savings after our optimization are 30–50% of RAM while maintaining quality.

Addressables and Asset Bundles: How to Stay Within Budget

Loading everything at startup is unacceptable for large projects. Addressables (a wrapper over Asset Bundles) provide addressable asynchronous asset loading. Explicit unload: Addressables.ReleaseInstance / Addressables.Release. Addressables do not automatically unload assets when objects are destroyed. A common mistake: Addressables.InstantiateAsync in a loop without Release – memory grows until crash. Reference counting: an asset is unloaded only when all its handles are freed. Architectural pattern: a service/manager holds the handle of the loaded asset and releases it during scene transitions.

Groups and Bundle Strategy: group assets by loading logic. For example, all assets of one level in one bundle, shared assets (UI, fonts) in a separate group with Prevent Updates. This strategy saves up to 30% memory.

Texture Memory: Where 70% of RAM Comes From

Textures are the main memory consumer. Analyze via Memory Profiler: All Of Memory -> Texture2D shows the heaviest textures immediately. In practice, we find textures with inflated Max Size (4096 for a mobile icon is a typical mistake). Measures: Mipmap for 3D textures (enable), for UI (disable); Streaming Mipmaps for open world – loads mip levels as camera approaches. A common problem: textures referenced by unused Materials remain in memory – Memory Profiler shows the reference chain. Remove unnecessary materials. After replacing all RGBA32 textures with ASTC 6×6 on Android, savings reach 60% without quality loss.

GC Allocations: How to Eliminate Freezes in Hot Path

C# garbage collector in Unity is stop-the-world. If heap memory is allocated per frame, GC pause causes visible freezes. Goal: zero allocations in hot path (Update, FixedUpdate, render). Typical sources: string concatenation in Update (replace with StringBuilder); LINQ in hot path (manual loops with pre-allocated lists); GetComponent<T>() every frame (cache in Awake/Start); boxing value types when passed as object parameters. After profiling with Unity Profiler, we reduce hot path allocations by 95% – freezes disappear.

How Can LOD and Culling Cut 40% of Draw Calls?

LOD Group switches to simplified geometry as the object moves away from camera. Standard for 3D environment: LOD0 (100% triangles), LOD1 (30–50%), LOD2 (10–15%), Culled. For mobile, set Culled threshold more aggressively – draw less per frame.

Occlusion Culling – Unity does not render objects behind walls. Requires baked occlusion data. For indoor scenes, reduces draw calls by 20–40%.

Frustum Culling works automatically – objects outside camera FOV are not rendered. But the draw call for the check still happens. For scenes with thousands of objects, use custom spatial partitioning (Quadtree, Octree). In one of our projects, implementing occlusion culling and LOD reduced total draw calls from 2800 to 450 on Android.

How to Maintain 72 FPS on Quest 3 with VR Optimization?

VR is a separate class of tasks. Frame rate of 72 or 90 Hz must not be violated, or motion sickness occurs. In addition to standard methods: Single Pass Instanced Rendering – renders both eyes in one pass (halves draw calls); Fixed Foveated Rendering (Quest) – reduces peripheral resolution; Late Latching (Quest 3) – updates controller position as late as possible before rendering; Dynamic Resolution in URP/HDRP – automatically lowers render resolution on fps drops. For Quest, profile via OVR Metrics Tool – displays CPU/GPU time directly in headset. After applying these methods, frame rate on Quest 2 stabilizes at 72 FPS even in scenes with 1.5 million polygons.

What Deliverables Do You Get from Game Performance Optimization? Stages and Timelines

We offer a comprehensive turnkey service. Here is exactly what you receive:

  1. Profiling report on target devices – metrics (FPS, draw calls, memory, GC) for 5–7 main scenarios. Delivery: 3–5 business days.
  2. Priority action plan – which problems are critical, which can be deferred. Priorities based on impact on gaming experience.
  3. Optimization implementation – batching, LOD, Addressables, shaders, occlusion culling. Average implementation cycle: 2–4 weeks.
  4. Re-profiling results – measured improvements. Typical FPS increase: 30–60% on mobile devices.
  5. Documentation – recommendations for maintenance and further development.
  6. Team training – how to prevent regressions. We conduct workshops on profiling and optimization.

Get a consultation – we evaluate your project for free and show the optimization potential. Contact us to learn exact timelines and details for your stack.