Hot reload shader, am I doing it wrong?

I have been unable to see the changes to my post processing shader without doing a shader.reload() in the PostProcessEffect script.

    public override void OnEnable()
    {
#if FLAX_EDITOR
        shader?.Reload(); 
#endif
    }

I can also manually reload it in the editor or simply reload the project, if not I get the old version of the shader. Which is a bit weird, because double clicking on the shaders flax file under content shows me the updated version even without a reload. So apparently my changes were picked up and compiled to the .flax file.

Reloading it in the code, as shown above, when in editor mode works, but it seems like an ugly hack. Is this a bug in Flax or am I doing it wrong?

Using Flax 1.10 on Windows 11

I have been testing this some more, and unfortunately the reload hack does not work when developing compute shaders. If I try to change a compute shader, even the smallest way, and recompile, I get some errors like

[ 00:14:22.928 ]: [Error] Failed to compile 'Compute'. ...ComputeShaderTest\Compute(22,32): error X3000: syntax error: unexpected end of file
[ 00:14:22.928 ]: [Error] Failed to compile 'CS_Main'
[ 00:14:22.928 ]: [Error] Shader compilation 'Compute' failed (profile: DirectX SM5)
[ 00:14:22.928 ]: [Error] Source: ...ComputeShaderTest/Cache/Shaders/Source/Compute.hlsl
[ 00:14:22.928 ]: [Error] Failed to compile shader 'FlaxEngine.Shader, 000002bc341dfc220000004300000065, ...ComputeShaderTest/Content/shaders/Compute.flax'
[ 00:14:22.928 ]: [Error] Cannot load 'FlaxEngine.Shader, 000002bc341dfc220000004300000065, ...ComputeShaderTest/Content/shaders/Compute.flax' shader cache.
[ 00:14:22.928 ]: [Error] Loading asset 'FlaxEngine.Shader, 000002bc341dfc220000004300000065, ...ComputeShaderTest/Content/shaders/Compute.flax' result: Failed.

In real there are no errors in the shader though. If I quit the editor and restart the project, the compute shader will be compiled as expected without errors, and the changes takes effect as expected.

This means that currently the only way I can develop a compute shader seems by doing the shader edits, then quit the editor, reload the project and test it.

Is this a known issue, or am I doing something wrong?

The test compute shader is quite basic:

#include "./Flax/Common.hlsl"

META_CB_BEGIN(0, Data)
float Brightness;
float3 _pad; // 16-byte row
META_CB_END;

Texture2D              Input  : register(t0);
RWTexture2D<float4>    Output : register(u0);

META_CS(true, FEATURE_LEVEL_SM5)
[numthreads(8, 8, 1)]
void CS_Main(uint3 id : SV_DispatchThreadID)
{
    uint2 size;
    Output.GetDimensions(size.x, size.y);
    if (id.x >= size.x || id.y >= size.y)
        return;

    float4 c = Input.Load(int3(id.xy, 0));
    c.rgb *= Brightness;
    Output[id.xy] = saturate(c);
}

And the C#

using System;
using System.Runtime.InteropServices;
using FlaxEngine;

public sealed class ComputeRenderer : PostProcessEffect
{
    [StructLayout(LayoutKind.Sequential)]
    private struct Data
    {
        public float Brightness;
        public Float3 Pad; // matches float3 _pad
    }

    [Limit(0.0f, 4.0f, 0.01f)]
    public float brightness = 1.0f;

    public Shader shader;

    private bool _hasCompute;

    public override void OnEnable()
    {
        #if FLAX_EDITOR
            shader?.Reload();
        #endif
        _hasCompute = GPUDevice.Instance.Limits.HasCompute;
        MainRenderTask.Instance.AddCustomPostFx(this);
    }

    public override void OnDisable()
    {
        MainRenderTask.Instance?.RemoveCustomPostFx(this);
    }

    public override bool CanRender()
    {
        return base.CanRender() && _hasCompute && shader && shader.IsLoaded;
    }

    public override unsafe void Render(GPUContext context, ref RenderContext renderContext, GPUTexture input, GPUTexture output)
    {
        nint cb = shader.GPU.GetCB(0);
        if (cb != IntPtr.Zero)
        {
            Data data;
            data.Brightness = brightness;
            data.Pad = Float3.Zero;
            context.UpdateCB(cb, new IntPtr(&data));
            context.BindCB(0, cb);
        }

        GPUTextureDescription desc = input.Description;
        desc.Flags = GPUTextureFlags.UnorderedAccess | GPUTextureFlags.ShaderResource | GPUTextureFlags.RenderTarget;
        GPUTexture temp = RenderTargetPool.Get(ref desc);

        context.BindSR(0, input);
        context.BindUA(0, temp.View());

        nint cs = shader.GPU.GetCS("CS_Main");
        uint groupsX = (uint)((output.Width  + 7) / 8);
        uint groupsY = (uint)((output.Height + 7) / 8);
        context.Dispatch(cs, groupsX, groupsY, 1);

        context.ResetUA();
        context.ResetSR();

        context.Draw(output, temp);
        RenderTargetPool.Release(temp);
    }
}

On some Windows PCs the file watcher service we use to track shader changes was not working correctly. Does the hot-reload work for C# scripts in Editor? We could impl manual shader reload button in Editor if needed.

1 Like

Thank you for your reply. Yes, regular c# script editing works fine. Maybe Hot Reload is the wrong term. I have not tried to edit while running the player, but stopping the player, editing c# and playing works as expected.

Seems the problem is specifically with shaders, and very serious with compute shaders. Not sure how to work around it now, as my game uses a custom renderer that has to be written in a compute shader to be fast enough for real time rendering. And quitting the editor every time I change the code is quite slow :sweat_smile:

I’m using windows 11, with all the latest patches. AMD cpu, 5090 rtx.

So, I found some more details. It looks like the compiler is trying to compile

ComputeShaderTest\Cache\Shaders\Source\Compute.hlsl

And complains " error X3000: syntax error: unexpected end of file"

Now, I opened this file and it reads

#include "./Flax/Common.hlsl"

META_CB_BEGIN(0, Data)
float Brightness;
float3 _pad; // 16-byte row
META_CB_END;

Texture2D              Input  : register(t0);
RWTexture2D<float4>    Output : register(u0);

META_CS(true, FEATURE_LEVEL_SM5)
[numthreads(8, 8, 1)]
void CS_Main(uint3 id : SV_DispatchThreadID)
{
    uint2 size;
    Output.GetDimensions(size.x, size.y);
    if (id.x >= size.x || id.y >= size.y)
        return;

    float4 c = Input.Load(int3(id.xy, 0));
    c.rgb *= Brightness*100.0;
    Output[id.xy] = saturate(

So, it is truly cut off at the end. the source

ComputeShaderTest\Source\Shaders\Compute.shader

contains

#include "./Flax/Common.hlsl"

META_CB_BEGIN(0, Data)
float Brightness;
float3 _pad; // 16-byte row
META_CB_END;

Texture2D              Input  : register(t0);
RWTexture2D<float4>    Output : register(u0);

META_CS(true, FEATURE_LEVEL_SM5)
[numthreads(8, 8, 1)]
void CS_Main(uint3 id : SV_DispatchThreadID)
{
    uint2 size;
    Output.GetDimensions(size.x, size.y);
    if (id.x >= size.x || id.y >= size.y)
        return;

    float4 c = Input.Load(int3(id.xy, 0));
    c.rgb *= Brightness*100.0;
    Output[id.xy] = saturate(c);
}

As expected. So, it looks like the code that copies the shader to the cache somehow cuts the end of the file? Could it be a file buffer that was not properly closed after saving the file?

The truncated file seems to always be 529 bytes, so padding with loads of comments in the end also doesnt work. I also tried to open the cache hlsl and copy in the full shader, but no luck.

A weird thing is that if I reload the project and the shader is compiled propery the cache hlsl is still truncated, but somehow that doesnt matter the first time the project opens?

I cant make sense of it or find any viable workaround except reloading the project. I also tried to “Reimport” the shader, no luck.

Could you attach both .shader and .flax files you have on your drive? I can investigate and fix this issue.

Thanks, the two files are here:

That’s weird. I tried those files and hot-reload works for me. Source file encoding is ok so I don’t know what’s going on. You could send the log file, maybe I’ll spot sth there.

Sure, I dont mind share the entire project with you, logs and all, it is just a compute shader test:

To recreate the problem I see here, simply open the project and do any minimal change to ComputeShaderTest\Source\Shaders\Compute.shader, like

c.rgb *= Brightness;
to
c.rgb *= Brightness*100.0;

and on my system this will trigger the issue.

Using Flax 1.10, dot net version 9.0.302, nVidia driver 577.00

I just tried this project on another computer with completely different hardware, and the same thing happened there. So, seems it is not hardware based at least or related to one specific computer configuration.

Thanks, I tried to reproduce it but didn’t get anything solid to fix on. Will try again later.

1 Like

Thanks, could it be that you have some hardcoded paths to resources on your development computer? Just a blind guess really. I did notice some crash logs had local paths from your user baked in, although not related to this specific case. Could be worth it to try on a blank computer without anything except the bare minimum requirements for running Flax, thats what I did for my last test.