How to Expose Addon Data as Global Uniforms for All Shaders?

  • leonaquitaine
  • Topic Author
More
5 months 1 week ago #1 by leonaquitaine How to Expose Addon Data as Global Uniforms for All Shaders? was created by leonaquitaine
Good morning all,

I'm developing an audio visualization addon for ReShade ( github.com/gposingway/Listeningway ); the addon analyzes audio in real time and exposes frequency band and volume data to shaders for visualization. The goal is to make this data available as global uniforms so that any shader (not just a specific one) can consume it by including a shared .fxh file.

What works:

The addon works perfectly when targeting a specific shader; the uniforms are updated and the visualization displays as expected.
The ReShade UI can see and save the values for these uniforms ( screenshot ).

What fails:

When attempting to set the uniforms globally (using find_uniform_variable("", "UniformName") and set_uniform_value_float), the data does not propagate to all shaders. The uniforms remain static or zero in shaders other than the one directly targeted.
There is no C++ API function like set_uniform_value_float("UniformName", ...) - the API only accepts a handle, not a string name.
From what I gathered, setting the uniform on the runtime should make it available to all shaders, but this does not seem to work in practice with my current implementation.

Question: What is the correct way, using the C++ Addon API, to expose addon-generated data as truly global uniforms so that any shader (with the appropriate include) can access it? Is there a way to set these uniforms globally for all effects, or is per-effect uniform setting the only reliable method? Are there any best practices or workarounds for this scenario?

Any advice or examples would be greatly appreciated!

Please Log in or Create an account to join the conversation.

  • leonaquitaine
  • Topic Author
More
5 months 1 week ago #2 by leonaquitaine Replied by leonaquitaine on topic How to Expose Addon Data as Global Uniforms for All Shaders?
I found a solution - here’s how it works:

When effects are loaded, the addon scans all loaded effects for every instance of the Listeningway_Volume and Listeningway_FreqBands uniforms using enumerate_uniform_variables, caching the handles for each found uniform. Then, whenever new audio data is available, it updates all cached uniforms with the latest values (volume and frequency bands).Does this approach look correct to others? Any feedback or edge cases I should consider?

Please Log in or Create an account to join the conversation.

  • crosire
More
5 months 1 week ago #3 by crosire Replied by crosire on topic How to Expose Addon Data as Global Uniforms for All Shaders?
'find_uniform_variable(...)' searches for a single uniform variable. Passing in no effect name for the first argument just tells it to search across all effects, but it still can just return a single uniform variable handle (as the name implies), so it will return the first one it comes across that has the specified name. If multiple effects contain a uniform variable of the same name, then which one of these variables is returned is undefined (depends on the order they got loaded).
'enumerate_uniform_variables(...)' on the other hand invokes the callback for all uniform variables and as such can also include variables from different effects that share a name. I wouldn't even worry about caching the handles, it's a reasonably fast operation, so can just do something like this to update:
runtime->enumerate_uniform_variables(nullptr, [my_value](effect_runtime *runtime, effect_uniform_variable variable, void *user_data) {
    char name[128] = "";
    runtime->get_uniform_variable_name(variable, name);
    if (std::strcmp(name, "UniformName") == 0) {
        runtime->set_uniform_value_float(variable, my_value);
    }
});

Generally the way uniform data shared across effects is provided in ReShade is not by variable name though, but rather by the use of annotations. E.g. a uniform variable of any name can request specific data via a "source" annotation, like 'uniform int blablabla < source = "framecount"; >;', which notes the uniform variable "blablabla" in that effect to receive the frame count. You'll see that pattern used in the example add-ons as well, e.g. github.com/crosire/reshade/blob/main/exa...depth_addon.cpp#L480 . It then looks something like this:
runtime->enumerate_uniform_variables(nullptr, [](effect_runtime *runtime, effect_uniform_variable variable, void *user_data) {
    char source[32];
    if (runtime->get_annotation_string_from_uniform_variable(variable, "source", source) && std::strcmp(source, "framecount") == 0) {
        runtime->set_uniform_value_int(variable, ...);
    }
});
The following user(s) said Thank You: leonaquitaine

Please Log in or Create an account to join the conversation.

  • leonaquitaine
  • Topic Author
More
5 months 1 week ago #4 by leonaquitaine Replied by leonaquitaine on topic How to Expose Addon Data as Global Uniforms for All Shaders?
This is precisely what I needed, thanks so much! Based on your advice, I refactored the uniform update logic to use enumerate_uniform_variables each frame, matching by annotation (preferred, e.g. < source = "listeningway_volume" >).
void UniformManager::update_uniforms(reshade::api::effect_runtime* runtime, float volume, const std::vector<float>& freq_bands, float beat) {    runtime->enumerate_uniform_variables(nullptr, [&](reshade::api::effect_runtime*, reshade::api::effect_uniform_variable var_handle) {
        char source[64] = "";
        bool has_source = runtime->get_annotation_string_from_uniform_variable(var_handle, "source", source);
        char name[128] = "";
        runtime->get_uniform_variable_name(var_handle, name);
        if (has_source) {
            if (strcmp(source, "listeningway_volume") == 0) {
                runtime->set_uniform_value_float(var_handle, &volume, 1);
                return;
            } else if (strcmp(source, "listeningway_freqbands") == 0) {
                if (!freq_bands.empty())
                    runtime->set_uniform_value_float(var_handle, freq_bands.data(), static_cast<uint32_t>(freq_bands.size()));
                return;
            } else if (strcmp(source, "listeningway_beat") == 0) {
                runtime->set_uniform_value_float(var_handle, &beat, 1);
                return;
            }
        }
    });
}

Best-practices, robust code is always best code. Thanks again for your time and suggestions!

Please Log in or Create an account to join the conversation.

We use cookies
We use cookies on our website. Some of them are essential for the operation of the forum. You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.