IPreprocessShaders is not called if Shaders are cached

I am using Shader Stripper, its rules are in Assets, and it is a Scriptable Object. If I build a project and then change Shader Stripper settings and after this build project IPreprocessShaders will not be called and cached shaders will be used. How can I trigger the call to recalculate the shaders for IPreprocessShaders to be invoked, and shaders will be stripped?

I tried modifying the shader through code, and it worked normally, but I use Addressable and it didn’t work for them. I Created an empty shader through the code, and put it in Addressable, and modified it. This caused a recalculation, but only for the group that this shader was in.

Deleting the cache of all shaders/shader variants is not an option for me, because the project is very large and the build would take too long.

You can use the Clean build option. See Unity - Manual: Incremental build pipeline

I tried Clean build it that way it didn’t work for me.
OnProcessShader started to be called and the stripper seemed to work, but nothing changed in the build.

  1. I used Shader Stripper to remove all shaders/shader variants, built the build, everything was magenta. 2
  2. Then i turned off Shader Stripper, built the build again, everything was still in magenta.
  3. Then I changed the shader and built the build, and only then the settings were applied and all the materials appeared.

I don’t really know what Shader Stripper is. I’m just saying that those callbacks are only called when either something changes in the build, or if one does a clean build.

Shader Stripper is an implementation of IPreprocessShaders interface, it discards some shader/shader variants by condition.

public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data)
        {
            if (!Enabled)
                Return;

            for (int i = 0; i < Strippers.Count; ++i)
            {
                ShaderStripperBase s = Strippers[i];
                if (!s.active)
                    continue;
                s.Strip(shader, snippet, data);
                if (data.Count == 0)
                    break;
            }
        }

Although it is called in case of Clean Build, and works correctly, discarding shaders by the new condition, for some reason old cached shaders still get into the build.

Is there any way to trigger the event that something has changed, just as it happens when shaders are changed, because in this case everything works correctly.

How exactly do you determine that?

  1. I make the shader stripper cut off part of the shaders, then build the build to see the magenta in the build.
  2. Then I turn off the stripper or make it not to strip shaders, and build again build again. And I see the same magenta.
  3. After that I already change the shader manually, and when I then build the build I have magenta disappears, because the stripper settings are just now being applied.

From this I assume that it takes cached, since I changed the settings in the console I saw that they applied. But in the build as was magenta and remained, although it should have disappeared.

And I repeat the question is there another way to call the same trigger as when changing shaders. Because even if in Clean build will work in my case to use it will not be possible.

Please try logging whether the settings are correct in the OnProcessShader callback.

Changing shaders (or touching any other asset) invalidates the cached build data. The effect should be exactly the same as when doing a clean build.

It doesn’t work for me when using Addressable. When I modify a shader that is outside of Addresable, the cache does not change for them.
If I put a shader in an Addressable group and modify it, it updates all shaders in that group. But all other groups use the old cache.
Is it possible to somehow trigger for Addresable completely, not just for a specific group?

I checked, it’s one more time. Both OnProcessShader and Shader Stripper work and settings are applied with Clean Build if Shader is in the project.
But in my case the shaders are in Addressable. And Addressable is not affected. And as I understood it is in them that the shader cache is packed.
As I wrote above, the stripper settings were applied only when changing a shader that is in Addressable, and then only to the group it is in.

Ah, I think that’s the root cause. The “do a clean build” option is for the assets outside of addressables.
Let me ask internally whether there’s an option to do the same for addressables.

You could try going down the following path:

  1. Window > Asset Management > Addressables > Groups
  2. Build > Clear Build Cache > All
    Please check if doing this triggers the stripping script correctly.

Yes, it works for me but.

Can I not completely clear the cache, but only for the shaders? (Also as it happens when changing them).

CI is used for builds, what is the correct way to call cache scrubbing through a script for Addressable, similar to what you wrote (or only for shaders if possible).

I am currently doing it this way and it works for me but maybe I have overlooked something and there is a better way to do it.

    Addressables.ClearDependencyCacheAsync(Addressables.ResourceLocators);
    BuildCache.PurgeCache(false); // Clean Addressable Cache
                
    Shader shader = Shader.Find(SHADER_NAME);
    ModifyShader(shader); // Clean Resources Shader Cache
1 Like

I don’t think it’s possible.

Why is this needed exactly? I think it should work without this part, too.

This clears the cache for shaders that are in Addressable, but does not clear for those that are in Resources or on a scene that is added to Scene In Build.

This dirties the shader that is in Resources forcing you to scrub the cache for them too.

I understand what it’s doing, I don’t think modifying the shader is required.
You only need to make sure you’re doing a clean build.

This is actually a bug in Unity’s Asset Bundle system itself. We ran into it too, and the only reliable way around it was to have our build machine totally delete Library between builds.