diff --git a/MMLaunch/ModUtil.fs b/MMLaunch/ModUtil.fs index 5510b422..320e5733 100644 --- a/MMLaunch/ModUtil.fs +++ b/MMLaunch/ModUtil.fs @@ -33,8 +33,8 @@ module DdsUtil = type HeaderInfo = { FourCC : string; HasDX10 : bool } - let PathToTexCli = [ "TPlib"; "..\\TPLib"; "..\\..\\TPLib"; "..\\..\\..\\TPLib"; ] - let PathToSnapshotProfiles = [ "SnapshotProfiles"; "..\\SnapshotProfiles"; "..\\..\\SnapshotProfiles"; "..\\..\\..\\SnapshotProfiles" ] + let PathToTexCli = [ "TPlib"; "ModelMod\\TPLib"; "..\\TPLib"; "..\\..\\TPLib"; "..\\..\\..\\TPLib"; ] + let PathToSnapshotProfiles = [ "SnapshotProfiles"; "ModelMod\\SnapshotProfiles"; "..\\SnapshotProfiles"; "..\\..\\SnapshotProfiles"; "..\\..\\..\\SnapshotProfiles" ] let SnapTexFormatFile = "TexFormat.txt" let TexConvName = "texconv.exe" diff --git a/Native/d3dx/src/d3dx.rs b/Native/d3dx/src/d3dx.rs index e4aef40f..e74dd4b5 100644 --- a/Native/d3dx/src/d3dx.rs +++ b/Native/d3dx/src/d3dx.rs @@ -71,14 +71,26 @@ pub fn load_lib(mm_root: &Option, device: &DevicePointer) -> Result { let base_names = vec!["d3dx11_43.dll", "d3dx11_42.dll"]; - // just try loading it first from the system - let mut handle = base_names.iter().find_map(|base_name| { - match util::load_lib(base_name) { - Ok(handle) => Some(handle), - Err(_) => None, - } - }); + + let mut handle:Option = None; + + let load_from_sys = || { + base_names.iter().find_map(|base_name| { + match util::load_lib(base_name) { + Ok(handle) => Some(handle), + Err(_) => None, + } + }) + }; + let mut searched:Vec = vec![]; + + // on actual windows try load from sys first; don't do this on wine because it will load, but + // we'll get wine's partially implemented version of the associated functions (on wine + // prefer the copy stored in TPLib) + if !util::is_wine() { + handle = load_from_sys(); + } if handle.is_none() { // not found so look into tplib dir, try looking for arch specific folder // or file with an _arch suffix in tplib @@ -116,9 +128,18 @@ pub fn load_lib(mm_root: &Option, device: &DevicePointer) -> Result return Err(HookError::LoadLibFailed(format!("D3DX11 not found in system or {:?}", searched))), Some(handle) => { + // Log exactly which d3dx11 DLL the loader resolved. + match util::get_module_path(handle) { + Ok(path) => write_log_file(&format!("loaded d3dx11 from: {}", path)), + Err(e) => write_log_file(&format!("loaded d3dx11 (path unavailable: {:?})", e)), + } unsafe { Ok(D3DXFn::DX11(D3DX11Fn { D3DX11SaveTextureToFileW: std::mem::transmute(util::get_proc_address( diff --git a/Native/hook_snapshot/src/hook_snapshot.rs b/Native/hook_snapshot/src/hook_snapshot.rs index e03dc1c5..7e1bb9ba 100644 --- a/Native/hook_snapshot/src/hook_snapshot.rs +++ b/Native/hook_snapshot/src/hook_snapshot.rs @@ -278,6 +278,27 @@ pub unsafe fn take(devptr:&mut DevicePointer, sd:&mut types::interop::SnapshotDa } } +/// Human-readable name for the DXGI formats we care about when logging texture snapshots. +/// Covers the block-compressed range, plus a few common uncompressed ones; anything else is reported as "?". +fn dxgi_format_name(fmt: DXGI_FORMAT) -> &'static str { + match fmt { + 0 => "UNKNOWN", + 2 => "R32G32B32A32_FLOAT", + 10 => "R16G16B16A16_FLOAT", + 28 => "R8G8B8A8_UNORM", + 29 => "R8G8B8A8_UNORM_SRGB", + 70 => "BC1_TYPELESS", 71 => "BC1_UNORM", 72 => "BC1_UNORM_SRGB", + 73 => "BC2_TYPELESS", 74 => "BC2_UNORM", 75 => "BC2_UNORM_SRGB", + 76 => "BC3_TYPELESS", 77 => "BC3_UNORM", 78 => "BC3_UNORM_SRGB", + 79 => "BC4_TYPELESS", 80 => "BC4_UNORM", 81 => "BC4_SNORM", + 82 => "BC5_TYPELESS", 83 => "BC5_UNORM", 84 => "BC5_SNORM", + 87 => "B8G8R8A8_UNORM", 88 => "B8G8R8X8_UNORM", 91 => "B8G8R8A8_UNORM_SRGB", + 94 => "BC6H_TYPELESS", 95 => "BC6H_UF16", 96 => "BC6H_SF16", + 97 => "BC7_TYPELESS", 98 => "BC7_UNORM", 99 => "BC7_UNORM_SRGB", + _ => "?", + } +} + unsafe fn save_textures(devtr:&mut DevicePointer, buffers:&Box, snap_dir:&str, snap_prefix:&str) -> Result<()> { // in d3d9 the managed code already did this let device = match devtr { @@ -345,12 +366,20 @@ unsafe fn save_textures(devtr:&mut DevicePointer, buffers:&Box bool { + unsafe { + let ntdll = GetModuleHandleA(b"ntdll.dll\0".as_ptr() as *const i8); + if ntdll.is_null() { + return false; + } + !GetProcAddress(ntdll, b"wine_get_version\0".as_ptr() as *const i8).is_null() + } +} + pub unsafe fn protect_memory( target: *mut winapi::ctypes::c_void, size: usize, @@ -327,14 +339,23 @@ pub fn to_wide_str(s: &str) -> Vec { } pub fn get_module_name() -> Result { - use std::os::windows::prelude::*; use winapi::um::libloaderapi::*; + let handle = unsafe { GetModuleHandleW(std::ptr::null_mut()) }; + get_module_path(handle) +} + +/// Return the on-disk path for a loaded module handle (as returned by `load_lib`). +/// Useful for logging exactly which DLL the OS loader resolved for a given name, +/// which can differ between the system copy and a game- or app-local copy. +pub fn get_module_path(handle: HMODULE) -> Result { + use std::os::windows::prelude::*; + use winapi::um::libloaderapi::GetModuleFileNameW; + unsafe { let ssize = 65535; let mut mpath: Vec = Vec::with_capacity(ssize); - let handle = GetModuleHandleW(std::ptr::null_mut()); let r = GetModuleFileNameW(handle, mpath.as_mut_ptr(), ssize as DWORD); if r == 0 { return Err(HookError::ModuleNameError(format!(