The equivalent of get_current_back_buffer for depth buffer

  • akuvfx
  • Topic Author
More
3 years 2 weeks ago #1 by akuvfx The equivalent of get_current_back_buffer for depth buffer was created by akuvfx
reshade::api::resource back_buffer = swapchain->get_current_back_buffer();

Is it possible to get depth buffer into a resource to use in obs_capture example just like back_buffer in the code above?

reshade::api::swapchain doesn't have any method for it

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

  • crosire
More
3 years 2 weeks ago - 3 years 2 weeks ago #2 by crosire Replied by crosire on topic The equivalent of get_current_back_buffer for depth buffer
There is no one depth buffer to get, so the API can't expose it. That's why the Generic Depth add-on exists, which is a rather complicated collection of heuristics and tracking methods that tries to figure out which of the thousands of resources a game creates is likely to be a depth buffer that contains the main scene.

But you can take advantage of that and just query what the Generic Depth add-on has found. Add-ons can attach private data to API objects and the Generic Depth add-on does that with a struct keeping track of which resource it deemed to be the depth buffer ( github.com/crosire/reshade/blob/main/exa...neric_depth.cpp#L116 , attached to swap chain objects). Since you can simply query for that private data in your own add-on, it's pretty trivial to get to the information. All you need is the struct declaration of the data you want (including the UUID it is being identified by), which I linked above:
struct __declspec(uuid("7c6363c7-f94e-437a-9160-141782c44a98")) generic_depth_data
{
... (declaration copied from generic_depth.cpp)
};

...

reshade::api::swapchain *swapchain = ...
reshade::api::resource depth_buffer = swapchain->get_private_data<generic_depth_data>().selected_depth_stencil;
...
Last edit: 3 years 2 weeks ago by crosire.
The following user(s) said Thank You: akuvfx

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

  • jason
More
2 years 9 months ago #3 by jason Replied by jason on topic The equivalent of get_current_back_buffer for depth buffer
Hi, I'm trying to use the above strategy to get the depth buffer with recent code on Github, but it can fail on DX12 games.

I'm working on a reshade addon to save 3D screenshots (RGB+depth).
For example, the below code can be pasted into "10-texture_overlay/texture_overlay_addon.cpp" above DllMain() to save a screenshot when you press F10.
The code works on 5.5.2, but on recent github commits on DX12 games, the depth frame fails to save. The corresponding displayed RGB frame is fine.

Specifically, I compiled github commits ef3f1eee47e1149 and e695c676f656345 from the last few days (Jan 12 - Jan 14).
It works on some DX10/DX11 games and Control (DX12), but it fails on Cyberpunk 2077 (DX12) and Horizon Zero Dawn (DX12).

In Reshade.log when it fails I see "ERROR | Failed to close immediate command list! HRESULT is E_INVALIDARG.".
The output (the saved image of the attempted depth buffer) is all zeros.
The line which prints that error is in "source/d3d12/d3d12_impl_command_list_immediate.cpp".
struct __declspec(uuid("7c6363c7-f94e-437a-9160-141782c44a98")) generic_depth_data
{
    reshade::api::resource selected_depth_stencil = { 0 };
    reshade::api::resource override_depth_stencil = { 0 };
    reshade::api::resource_view selected_shader_resource = { 0 };
    bool using_backup_texture = false;
};

static void on_reshade_finish_effects(reshade::api::effect_runtime *runtime,
    reshade::api::command_list *, reshade::api::resource_view rtv, reshade::api::resource_view)
{
    if (runtime->is_key_pressed(VK_F10))
    {
        // save color image
        reshade::api::resource displayedframe = runtime->get_device()->get_resource_from_view(rtv);
        save_texture_image(runtime->get_command_queue(), displayedframe, runtime->get_device()->get_resource_desc(displayedframe));

        // save depth buffer: works on older (dx10/dx11) games and works on Control DX12... but fails on Cyberpunk DX12 and Horizon Zero Dawn DX12
        generic_depth_data &genericdepdata = runtime->get_private_data<generic_depth_data>();
        save_texture_image(runtime->get_command_queue(), genericdepdata.selected_depth_stencil, runtime->get_device()->get_resource_desc(genericdepdata.selected_depth_stencil));
    }
}

..
// register that function:
    reshade::register_event<reshade::addon_event::reshade_finish_effects>(on_reshade_finish_effects);

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

  • crosire
More
2 years 9 months ago #4 by crosire Replied by crosire on topic The equivalent of get_current_back_buffer for depth buffer
Those games use a D32S8X24 depth buffer format. Unfortunately D3D12 changed copying behavior for that: While in D3D11 it's possible to copy the content into a R32X8X24 (so 64-bit per pixel) texture, this is no longer possible in D3D12. Depth and stencil are considered two separate planes in the resource there, so can only copy depth into a R32 buffer or stencil into a R8 buffer, but not both at once into an equivalent sized one.

That's a problem, because the code in "save_texture_image" assumes the data can be copied into a buffer of the exact same format as a whole. So for that D32S8X24 depth buffer it creates a R32X8X24 resource in system memory, then attempts to copy the depth buffer contents into it. But as explained before this is not possible in D3D12, so the D3D12 runtime throws an error when it sees that copy and invalidates the current command buffer (hence the error in the log).
Previously ReShade silently reinterpreted the R32X8X24 resource as a R32 resource and copied only depth into it and thus it seemed like things worked. But then trying to read the data as 64-bit per pixel would obviously get you garbage results, so that's not the right way to go about it. You can restore that behavior in the add-on by reverting the texture_overlay_addon.cpp change in github.com/crosire/reshade/commit/4ff8e6...b399ca11a8573d3f5e0f though. But still need special handling for D32S8X24 either way ...

Probably better to instead check if D3D12 is used and format is "d32_float_s8_uint"/"r32_g8_typeless" and if so, create the system memory resource in "save_texture_image" with the "r32_float" format instead of "format_to_default_typed(desc.texture.format)". Then when it is time to save the image to disk, interpret each pixel as 32-bit wide only.
The following user(s) said Thank You: jason

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.