The Material Layer Sampler Problem

The Problem

If you make a basic layered material like this:

You would expect that the texture mask is sampled once. But its sampled for each layer because it’s a unique parameter. (I don’t talk about “Samplers” but texture lookups, you can put them to shared where they would at least not use additional “Samplers”)

You can see it in render doc it samples the texture for each mask again:

  21: sample_indexable(texture2d)(float,float,float,float) r6.xyzw, v2.xyxx, t15.xyzw, s0
  22: dp4 r1.w, r6.xyzw, cb4[1].xyzw
  23: sample_indexable(texture2d)(float,float,float,float) r6.xyzw, v2.xyxx, t16.xyzw, s0
  24: dp4 r3.w, r6.xyzw, cb4[2].xyzw
  25: sample_indexable(texture2d)(float,float,float,float) r6.xyzw, v2.xyxx, t17.xyzw, s0
  26: dp4 r4.w, r6.xyzw, cb4[3].xyzw
  27: sample_indexable(texture2d)(float,float,float,float) r6.xyzw, v2.xyxx, t18.xyzw, s0
  28: dp4 r5.w, r6.xyzw, cb4[4].xyzw

Personally I would like the option that it compiles the Texture Parameters like static ones. So that it can merge the sampling of the same ones together.
This is one of the main reason I don’t want to use the layered material system.

Quick way of seeing it

In Render Doc after you have selected the drawn mesh. Go into Pipeline State → Pixel Shader.
You can see all the resources of the drawcall. And will see that it sends duplicate resources for each Texture Parameter. (And will also sample them each)

Workarounds

Static Mask

You can use a static mask. Where you don’t expose the texture as a parameter. But this is kinda awkward. Because it’s no parameter the compiler can merge all the usages of the same Texture together.

Render Doc with static Texture:

21: sample_indexable(texture2d)(float,float,float,float) r6.xyzw, v2.xyxx, t15.xyzw, s0

Pass the mask along

You can pass the mask inside the material attributes. (in some channel you don’t need) And reuse it on higher layer blends.

Now we get the same result but it will only sample once:

Render Doc:

21: sample_indexable(texture2d)(float,float,float,float) r6.xyzw, v2.xyxx, t15.xyzw, s0

Improvements

Make it easier to share resources in the Material Layer Workflow. One of the best solutions would be to treat some parameters like global ones. (As if you would add a function to the material) Then you could check “use global parameter” and each parameter with the same name would be shared like usual. Then it would be easy to add a “mesh mask” parameter make it shared and so on each layer it would be reused. This would even improve the workflow because for baked masks I don’t need to go to each layer blend and fix it.

Are there actual Performance problems?

I don’t have done any performance testing. The impact should be pretty small on high end machines: It doesn’t add additional textures or samplers (if shared samplers is enabled on the parameter) but it does read the textures again and calculates interpolation. For example you have 5 layer masks using the same texture: so it needs to read 5 textures * 4 pixels * 4 channels. Because textures are interpolated. And to read 64 pixels again for no reason I don’t know… It hurts my soul. And is probably pretty bad for low - mid end hardware.

Docs

You can see from the official documentation that they reuse the textures. But they will be sampled multiple times. For no reason.
And the same material using the non layered workflow should be cheaper to render. Because you would just place one texture parameter for the masks but this is not possible in the layer workflow.

2 Likes

Bumping semi old thread.
Does anyone know if this has been improved/fixed?

It’d be great to be able re-use the same texture on multiple layers without having to resample it per layer.

Seems like an easy in-engine oversight and I’m hoping it got fixed/addressed in 5.4 or something.
I know lots of people say to use Shared: Wrap or Shared: Clamp. But I think OP said there was still some overhead for that?

p.s. Material Layer Sampler is such a difficult thing to talk about, since it has a name similiar to like 3 other systems and most people think you are talking about 1 of those. I blame the naming on why this feature hasn’t gained more public visibility. Though supposedly lots of AAA studios use it internally, just no one really talks about it much publically?

1 Like

Yes setting it to Shared or Clamped will still sample the texture multiple times. Just no Sampler will get used up for it.
This is again one of the things which makes it confusing to talk about. You can read above about some of the possible workarounds.
I think there might actually be some confusion in the AAA studios. I don’t think they always look into the generated shader code or understand the system fully.
It’s also probably a tiny performance impact on AAA games, but which can add up and might be a dealbreaker for mobile or VR?
The examples from Epic also have this problem.
And I don’t expect a fix anytime soon. A fix would also require a small rework of some of the systems and a good consideration of the design.

Because materials are static compiled. If you want to merge two texture samples into one it will change the compiled material. So if you expose texture parameters in two layers, they might be different per layer. And even when you set them to the same no new material will get compiled to merge the samples together, because changing a texture parameter only changes the input to the material not the generated shader code. Also if you change the tiling per layer, it can not be possible at all.

My solution for fixing this:
An option to setup shared texture sampling in the Material Layer system. Like “Brick Mask Texture” and now on each layer you can use this as an input instead. If you change the texture or tiling of this global texture sample it will be the same on each material Layer.
It would work the same as the example I showed above which “passes the mask along” but would be easier to use.

Another good workaround is to input the shared textures into the material before the material layer node. Then you can use them on each material layer.

I always felt like the material layer system is just a little bit unfinished. It’s still amazing and if you can I would use it. (For example you can just toggle/add some layers to test features.)

1 Like