CoolGamer wrote on 2020-02-04, 18:31:
danoon wrote on 2020-02-04, 03:48:
Vulkan is on my radar, I think sometime this year I will see what it will take to do passthrough with it. OpenGL passthrough in Boxedwine was a pretty big effort.
Is it possible to implement the DirectX passthrough that I mentioned in my post after you are done with Vulkan? Why is the passthrough a big effort? As far as I understand, Boxedwine acts like a "virtual machine/sandbox". Can you just do a quick & dirty implementation where you allow the directx game to directly access ddraw.dll of the Windows host, bypassing the supervision of the sandbox?
I want to clarify that the DirectX passthrough that I requested should be optional, in case some people want to use the DirectX to OpenGL/Vulkan conversion offered by the Wine project. Some games might benefit from the DirectX passthrough, while the others might work better with Wine's internal Directx to OpenGL conversion wrapper.
Virtual machines are pretty complicated. And the complicated part isn't even the CPU emulation, its the memory. In a real machine each 32-bit process can control its own 4GB address space. With Windows all older exe's load into the same address at 0x400000. To do this, real machines have MMUs (Memory Management Unit). This will map the address in a process to physical memory. In a VM I have to implement the MMU and map the emulated memory to host memory. To make it more confusing, the MMU operates on chunks of 4096 bytes of memory called pages. So page 1 at 0x400000 could map to one host memory location and page 2 at 0x401000 could map to a completely unrelated part of memory on the host that is not next to page one.
So when a game wants to upload a texture to the video card it will pass a pointer (location to memory) to DirectX/OpenGL. If that texture doesn't fit in a single page (this is most likely), then that means it will span multiple pages, so I can't just give the page 1 memory location the emulator is mapped into to the host DirectX/OpenGL. I have to allocation new memory, copy the texture into it, then give that memory to the host API. This is called marshaling data and I have to do the same thing when the game calls an API that will fill in a pointer (the other direction compared to uploading a texture). Now imagine the API passes a structure and in that structure there are multiple pointers, everything needs to get marshaled.
To do this marshaling, I created my own library, libGL, that runs in my Linux VM, this will forward every possible OpenGL call (I've done about 1400 so far). Then in BoxedWine, I have to write code that libGL can communicate to, which is another 1400 functions. Each one of these functions I have to understand how the data needs to be marshaled. Sometimes in OpenGL it will pass a pointer and I don't know how to calculate the size of memory it uses, sometimes I just guess.
It probably took me 3 months of work to get OpenGL pass through to work. This time was because of the number of APIs and figuring out how to marshal the more complicated APIs. And even now I know some of the APIs are not correct.
Because of DirectX to OpenGL translation that Wine performs and my own marshaling of OpenGL calls, there is some overhead when it comes to performance, but for older games this seems to more than fine. At first I focused on late 90s direct draw games for Boxedwine, but now I'm starting to test more recent Direct3D 9 games and I haven't noticed OpenGL performance problems, I'm limited by my CPU emulation speed.