ConcreteMC / Alex

A Minecraft client written in C# aimed at compatibility with MC:Java & MC:Bedrock
Mozilla Public License 2.0
590 stars 46 forks source link

Reducing memory allocations #106

Closed kennyvv closed 2 years ago

kennyvv commented 2 years ago

VRam

Terrain data

We can reduce the amount of memory used by terrain data by removing "duplicate" vertices and instead using an indexbuffer to point to vertices. Now imagine minecraft's terrain, most of the terrain is matching terrain. Think of the planes biome for example, most of the blocks there are grass blocks. Every single one of those stores 4 vertices per visible face. For all of these matching in both texture and position we remove atleast 1 vertex from memory and replace it with an index in the indexbuffer.

Imagine we have a 16x16 area consisting only of grass blocks. (2 dimensional, for easier calculations) this would currently be a total of 1024 vertices.

X=16 (the grid size) Y=4 (4 vertices per block) XXY=1024 vertices

Now we know that on the perimeter blocks we can only save 1 vertex for every block. There are 4 sides to our little area, so we can remove 16*4=64 vertices from the total 1024. So we have a total of 960 vertices remaining. Great!

For every other block we can remove 1 vertex for every corner because the neighboring blocks can provide that info for us. So that's a total of 4 vertices for every other block. Awesome!

15×15×4÷2=450 vertices. Huray! This means we can remove an additional 450(!!!) vertices!

That only leaves us with a total of 510 vertices.

So assuming 1 vertex is lets say 32 bytes, we would orginally be taking up 32768 bytes of memory. We managed to reduce this to to only 16320 bytes.

That is about a 50% reduction in memory used for our 16x16 grass area. That's not bad!

Now, we can even keep this in mind when we are generating the vertex data for a block. If all neighboring blocks are the same and they do have vertices assigned to them, we can skip the vertex calculations for this block and just point to the neighboring block's vertices instead, thus save some precious cpu time as well!

Another benefit besides using less memory is that the upload to the gpu will take less time, thus resulting in a more stable framerate.

Entities

For entities using the same model we can skip the vertex calculations and only store the rotation and positional data for each bone.

We can apply the same logic to entities that share the same texture, re-use and thus reduce memory usage.

This comes with the extra benefit of not having to send any resources for this entity to the gpu, thus we don't need to block the rendering thread resulting in more stable framerates.

More information about this method of entity rendering can be found in #105

Textures

We can reduce the amount of memory used for terrain textures by improving the texture atlas generation. They currently have a lot of unused areas.

Ram

TODO

kennyvv commented 2 years ago

Copy paste from #89

Currently we have a lot of vertexbuffers for all sorts of different things. This causes a lot of lag when spawning or loading & updating chunks. All of these operations need to be executed on the UI/Rendering thread. To fight this we should reduce the amount of allocations & updates.

For example:

Chunks have multiple vertexbuffers, 1 for each renderstage required. (Renderstages seperate different block types like translucent, animated or solid blocks) For each entity a new vertexbuffer is created for it's model, model instancing should be used to reduce this as lots of entities share the same basic model.