ReShade Documentation

repository·main·Indexed 26 days ago

https://github.com/crosire/reshade

A post-processing injector for games and video software that uses the ReShade FX shader language to apply visual effects. It includes a standalone shader compiler and a header-only API for developers to create add-ons (DLLs) that extend functionality, intercept application behavior via events, manage GPU resources, and implement Dear ImGui overlays.

Tokens
5.4K
Snippets
7
Records
12
Agent score
40%

What's inside ReShade

  1. Overview of ReShade

    main

    ReShade is a generic post-processing injector for games and video software. It provides automated access to frame color and depth information. It uses a custom shader language called ReShade FX to implement effects such as ambient occlusion, depth of field, and color correction.

    ReShade supports add-ons, which are DLLs that utilize the ReShade API to extend the functionality of ReShade or the host application.

  2. Understand ReShade API Abstractions

    main

    The ReShade API provides an abstraction layer that maps closely to modern graphics APIs like D3D12 and Vulkan. Understanding these mappings helps in translating existing graphics code to ReShade:

    • Device & Commands: reshade::api::device is equivalent to ID3D12Device or VkDevice. reshade::api::command_list is equivalent to ID3D12CommandList or VkCommandBuffer. reshade::api::command_queue is equivalent to ID3D12CommandQueue or VkQueue.
    • Resources: reshade::api::resource is equivalent to ID3D12Resource or VkBuffer/VkImage. reshade::api::resource_view is equivalent to SRV/UAV/etc. in D3D12 or VkBufferView/VkImageView in Vulkan.
    • Pipelines: reshade::api::pipeline is equivalent to ID3D12PipelineState or VkPipeline.
    • Layouts & Tables: reshade::api::pipeline_layout is equivalent to ID3D12RootSignature or VkPipelineLayout. reshade::api::descriptor_table is equivalent to descriptor tables in D3D12 or VkDescriptorSet in Vulkan.
  3. Build ReShade from source

    main

    To build ReShade, you require Visual Studio 2017 or higher and Python must be available in your PATH environment variable for the glad dependency.

    Build Steps

    1. Clone the repository including all Git submodules:
    git clone --recurse-submodules https://github.com/crosire/reshade
    1. Open the Visual Studio solution.
    2. Select either the 32-bit or 64-bit target platform and build the solution. This builds ReShade and its dependencies.

    Building the Setup Tool

    To build the setup tool, you must follow this specific order:

    1. Build the Release configuration for the 32-bit target.
    2. Build the Release configuration for the 64-bit target.
    3. Build the Release Setup configuration (the target platform selection does not matter for this final step).
  4. Integrate the ReShade FX shader compiler

    main
    The ReShade FX shader compiler is standalone and can be integrated into other projects. To use it, add all source/effect_*.* files to your project and follow the implementation pattern found in the tools/fxc.cpp example.
  5. Add Dear ImGui overlays to ReShade

    main

    ReShade supports adding overlays for debug information or user interaction using the docking branch of Dear ImGui.

    To use it, include reshade.hpp after imgui.h. This automatically overwrites Dear ImGui functions to use the instance managed by ReShade, allowing you to use the API without building ImGui source files yourself.

    Key Rules:

    • Do not call ImGui::Begin and ImGui::End in your callback to create the main overlay window; ReShade handles the window lifecycle for you.
    • You can call ImGui::Begin and ImGui::End with a different title to create additional popup windows.
    • Overlay names are shared. You can append widgets to existing ReShade overlays by using their specific names:
      • Use ###settings to add widgets to the ReShade settings page.
      • Use OSD to add widgets to the On-Screen Display (e.g., clock, FPS).
    #define IMGUI_DISABLE_INCLUDE_IMCONFIG_H
    #include <imgui.h>
    #include <reshade.hpp>
    
    bool g_popup_window_visible = false;
    
    // Callback for a named overlay window
    static void draw_debug_overlay(reshade::api::effect_runtime *runtime)
    {
        ImGui::TextUnformatted("Some text");
    
        if (ImGui::Button("Press me to open an additional popup window"))
            g_popup_window_visible = true;
    
        if (g_popup_window_visible)
        {
            ImGui::Begin("Popup", &g_popup_window_visible);
            ImGui::TextUnformatted("Some other text");
            ImGui::End();
        }
    }
    
    // Callback for the special settings overlay
    static void draw_settings_overlay(reshade::api::effect_runtime *runtime)
    {
        ImGui::Checkbox("Popup window is visible", &g_popup_window_visible);
    }
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
    {
        switch (fdwReason)
        {
        case DLL_PROCESS_ATTACH:
            if (!reshade::register_addon(hinstDLL))
                return FALSE;
    
            // Registers a new window named "Test"
            reshade::register_overlay("Test", &draw_debug_overlay);
    
            // Registers a special settings overlay (shown in the add-on list)
            reshade::register_overlay(nullptr, &draw_settings_overlay);
            break;
        case DLL_PROCESS_DETACH:
            reshade::unregister_addon(hinstDLL);
            break;
        }
        return TRUE;
    }
  6. Create a ReShade add-on

    main

    A ReShade add-on is a DLL that uses the header-only ReShade API to register callbacks for various events.

    Setup

    1. Add the include directory from the ReShade repository to your project.
    2. Include the reshade.hpp header.
    3. (Optional) If you want to link against ReShade, define RESHADE_API_LIBRARY before including the headers.

    Lifecycle

    • Initialization: Call reshade::register_addon(hinstDLL) inside DllMain (under DLL_PROCESS_ATTACH) before calling any other ReShade API functions. This initializes the API and finds the ReShade instance.
    • Optional Initialization: Export an extern "C" __declspec(dllexport) bool AddonInit(HMODULE addon_module, HMODULE reshade_module) function for complex one-time setup.
    • Unregistration: Call reshade::unregister_addon(hinstDLL) during DLL_PROCESS_DETACH to unregister the add-on and all its registered events/overlays.
    • Optional Uninitialization: Export an extern "C" __declspec(dllexport) void AddonUninit(HMODULE addon_module, HMODULE reshade_module) function for cleanup.

    Deployment

    Build your add-on as a DLL, change the file extension from .dll to .addon, and place it in the ReShade add-on search directory (defaults to the ReShade directory).

    #include <reshade.hpp>
    
    static void on_reshade_present(reshade::api::effect_runtime *runtime)
    {
        // ...
    }
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
    {
        switch (fdwReason)
        {
        case DLL_PROCESS_ATTACH:
            if (!reshade::register_addon(hinstDLL))
                return FALSE;
            reshade::register_event<reshade::addon_event::reshade_present>(&on_reshade_present);
            break;
        case DLL_PROCESS_DETACH:
            reshade::unregister_event<reshade::addon_event::reshade_present>(&on_reshade_present);
            reshade::unregister_addon(hinstDLL);
            break;
        }
        return TRUE;
    }
  7. Manage descriptors and pipeline layouts

    main

    Descriptors (handles to reshade::api::resource_view, reshade::api::sampler, or reshade::api::buffer_range) are organized into reshade::api::descriptor_tables within a reshade::api::descriptor_heap. A reshade::api::pipeline_layout maps these tables to shader registers.

    Descriptor Management Options:

    1. Descriptor Tables: For complex resource management. Allocate via reshade::api::device::allocate_descriptor_tables() and fill using reshade::api::device::update_descriptors() or reshade::api::device::update_descriptor_tables(). Bind using reshade::api::command_list::bind_descriptor_tables().
    2. Push Descriptors: For simple use cases. Use reshade::api::command_list::push_descriptors() to write descriptors directly into a built-in command list heap without manual allocation. This is limited to a single linear list of descriptors of the same type per pipeline layout parameter.
    3. Push Constants: For small amounts of constant data (equivalent to D3D12 root constants). Use reshade::api::command_list::push_constants() to write data directly into a built-in command list memory pool.

    Note: Only a single pipeline layout per stage can be bound to a command list at a time. It is updated via bind_descriptor_tables(), push_descriptors(), or push_constants().

    reshade::api::pipeline_layout_param params[];
    
    ...
    
    params[0].type = reshade::api::pipeline_layout_param_type::descriptor_table;
    params[0].descriptor_table.count = 4;
    
    params[0].descriptor_table.ranges[0].binding = 0;
    params[0].descriptor_table.ranges[0].dx_register_index = 0; // Base shader register => t0 - t2
    params[0].descriptor_table.ranges[0].count = 2;
    params[0].descriptor_table.ranges[0].type = reshade::api::descriptor_type::texture_shader_resource_view; // => tX shader register
    
    params[0].descriptor_table.ranges[1].binding = 2;
    params[0].descriptor_table.ranges[1].dx_register_index = 6; // Base shader register => s6 - s10
    params[0].descriptor_table.ranges[1].count = 5;
    params[0].descriptor_table.ranges[1].array_size = 3; // First binding is an array descriptor of size 3...
    params[0].descriptor_table.ranges[1].type = reshade::api::descriptor_type::sampler; // => sX shader register
    
    params[0].descriptor_table.ranges[2].binding = 5;
    params[0].descriptor_table.ranges[2].dx_register_index = 1; // Base shader register => b1 - b2
    params[0].descriptor_table.ranges[2].count = 2;
    params[0].descriptor_table.ranges[2].type = reshade::api::descriptor_type::constant_buffer; // => bX shader register
    
    params[0].descriptor_table.ranges[3].binding = 7;
    params[0].descriptor_table.ranges[3].dx_register_index = 3;
    params[0].descriptor_table.ranges[3].count = 2;
    params[0].descriptor_table.ranges[3].array_size = 2;
    params[0].descriptor_table.ranges[3].type = reshade::api::descriptor_type::texture_shader_resource_view;
  8. Register overlays with `reshade::register_overlay`

    main

    Use reshade::register_overlay to attach Dear ImGui UI elements to the ReShade interface.

    Function Signatures

    Named Overlay

    reshade::register_overlay(const char *name, void (*callback)(reshade::api::effect_runtime *)) Registers a new window with the specified name. This window will appear in the ReShade overlay menu.

    Settings Overlay

    reshade::register_overlay(nullptr, void (*callback)(reshade::api::effect_runtime *)) Passing nullptr as the name registers a special settings overlay. This is displayed beneath the add-on information in the ReShade add-on list and is used to present configuration settings to the user.

    Appending to Existing Overlays

    Because names are shared, you can inject UI into ReShade's own windows:

    • reshade::register_overlay("###settings", ...): Appends to the ReShade settings page.
    • reshade::register_overlay("OSD", ...): Appends to the On-Screen Display (FPS, clock, etc.).
  9. Register and use ReShade events

    main

    ReShade uses an event-based system to allow add-ons to intercept application behavior. You register callbacks using reshade::register_event<T>(callback_ptr).

    Common Event Types

    • reshade::addon_event::init_device: Called after the application creates a reshade::api::device.
    • reshade::addon_event::destroy_device: Called before the device is destroyed.
    • reshade::addon_event::init_command_list / init_command_queue: Called after command recording/submission objects are created.
    • reshade::addon_event::draw / dispatch: Called during rendering commands. These pass the current reshade::api::command_list to allow adding or replacing commands.
    • reshade::addon_event::init_swapchain / create_swapchain: Called during swapchain lifecycle. create_swapchain allows modifying the reshade::api::swapchain_desc before creation.
    • reshade::addon_event::reshade_present: Occurs every time a new frame is presented to the screen.

    Intercepting Commands

    When registering for draw or dispatch events, returning true from the callback prevents the original application command from executing. This is useful if you intend to replace the command with your own via the provided command_list.

    // Example: Intercepting a draw call to clear a render target
    static bool on_draw(reshade::api::command_list *cmd_list, uint32_t vertices, uint32_t instances, uint32_t first_vertex, uint32_t first_instance)
    {
        if (vertices == 3 && instances == 1)
        {
            reshade::api::resource_view rtv = ...;
            const float clear_color[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
            cmd_list->clear_render_target_view(rtv, clear_color);
        }
    
        // Return false to let the original draw command proceed
        return false;
    }
    
    // Registering the event
    reshade::register_event<reshade::addon_event::draw>(&on_draw);
  10. Create and bind pipelines

    main

    Pipelines (reshade::api::pipeline) combine shaders and render state into monolithic objects. Create them using reshade::api::device::create_pipeline() by providing a list of reshade::api::pipeline_subobjects.

    Binding Pipelines: Use reshade::api::command_list::bind_pipeline() to bind the state.

    API Behavior by Backend:

    • D3D9, D3D10, D3D11, and OpenGL: Supports partial binding. You can call bind_pipeline() with specific reshade::api::pipeline_stage flags to bind only a subset of the pipeline state.
    • D3D12 and Vulkan: Pipelines must be monolithic. You must bind the entire pipeline using the following flags:
      • reshade::api::pipeline_stage::all_graphics (for graphics pipelines)
      • reshade::api::pipeline_stage::all_compute (for compute pipelines)
      • reshade::api::pipeline_stage::all_raytracing (for ray tracing pipelines)
    reshade::api::pipeline_subobject subobjects[];
    
    ...
    
    reshade::api::shader_desc vertex_shader;
    vertex_shader.code = ...;
    vertex_shader.code_size = ...;
    subobjects[0].type = reshade::api::pipeline_subobject_type::vertex_shader;
    subobjects[0].count = 1;
    subobjects[0].data = &vertex_shader;
    
    reshade::api::shader_desc pixel_shader;
    pixel_shader.code = ...;
    pixel_shader.code_size = ...;
    subobjects[1].type = reshade::api::pipeline_subobject_type::pixel_shader;
    subobjects[1].count = 1;
    subobjects[1].data = &pixel_shader;
    
    reshade::api::rasterizer_desc rasterizer_state;
    rasterizer_state.cull_mode = reshade::api::cull_mode::none;
    subobjects[2].type = reshade::api::pipeline_subobject_type::rasterizer_state;
    subobjects[2].count = 1;
    subobjects[2].data = &rasterizer_state;
  11. Manage GPU resources and devices

    main

    The ReShade API provides a cross-API abstraction for graphics operations.

    Device Abstraction

    Everything is built from a reshade::api::device. You can retrieve the native graphics API object (e.g., ID3D11Device for D3D11) using device->get_native().

    Resource Creation

    Resources like textures and buffers are created via reshade::api::device::create_resource().

    Resource Handles

    ReShade uses handles for most objects to maintain abstraction:

    • reshade::api::resource: Buffers and textures.
    • reshade::api::resource_view: Views for resources (e.g., depth-stencil, render target, shader resource, or unordered access views).
    • reshade::api::sampler: Sampler state objects.
    • reshade::api::pipeline: (Partial) pipeline state objects.
    // Example: Creating a new 800x600 texture via the ReShade API
    static void on_init_device(reshade::api::device *device)
    {
        reshade::api::resource texture = {};
        const reshade::api::resource_desc desc(
            800, 600, 1, 1,
            reshade::api::format::r8g8b8a8_unorm,
            1,
            reshade::api::memory_heap::gpu_only,
            reshade::api::resource_usage::shader_resource | reshade::api::resource_usage::render_target);
    
        if (!device->create_resource(desc, nullptr, reshade::api::resource_usage::undefined, &texture))
        {
            // Error handling ...
        }
    }
  12. Allocate and manage resources

    main

    Use reshade::api::device::create_resource() to allocate memory and create buffers or textures. You must specify the intended usage via reshade::api::resource_desc::usage.

    Memory Access Patterns:

    • GPU-only memory (reshade::api::memory_heap::gpu_only): Cannot be mapped to the CPU. To populate these, use the initial data parameter during creation, or use reshade::api::device::update_buffer_region() or reshade::api::device::update_texture_region().
    • CPU-visible memory (reshade::api::memory_heap::cpu_to_gpu or reshade::api::memory_heap::gpu_to_cpu): Can be mapped and accessed directly on the CPU using reshade::api::device::map_buffer_region() or reshade::api::device::map_texture_region().