Reducing memory usage

From JPCT
Jump to: navigation, search

Reducing memory usage

Android devices are much more limited devices than the usual desktop PC is when it comes to memory. This page will explain some ways to reduce the memory usage of a jPCT-AE powered application.


Watch your content

Check your models and textures to make sure that they aren't overly complex. You might want to lower texture resolution of vertex/polygon count of your mesh to save memory. Keep in mind that for textures, the uncompressed size matters...not the size that the file has on disk. I.e. a 32bit 512*512 texture needs 512*512=262144*4=1048576 (1MB). A 256*256 texture of the same depth only uses one quarter of that. In addition, the texture is stored twice by default, one copy remains in main memory while one will be uploaded to the GPU (you can disable this behaviour at the cost of not being able to recover from a pause or stop event then without reloading everything from scratch).

Reduce texture memory usage

As said, smaller textures need less memory. If this still doesn't help, there are ways to reduce memory usage somewhat further.

Use 16bit textures instead of 32bit ones

It might be sufficient to use 16bit textures (at least for some textures) instead of 32bit ones. These textures use only half the memory on the GPU and might also help to increase performance. To make a single texture use 16bit (i.e. 4 bits per pixel), so can use [1]. If you want all textures to be handled that way by default, [2] is your friend. Keep in mind that using this option increases color banding in the textures and it doesn't look good on all textures.

Compress the in-memory copy of the texture data

By default, jPCT-AE keeps a copy of the pixel data of a texture in main memory to handle pause/stop events, which destroy the gl context, i.e. all textures uploaded to the GPU. You can trade memory usage for upload performance by compressing this in-memory copy. Simple call [3] to enable this feature. Please note that this causes an little memory peak when uploading the compressed texture, because it has to be decompressed first.

Avoid mip-map generation on textures that don't need it

You should use mip-mapping ([4]) to improve image quality and avoid texture flickering. However, some textures just don't need it. For example uni-colored textures or textures used for blitting only. You can safely disable mip-mapping for these textures to save some memory.

Use the Virtualizer

You can use the Virtualizer to swap in-memory texture data out to the SD-Card. To do this, set your Virtualizer instance in the TextureManager and call TextureManager.virtualize(<Texture>); for textures that you want to virtualize. A virtualized texture will consume the same amount of memory on the GPU but no main memory. Keep in mind that this will save memory but increase startup-time.

Use texture ETC1-compression

You can enable ETC1 texture compression on hardware that supports it (almost all current devices do). If it's not supported, jPCT-AE will revert to uncompressed textures instead. Memory saving effect of this is on par with using 16bit textures, but the quality might be better in some cases. The compression happens at runtime. If you have a Virtualizer instance assigned to the TextureManager, you can enable caching for compressed textures in Config by setting cacheCompressedTextures to true.

Reduce animation size

Keyframe animations are fast and simple to use, but require a lot of memory. However, there are some ways to reduce this.

Reduce the number of keyframes

Your animation might look good enough with less keyframes. Just give it a try.

Remove animation sequences

A MD2-file usually contains a large set of animation sequences that you might not need in your application. You can remove them by calling [5].

Compress meshes

If you create your keyframe animation out of individual meshes (and not by loading a MD2 file), it can help a little to compress the mesh. You can either do this by letting cloneMesh(true) ([6]) do this for you or by calling compress() ([7]) on the mesh yourself.

Strip meshes

You can safely remove triangle information from a mesh if it's used for animations only. If it isn't, you should make a clone of it anyway, so actually, this applies in every case. A call to strip() ([8]) does this for you per mesh. If you want to strip the whole animation, you can do this by calling strip on the animation itself ([9])

Reduce memory usage of objects

Strip objects

If you don't want to modify an object at runtime, you can strip it to save some memory by calling strip() ([10]). However, if you want to clone this object later at runtime, you might run into trouble...

Make objects share meshes in main memory

If an object is used multiple times at once in an application (like bullets, multiple enemies...), you shouldn't load them multiple times but create clones of existing objects. This can be done by either calling cloneObject ([11]) or by using an appropriate constructor of Object3D.

Make objects share meshes on the GPU

In addition to sharing meshes in the vm's memory, you can also enable this for the data on the GPU. shareCompiledData() ([12]) is your friend here. This can also be used to make one animation call animate dozens of instances.

Use indexed geometry

By default, jPCT decides which objects should be compiled to indexed geometry and which to flat. However, flat consumes a little more memory, so if you are using a lot of small objects that jPCT compiles to flat, you can try to call forceGeometryIndices(true) ([13]) to force them into indexed mode.

Use the Virtualizer

By default, jPCT-AE keeps a copy of the compiled data that will be send to the GPU to handle context changes properly. You can offload this data to the SD-card by assigning a Virtualizer instance to an Object3D.