Hacks Runtime

0 views
Skip to first unread message

Idara Viengxay

unread,
Aug 5, 2024, 4:06:37 AM8/5/24
to punimure
Im working on a game (targeting PC, Mac, Linux) that probably uses a number of Spine characters at once that perhaps would be far higher than expected or supported. Here's my current benchmark, when running 81 animating skeletons of the nature discussed further below:

I would love to bring that 41% down as low as possible. My goal would be to have there be up to 100 zoo visitors at 60fps, but 80 drags it down to 30fps. I understand that SkeletonRenderer.LateUpdate and SkeletonAnimator.Update do a fair bit of work, so what I'm probably looking for are some hacky-approaches that save me some CPU time, but more on that in a bit. First, I've got to do my due-diligence based on what has already been said on these forums on the subject of performance. Sixth months ago Pharan wrote a helpful pointed list to go through to improve performance:


1) Minimize the number of keyed properties in spine. For example: If a bone doesn't need to rotate, don't give it a key to rotate. Anywhere. That item shouldn't have a row in the dopesheet. Each row in the dopesheet is extra overhead. So even if you only have 1 key on it, it'll eat up resources. (Each dopesheet row is one Timeline runtime object that the runtime has to iterate over every Update an animation makes.)


I think the Bones count is inoffensive. I probably could go down to two spinal bones, but would have to go through all my animations to correct for it, so I'm leaving that until I absolutely have to.


The Attachments count, however, are quite high. There are 178 attachments because I have half a dozen skins that share the skeleton. For the skin displayed above, there are just 26 attachments. I imagine the answer is 'of course not' but attachments in skins that aren't displayed in Unity don't drag down the performance, do they?


4) If your skeletons are for looping environment stuff, and you want want it to play one animation over and over, Baking may be a good option, especially if you just want it to do a Weighted/Skinned animation. Baking will take advantage of the GPU to animate the meshes and free up your CPU to do the more controlled things. For maximum compatibility with Unity GPU skinning settings, make sure each VERTEX is bound to a maxmimum of two bones.


I'm really not too keen on baking stuff, because I want to ragdoll these skeletons later on, if I possibly can. I suppose I could swap out a baked version with a non-baked version. The player can't be baked because I'm mixing animations too much, but that's just one skeleton. I've not actually baked anything with Spine/Unity yet, so I don't know how baking to 60fps and displaying that would perform? Can anyone with some experience in this area make any educated guesses as to how that would turn out?


I've had a few thoughts, that essentially come down to what I described earlier as hacky approaches to this problem. For full context, here's a screenshot of the game, showing the one player Skeleton, and some of the eighty Visitor Skeletons:


The second idea is for skeletons that are far enough away from the camera, to just update their animations at 30fps, even less. The lack of smoothness is very noticeable up close, but I'm guessing less so further away. Slipping a:


There are a few under Advanced in the inspector that should work depending on your setup.

Disable Render Meshes if you're not using meshes.

Enable Immutable Triangles if you never change draw order or enable/disable attachments.


I kinda think your skeleton may still have a few too many bones.

I mean I don't know why your torso has 3 bones.

And I'm guessing you could also sacrifice the foot flexibility by just letting it have 1 joint at the ankle instead of 2 bones per foot. Maybe he could even live without a neck bone, since the neck is barely visible anyway.

But you have better knowledge of what your skeleton needs to do, so that'll be up to your judgement, I'm sure.


Here's another observation, the game runs so much quicker when actually exported from Unity. It's only in the engine that I have significant trouble. I haven't really encountered much overhead from the Editor until now, but the High setting I described above works fine for me when exported, but in the Editor Medium or Low will have to do. I'm glad these are good ways to decrease CPU speed, I'm hoping to have the game playable on less powerful computers and laptops. In any case, I'm back to having a couple of hundred animating characters with a game frame rate of 60. Hooray!


I am able to pass an opaque pointer of a Swift wrapper instance to the GObject and release it upon the GObject instance destruction. Therefore I am able to ensure, that at most 1 Swift wrapper instance is living at any time.


Since hacking the GObject ref (retain) and unref (release) functions is not an option, I've focused on the Swift runtime. By reading The Swift Runtime: Heap Objects // -dealloc and GitHub - wickwirew/Runtime: A Swift Runtime library for viewing type info, and the dynamic getting and setting of properties. I think I have all I need to achieve my objective already.


My question is, whether I can "swizzle" a runtime method in the same manner as in Objective-C. I would like to perform some additional operations for instances of Swift wrappers and then call the original swift_retain.


Can you take a look at gtk-swift/Sources/GTK at master svanimpe/gtk-swift GitHub?

I did some experimenting with creating a Swift wrapper around GTK earlier this year, and that's how far I got before I had to move my attention elsewhere.


I have forked Rene Hexel's wrappers (GitHub - rhx/SwiftGtk: A Swift wrapper around gtk-3.x and gtk-4.x that is largely auto-generated from gobject-introspection) I intend to explore possibilities for improvements (like this) and merge whatever ends up useful. The rhx's implementation shares the same approach as you. I will take a look.


Meanwhile for the context :) : I've already done some work on signals (passing Swift closures to GObject signals). This is the reason why I explore this particular problem. Consider following example:


The onClicked closure has taken a strong reference to the label instace. However if I captured a weak reference instead (as I would like to do), the label would deallocate and I would end up with nil value during the call of the signal.


While there is nothing wrong with it, I would like to warn you in advance. I've already seen some hand-written wrappes (on github, by TomasLinhart and fork by the GothStar (btw what a nickname :D )). There are two main issues with hand written wrappers when it comes to GTK. The first issue is the size of the codebase. GTK with all of it's dependencies has hundrets of types and untold number of functions. The second issue is, that there is a lot of versions of Gtk+ available and you might end up with compatibility issues if you "ship" wrapper code directly. There is a solution to this problem, called GObjectIntrospection. Tho GI is not only able to procude xml files describing the C API but it can serve as a middleware too ( I have never tried it tho).


Edit: I can confirm this is exactly what I was searching for. Thank you again :) If anyone had anything to say about the topic (main why I should never try to do something like this :)) please let me know. From my perspective this seems as a reasonable thing to try. Slowing the Swift a bit is not a dealbreaker for me.


A Swift wrapper around gtk-3.x and gtk-4.x that is largely auto-generated from gobject-introspection - GitHub - rhx/SwiftGtk: A Swift wrapper around gtk-3.x and gtk-4.x that is largely auto-generat...


Maybe starting some wiki about the project and share our experiences better. I think the biggest weakness of Rhx's work is, that the project is a little bit confusing when it comes to inner workings of gir2swift and the post processing phase with xed and sed.


My goal was to have a UI framework on Linux that is good enough for me to teach the fundamentals of event-driven UI. I wanted a framework that looks like a Swift framework and that students can learn/use without having to know anything about GTK or GObject. The less API I have to expose, the better!


I was wondering if adding a new attribute like @gobject to LLVM and create the required wrappers and other scaffolding code there, at the compiler level would be something that people would look forward to. Is the current solution easy and complete enough?


Gnome project

Gnome project (especially libraries like GLib/GObject, GTK) is a mature project with a lengthy history. One of the aims of GLib/GObject libraries is to provide C API that is bindable by other languages. Therefore the GTK library is already accessible from almost all most common languages. I am not that knowledgable about various GNOME projects, but I saw most GTK apps written in C, Vala, Python or JS.

Therefore I would say, that "Swift needs GTK more then GTK need Swift". I would also say, that Swift won't became mainstream amongst GTK developers since Swift is Apple owned and controlled language which would contrast with the philosophy of the GNOME project originating in GNU.


The Swift bindings for GLib/GObject, GTK

The GTK (and it's dependencies) is a huge codebase. The public API and documentation itself is hundreds of thousands of lines. Since all of the APIs are in C, you are free to use the GTK from Swift already.

The quest for more idiomatic Swift interface for GLib/GObject or GTK is a tough one. The most viable approach is to generate Swift wrapper for C APIs. This can be done already, since GLib/GObject libraries can take advantage of project called gobject-introspection which (amongst many things) produces XML metadata files with extension .gir. Those .gir files are distributed alongside with developer versions of GLib/GObject and GTK libraries.

There is already a project which generates .swift interfaces based on metadata in .gir files called gir2swift.


The gir2swift project

The gir2swift project GitHub - rhx/gir2swift: A simple GIR parser in Swift for creating Swift types for a .gir file is a part of wider initiative to provide GTK bindings to Swift developers know as SwiftGtk GitHub - rhx/SwiftGtk: A Swift wrapper around gtk-3.x and gtk-4.x that is largely auto-generated from gobject-introspection.

I am a contributor to both projects. The gir2swift already implements a lot of features but the project is (in my opinion) in dire need of refactoring to make it more Swift-idiomatic and understandable for wider audience of open source developers willing to contribute. If you consider contributing, feel free to contact me with any issue and I will try to help as much as I would be able to.

3a8082e126
Reply all
Reply to author
Forward
0 new messages