[Bug 47974] X Rebirth - wined3d GL_INVALID_OPERATION dimensions must be identical with current filtering modes

WineHQ Bugzilla wine-bugs at winehq.org
Wed Oct 23 09:39:41 CDT 2019


https://bugs.winehq.org/show_bug.cgi?id=47974

Paul Gofman <gofmanp at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |gofmanp at gmail.com

--- Comment #2 from Paul Gofman <gofmanp at gmail.com> ---
Created attachment 65500
  --> https://bugs.winehq.org/attachment.cgi?id=65500
hack

I tested the game (GOG version, installed through GOG Galaxy).

I spotted and had to workaround 3 issues to make the game run, and will
describe each one here, while the bug probably needs splitting. I suggest to
make this bug about virtual memory issue 2 described below and split off d3dx
issues 1, 3 into separate bugs (as those are easier and have a workaround
without custom patches). The issue with GL_INVALID_OPERATION (which is
currently in bug title) is the forth one and probably worth attention, but
seems not to affect the game: I did not notice any glitches after working
around the other 3 (tested the start and beginning of the campaign).

1. d3dx9: D3DXCreateCubeTextureFromFileInMemoryEx() fails to create a cube
texture. This is because requested usage is D3DUSAGE_RENDERTARGET with default
pool. The implementation of the function decides to change the pool to sysmem
due to the side reasons, and the texture creation fails which is fatal for the
game start. The function is likely have to mind the render target usage flag,
doing so in code seem to fix the issue though I did not yet make the unit test.
The easiest workaround for now is to use native d3dx9_43 ('winetricks
d3dx9_43').

2. After working around p. 1., the game displays some intro movie (can be
skipped), and then crashes. The game processes the crashes, so it does not
display Wine crash dialog but tries to send crash report instead; it displays
the message box complaining about missing INI file. This is accompanied by the
following output from game (there are a lot of them for different lua files):

======================================
Error while loading the Lua file: 'ui/addons/ego_movie/movie.lua' for addon
'ego_movie': 'not enough memory'
======================================

    This is due to the failures to allocate memory with
NtAllocateVirtualMemory():
---
00a7:Call
ntdll.NtAllocateVirtualMemory(ffffffffffffffff,7f4d8e4ceeb8,00000001,7f4d8e4ceec0,00003000,7f4d00000004)
ret=00f5fc25
00a7:trace:virtual:NtAllocateVirtualMemory 0xffffffffffffffff (nil) 00020000
3000 00000004
00a7:Ret  ntdll.NtAllocateVirtualMemory() retval=c0000017 ret=00f5fc25
00a7:Call KERNEL32.RaiseException(e24c4a04,00000001,00000000,00000000)
ret=00f88bce
---

    This is called from lua51_64.dll.
    This would look like a not so unusual VM exhaustion issue, but the game
executable is 64bit.
    Please mind zero_bits parameter for NtAllocateVirtualMemory set to 1. The
proper support for such zero_bits parameter was added lately by commit
8a765533d6e19b0b8d51bf1ef7f316d79f9bb968. Without that (or forcefully setting
zero_bits to 0) result in successful memory allocation of course, but no
surprise the game crashes soon after as it really expects the returned address
to fit in 31 bits. The first few same calls to NtAllocateVirtualMemory (same
parameters, same return address) succeed, but then it reports out of memory
status. Now it may look like we face VM exhaustion in the lower 31 bit, yet my
further analysis show that it is not exactly the case.

    map_view() (dlls/ntdll/virtual.c) tries to get memory range for non-zero
zero_bits parameter in two ways. First it searches for the available memory in
reserved areas. All the successful allocations mentioned above hit this path.
When there is no memory in reserved areas, it tries to get the correct address
with find_free_area(), but this seem to always fail, regardless of actual
memory range availability. NULL start address is passed to find_free_area(),
without MEM_TOP_DOWN flag. This seem to always fail the search due to this
condition in find_free_area() (currently at line 537): 'if (!start || start >=
end || (char *)end - (char *)start < size) return NULL;'. 'start' is going to
be non NULL here only if we have a view with NULL start address in the tree,
but we don't have that, so the search always fails. If we pass
'address_space_start' instead of NULL as base address for find_free_area(), the
search succeeds, and in my tests all the allocations start to succeed. Sadly,
it is not the end of story, as after find_free_area() succeeds here we hit the
next, harder, problem.

    Now, when we get memory found through find_free_area(), after certain
moment each call to OpenGL causes invalid memory access inside host opengl
library. This is likely caused by corruption of the memory areas which native
GL library previously allocated using native mmap(). It looks like it has
something to do with this code in map_view(): 'if ((ptr = wine_anon_mmap( ptr,
view_size, VIRTUAL_GetUnixProt(vprot), ptr ? MAP_FIXED : 0 )) == (void
*)-1)...'. ptr is not NULL only for nonzero 'zero_bits', and given the
find_free_area() never succeeded before the change I described in the previous
paragraph, MAP_FIXED was never actually used here before. The problem seem to
be related to the change in MAP_FIXED behaviour starting from Linux 4.17. Now
MAP_FIXED does not mind previously mapped areas at the requested location, and
clobbers preexisting map range. Starting from Linux 4.17, we are supposed to
use MAP_FIXED_NOREPLACE here to do what we want. When I change MAP_FIXED to
MAP_FIXED_NOREPLACE here, I am starting to get EEXIST error, which contributes
to the guess about GL driver memory corruption. Yet just changing the flag does
not solve the allocation issues, as we merely end up being where we started: we
still get no memory while actually free areas in the desired range do exist.
    I am attaching a proof of concent hacky patch which works around the issue
and lets me to run the game flawlessly. Yet the patch is nowhere close to even
a good workaround yet, as it doesn't care about a load of things, like the
correct size of created view, or some mechanism to get the virtual space back
if native library unmaps the range. Not mentioning that we need to guess kernel
type and version to choose the correct flag; this patch is for Linux kernels
4.17+. The other versions might not need the new flag, but still need to care
about marking the VM area as busy and retrying the allocation.
    The other simplier hack which also lets the game work is like this:

--- a/loader/preloader.c
+++ b/loader/preloader.c
@@ -118,7 +118,7 @@ static struct wine_preload_info preload_info[] =
     { (void *)0x7f000000, 0x03000000 },  /* top-down allocations + shared heap
+ virtual heap */
 #else
     { (void *)0x000000010000, 0x00100000 },  /* DOS area */
-    { (void *)0x000000110000, 0x67ef0000 },  /* low memory area */
+    { (void *)0x000000110000, 0x77ef0000 },  /* low memory area */
     { (void *)0x00007ff00000, 0x000f0000 },  /* shared user data */
     { (void *)0x7ffffe000000, 0x01ff0000 },  /* top-down allocations + virtual
heap */
 #endif

3. d3dx9: The function is using parameter blocks for setting effect parameters
which is currently not implemented. This is the first game I encounter which
uses this functionality. It does not prevent the game from starting (while of
course it has severe graphical glitches). The workaround for now is the same as
in p. 1.

-- 
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