Providing game data to ReShade
- doodlum
-
Topic Author
Right now, any game render target could be provided to ReShade, as well as the main camera information (view, position, whatever), motion vectors, normals and specular.
The lighting and weather information, game tonemapping/color correction parameters, and ENB variables can be provided, perhaps as constant buffers?
The world cubemap (the sky + lod) should be possible to provide. For another project I want to cache light source information, so that might be possible alongside the shadow map. I don't know if any of that's useful though.
Information about how best to provide these bits of data would be appreciated. These are also D3D11 resources (the render targets) although I guess I can just capture them via ReShade if they aren't compatible.
What actually are the render effect arguments? I don't really understand why there are two RTVs. Can they be given HDR buffers?
Please Log in or Create an account to join the conversation.
- crosire
-
There are various ways to choose which effect variables should be updated, e.g. find those with a fixed name, or with a specific annotation on them, ...
For uniform variables for example, in ReShade it's common practise to have them ask for specific data via a "source" annotation (e.g. "uniform MyVarName < source = "fill_this_with_x";" in the ReShade FX effect code), so in an add-on you would then enumerate all uniform variables, filter them by those which have that annotation set to "fill_this_with_x" and update those with the appropriate data, like so (see also crosire.github.io/reshade-docs/structres...9781b8f0a3f2eac4209a ):
reshade::api::effect_runtime *runtime = ...;
float example_vector_to_provide_to_effects[3] = { x, y, z };
runtime->enumerate_uniform_variables(nullptr, [](reshade::api::effect_runtime *runtime, reshade::api::effect_uniform_variable variable) {
char annotation_value[32];
if (runtime->get_annotation_string_from_uniform_variable(variable, "source", annotation_value))
{
if (strcmp(annotation_value, "fill_this_with_x") == 0)
{
runtime->set_uniform_value_float(variable, example_vector_to_provide_to_effects, 3);
}
}
});
reshade::api::effect_runtime *runtime = ...;
float width = ..., height = ...;
runtime->enumerate_uniform_variables(nullptr, [](effect_runtime *runtime, effect_uniform_variable variable) {
char variable_name[32];
if (runtime->get_uniform_variable_name(variable, variable_name))
{
if (strcmp(variable_name, "ScreenSize") == 0)
{
runtime->set_uniform_value_float(variable, width, 1.0f / width, width / height, height / width);
}
}
});
Textures are handled a bit different, since ReShade FX has explicit language syntax to specify that a texture should come from an external source (via "texture MyVarName : MY_TEXTURE_SEMANTIC;", where "MY_TEXTURE_SEMANTIC" describes what that texture should be filled with, similar to "COLOR" and "DEPTH" ReShade already provides). As such there is a special method "reshade::api::effect_runtime::update_texture_bindings()" to automatically update all texture variables with a specific semantic to a texture of your choosing (see also crosire.github.io/reshade-docs/structres...62e2e9d5d5090e495cca ):
reshade::api::effect_runtime *runtime = ...;
reshade::api::resource_view shader_resource_view = ...; // This is a SRV to the texture you want to use. In case of D3D11, "reshade::api::resource_view" is equivalent to "ID3D11ShaderResourceView", so if you already have a SRV to the texture can just reinterpret_cast that "ID3D11ShaderResourceView" pointer to "reshade::api::resource_view" and use it here directly. Otherwise can use "reshade::api::device::create_resource_view" or "ID3D11Device::CreateShaderResourceView" to create one for the texture in question.
reshade::api::resource_view srgb_shader_resource_view = ...; // If the texture has a format that supports sRGB, ideally provide one SRV with the non-sRGB format variant and one with, so that the "SRGBTexture" sampler state in ReShade FX works. Otherwise just leave this zero.
runtime->update_texture_bindings("MY_TEXTURE_SEMANTIC", shader_resource_view, srgb_shader_resource_view);
Now as for "reshade::api::effect_runtime::render_effects()", the RTVs provided to that function are what ReShade will consider the "default backbuffer" while rendering. Meaning any passes that do not have a render target specified in ReShade FX effect code will end up in those RTVs (the former when the "SRGBWriteEnable" pass state is false, the latter when it is true), plus ReShade will automatically copy the data in those RTVs and make it available to textures with the "COLOR" semantic (like the commonly used ReShade::BackBuffer specified in ReShade.fxh). In case of D3D11 "reshade::api::resource_view" is equivalent to "ID3D11RenderTargetView" in this case, so if you already have the appropriate render target pointer, can reinterpret_cast them and pass directly. The format of these RTVs doesn't matter, they can be given HDR buffers, yes, ReShade will deal with that. The only thing ReShade expects is that these have the same width and height as the swapchain, otherwise effects may behave wrong (since "BUFFER_WIDTH" and "BUFFER_HEIGHT" in ReShade FX are not updated, see also crosire.github.io/reshade-docs/structres...5dacc2fdc84b1eed47c9 ).
In general I really encourage checking out crosire.github.io/reshade-docs/structres...effect__runtime.html to get a feel for all the methods available to communicate with the ReShade effect runtime.
Please Log in or Create an account to join the conversation.
- crosire
-
Note: "update_texture_bindings" and "set_preprocessor_definition" are expensive operations (the former synchronizes CPU/GPU, the later recompiles all effects), so do not call them every frame, but only when things change!!
Please Log in or Create an account to join the conversation.
- doodlum
-
Topic Author
Similarly to the annotations you referenced, would it be possible to have annotations which a shader can use to specify where it's ideally executed? It looks like to do so, I'd have to takeover the rendering of specific shaders. It would be cool if that for any game with "extended" support, shaders could declare where they would prefer to be run, such as before transparency. My understanding is that to render at unique points, users have to disable the shader in the main reshade window and enable it with custom UI (i.e. groups)
Please Log in or Create an account to join the conversation.
- crosire
-
So an add-on that wants to group effects into groups that can be rendered independently at different points would already make the ReShade user interface for effect selection moot, and would require an interface to configure of its own. At that point it's easier to just replace the effect rendering loop in ReShade entirely and ignore whatever is configured in the main ReShade window, hence why there is only an API to render techniques individually ("reshade::api::effect_runtime::render_technique()", to find out which techniques exist would use "reshade::api::effect_runtime::enumerate_techniques()"), which can be used to replace what ReShade does.
Please Log in or Create an account to join the conversation.
- doodlum
-
Topic Author
reshade::api::resource_view srgb_shader_resource_view = (reshade::api::resource_view)(int64_t)0;
runtime->update_texture_bindings(RTNames[n], shader_resource_view, srgb_shader_resource_view);
So far I've ended up with this. Reinterpret cast just does not work, the compiler complains. I'm assuming it is just a pointer.
I don't understand how I assign a namespace to the texture, or if it already exists.
Please Log in or Create an account to join the conversation.
- crosire
-
ID3D11ShaderResourceView *d3d_srv = ...;
reshade::api::resource_view reshade_srv = { reinterpret_cast<uintptr_t>(d3d_srv) };
runtime->update_texture_bindings("BLUB", reshade_srv, reshade::api::resource_view { 0 });
Don't pass in a ID3D11RenderTargetView into "update_texture_bindings"! It specifically requires a SRV rather than a RTV.
I'm not sure what you mean by namespace. The string you pass to "update_texture_bindings" is the semantic by which you would reference the texture in an effect. E.g. "update_texture_bindings("BLUB", ...)" in add-on => "texture WhatEverVariableNameYouWant : BLUB;" in ReShade FX.
Please Log in or Create an account to join the conversation.
- doodlum
-
Topic Author
.. I got confused about the RTVs vs SRVs , assuming ReShade just does something to the RTV to make a new SRV. I was testing with SRVs though, hence my other post.
Please Log in or Create an account to join the conversation.
- doodlum
-
Topic Author
My assumption is that ReShade backs up the current state, and will execute render_technique at any point.
Right now I am doing runtime->render_technique(technique, cmd_list, rtv[0]) within on_bind_render_targets_and_depth_stencil.
I don't really understand command lists. Is it correct that I use the one provided by on_bind_render_targets_and_depth_stencil? Does it matter if I use the one there, or get_immediate_command_list()?
If none of these are the issue, then the issue is presumably that this game shader is copying from other textures, into the render target. In that case, I'm using the wrong render target and just need to use the input texture's render target
Please Log in or Create an account to join the conversation.
- doodlum
-
Topic Author
streamable.com/fdu280
Pre-transparency is now functional. I used runtime->get_command_queue()->get_immediate_command_list() and a function to search for an SRV's RTV.
Please Log in or Create an account to join the conversation.
- crosire
-
ReShade does backup/restore state in "render_technique" in case of D3D11, so you are safe there (it does not do so in D3D12 due to massive overhead and having multiple command lists making it less of an issue).
Please Log in or Create an account to join the conversation.
- doodlum
-
Topic Author
It seems a bit wasteful otherwise because I already have structs I could directly send over.
it looks like set_uniform_value_float might be able to? But I'm unsure how that would look in ReShade, i.e. if each variable can have a name and be size float4. Some are also matrixes (view proj).
Ideally I could directly provide the constant buffer which already exists.
Please Log in or Create an account to join the conversation.
- crosire
-
Please Log in or Create an account to join the conversation.
- doodlum
-
Topic Author
Edit: On DX11 no matter what, there will be a black texture output and nothing else, although the ReShade UI will show. Using the example code.
Please Log in or Create an account to join the conversation.
- crosire
-
For a somewhat complete example doing this (though a bit of a headbender to understand by itself, so I hope the previous explanation of what needs to be done helps) I'd take a look at alex1333's add-on (which allows rendering effects after the game has rendered something with a specific shader identified with Otis' shader toggler): github.com/4lex4nder/ReshadeEffectShader...ng/src/Main.cpp#L604 .
The reason this is not done by ReShade is that keeping track of all state has more overhead than e.g. in D3D11, where the runtime does that already anyway and lets one query it, and I don't want users to have to always pay for that overhead unless it's needed.
Please Log in or Create an account to join the conversation.
- crosire
-
Please Log in or Create an account to join the conversation.
- doodlum
-
Topic Author
Please Log in or Create an account to join the conversation.
- crosire
-
Simply add state_tracking.cpp/hpp to your code and call "register_state_tracking()" in DllMain. Then can get the current state of a command list at any time via "cmd_list->get_private_data<state_block>();" and e.g. re-apply that state by calling "state_block.apply(cmd_list);".
Feel free to take that a base and improve upon it

Please Log in or Create an account to join the conversation.
- doodlum
-
Topic Author
I released a witcher 3 helper using it, so we can see what users dig up in terms of issues with these kinds of edits.
One thing I've seen so far is that the depth buffer breaks in a very strange way, where displaydepth shader seems to zoom into the top left corner, and doesn't split the image into normals and depth (only zoomed into normals) when looking into the sun. I know almost nothing about graphics programming so I guess perhaps the depth buffer is being used in another command lists for occlusion tests for sunrays or something.
Additionally, the gamma of the image is different to what reshade is happy with. This seems to be the same issue that the fo4 helper had. For this helper, I wrote a little shader Remap.fx which automatically runs before and after render_effects which converts from linear to sRGB and back. No idea how this would impact HDR monitors. I don't really understand the difference between a raw rtv and an rtv with srgb.
Edit: Seems that depth only has an issue on D3D11. Not too big of a deal then.
Edit: Is there a way to render before a shader with your methods? When I tried before (d3d11, singlethreaded) I ran into issues with creating RTVs from the SRV.
Please Log in or Create an account to join the conversation.
- crosire
-
E.g. if the target texture is of format "r8g8b8a8", the first RTV for that texture has to be of format "r8g8b8a8_unorm" and the second RTV for that texture has to be of format "r8g8b8a8_unorm_srgb". Either the game already has these lying around somewhere, or one needs to create them (the add-on API contains the utility function "format_to_default_typed" which can be helpful to translate the format as needed):
reshade::api::resource target_texture = ...;
reshade::api::resource_desc desc = device->get_resource_desc(target_texture);
reshade::api::resource_view rtv = {};
device->create_resource_view(target_texture, reshade::api::resource_usage::render_target, reshade::api::resource_view_desc(reshade::api::format_to_default_typed(desc.texture.format, 0), 0, 1, 0, 1), &rtv);
reshade::api::resource_view rtv_srgb = {};
device->create_resource_view(target_texture, reshade::api::resource_usage::render_target, reshade::api::resource_view_desc(reshade::api::format_to_default_typed(desc.texture.format, 1), 0, 1, 0, 1), &rtv_srgb);
...
runtime->render_effects(cmd_list, rtv, rtv_srgb);
An RTV is just a piece of information that tells the driver how to interpret the data that is sitting inside a texture. So a RTV with a sRGB format means that the hardware should automatically apply a sRGB->linear conversion every time the texture is accessed through that RTV, whereas a RTV with a normal format would just pass it through as-is.
I don't see a reason why rendering before the game draws with a shader should not work, what issues did you run into?
[Btw., if you don't mind, I'd prefer if credits only refer to my pseudonym "crosire", rather than my real name

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