From b35d80683e9a81f752d0dc3768738f27b0b96c78 Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Wed, 13 Mar 2024 11:30:14 -0400 Subject: [PATCH] feat(devkit): add live shaders --- src/devkit/addon.cpp | 650 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 548 insertions(+), 102 deletions(-) diff --git a/src/devkit/addon.cpp b/src/devkit/addon.cpp index 8588c6a2..26539699 100644 --- a/src/devkit/addon.cpp +++ b/src/devkit/addon.cpp @@ -4,6 +4,7 @@ */ #define IMGUI_DISABLE_INCLUDE_IMCONFIG_H +#define ImTextureID ImU64 #include #include @@ -30,6 +31,17 @@ extern "C" __declspec(dllexport) const char* NAME = "RenoDX - DevKit"; extern "C" __declspec(dllexport) const char* DESCRIPTION = "RenoDX DevKit Module"; +struct CachedPipeline { + reshade::api::pipeline pipeline; + reshade::api::device* device; + reshade::api::pipeline_layout layout; + reshade::api::pipeline_subobject* subobjectsCache; + uint32_t subobjectCount; + bool cloned; + reshade::api::pipeline pipelineClone; + uint32_t shaderHash; +}; + struct CachedShader { void* data = nullptr; size_t size = 0; @@ -38,20 +50,221 @@ struct CachedShader { }; std::shared_mutex s_mutex; + std::unordered_set computeShaderLayouts; -std::unordered_map pipelineToLayoutMap; -std::unordered_map pipelineToShaderHash; -std::unordered_map shaderCache; -std::unordered_set originalShaders; +std::unordered_set backBuffers; + +std::unordered_map pipelineCacheByPipelineHandle; +std::unordered_map pipelineCacheByShaderHash; +std::unordered_map shaderCache; + +std::unordered_map pipelineCloneMap; + std::vector traceHashes; static bool traceScheduled = false; static bool traceRunning = false; +static bool needsLiveReload = false; static uint32_t shaderCacheCount = 0; static uint32_t shaderCacheSize = 0; static uint32_t traceCount = 0; +static uint32_t presentCount = 0; + +std::filesystem::path getShaderPath() { + wchar_t file_prefix[MAX_PATH] = L""; + GetModuleFileNameW(nullptr, file_prefix, ARRAYSIZE(file_prefix)); + + std::filesystem::path dump_path = file_prefix; + dump_path = dump_path.parent_path(); + dump_path /= ".\\renodx-dev"; + return dump_path; +} + +static void loadLiveShaders() { + const std::unique_lock lock(s_mutex); + reshade::log_message(reshade::log_level::debug, "loadLiveShader()"); + + // Clear all shaders + for (auto pair : pipelineCacheByPipelineHandle) { + auto cachedPipeline = pair.second; + if (!cachedPipeline->cloned) continue; + cachedPipeline->device->destroy_pipeline(cachedPipeline->pipelineClone); + cachedPipeline->cloned = false; + } + + auto directory = getShaderPath(); + directory /= ".\\live"; + + if (std::filesystem::exists(directory) == false) { + std::stringstream s; + s << "loadLiveShaders(Directory not found: " + << directory.string() + << ")"; + reshade::log_message(reshade::log_level::warning, s.str().c_str()); + return; + } + + for (const auto &entry : std::filesystem::directory_iterator(directory)) { + if (!entry.is_regular_file()) { + reshade::log_message(reshade::log_level::warning, "loadLiveShaders(not a regular file)"); + continue; + } + auto entryPath = entry.path(); + if (!entryPath.has_extension()) { + std::stringstream s; + s << "loadLiveShaders(Missing extension: " + << entryPath.string() + << ")"; + reshade::log_message(reshade::log_level::warning, s.str().c_str()); + continue; + } + if (entryPath.extension().compare(".cso") != 0) { + std::stringstream s; + s << "loadLiveShaders(Missing not .cso: " + << entryPath.string() + << ")"; + reshade::log_message(reshade::log_level::warning, s.str().c_str()); + continue; + } + + auto filename = entryPath.filename(); + auto filename_string = filename.string(); + if (filename_string.size() != 14) { + std::stringstream s; + s << "loadLiveShaders(Filename length not 14: " + << filename_string + << ")"; + reshade::log_message(reshade::log_level::warning, s.str().c_str()); + continue; + } + uint32_t hash = std::stoi(filename_string.substr(2, 8), nullptr, 16); + + auto pair = pipelineCacheByShaderHash.find(hash); + if (pair == pipelineCacheByShaderHash.end()) { + std::stringstream s; + s << "loadLiveShaders(Unknown hash: 0x" + << std::hex << hash << std::dec + << ")"; + reshade::log_message(reshade::log_level::warning, s.str().c_str()); + continue; + } + CachedPipeline* cachedPipeline = pair->second; + + reshade::log_message(reshade::log_level::debug, "Reading file..."); + std::ifstream file(entryPath, std::ios::binary); + file.seekg(0, std::ios::end); + size_t code_size = file.tellg(); + char* code = reinterpret_cast(malloc((code_size + 1) * sizeof(char))); + file.seekg(0, std::ios::beg).read(code, code_size); + code[code_size] = NULL; + + { + std::stringstream s; + s << "loadLiveShaders(Read " + << code_size << " bytes " + << " from " << entryPath.string() + << ")"; + reshade::log_message(reshade::log_level::debug, s.str().c_str()); + } + + // DX12 can use PSO objects that need to be cloned + + uint32_t subobjectCount = cachedPipeline->subobjectCount; + reshade::api::pipeline_subobject* subobjects = cachedPipeline->subobjectsCache; + reshade::api::pipeline_subobject* newSubobjects = new reshade::api::pipeline_subobject[subobjectCount]; + memcpy(newSubobjects, cachedPipeline->subobjectsCache, sizeof(reshade::api::pipeline_subobject) * subobjectCount); + + { + std::stringstream s; + s << "loadLiveShaders(Cloning pipeline " + << reinterpret_cast(cachedPipeline->pipeline.handle) + << " with " << subobjectCount << " object(s)" + << ")"; + reshade::log_message(reshade::log_level::debug, s.str().c_str()); + } + reshade::log_message(reshade::log_level::debug, "Iterating pipeline..."); + + bool needsClone = false; + bool foundComputeShader = false; + bool foundInjection = false; + for (uint32_t i = 0; i < subobjectCount; ++i) { + reshade::log_message(reshade::log_level::debug, "Checking subobject..."); + const auto subobject = subobjects[i]; + switch (subobject.type) { + case reshade::api::pipeline_subobject_type::compute_shader: + case reshade::api::pipeline_subobject_type::pixel_shader: + break; + default: + continue; + } + const reshade::api::shader_desc desc = *static_cast(subobject.data); + + // if (desc.code_size == 0) { + // reshade::log_message(reshade::log_level::warning, "Code size 0"); + // continue; + // } + + // reshade::log_message(reshade::log_level::debug, "Computing hash..."); + // Pipeline has a pixel shader with code. Hash code and check + // auto shader_hash = compute_crc32(static_cast(desc.code), desc.code_size); + // if (hash != shader_hash) { + // reshade::log_message(reshade::log_level::warning, ""); + // continue; + // } + + auto cloneSubject = &newSubobjects[i]; + + auto newDesc = static_cast(cloneSubject->data); -void logLayout( + newDesc->code = code; + newDesc->code_size = code_size; + + auto new_hash = compute_crc32(static_cast(newDesc->code), newDesc->code_size); + + std::stringstream s; + s << "loadLiveShaders(Injected pipeline data" + << " with 0x" << std::hex << new_hash << std::dec + << " (" << code_size << " bytes)" + << ")"; + reshade::log_message(reshade::log_level::debug, s.str().c_str()); + } + + { + std::stringstream s; + s << "Creating pipeline clone (" + << "hash: 0x" << std::hex << hash << std::dec + << ", layout: 0x" << std::hex << cachedPipeline->layout.handle << std::dec + << ", subobjectcount: " << subobjectCount + << ")"; + reshade::log_message(reshade::log_level::debug, s.str().c_str()); + } + + reshade::api::pipeline pipelineClone; + bool builtPipelineOK = cachedPipeline->device->create_pipeline( + cachedPipeline->layout, + subobjectCount, + &newSubobjects[0], + &pipelineClone + ); + if (builtPipelineOK) { + pipelineCloneMap.emplace(cachedPipeline->pipeline.handle, pipelineClone); + cachedPipeline->pipelineClone = pipelineClone; + cachedPipeline->cloned = true; + } + // free(code); + std::stringstream s; + s << "init_pipeline(cloned " + << reinterpret_cast(cachedPipeline->pipeline.handle) + << " => " << reinterpret_cast(pipelineClone.handle) + << ", layout: " << reinterpret_cast(cachedPipeline->layout.handle) + << ", size: " << subobjectCount + << ", " << (builtPipelineOK ? "OK" : "FAILED!") + << ")"; + reshade::log_message(builtPipelineOK ? reshade::log_level::info : reshade::log_level::error, s.str().c_str()); + } +} + +static void logLayout( const uint32_t paramCount, const reshade::api::pipeline_layout_param* params, uint32_t tag @@ -106,7 +319,7 @@ void logLayout( } } else if (param.type == reshade::api::pipeline_layout_param_type::push_constants) { std::stringstream s; - s << "pipeline_layout("; + s << "logPipelineLayout("; s << tag; s << " | PC" << " | " << param.push_constants.binding @@ -119,7 +332,7 @@ void logLayout( reshade::log_message(reshade::log_level::info, s.str().c_str()); } else if (param.type == reshade::api::pipeline_layout_param_type::push_descriptors) { std::stringstream s; - s << "pipeline_layout("; + s << "logPipelineLayout("; s << tag; s << " | PD" << " | " << param.push_descriptors.array_size @@ -134,7 +347,7 @@ void logLayout( reshade::log_message(reshade::log_level::info, s.str().c_str()); } else if (param.type == reshade::api::pipeline_layout_param_type::push_descriptors_with_ranges) { std::stringstream s; - s << "pipeline_layout(" + s << "logPipelineLayout(" << tag << " | PDR?? | " << ")" @@ -142,7 +355,7 @@ void logLayout( reshade::log_message(reshade::log_level::info, s.str().c_str()); } else { std::stringstream s; - s << "pipeline_layout(" + s << "logPipelineLayout(" << tag << " | ???" << " | " << (uint32_t)param.type @@ -154,6 +367,19 @@ void logLayout( } static void on_init_swapchain(reshade::api::swapchain* swapchain) { + const size_t backBufferCount = swapchain->get_back_buffer_count(); + + for (uint32_t index = 0; index < backBufferCount; index++) { + auto buffer = swapchain->get_back_buffer(index); + backBuffers.emplace(buffer.handle); + + std::stringstream s; + s << "init_swapchain(" + << "buffer:" << reinterpret_cast(buffer.handle) + << ")"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); + } + std::stringstream s; s << "init_swapchain" << "(colorspace: " << (uint32_t)swapchain->get_color_space() @@ -209,29 +435,6 @@ static void on_init_pipeline_layout( reshade::log_message(reshade::log_level::info, s.str().c_str()); } -static bool on_create_pipeline( - reshade::api::device* device, - reshade::api::pipeline_layout layout, - uint32_t subobject_count, - const reshade::api::pipeline_subobject* subobjects -) { - const reshade::api::device_api device_type = device->get_api(); - - for (uint32_t i = 0; i < subobject_count; ++i) { - switch (subobjects[i].type) { - case reshade::api::pipeline_subobject_type::compute_shader: - case reshade::api::pipeline_subobject_type::pixel_shader: - const reshade::api::shader_desc desc = *static_cast(subobjects[i].data); - if (desc.code_size == 0) continue; - auto shader_hash = compute_crc32(static_cast(desc.code), desc.code_size); - originalShaders.emplace(shader_hash); - break; - } - } - - return false; -} - // After CreatePipelineState static void on_init_pipeline( reshade::api::device* device, @@ -240,61 +443,111 @@ static void on_init_pipeline( const reshade::api::pipeline_subobject* subobjects, reshade::api::pipeline pipeline ) { + reshade::api::pipeline_subobject* newSubobjects = new reshade::api::pipeline_subobject[subobjectCount]; + memcpy(newSubobjects, subobjects, sizeof(reshade::api::pipeline_subobject) * subobjectCount); + + std::stringstream s; + s << "on_init_pipeline(" + << reinterpret_cast(pipeline.handle) + << " on " << reinterpret_cast(layout.handle) + << ", subobjects: " << (subobjectCount) + << " )"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); + + CachedPipeline* cachedPipeline = new CachedPipeline{ + pipeline, + device, + layout, + newSubobjects, + subobjectCount + }; + for (uint32_t i = 0; i < subobjectCount; ++i) { switch (subobjects[i].type) { case reshade::api::pipeline_subobject_type::compute_shader: + computeShaderLayouts.emplace(layout.handle); case reshade::api::pipeline_subobject_type::pixel_shader: break; default: + { + std::stringstream s; + s << "on_init_pipeline(" + << reinterpret_cast(pipeline.handle) + << ", subobject: " << (uint32_t)subobjects[i].type + << " )"; + reshade::log_message(reshade::log_level::debug, s.str().c_str()); + } + // likely should be cloned continue; } - const reshade::api::shader_desc desc = *static_cast(subobjects[i].data); - if (desc.code_size == 0) continue; - // Pipeline has a pixel shader with code. Hash code and check - auto shader_hash = compute_crc32(static_cast(desc.code), desc.code_size); + auto cloneSubject = &newSubobjects[i]; + auto desc = static_cast(cloneSubject->data); + // Clone desc + reshade::api::shader_desc clonedDesc; + memcpy(&clonedDesc, desc, sizeof(reshade::api::shader_desc)); + // Point to cloned desc + cloneSubject->data = &clonedDesc; + + if (desc->code_size == 0) continue; + + auto shader_hash = compute_crc32(static_cast(desc->code), desc->code_size); // Cache shader + CachedShader* cache = new CachedShader{ + malloc(desc->code_size), + desc->code_size + }; + memcpy(cache->data, desc->code, cache->size); + shaderCacheCount++; + shaderCacheSize += cache->size; + shaderCache.emplace(shader_hash, cache); - if (shaderCache.count(shader_hash) == 0) { - CachedShader cache = {malloc(desc.code_size), desc.code_size}; - memcpy(cache.data, desc.code, cache.size); - shaderCache.emplace(shader_hash, cache); - shaderCacheCount++; - shaderCacheSize += cache.size; - std::stringstream s; - s << "caching shader(" - << "hash: 0x" << std::hex << shader_hash << std::dec - << ", type: " << (uint32_t)subobjects[i].type - << ")"; - reshade::log_message(reshade::log_level::info, s.str().c_str()); - } - pipelineToLayoutMap.emplace(pipeline.handle, layout); - pipelineToLayoutMap.emplace(pipeline.handle, layout); - pipelineToShaderHash.emplace(pipeline.handle, shader_hash); + // Point to cached shader + clonedDesc.code = cache->data; - bool isComputeShader = subobjects[i].type == reshade::api::pipeline_subobject_type::compute_shader; - if (isComputeShader) { - computeShaderLayouts.emplace(layout.handle); - } + // Indexes + cachedPipeline->shaderHash = shader_hash; + pipelineCacheByShaderHash.emplace(shader_hash, cachedPipeline); + + // Metrics std::stringstream s; - s << "on_init_pipeline(" - << reinterpret_cast(pipeline.handle) - << ", " << reinterpret_cast(layout.handle) - << ", hash: 0x" << std::hex << shader_hash << std::dec - << ", type: " << (isComputeShader ? "compute" : "graphics") + s << "caching shader(" + << "hash: 0x" << std::hex << shader_hash << std::dec + << ", type: " << (uint32_t)subobjects[i].type + << ", pipeline: " << reinterpret_cast(pipeline.handle) << ")"; reshade::log_message(reshade::log_level::info, s.str().c_str()); } + pipelineCacheByPipelineHandle.emplace(pipeline.handle, cachedPipeline); } static void on_destroy_pipeline( reshade::api::device* device, reshade::api::pipeline pipeline ) { - pipelineToLayoutMap.erase(pipeline.handle); - computeShaderLayouts.erase(pipeline.handle); - pipelineToShaderHash.erase(pipeline.handle); + uint32_t changed = false; + changed |= computeShaderLayouts.erase(pipeline.handle); + auto pipelineCachePair = pipelineCacheByPipelineHandle.find(pipeline.handle); + if (pipelineCachePair != pipelineCacheByPipelineHandle.end()) { + free(pipelineCachePair->second); + pipelineCacheByPipelineHandle.erase(pipeline.handle); + changed = true; + } + + auto pipelineClonePair = pipelineCloneMap.find(pipeline.handle); + if (pipelineClonePair != pipelineCloneMap.end()) { + pipelineCloneMap.erase(pipeline.handle); + device->destroy_pipeline(pipelineClonePair->second); + changed = true; + } + if (!changed) return; + + std::stringstream s; + s << "on_destroy_pipeline(" + << reinterpret_cast(pipeline.handle) + << " )"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); } // AfterSetPipelineState @@ -303,29 +556,43 @@ static void on_bind_pipeline( reshade::api::pipeline_stage type, reshade::api::pipeline pipeline ) { - if (!traceRunning) return; const std::unique_lock lock(s_mutex); - auto pair0 = pipelineToLayoutMap.find(pipeline.handle); - if (pair0 == pipelineToLayoutMap.end()) return; - auto layout = pair0->second; + auto pipelineToClone = pipelineCloneMap.find(pipeline.handle); + if (pipelineToClone != pipelineCloneMap.end()) { + auto newPipeline = pipelineToClone->second; - bool isComputeShader = (computeShaderLayouts.count(layout.handle) != 0); + if (traceRunning) { + std::stringstream s; + s << "bind_pipeline(swapping pipeline " + << reinterpret_cast(pipeline.handle) + << " => " << reinterpret_cast(newPipeline.handle) + << ", stage: " << std::hex << (uint32_t)type + << ")"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); + } - uint32_t shader_hash = 0; - auto pair1 = pipelineToShaderHash.find(pipeline.handle); - if (pair1 != pipelineToShaderHash.end()) { - shader_hash = pair1->second; + cmd_list->bind_pipeline(type, newPipeline); } - if (shader_hash) { - traceHashes.push_back(shader_hash); + + if (!traceRunning) return; + + auto pair0 = pipelineCacheByPipelineHandle.find(pipeline.handle); + if (pair0 == pipelineCacheByPipelineHandle.end()) return; + auto cachedPipeline = pair0->second; + + bool isComputeShader = (computeShaderLayouts.count(cachedPipeline->layout.handle) != 0); + + if (cachedPipeline->shaderHash) { + traceHashes.push_back(cachedPipeline->shaderHash); } std::stringstream s; s << "bind_pipeline(" - << reinterpret_cast(pipeline.handle) - << ", " << reinterpret_cast(layout.handle) - << ", " << (isComputeShader ? "compute" : "graphics") - << ", 0x" << std::hex << shader_hash << std::dec + << traceHashes.size() << ": " + << reinterpret_cast(cachedPipeline->pipeline.handle) + << ", " << reinterpret_cast(cachedPipeline->layout.handle) + << ", type: " << std::hex << (uint32_t)type << std::dec + << ", 0x" << std::hex << cachedPipeline->shaderHash << std::dec << ")"; reshade::log_message(reshade::log_level::info, s.str().c_str()); } @@ -368,6 +635,19 @@ static bool on_draw( return false; } +static bool on_dispatch(reshade::api::command_list* cmd_list, uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z) { + if (traceRunning) { + std::stringstream s; + s << "on_dispatch" + << "(" << group_count_x + << ", " << group_count_y + << ", " << group_count_z + << ")"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); + } + return false; +} + static bool on_draw_indexed( reshade::api::command_list* cmd_list, uint32_t index_count, @@ -435,6 +715,154 @@ static bool on_copy_texture_region( return false; } +static bool on_resolve_texture_region( + reshade::api::command_list* cmd_list, + reshade::api::resource source, + uint32_t source_subresource, + const reshade::api::subresource_box* source_box, + reshade::api::resource dest, + uint32_t dest_subresource, + int32_t dest_x, + int32_t dest_y, + int32_t dest_z, + reshade::api::format format +) { + if (traceRunning) { + std::stringstream s; + s << "on_resolve_texture_region" + << "(" << reinterpret_cast(source.handle) + << ": " << (source_subresource) + << " => " << reinterpret_cast(dest.handle) + << ": " << (dest_subresource) + << ", (" << dest_x << ", " << dest_y << ", " << dest_z << ") " + << ")"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); + } + return false; +} + +static bool on_copy_resource( + reshade::api::command_list* cmd_list, + reshade::api::resource source, + reshade::api::resource dest +) { + if (traceRunning) { + std::stringstream s; + s << "on_copy_resource" + << "(" << reinterpret_cast(source.handle) + << " => " << reinterpret_cast(dest.handle) + << ")"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); + } + return false; +} + +static void on_barrier( + reshade::api::command_list* cmd_list, + uint32_t count, + const reshade::api::resource* resources, + const reshade::api::resource_usage* old_states, + const reshade::api::resource_usage* new_states +) { + if (traceRunning) { + for (uint32_t i = 0; i < count; i++) { + std::stringstream s; + s << "on_barrier(" + << reinterpret_cast(resources[i].handle) + << ", " << std::hex << (uint32_t)old_states[i] << std::dec + << " => " << std::hex << (uint32_t)new_states[i] << std::dec + << ")" + << "[" << i << "]"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); + } + } +} + +static void on_bind_render_targets_and_depth_stencil( + reshade::api::command_list* cmd_list, + uint32_t count, + const reshade::api::resource_view* rtvs, + reshade::api::resource_view dsv +) { + if (traceRunning) { + for (uint32_t i = 0; i < count; i++) { + auto rtv = rtvs[i]; + std::stringstream s; + s << "on_bind_render_targets_and_depth_stencil(" + << reinterpret_cast(rtv.handle) + << ") => " << reinterpret_cast(dsv.handle) + << "[" << i << "]"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); + } + } +} + +static void on_init_resource( + reshade::api::device* device, + const reshade::api::resource_desc &desc, + const reshade::api::subresource_data* initial_data, + reshade::api::resource_usage initial_state, + reshade::api::resource resource +) { + if (!traceRunning && presentCount >= 5) return; + std::stringstream s; + s << "init_resource(" + << reinterpret_cast(resource.handle) + << ", flags: " << std::hex << (uint32_t)desc.flags << std::dec + << ", size: " << (uint32_t)desc.buffer.size + << ", state: " << std::hex << (uint32_t)initial_state << std::dec + << ", width: " << (uint32_t)desc.texture.width + << ", height: " << (uint32_t)desc.texture.height + << ", format: " << (uint32_t)desc.texture.format + << ")"; + reshade::log_message( + desc.texture.format == reshade::api::format::unknown + ? reshade::log_level::warning + : reshade::log_level::info, + s.str().c_str() + ); +} + +static void on_init_resource_view( + reshade::api::device* device, + reshade::api::resource resource, + reshade::api::resource_usage usage_type, + const reshade::api::resource_view_desc &desc, + reshade::api::resource_view view +) { + if (!traceRunning && presentCount >= 5) return; + std::stringstream s; + s << "init_resource_view(" + << reinterpret_cast(view.handle) + << ", view type: " << (uint32_t)desc.type + << ", view format: " << (uint32_t)desc.format + << ", resource: " << reinterpret_cast(resource.handle) + << ", resource usage: " << std::hex << (uint32_t)usage_type << std::dec; + if (resource.handle) { + const auto resourceDesc = device->get_resource_desc(resource); + s << ", resource type: " << (uint32_t)resourceDesc.type; + + switch (resourceDesc.type) { + default: + case reshade::api::resource_type::unknown: + break; + case reshade::api::resource_type::buffer: + s << ", buffer offset: " << desc.buffer.offset; + s << ", buffer size: " << desc.buffer.size; + break; + case reshade::api::resource_type::texture_1d: + case reshade::api::resource_type::texture_2d: + case reshade::api::resource_type::texture_3d: + case reshade::api::resource_type::surface: + s << ", texture format: " << (uint32_t)resourceDesc.texture.format; + s << ", texture width: " << (uint32_t)resourceDesc.texture.width; + s << ", texture height: " << (uint32_t)resourceDesc.texture.height; + } + } + s << ")"; + reshade::log_message(reshade::log_level::info, s.str().c_str()); +} + static void on_reshade_present(reshade::api::effect_runtime* runtime) { if (traceRunning) { reshade::log_message(reshade::log_level::info, "present()"); @@ -447,6 +875,13 @@ static void on_reshade_present(reshade::api::effect_runtime* runtime) { traceRunning = true; reshade::log_message(reshade::log_level::info, "--- Frame ---"); } + if (presentCount < 5) { + // presentCount++; + } + if (needsLiveReload) { + loadLiveShaders(); + needsLiveReload = false; + } } static const char* findFXC() { @@ -476,16 +911,6 @@ std::string exec(const char* cmd) { return result; } -std::filesystem::path getShaderPath() { - wchar_t file_prefix[MAX_PATH] = L""; - GetModuleFileNameW(nullptr, file_prefix, ARRAYSIZE(file_prefix)); - - std::filesystem::path dump_path = file_prefix; - dump_path = dump_path.parent_path(); - dump_path /= ".\\renodx-dev"; - return dump_path; -} - void dumpShader(uint32_t shader_hash) { auto dump_path = getShaderPath(); @@ -502,13 +927,14 @@ void dumpShader(uint32_t shader_hash) { std::ofstream file(dump_path, std::ios::binary); - file.write(static_cast(cachedShader.data), cachedShader.size); + file.write(static_cast(cachedShader->data), cachedShader->size); } char* dumpFXC(uint32_t shader_hash, bool force = false) { auto fxcExePath = findFXC(); if (fxcExePath == NULL) { reshade::log_message(reshade::log_level::warning, "fxc.exe not found."); + return nullptr; } // Prepend executable directory to image files @@ -569,6 +995,17 @@ static void on_register_overlay(reshade::api::effect_runtime* runtime) { ImGui::Text("Traced Shaders: %d", traceCount); ImGui::Text("Cached Shaders: %d", shaderCacheCount); + ImGui::SameLine(); + if (ImGui::Button("Dump All")) { + for (auto shader : shaderCache) { + dumpShader(shader.first); + } + } + + if (ImGui::Button("Load Live Shaders")) { + needsLiveReload = true; + } + ImGui::Text("Cached Shaders Size: %d", shaderCacheSize); static int32_t selectedIndex = -1; bool changedSelected = false; @@ -578,11 +1015,12 @@ static void on_register_overlay(reshade::api::effect_runtime* runtime) { for (auto index = 0; index < traceCount; index++) { auto hash = traceHashes.at(index); const bool isSelected = (selectedIndex == index); - const bool isModded = originalShaders.count(hash) == 0; + auto pair = pipelineCacheByShaderHash.find(hash); + const bool isCloned = pair != pipelineCacheByShaderHash.end() && pair->second->cloned; std::stringstream name; name << std::setfill('0') << std::setw(3) << index << std::setw(0) << " - 0x" << std::hex << hash; - if (isModded) { + if (isCloned) { name << "*"; } if (ImGui::Selectable(name.str().c_str(), isSelected)) { @@ -607,17 +1045,17 @@ static void on_register_overlay(reshade::api::effect_runtime* runtime) { ImGui::BeginDisabled(selectedIndex == -1); if (changedSelected) { auto hash = traceHashes.at(selectedIndex); - if (originalShaders.count(hash)) { - auto cache = shaderCache.find(hash)->second; - if (cache.source.length() == 0) { - char* fxc = dumpFXC(hash); - cache.source.assign(fxc); + auto cache = shaderCache.find(hash)->second; + if (cache->source.length() == 0) { + char* fxc = dumpFXC(hash); + if (fxc == nullptr) { + cache->source.assign("Decompilation failed."); + } else { + cache->source.assign(fxc); free(fxc); } - sourceCode.assign(cache.source); - } else { - sourceCode.assign("Modded shader."); } + sourceCode.assign(cache->source); } if (ImGui::BeginChild("HashSourceCode", ImVec2(-FLT_MIN, -FLT_MIN), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysVerticalScrollbar)) { @@ -645,15 +1083,24 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID) { reshade::register_event(on_init_pipeline); reshade::register_event(on_destroy_pipeline); - reshade::register_event(on_create_pipeline); reshade::register_event(on_bind_pipeline); reshade::register_event(on_bind_pipeline_states); + reshade::register_event(on_init_resource); + reshade::register_event(on_init_resource_view); + reshade::register_event(on_draw); + reshade::register_event(on_dispatch); reshade::register_event(on_draw_indexed); reshade::register_event(on_draw_or_dispatch_indirect); + reshade::register_event(on_bind_render_targets_and_depth_stencil); reshade::register_event(on_copy_texture_region); + reshade::register_event(on_resolve_texture_region); + + reshade::register_event(on_copy_resource); + + reshade::register_event(on_barrier); reshade::register_event(on_reshade_present); @@ -664,7 +1111,6 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID) { reshade::unregister_event(on_init_swapchain); reshade::unregister_event(on_init_pipeline_layout); - reshade::unregister_event(on_create_pipeline); reshade::unregister_event(on_init_pipeline); reshade::unregister_event(on_destroy_pipeline);