The statistic clearly show a set pass call of 1. The 3 items ( the plane and 2 rocks ) are batched, according to unity. However in RenderDoc it’s clear that there are 3 calls to render all 3 meshes. Another thing I’ve noticed, at the top there are 3 write events which belong to each of these DrawIndexed calls. At first I assumed the 3 write events were because unity writes the data into a " combined " vertex buffer, but if you step trough the calls each rock and the plane are drawn in sequence, individually.
Does anyone have any insight on how to interpret this data?
I’ve seen other scenes where combined items are indeed batched and drawn in one call. But this simple setup shows a contradiction between the two stats.
SetPass, Batches, and Draw Calls are different things.
When you draw two different objects there are multiple things that have to happen that each have different of costs. Whenever you render something you actually pass the GPU a bunch of information and then issue a “draw call”, which is really just “okay GPU, render with the data I’ve already sent you.”
The three major bits of data needed for a draw call are:
The shader.
The material textures.
The material parameters (floats, matrices, etc.).
The mesh.
All of this is hidden by Unity as you just have objects in the scene, or you can explicitly say “draw this thing with these settings”, but under the hood it has to do the above steps, and more. Changing only one of those things at a time is cheaper than changing all of them, and generally changing which mesh is being used is the cheapest thing to change. So if you have a set of objects that are all the same shader, and same material, but different meshes, it can be faster to render them all back to back rather than render something else with a different shader or material in between. Also be aware that “shader” in this case is each variant of each shader pass, not each shader file. So something like the Unity Standard shader can have several passes with hundreds of variants, and to the GPU each of these are different shaders.
Changing the shader is all SetPass actually does, and batching here is a Unity specific terminology that can either mean combining meshes into one, or just rendering similar materials back to back. So to decode what the Unity stats are saying is there is only one SetPass (only one shader being used), there was 1 batch, which saved “2”. That “2” is usually understood to mean 2 draw calls, but really it means 2 full setups of the above data for a draw call and their may or may not be 3 actual draw calls.
Right, However, that does not explain the “writes”. This happens every frame I capture. So what exactly is Unity doing there? Each meshfilter on runtime shows the mesh itself is a “combined” mesh.
It is a combined mesh. I suggest you read up on DrawIndexed. Basically it allows Unity to use a single mesh, but still respect the enabled/active flags on renderer components and game objects.
I understand DrawIndexed, but I was under the impression that when unity combines the meshes it would only draw the indexed buffer that contains all 3 items.
So if the combined mesh isn’t used in rendering, what’s the point of combining them? Just sounds like unnecessary overhead for writing them.
Like I said, there’s a cost to changing the shader, parameters, and mesh. Unity is using a combined mesh and DrawIndexed so that the mesh that’s being rendered never changes, thus avoiding that cost. Instead the shader, the parameters, and the mesh are sent all at once, then DrawIndexed is used to render each section of the mesh that corresponds to the original renderer components individually to support toggling of parts on and off. Conceivably they could just render it all with one DrawIndexed call if all parts are enabled, but it might not be noticeably faster to do that, and it’s possible they could still do sorting. DrawIndexed is really, really, fast since the majority of the CPU side cost of rendering is the setup and not the actual draw.
I just realized that according to RenderDoc DrawIndexed is called with StartIndexLocation = 0 on all 3 instances. So I’m still not entirely convinced Unity is making use of the combined mesh. If it truly is one mesh then at least their starting offset should be different?
You may be right then. Certainly it “should” be working the way I described going by how Unity has said it works, but maybe they’ve changed it, or maybe you’ve found a bug!
Then perhaps the index buffers contain the offsets themselves, they are basically indices to a vertex position, right? That makes sense to me. But I can’t find a way for RenderDoc to show the combined mesh.