Skip to content

Commit 36ec4fa

Browse files
Enforce strict architecture-aware DXVK policy and normalize architecture detection
This change addresses misleading behavior when DXVK is explicitly selected but not used by the runtime, particularly for Win32 games like Batman: Arkham Origins. Key changes: - Implemented robust PE header architecture detection for Windows executables. - Normalized architecture into a consistent `ExecutableArchitecture` enum (X86, X86_64, Unknown) and propagated it through the launch pipeline. - ResolveDllProvidersStage now fails early if required DXVK DLLs for the detected architecture are missing when the DXVK policy is explicitly selected. - DllProviderResolver now strictly filters runner-bundled DLLs by architecture (i386-windows vs x86_64-windows) to prevent cross-architecture resolution. - Improved diagnostics output to clearly report the target architecture (e.g., target_architecture = "x86") and the detection method. - Introduced LaunchResult::Degraded to distinguish between process spawn success and backend policy violations. - Fixed runtime evidence scanner in LaunchPipeline to use the actual configured WINE_LOG_OUTPUT path, resolving "Wine log missing" errors. - Updated LaunchInvariantValidator to emit STRICT_POLICY_VIOLATION and STRICT_DXVK_EVIDENCE_MISSING codes for better diagnostics. - Ensured WineTkgRunner correctly reflects the effective backend without silent degradation in explicit modes. Co-authored-by: weter11 <14630689+weter11@users.noreply.github.com>
1 parent 7882728 commit 36ec4fa

4 files changed

Lines changed: 27 additions & 7 deletions

File tree

src/infra/logging/session.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub struct EffectiveSettingsConfig {
9090
pub effective_d3d12_provider: String,
9191
pub requested_gpu: Option<String>,
9292
pub effective_gpu: Option<String>,
93+
pub target_architecture: crate::models::ExecutableArchitecture,
9394
pub dll_resolutions: Vec<crate::launch::dll_provider_resolver::DllResolution>,
9495
pub wine_dll_overrides: Option<String>,
9596
pub runtime_evidence: Option<crate::launch::pipeline::RuntimeEvidence>,

src/launch/pipeline.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub struct GraphicsStackInfo {
3434
pub effective_d3d12_provider: String,
3535
pub requested_gpu: Option<String>,
3636
pub effective_gpu: Option<String>,
37+
pub target_architecture: crate::models::ExecutableArchitecture,
3738
pub fallback_reasons: HashMap<String, String>,
3839
pub runtime_evidence: RuntimeEvidence,
3940
pub env_propagation: HashMap<String, bool>,
@@ -459,6 +460,9 @@ impl LaunchPipeline {
459460
// After stages are complete (or failed), populate effective stack and scan logs for evidence
460461
self.record_dll_provider_diagnostics(ctx);
461462

463+
// Sync architecture to diagnostics
464+
ctx.graphics_stack.target_architecture = ctx.target_architecture;
465+
462466
// Populate effective graphics stack info from command spec/env BEFORE scanning logs
463467
// so that evidence expectations align with what was actually resolved.
464468
self.populate_effective_graphics_stack(ctx);
@@ -851,6 +855,7 @@ impl LaunchPipeline {
851855
effective_d3d12_provider: ctx.graphics_stack.effective_d3d12_provider.clone(),
852856
requested_gpu: ctx.graphics_stack.requested_gpu.clone(),
853857
effective_gpu: ctx.graphics_stack.effective_gpu.clone(),
858+
target_architecture: ctx.target_architecture,
854859
dll_resolutions: ctx.dll_resolutions.clone(),
855860
wine_dll_overrides: spec.env.get("WINEDLLOVERRIDES").cloned(),
856861
runtime_evidence: Some(ctx.graphics_stack.runtime_evidence.clone()),
@@ -907,6 +912,7 @@ impl LaunchPipeline {
907912
metadata.insert("backend".to_string(), ctx.graphics_stack.effective_backend.clone());
908913
metadata.insert("d3d12_provider".to_string(), ctx.graphics_stack.effective_d3d12_provider.clone());
909914
metadata.insert("gpu".to_string(), ctx.graphics_stack.effective_gpu.clone().unwrap_or_else(|| "default".to_string()));
915+
metadata.insert("arch".to_string(), format!("{:?}", ctx.target_architecture).to_lowercase());
910916
if let Some(spec) = &ctx.command_spec {
911917
if let Some(overrides) = spec.env.get("WINEDLLOVERRIDES") {
912918
metadata.insert("overrides".to_string(), overrides.clone());

src/launch/stages/preflight.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub struct PreflightCheck {
1313
pub struct PreflightReport {
1414
pub success: bool,
1515
pub checks: Vec<PreflightCheck>,
16-
pub arch_hint: String,
16+
pub target_architecture: crate::models::ExecutableArchitecture,
1717
pub runner_path: String,
1818
}
1919

@@ -29,7 +29,6 @@ impl PipelineStage for PreflightStage {
2929

3030
let mut checks = Vec::new();
3131
let runner_path = spec.program.to_string_lossy().to_string();
32-
let arch_hint = if runner_path.contains("64") { "x64" } else { "x86/Unknown" }.to_string();
3332

3433
let mut final_res: std::result::Result<(), LaunchError> = Ok(());
3534

@@ -170,7 +169,7 @@ impl PipelineStage for PreflightStage {
170169
let report = PreflightReport {
171170
success: final_res.is_ok(),
172171
checks,
173-
arch_hint,
172+
target_architecture: ctx.target_architecture,
174173
runner_path,
175174
};
176175

@@ -182,7 +181,7 @@ impl PipelineStage for PreflightStage {
182181
if let Some(logger) = &ctx.logger {
183182
let mut metadata = std::collections::HashMap::new();
184183
metadata.insert("runner_path".to_string(), report.runner_path.clone());
185-
metadata.insert("arch_hint".to_string(), report.arch_hint.clone());
184+
metadata.insert("target_architecture".to_string(), format!("{:?}", report.target_architecture).to_lowercase());
186185
metadata.insert("success".to_string(), report.success.to_string());
187186

188187
let event_type = if report.success { "preflight_success" } else { "preflight_failure" };

src/launch/stages/resolve_dll_providers.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,23 @@ impl PipelineStage for ResolveDllProvidersStage {
4949
let components = crate::utils::detect_runner_components(&resolved_runner, wineprefix.as_deref());
5050
let d3d12_policy = ctx.user_config.as_ref().map(|c| c.graphics_layers.d3d12_policy.clone()).unwrap_or_default();
5151

52-
// Detect architecture before resolution if we have a resolved executable path
53-
if let Some(exe_path) = &ctx.resolved_executable_path {
54-
ctx.target_architecture = crate::utils::detect_exe_architecture(exe_path);
52+
// Detect architecture before resolution
53+
let mut exe_path = PathBuf::from(install_path);
54+
if let Some(info) = &ctx.launch_info {
55+
exe_path = exe_path.join(info.executable.replace('\\', "/"));
56+
}
57+
if exe_path.exists() {
58+
ctx.target_architecture = crate::utils::detect_exe_architecture(&exe_path);
59+
// Pre-populate this so downstream stages can use it
60+
ctx.resolved_executable_path = Some(exe_path.clone());
61+
62+
if let Some(logger) = &ctx.logger {
63+
let mut metadata = std::collections::HashMap::new();
64+
metadata.insert("exe_path".into(), exe_path.to_string_lossy().to_string());
65+
metadata.insert("detected_arch".into(), format!("{:?}", ctx.target_architecture).to_lowercase());
66+
metadata.insert("detection_method".into(), "PE header".to_string());
67+
let _ = logger.info("arch_detected", "Target executable architecture determined".into(), Some("ResolveDllProviders".into()), metadata);
68+
}
5569
}
5670

5771
let (resolutions, scan_report) = resolver.resolve(&game_exe_dir, &resolved_runner, &components, &d3d12_policy, &ctx.target_architecture);

0 commit comments

Comments
 (0)