Loading weBench…
Loading weBench…
ID: metro_last_light_complete_presentmon• Submitter: webench-catalog•Game: Metro: Last Light Complete Edition
{
"args": [
"##gamepath##",
"##width## x ##height##",
"##preset##",
"##api##"
],
"runs": 1,
"score": "presentmon",
"weight": 1,
"requires": [
"dx11"
],
"time_est": 330,
"executable": "webench_metro_last_light.ps1",
"default_api": "dx11",
"default_preset": "High",
"script_content": "param(\n [Parameter(Mandatory = $true)][string]$GamePath,\n [string]$Resolution = \"1920 x 1080\",\n [string]$Quality = \"High\",\n [string]$DirectX = \"DirectX 11\",\n [int]$CleanupAfterSeconds = 315\n)\n\n$ErrorActionPreference = \"Stop\"\n$startedAt = Get-Date\n$launcherPath = Join-Path $GamePath \"MetroLLbenchmark.exe\"\nif (-not (Test-Path -LiteralPath $launcherPath)) {\n throw \"Metro Last Light benchmark launcher was not found at $launcherPath\"\n}\n\nAdd-Type -AssemblyName UIAutomationClient\nAdd-Type -AssemblyName UIAutomationTypes\nAdd-Type @\"\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\npublic static class MetroBenchmarkNative {\n [DllImport(\"user32.dll\", CharSet = CharSet.Auto)]\n public static extern IntPtr SendMessage(IntPtr hwnd, uint message, IntPtr wParam, StringBuilder lParam);\n\n [DllImport(\"user32.dll\")]\n public static extern IntPtr SendMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);\n\n [DllImport(\"user32.dll\")]\n public static extern bool PostMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);\n\n [DllImport(\"user32.dll\")]\n public static extern IntPtr GetParent(IntPtr hwnd);\n\n [DllImport(\"user32.dll\")]\n public static extern int GetDlgCtrlID(IntPtr hwnd);\n\n}\n\"@\n\n$WM_COMMAND = 0x0111\n$BM_CLICK = 0x00F5\n$CB_GETCOUNT = 0x0146\n$CB_GETLBTEXT = 0x0148\n$CB_GETLBTEXTLEN = 0x0149\n$CB_SETCURSEL = 0x014E\n$CBN_SELCHANGE = 1\n\nfunction Get-Root([System.Diagnostics.Process]$Process) {\n for ($attempt = 0; $attempt -lt 100; $attempt++) {\n $Process.Refresh()\n if ($Process.MainWindowHandle -ne 0) {\n return [System.Windows.Automation.AutomationElement]::FromHandle($Process.MainWindowHandle)\n }\n Start-Sleep -Milliseconds 100\n }\n throw \"Metro benchmark launcher did not create a window.\"\n}\n\nfunction Find-NamedElement($Root, [string]$Name) {\n $condition = New-Object System.Windows.Automation.PropertyCondition(\n [System.Windows.Automation.AutomationElement]::NameProperty,\n $Name\n )\n return $Root.FindFirst([System.Windows.Automation.TreeScope]::Descendants, $condition)\n}\n\nfunction Dismiss-SafeModePrompt {\n $desktop = [System.Windows.Automation.AutomationElement]::RootElement\n $windows = $desktop.FindAll(\n [System.Windows.Automation.TreeScope]::Children,\n [System.Windows.Automation.Condition]::TrueCondition\n )\n foreach ($window in $windows) {\n try {\n if ($window.Current.Name -notlike \"*Metro*\") { continue }\n $elements = $window.FindAll(\n [System.Windows.Automation.TreeScope]::Descendants,\n [System.Windows.Automation.Condition]::TrueCondition\n )\n $isSafeModePrompt = @($elements | Where-Object {\n $_.Current.Name -like \"*previous launch was unsuccessful*\"\n }).Count -gt 0\n if (-not $isSafeModePrompt) { continue }\n\n $noButton = $window.FindFirst(\n [System.Windows.Automation.TreeScope]::Descendants,\n (New-Object System.Windows.Automation.PropertyCondition(\n [System.Windows.Automation.AutomationElement]::NameProperty,\n \"No\"\n ))\n )\n if ($null -eq $noButton -or $noButton.Current.NativeWindowHandle -eq 0) {\n throw \"Metro safe-mode prompt did not expose a No button.\"\n }\n [MetroBenchmarkNative]::SendMessage(\n [IntPtr]$noButton.Current.NativeWindowHandle,\n $BM_CLICK,\n [IntPtr]::Zero,\n [IntPtr]::Zero\n ) | Out-Null\n Write-Output \"Declined Metro safe mode to preserve the selected benchmark settings.\"\n return $true\n } catch {\n # The launcher can close a stale UI Automation window while it starts.\n }\n }\n return $false\n}\n\nfunction Get-ComboItems([IntPtr]$Handle) {\n $count = [MetroBenchmarkNative]::SendMessage($Handle, $CB_GETCOUNT, [IntPtr]::Zero, [IntPtr]::Zero).ToInt32()\n if ($count -le 0 -or $count -gt 100) { return @() }\n $items = @()\n for ($index = 0; $index -lt $count; $index++) {\n $length = [MetroBenchmarkNative]::SendMessage($Handle, $CB_GETLBTEXTLEN, [IntPtr]$index, [IntPtr]::Zero).ToInt32()\n $text = New-Object System.Text.StringBuilder ($length + 2)\n [MetroBenchmarkNative]::SendMessage($Handle, $CB_GETLBTEXT, [IntPtr]$index, $text) | Out-Null\n $items += $text.ToString()\n }\n return $items\n}\n\nfunction Set-ComboValue($Root, [scriptblock]$Matcher, [string]$Value) {\n $elements = $Root.FindAll(\n [System.Windows.Automation.TreeScope]::Descendants,\n [System.Windows.Automation.Condition]::TrueCondition\n )\n foreach ($element in $elements) {\n $handle = [IntPtr]$element.Current.NativeWindowHandle\n if ($handle -eq [IntPtr]::Zero) { continue }\n $items = @(Get-ComboItems $handle)\n if ($items.Count -eq 0 -or -not (& $Matcher $items)) { continue }\n $index = [Array]::IndexOf($items, $Value)\n if ($index -lt 0) { throw \"Benchmark option '$Value' is unavailable. Choices: $($items -join ', ')\" }\n [MetroBenchmarkNative]::SendMessage($handle, $CB_SETCURSEL, [IntPtr]$index, [IntPtr]::Zero) | Out-Null\n $parent = [MetroBenchmarkNative]::GetParent($handle)\n $controlId = [MetroBenchmarkNative]::GetDlgCtrlID($handle)\n $command = [IntPtr](($CBN_SELCHANGE -shl 16) -bor ($controlId -band 0xffff))\n [MetroBenchmarkNative]::SendMessage($parent, $WM_COMMAND, $command, $handle) | Out-Null\n return\n }\n throw \"Could not find the Metro benchmark option for '$Value'.\"\n}\n\n$launcher = Start-Process -FilePath $launcherPath -WorkingDirectory $GamePath -PassThru\ntry {\n $root = Get-Root $launcher\n $runButton = Find-NamedElement $root \"Run Selected\"\n if ($null -eq $runButton) { throw \"Metro benchmark Run Selected control was not found.\" }\n\n if (-not $runButton.Current.IsEnabled) {\n $presets = Find-NamedElement $root \"Presets\"\n if ($null -eq $presets) { throw \"Metro benchmark preset controls were not found.\" }\n $presetControls = @($presets.FindAll(\n [System.Windows.Automation.TreeScope]::Descendants,\n [System.Windows.Automation.Condition]::TrueCondition\n )) | Where-Object {\n $_.Current.Name -eq \"\" -and\n $_.Current.NativeWindowHandle -ne 0 -and\n $_.Current.BoundingRectangle.Width -ge 50 -and\n $_.Current.BoundingRectangle.Width -le 80\n } | Sort-Object { $_.Current.BoundingRectangle.Y }\n if ($presetControls.Count -eq 0) { throw \"Metro benchmark New Preset control was not found.\" }\n [MetroBenchmarkNative]::SendMessage(\n [IntPtr]$presetControls[0].Current.NativeWindowHandle,\n $BM_CLICK,\n [IntPtr]::Zero,\n [IntPtr]::Zero\n ) | Out-Null\n Start-Sleep -Milliseconds 250\n $root = Get-Root $launcher\n $runButton = Find-NamedElement $root \"Run Selected\"\n }\n\n Set-ComboValue $root { param($items) $items -contains \"DirectX 10\" -and $items -contains \"DirectX 11\" } $DirectX\n Set-ComboValue $root { param($items) $items -contains \"1920 x 1080\" -and $items -contains \"1280 x 720\" } $Resolution\n Set-ComboValue $root { param($items) $items -contains \"Low\" -and $items -contains \"Very High\" -and -not ($items -contains \"Off\") } $Quality\n Set-ComboValue $root { param($items) $items -contains \"AF 4X\" -and $items -contains \"AF 16X\" } \"AF 16X\"\n Set-ComboValue $root { param($items) $items.Count -eq 2 -and $items -contains \"Low\" -and $items -contains \"Normal\" } \"Normal\"\n Set-ComboValue $root { param($items) $items -contains \"Off\" -and $items -contains \"Very High\" } \"Normal\"\n # This launcher owns the OpenAutomate server that supplies the selected\n # settings to MetroLL.exe and starts its stable default of three runs.\n\n if (-not $runButton.Current.IsEnabled) { throw \"Metro benchmark preset was not runnable after configuration.\" }\n [MetroBenchmarkNative]::PostMessage(\n [IntPtr]$runButton.Current.NativeWindowHandle,\n $BM_CLICK,\n [IntPtr]::Zero,\n [IntPtr]::Zero\n ) | Out-Null\n\n $game = $null\n for ($attempt = 0; $attempt -lt 300; $attempt++) {\n if ($attempt % 10 -eq 0) {\n Dismiss-SafeModePrompt | Out-Null\n }\n $game = Get-Process -Name \"MetroLL\" -ErrorAction SilentlyContinue |\n Where-Object { $_.StartTime -ge $startedAt } |\n Sort-Object StartTime -Descending |\n Select-Object -First 1\n if ($null -ne $game) { break }\n Start-Sleep -Milliseconds 100\n }\n if ($null -eq $game) { throw \"Metro benchmark workload did not start within 30 seconds.\" }\n\n # The Flutter runner intentionally stops this wrapper after its timed\n # PresentMon capture. PowerShell does not execute finally after a forced\n # kill, so a detached watchdog gives the sample a bounded cleanup path.\n $watchdogCommand = @\"\nStart-Sleep -Seconds $CleanupAfterSeconds\ntaskkill.exe /F /T /PID $($game.Id) 2>`$null | Out-Null\ntaskkill.exe /F /T /PID $($launcher.Id) 2>`$null | Out-Null\n\"@\n $encodedWatchdog = [Convert]::ToBase64String(\n [Text.Encoding]::Unicode.GetBytes($watchdogCommand)\n )\n Start-Process -FilePath \"powershell.exe\" -ArgumentList @(\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-EncodedCommand\",\n $encodedWatchdog\n ) -WindowStyle Hidden | Out-Null\n\n Write-Output \"Metro benchmark workload started with PID $($game.Id).\"\n $game.WaitForExit()\n Write-Output \"Metro benchmark workload completed.\"\n} finally {\n if ($null -ne $launcher -and -not $launcher.HasExited) {\n Stop-Process -Id $launcher.Id -Force -ErrorAction SilentlyContinue\n }\n}\n",
"supported_apis": [
"dx10",
"dx11"
],
"thread_options": [
-1
],
"api_script_values": {
"dx10": "DirectX 10",
"dx11": "DirectX 11"
},
"presentmon_config": {
"process_name": "MetroLL.exe",
"trim_end_seconds": 2,
"start_delay_seconds": 5,
"capture_duration_seconds": 320
},
"supported_presets": [
"Low",
"Medium",
"High",
"Very High"
],
"default_resolution": "1920x1080",
"supported_resolutions": [
"1280x720",
"1280x800",
"1280x1024",
"1600x1000",
"1600x1200",
"1680x1050",
"1920x1080",
"1920x1200",
"2048x1536",
"2560x1600",
"2880x1800"
],
"preset_scaling_factors": {
"Low": 1.25,
"High": 0.82,
"Medium": 1,
"Very High": 0.7
},
"allow_custom_resolution": false
}No community reviews have been submitted for this recipe yet.