Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What Do We Need To Autogenerate Javascript Bindings? #25

Closed
zicklag opened this issue Jan 26, 2019 · 30 comments
Closed

What Do We Need To Autogenerate Javascript Bindings? #25

zicklag opened this issue Jan 26, 2019 · 30 comments

Comments

@zicklag
Copy link

zicklag commented Jan 26, 2019

I was looking around because I needed some extra bindings that I found were not in Bt.hx but were in the WebIDL and I found that the Javascript bindings were not generated automatically yet.

// These will be eventually auto-generated, similar to the above

If it is worth your time to explain, I might be able to do the work to get that done. Before I started on anything I just wanted to make sure you haven't already figured out what we need to do. If it isn't worth the time right now, no problem, I don't care either way, I'll just add the extra bindings that I need to Bt.hx for now.

@luboslenco
Copy link
Member

luboslenco commented Jan 27, 2019

Help on this would be amazing! The macro at:

typedef Bt = haxe.macro.MacroType<[webidl.Module.build({ idlFile : "Sources/bullet/bullet.idl", chopPrefix : "bt", autoGC : false, nativeLib : "bullet" })]>;

is also supposed to work for JS.

  • We should probably compile our own "ammo.js" using webidl and emscripten, so the generated bindings match.
  • Calling the webidl.Module.build macro above every time seemed to prolong the build times. Perhaps it would be better to somehow output the generated bindings into .hx file and reuse that.

Still a novice on this myself but was amazed how it worked so far. We can basically drop-in any C/C++ lib just by writing the .idl file.

@zicklag
Copy link
Author

zicklag commented Jan 27, 2019

OK awesome. If I get the time, I'll look into it. 👍

@zicklag
Copy link
Author

zicklag commented Jan 30, 2019

I just got a custom Emscripten build of bullet using the Haxe Webidl library. It looks like it works! I've already been able to get a Haxe extern file from it so that we should be able to cache the externs and avoid generating them every build. Using the WebIDL gives exactly the same bindings for JS and HL which is awesome and takes out all of the #if js #else #end stuff from PhysicsWorld and friends.

Now I'm going to try to integrate the binder into Khamake/Koremake so that you can use it for any Kha project just by adding a WebIDL file and some statements to your Khamake.js file. 🎉 This is going to be so awesome if it works.

@luboslenco
Copy link
Member

😍😍😍

@zicklag
Copy link
Author

zicklag commented Feb 2, 2019

I've now got Khamake building the bindings for you automatically. The next step is getting Kha to load the compiled JavaScript for the Krom and web platforms so that you don't have to manually include and eval ammo.js or anything like that. Things are going really well so far so hopefully I will be able to finish this pretty soon.

The way that it is setup is that you just have a library ( for example haxebullet ) that includes your C++ sources, a WebIDL file, and a khabind.json file ( the name may change, but that's what I went with for now ).

To use it, all you have to do is add the library to your Kha project like you normally would by adding a project.addLibrary("haxebullet"); line to the khafile.js for your project. When you run Khamake, it will automatically generate the Haxe bindings in the Sources directory, builds the C++ library to JavaScript using Emscripten, and creates a korefile.js for the library. If the sources are already built, it won't recompile them and if some of the sources are changed, it will recompile only the changed files, just like make. Eventually it will also bundle the JavaScript version of the library into the generated code so that it is completely hands off.

I've still got some cleanup and slight reorganization to do, but it is going really well so far.

Also, for reference, here is what my khabind.json file looks like at the moment. It will change a little bit, but it gets the idea across.

{
    "idlFile": "bullet.idl",
    "nativeLib": "bullet",
    "sourcesDir": "bullet",
    "chopPrefix": "bt",
    "hxPackageName": "bullet",
    "hxModuleName": "Bt",
    "autoGC": false,
    "includes": [
        "<btBulletDynamicsCommon.h>",
        "<BulletSoftBody/btSoftBody.h>",
        "<BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h>",
        "<BulletSoftBody/btDefaultSoftBodySolver.h>",
        "<BulletSoftBody/btSoftBodyHelpers.h>",
        "<BulletSoftBody/btSoftRigidDynamicsWorld.h>",
        "<BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>",
        "<BulletCollision/CollisionDispatch/btGhostObject.h>",
        "<BulletDynamics/Character/btKinematicCharacterController.h>",
        "<BulletCollision/Gimpact/btGImpactShape.h>",
        "<BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h>"
    ]
}

@zicklag
Copy link
Author

zicklag commented Feb 3, 2019

It works!!! Last night I got an end to end build that successfully utilized the entire workflow! I've still got a little bit of cleanup and slight re-organization, but I should be done today or tomorrow! I'll have PRs for Kha, Khamake, haxebullet, and Armory.

@luboslenco
Copy link
Member

Sounds awesome, can't wait!

@zicklag
Copy link
Author

zicklag commented Feb 8, 2019

I ran into some issues, but I'm getting close to finishing. I have gotten most of it working, but then ran into an issue when enabling MODULARIZE for the Emscripten build. I'm also not 100% sure I've figured out how to make sure that JS libs are loaded before the game starts.

Right now I'm working on figuring out if there is an alternative to using eval() to load the JS lib. Maybe Function, which is supposed to be a better alternative to eval.

@zicklag
Copy link
Author

zicklag commented Feb 11, 2019

@luboslenco and @RobDangerous I've opened the following PRs for the automatic WebIDL binding system for Kha projects and for Armory's Bullet bindings:

There is kind of a lot changes throughout those repos so tell me if I missed anything. I can give more description of how it works later, but I figured I'd submit these for review.

It is looking really cool. I'm so excited about this update! 😃 🎊

@zicklag
Copy link
Author

zicklag commented Feb 11, 2019

I created a Gist that documents how to use the new "Khabind" feature: Khabind: Binding C++ Libraries To Kha For JS/HashLink.

@zicklag
Copy link
Author

zicklag commented Feb 11, 2019

Review Note

Emscripten Bytecode in Haxebullet Repo

I included the bytecode generated by Emscripten in the PR for Haxebullet because the way that I setup the compiler cache in Khamake was that it will compile any C/C++ source file that doesn't have a corresponding bytecode file with a newer timestamp. Technically I could add some more logic to the compiler cache so that it would not compile any sources if there is already the generated JavaScript library that has a newer timestamp than all of the source files. It would just add slightly more complication to the build logic so if you don't think it is a problem I will just leave it, otherwise I have no problem making it a little smarter.

Error with heap memory

I'm getting an error every once in a while when a physics world runs for too long:

TypeError: Object expected
   at abort (krom.js:25:106134)
   at abortOnCannotGrowMemory (krom.js:8:10625)
   at _emscripten_resize_heap (krom.js:8:49209)
   at updateContacts (krom.js:3185:5)
   at lateUpdate (krom.js:3157:3)
   at iron_App.update (krom.js:7608:3)
   at Anonymous function (krom.js:26554:3)
   at kha_Scheduler.executeTimeTasks (krom.js:26438:4)
   at kha_Scheduler.executeFrame (krom.js:26390:3)
   at kha_SystemImpl.renderCallback (krom.js:27165:2)

It helped when I increased the TOTAL_MEMORY to the size that the Ammo.js project uses, but it still happens, just less often. It looks like you can set the heap memory to be growable without performance consequences for WASM, but I haven't gotten Emscripten WASM builds to work in Krom ( I don't know why, it just crashes ). It would be best if we could figure out how to run the WASM build in Krom.

@luboslenco
Copy link
Member

Thanks, this is big! Will have fun this weekend. 🙂 (+ doing a proper haxerecast upgrade is also easier now!)

@zicklag
Copy link
Author

zicklag commented Feb 15, 2019

Awesome. I can't wait to get some feedback on my code! :)

Also, I did manage to figure out what was causing it to run out of memory. The WebIDL binder that comes with Emscripten that is used to create Ammo.js does some sort of wrapping for the C++ pointers that can garbage collect them automatically ( for classes that don't require a destructor ). The bindings that we are generating with our WebIDL binder, though, doesn't do any garbage collecting for you. This left a memory leak in PhysicsWorld.updateContacts(). I fixed that one, but there might be some more laying around in the different physics classes.

It looks like ncannasse/webidl does have the auto garbage collector option that should work for HashLink, which is good. It is up to you whether or not we want to use it for Bullet in Armory, but I'm also going to do my best to figure out if I can use the trick that the Emscripten WebIDL binder used to get JavaScript to garbage collect it like Ammo.js did.

@zicklag
Copy link
Author

zicklag commented Feb 21, 2019

Linking: ncannasse/webidl#15.

@luboslenco
Copy link
Member

Getting more familiar with it! Is it a bad idea to have khabind.json contained directly in khafile.js library file as a 'regular' command?

@zicklag
Copy link
Author

zicklag commented Feb 23, 2019

The reason I had it in its own file was because khafile.js files are only processed by Khamake when you include a sub-project, and not when you just include a library like haxebullet. korefile.js would be another option, but that's not quite right either because those are only processed during Kore builds.

I didn't see a reason to mess too much with how Khamake processes the files when all I needed was some static parameters for the library.

@RobDangerous
Copy link
Contributor

"sub-projects" are merely more powerful libraries and I think I can persuade Lubos to add a khafile to haxebullet.

@zicklag
Copy link
Author

zicklag commented Feb 23, 2019

In that case it should be perfectly fine. It would probably be good to make the handling less 'special' so to speak.

@zicklag
Copy link
Author

zicklag commented Feb 26, 2019

@RobDangerous Does it make any sense to have Khamake automatically add a project if you are adding a library with a khafile.js in it? It seems like it would be nice just to be able to drop haxebullet in your Libraries folder to include it in a Kha project.

@RobDangerous
Copy link
Contributor

No, the big difference is that loading a project is async because khafiles require that.

@zicklag
Copy link
Author

zicklag commented Feb 26, 2019

Just pushed updates to all of the repos to use khafile.js instead of khabind.json.

@zicklag
Copy link
Author

zicklag commented Feb 28, 2019

It looks like there actually isn't a way to get JavaScript to auto GC the references. 🙁 ( see emscripten-core/emscripten#8206 (comment) ) I don't know why we didn't see the out of memory exceptions with the Ammo.js version that we used to use, though. 🤔 I'm not sure if it had the heap set to growable or if it was something else, but either way it looks like we will just have to fix the memory leaks. I fixed the major ones, but there is still at least another minor one, because I had it running for an extended time period earlier and it ran out of memory again.

@luboslenco
Copy link
Member

Growable heap should be disabled in current ammo.js build, so I guess the current one should also crash eventually? How long is extended time period? 🕐 Do all physics enabled scenes run into this? Will try to reproduce.

@zicklag
Copy link
Author

zicklag commented Feb 28, 2019

At first it would crash within a few minutes before I pushed, armory3d/armory@d43d9c4. After that the only time I've noticed a crash was with a basic rigid body sim that I had accidentally let run for a couple hours or so. Still if the Ammo.js build doesn't have a growable heap, then I can't immagine what is making it not crash if there is no way to auto GC memory. Maybe we should test reverting armory3d/armory@d43d9c4 to make the effect more apparent and then compare Ammo.js and our custom build. Maybe my Khabind script isn't correctly setting the heap size or something like that. This is kind of strange. 🤔 ❓

@zicklag
Copy link
Author

zicklag commented Feb 28, 2019

Here is an example that crashes really quick. It lasts less than a minute. ( 400+ spheres )
ball-example.zip

@zicklag
Copy link
Author

zicklag commented Feb 28, 2019

Oh, I found the leak:

RigidBody.hx:291

var p = trans.getOrigin();
var q = trans.getRotation();
var qw:bullet.Bt.QuadWord = q;

Just needed to delete those after use. Now the example continues working for an unknown amount of time. I'm going to try testing it with Ammo.js and see if I have the same problem ( without the leak fix ).

Edit: I tested the same example with Armory's current Ammo.js and it works without any attempts to fix the leaks that show up for the Khabind build. There has to be some sort of difference between them, I just don't know what it is. For one reason or another Ammo.js doesn't run out of heap memory. 🤔 💭 ‼️

@zicklag
Copy link
Author

zicklag commented Apr 23, 2019

OK, I was finally able to get back to this. 🙂

Good news is, I think it is done! At least the binding part anyway. So I never figured out how Ammo.js magically avoids memory leaks, but it doesn't matter, because the memory leaks are not unique to the JavaScript build, they happen with the HashLink target as well. This means that we have to fix the memory leaks by adding the proper delete() calls anyway.

I went through and I found the last memory leak that occurs when doing a pure rigid body simulation ( without cloth, soft bodies, or constraints ). The simulation can run with hundreds of objects without steadily increasing in memory usage, now. There might be some more in the cloth, soft body, or constraint code still.

Remaining Issues

I notice that some of the physics behave a bit differently than Ammo.js did with the new bindings. The behavior of Convex Hull shaped objects is sporadic and it seems like the mesh collision shape has some issues when I try to set the floor to use it ( it freezes in Krom and things go through it in HashLink ). I don't really have any experience with the Bullet API so I don't know that I will be able to fix that right now.

The good thing about it, though, is that the JavaScript build now behaves the same as the HashLink build, so any issues that we have in Krom are probably just things that we hadn't noticed were already an issue in HashLink builds.

@lubos If you could test it out that would be great. I've got a simple blend with some test objects where you can see the convex hull shape issue, and if you set the floor to use a mesh collision shape you can see the mesh shape issue as well.

basic_test.zip

@zicklag
Copy link
Author

zicklag commented Apr 24, 2019

Update

  • It looks like the latest changes have a problem with Haxe 4.0.0-rc1 that comes with Kha right now. Gives a very undescribed Invalid_argument("index out of bounds"). Works with 4.0.0-rc2 though. @RobDangerous are you good with updating Haxe for Kha?

  • The HashLink build is having problems with the mesh collision shape. You can see it in that example that I uploaded earlier. Kind of strange... I'm still pretty sure that the bindings themselves are working fine, I just don't know much about the physics code itself.

  • The ragdoll example seems to work fine in Krom, but it crashes after messing around with it a little bit on HashLink with either a strange radeon error ( below ) or a SIGSEGV;

Radeon Error:

radeon: Failed to allocate virtual address for buffer:
radeon:    size      : 4096 bytes
radeon:    alignment : 4096 bytes
radeon:    domains   : 2
radeon:    va        : 0x429b5ed24238f000
radeon: Failed to allocate virtual address for buffer:
radeon:    size      : 4096 bytes
radeon:    alignment : 4096 bytes
radeon:    domains   : 2
radeon:    va        : 0x429b5ed24238f000
... Lots of that ^
  • The Physics picking example is only working for the first click.

  • The softbody example freezes after startup in Krom. This is probably related to the mesh collision shape issues.

@RobDangerous
Copy link
Contributor

Nope, sorry, I've seen several reports about critical issues in rc2, won't update before rc3.

@luboslenco
Copy link
Member

See Kode/Kha#986, hoping to revisit in the future. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants