Compare submitted versus visible primitives — a visible ratio far below 50% points at unsplit large models — then break Shader Cycles into arithmetic, interpolator, load-store, and texture to find which unit is the actual bottleneck.
A GPU-heavy scene usually traces back to one of two sources: too many primitives submitted for rendering, or shaders that cost too many cycles per pixel. Both end in the same symptoms — heat, throttling, dropped frames — but the fixes are completely different, and optimizing the wrong one changes nothing.
GameOptim GOT Online's Mali GPU Counter module now reports both. GPU primitives data shows how many triangles reach the GPU and how many survive culling, which separates "the scene genuinely has too much geometry" from "the scene submits geometry it then throws away." GPU Shader Cycles is now broken into four sub-counters, so you can see whether math, interpolation, register access, or texture work dominates. This article explains how to read both, and the 50% rule that turns primitive counts into a concrete diagnosis.
Summary
- GPU pressure has two main measurable sources: submitted primitives and shader complexity. Each now has its own counter in the Mali GPU Counter module.
- Total primitives is roughly equal to the engine-side rendered face count; visible primitives are the triangles that survive frustum and backface culling on the GPU.
- In a 3D scene the visible ratio should be near or above 50%, because for most models about half the triangles are culled by facing direction. A much lower ratio at certain camera angles indicates large-area models (terrain, big buildings) that were never split.
- Shader Cycles splits into Arithmetic, Interpolator, LoadStore, and Texture — the dominant category tells you which shader work is the bottleneck.
- Excessive primitive submission costs bandwidth and power even when the triangles are culled — culling should happen on the CPU side before submission.
What Is the Core Problem?
Rendered faces are one of the primary sources of GPU pressure. The Triangle metric in Overview mode already shows which scenes carry the most rendered faces, but it cannot tell you why the count is high. High face counts come from two very different situations:
- Models are genuinely complex. Dense character or prop meshes push the face count up wherever they appear.
- Large-area models were never split. Terrain and big buildings can have few faces inside the view frustum while still submitting a huge number of faces to the GPU, because the whole mesh is submitted before per-triangle culling runs.
Situation 1 is well understood; situation 2 is easy to miss, because the visible scene looks sparse while the GPU still processes everything. The new GPU primitives data exists to expose exactly this case.
Why Do Invisible Triangles Still Cost the GPU Time?
Culling happens after submission. The engine hands the GPU a batch of primitives; the GPU then discards triangles outside the view frustum and triangles facing away from the camera. The discarded triangles cost bandwidth and power during submission and processing, even though they never produce pixels.
This is why the primitive counters distinguish two numbers:
| Counter | Definition | What it tells you |
|---|---|---|
| Total primitives | All primitives submitted to the GPU; basically equal to the engine-side rendered face count | Whether the scene's overall face budget is reasonable |
| Visible primitives | Triangles remaining after GPU-side culling that actually participate in rendering | How much of the submission was wasted |
Visible primitives exclude triangles culled for being outside the view frustum and triangles culled by facing direction. The gap between total and visible is work the GPU did for nothing.
How Can You Tell Whether Triangle Submission Is the Problem?
Use the visible-to-total ratio, and read it per camera angle:
- Ratio near or above 50% is the expected case in a 3D scene — for most models, roughly half the triangles are backface-culled. The geometry budget is behaving normally.
- Ratio very low at specific camera angles is the diagnostic signal for unsplit large-area models. When terrain or a large building dominates the submission but most of it gets culled, the visible ratio collapses at the angles where that mesh fills the submission.
When you find such an angle, inspect the large-area models submitted to the GPU at that angle — those are the concrete optimization targets.
Two supporting readings strengthen the diagnosis:
- Total primitives lets you sanity-check the engine's rendered face count from the GPU side and judge whether the budget itself is reasonable.
- Excessive primitive processing also loads bandwidth and power, so a submission problem can show up as heat and battery drain before it shows up as frame time.
Which Shader Unit Is the Bottleneck?
High shader complexity is one of the main causes of GPU pressure, and some content is especially prone to it: post-processing, large terrain, water, character models, and particle effects. The Shader Cycles counter shows the cycles the GPU spends on shader processing overall — but the total alone does not tell you what to change.
The four sub-counters split that total by work type:
| Sub-counter | What it covers |
|---|---|
| Shader Arithmetic Cycles | Math computation |
| Shader Interpolator Cycles | Vertex-to-pixel interpolation |
| Shader LoadStore Cycles | Register reads |
| Shader Texture Cycles | Texture processing |
Reading the breakdown converts "the shaders are expensive" into "the expense is concentrated in X." In a high-complexity scene, whichever category dominates is the unit to investigate — a shader-heavy scene dominated by texture cycles needs different attention than one dominated by arithmetic.
What Should You Check First?
- Open the Triangle metric and shortlist scenes with high rendered-face counts. This narrows where to look before reading any GPU counter.
- Check total versus visible primitives in those scenes. A healthy ratio sits near or above 50%; a collapsed ratio at specific angles points at unsplit large-area models.
- Identify the angle and the model. If the ratio is low, find which terrain or building mesh dominates submission at that camera angle.
- Open the Shader Cycles breakdown for the same scenes. Compare Arithmetic, Interpolator, LoadStore, and Texture to find the dominant unit.
- Correlate with content type. Post-processing, terrain, water, characters, and particles are the usual sources of high shader complexity — check whether the dominant cycle category matches the content in the scene.
- Re-measure after changes with the same counters, since both primitive ratio and cycle breakdown respond to specific fixes.
What Should You Optimize?
Match the fix to the diagnosis:
- Genuinely complex models → apply LOD or HLOD to simplify distant versions without visibly hurting quality. This is the standard lever for situation 1.
- Unsplit large-area models → split terrain and large buildings so that submission aligns with what the view frustum can actually contain. This is the fix for situation 2, and the visible-ratio collapse is what identifies it.
- Excessive submission overall → complete culling on the CPU side and reduce the primitive count sent to the GPU, because culled triangles still cost bandwidth and power.
- Shader complexity → use the dominant cycle category to target the investigation: arithmetic-heavy shaders need math reduction, texture-dominated shaders point at texture-heavy shading, and so on. The breakdown narrows where to look; it does not replace reading the shader itself.
- Memory that is not resources or Mono → if Unity memory runs high while mainstream resources and Mono both look normal, check AssetBundle resident memory in Overview's Resource mode. When residency is large, adjusting the caching strategy to reduce resident bundles lowers Unity memory.
What Should You Avoid?
- Do not judge the geometry budget by visible primitives alone. Total submission drives bandwidth and power; a scene can look cheap on visible triangles while wasting both on culled ones.
- Do not read a low visible ratio as overdraw. It is the opposite failure: too much submitted geometry that gets culled. The fix is model splitting or CPU-side culling, not pixel-cost reduction.
- Do not apply LOD where splitting is the real fix. LOD simplifies distant complex models; it does not stop a single huge terrain mesh from being submitted whole.
- Do not treat total Shader Cycles as an action item. Without the four-way breakdown you cannot tell which unit to work on.
- Do not chase shader fixes when the pressure is primitive-driven. Shader cost and primitive cost are independent; confirm which counter is elevated before editing either.
Practical Recommendations
| Problem | What to inspect | How to judge | What to change | What to re-measure |
|---|---|---|---|---|
| Face count high in some scenes | Total vs visible primitives | Ratio far below 50% at specific angles | Split the large-area model submitted at those angles | Visible ratio at the same angles |
| Dense models everywhere | Triangle metric + total primitives | Total primitives high, ratio near 50% | LOD/HLOD for distant versions | Total primitives per scene |
| GPU hot or draining fast | Total primitives + bandwidth/power signals | High submission with heavy culling | CPU-side culling before submission | Total primitives and thermal data |
| Shader cost dominates | Four Shader Cycle categories | One category clearly dominates | Target that unit's shading work | Shader Cycles breakdown |
| Unity memory high, resources and Mono normal | AssetBundle resident info (Resource mode) | Resident bundles large | Adjust caching strategy | Unity memory and resident count |
What Else Did This Update Change?
Three smaller refinements round out the release:
- Temperature display. The hardware info section of Overview mode now shows CPU temperature, GPU temperature, and battery temperature, which helps locate why a device is heating up — useful when you need to confirm that GPU pressure is showing up as real heat.
- Timeline thread names. Timeline now labels threads such as the main thread and rendering thread, so multi-thread analysis no longer requires guessing which row is which.
- AssetBundle resident info. Covered above: it closes the diagnostic gap when Unity memory is high but neither mainstream resources nor Mono explain it.
Key Takeaways
- Total primitives ≈ engine-side rendered face count; visible primitives = triangles surviving frustum and backface culling. The gap between them is wasted GPU work.
- A visible ratio near or above 50% is expected in 3D scenes; a much lower ratio at specific angles identifies unsplit terrain or large buildings.
- Culling belongs on the CPU side, because submitted-but-culled triangles still cost bandwidth and power.
- Shader Cycles breaks into Arithmetic, Interpolator, LoadStore, and Texture — the dominant category is the shader bottleneck to investigate.
- AssetBundle resident memory explains Unity memory growth that resources and Mono do not.
FAQ
What is the difference between total primitives and visible primitives?
Total primitives are everything submitted to the GPU, roughly equal to the engine's rendered face count. Visible primitives are the triangles left after GPU-side frustum and backface culling that actually render.
Why is a 50% visible ratio considered normal?
For most models, about half the triangles face away from the camera and are culled by facing direction. In a 3D scene the visible count therefore lands near or above half the submitted count when geometry is well organized.
My scene looks empty but the GPU is busy. What does that mean?
Check the visible-to-total primitive ratio. A very low ratio at certain angles means large-area models such as terrain or buildings are being submitted whole and then mostly culled — split those models rather than optimizing pixels.
What are the four Shader Cycle categories?
Arithmetic Cycles cover math computation, Interpolator Cycles cover vertex-to-pixel interpolation, LoadStore Cycles cover register reads, and Texture Cycles cover texture processing. The dominant one identifies which shader work is the bottleneck.
Unity memory is high, but resources and Mono look normal. What should I check?
Look at AssetBundle resident memory in Overview's Resource mode. If residency is large, optimizing the caching strategy to reduce resident bundles will lower Unity memory.
Top comments (0)