diff --git a/gamebridge_reshade/src/directx12weaver.cpp b/gamebridge_reshade/src/directx12weaver.cpp index 116c269..6d6e416 100644 --- a/gamebridge_reshade/src/directx12weaver.cpp +++ b/gamebridge_reshade/src/directx12weaver.cpp @@ -63,7 +63,7 @@ bool DirectX12Weaver::init_weaver(reshade::api::effect_runtime* runtime, reshade std::string latencyLog = "Current latency mode set to: STATIC " + std::to_string(DEFAULT_WEAVER_LATENCY) + " Microseconds"; reshade::log_message(reshade::log_level::info, latencyLog.c_str()); } - catch (std::exception e) { + catch (std::exception& e) { reshade::log_message(reshade::log_level::info, e.what()); return false; } @@ -116,73 +116,25 @@ void DirectX12Weaver::draw_settings_overlay(reshade::api::effect_runtime* runtim { } -bool DirectX12Weaver::init_effect_copy_resources(reshade::api::effect_runtime* runtime) { - // Only initialize resources once - if (effect_copy_resources_initialized) { - return true; - } - - uint32_t num_buffers = runtime->get_back_buffer_count(); - - // Init copy resource vectors - effect_copy_resources = std::vector(num_buffers); - effect_copy_resource_res = std::vector(num_buffers); - - // Create copy resource for every back buffer - for (uint32_t i = 0; i < num_buffers; i++) { - if (!create_effect_copy_resource(runtime, i)) { - // Destroy on failure - destroy_effect_copy_resources(); - - log_message(reshade::log_level::info, "Failed initialing frame copy resources"); - return false; - } - } - - effect_copy_resources_initialized = true; - return true; -} +bool DirectX12Weaver::create_effect_copy_buffer(const reshade::api::resource_desc& effect_resource_desc) { + reshade::api::resource_desc desc = effect_resource_desc; + desc.type = reshade::api::resource_type::texture_2d; + desc.heap = reshade::api::memory_heap::gpu_only; + desc.usage = reshade::api::resource_usage::copy_dest; -bool DirectX12Weaver::create_effect_copy_resource(reshade::api::effect_runtime* runtime, uint32_t back_buffer_index) { - reshade::api::resource_desc back_buffer_desc(d3d12_device->get_resource_desc(runtime->get_back_buffer(back_buffer_index))); - reshade::api::resource_desc copy_resource_description( - reshade::api::resource_type::texture_2d, - back_buffer_desc.texture.width, - back_buffer_desc.texture.height, - back_buffer_desc.texture.depth_or_layers, - back_buffer_desc.texture.levels, - back_buffer_desc.texture.format, - 1, - reshade::api::memory_heap::gpu_only, - reshade::api::resource_usage::copy_dest | reshade::api::resource_usage::unordered_access - ); + if (!d3d12_device->create_resource(reshade::api::resource_desc(desc.texture.width, desc.texture.height, desc.texture.depth_or_layers, desc.texture.levels, desc.texture.format, 1, reshade::api::memory_heap::gpu_only, reshade::api::resource_usage::copy_dest | reshade::api::resource_usage::unordered_access), + nullptr, reshade::api::resource_usage::unordered_access, &effect_frame_copy)) { - if (!d3d12_device->create_resource(copy_resource_description, nullptr, reshade::api::resource_usage::unordered_access, &effect_copy_resources[back_buffer_index])) { - - log_message(reshade::log_level::info, "Failed to initialize copy resource"); - - effect_copy_resource_res[back_buffer_index].x = 0; - effect_copy_resource_res[back_buffer_index].y = 0; + effect_frame_copy_x = 0; + effect_frame_copy_y = 0; + reshade::log_message(reshade::log_level::warning, "Failed creating the effect frame copy"); return false; } - effect_copy_resource_res[back_buffer_index].x = back_buffer_desc.texture.width; - effect_copy_resource_res[back_buffer_index].y = back_buffer_desc.texture.height; - - return true; -} - -bool DirectX12Weaver::destroy_effect_copy_resources() -{ - for (uint32_t i = 0; i < effect_copy_resources.size(); i++) { - d3d12_device->destroy_resource(effect_copy_resources[i]); + effect_frame_copy_x = desc.texture.width; + effect_frame_copy_y = desc.texture.height; - effect_copy_resource_res[i].x = 0; - effect_copy_resource_res[i].y = 0; - } - - effect_copy_resources_initialized = false; return true; } @@ -190,8 +142,6 @@ void DirectX12Weaver::on_reshade_finish_effects(reshade::api::effect_runtime* ru reshade::api::resource rtv_resource = d3d12_device->get_resource_from_view(rtv); reshade::api::resource_desc desc = d3d12_device->get_resource_desc(rtv_resource); - uint32_t back_buffer_index = runtime->get_current_back_buffer_index(); - if (weaver_initialized) { // Check if we need to set the latency in frames. if(get_latency_mode() == LatencyModes::latencyInFramesAutomatic) { @@ -199,105 +149,59 @@ void DirectX12Weaver::on_reshade_finish_effects(reshade::api::effect_runtime* ru } // Check texture size - if (desc.texture.width != effect_copy_resource_res[back_buffer_index].x || desc.texture.height != effect_copy_resource_res[back_buffer_index].y) { - //TODO Might have to get the buffer from the create_effect_copy_buffer function and only swap them when creation succeeds - - // Copy to destroy list - Destroy_Resource_Data type; - type.frames_alive = 0; - type.resource = effect_copy_resources[back_buffer_index]; - to_destroy.push_back(type); - - reshade::log_message(reshade::log_level::info, "Resource marked for destroy"); - - if (!create_effect_copy_resource(runtime, back_buffer_index) /** && !resize_buffer_failed **/) { - reshade::log_message(reshade::log_level::warning, "Couldn't create effect copy buffer, trying again next frame"); + if (desc.texture.width != effect_frame_copy_x || desc.texture.height != effect_frame_copy_y) { + // TODO Might have to get the buffer from the create_effect_copy_buffer function and only swap them when creation succeeds + // Destroy the resource only when the GPU is finished drawing. + runtime->get_command_queue()->wait_idle(); + d3d12_device->destroy_resource(effect_frame_copy); + if (!create_effect_copy_buffer(desc) && !resize_buffer_failed) { + reshade::log_message(reshade::log_level::info, "Couldn't create effect copy buffer, trying again next frame"); + resize_buffer_failed = true; } - reshade::log_message(reshade::log_level::info, "Buffer size changed"); + // Set newly create buffer as input + weaver->setInputFrameBuffer((ID3D12Resource*)effect_frame_copy.handle); + reshade::log_message(reshade::log_level::warning, "Buffer size changed"); } else { if (weaving_enabled) { + weaver->setCommandList((ID3D12GraphicsCommandList*)cmd_list->get_native()); + // Create copy of the effect buffer - cmd_list->barrier(effect_copy_resources[back_buffer_index], reshade::api::resource_usage::unordered_access, reshade::api::resource_usage::copy_dest); + cmd_list->barrier(effect_frame_copy, reshade::api::resource_usage::unordered_access, reshade::api::resource_usage::copy_dest); cmd_list->barrier(rtv_resource, reshade::api::resource_usage::render_target, reshade::api::resource_usage::copy_source); - cmd_list->copy_resource(rtv_resource, effect_copy_resources[back_buffer_index]); + cmd_list->copy_resource(rtv_resource, effect_frame_copy); cmd_list->barrier(rtv_resource, reshade::api::resource_usage::copy_source, reshade::api::resource_usage::render_target); // Bind back buffer as render target cmd_list->bind_render_targets_and_depth_stencil(1, &rtv); // Weave to back buffer - weaver->setCommandList((ID3D12GraphicsCommandList*)cmd_list->get_native()); - cmd_list->barrier(effect_copy_resources[back_buffer_index], reshade::api::resource_usage::copy_dest, reshade::api::resource_usage::unordered_access); - weaver->setInputFrameBuffer((ID3D12Resource*)effect_copy_resources[back_buffer_index].handle); + cmd_list->barrier(effect_frame_copy, reshade::api::resource_usage::copy_dest, reshade::api::resource_usage::unordered_access); + //weaver->setInputFrameBuffer((ID3D12Resource*)effect_frame_copy.handle); weaver->weave(desc.texture.width, desc.texture.height); // Check if the descriptor heap offset is set. If it is, we have to reset the descriptor heaps to ensure the ReShade overlay can render. - if (descriptor_heap_impl_offset_in_bytes != -1) { - // Force reset of descriptor heap state that ReShade keeps (DANGER! THIS WILL BREAK IF THE CLASS LAYOUT IN RESHADE CHANGES, SEE directx12weaver.cpp TO UPDATE KNOWN OFFSETS!) - auto current_descriptor_heaps = reinterpret_cast(reinterpret_cast(cmd_list) + descriptor_heap_impl_offset_in_bytes /* offsetof(reshade::d3d12::command_list_impl, _current_descriptor_heaps) */); - auto testHeap = dynamic_cast(*current_descriptor_heaps); - if (testHeap != nullptr) { - current_descriptor_heaps[0] = nullptr; - current_descriptor_heaps[1] = nullptr; - } - } + cmd_list->bind_descriptor_tables(reshade::api::shader_stage::all, reshade::api::pipeline_layout {}, 0, 0, nullptr); } } } else { - if(!init_effect_copy_resources(runtime)) - { - // Initialization of resources failed. - return; - } - - if (init_weaver(runtime, effect_copy_resources[0], d3d12_device->get_resource_from_view(rtv))) { + create_effect_copy_buffer(desc); + if (init_weaver(runtime, effect_frame_copy, d3d12_device->get_resource_from_view(rtv))) { //Set command list and input frame buffer again to make sure they are correct weaver->setCommandList((ID3D12GraphicsCommandList*)cmd_list->get_native()); - weaver->setInputFrameBuffer((ID3D12Resource*)effect_copy_resources[back_buffer_index].handle); - - // Determine what descriptor heap offset is needed for the loaded version of ReShade. - int32_t offset_for_descriptor_heap = determine_offset_for_descriptor_heap(); - if(offset_for_descriptor_heap > -1) { - descriptor_heap_impl_offset_in_bytes = offset_for_descriptor_heap; - } -#ifdef GET_DESCRIPTOR_OFFSET_FROM_RESHADE_SOURCE - // Code for finding the correct descriptor heap offset in linked-to ReShade version. - class ReShadeCommandListInheritor : public reshade::d3d12::command_list_impl { - public: - static size_t getCurrentHeapDescriptorOffset() { - return offsetof(ReShadeCommandListInheritor, _current_descriptor_heaps); - } - }; - descriptor_heap_impl_offset_in_bytes = ReShadeCommandListInheritor::getCurrentHeapDescriptorOffset(); -#endif - weaver->setInputFrameBuffer((ID3D12Resource*)effect_copy_resources[back_buffer_index].handle); + weaver->setInputFrameBuffer((ID3D12Resource*)effect_frame_copy.handle); } else { - // When buffer creation succeeds and this fails, delete the created buffer - destroy_effect_copy_resources(); + // When buffer creation succeeds and this fails, delete the created buffer after waiting for the GPU to finish. + runtime->get_command_queue()->wait_idle(); + d3d12_device->destroy_resource(effect_frame_copy); reshade::log_message(reshade::log_level::info, "Failed to initialize weaver"); return; } } - - // Destroy resources - for(auto it = to_destroy.begin(); it != to_destroy.end();) - { - it->frames_alive++; - if (it->frames_alive > 5) - { - d3d12_device->destroy_resource(it->resource); - it = to_destroy.erase(it); - reshade::log_message(reshade::log_level::info, "Resource destroyed"); - continue; - } - - ++it; - } } void DirectX12Weaver::on_init_effect_runtime(reshade::api::effect_runtime* runtime) { @@ -309,17 +213,6 @@ void DirectX12Weaver::do_weave(bool doWeave) weaving_enabled = doWeave; } -/** - * Takes a major, minor and patch number from ReShade and concatenates them into a single number for easier processing. - */ -int32_t concatenate_reshade_version(int32_t major, int32_t minor, int32_t patch) { - std::string result = ""; - result += std::to_string(major); - result += std::to_string(minor); - result += std::to_string(patch); - return std::stoi(result); -} - /** * Find the closest element to a given value in a sorted array. * @@ -354,44 +247,6 @@ int32_t find_closest(const std::vector& sorted_array, int target_value) return closest_value; } -/** - * Compares the version of the ReShade with the list of known offsets. - * If version is smaller than 5.9.X, this check will return an offset of -1 to signal no offset is required. - * Update: Version 5.9.X now crashes with the most recent version of the SD3D shader and our addon. I am choosing to up the minimum version to 6.0.0. - * If the version number is not on the list of known ones, we will use the offset of the closest known version to it. - */ -int32_t DirectX12Weaver::determine_offset_for_descriptor_heap() { - int32_t result; - int32_t reshade_version_concat = concatenate_reshade_version(reshade_version_nr_major, reshade_version_nr_minor, - reshade_version_nr_patch); - if (reshade_version_concat < 590) { - // No offset needed, return -1 - return -1; - } - std::vector descriptor_offset_versions; - for(auto it = known_descriptor_heap_offsets_by_version.begin(); it != known_descriptor_heap_offsets_by_version.end(); ++it ) { - descriptor_offset_versions.push_back(it->first ); - } - - try { - result = known_descriptor_heap_offsets_by_version.at(find_closest(descriptor_offset_versions, reshade_version_concat)); - } - catch (std::out_of_range& e) { - std::string error_msg = "Couldn't find correct ReShade version descriptor heap offset because the requested known descriptor offset is out of index:\n"; - error_msg += e.what(); - reshade::log_message(reshade::log_level::warning, error_msg.c_str()); - return -1; - } - catch (std::invalid_argument& e) { - std::string errorMsg = "Couldn't find correct ReShade version descriptor heap offset because the known descriptor offset list is empty:\n"; - errorMsg += e.what(); - reshade::log_message(reshade::log_level::warning, errorMsg.c_str()); - return -1; - } - - return result; -} - bool DirectX12Weaver::set_latency_in_frames(int32_t numberOfFrames) { if (weaver_initialized) { if (numberOfFrames < 0) { diff --git a/gamebridge_reshade/src/directx12weaver.h b/gamebridge_reshade/src/directx12weaver.h index ceccb5d..889a4fd 100644 --- a/gamebridge_reshade/src/directx12weaver.h +++ b/gamebridge_reshade/src/directx12weaver.h @@ -33,19 +33,12 @@ class DirectX12Weaver: public IGraphicsApi { float view_separation = 0.f; float vertical_shift = 0.f; - size_t descriptor_heap_impl_offset_in_bytes = -1; - // This must be updated for every new version of ReShade as it can change when the class layout changes! - // [key] int32_t represents the version number of ReShade without the periods. [value] int32_t represents the offset in bytes inside the class. - const std::map known_descriptor_heap_offsets_by_version = { - {600, 80}, - }; - reshade::api::command_list* command_list; reshade::api::resource_view game_frame_buffer; - std::vector effect_copy_resources; std::vector effect_copy_resource_res; - bool effect_copy_resources_initialized = false; + reshade::api::resource effect_frame_copy; + uint32_t effect_frame_copy_x = 0, effect_frame_copy_y = 0; std::vector to_destroy; @@ -53,12 +46,10 @@ class DirectX12Weaver: public IGraphicsApi { void set_latency_mode(LatencyModes mode); public: + bool resize_buffer_failed = false; explicit DirectX12Weaver(SR::SRContext* context); bool init_weaver(reshade::api::effect_runtime* runtime, reshade::api::resource rtv, reshade::api::resource back_buffer); - bool init_effect_copy_resources(reshade::api::effect_runtime* runtime); - bool destroy_effect_copy_resources(); - bool create_effect_copy_resource(reshade::api::effect_runtime* runtime, uint32_t back_buffer_index); - int32_t determine_offset_for_descriptor_heap(); + bool create_effect_copy_buffer(const reshade::api::resource_desc& effect_resource_desc); // Inherited via IGraphicsApi void draw_debug_overlay(reshade::api::effect_runtime* runtime) override; diff --git a/gamebridge_reshade/src/dllmain.cpp b/gamebridge_reshade/src/dllmain.cpp index 0930160..455a153 100644 --- a/gamebridge_reshade/src/dllmain.cpp +++ b/gamebridge_reshade/src/dllmain.cpp @@ -35,9 +35,10 @@ HotKeyManager* hotKey_manager = nullptr; //Currently we use this string to determine if we should toggle this shader on press of the shortcut. We can expand this to a list later. static const std::string depth_3D_shader_name = "SuperDepth3D"; -static const std::string fxaa_shader_name = "FXAA"; +static const std::string sr_shader_name = "SR"; static char g_charBuffer[CHAR_BUFFER_SIZE]; static size_t g_charBufferSize = CHAR_BUFFER_SIZE; +static bool effects_are_active = false; std::vector reshade_dll_names = { L"dxgi.dll", L"ReShade.dll", L"ReShade64.dll", L"ReShade32.dll", L"d3d9.dll", L"d3d10.dll", L"d3d11.dll", L"d3d12.dll", L"opengl32.dll" }; @@ -198,23 +199,27 @@ static void draw_settings_overlay(reshade::api::effect_runtime* runtime) { } static void on_reshade_reload_effects(reshade::api::effect_runtime* runtime) { - vector fxaaTechnique = {}; + vector sr_technique = {}; // Todo: This is not a nice way of forcing on_finish_effects to trigger. Maybe make a dummy shader that you always turn on instead (or use a different callback) - // Toggle FXAA.fx on - enumerate_techniques(runtime, [&fxaaTechnique](reshade::api::effect_runtime* runtime, reshade::api::effect_technique technique, string& name) { - if (!name.compare(fxaa_shader_name)) { - reshade::log_message(reshade::log_level::info, "Found FXAA.fx shader!"); - fxaaTechnique.push_back(technique); + // Toggle SR.fx on + enumerate_techniques(runtime, [&sr_technique](reshade::api::effect_runtime* runtime, reshade::api::effect_technique technique, string& name) { + if (!name.compare(sr_shader_name)) { + reshade::log_message(reshade::log_level::info, "Found SR.fx shader!"); + sr_technique.push_back(technique); } - }); + }); - for (int effectIterator = 0; effectIterator < fxaaTechnique.size(); effectIterator++) { - runtime->set_technique_state(fxaaTechnique[effectIterator], true); - reshade::log_message(reshade::log_level::info, "Toggled FXAA to ensure on_finish_effects gets called."); + for (int effectIterator = 0; effectIterator < sr_technique.size(); effectIterator++) { + runtime->set_technique_state(sr_technique[effectIterator], true); + reshade::log_message(reshade::log_level::info, "Toggled SR to ensure on_finish_effects gets called."); } } +static void on_reshade_begin_effects(reshade::api::effect_runtime* runtime, reshade::api::command_list* cmd_list, reshade::api::resource_view rtv, reshade::api::resource_view rtv_srgb) { + effects_are_active = false; +} + static void on_reshade_finish_effects(reshade::api::effect_runtime* runtime, reshade::api::command_list* cmd_list, reshade::api::resource_view rtv, reshade::api::resource_view rtv_srgb) { std::map hot_key_list; @@ -225,7 +230,10 @@ static void on_reshade_finish_effects(reshade::api::effect_runtime* runtime, res execute_hot_key_function_by_type(hot_key_list, runtime); } - weaver_implementation->on_reshade_finish_effects(runtime, cmd_list, rtv, rtv_srgb); + // Todo: This workaround should be removed in the next ReShade version (> v6.0.1) + if (effects_are_active) { + weaver_implementation->on_reshade_finish_effects(runtime, cmd_list, rtv, rtv_srgb); + } } static void init_sr() { @@ -281,6 +289,10 @@ static void on_init_effect_runtime(reshade::api::effect_runtime* runtime) { weaver_implementation->on_init_effect_runtime(runtime); } +static void on_render_technique(reshade::api::effect_runtime *runtime, reshade::api::effect_technique technique, reshade::api::command_list *cmd_list, reshade::api::resource_view rtv, reshade::api::resource_view rtv_srgb) { + effects_are_active = true; +} + static void on_destroy_swapchain(reshade::api::swapchain *swapchain) { if(weaver_implementation != nullptr) { weaver_implementation->on_destroy_swapchain(swapchain); @@ -300,9 +312,11 @@ BOOL APIENTRY DllMain( HMODULE hModule, return FALSE; reshade::register_event(&on_init_effect_runtime); + reshade::register_event(&on_reshade_begin_effects); reshade::register_event(&on_reshade_finish_effects); reshade::register_event(&on_reshade_reload_effects); reshade::register_event(&on_destroy_swapchain); + reshade::register_event(&on_render_technique); reshade::register_overlay(nullptr, &draw_status_overlay); diff --git a/gamebridge_reshade/src/igraphicsapi.cpp b/gamebridge_reshade/src/igraphicsapi.cpp index e44ac6f..693776c 100644 --- a/gamebridge_reshade/src/igraphicsapi.cpp +++ b/gamebridge_reshade/src/igraphicsapi.cpp @@ -6,3 +6,14 @@ */ #include "igraphicsapi.h" + +/** + * Takes a major, minor and patch number from ReShade and concatenates them into a single number for easier processing. + */ +int32_t IGraphicsApi::get_concatinated_reshade_version() { + std::string result = ""; + result += std::to_string(reshade_version_nr_major); + result += std::to_string(reshade_version_nr_minor); + result += std::to_string(reshade_version_nr_patch); + return std::stoi(result); +} diff --git a/gamebridge_reshade/src/igraphicsapi.h b/gamebridge_reshade/src/igraphicsapi.h index 15db887..7735fed 100644 --- a/gamebridge_reshade/src/igraphicsapi.h +++ b/gamebridge_reshade/src/igraphicsapi.h @@ -32,6 +32,8 @@ class IGraphicsApi { int32_t reshade_version_nr_minor = 0; int32_t reshade_version_nr_patch = 0; + int32_t get_concatinated_reshade_version(); + virtual void draw_debug_overlay(reshade::api::effect_runtime* runtime) = 0; virtual void draw_sr_settings_overlay(reshade::api::effect_runtime* runtime) = 0; virtual void draw_settings_overlay(reshade::api::effect_runtime* runtime) = 0; diff --git a/gamebridge_reshade/third-party/reshade/include/reshade b/gamebridge_reshade/third-party/reshade/include/reshade index e68e5f9..1c952ec 160000 --- a/gamebridge_reshade/third-party/reshade/include/reshade +++ b/gamebridge_reshade/third-party/reshade/include/reshade @@ -1 +1 @@ -Subproject commit e68e5f9f240b977314a898791149fcbbf905053c +Subproject commit 1c952ec211a91b9ebbf9042e23a4a810feba44ff