[Bug 35112] New: L.A. Noire 1.3 (Steam version) fails to start, claiming "DX94: Graphics card capabilities are below the minimum specifications." (wined3d clamps device caps MaxVertexIndex to 0xFFFFF)

wine-bugs at winehq.org wine-bugs at winehq.org
Thu Dec 12 15:43:45 CST 2013


http://bugs.winehq.org/show_bug.cgi?id=35112

            Bug ID: 35112
           Summary: L.A. Noire 1.3 (Steam version) fails to start,
                    claiming "DX94: Graphics card capabilities are below
                    the minimum specifications." (wined3d clamps device
                    caps MaxVertexIndex to 0xFFFFF)
           Product: Wine
           Version: 1.7.8
          Hardware: x86
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: directx-d3d
          Assignee: wine-bugs at winehq.org
          Reporter: focht at gmx.net
    Classification: Unclassified

Hello folks,

now with bug 35109 fixed the game runs into next problem.

After the main process 'LANoire.exe' has started an error dialog window is
shown, stating:

"Error: DX94: Graphics card capabilities are below the minimum specifications."

It was actually a bit of pain to diagnose/debug because of several processes
involved which are (re)started in sequence with the actual timing being
important.
There are only very small time windows for attaching debuggers, if you miss
them -> boom (avoid 'auto' debugging of childs from parent).

Additionally, these processes are a mixture of native binaries, .NET binaries
and mixed-mode binaries somewhat complicating diagnosis further (unmanaged code
with various managed code transitions in the same process).

Relevant part of trace log, showing processes involved:

NOTE: Don't redirect to files located within Steam folder to avoid
unnecessarily triggering the directory watcher thread(s).

--- snip ---
$ WINEDEBUG=+tid,+seh,+loaddll,+process,+msvcrt,+d3d9,+relay wine ./steam.exe
-applaunch 110800 >>~/Downloads/trace.txt 2>&1
...
0024:trace:process:__wine_kernel_init starting process name=L"C:\\Program
Files\\Steam\\steam.exe" argv[0]=L"C:\\Program Files\\Steam\\steam.exe" 
...

0024:Call KERNEL32.CreateProcessW(00b1ed88 L"C:\\Program
Files\\Steam\\steamerrorreporter.exe",00000000,00000000,00000000,00000000,00000000,00000000,00b1edf0
L"C:\\Program Files\\Steam",0033f4e8,0033f52c) ret=10001121 
...
0024:trace:process:create_process_impl starting L"C:\\Program
Files\\Steam\\steamerrorreporter.exe" as Win32 binary (0x400000-0x436000, arch
014c) 
...
0024:trace:process:create_process_impl started process pid 0025 tid 0026 
...

003f:Call KERNEL32.CreateProcessW(02a54a40 L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LanLauncher.exe",02a54f50
L"\"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LanLauncher.exe\"",00000000,00000000,00000000,00000004,00000000,02978818
L"C:\\Program Files\\Steam\\steamapps\\common\\L.A.Noire",06dcb588,06dcb604)
ret=381ec242 
...
003f:trace:process:create_process_impl starting L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LanLauncher.exe" as Win32 binary
(0x400000-0x514000, arch 014c) 
...
003f:trace:process:create_process_impl started process pid 0056 tid 0057 
...

0057:Call KERNEL32.CreateProcessW(00000000,0033de68 L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LANPatcher.exe",00000000,00000000,00000000,00000404,00000000,044c8b88
L"C:\\Program Files\\Steam\\steamapps\\common\\L.A.Noire",0033d520,0033d510)
ret=100416f7 
...
0057:trace:process:create_process_impl starting L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LANPatcher.exe" as Win32 binary
(0x400000-0x4ae000, arch 014c) 
...
0057:trace:process:create_process_impl started process pid 005b tid 005c 
...

005c:Call KERNEL32.CreateProcessW(00000000,0033dd18 L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LANLauncher.exe
-SkipPatchCheck",00000000,00000000,00000000,00000404,00000000,04497e78
L"C:\\Program Files\\Steam\\steamapps\\common",0033d3d0,0033d3c0) ret=100416f7 
...
005c:trace:process:create_process_impl starting L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LANLauncher.exe" as Win32 binary
(0x400000-0x514000, arch 014c) 
...
005c:trace:process:create_process_impl started process pid 0066 tid 0067 

0067:Call KERNEL32.CreateProcessW(00000000,0033d8b8 L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LANoire.exe -windowed
-parentIsLauncher",00000000,00000000,00000000,00000404,00000000,04531618
L"C:\\Program Files\\Steam\\steamapps\\common\\L.A.Noire",0033cf70,0033cf60)
ret=100416f7 
...
0067:trace:process:create_process_impl starting L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LANoire.exe" as Win32 binary
(0x400000-0x184f000, arch 014c) 
...
0067:trace:process:create_process_impl started process pid 0026 tid 0025 

0067:Call KERNEL32.CreateProcessW(00000000,0033d8b8 L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LANLauncher.exe -SplashScreen
Loading",00000000,00000000,00000000,00000404,00000000,00000000,0033cf70,0033cf60)
ret=100416f7 
...
0067:trace:process:create_process_impl starting L"C:\\Program
Files\\Steam\\steamapps\\common\\L.A.Noire\\LANLauncher.exe" as Win32 binary
(0x400000-0x514000, arch 014c) 
...
0067:trace:process:create_process_impl started process pid 004b tid 004d 

...
0064:fixme:advapi:CreateProcessAsUserW 0x44c L"C:\\Program Files\\Rockstar
Games\\Social Club\\renderer.exe" L"\"C:\\Program Files\\Rockstar Games\\Social
Club\\renderer.exe\" --type=renderer --disable-logging
--disable-desktop-notifications --disable-speech-input
--enable-accelerated-compositing --lang=en-US --channel=38.0F96F300.97936503
/prefetch:3" (nil) (nil) 0 0x0100040c (nil) (null) 0x322ae14c 0x322ae134 -
semi- stub 
...
0064:trace:process:create_process_impl started process pid 006a tid 006b 
...
--- snip ---

After dumping, rebuilding and analysing the main executable + trace log for
some hours I finally deduced the place where the problem originated.
The d3d calls from trace log are register indirect calls which requires a
debugger to identify the actual call site at run time.
Additionally some of them are hooked at through Steam gameoverlay renderer.

--- snip ---
...
0025:trace:d3d9:d3d9_device_GetDeviceCaps iface 0x32977c18, caps 0x332a74.
0025:Call ntdll.RtlAllocateHeap(00110000,00000008,0000017c) ret=f687fa1f
0025:Ret  ntdll.RtlAllocateHeap() retval=32fe6448 ret=f687fa1f
0025:Call wined3d.wined3d_mutex_lock() ret=f687fa55
0025:Ret  wined3d.wined3d_mutex_lock() retval=00000000 ret=f687fa55
0025:Call wined3d.wined3d_device_get_device_caps(328e2cb8,32fe6448)
ret=f687fa6a
0025:Ret  wined3d.wined3d_device_get_device_caps() retval=00000000 ret=f687fa6a
0025:Call wined3d.wined3d_mutex_unlock() ret=f687fa72
0025:Ret  wined3d.wined3d_mutex_unlock() retval=00000000 ret=f687fa72
0025:Call ntdll.RtlFreeHeap(00110000,00000000,32fe6448) ret=f687ff1c
0025:Ret  ntdll.RtlFreeHeap() retval=00000001 ret=f687ff1c
0025:trace:d3d9:d3d9_GetAdapterDisplayMode iface 0x32977990, adapter 0, mode
0x332a64.
0025:Call wined3d.wined3d_mutex_lock() ret=f688af86
0025:Ret  wined3d.wined3d_mutex_lock() retval=00000000 ret=f688af86
0025:Call
wined3d.wined3d_get_adapter_display_mode(328d9f38,00000000,003329fc,00000000)
ret=f688afac
0025:Call user32.EnumDisplaySettingsExW(328dcdf0
L"\\\\.\\DISPLAY1",ffffffff,00332860,00000000) ret=f66ba608
0025:Call
winex11.drv.EnumDisplaySettingsEx(328dcdf0,ffffffff,00332860,00000000)
ret=7ed181c2
0025:Ret  winex11.drv.EnumDisplaySettingsEx() retval=00000001 ret=7ed181c2
0025:Ret  user32.EnumDisplaySettingsExW() retval=00000001 ret=f66ba608
0025:Ret  wined3d.wined3d_get_adapter_display_mode() retval=00000000
ret=f688afac
0025:Call wined3d.wined3d_mutex_unlock() ret=f688afb5
0025:Ret  wined3d.wined3d_mutex_unlock() retval=00000000 ret=f688afb5
0025:trace:d3d9:d3d9_CheckDeviceFormat iface 0x32977990, adapter 0, device_type
0x1, adapter_format 0x16, usage 0x1, resource_type 0x1, format 0x4c4c554e.
0025:Call wined3d.wined3d_mutex_lock() ret=f688b1b6
0025:Ret  wined3d.wined3d_mutex_lock() retval=00000000 ret=f688b1b6
0025:Call
wined3d.wined3d_check_device_format(328d9f38,00000000,00000001,00000073,00000001,00000001,4c4c554e)
ret=f688b202
0025:Ret  wined3d.wined3d_check_device_format() retval=00000000 ret=f688b202
0025:Call wined3d.wined3d_mutex_unlock() ret=f688b20b
0025:Ret  wined3d.wined3d_mutex_unlock() retval=00000000 ret=f688b20b
0025:trace:d3d9:d3d9_CheckDeviceFormat iface 0x32977990, adapter 0, device_type
0x1, adapter_format 0x16, usage 0x2, resource_type 0x3, format 0x5a544e49.
0025:Call wined3d.wined3d_mutex_lock() ret=f688b1b6
0025:Ret  wined3d.wined3d_mutex_lock() retval=00000000 ret=f688b1b6
0025:Call
wined3d.wined3d_check_device_format(328d9f38,00000000,00000001,00000073,00000002,00000003,5a544e49)
ret=f688b202
0025:Ret  wined3d.wined3d_check_device_format() retval=00000000 ret=f688b202
0025:Call wined3d.wined3d_mutex_unlock() ret=f688b20b
0025:Ret  wined3d.wined3d_mutex_unlock() retval=00000000 ret=f688b20b
0025:Call KERNEL32.GetLastError() ret=79e7a087
0025:Ret  KERNEL32.GetLastError() retval=00000000 ret=79e7a087 
...
<several transitions to managed code>
...
<huge amount of unrelated trace messages later>
...
0073:Call user32.CreateWindowExW(00000200,0907369c
L"WindowsForms10.EDIT.app.0.3ce0bb8",0906fedc L"DX94: Graphics card
capabilities are below the minimum
specifications.",560108c0,00000005,00000013,0000027d,00000015,00020184,00000000,00400000,00000000)
ret=017edcbc 
--- snip ---

The error dialog window is created from .NET code (windows form), along with
some unusable callstack display (another bug).
The actual reason for the problem is not visible in trace log, one has to
analyse and step the disassembly.

d3d9_device_GetDeviceCaps() returns D3D9 Device Caps structure.
The engine code checks several caps struct members to decide if the card is
'good'.

My card 'NVIDIA GeForce GT 425M' was not recognized (bug 35054) hence Wine's
default choice was taken: 'Graphics Card: NVIDIA GeForce 8800 GTX'.

The minimum video card requirements for this game (from website): "NVIDIA
GeForce 8600 GT 512MB" ... so even with the default (incorrect) choice it
should have been 'good'.

Each time a requirement is not met the game internally assigns an error code
'DX<two-digit-code>' which is translated to a more or less generic error
message.

DirectX caps checks (in order):

--- snip ---
VertexShaderVersion

my raw value: 0xFFFE0300
good value: >= 3.0 (masked out)
failure: "DX92: Shadermodel 3.0 required"
--- snip ---

--- snip ---
PixelShaderVersion

my raw value: 0xFFFF0300
sanitized good value: >= 3.0 (masked out)
failure: "DX93: Shadermodel 3.0 required")
--- snip ---

Now the important one ...

--- snip ---
MaxVertexIndex

my raw value: 0xFFFFF
good value: 0x555555 (5592405 decimal)
failure: "DX94: Graphics card capabilities are below the minimum
specifications."
--- snip ---

Wine uses a hard-coded default value.

d3d9_device_GetDeviceCaps -> wined3d_device_get_device_caps ->
wined3d_get_device_caps

(filter_caps)

Source:
http://source.winehq.org/git/wine.git/blob/34ad4c7014c63a4b4f96f94ba4973831b97be2e5:/dlls/wined3d/directx.c#l4440

--- snip ---
4100 HRESULT CDECL wined3d_get_device_caps(const struct wined3d *wined3d, UINT
adapter_idx,
4101 enum wined3d_device_type device_type, WINED3DCAPS *caps)
4102 {
...
4441 caps->MaxAnisotropy = gl_info->limits.anisotropy;
4442 caps->MaxPointSize = gl_info->limits.pointsize_max;
4443
4444 caps->MaxPrimitiveCount = 0xfffff; /* For now set 2^20-1 which is used by
most >=Geforce3/Radeon8500 cards */
4445 caps->MaxVertexIndex = 0xfffff;
4446 caps->MaxStreams = MAX_STREAMS;
4447 caps->MaxStreamStride = 1024;
...
--- snip ---

Increasing the limit to 0x555555 made the game DirectX engine happy :)
There were a few other dx caps checks following but those requirements were
fulfilled by default.

***

Interesting tidbit:

There exists a kind of hack to overcome the failing dx caps check without
modifying Wine code.
During dumping/analysis of the main binary I found several 'goodies' ->
semi-/undocumented command line parameters.

One of them is '-disablecrashhandler'.
You can pass it through launcher 'command line' options dialog.

This basically skips the invocation of the .NET based error handler and lets
the game engine code continue as if nothing happened.

Having this kind of 'override' in actual code is usually disastrous.
Due to the special way the requirement checks were coded this 'magically'
works.
Each invocation of error handler leads to a no-return 'continuation' like call.
The next prerequisite check immediately follows the no-return call (without
branches in between).
Disabling the crash handler made the no-return calls basically a no-op hence
letting the execution flow 'magically' continue.

***

The game runs further until next problem ... looks like some wined3d volume
texture/surface management thing (that area is currently being worked on).

$ wine --version
wine-1.7.8-200-gd566292

Regards

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list