Technical background of graphics card requirements
|
01-13-2012, 06:11 AM
Neobrain can you please explain this to him in detail? I've used up my very limited knowledge of the subject area and you know the video thread code better than anyone (except maybe tino).
"Normally if given a choice between doing something and nothing, I’d choose to do nothing. But I would do something if it helps someone else do nothing. I’d work all night if it meant nothing got done."
-Ron Swanson "I shall be a good politician, even if it kills me. Or if it kills anyone else for that matter. " -Mark Antony
(fwiw, read the two explanations on "virtual memory" and "gpu registers" at the bottom first if you have no idea what these two are)
Wine "emulates" stuff by statically recompiling (actually, it only statically relinks) program binaries. All references to Windows API functions get replaced by references to own implementations of those functions. I.e. if a program binary tries to call IDirect3DDevice9:rawIndexedPrimitive, Wine will execute the own implementation (i.e. the OpenGL wrapper) of that function. This works because the program binary doesn't actually contain the implementation of DrawIndexedPrimitive but only a reference to a DLL which contains the binary code for the implementation. Thus, Wine can easily patch the program binary to call the OpenGL wrapper instead of the DLL implementation. This is why it's often called API emulation. The advantage is that it's much easier to do: The native DrawIndexedPrimitive implementation would poke some GPU registers, fill the GPUs command processor queue, etc. Emulating the behavior of those GPU registers would be much more work with effectively no gain since the only way applications access the GPU is through Direct3D (or OpenGL) anyway. I.e. API emulation is ideally just as compatible as low-level register emulation IF applications always only use the API instead of manually accessing registers anyway. (This is greatly simplified, but I hope you get the idea) For executing Windows applications within a Linux environment, that "IF" is not much of a big deal, since there are virtually no applications which directly program the GPU. On the Wii (or console emulation in general), it's a different thing though. There's different problems which don't allow for API emulation: a) LTCG (link time code generation) often will "copy" a function implementation into the program binary instead of just putting a reference into the binary. Obviously, we can't just replace the function implementations easily now since we don't even know where a HLE'able function sits in the program binary. b) AFAICT, the Wii in particular doesn't even have any DLL-like libraries. Wii applications of course are compiled against the SDK libraries. However, they're not dynamically linked, but statically linked. This is similar to case a: There are no references to functions, but the function implementation code resides in the binary itself. It's a little different, because LTCG often has multiple (slightly different) function implementations which are optimized to the current usage. Static linkage probably will put a single code implementation "at the top" of the program binary (which also looks the same for all applications which linked against the same library). Thus, this issue could be worked around with some pattern checks and stuff. c) On top of that, game programmers often don't even only use the SDK functions to access e.g. the GPU. This breaks our big "IF" from above: If a hardware device is accessed through a different mean than a standardized API, you'll end up sacrificing compatibility if you're using API emulation. So... this was an explanation about why we can't use API emulation in Dolphin. This is one difference to Wine. There's another one as well though: Wine can't fix issues a and c at all because it doesn't emulate a CPU. LTCG is also a reason why Cxbx and Dxbx (the most advanced xbox emulators at the moment) fail at emulating some games currently, because C/Dxbx heavily rely on detecting API calls via pattern detection (similar to Wine). For Wine, LTCG isn't such a big deal for Wine since system-libraries like Direct3D aren't LTCG'ed. Anyway the problem is the following: If a program binary pokes a hardware register directly (either because of failed API function detection or because the programmers felt like programming the GPU directly), Wine can't detect that and will just fail/crash/do nothing. For Dolphin, it's a different thing. We are emulation the PPC CPU. Whenever the CPU tries to write to a certain virtual memory address*, we can check if that memory address corresponds to the GPU register set and properly emulate the GPU functionality on the register level that way. *virtual memory: One would think that the memory which is writable by the CPU is only the RAM memory; however, it can also write to other stuff like e.g. GPU registers. All of these things are mapped to a continuous memory map called "virtual memory". Whenever the CPU tries to read from / write to the virtual memory, the MMU (memory management unit) will resolve the virtual memory address and redirect the access to the proper destination. *GPU register (or hardware registers in general): hardware devices can expose their capabilities/configuration/etc by reserving a certain range of virtual memory. The CPU then can write to that memory range and directly program the device that way. In case of a GPU, some of the exposed features could be the command queue, some render states, etc. Each byte of the GPU registers has a certain function, e.g. if the CPU writes to the byte at a certain offset, it can tell the GPU to enable lighting in the next render call. Telling the GPU to start rendering stuff would be another register. Flipping the back buffer another one. .... So much about the difference between Wine and Dolphin. I'll maybe elaborate a bit on the actual causes of slow GPU emulation in Dolphin in another post at a later point. 01-15-2012, 05:54 AM
(01-15-2012, 03:14 AM)neobrain Wrote: b) AFAICT, the Wii in particular doesn't even have any DLL-like libraries. Aren't IOS's DLL-like? Or are they more like drivers?
Main Laptop:
Dell XPS 17 i7 2720QM @ 2.2GHz 8GB DDR3 RAM Nvidia GeForce GT 555M Windows 7 64-bit
IOS =Input-Output-Systems
They are very little "operating systems" which run in the coprocessor Starlet. Each IOS has a different function, e.g. IOS36 is necessary to play Super Smash Bros Brawl. for the interested guys: http://wiibrew.org/wiki/IOS 01-15-2012, 06:40 AM
I don't know the details, but we're HLEing the IOS part of the Wii. It's comparable to API emulation in the way that we're emulating the IOCtls of device interfaces, but it's much more low-level since we have to emulate the Broadway<->Starlet communication as well.
01-15-2012, 07:37 AM
Hey neobrain,
thank you very much for your explanations! A few questions, if you don't mind: Is LTCG the same as static linking? Or is there a slight difference? Does wine really have problems with statically linked programs? I never heard about that. Or do they have a good solution for this problem? Also, for writing to the registers directly -- is this a problem for wine? It's not emulating another architecture, so if it just passes the operation through, it'll likely succeed, won't it? It's clear that it doesn't work for dolphin, but isn't this because the registers of the Wii / GC CPU / GPU are very different from those of the x86 (or whatever) architecture? I'm very curious for the further explanations you said you'd write Greetings 01-15-2012, 08:15 AM
LTCG is not the same as static linking. With dynamic linkage, when an application tries to use (for example) a system function, it will just put a reference (to the dll address where the function is implemented) at the place the function is supposed to be called. With static linkage, it will still put a reference to that function, but the difference is that the function implementation is stored in the program binary itself - i.e. when the CPU hits the function reference it will jump from the current executed instruction to the function implementation. The difference from the emulation difficulty is that with dynamic linkage, the reference will look like "call d3d9.dllrawIndexedPrimitive" which will get resolved to some address where the binary is located, whereas with static linkage the reference looks like "call 0xabc34250" since it's obvious that the address is referring to the program binary. Because of that, we can easily detect which function calls to patch when those functions are dynamically linked. Calls to statically linked functions can't be patched easily because they look like any other function calls. With some fancy pattern detection we could still find out where the linked functions are and patch them anyway though, since statically linked function always have the same binary code.
I don't know the exact details of LTCG, but afaict it's like static linkage, but: Instead of referencing a linked function, the whole function implementation will be copied to the program code whenever it gets used. The advantage (from a game programmer's perspective, anyway) of this is that the function will be optimized for each use case that way. The disadvantage is that we can't patch linked functions which are link time code generation optimized because they'll have a different binary code in many cases. Wine would fail horribly at LTCG-optimized functions. It would even fail at statically linked functions. However, Wine's advantage is that system functions never get statically linked (and thus can't be LTCG-optimized anyway). "System functions" can be kernel functions, user32/GDI (core OS functions and GUI functions), Direct3D, etc. They don't get statically linked because Microsoft doesn't provide any static libraries for them, for good reasons (static linking prevents security holes to be fixed without recompiling an application, etc). Higher level libraries occasionally get statically linked, but that usually doesn't cause trouble since just executing the native code works just as fine (or just as bad) like executing the program binary itself. However, I remember DirectDraw being open-sourced and some companies statically linking against it. This caused some problems IIRC, but apparently they somehow resolved them (probably by more properly emulating whatever lower-level library is used by DDraw itself).
Wine likely also fails horribly at writing registers directly - in fact, I don't think writing to hardware registers is even allowed from user-space. Probably the register mapping doesn't even match between Windows and Linux. I don't really know how that stuff works in detail on PC hardware though. There's no way for Wine to emulate that stuff though, that's for sure, because it doesn't emulate a Memory Management Unit.
EDIT: http://en.wikipedia.org/wiki/Memory-mapped_I/O maybe gives a more solid idea of what those "registers" I'm talking about are.
Ah, okay. So LTCG is like the "inline" in C++, you trade program size for execution speed (well, except that it's performed by the linker and not the compiler, obviously).
It also makes sense to me that writing to certain registers is only allowed in kernel mode. The fact that wine fails to run even the simplest drivers (like USB drivers or stuff) supports your statement. However, this restriction probably only applies to the non-memory part of the address space, doesn't it? I must be able to write into the accumulator for my processor from user mode for sure. And yeah, as you said, if the OS maps the registers to the address space, it's indeed unlikely that this mapping will match between different operating systems... so wine will probably fail here, too. Cheers |
« Next Oldest | Next Newest »
|
Users browsing this thread: 1 Guest(s)