diff --git a/rpcs3/Emu/RSX/rsx_cache.h b/rpcs3/Emu/RSX/rsx_cache.h index 6fedcf5753c9..07098dbb2f20 100644 --- a/rpcs3/Emu/RSX/rsx_cache.h +++ b/rpcs3/Emu/RSX/rsx_cache.h @@ -447,17 +447,31 @@ namespace rsx fs::dir_entry tmp = entries[pos]; const auto filename = directory_path + "/" + tmp.name; - std::vector bytes; fs::file f(filename); + + if (!f) + { + // Unexpected error, but avoid crash + continue; + } + if (f.size() != sizeof(pipeline_data)) { rsx_log.error("Removing cached pipeline object %s since it's not binary compatible with the current shader cache", tmp.name.c_str()); fs::remove_file(filename); continue; } - f.read(bytes, f.size()); - auto entry = unpack(*reinterpret_cast(bytes.data())); + pipeline_data pdata{}; + f.read(&pdata, f.size(); + + auto entry = unpack(pdata); + + if (std::get<1>(entry).data.empty() || !std::get<2>(entry).ucode_length) + { + continue; + } + m_storage.preload_programs(std::get<1>(entry), std::get<2>(entry)); unpacked[unpacked.push_begin()] = entry; @@ -573,23 +587,22 @@ namespace rsx std::string directory_path = root_path + "/pipelines/" + pipeline_class_name + "/" + version_prefix; - if (!fs::is_dir(directory_path)) + fs::dir root = fs::dir(directory_path); + + if (!root) { fs::create_path(directory_path); fs::create_path(root_path + "/raw"); - return; } - fs::dir root = fs::dir(directory_path); - u32 entry_count = 0; std::vector entries; for (auto It = root.begin(); It != root.end(); ++It, entry_count++) { fs::dir_entry tmp = *It; - if (tmp.name == "." || tmp.name == "..") + if (tmp.is_directory || tmp.name.ends_with(".temp")) continue; entries.push_back(tmp); @@ -648,12 +661,16 @@ namespace rsx if (!fs::is_file(fp_name)) { - fs::file(fp_name, fs::rewrite).write(fp.get_data(), fp.ucode_length); + const std::string temp_name = fmt::format("%s.%s.temp", fp_name, fmt::base57(utils::get_unique_tsc())); + fs::file(temp_name, fs::rewrite).write(fp.get_data(), fp.ucode_length); + fs::rename(temp_name, fp_name, true); // Atomically write data } if (!fs::is_file(vp_name)) { - fs::file(vp_name, fs::rewrite).write(vp.data); + const std::string temp_name = fmt::format("%s.%s.temp", vp_name, fmt::base57(utils::get_unique_tsc())); + fs::file(temp_name, fs::rewrite).write(vp.data); + fs::rename(temp_name, fp_name, true); // Atomically write data } u64 state_hash = 0; @@ -669,21 +686,22 @@ namespace rsx state_hash ^= rpcs3::hash_base(data.fp_shadow_textures); state_hash ^= rpcs3::hash_base(data.fp_redirected_textures); - std::string pipeline_file_name = fmt::format("%llX+%llX+%llX+%llX.bin", data.vertex_program_hash, data.fragment_program_hash, data.pipeline_storage_hash, state_hash); - std::string pipeline_path = root_path + "/pipelines/" + pipeline_class_name + "/" + version_prefix + "/" + pipeline_file_name; - fs::file(pipeline_path, fs::rewrite).write(&data, sizeof(pipeline_data)); + const std::string pipeline_file_name = fmt::format("%llX+%llX+%llX+%llX.bin", data.vertex_program_hash, data.fragment_program_hash, data.pipeline_storage_hash, state_hash); + const std::string pipeline_path = root_path + "/pipelines/" + pipeline_class_name + "/" + version_prefix + "/" + pipeline_file_name; + const std::string temp_path = fmt::format("%s.%s.temp", pipeline_path, fmt::base57(utils::get_unique_tsc())); + fs::file(temp_path, fs::rewrite).write(&data, sizeof(data)); + fs::rename(temp_path, pipeline_path, true); } RSXVertexProgram load_vp_raw(u64 program_hash) { - std::vector data; + RSXVertexProgram vp = {}; + std::string filename = fmt::format("%llX.vp", program_hash); fs::file f(root_path + "/raw/" + filename); - f.read(data, f.size() / sizeof(u32)); + if (f) f.read(vp.data, f.size() / sizeof(u32)); - RSXVertexProgram vp = {}; - vp.data = data; vp.skip_vertex_input_check = true; return vp; @@ -695,15 +713,15 @@ namespace rsx std::string filename = fmt::format("%llX.fp", program_hash); fs::file f(root_path + "/raw/" + filename); - f.read(data, f.size()); + if (f) f.read(data, f.size() / sizeof(u32)); RSXFragmentProgram fp = {}; + fp.ucode_length = ::size32(data); { - std::lock_guard lock(fpd_mutex); - fragment_program_data[program_hash] = data; + std::lock_guard lock(fpd_mutex); + fragment_program_data.insert_or_assign(program_hash, std::move(data)); fp.data = fragment_program_data[program_hash].data(); } - fp.ucode_length = ::size32(data); return fp; }