diff --git a/include/reshade_api.hpp b/include/reshade_api.hpp
index d4b0600777..8d37059209 100644
--- a/include/reshade_api.hpp
+++ b/include/reshade_api.hpp
@@ -178,6 +178,20 @@ namespace reshade { namespace api
};
};
+ ///
+ /// Describes a rectangular region in a resource.
+ ///
+ struct region
+ {
+ uint32_t left;
+ uint32_t top;
+ uint32_t right;
+ uint32_t bottom;
+
+ constexpr uint32_t width() const { return right - left; }
+ constexpr uint32_t height() const { return bottom - top; }
+ };
+
///
/// An opaque handle to a resource object (buffer, texture, ...).
/// Resources created by the application are only guaranteed to be valid during event callbacks.
diff --git a/source/addon/generic_depth.cpp b/source/addon/generic_depth.cpp
index c29d738a5f..54333c7a1a 100644
--- a/source/addon/generic_depth.cpp
+++ b/source/addon/generic_depth.cpp
@@ -10,6 +10,7 @@
#include "dll_log.hpp"
#include "dll_config.hpp"
#include "reshade.hpp"
+#include "openvr/reshade_vr.hpp"
#include "addon_manager.hpp"
#include "dxgi/format_utils.hpp"
#include
@@ -37,6 +38,7 @@ struct depth_stencil_info
draw_stats current_stats; // Stats since last clear operation
std::vector clears;
bool copied_during_frame = false;
+ std::chrono::high_resolution_clock::time_point last_drawcall;
};
struct state_tracking
@@ -91,69 +93,44 @@ struct state_tracking
}
};
-struct state_tracking_context
+struct depth_stencil_selection
{
- static constexpr uint8_t GUID[16] = { 0x7c, 0x63, 0x63, 0xc7, 0xf9, 0x4e, 0x43, 0x7a, 0x91, 0x60, 0x14, 0x17, 0x82, 0xc4, 0x4a, 0x98 };
-
- // Enable or disable the creation of backup copies at clear operations on the selected depth-stencil
- bool preserve_depth_buffers = false;
- // Enable or disable the aspect ratio check from 'check_aspect_ratio' in the detection heuristic
- bool use_aspect_ratio_heuristics = true;
-
- // Set to zero for automatic detection, otherwise will use the clear operation at the specific index within a frame
- size_t force_clear_index = 0;
-
// Stats of the previous frame for the selected depth-stencil
draw_stats previous_stats = {};
// A resource used as target for a backup copy for the selected depth-stencil
- resource_handle backup_texture = { 0 };
+ resource_handle backup= { 0 };
// The depth-stencil that is currently selected as being the main depth target
// Any clear operations on it are subject for special handling (backup copy or replacement)
- resource_handle selected_depth_stencil = { 0 };
+ resource_handle resource = { 0 };
// Resource used to override automatic depth-stencil selection
- resource_handle override_depth_stencil = { 0 };
+ resource_handle override= { 0 };
// The current shader resource view bound to shaders
// This can be created from either the original depth-stencil of the application (if it supports shader access), or from the backup resource, or from one of the replacement resources
- resource_view_handle selected_shader_resource = { 0 };
+ resource_view_handle view = { 0 };
-#if RESHADE_GUI
- // List of all encountered depth-stencils of the last frame
- std::vector> current_depth_stencil_list;
- std::unordered_map display_count_per_depth_stencil;
-#endif
-
- // Checks whether the aspect ratio of the two sets of dimensions is similar or not
- bool check_aspect_ratio(float width_to_check, float height_to_check, uint32_t width, uint32_t height) const
- {
- if (width_to_check == 0.0f || height_to_check == 0.0f)
- return true;
-
- const float w = static_cast(width);
- const float w_ratio = w / width_to_check;
- const float h = static_cast(height);
- const float h_ratio = h / height_to_check;
- const float aspect_ratio = (w / h) - (static_cast(width_to_check) / height_to_check);
+ // Enable or disable the creation of backup copies at clear operations on the selected depth-stencil
+ bool preserve_depth_buffers = false;
- return std::fabs(aspect_ratio) <= 0.1f && w_ratio <= 1.85f && h_ratio <= 1.85f && w_ratio >= 0.5f && h_ratio >= 0.5f;
- }
+ // Set to zero for automatic detection, otherwise will use the clear operation at the specific index within a frame
+ size_t force_clear_index = 0;
// Update the backup texture to match the requested dimensions
void update_backup_texture(device *device, resource_desc desc)
{
- if (backup_texture != 0)
+ if (backup != 0)
{
- const resource_desc existing_desc = device->get_resource_desc(backup_texture);
+ const resource_desc existing_desc = device->get_resource_desc(backup);
if (desc.width == existing_desc.width && desc.height == existing_desc.height && desc.format == existing_desc.format)
return; // Texture already matches dimensions, so can re-use
device->wait_idle(); // Texture may still be in use on device, so wait for all operations to finish before destroying it
- device->destroy_resource(backup_texture);
- backup_texture = { 0 };
+ device->destroy_resource(backup);
+ backup= { 0 };
}
desc.usage = resource_usage::shader_resource | resource_usage::copy_dest;
@@ -163,14 +140,57 @@ struct state_tracking_context
if (device->get_api() >= render_api::d3d10 && device->get_api() <= render_api::d3d12)
desc.format = static_cast(make_dxgi_format_typeless(static_cast(desc.format)));
- if (!device->create_resource(resource_type::texture_2d, desc, memory_usage::gpu_only, resource_usage::copy_dest, &backup_texture))
+ if (!device->create_resource(resource_type::texture_2d, desc, memory_usage::gpu_only, resource_usage::copy_dest, &backup))
LOG(ERROR) << "Failed to create backup depth-stencil texture!";
}
};
-static void clear_depth_impl(command_list *cmd_list, state_tracking &state, const state_tracking_context &device_state, resource_handle depth_stencil, bool fullscreen_draw_call)
+struct state_tracking_context
+{
+ static constexpr uint8_t GUID[16] = { 0x7c, 0x63, 0x63, 0xc7, 0xf9, 0x4e, 0x43, 0x7a, 0x91, 0x60, 0x14, 0x17, 0x82, 0xc4, 0x4a, 0x98 };
+
+ // Enable or disable the aspect ratio check from 'check_aspect_ratio' in the detection heuristic
+ bool use_aspect_ratio_heuristics = true;
+
+ depth_stencil_selection selected_depth_stencil;
+ depth_stencil_selection vr_depth_stencil[2];
+
+ // By default, the left eye is expected to be the first eye rendered. Enable this to swap eyes if necessary.
+ bool vr_swap_eyes = false;
+
+#if RESHADE_GUI
+ // List of all encountered depth-stencils of the last frame
+ std::vector> current_depth_stencil_list;
+ std::unordered_map display_count_per_depth_stencil;
+#endif
+
+ // Checks whether the aspect ratio of the two sets of dimensions is similar or not
+ bool check_aspect_ratio(float width_to_check, float height_to_check, uint32_t width, uint32_t height) const
+ {
+ if (width_to_check == 0.0f || height_to_check == 0.0f)
+ return true;
+
+ const float w = static_cast(width);
+ const float w_ratio = w / width_to_check;
+ const float h = static_cast(height);
+ const float h_ratio = h / height_to_check;
+ const float aspect_ratio = (w / h) - (static_cast(width_to_check) / height_to_check);
+
+ return std::fabs(aspect_ratio) <= 0.1f && w_ratio <= 1.85f && h_ratio <= 1.85f && w_ratio >= 0.5f && h_ratio >= 0.5f;
+ }
+};
+
+struct match_info
+{
+ resource_desc description;
+ resource_handle resource;
+ depth_stencil_info snapshot;
+};
+
+
+static void clear_depth_impl(command_list *cmd_list, state_tracking &state, const state_tracking_context &device_state, const depth_stencil_selection &selected_depth_stencil, resource_handle depth_stencil, bool fullscreen_draw_call)
{
- if (depth_stencil == 0 || device_state.backup_texture == 0 || depth_stencil != device_state.selected_depth_stencil)
+ if (depth_stencil == 0 || selected_depth_stencil.backup == 0 || depth_stencil != selected_depth_stencil.resource)
return;
depth_stencil_info &counters = state.counters_per_used_depth_stencil[depth_stencil.handle];
@@ -178,7 +198,7 @@ static void clear_depth_impl(command_list *cmd_list, state_tracking &state, cons
// Update stats with data from previous frame
if (!fullscreen_draw_call && counters.current_stats.drawcalls == 0 && state.first_empty_stats)
{
- counters.current_stats = device_state.previous_stats;
+ counters.current_stats = selected_depth_stencil.previous_stats;
state.first_empty_stats = false;
}
@@ -197,11 +217,11 @@ static void clear_depth_impl(command_list *cmd_list, state_tracking &state, cons
counters.clears.push_back({ counters.current_stats, fullscreen_draw_call });
// Make a backup copy of the depth texture before it is cleared
- if (device_state.force_clear_index == 0 ?
+ if (selected_depth_stencil.force_clear_index == 0 ?
// If clear index override is set to zero, always copy any suitable buffers
fullscreen_draw_call || counters.current_stats.vertices > state.best_copy_stats.vertices :
// This is not really correct, since clears may accumulate over multiple command lists, but it's unlikely that the same depth-stencil is used in more than one
- counters.clears.size() == device_state.force_clear_index)
+ counters.clears.size() == selected_depth_stencil.force_clear_index)
{
// Since clears from fullscreen draw calls are selected based on their order (last one wins), their stats are ignored for the regular clear heuristic
if (!fullscreen_draw_call)
@@ -209,7 +229,7 @@ static void clear_depth_impl(command_list *cmd_list, state_tracking &state, cons
// A resource has to be in this state for a clear operation, so can assume it here
cmd_list->transition_state(depth_stencil, resource_usage::depth_stencil_write, resource_usage::copy_source);
- cmd_list->copy_resource(depth_stencil, device_state.backup_texture);
+ cmd_list->copy_resource(depth_stencil, selected_depth_stencil.backup);
cmd_list->transition_state(depth_stencil, resource_usage::copy_source, resource_usage::depth_stencil_write);
counters.copied_during_frame = true;
@@ -225,21 +245,39 @@ static void on_init_device(device *device)
const reshade::ini_file &config = reshade::global_config();
config.get("DEPTH", "DisableINTZ", s_disable_intz);
- config.get("DEPTH", "DepthCopyBeforeClears", device_state.preserve_depth_buffers);
- config.get("DEPTH", "DepthCopyAtClearIndex", device_state.force_clear_index);
+ config.get("DEPTH", "DepthCopyBeforeClears", device_state.selected_depth_stencil.preserve_depth_buffers);
+ config.get("DEPTH", "DepthCopyAtClearIndex", device_state.selected_depth_stencil.force_clear_index);
config.get("DEPTH", "UseAspectRatioHeuristics", device_state.use_aspect_ratio_heuristics);
+ config.get("DEPTH", "VRFirstEyeCopyAtClearIndex", device_state.vr_depth_stencil[0].force_clear_index);
+ config.get("DEPTH", "VRSwapEyes", device_state.vr_swap_eyes);
+
+ if (device_state.selected_depth_stencil.force_clear_index == std::numeric_limits::max())
+ device_state.selected_depth_stencil.force_clear_index = 0;
+ if (device_state.vr_depth_stencil[0].force_clear_index == std::numeric_limits::max())
+ device_state.vr_depth_stencil[0].force_clear_index = 0;
- if (device_state.force_clear_index == std::numeric_limits::max())
- device_state.force_clear_index = 0;
+ for (int i = 0; i < 2; ++i)
+ {
+ device_state.vr_depth_stencil[i].preserve_depth_buffers = device_state.selected_depth_stencil.preserve_depth_buffers;
+ if (device_state.vr_depth_stencil[i].force_clear_index == 0)
+ device_state.vr_depth_stencil[i].force_clear_index = device_state.selected_depth_stencil.force_clear_index;
+ }
}
static void on_destroy_device(device *device)
{
state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
- if (device_state.backup_texture != 0)
- device->destroy_resource(device_state.backup_texture);
- if (device_state.selected_shader_resource != 0)
- device->destroy_resource_view(device_state.selected_shader_resource);
+ if (device_state.selected_depth_stencil.backup != 0)
+ device->destroy_resource(device_state.selected_depth_stencil.backup);
+ if (device_state.selected_depth_stencil.view != 0)
+ device->destroy_resource_view(device_state.selected_depth_stencil.view);
+ for (int i = 0; i < 2; ++i)
+ {
+ if (device_state.vr_depth_stencil[i].backup != 0)
+ device->destroy_resource(device_state.vr_depth_stencil[i].backup);
+ if (device_state.vr_depth_stencil[i].view != 0)
+ device->destroy_resource_view(device_state.vr_depth_stencil[i].view);
+ }
device->destroy_data(state_tracking_context::GUID);
}
@@ -329,6 +367,7 @@ static void on_draw(command_list *cmd_list, uint32_t vertices, uint32_t instance
counters.current_stats.vertices += vertices * instances;
counters.current_stats.drawcalls += 1;
std::memcpy(counters.current_stats.last_viewport, state.current_viewport, 6 * sizeof(float));
+ counters.last_drawcall = std::chrono::high_resolution_clock::now();
}
static void on_draw_indexed(command_list *cmd_list, uint32_t indices, uint32_t instances, uint32_t, int32_t, uint32_t)
{
@@ -366,7 +405,10 @@ static void on_set_depth_stencil(command_list *cmd_list, uint32_t, const resourc
// Make a backup of the depth texture before it is used differently, since in D3D12 or Vulkan the underlying memory may be aliased to a different resource, so cannot just access it at the end of the frame
if (depth_stencil != state.current_depth_stencil && state.current_depth_stencil != 0 && (device->get_api() == render_api::d3d12 || device->get_api() == render_api::vulkan))
{
- clear_depth_impl(cmd_list, state, device->get_data(state_tracking_context::GUID), state.current_depth_stencil, true);
+ state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
+ clear_depth_impl(cmd_list, state, device_state, device_state.selected_depth_stencil, state.current_depth_stencil, true);
+ clear_depth_impl(cmd_list, state, device_state, device_state.vr_depth_stencil[0], state.current_depth_stencil, true);
+ clear_depth_impl(cmd_list, state, device_state, device_state.vr_depth_stencil[1], state.current_depth_stencil, true);
}
state.current_depth_stencil = depth_stencil;
@@ -376,7 +418,8 @@ static void on_clear_depth_stencil(command_list *cmd_list, resource_view_handle
device *const device = cmd_list->get_device();
const state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
- if ((clear_flags & 0x1) == 0 || !device_state.preserve_depth_buffers)
+ // FIXME: may need adjustment for VR?
+ if ((clear_flags & 0x1) == 0 || (!device_state.selected_depth_stencil.preserve_depth_buffers && !device_state.vr_depth_stencil[0].preserve_depth_buffers))
{
// Ignore clears that do not affect the depth buffer (stencil clears)
return;
@@ -385,7 +428,10 @@ static void on_clear_depth_stencil(command_list *cmd_list, resource_view_handle
resource_handle depth_stencil = { 0 };
device->get_resource_from_view(dsv, &depth_stencil);
- clear_depth_impl(cmd_list, cmd_list->get_data(state_tracking::GUID), device_state, depth_stencil, false);
+ state_tracking state = cmd_list->get_data(state_tracking::GUID);
+ clear_depth_impl(cmd_list, state, device_state, device_state.selected_depth_stencil, depth_stencil, false);
+ clear_depth_impl(cmd_list, state, device_state, device_state.vr_depth_stencil[0], depth_stencil, false);
+ clear_depth_impl(cmd_list, state, device_state, device_state.vr_depth_stencil[1], depth_stencil, false);
}
static void on_reset(command_list *cmd_list)
@@ -400,24 +446,17 @@ static void on_execute(api_object *queue_or_cmd_list, command_list *cmd_list)
target_state.merge(source_state);
}
-static void on_present(command_queue *, effect_runtime *runtime)
+static std::vector find_matching_depth_textures(effect_runtime *runtime)
{
- device *const device = runtime->get_device();
- command_queue *const queue = runtime->get_command_queue();
- state_tracking &queue_state = queue->get_data(state_tracking::GUID);
- state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
-
-#if RESHADE_GUI
- device_state.current_depth_stencil_list.clear();
- device_state.current_depth_stencil_list.reserve(queue_state.counters_per_used_depth_stencil.size());
-#endif
+ const device *const device = runtime->get_device();
+ const command_queue *const queue = runtime->get_command_queue();
+ const state_tracking &queue_state = queue->get_data(state_tracking::GUID);
+ const state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
uint32_t frame_width, frame_height;
runtime->get_frame_width_and_height(&frame_width, &frame_height);
- resource_desc best_desc = {};
- resource_handle best_match = { 0 };
- depth_stencil_info best_snapshot;
+ std::vector matches;
for (const auto &[depth_stencil_handle, snapshot] : queue_state.counters_per_used_depth_stencil)
{
@@ -425,11 +464,6 @@ static void on_present(command_queue *, effect_runtime *runtime)
if (!device->check_resource_handle_valid(resource))
continue; // Skip resources that were destroyed by the application
-#if RESHADE_GUI
- // Save to current list of depth-stencils on the device, so that it can be displayed in the GUI
- device_state.current_depth_stencil_list.emplace_back(resource, snapshot);
-#endif
-
if (snapshot.total_stats.drawcalls == 0)
continue; // Skip unused
@@ -440,44 +474,58 @@ static void on_present(command_queue *, effect_runtime *runtime)
if (device_state.use_aspect_ratio_heuristics && !device_state.check_aspect_ratio(static_cast(desc.width), static_cast(desc.height), frame_width, frame_height))
continue; // Not a good fit
- if (!queue_state.has_indirect_drawcalls ?
+ matches.push_back({ desc, resource, snapshot });
+ }
+ std::sort(matches.begin(), matches.end(), [&](const match_info &a, const match_info &b) {
+ if (!queue_state.has_indirect_drawcalls)
+ {
// Choose snapshot with the most vertices, since that is likely to contain the main scene
- snapshot.total_stats.vertices > best_snapshot.total_stats.vertices :
- // Or check draw calls, since vertices may not be accurate if application is using indirect draw calls
- snapshot.total_stats.drawcalls > best_snapshot.total_stats.drawcalls)
+ return a.snapshot.total_stats.vertices > b.snapshot.total_stats.vertices;
+ }
+ else
{
- best_desc = desc;
- best_match = resource;
- best_snapshot = snapshot;
+ // Or check draw calls, since vertices may not be accurate if application is using indirect draw calls
+ return a.snapshot.total_stats.drawcalls > b.snapshot.total_stats.drawcalls;
}
- }
+ });
+
+ // have at least one empty result in the list
+ matches.push_back({});
+ return matches;
+}
- if (device_state.override_depth_stencil != 0 &&
- device->check_resource_handle_valid(device_state.override_depth_stencil))
+static void update_selected_depth_stencil(effect_runtime *runtime, depth_stencil_selection &selected_depth_stencil, match_info match) {
+ device *const device = runtime->get_device();
+ command_queue *const queue = runtime->get_command_queue();
+ state_tracking &queue_state = queue->get_data(state_tracking::GUID);
+ state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
+
+ if (selected_depth_stencil.override != 0 &&
+ device->check_resource_handle_valid(selected_depth_stencil.override))
{
- best_desc = device->get_resource_desc(device_state.override_depth_stencil);
- best_match = device_state.override_depth_stencil;
- best_snapshot = queue_state.counters_per_used_depth_stencil[best_match.handle];
+ match.description = device->get_resource_desc(selected_depth_stencil.override);
+ match.resource = selected_depth_stencil.override;
+ match.snapshot = queue_state.counters_per_used_depth_stencil[match.resource.handle];
}
- if (best_match != 0)
+ if (match.resource != 0)
{
- if (best_match != device_state.selected_depth_stencil)
+ if (match.resource != selected_depth_stencil.resource)
{
// Destroy previous resource view, since the underlying resource has changed
- if (device_state.selected_shader_resource != 0)
+ if (selected_depth_stencil.view != 0)
{
device->wait_idle(); // Ensure resource view is no longer in-use before destroying it
- device->destroy_resource_view(device_state.selected_shader_resource);
+ device->destroy_resource_view(selected_depth_stencil.view);
}
- device_state.selected_depth_stencil = best_match;
- device_state.selected_shader_resource = { 0 };
+ selected_depth_stencil.resource = match.resource;
+ selected_depth_stencil.view = { 0 };
// Create two-dimensional resource view to the first level and layer of the depth-stencil resource
resource_view_desc srv_desc = {};
srv_desc.type = resource_view_type::texture_2d;
- srv_desc.format = best_desc.format;
+ srv_desc.format = match.description.format;
srv_desc.levels = 1;
srv_desc.layers = 1;
@@ -486,75 +534,138 @@ static void on_present(command_queue *, effect_runtime *runtime)
// Need to create backup texture only if doing backup copies or original resource does not support shader access (which is necessary for binding it to effects)
// Also always create a backup texture in D3D12 or Vulkan to circument problems in case application makes use of resource aliasing
- if (device_state.preserve_depth_buffers || (best_desc.usage & resource_usage::shader_resource) == 0 || (device->get_api() == render_api::d3d12 || device->get_api() == render_api::vulkan))
+ if (selected_depth_stencil.preserve_depth_buffers || (match.description.usage & resource_usage::shader_resource) == 0 || (device->get_api() == render_api::d3d12 || device->get_api() == render_api::vulkan))
{
- device_state.update_backup_texture(device, best_desc);
+ selected_depth_stencil.update_backup_texture(device, match.description);
- if (device_state.backup_texture != 0)
+ if (selected_depth_stencil.backup != 0)
{
if (device->get_api() == render_api::d3d9)
srv_desc.format = 114; // Same format as backup texture, as set in 'update_backup_texture'
- device->create_resource_view(device_state.backup_texture, resource_usage::shader_resource, srv_desc, &device_state.selected_shader_resource);
+ device->create_resource_view(selected_depth_stencil.backup, resource_usage::shader_resource, srv_desc, &selected_depth_stencil.view);
}
}
else
{
- device->create_resource_view(best_match, resource_usage::shader_resource, srv_desc, &device_state.selected_shader_resource);
+ device->create_resource_view(match.resource, resource_usage::shader_resource, srv_desc, &selected_depth_stencil.view);
- if (device_state.backup_texture != 0)
+ if (selected_depth_stencil.backup != 0)
{
- device->destroy_resource(device_state.backup_texture);
- device_state.backup_texture = { 0 };
+ device->destroy_resource(selected_depth_stencil.backup);
+ selected_depth_stencil.backup = { 0 };
}
}
-
- runtime->update_texture_bindings("DEPTH", device_state.selected_shader_resource);
-
- const bool bufready_depth_value = true;
- runtime->update_uniform_variables("bufready_depth", &bufready_depth_value, 1);
}
- if (device_state.preserve_depth_buffers)
+ if (selected_depth_stencil.preserve_depth_buffers)
{
- device_state.previous_stats = best_snapshot.current_stats;
+ selected_depth_stencil.previous_stats = match.snapshot.current_stats;
}
else
{
// Copy to backup texture unless already copied during the current frame
- if (device_state.backup_texture != 0 && !best_snapshot.copied_during_frame && (best_desc.usage & resource_usage::copy_source) != 0)
+ if (selected_depth_stencil.backup != 0 && !match.snapshot.copied_during_frame && (match.description.usage & resource_usage::copy_source) != 0)
{
command_list *const cmd_list = queue->get_immediate_command_list();
- cmd_list->transition_state(best_match, resource_usage::depth_stencil | resource_usage::shader_resource, resource_usage::copy_source);
- cmd_list->copy_resource(best_match, device_state.backup_texture);
- cmd_list->transition_state(best_match, resource_usage::copy_source, resource_usage::depth_stencil | resource_usage::shader_resource);
+ cmd_list->transition_state(match.resource, resource_usage::depth_stencil | resource_usage::shader_resource, resource_usage::copy_source);
+ cmd_list->copy_resource(match.resource, selected_depth_stencil.backup);
+ cmd_list->transition_state(match.resource, resource_usage::copy_source, resource_usage::depth_stencil | resource_usage::shader_resource);
}
}
- best_snapshot.copied_during_frame = false;
+ match.snapshot.copied_during_frame = false;
}
else
{
// Unset any existing depth-stencil selected in previous frames
- if (device_state.selected_depth_stencil != 0)
+ if (selected_depth_stencil.resource != 0)
{
- if (device_state.selected_shader_resource != 0)
+ if (selected_depth_stencil.view != 0)
{
device->wait_idle(); // Ensure resource view is no longer in-use before destroying it
- device->destroy_resource_view(device_state.selected_shader_resource);
+ device->destroy_resource_view(selected_depth_stencil.view);
}
- device_state.selected_depth_stencil = { 0 };
- device_state.selected_shader_resource = { 0 };
+ selected_depth_stencil = { 0 };
+ selected_depth_stencil.view = { 0 };
+ }
+ }
+
+ runtime->update_texture_bindings("DEPTH", selected_depth_stencil.view);
+
+ const bool bufready_depth_value = match.resource != 0;
+ runtime->update_uniform_variables("bufready_depth", &bufready_depth_value, 1);
+}
+
+static void on_present_vr(effect_runtime *runtime, reshade::vr::submit_info submit_info)
+{
+ device *const device = runtime->get_device();
+ state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
- runtime->update_texture_bindings("DEPTH", device_state.selected_shader_resource);
+ std::vector matches = find_matching_depth_textures(runtime);
+ matches.resize(2);
- const bool bufready_depth_value = false;
- runtime->update_uniform_variables("bufready_depth", &bufready_depth_value, 1);
+ if (matches[0].resource != 0)
+ {
+ if (matches[0].description.width >= submit_info.region.width() * 2 - 10) {
+ // case 1: single large depth texture containing both eyes
+ matches[1] = matches[0];
+ }
+ else if (matches[1].resource == 0 || matches[1].description.width != matches[0].description.width || matches[1].description.height != matches[0].description.height) {
+ // case 2: single depth texture used for both eyes consecutively
+ // in this case, we'll have to make a copy during clear for the first eye
+ matches[1] = matches[0];
+ device_state.vr_depth_stencil[0].preserve_depth_buffers = true;
}
+ else if (matches[1].resource != 0 && matches[1].snapshot.last_drawcall < matches[0].snapshot.last_drawcall)
+ {
+ // case 3: two separate textures, but we need to bring them in the right order depending
+ // on the last drawcall timestamp
+ std::swap(matches[0], matches[1]);
+ }
+ }
+
+ uint8_t eye = device_state.vr_swap_eyes ? 1 - submit_info.eye : submit_info.eye;
+ depth_stencil_selection &selected_depth_stencil = device_state.vr_depth_stencil[eye];
+ selected_depth_stencil.override = submit_info.depth;
+ update_selected_depth_stencil(runtime, selected_depth_stencil, matches[eye]);
+}
+
+static void on_present(command_queue *, effect_runtime *runtime)
+{
+ reshade::vr::submit_info *submit_info = nullptr;
+ if (runtime->get_data(reshade::vr::submit_info::GUID, reinterpret_cast(&submit_info)))
+ {
+ on_present_vr(runtime, *submit_info);
+ return;
}
+ device *const device = runtime->get_device();
+ command_queue *const queue = runtime->get_command_queue();
+ state_tracking &queue_state = queue->get_data(state_tracking::GUID);
+ state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
+
+
+#if RESHADE_GUI
+ device_state.current_depth_stencil_list.clear();
+ device_state.current_depth_stencil_list.reserve(queue_state.counters_per_used_depth_stencil.size());
+
+ for (const auto &[depth_stencil_handle, snapshot] : queue_state.counters_per_used_depth_stencil)
+ {
+ resource_handle const resource = { depth_stencil_handle };
+ if (!device->check_resource_handle_valid(resource))
+ continue; // Skip resources that were destroyed by the application
+
+ // Save to current list of depth-stencils on the device, so that it can be displayed in the GUI
+ device_state.current_depth_stencil_list.emplace_back(resource, snapshot);
+ }
+#endif
+
+ match_info match = find_matching_depth_textures(runtime).front();
+ update_selected_depth_stencil(runtime, device_state.selected_depth_stencil, match);
+
queue_state.reset_on_present();
}
@@ -564,22 +675,19 @@ static void on_init_effect_runtime(effect_runtime *runtime)
const state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
// Need to set texture binding again after a runtime was reset
- runtime->update_texture_bindings("DEPTH", device_state.selected_shader_resource);
+ runtime->update_texture_bindings("DEPTH", device_state.selected_depth_stencil.view);
- const bool bufready_depth_value = device_state.selected_shader_resource != 0;
+ const bool bufready_depth_value = device_state.selected_depth_stencil.view != 0;
runtime->update_uniform_variables("bufready_depth", &bufready_depth_value, 1);
}
-static void on_before_render_effects(effect_runtime *runtime, command_list *cmd_list)
+static void transition_state_before_effects(device *const device, command_list *cmd_list, const depth_stencil_selection &selected_depth_stencil)
{
- device *const device = runtime->get_device();
- const state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
-
- if (device_state.selected_shader_resource != 0)
+ if (selected_depth_stencil.view != 0)
{
resource_handle resource = { 0 };
- device->get_resource_from_view(device_state.selected_shader_resource, &resource);
+ device->get_resource_from_view(selected_depth_stencil.view, &resource);
- if (resource == device_state.backup_texture)
+ if (resource == selected_depth_stencil.backup)
{
cmd_list->transition_state(resource, resource_usage::copy_dest, resource_usage::shader_resource);
}
@@ -589,17 +697,23 @@ static void on_before_render_effects(effect_runtime *runtime, command_list *cmd_
}
}
}
-static void on_after_render_effects(effect_runtime *runtime, command_list *cmd_list)
+static void on_before_render_effects(effect_runtime *runtime, command_list *cmd_list)
{
device *const device = runtime->get_device();
const state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
- if (device_state.selected_shader_resource != 0)
+ transition_state_before_effects(device, cmd_list, device_state.selected_depth_stencil);
+ transition_state_before_effects(device, cmd_list, device_state.vr_depth_stencil[0]);
+ transition_state_before_effects(device, cmd_list, device_state.vr_depth_stencil[1]);
+}
+static void transition_state_after_effects(device *const device, command_list *cmd_list, const depth_stencil_selection &selected_depth_stencil)
+{
+ if (selected_depth_stencil.view != 0)
{
resource_handle resource = { 0 };
- device->get_resource_from_view(device_state.selected_shader_resource, &resource);
+ device->get_resource_from_view(selected_depth_stencil.view, &resource);
- if (resource == device_state.backup_texture)
+ if (resource == selected_depth_stencil.backup)
{
cmd_list->transition_state(resource, resource_usage::shader_resource, resource_usage::copy_dest);
}
@@ -609,6 +723,15 @@ static void on_after_render_effects(effect_runtime *runtime, command_list *cmd_l
}
}
}
+static void on_after_render_effects(effect_runtime *runtime, command_list *cmd_list)
+{
+ device *const device = runtime->get_device();
+ const state_tracking_context &device_state = device->get_data(state_tracking_context::GUID);
+
+ transition_state_after_effects(device, cmd_list, device_state.selected_depth_stencil);
+ transition_state_after_effects(device, cmd_list, device_state.vr_depth_stencil[0]);
+ transition_state_after_effects(device, cmd_list, device_state.vr_depth_stencil[1]);
+}
#if RESHADE_GUI
static void draw_debug_menu(effect_runtime *runtime, void *)
@@ -621,7 +744,7 @@ static void draw_debug_menu(effect_runtime *runtime, void *)
modified |= ImGui::Checkbox("Disable replacement with INTZ format (requires restart)", &s_disable_intz);
modified |= ImGui::Checkbox("Use aspect ratio heuristics", &device_state.use_aspect_ratio_heuristics);
- modified |= ImGui::Checkbox("Copy depth buffer before clear operations", &device_state.preserve_depth_buffers);
+ modified |= ImGui::Checkbox("Copy depth buffer before clear operations", &device_state.selected_depth_stencil.preserve_depth_buffers);
ImGui::Spacing();
ImGui::Separator();
@@ -673,7 +796,7 @@ static void draw_debug_menu(effect_runtime *runtime, void *)
device_state.display_count_per_depth_stencil[item.resource.handle] = item.display_count;
char label[512] = "";
- sprintf_s(label, "%s0x%016llx", (item.resource == device_state.selected_depth_stencil ? "> " : " "), item.resource.handle);
+ sprintf_s(label, "%s0x%016llx", (item.resource == device_state.selected_depth_stencil.resource ? "> " : " "), item.resource.handle);
if (item.desc.samples > 1) // Disable widget for MSAA textures
{
@@ -681,10 +804,10 @@ static void draw_debug_menu(effect_runtime *runtime, void *)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
}
- if (bool value = (item.resource == device_state.override_depth_stencil);
+ if (bool value = (item.resource == device_state.selected_depth_stencil.override);
ImGui::Checkbox(label, &value))
{
- device_state.override_depth_stencil = value ? item.resource : resource_handle { 0 };
+ device_state.selected_depth_stencil.override = value ? item.resource : resource_handle { 0 };
modified = true;
}
@@ -692,16 +815,16 @@ static void draw_debug_menu(effect_runtime *runtime, void *)
ImGui::Text("| %4ux%-4u | %5u draw calls ==> %8u vertices |%s",
item.desc.width, item.desc.height, item.snapshot.total_stats.drawcalls, item.snapshot.total_stats.vertices, (item.desc.samples > 1 ? " MSAA" : ""));
- if (device_state.preserve_depth_buffers && item.resource == device_state.selected_depth_stencil)
+ if (device_state.selected_depth_stencil.preserve_depth_buffers && item.resource == device_state.selected_depth_stencil.resource)
{
for (size_t clear_index = 1; clear_index <= item.snapshot.clears.size(); ++clear_index)
{
- sprintf_s(label, "%s CLEAR %2zu", (clear_index == device_state.force_clear_index ? "> " : " "), clear_index);
+ sprintf_s(label, "%s CLEAR %2zu", (clear_index == device_state.selected_depth_stencil.force_clear_index ? "> " : " "), clear_index);
- if (bool value = (device_state.force_clear_index == clear_index);
+ if (bool value = (device_state.selected_depth_stencil.force_clear_index == clear_index);
ImGui::Checkbox(label, &value))
{
- device_state.force_clear_index = value ? clear_index : 0;
+ device_state.selected_depth_stencil.force_clear_index = value ? clear_index : 0;
modified = true;
}
@@ -722,22 +845,24 @@ static void draw_debug_menu(effect_runtime *runtime, void *)
if (modified)
{
// Reset selected depth-stencil to force re-creation of resources next frame (like the backup texture)
- if (device_state.selected_shader_resource != 0)
+ if (device_state.selected_depth_stencil.view != 0)
{
device->wait_idle(); // Ensure resource view is no longer in-use before destroying it
- device->destroy_resource_view(device_state.selected_shader_resource);
+ device->destroy_resource_view(device_state.selected_depth_stencil.view);
}
device_state.selected_depth_stencil = { 0 };
- device_state.selected_shader_resource = { 0 };
+ device_state.selected_depth_stencil.view = { 0 };
on_init_effect_runtime(runtime);
reshade::ini_file &config = reshade::global_config();
config.set("DEPTH", "DisableINTZ", s_disable_intz);
- config.set("DEPTH", "DepthCopyBeforeClears", device_state.preserve_depth_buffers);
- config.set("DEPTH", "DepthCopyAtClearIndex", device_state.force_clear_index);
+ config.set("DEPTH", "DepthCopyBeforeClears", device_state.selected_depth_stencil.preserve_depth_buffers);
+ config.set("DEPTH", "DepthCopyAtClearIndex", device_state.selected_depth_stencil.force_clear_index);
config.set("DEPTH", "UseAspectRatioHeuristics", device_state.use_aspect_ratio_heuristics);
+ config.set("DEPTH", "VRFirstEyeCopyAtClearIndex", device_state.vr_depth_stencil[0].force_clear_index);
+ config.set("DEPTH", "VRSwapEyes", device_state.vr_swap_eyes);
}
}
#endif
diff --git a/source/openvr/openvr.cpp b/source/openvr/openvr.cpp
index af3a0ac3cf..cebb5e9ca5 100644
--- a/source/openvr/openvr.cpp
+++ b/source/openvr/openvr.cpp
@@ -14,9 +14,12 @@
#include "opengl/runtime_gl.hpp"
#include "vulkan/vulkan_hooks.hpp"
#include "vulkan/runtime_vk.hpp"
+#include "reshade_vr.hpp"
#include
static std::pair s_vr_runtime = { nullptr, vr::TextureType_Invalid };
+static void *last_submitted_texture = nullptr;
+static vr::VRTextureBounds_t last_submitted_bounds = { 0, 0, 0, 0 };
extern lockfree_table g_vulkan_devices;
@@ -41,14 +44,8 @@ static bool on_submit_d3d11(vr::EVREye, ID3D11Texture2D *texture, const vr::VRTe
texture->GetDesc(&tex_desc);
D3D11_BOX region = { 0, 0, 0, tex_desc.Width, tex_desc.Height, 1 };
- if (bounds != nullptr)
- {
- region.left = static_cast(region.right * std::min(bounds->uMin, bounds->uMax));
- region.top = static_cast(region.bottom * std::min(bounds->vMin, bounds->vMax));
- region.right = static_cast(region.right * std::max(bounds->uMin, bounds->uMax));
- region.bottom = static_cast(region.bottom * std::max(bounds->vMin, bounds->vMax));
- }
+ RESHADE_ADDON_EVENT(present, s_vr_runtime.first->get_command_queue(), s_vr_runtime.first);
return static_cast(s_vr_runtime.first)->on_present(texture, region, nullptr);
}
static bool on_submit_d3d12(vr::EVREye, const vr::D3D12TextureData_t *texture, const vr::VRTextureBounds_t *bounds)
@@ -68,14 +65,8 @@ static bool on_submit_d3d12(vr::EVREye, const vr::D3D12TextureData_t *texture, c
const D3D12_RESOURCE_DESC tex_desc = texture->m_pResource->GetDesc();
D3D12_BOX region = { 0, 0, 0, static_cast(tex_desc.Width), tex_desc.Height, 1 };
- if (bounds != nullptr)
- {
- region.left = static_cast(region.right * std::min(bounds->uMin, bounds->uMax));
- region.top = static_cast(region.bottom * std::min(bounds->vMin, bounds->vMax));
- region.right = static_cast(region.right * std::max(bounds->uMin, bounds->uMax));
- region.bottom = static_cast(region.bottom * std::max(bounds->vMin, bounds->vMax));
- }
+ RESHADE_ADDON_EVENT(present, s_vr_runtime.first->get_command_queue(), s_vr_runtime.first);
// Resource should be in D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE state at this point
return static_cast(s_vr_runtime.first)->on_present(texture->m_pResource, region, nullptr);
}
@@ -96,14 +87,8 @@ static bool on_submit_opengl(vr::EVREye, GLuint object, bool is_rbo, bool is_arr
reshade::opengl::make_resource_handle(is_rbo ? GL_RENDERBUFFER : GL_TEXTURE, object), nullptr, nullptr);
GLint region[4] = { 0, 0, static_cast(object_desc.width), static_cast(object_desc.height) };
- if (bounds != nullptr)
- {
- region[0] = static_cast(object_desc.width * std::min(bounds->uMin, bounds->uMax));
- region[1] = static_cast(object_desc.height * std::min(bounds->vMin, bounds->vMax));
- region[2] = static_cast(object_desc.width * std::max(bounds->uMin, bounds->uMax));
- region[3] = static_cast(object_desc.height * std::max(bounds->vMin, bounds->vMax));
- }
+ RESHADE_ADDON_EVENT(present, s_vr_runtime.first->get_command_queue(), s_vr_runtime.first);
return static_cast(s_vr_runtime.first)->on_present(object, is_rbo, is_array, object_desc.width, object_desc.height, region);
}
static bool on_submit_vulkan(vr::EVREye, const vr::VRVulkanTextureData_t *texture, bool with_array_data, const vr::VRTextureBounds_t *bounds)
@@ -130,16 +115,10 @@ static bool on_submit_vulkan(vr::EVREye, const vr::VRVulkanTextureData_t *textur
VkOffset2D { 0, 0 },
VkExtent2D { texture->m_nWidth, texture->m_nHeight }
};
- if (bounds != nullptr)
- {
- region.offset.x = static_cast(texture->m_nWidth * std::min(bounds->uMin, bounds->uMax));
- region.extent.width = static_cast(texture->m_nWidth * std::max(bounds->uMin, bounds->uMax) - region.offset.x);
- region.offset.y = static_cast(texture->m_nHeight * std::min(bounds->vMin, bounds->vMax));
- region.extent.height = static_cast(texture->m_nHeight * std::max(bounds->vMin, bounds->vMax) - region.offset.y);
- }
const uint32_t layer_index = with_array_data ? static_cast(texture)->m_unArrayIndex : 0;
+ RESHADE_ADDON_EVENT(present, s_vr_runtime.first->get_command_queue(), s_vr_runtime.first);
// Image should be in VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL layout at this point
std::vector wait_semaphores;
return static_cast(s_vr_runtime.first)->on_present(
@@ -153,6 +132,59 @@ static bool on_submit_vulkan(vr::EVREye, const vr::VRVulkanTextureData_t *textur
wait_semaphores);
}
+static void update_submit_info(vr::EVREye eye, const vr::Texture_t *texture, const vr::VRTextureBounds_t *bounds, vr::EVRSubmitFlags submitFlags)
+{
+ if (s_vr_runtime.first == nullptr)
+ return;
+
+ reshade::vr::submit_info *submit_info = nullptr;
+ if (!s_vr_runtime.first->get_data(reshade::vr::submit_info::GUID, reinterpret_cast(&submit_info)))
+ submit_info = &s_vr_runtime.first->create_data(reshade::vr::submit_info::GUID);
+
+ auto *device = s_vr_runtime.first->get_device();
+
+ submit_info->eye = eye;
+
+ if (texture == nullptr || texture->handle == nullptr)
+ return;
+
+ submit_info->color = reshade::api::resource_handle {reinterpret_cast(texture->handle)};
+ auto desc = device->get_resource_desc(submit_info->color);
+ reshade::api::region region { 0, 0, desc.width, desc.height };
+ if (bounds != nullptr)
+ {
+ region.left = static_cast(desc.width * std::min(bounds->uMin, bounds->uMax));
+ region.top = static_cast(desc.height * std::min(bounds->vMin, bounds->vMax));
+ region.right = static_cast(desc.width * std::max(bounds->uMin, bounds->uMax));
+ region.bottom = static_cast(desc.height * std::max(bounds->vMin, bounds->vMax));
+ }
+ submit_info->region = region;
+
+ submit_info->depth = {0};
+ if (submitFlags & vr::Submit_TextureWithDepth)
+ {
+ vr::VRTextureDepthInfo_t depth_info = submitFlags & vr::Submit_TextureWithPose
+ ? static_cast(texture)->depth
+ : static_cast(texture)->depth;
+ submit_info->depth = {reinterpret_cast(depth_info.handle)};
+ }
+}
+
+bool should_apply_effects(void *texture_handle, const vr::VRTextureBounds_t *bounds)
+{
+ if (texture_handle != last_submitted_texture || bounds == nullptr || (bounds->uMin == last_submitted_bounds.uMin && bounds->uMax == last_submitted_bounds.uMax && bounds->vMin == last_submitted_bounds.vMin && bounds->vMax == last_submitted_bounds.vMax))
+ {
+ last_submitted_texture = texture_handle;
+ last_submitted_bounds = *bounds;
+ return true;
+ }
+ else
+ {
+ last_submitted_texture = nullptr;
+ return false;
+ }
+}
+
#ifdef WIN64
#define IVRCompositor_Submit_Impl(vtable_offset, interface_version, impl) \
static vr::EVRCompositorError IVRCompositor_Submit_##interface_version(vr::IVRCompositor *pCompositor, IVRCompositor_Submit_##interface_version##_ArgTypes) \
@@ -195,50 +227,80 @@ static bool on_submit_vulkan(vr::EVREye, const vr::VRVulkanTextureData_t *textur
#define IVRCompositor_Submit_012_ArgNames eEye, pTexture, pBounds, nSubmitFlags
IVRCompositor_Submit_Impl(6, 007, {
- switch (eTextureType)
+ if (!should_apply_effects(pTexture, pBounds))
+ status = true;
+ else
{
- case 0: // API_DirectX
- status = on_submit_d3d11(eEye, static_cast(pTexture), pBounds);
- break;
- case 1: // API_OpenGL
- status = on_submit_opengl(eEye, static_cast(reinterpret_cast(pTexture)), false, false, pBounds);
- break;
+ update_submit_info(eEye, nullptr, nullptr, vr::Submit_Default);
+ switch (eTextureType)
+ {
+ case 0: // API_DirectX
+ status = on_submit_d3d11(eEye, static_cast(pTexture), pBounds);
+ break;
+ case 1: // API_OpenGL
+ status = on_submit_opengl(eEye, static_cast(reinterpret_cast(pTexture)), false, false, pBounds);
+ break;
+ }
} })
IVRCompositor_Submit_Impl(6, 008, {
- switch (eTextureType)
+ if (!should_apply_effects(pTexture, pBounds))
+ status = true;
+ else
{
- case 0: // API_DirectX
- status = on_submit_d3d11(eEye, static_cast(pTexture), pBounds);
- break;
- case 1: // API_OpenGL
- status = on_submit_opengl(eEye, static_cast(reinterpret_cast(pTexture)), (nSubmitFlags & vr::Submit_GlRenderBuffer) != 0, false, pBounds);
- break;
+ update_submit_info(eEye, nullptr, nullptr, vr::Submit_Default);
+ switch (eTextureType)
+ {
+ case 0: // API_DirectX
+ status = on_submit_d3d11(eEye, static_cast(pTexture), pBounds);
+ break;
+ case 1: // API_OpenGL
+ status = on_submit_opengl(eEye, static_cast(reinterpret_cast(pTexture)), (nSubmitFlags & vr::Submit_GlRenderBuffer) != 0, false, pBounds);
+ break;
+ }
} })
IVRCompositor_Submit_Impl(4, 009, {
- switch (pTexture->eType)
+ if (pTexture->handle == nullptr)
+ return vr::VRCompositorError_InvalidTexture;
+ update_submit_info(eEye, pTexture, pBounds, nSubmitFlags);
+
+ if (!should_apply_effects(pTexture->handle, pBounds))
+ status = true;
+ else
{
- case vr::TextureType_DirectX:
- status = on_submit_d3d11(eEye, static_cast(pTexture->handle), pBounds);
- break;
- case vr::TextureType_OpenGL:
- status = on_submit_opengl(eEye, static_cast(reinterpret_cast(pTexture->handle)), (nSubmitFlags & vr::Submit_GlRenderBuffer) != 0, false, pBounds);
- break;
+ switch (pTexture->eType)
+ {
+ case vr::TextureType_DirectX:
+ status = on_submit_d3d11(eEye, static_cast(pTexture->handle), pBounds);
+ break;
+ case vr::TextureType_OpenGL:
+ status = on_submit_opengl(eEye, static_cast(reinterpret_cast(pTexture->handle)), (nSubmitFlags & vr::Submit_GlRenderBuffer) != 0, false, pBounds);
+ break;
+ }
} })
IVRCompositor_Submit_Impl(5, 012, {
- switch (pTexture->eType)
+ if (pTexture->handle == nullptr)
+ return vr::VRCompositorError_InvalidTexture;
+ update_submit_info(eEye, pTexture, pBounds, nSubmitFlags);
+
+ if (!should_apply_effects(pTexture->handle, pBounds))
+ status = true;
+ else
{
- case vr::TextureType_DirectX:
- status = on_submit_d3d11(eEye, static_cast(pTexture->handle), pBounds);
- break;
- case vr::TextureType_DirectX12:
- status = on_submit_d3d12(eEye, static_cast(pTexture->handle), pBounds);
- break;
- case vr::TextureType_OpenGL:
- status = on_submit_opengl(eEye, static_cast(reinterpret_cast(pTexture->handle)), (nSubmitFlags & vr::Submit_GlRenderBuffer) != 0, (nSubmitFlags & vr::Submit_GlArrayTexture) != 0, pBounds);
- break;
- case vr::TextureType_Vulkan:
- status = on_submit_vulkan(eEye, static_cast(pTexture->handle), (nSubmitFlags & vr::Submit_VulkanTextureWithArrayData) != 0, pBounds);
- break;
+ switch (pTexture->eType)
+ {
+ case vr::TextureType_DirectX:
+ status = on_submit_d3d11(eEye, static_cast(pTexture->handle), pBounds);
+ break;
+ case vr::TextureType_DirectX12:
+ status = on_submit_d3d12(eEye, static_cast(pTexture->handle), pBounds);
+ break;
+ case vr::TextureType_OpenGL:
+ status = on_submit_opengl(eEye, static_cast(reinterpret_cast(pTexture->handle)), (nSubmitFlags & vr::Submit_GlRenderBuffer) != 0, (nSubmitFlags & vr::Submit_GlArrayTexture) != 0, pBounds);
+ break;
+ case vr::TextureType_Vulkan:
+ status = on_submit_vulkan(eEye, static_cast(pTexture->handle), (nSubmitFlags & vr::Submit_VulkanTextureWithArrayData) != 0, pBounds);
+ break;
+ }
} })
HOOK_EXPORT uint32_t VR_CALLTYPE VR_InitInternal2(vr::EVRInitError *peError, vr::EVRApplicationType eApplicationType, const char *pStartupInfo)
diff --git a/source/openvr/reshade_vr.hpp b/source/openvr/reshade_vr.hpp
new file mode 100644
index 0000000000..82c12cb342
--- /dev/null
+++ b/source/openvr/reshade_vr.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "reshade_api.hpp"
+
+namespace reshade::vr
+{
+ struct submit_info
+ {
+ static constexpr uint8_t GUID[16] = { 0x20, 0x98, 0x62, 0x08, 0xA2, 0x5E, 0x47, 0x43, 0xBC, 0x2B, 0x42, 0xF2, 0xA6, 0x23, 0xBB, 0xB6 };
+
+ uint8_t eye = 0;
+ api::resource_handle color = {0};
+ api::resource_handle depth = {0};
+ api::region region;
+ };
+}