CesiumGS / cesium-unreal

Bringing the 3D geospatial ecosystem to Unreal Engine
https://cesium.com/platform/cesium-for-unreal/
Apache License 2.0
916 stars 292 forks source link

Unnecessary tile pop in when viewing a previously loaded area (memory caching bug) #1327

Open csciguy8 opened 8 months ago

csciguy8 commented 8 months ago
  1. Open the cesium-unreal-samples project

  2. Open level 12_GoogleMapsTiles

  3. In the editor perspective window, you should see the Googleplex and surrounding area load

  4. Move the camera 180 degrees so you are looking behind you

  5. Move the camera back to the starting position

You will see the original tiles load again, faster, because they are cached on disk. This isn't the desired behavior though.

It is expected that you should not see any tiles load or pop in at all. The Cesium3DTileset's Maximum Cached Bytes is configured for 256MB, and all of these tiles only take up ~40MB in the disk cache (cesium-request-cache.sqlite). The tiles in the original view should stay loaded in this scenario.

Thanks @kring for mentioning this last month.

kring commented 8 months ago

I noticed that changing the Maximum Cached Bytes property from 268435456 (256MiB) to 26843545600 (25600MiB) makes the problem go away. So the problem does seem to be that tiles are being unloaded when you look away due to the cache size being exceeded, but I'm not sure why.

kring commented 8 months ago

Turns out I was wrong about how the tile data size is measured for cache purposes. It's actually formed by adding up the number of bytes in all of the glTF buffers (cesium.data.size()) and images (cesium.pixelData.size()). That is after things like Draco and JPG decompression, so it can be a lot larger than the size of the data downloaded over the network (even after it is gunzipped). A single 256x256 JPG ends up being 341KiB.

csciguy8 commented 8 months ago

Interesting. So given my previous example of a 40MB SQLite cache... If I imagine it was filled solely with JPGs, and we have a typical JPEG compression ratio of 10:1, they would expand to ~400MB in memory. This is clearly over my cached bytes setting of 256MB, so maybe everything is working as designed?

If so, maybe it's just a matter of usability with Maximum Cached Bytes? Or maybe my expectations were just wrong?

kring commented 8 months ago

Right, for that Googleplex scene, the actual size of the traversed tiles is about 300 MiB. I'm still trying to be 100% certain it's correct, but I think it is. In which case the default 256MiB max cache for Google Photorealistic 3D Tiles is simply too small.

csciguy8 commented 8 months ago

Ok, if that's true, then my expectations were just wrong.

But this problem could lead to more work with this feature. For example, a new "auto" setting that determines a reasonable size based on your system memory or some other metrics. We could still have a fixed memory size for users that know exactly their device constraints.

kring commented 8 months ago

For comparison, the default in CesiumJS is 512MiB. It's not clear why ours is half that. Part of the reason may be that we're assuming there are extra copies kicking around in memory. cesium-native maintains a copy of all the tile data in the glTF data structure that isn't used at all for rendering. The game engines maintain the copy for rendering, of course, but may also maintain their own CPU-side copy as well.

kring commented 8 months ago

The Unreal "Memory" stat doesn't seem to work at all for showing our texture memory usage. If I set the cache size huge and fly around, the static mesh memory goes up steadily, as you'd expect. But the texture memory usage doesn't change at all.

image

Perhaps our custom texture upload code is somehow evading UE's texture memory performance counter? 😬

kring commented 8 months ago

Perhaps our custom texture upload code is somehow evading UE's texture memory performance counter?

Yes, this. If I force it to use the legacy texture upload path, the texture memory usage is much more realistic:

image