Skip to content

Commit

Permalink
Merge pull request #17 from JoeyAnthony/feature/GB-204-reshade-6.0.1
Browse files Browse the repository at this point in the history
Feature/gb 204 reshade 6.0.1
  • Loading branch information
JoeyAnthony authored Feb 1, 2024
2 parents 023979f + 3ebb892 commit b433879
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 208 deletions.
219 changes: 37 additions & 182 deletions gamebridge_reshade/src/directx12weaver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -116,188 +116,92 @@ 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<reshade::api::resource>(num_buffers);
effect_copy_resource_res = std::vector<Int32XY>(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;
}

void DirectX12Weaver::on_reshade_finish_effects(reshade::api::effect_runtime* runtime, reshade::api::command_list* cmd_list, reshade::api::resource_view rtv, reshade::api::resource_view) {
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) {
weaver->setLatencyInFrames(runtime->get_back_buffer_count()); // Set the latency with which the weaver should do prediction.
}

// 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<ID3D12DescriptorHeap **>(reinterpret_cast<uint8_t *>(cmd_list) + descriptor_heap_impl_offset_in_bytes /* offsetof(reshade::d3d12::command_list_impl, _current_descriptor_heaps) */);
auto testHeap = dynamic_cast<ID3D12DescriptorHeap*>(*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) {
Expand All @@ -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.
*
Expand Down Expand Up @@ -354,44 +247,6 @@ int32_t find_closest(const std::vector<int32_t>& 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<int32_t> 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) {
Expand Down
17 changes: 4 additions & 13 deletions gamebridge_reshade/src/directx12weaver.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,32 +33,23 @@ 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<int32_t, int32_t> known_descriptor_heap_offsets_by_version = {
{600, 80},
};

reshade::api::command_list* command_list;
reshade::api::resource_view game_frame_buffer;

std::vector<reshade::api::resource> effect_copy_resources;
std::vector<Int32XY> 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<Destroy_Resource_Data> to_destroy;

LatencyModes current_latency_mode = LatencyModes::framerateAdaptive;
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;
Expand Down
Loading

0 comments on commit b433879

Please sign in to comment.