0
\$\begingroup\$

Just found creating a material in a script for the first time would have performance impact.
(Using Unity 5.6.5f)

A very simple script for testing is to create a game object with MeshRenderer in Start(), assign a new material each time in Update(),

gameObj.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Standard"));

From Unity Profiler the first function call took much longer than following calls, the first one took 100ms and others less then 1ms.

Can someone give it an explanation? Thanks.

\$\endgroup\$
0
\$\begingroup\$

I'm not sure what kind of explanation you're hoping for here, but the gist is that this is standard "first-time setup" work.

I imagine this only happens in the editor, though I haven't verified that. Unless I'm completely misunderstanding what's being done, the property drawers don't need to be created in a built game. Perhaps try timing there to see if the issue persists.


That said, here's some more info if you're curious:

Comparing the first and second frames in the profiler, you can see that the calls under the Material constructor are quite similar. The critical difference comes in MaterialPropertyHandler.GetHandler().

First frame, that method also calls MaterialPropertyHandler.GetShaderPropertyHandler(), under which are many other calls, including a fair amount of memory allocation. (231.3KB on my machine).

A quick google search turns up what happens in GetHandler() that makes a difference:

if (MaterialPropertyHandler.s_PropertyHandlers.TryGetValue(propertyString, out materialPropertyHandler))
  return materialPropertyHandler;
materialPropertyHandler = MaterialPropertyHandler.GetShaderPropertyHandler(shader, name);

I.e., that dictionary (apparently) has to be populated the first time you create a Material. After that, it will skip the call to GetShaderPropertyHandler().

You can adjust when this happens (e.g. in Start() or Awake(), etc.) if you need to, but I don't know of any way to avoid it entirely.

\$\endgroup\$
  • \$\begingroup\$ Thanks, those extra info is really helpful and might be the reason, I checked it again and saw a function MaterialEditor.ApplyMaterialPropertyDrawers() was called each frame, it took 38ms and also 230KB memory in the first call, along with two extra function Shader.EditorLoadVariant() and Loading.ReadObject(), three calls summed up to 100ms. Following MaterialEditor.ApplyMaterialPropertyDrawers() calls only took 0.1ms, without extra function calls. \$\endgroup\$ – Arxz Aug 21 '18 at 8:37
  • \$\begingroup\$ but seems these info is at a much lower level than which showed in my Unity profiler and I didn't see MaterialPropertyHandler.GetHandler(), how can I make it show in profiler? \$\endgroup\$ – Arxz Aug 21 '18 at 8:43
  • \$\begingroup\$ @Arxz there is a Deep profile option in the profiler that should show it. \$\endgroup\$ – Uri Popov Aug 21 '18 at 8:46
  • \$\begingroup\$ Yeah, I was using the deep profiling option for this. Overkill sometimes, but useful for situations like this. \$\endgroup\$ – Chris Mills-Price Aug 21 '18 at 15:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.