Git Product home page Git Product logo

mochi.physx's People

Contributors

pathogendavid avatar xtqqczze avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

mochi.physx's Issues

Building PhysX as multiple DLLs or a single DLL

This issue is mostly to note my thoughts and reasoning behind how I ended up at the solution I'll eventually be pushing here.

Special compilation target for a single DLL

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:

  • It required forking the PhysX repo
  • It caused all of PhysX to be built twice (if you wanted to use the CMake INSTALL target.)
  • It didn't evolve well to meet the introduction of LinkImportsTransformation
    • To use it properly we'd have to either build all of PhysX during generation which is slow
    • In theory we could've also hard-coded the DLL to InfectedPhysX.Native.dll, but then we miss out on validation.
  • It gets kinda far away from how PhysX is normally built

Using individual DLLs like PhysX normally does

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:

  • Only some PhysX components are actually built as DLLs when PX_GENERATE_STATIC_LIBRARIES is disabled.
    • In particular the following are never built as DLLs on any platform:
      • PhysXCharacterKinematic
      • PhysXExtensions
      • PhysXPvdSDK
      • PhysXTask
      • PhysXVehicle
    • At one point I attempted to minimally modify the affected libraries to build DLLs anyway, but things broke because the CMake configurations for building them as DLLs aren't exercised.
    • Additionally, only the Windows presets have 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:

  • Modularity (only include the PhysX components you want.)
    • Great in theory, but due to how inline export helpers work you probably end up getting large chunks of the static libs anyway.)
    • Have to manually define the relationships between the various modules (not actually that bad, a quick skim suggests the all only depend on Common and/or Foundation which are required anyway.)
    • In theory the main motivation here is that the build will be smaller, right?
  • Uhhh, not much else?

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

Building PhysX as static libraries normally and then combining them into one DLL

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)

Figure out how to distribute native PDBs

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:

  • Just distribute them in the native runtime packages
    • ✔ Simple, people will get them by default
    • ❌ Bloats the packages for something many/most people will never need (They won't even get used unless they enable mixed debugging.)
    • ❌ They end up in published builds by default
  • Distribute a separate symbol package
    • ✔ Simple, people who want them can get them
    • ❌ Easy to mix incompatible versions by mistake
    • ❌ Will end up in published builds by default
  • Host our own symbol server
    • ✔ Simple, people who want them can get them and do so automatically as-needed
    • ❌ Has increased costs for MochiLibraries
    • ❌ People need to know to set up the symbol server source
    • ❌ Not sure if there's a good self-hosting option for symbol servers. (Found a few on GitHub but nothing battle-tested. It kinda sounds like it's possible to host one purely with static files though?)

Hosting our own symbol server is my personal preference, but it's really unclear how easy it would be to do.

Add transformation to handle PxClientID

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);
}

Add support for `is<T>`

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.

Ensure PxSomeFlag::Enum is passed correctly

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?

Provide NuGet package for CUDA support

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 notMochi.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.)

Port C++ snippets to C#

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.

  • SnippetArticulation
  • SnippetBVHStructure
  • SnippetContactModification
  • SnippetContactReport
  • SnippetContactReportCCD
  • SnippetConvert
  • SnippetConvexMeshCreate
  • SnippetCustomJoint
  • SnippetCustomProfiler
  • SnippetDeformableMesh
  • SnippetDelayLoadHook
    • This snippet is not relevant when using Mochi.PhysX since we build all of PhysX into a single DLL.
  • SnippetHelloGRB -- GRB stands for "GPU Rigid Bodies". IE: This is the CUDA snippet.
  • SnippetHelloWorld
  • SnippetImmediateArticulation
  • SnippetImmediateMode
  • SnippetJoint
  • SnippetLoadCollection
  • SnippetMBP
  • SnippetMultiThreading
  • SnippetNestedScene
  • SnippetPrunerSerialization
  • SnippetRaycastCCD
  • SnippetSerialization
  • SnippetSplitFetchResults
  • SnippetSplitSim
  • SnippetStepper
  • SnippetToleranceScale
  • SnippetTriangleMeshCreate
  • SnippetTriggers
  • SnippetVehicle4W
  • SnippetVehicleContactMod
  • SnippetVehicleMultiThreading
  • SnippetVehicleNoDrive
  • SnippetVehicleScale
  • SnippetVehicleTank

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.