mochilibraries / mochi.physx Goto Github PK
View Code? Open in Web Editor NEWAutomatically generated C# bindings for NVIDIA PhysX
License: MIT License
Automatically generated C# bindings for NVIDIA PhysX
License: MIT License
This issue is mostly to note my thoughts and reasoning behind how I ended up at the solution I'll eventually be pushing here.
This is what the original prototype used. It worked by adding a special CMake target to PhysX its self which used CMake shenanigans to combine the various parts of PhysX into a single DLL. This modified InfectedPhysX.Native.dll
also included the equivalent of the inline export helpers at the time.
This approach had some major downsides:
INSTALL
target.)LinkImportsTransformation
InfectedPhysX.Native.dll
, but then we miss out on validation.This feels the most natural and requires 0 modification to the PhysX repo. However it has a major downside of not handling the static components of PhysX very well:
PX_GENERATE_STATIC_LIBRARIES
is disabled.
PX_GENERATE_STATIC_LIBRARIES
disabled by default.I worked around the static library issue on Windows by generating linker response files along these lines:
/NOLOGO
/IGNORE:4001
/IGNORE:4102
/MACHINE:X64
/DLL
/DEBUG
"..\path\to\PhysXExtensions_static_64.lib"
/LIBPATH:"C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.30.30704\lib\x64\"
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.20348.0\ucrt\x64\"
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.20348.0\um\x64\"
/DEFAULTLIB:libcmt.lib
"..\path\to\other\PhysXComponent1_64.lib"
"..\path\to\other\PhysXComponent2_64.lib"
"..\path\to\other\PhysXComponentETC_64.lib"
/OUT:"PhysXExtensions_64.dll"
/EXPORT:symbol_needing_export_from_lib1
/EXPORT:symbol_needing_export_from_lib2
/EXPORT:symbol_needing_export_from_libETC
I also experimented with doing something similar (and much simpler) on Linux:
clang -shared -L. -Wl,--whole-archive -lPhysX_static_64 -o libPhysX_64.so -Wl,--no-whole-archive
However, either way you cut it both of these are adding quite a bit of complexity. (Particularly with the Windows version since in the above form it needs paths to a bunch of system junk.)
There's also the question of whether or not unintentional static non-sharing is occurring like we had with libclang. This isn't really easy to validate and could easily be happening between the inline export helper and the converted static libraries since the inline export helper is going to end up linking in its own copy of the static libraries it depends on. There may be nothing like this (there honestly probably isn't), but it's a HUGE pain when it pops up.
In theory we could gain some peace of mind here by converting each static library into a DLL along with its corresponding inline export helpers but that's even more added complexity and would require we either build the inline export helpers directly in-generator, have the generator emit individual CMake project, or hard-code individual CMake projects for the individual static libraries within PhysX (and have to keep up if they ever add news ones -- which is probably rare but still a pain.)
Finally, we really need to look at what this gains us:
Common
and/or Foundation
which are required anyway.)This would also mean we need to split up the C# bindings into multiple assemblies. Not that difficult, but this runs into the same issues mentioned earlier relating to multiple CMake projects for each static library. (Although emitting a small C# file isn't very hard.)
Let's look at that main motivation: Making the build smaller through modularity.
Here's the sizes of the individual PhysX modules on Windows: (All DLLs below are the checked builds.)
Size | File |
---|---|
310K | InfectedPhysX.Native.dll |
842K | PhysXCharacterKinematic_64.dll |
1.5M | PhysXCommon_64.dll |
393K | PhysXCooking_64.dll |
2.1M | PhysXExtensions_64.dll |
267K | PhysXFoundation_64.dll |
893K | PhysXPvdSDK_64.dll |
627K | PhysXTask_64.dll |
1.4M | PhysXVehicle_64.dll |
2.2M | PhysX_64.dll |
10.2M | Total |
4.14M | Minimum |
(Minimum includes InfectedPhysX.Native.dll
, PhysX_64.dll
, PhysXCommon_64.dll
, and PhysXFoundation_64.dll
since they are all absolutely mandatory.)
I wanted to test the size a runtime where everything is combined* and it came out to...5.96 MB. So you'd be saving a whopping 1.82 MB if you went with the bare minimum PhysX distribution, and you'd actually be paying more if you included each module separately. Furthermore I suspect most of this is probably from PVD which isn't even present in release builds. (Well, that's what the documentation says, I built in release and still got a PVD lib.)
(*To make this runtime, I created a PhysX build preset which built Win64 as static libraries, used Biohazrd to make a list of /EXPORT
directives for all symbols in all of those static libraires, and them built the inline export helper with those directives and linked it to the static libraries.)
This is sort-of a hybrid of the above two options. We'll build PhysX with PX_GENERATE_STATIC_LIBRARIES
enabled and combine the individual static libraries and the inline export helper into a single DLL using generated export directives (or maybe a def
file -- and the equivalent on Linux.)
If it isn't obvious by now, this is the option I want to go with. IMO it's the right tradeoff between complexity and keeping our build similar to C++. It also probably gives a more natural progression towards static linking in NativeAOT scenarios. It also keeps the way we consume PhysX consistent between different platforms.
The downside of this is needing to get our presets into PhysX. I think we'll just provide a script that copies them into PhysX automagically. (Making our own preset isn't even considered non-standard, Nvidia specifically documents it as something you can do: https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/BuildingWithPhysX.html#customize-cmake-presets)
Because snupkg only works with portable PDBs (which are .NET-specific), we cannot use the NuGet symbol server for Mochi.PhysX.Native
. As such we need to figure out our own way to distribute them.
We should also look into setting up source link for them:
Possible solutions:
Hosting our own symbol server is my personal preference, but it's really unclear how easy it would be to do.
PxClientID
is a typedef used for IDs assigned by PxScene
. Right now I'm pretty sure that they don't get translated at all (or maybe they're completely untyped.)
We should transform the PxClientID
typedef from this:
typedef PxU8 PxClientID;
static const PxClientID PX_DEFAULT_CLIENT = 0;
static const PxClientID PX_MAX_CLIENTS = 128;
Into something like this:
struct PxClientID
{
public readonly ubyte Id;
private PxClientId(ubyte id)
=> Id = id;
//TODO: Operators?
public static readonly PxClientID Default = new PxClientID(0);
public static readonly PxClientID MaxValue = new PxClientId(128);
}
I had this delightfully vague sentence in the notes from the original prototype:
PxFlags doesn't seem to be translating in the context of function pointers.
It's unclear whether or not this issue was resolved. We should double-check that it was.
PxBase
has a template method named is<T>
which can be used to identify the subtype of a PxBase
object at runtime. It's not super commonly used, but it does come up every once and a while. It is currently untranslated because it's a template method.
Generally you can get a similar check using getConcreteType
, but that only works if you know the specific type you're looking for. It does not work well when you want the ability to identify collection of types. (IE: PxRigidActor
, which has multiple concrete variants PxRigidStatic
, PxRigidDynamic
, and PxAtriculationLink
.) Doing a check similar to this requires using isKindOf
, which is currently not translated as it is protected.
In theory we could use Biohazrd's template specialization to generate many is_Blah
implementations, but I don't think that's a user-friendly approach here. We should instead implement our own variant of it using C# generics.
This also means we need to implement an equivalent of PxTypeInfo
(also currently untranslated.) The C++ approach does not make sense for C# here. We should instead either A) use the default(T)
+property trick we used in Mochi.DirectX for interface IIDs or B) use static abstract interfaces.
A is in theory slightly worse for performance, but B requires the use of preview features prior to .NET 7.
PxFlags
are translated as [Flags]
-style C# enums. This works perfectly for the most part, but there are some places in PhysX where the underlying enum type is referenced directly. (IE: Referring to PxSomeFlag::Enum
instead of the PxFlags<PxSomeFlag::Enum, PxU8>
type.)
This could be problematic when sizeof(PxFlags<PxSomeFlag::Enum, PxU8>) != sizeof(PxSomeFlag::Enum)
(which is generally always when the second template argument isn't 32 bits.) In theory the enum values will always just go into a register anyway, but I need to double check this doesn't cause subtle issues.
It may be easier to just leave this issue to MochiLibraries/Biohazrd#32 since it probably depends on the target platform (and maybe even the target compiler.)
Can [MarshalAs]
be used to coerce the enum in these scenarios?
CUDA support in PhysX is closed-source and requires redistributing a pair of additional DLLs. PhysXDevice64.dll
and PhysXGpu_64.dll
For Linux there is just a single libPhysXGpu_64.so
.
These DLLs are fairly huge, even bigger than PhysX its self, so I don't think it makes sense to include them in the Mochi.PhysX.Native
packages since not everyone will want or need them.
For whatever reason, these DLLs are not copied to the install
folder. So we need to dig them out of the bin
directory ourselves.
Additionally, for Windows PhysXGpu_64.dll
is only present in the win.x86_64.vc140.mt
folder. For other versions of MSVC it is copied from there. The PhysXDevice64.dll
is present in all folders, although it's just the same file copied over and over.
It is worth noting that none of these files are the same between build variants. I accidentally loaded the release
GPU DLL with a checked
build and it crashed, so it's important we match variants.
As such I think we should extend MochiPhysX.SelectRuntimeVariant
to call PxSetPhysXGpuLoadHook
as appropriate on the user's behalf. It might also be wise to force it to an invalid value in the event the DLL is missing in order to prevent a crash in the scenario where the developer has a Mochi.PhysX.Native.win-x64-checked
and ``Mochi.PhysX.NativeGpu.win-x64installed but not
Mochi.PhysX.NativeGpu.win-x64.checked`. (PhysX gracefully handles the DLL missing, presumably running as if GPU support wasn't enabled. The structure of `SnippetHelloGRB` somewhat implies this is partially the consumer's responsibility, but in practice it doesn't actually seem to work that way.)
It isn't supported to mix different versions of the various Mochi.PhysX NuGet packages, but NuGet won't enforce this for the optional packages (such as the checked variant of the runtime.)
We should enforce this at compile time using a method similar to the one used for ClangSharp.Pathogen.
We might consider also doing something similar at runtime via #6.
The PhysX SDK contains a good number of small mostly-self-contained examples called snippets. These snippets are quite useful for understanding how to interact with PhysX and it'd be helpful to port them to C# both to test Mochi.PhysX as well as serve as an example of how things might be different between C++ and C#.
It is a non-goal to make these snippets C#-friendly. They should stay as close to the C++ snippets as possible in order to make it easier to compare and contrast them.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.