Hi wine-devel,
I'm attempting to fix http://bugs.winehq.org/show_bug.cgi?id=13683 but need some advice as to where to start. I'm not too familiar with hacking on Wine.
I'd like to test Stefan Dösinger's theory outlined in the comments for #13683 that the missing second mouse cursor is perhaps being implemented using DirectX overlays and that Wine's lack of overlay compatibility flags is to blame.
Would the proper action to test this theory be to fake a certain set of flags in dlls/d3d8/device.c's static HRESULT WINAPI d3d8_device_GetDeviceCaps(IDirect3DDevice8 *iface, D3DCAPS8 *caps) ? If that proves to be the issue, I'd then need to write proper code to report the correct set of flags presumably.
Is there any easy way to see which DLLs Wine loads when running an application?
I appreciate any advice, I'm new but want to help, Christopher Thielen
On Feb 15, 2014, at 6:17 PM, Christopher Thielen wrote:
I'm attempting to fix http://bugs.winehq.org/show_bug.cgi?id=13683 but need some advice as to where to start. I'm not too familiar with hacking on Wine.
I'd like to test Stefan Dösinger's theory outlined in the comments for #13683 that the missing second mouse cursor is perhaps being implemented using DirectX overlays and that Wine's lack of overlay compatibility flags is to blame.
Would the proper action to test this theory be to fake a certain set of flags in dlls/d3d8/device.c's static HRESULT WINAPI d3d8_device_GetDeviceCaps(IDirect3DDevice8 *iface, D3DCAPS8 *caps) ? If that proves to be the issue, I'd then need to write proper code to report the correct set of flags presumably.
Probably you should start by collecting a log with the +ddraw,+d3d,+d3d_surface channels and looking for messages that mention "overlay".
From a cursory look, it seems that wined3d supports some types of overlay surfaces and some operations on those surfaces, but not all.
Is there any easy way to see which DLLs Wine loads when running an application?
You can look at a +module log.
-Ken
No luck so far: I ran the application for about 30 seconds and generated a 975 MB log file but a case insensitive "overlay" appears not at all.
Since this missing secondary mouse cursor only appears during certain game states, one idea I had is to look at the 'fixme's in the log and see if any roughly correlate to when the cursor should be on-screen. This is assuming the log growth correlates to game-time, which it probably does with the exception of program start and stop.
I don't know if that's the next best way to debug this but there are two fixme lines that come up a lot (hundreds and hundreds of times):
fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00.
(and somewhat less often though still prevalent):
fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000
Do any of these fixmes sound to be likely candidates to the more knowledgeable DirectX folks? (The former sounds like a DX surface is supposed to be blitted somewhere but the request is invalid - perhaps that's the missing cursor?)
- Christopher Thielen
On 02/15/2014 05:05 PM, Ken Thomases wrote:
On Feb 15, 2014, at 6:17 PM, Christopher Thielen wrote:
I'm attempting to fix http://bugs.winehq.org/show_bug.cgi?id=13683 but need some advice as to where to start. I'm not too familiar with hacking on Wine.
I'd like to test Stefan Dösinger's theory outlined in the comments for #13683 that the missing second mouse cursor is perhaps being implemented using DirectX overlays and that Wine's lack of overlay compatibility flags is to blame.
Would the proper action to test this theory be to fake a certain set of flags in dlls/d3d8/device.c's static HRESULT WINAPI d3d8_device_GetDeviceCaps(IDirect3DDevice8 *iface, D3DCAPS8 *caps) ? If that proves to be the issue, I'd then need to write proper code to report the correct set of flags presumably.
Probably you should start by collecting a log with the +ddraw,+d3d,+d3d_surface channels and looking for messages that mention "overlay".
From a cursory look, it seems that wined3d supports some types of overlay surfaces and some operations on those surfaces, but not all.
Is there any easy way to see which DLLs Wine loads when running an application?
You can look at a +module log.
-Ken
On Feb 16, 2014, at 3:06 AM, Christopher Thielen wrote:
No luck so far: I ran the application for about 30 seconds and generated a 975 MB log file but a case insensitive "overlay" appears not at all.
To keep the log size down, you could try a warn+ddraw,warn+d3d,warn+d3d_surface log, instead.
Since this missing secondary mouse cursor only appears during certain game states, one idea I had is to look at the 'fixme's in the log and see if any roughly correlate to when the cursor should be on-screen. This is assuming the log growth correlates to game-time, which it probably does with the exception of program start and stop.
I don't know if that's the next best way to debug this but there are two fixme lines that come up a lot (hundreds and hundreds of times):
fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00.
The wined3d_debug_location() function is used in other tracing lines. So, to figure out what is affected by it, you would want to read the next line or two from the log.
fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000
Same here.
These both may go away if you reduce the logging to just WARNs (and ERRs and FIXMEs which are enabled by default). It's possible they were only be generated by TRACEs.
-Ken
Unfortunately, there is no reference to "ddraw7_GetCaps" or "GetCaps" anywhere in the 975 MB log. That confirms it isn't using overlays, right?
This gog.com version uses nGlide to wrap the Glide API to DirectX calls - DX9 I believe, based on the requirements of nGlide (http://www.zeus-software.com/downloads/nglide). Not sure if this information helps.
I re-ran the test case using Ken's suggestion of adding the 'warn' lines and the log went down to 35 MB. I uploaded a gzipped version to the bug report.
The two lines I was wondering about still appear even with 'warn+ddraw,warn+d3d,warn+d3d_surface'.
The surrounding log lines around the first of the two lines in question are simply repeats. A snippet of the logfile looks something like:
fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00. fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00.
The second line I'm curious about is a little more interesting and seems to occur in groups like this:
warn:d3d:wined3d_get_adapter_display_mode Overriding format WINED3DFMT_B8G8R8X8_UNORM with stored format WINED3DFMT_B8G8R8A8_UNORM. fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000 fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000 fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000 fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000 fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000 fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000 fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000 (end of the Unrecognized usage flag(s) repeating - the line seems to appear 7 times each grouping)
Given that these lines appear even with the 'warn' level increased, does anyone think they're significant? I could start reading some API docs and figure out what these unrecognized flags are if it sounds promising.
- Christopher Thielen
On 02/16/2014 01:48 AM, Ken Thomases wrote:
On Feb 16, 2014, at 3:06 AM, Christopher Thielen wrote:
No luck so far: I ran the application for about 30 seconds and generated a 975 MB log file but a case insensitive "overlay" appears not at all.
To keep the log size down, you could try a warn+ddraw,warn+d3d,warn+d3d_surface log, instead.
Since this missing secondary mouse cursor only appears during certain game states, one idea I had is to look at the 'fixme's in the log and see if any roughly correlate to when the cursor should be on-screen. This is assuming the log growth correlates to game-time, which it probably does with the exception of program start and stop.
I don't know if that's the next best way to debug this but there are two fixme lines that come up a lot (hundreds and hundreds of times):
fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00.
The wined3d_debug_location() function is used in other tracing lines. So, to figure out what is affected by it, you would want to read the next line or two from the log.
fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000
Same here.
These both may go away if you reduce the logging to just WARNs (and ERRs and FIXMEs which are enabled by default). It's possible they were only be generated by TRACEs.
-Ken
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Am 2014-02-16 20:39, schrieb Christopher Thielen:
fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00.
These lines are harmless. That's pretty much code doing something like this
TRACE("Removing flags %s.\n", wined3d_debug_location(~WINED3D_LOCATION_SYSMEM);
which ends up passing a value like 0xfffffffe to wined3d_debug_location.
wined3d_debug_location then does something like
if (flags & (SYSMEM | BUFFER | ALL | DEFINED | FLAGS)) FIXME("Unrecognized location flag(s) %#x.\n", flags);
What is missing here is a logical and that filters out unknown flags in places where a bitwise not is used, or maybe just the removal of the unknown flags fixme in wined3d_debug_location.
Unfortunately, there is no reference to "ddraw7_GetCaps" or "GetCaps" anywhere in the 975 MB log. That confirms it isn't using overlays, right?
Pretty much, yeah.
fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000
That's WINED3DUSAGE_TEXTURE and needs to be added to the debug function.
This gog.com version uses nGlide to wrap the Glide API to DirectX calls - DX9 I believe, based on the requirements of nGlide (http://www.zeus-software.com/downloads/nglide). Not sure if this information helps.
This means the GOG version is using an entirely different codepath than what you're trying to run. It is quite possible that the codepath you're running is broken in some way. I recommend to test if the game's ddraw codepath is working properly on Windows before you bang your head against it. It can save you a lot of time :-) .
If it turns out that the ddraw codepath is working just fine on Windows 7 there's certainly value in fixing it. If it is not, but it is working on e.g. Windows XP, it might still be worth a look.
I should clarify as per Stefan Dösinger's comments that I have only been using the gog.com version (both under Wine and in my testing so far under Windows XP) so the nGlide wrapper code paths should be the same. The original, non-gog.com version is more or less garbage due to some CD-ROM driver DRM-trickery.
Erich Hoover suggested to look at WINEDEBUG=+cursor,+icon,+resource and see if the game is merely using 'traditional' cursors. I do know this game was in development for quite a while and originally started out as a Glide game, so it makes some sense that the DirectX ShowCursor stuff might not be used at all. I tried TRACE'ing d3d8_device,d3d9_device,and dinput but found no calls related to cursors.
The WINEDEBUG=+cursor,+icon,+resource trace does appear to be onto something though. I attached the log to the bug but here are some snippets:
trace:icon:ICO_LoadIcon 0x360000 0x360086 trace:cursor:CreateIconFromResourceEx 0x37dc22 (1128 bytes), ver 00030000, 32x32 icon trace:cursor:ungrab_clipping_window no longer clipping trace:icon:DrawIconEx (hdc=0x2002d,pos=23.4,hicon=0x10044,extend=32.32,istep=0,br=(nil),flags=0x0000000b) trace:resource:LdrFindResource_U module 0x7e920000 type #0018 name #0002 lang 0000 level 3 trace:resource:find_entry_by_id root 0x7e93f3b4 dir 0x7e93f3b4 id 0018 not found trace:cursor:LoadCursorW (nil), #7f00 trace:resource:LoadImageW ((nil),#7f00,2,0,0,0x00008040) trace:cursor:CURSORICON_Load (nil), #7f00, 0x0, depth 32, fCursor 1, flags 0x8040
In particular, when the user presses 'Q', it should toggle the cursor icon. Here is the log grepped for "cursor:LoadIconW":
trace:cursor:LoadIconW (nil), #7f05 trace:cursor:LoadIconW (nil), #7f05 trace:cursor:LoadIconW 0x7edb0000, L"" trace:cursor:LoadIconW (nil), L"" trace:cursor:LoadIconW (nil), #7f05 trace:cursor:LoadIconW 0x7edf0000, #0001 trace:cursor:LoadIconW 0x7edb0000, #0001 trace:cursor:LoadIconW (nil), #7f05 trace:cursor:LoadIconW (nil), #7f00 trace:cursor:LoadIconW (nil), #7f00
Am I wrong in reading this as the game toggling between two cursors? Is there a way to dump the ICO resource from LoadIconW to the file system to debug which icons it is trying and/or failing to load?
Thanks again to everybody for all your help so far, Christopher Thielen
On 02/16/2014 11:55 AM, Stefan Dösinger wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Am 2014-02-16 20:39, schrieb Christopher Thielen:
fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00.
These lines are harmless. That's pretty much code doing something like this
TRACE("Removing flags %s.\n", wined3d_debug_location(~WINED3D_LOCATION_SYSMEM);
which ends up passing a value like 0xfffffffe to wined3d_debug_location.
wined3d_debug_location then does something like
if (flags & (SYSMEM | BUFFER | ALL | DEFINED | FLAGS)) FIXME("Unrecognized location flag(s) %#x.\n", flags);
What is missing here is a logical and that filters out unknown flags in places where a bitwise not is used, or maybe just the removal of the unknown flags fixme in wined3d_debug_location.
Unfortunately, there is no reference to "ddraw7_GetCaps" or "GetCaps" anywhere in the 975 MB log. That confirms it isn't using overlays, right?
Pretty much, yeah.
fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000
That's WINED3DUSAGE_TEXTURE and needs to be added to the debug function.
This gog.com version uses nGlide to wrap the Glide API to DirectX calls - DX9 I believe, based on the requirements of nGlide (http://www.zeus-software.com/downloads/nglide). Not sure if this information helps.
This means the GOG version is using an entirely different codepath than what you're trying to run. It is quite possible that the codepath you're running is broken in some way. I recommend to test if the game's ddraw codepath is working properly on Windows before you bang your head against it. It can save you a lot of time :-) .
If it turns out that the ddraw codepath is working just fine on Windows 7 there's certainly value in fixing it. If it is not, but it is working on e.g. Windows XP, it might still be worth a look. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
iQIcBAEBAgAGBQJTARfAAAoJEN0/YqbEcdMwSC0P/1iZxKSLjIqEXeDmPsy7ARU9 vWm0Uqo0SYdCAEemGA2vD53IuojRUyMZ9E0ikfCZ7qlVK7uaFs54TtiY15C+p6ic gZhNezdyt/6idLootvCsJ9ZDoSaFdIDvoWga7JThwlZnfGVVZIGj6WeJeTV+rXon QHkQO/jghlHpgZIT6mdicvsltaWujg+Idwfuz1Z8i8+fKEhy7Uvp+QKCqsF8JdNf AuDceOPwF8aaH0YWVieyQfTiqzv4RHTnF5i+LGWPx61SRuRXi2YT+2hHlTbspua2 6/FfQ+c2P6eoI39UiRysWL8+zB+T0o5V0JOF2PD5EJGqc+vP4066XkxZlA7Kdl6W h8RCzDbU+gxeq49cXHTG6AbvLUdkbDowo/dwW6x4wOmnlzZBW5CNxF0NbQ0Jf4sW mQLynduNdejnqgwZSFb5m8AoTqCZ+XbLkGq5uPAcAz6TIlsrKW7oQ41rTkeLxpU/ Z5nlLDmC5MIP8t8he2KuLu8eVrLhSsxYFEyeevhHY/SvNkmi1LxkXJMQHt8gDpdi 3ZW+LuW5nsOJ/9T7vH27ENorqRNtpFWnpdwPMyBgQJbPlNCYVp5ZTKE8WHpk+fk4 T+LzzbOlli8svOLHll4rmDhD89qYiQQUWNv7V7XjTHrgrxpZFY5aLXrprEGTc6Kc PCO4omr8MIkjrtJAHfKX =evKW -----END PGP SIGNATURE-----
I still haven't figured this bug out yet but Erich Hoover's help I've at least determined the missing cursor is not loaded from a resource in the .exe.
I ported an Allegro-based fan tool somebody wrote in 2000 to Linux+SDL and have determined that the missing cursor is loaded from a resource file in the game's static/bitmap.flx file.
Two questions: 1) Is there a way to add timestamps to the TRACE statements in Wine? 2) If I know which file is opened by the game, is there a way to debug from that point on, i.e. capture the fopen() and enable +cursor,+resource,+d3d TRACES for say, only 5 seconds after that point? Something along those lines?
I can find the exact offset within the data file used to load the missing resource - but I'd need a way to know when a fread() was that far along. I figure if I can determine that I can determine if the cursor is loaded as a Windows cursor or as a D3D surface and go from there.
Any ideas?
- Christopher Thielen
On 02/17/2014 12:27 PM, Christopher Thielen wrote:
I should clarify as per Stefan Dösinger's comments that I have only been using the gog.com version (both under Wine and in my testing so far under Windows XP) so the nGlide wrapper code paths should be the same. The original, non-gog.com version is more or less garbage due to some CD-ROM driver DRM-trickery.
Erich Hoover suggested to look at WINEDEBUG=+cursor,+icon,+resource and see if the game is merely using 'traditional' cursors. I do know this game was in development for quite a while and originally started out as a Glide game, so it makes some sense that the DirectX ShowCursor stuff might not be used at all. I tried TRACE'ing d3d8_device,d3d9_device,and dinput but found no calls related to cursors.
The WINEDEBUG=+cursor,+icon,+resource trace does appear to be onto something though. I attached the log to the bug but here are some snippets:
trace:icon:ICO_LoadIcon 0x360000 0x360086 trace:cursor:CreateIconFromResourceEx 0x37dc22 (1128 bytes), ver 00030000, 32x32 icon trace:cursor:ungrab_clipping_window no longer clipping trace:icon:DrawIconEx (hdc=0x2002d,pos=23.4,hicon=0x10044,extend=32.32,istep=0,br=(nil),flags=0x0000000b)
trace:resource:LdrFindResource_U module 0x7e920000 type #0018 name #0002 lang 0000 level 3 trace:resource:find_entry_by_id root 0x7e93f3b4 dir 0x7e93f3b4 id 0018 not found trace:cursor:LoadCursorW (nil), #7f00 trace:resource:LoadImageW ((nil),#7f00,2,0,0,0x00008040) trace:cursor:CURSORICON_Load (nil), #7f00, 0x0, depth 32, fCursor 1, flags 0x8040
In particular, when the user presses 'Q', it should toggle the cursor icon. Here is the log grepped for "cursor:LoadIconW":
trace:cursor:LoadIconW (nil), #7f05 trace:cursor:LoadIconW (nil), #7f05 trace:cursor:LoadIconW 0x7edb0000, L"" trace:cursor:LoadIconW (nil), L"" trace:cursor:LoadIconW (nil), #7f05 trace:cursor:LoadIconW 0x7edf0000, #0001 trace:cursor:LoadIconW 0x7edb0000, #0001 trace:cursor:LoadIconW (nil), #7f05 trace:cursor:LoadIconW (nil), #7f00 trace:cursor:LoadIconW (nil), #7f00
Am I wrong in reading this as the game toggling between two cursors? Is there a way to dump the ICO resource from LoadIconW to the file system to debug which icons it is trying and/or failing to load?
Thanks again to everybody for all your help so far, Christopher Thielen
On 02/16/2014 11:55 AM, Stefan Dösinger wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Am 2014-02-16 20:39, schrieb Christopher Thielen:
fixme:d3d:wined3d_debug_location Unrecognized location flag(s) 0xfffffc00.
These lines are harmless. That's pretty much code doing something like this
TRACE("Removing flags %s.\n", wined3d_debug_location(~WINED3D_LOCATION_SYSMEM);
which ends up passing a value like 0xfffffffe to wined3d_debug_location.
wined3d_debug_location then does something like
if (flags & (SYSMEM | BUFFER | ALL | DEFINED | FLAGS)) FIXME("Unrecognized location flag(s) %#x.\n", flags);
What is missing here is a logical and that filters out unknown flags in places where a bitwise not is used, or maybe just the removal of the unknown flags fixme in wined3d_debug_location.
Unfortunately, there is no reference to "ddraw7_GetCaps" or "GetCaps" anywhere in the 975 MB log. That confirms it isn't using overlays, right?
Pretty much, yeah.
fixme:d3d:debug_d3dusage Unrecognized usage flag(s) 0x10000000
That's WINED3DUSAGE_TEXTURE and needs to be added to the debug function.
This gog.com version uses nGlide to wrap the Glide API to DirectX calls - DX9 I believe, based on the requirements of nGlide (http://www.zeus-software.com/downloads/nglide). Not sure if this information helps.
This means the GOG version is using an entirely different codepath than what you're trying to run. It is quite possible that the codepath you're running is broken in some way. I recommend to test if the game's ddraw codepath is working properly on Windows before you bang your head against it. It can save you a lot of time :-) .
If it turns out that the ddraw codepath is working just fine on Windows 7 there's certainly value in fixing it. If it is not, but it is working on e.g. Windows XP, it might still be worth a look. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
iQIcBAEBAgAGBQJTARfAAAoJEN0/YqbEcdMwSC0P/1iZxKSLjIqEXeDmPsy7ARU9 vWm0Uqo0SYdCAEemGA2vD53IuojRUyMZ9E0ikfCZ7qlVK7uaFs54TtiY15C+p6ic gZhNezdyt/6idLootvCsJ9ZDoSaFdIDvoWga7JThwlZnfGVVZIGj6WeJeTV+rXon QHkQO/jghlHpgZIT6mdicvsltaWujg+Idwfuz1Z8i8+fKEhy7Uvp+QKCqsF8JdNf AuDceOPwF8aaH0YWVieyQfTiqzv4RHTnF5i+LGWPx61SRuRXi2YT+2hHlTbspua2 6/FfQ+c2P6eoI39UiRysWL8+zB+T0o5V0JOF2PD5EJGqc+vP4066XkxZlA7Kdl6W h8RCzDbU+gxeq49cXHTG6AbvLUdkbDowo/dwW6x4wOmnlzZBW5CNxF0NbQ0Jf4sW mQLynduNdejnqgwZSFb5m8AoTqCZ+XbLkGq5uPAcAz6TIlsrKW7oQ41rTkeLxpU/ Z5nlLDmC5MIP8t8he2KuLu8eVrLhSsxYFEyeevhHY/SvNkmi1LxkXJMQHt8gDpdi 3ZW+LuW5nsOJ/9T7vH27ENorqRNtpFWnpdwPMyBgQJbPlNCYVp5ZTKE8WHpk+fk4 T+LzzbOlli8svOLHll4rmDhD89qYiQQUWNv7V7XjTHrgrxpZFY5aLXrprEGTc6Kc PCO4omr8MIkjrtJAHfKX =evKW -----END PGP SIGNATURE-----
Am 18.02.2014 um 06:12 schrieb Christopher Thielen christopher@thielen.co:
Two questions:
- Is there a way to add timestamps to the TRACE statements in Wine?
WINEDEBUG=+timestamp
This adds timestamps to other traces, so you can do e.g. WINEDEBUG=d3d,timestamp to get a d3d trace with timestamps.
- If I know which file is opened by the game, is there a way to debug from that point on, i.e. capture the fopen() and enable +cursor,+resource,+d3d TRACES for say, only 5 seconds after that point? Something along those lines?
Afaik no. You could use some search and replace tricks in text editors or with command line text tools though.
I can find the exact offset within the data file used to load the missing resource - but I'd need a way to know when a fread() was that far along. I figure if I can determine that I can determine if the cursor is loaded as a Windows cursor or as a D3D surface and go from there.
Note that there are plenty of ways to open and read files. fopen and fread are just one of them. There are win32 equivalents of those C functions, and there are specific resource loading functions which you’ve probably already seen.
Good point. Maybe knowing the offset isn't too useful for now.
I still haven't figured out through what mechanism the game draws this missing cursor. The D3D9 cursor functions never make a sound in the logs and while the User32 LoadCursor/SetCursor/clipping stuff is called an awful lot on initialization, it looks like it's always for the system cursors. I also pasted in a method to dump to a .bmp file anything that goes through LoadIcon and wound up with one icon I don't recall and another which was simply Wine's icon.
So, my hunch now is that the game draws the cursor using DirectX and uses User32 only for setting mouse clipping.
Is there a decent way to dump as a file every DX resource loaded that's under a certain size? I'd like to confirm my theory and maybe if I'm lucky figure out which DX surface/texture is being drawn incorrectly (if any).
- Christopher Thielen
On 02/18/2014 12:16 AM, Stefan Dösinger wrote:
Am 18.02.2014 um 06:12 schrieb Christopher Thielen christopher@thielen.co:
Two questions:
- Is there a way to add timestamps to the TRACE statements in Wine?
WINEDEBUG=+timestamp
This adds timestamps to other traces, so you can do e.g. WINEDEBUG=d3d,timestamp to get a d3d trace with timestamps.
- If I know which file is opened by the game, is there a way to debug from that point on, i.e. capture the fopen() and enable +cursor,+resource,+d3d TRACES for say, only 5 seconds after that point? Something along those lines?
Afaik no. You could use some search and replace tricks in text editors or with command line text tools though.
I can find the exact offset within the data file used to load the missing resource - but I'd need a way to know when a fread() was that far along. I figure if I can determine that I can determine if the cursor is loaded as a Windows cursor or as a D3D surface and go from there.
Note that there are plenty of ways to open and read files. fopen and fread are just one of them. There are win32 equivalents of those C functions, and there are specific resource loading functions which you’ve probably already seen.
I determined this isn't the User32 cursor stuff. It's probably a D3D surface with incorrect properties.
Can anyone recommend an OpenGL debugger or other mechanism for exploring the surfaces of a given scene and playing with their properties? My guess is the tools are pretty primitive for this kind of thing.
On 2/18/14, 7:19 PM, Christopher Thielen wrote:
Good point. Maybe knowing the offset isn't too useful for now.
I still haven't figured out through what mechanism the game draws this missing cursor. The D3D9 cursor functions never make a sound in the logs and while the User32 LoadCursor/SetCursor/clipping stuff is called an awful lot on initialization, it looks like it's always for the system cursors. I also pasted in a method to dump to a .bmp file anything that goes through LoadIcon and wound up with one icon I don't recall and another which was simply Wine's icon.
So, my hunch now is that the game draws the cursor using DirectX and uses User32 only for setting mouse clipping.
Is there a decent way to dump as a file every DX resource loaded that's under a certain size? I'd like to confirm my theory and maybe if I'm lucky figure out which DX surface/texture is being drawn incorrectly (if any).
- Christopher Thielen
On 02/18/2014 12:16 AM, Stefan Dösinger wrote:
Am 18.02.2014 um 06:12 schrieb Christopher Thielen christopher@thielen.co:
Two questions:
- Is there a way to add timestamps to the TRACE statements in Wine?
WINEDEBUG=+timestamp
This adds timestamps to other traces, so you can do e.g. WINEDEBUG=d3d,timestamp to get a d3d trace with timestamps.
- If I know which file is opened by the game, is there a way to
debug from that point on, i.e. capture the fopen() and enable +cursor,+resource,+d3d TRACES for say, only 5 seconds after that point? Something along those lines?
Afaik no. You could use some search and replace tricks in text editors or with command line text tools though.
I can find the exact offset within the data file used to load the missing resource - but I'd need a way to know when a fread() was that far along. I figure if I can determine that I can determine if the cursor is loaded as a Windows cursor or as a D3D surface and go from there.
Note that there are plenty of ways to open and read files. fopen and fread are just one of them. There are win32 equivalents of those C functions, and there are specific resource loading functions which you’ve probably already seen.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Am 2014-03-19 22:45, schrieb Christopher Thielen:
I determined this isn't the User32 cursor stuff. It's probably a D3D surface with incorrect properties.
Apitrace works for d3d9.
Can anyone recommend an OpenGL debugger or other mechanism for exploring the surfaces of a given scene and playing with their properties? My guess is the tools are pretty primitive for this kind of thing.
Did you see if d3d+warn writes anything about failed surface creation?
You can try to record a game drawing with apitrace on Windows and see if it plays back correctly on Wine. Also check if the playback shows the mouse pointer in Windows.
I don't know if d3d9 recording with apitrace works in Wine - it might just work, or it might be missing some DECLSPEC_HOTPATCH markers on some d3d9 functions.
You can also use the Linux version of apitrace to record the opengl calls wined3d creates. This will probably not help you in your case.
I could be running it wrong but both:
WINEDEBUG=d3d+warn wine ./u9.exe
and
WINEDEBUG=+d3d+warn wine ./u9.exe
show no lines about D3D warnings.
Just this, right at program start: fixme:d3d:init_driver_info Unable to find a driver/device info for vendor_id=0x10de device_id=0x421 for driver_model=2 fixme:win:EnumDisplayDevicesW ((null),0,0x32e8c8,0x00000000), stub! fixme:d3d:init_driver_info Unable to find a driver/device info for vendor_id=0x10de device_id=0x421 for driver_model=2 fixme:win:EnumDisplayDevicesW ((null),0,0x32e6a8,0x00000000), stub! fixme:d3d:resource_check_usage Unhandled usage flags 0x8. fixme:d3d:resource_check_usage Unhandled usage flags 0x8.
apitrace is really neat, thanks for pointing it out. I ran it on Windows XP with the Ultima IX (GOG edition) and generated a trace - which shows the missing mouse cursor - then rebooted into Linux and ran the Windows version of apitrace's GUI using the same .trace file and it _did_ also show the mouse cursor, running under Wine.
What does this mean? What direction would one explore from here? How is it when u9.exe executes the same D3D calls (running the game under Wine) the cursor is missing but when Wine runs the apitrace GUI, making the same D3D calls and getting translated through the same Wine code, the cursor doesn't appear. What am I missing?
Also, I don't know apitrace that well, but is the per-frame 'texture' tab only showing textures utilized in that frame, not counting anything already in the framebuffer? I couldn't find the cursor texture after looking at about two dozen frames, but then again, I didn't find most textures using that method.
I did run an apitrace of Ultima IX (GOG edition) on Linux for kicks but I don't think it'll help much. There is a factor of about 4x as many calls per frame when running under Wine FYI, but I'm assuming the Wine D3D folks are already aware of that sort of issue.
On 03/19/2014 03:13 PM, Stefan Dösinger wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Am 2014-03-19 22:45, schrieb Christopher Thielen:
I determined this isn't the User32 cursor stuff. It's probably a D3D surface with incorrect properties.
Apitrace works for d3d9.
Can anyone recommend an OpenGL debugger or other mechanism for exploring the surfaces of a given scene and playing with their properties? My guess is the tools are pretty primitive for this kind of thing.
Did you see if d3d+warn writes anything about failed surface creation?
You can try to record a game drawing with apitrace on Windows and see if it plays back correctly on Wine. Also check if the playback shows the mouse pointer in Windows.
I don't know if d3d9 recording with apitrace works in Wine - it might just work, or it might be missing some DECLSPEC_HOTPATCH markers on some d3d9 functions.
You can also use the Linux version of apitrace to record the opengl calls wined3d creates. This will probably not help you in your case.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
iQIcBAEBAgAGBQJTKhZ3AAoJEN0/YqbEcdMwuxsP/iK9wDECv6CoMjYxjDo1yxQV jPC0KbSUw2DwUl0fFTCdWi6PxeTUoz8Hp2IC60D07BvGDiPaxJwRvewfO5jeYuqr sINzPgk5NgnZjkUN+cs4oGYlEFXY4p02eSe3uZhihlD0lnbJ0pV/g+8f4RPeIctM acTdC6kaIOUQLkRGliOotaj3w27e5QomXiaHcn1l8Ov3of7dBnJtg7hJTvlymL0g bUOpnCVHtN1BoeWwQUPUEzhqMjmU4gUCgBZ7lBDsbReeNmFHoeR0QaIqC8EWKr0D jznbKuAjuK+9GB/cVhqJj+hHlCaj6xoyNfOQQ34KHYcdtbAMhOTCkJbKzPmCeH8r xU3C2nSH88fld/Ie7oULE671XUNnXjPgDQPIcyeBC3PYZ33dR5vzLJrMA63/zA9X dP2qiF/A2N7Sk0Mq0FHtKcLICo9W+w7AXOdksZlrWEX4iiUB6LX3sQ+vMm+IePL0 WxcxP4CEAhXGiu/bub4hj8y3BbvbfyQklrZ4cz05iIf+WS4xYo6cwZ53ciVpgwBu V52s8N/XpC6QSy7UpqV1b6JuvMliHlLKGSbCZMezbsB6mShKdGyq45T1JhGukkh0 Q3DEQoX5TQSg8RqyRwr8coDZDwD0zese6uE+aVuzzznyY0LrTDo4Jio+Y3mWL45e jivFvw1C6uoFTKPqU8oM =QPSs -----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Am 2014-03-21 03:24, schrieb Christopher Thielen:
apitrace is really neat, thanks for pointing it out. I ran it on Windows XP with the Ultima IX (GOG edition) and generated a trace - which shows the missing mouse cursor - then rebooted into Linux and ran the Windows version of apitrace's GUI using the same .trace file and it _did_ also show the mouse cursor, running under Wine.
It means one thing for sure: The cursor is not a user32 cursor. Otherwise it would not show up in the captures.
I have two theories: Either the game looks at the d3d capabilities (CheckDeviceFormat, GetDeviceCaps, mostly IDirect3D9 methods) and concludes that something is missing, enters a bad codepath and does not draw the pointer.
Or some function unrelated to d3d does not work and the game fails to read the pointer from its resources.
Since this is a glide application running through a glide wrapper the second case is much more likely. (Unless my memory is completely broken)
You can compile wined3d for Windows. The basic idea is to set CFLAGS=-DUSE_WIN32_OPENGL and compile it with mingw on Windows, or Cross-Compile it from Linux. I also have a hacky Visual Studio 2013 based build setup, but you'll have a hard time generating a binary that works on Windows XP with that. With a Win32 build of wined3d.dll and our d3d9.dll you can run the game on Windows with our d3d code. If the pointer shows up in that case this demonstrates that it is not a d3d issue. If it does not, it shows that the issue is a capability flag problem.
Also, I don't know apitrace that well, but is the per-frame 'texture' tab only showing textures utilized in that frame, not counting anything already in the framebuffer? I couldn't find the cursor texture after looking at about two dozen frames, but then again, I didn't find most textures using that method.
No idea :-(
I did run an apitrace of Ultima IX (GOG edition) on Linux for kicks but I don't think it'll help much. There is a factor of about 4x as many calls per frame when running under Wine FYI, but I'm assuming the Wine D3D folks are already aware of that sort of issue.
Did you run the Linux apitrace? In this case you'll see OpenGL calls instead of d3d calls. Or did you use the Windows apitrace version inside Wine?
2014-03-21 10:14 GMT+01:00 Stefan Dösinger stefandoesinger@gmail.com:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Am 2014-03-21 03:24, schrieb Christopher Thielen:
apitrace is really neat, thanks for pointing it out. I ran it on Windows XP with the Ultima IX (GOG edition) and generated a trace - which shows the missing mouse cursor - then rebooted into Linux and ran the Windows version of apitrace's GUI using the same .trace file and it _did_ also show the mouse cursor, running under Wine.
It means one thing for sure: The cursor is not a user32 cursor. Otherwise it would not show up in the captures.
I have two theories: Either the game looks at the d3d capabilities (CheckDeviceFormat, GetDeviceCaps, mostly IDirect3D9 methods) and concludes that something is missing, enters a bad codepath and does not draw the pointer.
Or some function unrelated to d3d does not work and the game fails to read the pointer from its resources.
Since this is a glide application running through a glide wrapper the second case is much more likely. (Unless my memory is completely broken)
You can compile wined3d for Windows. The basic idea is to set CFLAGS=-DUSE_WIN32_OPENGL and compile it with mingw on Windows, or Cross-Compile it from Linux. I also have a hacky Visual Studio 2013 based build setup, but you'll have a hard time generating a binary that works on Windows XP with that. With a Win32 build of wined3d.dll and our d3d9.dll you can run the game on Windows with our d3d code. If the pointer shows up in that case this demonstrates that it is not a d3d issue. If it does not, it shows that the issue is a capability flag problem.
Also, I don't know apitrace that well, but is the per-frame 'texture' tab only showing textures utilized in that frame, not counting anything already in the framebuffer? I couldn't find the cursor texture after looking at about two dozen frames, but then again, I didn't find most textures using that method.
No idea :-(
I never used apitrace on D3D traces, I assume it works in the same fashion as on GL ones. The 'texture' tab shows the textures bound to the texture units at that point in time, each one of them might or might not be used by the draw call you're examining. You should check the shaders (or the state of the fixed function pipeline, if no shaders are bound) to know which of those textures are actually used by the draw you're looking into.
What you can do at this point is to go through the draw calls of a frame, looking for the one which draws the cursor (I would do that just by looking at the framebuffer contents). Then run the game in Wine + apitrace and see if you can find the same draw in the GL trace. Either the draw is there, in which case you can look into why it doesn't draw anything, or the call is totally missing, which would support the hypothesis of the bad caps / wrong game codepath.
I was able to find the frame and exact call which draws the cursor under the Windows XP code paths: it's drawn toward the end of the frame in two DrawPrimitiveUP calls.
I ran into trouble tracing the Wine codepaths for the same:
I first tried running the Win32 version of apitrace under Wine. It runs successfully but never generates a .trace file, even when I specify --output. If I ask it to run a program which doesn't load d3d9.dll, it emits a warning saying as much, so I know it's running. Anyone have success running the Win32 version of apitrace under Wine and getting a .trace file?
I then tried cross-compiling Wine from Linux using MinGW. I copied over the resulting d3d9.dll and wined3d.dll to the game's directory on Windows XP but it then won't run, complaining:
"The procedure entry point __wine_get_wgl_driver could not be located in the dynamic link library gdi32.dll."
So I tried copying over Wine's cross-compiled gdi32.dll but the message doesn't change. My guess is you cannot locally override gdi32? Should __wine_get_wgl_driver be in gdi32? Any idea how I can get the game to launch using Wine's DLLs?
I also have the Wine codepath OpenGL trace (from the Linux version of apitrace, tracing Wine) in which I've identified the frame but not the calls yet, so I cannot say if the texture is loaded correctly under Wine's codepaths or not yet.
On 3/21/2014 9:10 AM, Matteo Bruni wrote:
2014-03-21 10:14 GMT+01:00 Stefan Dösinger stefandoesinger@gmail.com:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Am 2014-03-21 03:24, schrieb Christopher Thielen:
apitrace is really neat, thanks for pointing it out. I ran it on Windows XP with the Ultima IX (GOG edition) and generated a trace - which shows the missing mouse cursor - then rebooted into Linux and ran the Windows version of apitrace's GUI using the same .trace file and it _did_ also show the mouse cursor, running under Wine.
It means one thing for sure: The cursor is not a user32 cursor. Otherwise it would not show up in the captures.
I have two theories: Either the game looks at the d3d capabilities (CheckDeviceFormat, GetDeviceCaps, mostly IDirect3D9 methods) and concludes that something is missing, enters a bad codepath and does not draw the pointer.
Or some function unrelated to d3d does not work and the game fails to read the pointer from its resources.
Since this is a glide application running through a glide wrapper the second case is much more likely. (Unless my memory is completely broken)
You can compile wined3d for Windows. The basic idea is to set CFLAGS=-DUSE_WIN32_OPENGL and compile it with mingw on Windows, or Cross-Compile it from Linux. I also have a hacky Visual Studio 2013 based build setup, but you'll have a hard time generating a binary that works on Windows XP with that. With a Win32 build of wined3d.dll and our d3d9.dll you can run the game on Windows with our d3d code. If the pointer shows up in that case this demonstrates that it is not a d3d issue. If it does not, it shows that the issue is a capability flag problem.
Also, I don't know apitrace that well, but is the per-frame 'texture' tab only showing textures utilized in that frame, not counting anything already in the framebuffer? I couldn't find the cursor texture after looking at about two dozen frames, but then again, I didn't find most textures using that method.
No idea :-(
I never used apitrace on D3D traces, I assume it works in the same fashion as on GL ones. The 'texture' tab shows the textures bound to the texture units at that point in time, each one of them might or might not be used by the draw call you're examining. You should check the shaders (or the state of the fixed function pipeline, if no shaders are bound) to know which of those textures are actually used by the draw you're looking into.
What you can do at this point is to go through the draw calls of a frame, looking for the one which draws the cursor (I would do that just by looking at the framebuffer contents). Then run the game in Wine + apitrace and see if you can find the same draw in the GL trace. Either the draw is there, in which case you can look into why it doesn't draw anything, or the call is totally missing, which would support the hypothesis of the bad caps / wrong game codepath.
Am 24.03.2014 um 18:53 schrieb Christopher Thielen christopher@thielen.co:
I then tried cross-compiling Wine from Linux using MinGW. I copied over the resulting d3d9.dll and wined3d.dll to the game's directory on Windows XP but it then won't run, complaining:
"The procedure entry point __wine_get_wgl_driver could not be located in the dynamic link library gdi32.dll.“
Did you set CFLAGS=-DUSE_WIN32_OPENGL ? This preprocessor define is needed to make wined3d work on Windows. Otherwise it uses some Wine-specific exports to bypass opengl32.dll for non-WGL calls and calls libGL.so directly for performance reasons.
That was exactly the problem - didn't read carefully enough.
Using Wine's D3D9 implementation on Windows XP, the missing cursor _does_ show up, so this Wine bug is likely not a D3D issue.
I did find some old fan-created tools which can extract the resources from the game's proprietary formats.
As there are no failed CreateSurface/CreateTexture calls, I'm assuming the code path never gets to that point.
Any ideas on how to go about debugging the problem of a custom file type not getting loaded? Does Wine implement it's own libc in which one could perhaps trace fread(), etc.? From the fan-made tools, I do have the byte offsets within the proprietary format where the missing cursor should be loaded from.
Also, is there any likely reason why Wine's behavior might differ from Windows on operations which are relatively libc-style operations?
On 3/24/2014 1:14 PM, Stefan Dösinger wrote:
Am 24.03.2014 um 18:53 schrieb Christopher Thielen christopher@thielen.co:
I then tried cross-compiling Wine from Linux using MinGW. I copied over the resulting d3d9.dll and wined3d.dll to the game's directory on Windows XP but it then won't run, complaining:
"The procedure entry point __wine_get_wgl_driver could not be located in the dynamic link library gdi32.dll.“
Did you set CFLAGS=-DUSE_WIN32_OPENGL ? This preprocessor define is needed to make wined3d work on Windows. Otherwise it uses some Wine-specific exports to bypass opengl32.dll for non-WGL calls and calls libGL.so directly for performance reasons.
Using WINEDEBUG=+all, the resource in question (static/bitmap16.flx) is loaded via kernel32's CreateFile, ReadFile.
Is there a way to trace only kernel32 calls dealing with a specific file handle? I'm curious if there are any failed reads. Does that seem like a reasonable next step?
On 03/24/2014 03:34 PM, Christopher Thielen wrote:
That was exactly the problem - didn't read carefully enough.
Using Wine's D3D9 implementation on Windows XP, the missing cursor _does_ show up, so this Wine bug is likely not a D3D issue.
I did find some old fan-created tools which can extract the resources from the game's proprietary formats.
As there are no failed CreateSurface/CreateTexture calls, I'm assuming the code path never gets to that point.
Any ideas on how to go about debugging the problem of a custom file type not getting loaded? Does Wine implement it's own libc in which one could perhaps trace fread(), etc.? From the fan-made tools, I do have the byte offsets within the proprietary format where the missing cursor should be loaded from.
Also, is there any likely reason why Wine's behavior might differ from Windows on operations which are relatively libc-style operations?
On 3/24/2014 1:14 PM, Stefan Dösinger wrote:
Am 24.03.2014 um 18:53 schrieb Christopher Thielen christopher@thielen.co:
I then tried cross-compiling Wine from Linux using MinGW. I copied over the resulting d3d9.dll and wined3d.dll to the game's directory on Windows XP but it then won't run, complaining:
"The procedure entry point __wine_get_wgl_driver could not be located in the dynamic link library gdi32.dll.“
Did you set CFLAGS=-DUSE_WIN32_OPENGL ? This preprocessor define is needed to make wined3d work on Windows. Otherwise it uses some Wine-specific exports to bypass opengl32.dll for non-WGL calls and calls libGL.so directly for performance reasons.
On Mar 24, 2014, at 7:48 PM, Christopher Thielen wrote:
Using WINEDEBUG=+all, the resource in question (static/bitmap16.flx) is loaded via kernel32's CreateFile, ReadFile.
Is there a way to trace only kernel32 calls dealing with a specific file handle? I'm curious if there are any failed reads. Does that seem like a reasonable next step?
Not really. You'll want to use a +file log and follow the handle as it's passed to subsequent calls. It might also be necessary to use +tid,+relay to see all uses if Wine isn't logging the handle in all relevant functions.
Certainly, look for failed reads, but I wouldn't expect that unless you think the file is damaged vs. what's installed on Windows. More likely, the game requires external help interpreting the data that is has read, like a compression or image library. If that's not present or is incomplete in Wine, then that would explain the problem. The +tid,+relay log may help to identify what the program does next after it has read the data in.
-Ken
Thanks Ken!
I don't think a missing library is the problem: the game stores all its texture resources in a file called bitmap16.flx and the code paths under Wine for reading those bitmaps and making textures out of them seems to work just fine given that many of them are visible in the final running game.
The offset of the cursor resource within bitmap16.flx is 0x1020eb4 and the '.flx item' (as files within this proprietary archive are called) itself is about 400,000 bytes (that's for 121 separate cursors all read at once).
Looking through +file,+tid,+relay recommended by Ken, I found:
0009:trace:file:CreateFileW L"C:\GOG Games\Ultima IX - Ascension\static\bitmap16.flx" GENERIC_READ creation 4 attributes 0x80 0009:trace:file:RtlDosPathNameToNtPathName_U (L"C:\GOG Games\Ultima IX - Ascension\static\bitmap16.flx",0x32ef74,(nil),(nil)) 0009:trace:file:RtlGetFullPathName_U (L"C:\GOG Games\Ultima IX - Ascension\static\bitmap16.flx" 520 0x32ecc4 (nil)) 0009:trace:file:wine_nt_to_unix_file_name L"\??\C:\GOG Games\Ultima IX - Ascension\static\bitmap16.flx" -> "/home/cthielen/.wine/dosdevices/c:/GOG Games/Ultima IX - Ascension/static/bitmap16.flx" 0009:trace:file:CreateFileW returning 0xac
which I believe implies bitmap16.flx is being given the file handle 0xac. Searching for '0xac' I later find:
0009:Call KERNEL32.SetFilePointer(000000ac,01020eb4,00000000,00000000) ret=005de4c9 0009:Ret KERNEL32.SetFilePointer() retval=01020eb4 ret=005de4c9 0009:Call KERNEL32.ReadFile(000000ac,02539110,00061b8c,0032edfc,00000000) ret=005de512 0009:trace:file:ReadFile 0xac 0x2539110 400268 0x32edfc (nil) 0009:Ret KERNEL32.ReadFile() retval=00000001 ret=005de512 0009:Call KERNEL32.GetLastError() ret=005de518 0009:Ret KERNEL32.GetLastError() retval=00000002 ret=005de518 0009:Call ntdll.RtlAllocateHeap(01450000,00000000,00001700) ret=00714f22 0009:Ret ntdll.RtlAllocateHeap() retval=0259aca8 ret=00714f22 0009:Call ntdll.RtlAllocateHeap(01450000,00000000,00000200) ret=00714f22 0009:Ret ntdll.RtlAllocateHeap() retval=0259c3b0 ret=00714f22 0009:Call user32.LoadCursorA(00000000,00007f00) ret=005d5743 0009:Ret user32.LoadCursorA() retval=00010038 ret=005d5743 0009:Call user32.SetCursor(00010038) ret=005dbf5f 0009:Call winex11.drv.SetCursor(00010038) ret=7eb0f777 0009:Ret winex11.drv.SetCursor() retval=00000000 ret=7eb0f777 0009:Ret user32.SetCursor() retval=00000000 ret=005dbf5f 0009:Call user32.CreateWindowExA(00000000,0032f5c0 "OFCBlackWindowClass",00787774 "Ultima IX",80030000,80000000,80000000,80000000,80000000,00000000,00000000,00400000,00000000) ret=005d579c 0009:Call KERNEL32.LZOpenFileW(0032ee74 L"C:\GOG Games\Ultima IX - Ascension\u9.exe",0032ed64,00000000) ret=b7788b42 0009:trace:file:LZOpenFileA (C:\GOG Games\Ultima IX - Ascension\u9.exe,0x32ed64,0)
which appears to be reading the exact offset I know the cursor to be in within bitmap16.flx (file handle 0xac presumably). It also seems to request about 400,000 bytes at that offset, which also lines up with what I know about the missing cursor resource.
What it then seems to do is call LoadCursor and SetCursor which may be curious because I thought we had ruled out user32 cursors as having been used. Based on cross-compiling d3d7 and running the game on Windows XP with Wine's d3d7 however, we know the problem is not in Wine's D3D implementation, so maybe it's logical to suspect cursor after all.
However that doesn't make much sense because LoadCursor 7f00 is the standard system cursor.
But what about the GetLastError() call returning 2 (which I believe is ERROR_FILE_NOT_FOUND)? Does that seem normal right after a successful (non-zero) file read?
Here's a wild theory knowing little about this stuff: ReadFile is maybe supposed to clear out that thread's GetLastError value and u9.exe is calling GetLastError() to see if errors exist, instead of checking only after a zero return value from ReadFile like it should (it is considered a poorly written game). If Wine doesn't clear out GetLastError correctly, it could cause an alternate code path to run under Wine in which the cursors are believed not to be loaded properly.
Notably, that same file handle seems to be used correctly later on:
(0xac is bitmap16.flx)
0009:Call KERNEL32.SetFilePointer(000000ac,01e3dcc0,00000000,00000000) ret=005de4c9 0009:Ret KERNEL32.SetFilePointer() retval=01e3dcc0 ret=005de4c9 0009:Call KERNEL32.ReadFile(000000ac,0032f3f4,00000008,0032f3c4,00000000) ret=005de512 0009:trace:file:ReadFile 0xac 0x32f3f4 8 0x32f3c4 (nil) 0009:Ret KERNEL32.ReadFile() retval=00000001 ret=005de512 0009:Call KERNEL32.GetLastError() ret=005de518 0009:Ret KERNEL32.GetLastError() retval=00000000 ret=005de518
Or is that am incorrect assumption?
Any ideas?
On 03/24/2014 06:27 PM, Ken Thomases wrote:
On Mar 24, 2014, at 7:48 PM, Christopher Thielen wrote:
Using WINEDEBUG=+all, the resource in question (static/bitmap16.flx) is loaded via kernel32's CreateFile, ReadFile.
Is there a way to trace only kernel32 calls dealing with a specific file handle? I'm curious if there are any failed reads. Does that seem like a reasonable next step?
Not really. You'll want to use a +file log and follow the handle as it's passed to subsequent calls. It might also be necessary to use +tid,+relay to see all uses if Wine isn't logging the handle in all relevant functions.
Certainly, look for failed reads, but I wouldn't expect that unless you think the file is damaged vs. what's installed on Windows. More likely, the game requires external help interpreting the data that is has read, like a compression or image library. If that's not present or is incomplete in Wine, then that would explain the problem. The +tid,+relay log may help to identify what the program does next after it has read the data in.
-Ken
On Apr 22, 2014, at 7:57 PM, Christopher Thielen wrote:
Here's a wild theory knowing little about this stuff: ReadFile is maybe supposed to clear out that thread's GetLastError value and u9.exe is calling GetLastError() to see if errors exist, instead of checking only after a zero return value from ReadFile like it should (it is considered a poorly written game). If Wine doesn't clear out GetLastError correctly, it could cause an alternate code path to run under Wine in which the cursors are believed not to be loaded properly.
That's a reasonable theory given what the relay log shows. Try adding a call to SetLastError(0) near the top of ReadFile() to see if it changes the game's behavior.
-Ken
Sadly didn't help.
I discovered API Monitor for Windows so I've been comparing the two code paths as best I can. They're pretty similar between Windows XP and Wine. My theory about clearing LastError wasn't correct - Windows XP also leaves it with stale error codes.
Once the cursor data is loaded from bitmap16.flx to a heap, I never see a reference to that memory again, at least in an API trace. After various initializations, there are a lot of CreateTexture calls followed by LockRect ... UnlockRect. From reading around online, my guess is the game uploads textures using memcpy() while the rect is locked. Can anyone who knows a bit more about D3D confirm that's a probable method of uploading textures?
If that's true, I think the next logical step is trying to find when the texture resource is loaded in the Windows code path so I can start to find where Wine differs. I'm not sure how to do that short of API Monitor's "break on call and look at assembly" feature.
On 4/22/2014 5:57 PM, Christopher Thielen wrote:
Thanks Ken!
I don't think a missing library is the problem: the game stores all its texture resources in a file called bitmap16.flx and the code paths under Wine for reading those bitmaps and making textures out of them seems to work just fine given that many of them are visible in the final running game.
The offset of the cursor resource within bitmap16.flx is 0x1020eb4 and the '.flx item' (as files within this proprietary archive are called) itself is about 400,000 bytes (that's for 121 separate cursors all read at once).
Looking through +file,+tid,+relay recommended by Ken, I found:
0009:trace:file:CreateFileW L"C:\GOG Games\Ultima IX - Ascension\static\bitmap16.flx" GENERIC_READ creation 4 attributes 0x80 0009:trace:file:RtlDosPathNameToNtPathName_U (L"C:\GOG Games\Ultima IX - Ascension\static\bitmap16.flx",0x32ef74,(nil),(nil)) 0009:trace:file:RtlGetFullPathName_U (L"C:\GOG Games\Ultima IX - Ascension\static\bitmap16.flx" 520 0x32ecc4 (nil)) 0009:trace:file:wine_nt_to_unix_file_name L"\??\C:\GOG Games\Ultima IX - Ascension\static\bitmap16.flx" -> "/home/cthielen/.wine/dosdevices/c:/GOG Games/Ultima IX - Ascension/static/bitmap16.flx" 0009:trace:file:CreateFileW returning 0xac
which I believe implies bitmap16.flx is being given the file handle 0xac. Searching for '0xac' I later find:
0009:Call KERNEL32.SetFilePointer(000000ac,01020eb4,00000000,00000000) ret=005de4c9 0009:Ret KERNEL32.SetFilePointer() retval=01020eb4 ret=005de4c9 0009:Call KERNEL32.ReadFile(000000ac,02539110,00061b8c,0032edfc,00000000) ret=005de512 0009:trace:file:ReadFile 0xac 0x2539110 400268 0x32edfc (nil) 0009:Ret KERNEL32.ReadFile() retval=00000001 ret=005de512 0009:Call KERNEL32.GetLastError() ret=005de518 0009:Ret KERNEL32.GetLastError() retval=00000002 ret=005de518 0009:Call ntdll.RtlAllocateHeap(01450000,00000000,00001700) ret=00714f22 0009:Ret ntdll.RtlAllocateHeap() retval=0259aca8 ret=00714f22 0009:Call ntdll.RtlAllocateHeap(01450000,00000000,00000200) ret=00714f22 0009:Ret ntdll.RtlAllocateHeap() retval=0259c3b0 ret=00714f22 0009:Call user32.LoadCursorA(00000000,00007f00) ret=005d5743 0009:Ret user32.LoadCursorA() retval=00010038 ret=005d5743 0009:Call user32.SetCursor(00010038) ret=005dbf5f 0009:Call winex11.drv.SetCursor(00010038) ret=7eb0f777 0009:Ret winex11.drv.SetCursor() retval=00000000 ret=7eb0f777 0009:Ret user32.SetCursor() retval=00000000 ret=005dbf5f 0009:Call user32.CreateWindowExA(00000000,0032f5c0 "OFCBlackWindowClass",00787774 "Ultima IX",80030000,80000000,80000000,80000000,80000000,00000000,00000000,00400000,00000000) ret=005d579c 0009:Call KERNEL32.LZOpenFileW(0032ee74 L"C:\GOG Games\Ultima IX - Ascension\u9.exe",0032ed64,00000000) ret=b7788b42 0009:trace:file:LZOpenFileA (C:\GOG Games\Ultima IX - Ascension\u9.exe,0x32ed64,0)
which appears to be reading the exact offset I know the cursor to be in within bitmap16.flx (file handle 0xac presumably). It also seems to request about 400,000 bytes at that offset, which also lines up with what I know about the missing cursor resource.
What it then seems to do is call LoadCursor and SetCursor which may be curious because I thought we had ruled out user32 cursors as having been used. Based on cross-compiling d3d7 and running the game on Windows XP with Wine's d3d7 however, we know the problem is not in Wine's D3D implementation, so maybe it's logical to suspect cursor after all.
However that doesn't make much sense because LoadCursor 7f00 is the standard system cursor.
But what about the GetLastError() call returning 2 (which I believe is ERROR_FILE_NOT_FOUND)? Does that seem normal right after a successful (non-zero) file read?
Here's a wild theory knowing little about this stuff: ReadFile is maybe supposed to clear out that thread's GetLastError value and u9.exe is calling GetLastError() to see if errors exist, instead of checking only after a zero return value from ReadFile like it should (it is considered a poorly written game). If Wine doesn't clear out GetLastError correctly, it could cause an alternate code path to run under Wine in which the cursors are believed not to be loaded properly.
Notably, that same file handle seems to be used correctly later on:
(0xac is bitmap16.flx)
0009:Call KERNEL32.SetFilePointer(000000ac,01e3dcc0,00000000,00000000) ret=005de4c9 0009:Ret KERNEL32.SetFilePointer() retval=01e3dcc0 ret=005de4c9 0009:Call KERNEL32.ReadFile(000000ac,0032f3f4,00000008,0032f3c4,00000000) ret=005de512 0009:trace:file:ReadFile 0xac 0x32f3f4 8 0x32f3c4 (nil) 0009:Ret KERNEL32.ReadFile() retval=00000001 ret=005de512 0009:Call KERNEL32.GetLastError() ret=005de518 0009:Ret KERNEL32.GetLastError() retval=00000000 ret=005de518
Or is that am incorrect assumption?
Any ideas?
On 03/24/2014 06:27 PM, Ken Thomases wrote:
On Mar 24, 2014, at 7:48 PM, Christopher Thielen wrote:
Using WINEDEBUG=+all, the resource in question (static/bitmap16.flx) is loaded via kernel32's CreateFile, ReadFile.
Is there a way to trace only kernel32 calls dealing with a specific file handle? I'm curious if there are any failed reads. Does that seem like a reasonable next step?
Not really. You'll want to use a +file log and follow the handle as it's passed to subsequent calls. It might also be necessary to use +tid,+relay to see all uses if Wine isn't logging the handle in all relevant functions.
Certainly, look for failed reads, but I wouldn't expect that unless you think the file is damaged vs. what's installed on Windows. More likely, the game requires external help interpreting the data that is has read, like a compression or image library. If that's not present or is incomplete in Wine, then that would explain the problem. The +tid,+relay log may help to identify what the program does next after it has read the data in.
-Ken
Am 23.04.2014 um 09:15 schrieb Christopher Thielen christopher@thielen.co:
Once the cursor data is loaded from bitmap16.flx to a heap, I never see a reference to that memory again, at least in an API trace. After various initializations, there are a lot of CreateTexture calls followed by LockRect ... UnlockRect. From reading around online, my guess is the game uploads textures using memcpy() while the rect is locked. Can anyone who knows a bit more about D3D confirm that's a probable method of uploading textures?
Correct. This is a common way to load textures. There are others, but they all involve LockRect and UnlockRect at some point.
Do you know of a method to watch texture load like this? I am able to find the spot in the executable where the cursor resource is loaded into a heap (and the address of that heap in the running process), but I am unable to link it to any particular texture create call. Perhaps there's a debugger which watches for memory access at certain locations?
On 4/23/2014 1:59 AM, Stefan Dösinger wrote:
Am 23.04.2014 um 09:15 schrieb Christopher Thielen christopher@thielen.co:
Once the cursor data is loaded from bitmap16.flx to a heap, I never see a reference to that memory again, at least in an API trace. After various initializations, there are a lot of CreateTexture calls followed by LockRect ... UnlockRect. From reading around online, my guess is the game uploads textures using memcpy() while the rect is locked. Can anyone who knows a bit more about D3D confirm that's a probable method of uploading textures?
Correct. This is a common way to load textures. There are others, but they all involve LockRect and UnlockRect at some point.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
There is another easy way to test if the game is using an overlay on Windows: Take a screenshot with the print key. If the mouse pointer shows up, it is *not* an overlay. If it does not show up, it might be an overlay or a user32 mouse pointer.
Am 2014-02-16 10:06, schrieb Christopher Thielen:
No luck so far: I ran the application for about 30 seconds and generated a 975 MB log file but a case insensitive "overlay" appears not at all.
If the game looks for overlay flags it may not even call any overlay-related function if it doesn't find the flags present. And there's no way to find out at which flags it looks, short of disassembling the game code.
What you can do is looking for IDirectDraw::GetCaps calls (grep the log for ddraw7_GetCaps). If it does not call that it doesn't look at overlay capabilities and my theory is moot. If it does, you can try to add overlay capabilities and see if it starts calling IDirectDrawSurface::UpdateOverlay (look for ddraw_surface7_UpdateOverlay) and friends.
Unfortunately there's not a one-button switch to fake overlay capabilities. You may have to look at a DDCAPS structure returned from Windows and add / remove capabilities from Wine's until they look more alike. I know that I looked into Setter 3's overlay mouse pointer and it was rather tricky to figure out what the game wanted. I think it needed a proper dwMinOverlayStretch and dwMaxOverlayStretch value set, among other things.
Some hints to get you started: DDCAPS_OVERLAY, DDSCAPS_OVERLAY, dwMaxVisibleOverlays, dwMinOverlayStretch, etc.