Overflow! Each collection allocates memory by numbers from the game.project (SOVLED)

The actual problem is that each collection allocates full memory specified in the game.project.

I created a project with hundreds of collections that are created through a proxy.
These are empty collections.
I took the project settings the same as the working project.
Result:

In other words, 27 empty collections required 133 MB of memory! This is the problem.

We need to control the amount of memory allocated to the entities within the collection.
For a large collection, we really need more than 4000, but for small ones 20 would suffice.

I think guys want something like a gui and nodes, when developer can set maximum of node counts for each gui component.
Would be great to have the same thing for collections proxy and property in game.project can be used only for main collection.

2 Likes

YES!!! Y E S !!!11

In our real project, the numbers are:
Roads = 11,
Tiles = 375,
Resources = 410,
Rocks = 144,
Clouds = 203,
Decals = 247,
and over 2000 instances for all characters animations.
All this within the same collection.
That’s why we had to specify 5000 instances in game.project

About animations - it was very unexpected to learn that one Spine character has up to 100 GO-instances!

Yes, Spine animations require one GO per bone. Game objects are very cheap though. They are the smallest building block in the engine.

Note though that transforming thousands of bones/game objects each frame might cause problems on mobile. I’ve tried animating 200 or so characters with 30 bones each on an iPhone 6. It ran in 60 FPS fine but the engine was pretty busy.

Regarding memory consumption. @sven or @Mathias_Westerdahl can probably clarify a bit, or @Ragnar_Svensson. I think that the intended use cases for collection proxies are different from what you are trying but I leave it to the engine experts to answer that.

An empty game object instance in Defold is equivalent to a scene graph node in another engine, e.g. a specific skeleton bone, or something as small. They are not equivalent to an instance in e.g. Unity. In Defold, it’s an entry in a few arrays as opposed to a dynamically allocated heavy-duty object. In terms of cost, they are much closer to particles in a particle system, than an NPC for example.

The typical use case for a collection proxy is to do dynamic level loading, or possibly to run two game sessions simultaneously (to do cross fades or similar). It’s not meant to solve asset streaming. Since there is no support for asset streaming currently*, we understand that many use collection proxies as a workaround for this. So rather than changing how collection proxies work in this aspect, we would need to implement streaming support to solve the problems you are facing in a good way.

*) I believe it’s possible for users to achieve asset streaming to some degree using native extensions and the buffer api, but it would probably be a pretty challenging exercise.

4 Likes

I know several possible solving of problem, and all of them has bottleneck on engile side.

  1. Replace RGBA textures with RGB, and one more RGB texture can use R, G and B channel as alpha for three different texture. Small shader, and it can work, but:
    - defold can’t use two textures in material

  2. Polygonal sprites (can use with point 1, and help to make better compressin sprites with alpha) - I told about it here.

  3. And, of cource, assets streaming.

All this features “must have” for any 2d engine because every 2d game use too many sprites with alpha chanel, and every big game will be have a memory problem.

1 Like

The problem I described is very serious for us.
In fact, we can’t continue developing further, because the game does not start on low/mid smartphones due to memory overruns.

The ideal solution would be the ability to individually setup for each collection the number of instances for it. The collection is a very convenient form of storing game asses. I think it would be very convenient to implement the assets streaming.

Where can I read more about this (buffer api)?

There are several possible ways forward, but it is unlikely that collection proxies will be rethought to cater for your use case. Proxies are used to create whole game world instances so there is a lot of systems that come with them, for instance separate physics worlds. The instance counters have little effect on memory consumption so individual counters would not solve the problem.

Proper asset streaming is a future feature that will require lots of design and a thorough implementation process. It will likely happen at some point in the future but there are no concrete plans.

For your case: there are ways to lessen the memory footprint of textures. Have you looked at hardware texture compression, removing alpha and such? Also, support for 16 bit textures is in the works.

Another option: does your design permit separating the game into larger “chunks” that can be loaded via proxy the way they are intended to be used?

1 Like

Sidenote: I’ve added a clarification warning to the collection proxy manual.

We understand this is a big problem for you (and many others using Defold). We have been discussing alternative solutions a bit. We’ll investigate it a bit more and get back to you in a few days to see what we have found.

2 Likes

I just did a test that might point to a way forward for you:

  • I created an atlas with some images:

  • I set up a sprite to use one of these images as texture.

  • I dug out the texturec from the “build” folder

  • I copied the texturec to a folder in the project, named it “test.texturec” and added the folder to the custom resources.

  • Now I changed the atlas to contain different images, but the image sizes and order is intact:

  • Running the game now shows the pink square:

  • But with this little piece of code I can dynamically load and replace the texture resource on the sprite:
local buffer = resource.load("/res/test.texturec")
resource.set(go.get("#sprite", "texture0"), buffer)

5 Likes

Wow! But how to unload this texture from the memory?

It’s unloaded when you stop refering to it. Resources are reference counted.

The complexity of this solution is that the resources of buildings are not of the same type. One building consists of several simple small GO. The second building contains animations and large atlases. We will have to unify the structures of all buildings for easy replacement of textures (and create local custom texture management) - it’s very hard for today.

Perhaps this method is suitable to split one RGBA-texture into two RGB + A.

Hey! Our approach to solve this problem is to improve collection factories to handle dynamic resource loading better. With these changes you should be able to use collection factories to spawn your buildings with ability to control when the resources are loaded/unloaded. While I was experimenting with this, I found that the current implementation is buggy, as it is already loading resources dynamically. It however loads them synchronously so I would expect it to cause a few hitches while loading textures etc. Right now you can however exploit this bug to get rid of the memory issue, i.e. spawn your buildings through collection factories.

Current faulty behaviour:
Collection factory loads resources synchronously when collectionfactory.create is called

Correct behaviour:
Collection factory either (controlled by user):
loads resources when its containing collection (i.e. the game or the level) is being loaded
loads resources asynchronously when collectionfactory.create is called, or a new function collectionfactory.load is called

We will also add the same thing to the factory component, which is used when spawning single game objects.

10 Likes

How to be with atlas removing?
I tried to use this bug, and yes - atlas load synchronously when I call collectionfactory.create. But I can’t remove this atlas. Is it possible?

Not yet… :slight_smile:

1 Like

Dynamic loading for gameobject and collection factories added in release 1.2.115

8 Likes