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

Reduce texture memory usage on non-Windows systems #1329

Closed kring closed 7 months ago

kring commented 8 months ago

This is a simple change that significantly reduces the amount of (CPU) memory used by textures on non-Windows systems.

We create textures in most situations and on most platforms by populating Unreal's FBulkData class with the raw pixel data from the glTF or raster overlay. Then, sometime later, Unreal's uploads it to the GPU. I noticed while spelunking through the Unreal source code while working on #1327 that FBulkData has a flag: BULKDATA_SingleUse. When this is set, Unreal directly grabs the buffer from the FBulkData as the source of the GPU upload, and frees it afterward. It's single use because we can't use that buffer ourselves after Unreal has grabbed it. When it's not set (which is the default), Unreal copies the bulk data again, uses the copy as the source of the upload, and leaves our original buffer in FBulkData intact.

We don't need the buffer in FBulkData - we already have our own copy of this data in the glTF - so BULKDATA_SingleUse is perfect for our use, and this PR adds it. Specifying this flags avoids a game-thread copy of the texture data. It also significantly reduces memory usage by texture data because the copy in the FBulkData doesn't sit around for the entire lifetime of the texture anymore.

This affects:

  1. Every texture on non-Windows platforms (D3D11 and D3D12 use a custom texture creation path that is not affected by this change)
  2. Feature metadata-related textures on all platforms (even Windows, because these textures don't use the custom texture creation path on Windows)

To measure the memory reduction, I hacked the Windows implementation to use the standard texture creation instead of the custom one. If you want to do this yourself, look for GRHISupportsAsyncTextureCreation in CesiumTextureUtility.cpp and replace it with false.

Then I opened up level 1 of the Samples project in the Editor and let it load. Before this change, the Editor process used 1.669 GB. Afterward, it used 1.538. Then I loaded the Google Photorealistic 3D Tiles sample level, and let that load. On that level, the Editor process went from 2.182 GB down to 1.918 GB with this change. These don't sound like huge changes percentage-wise, but the Editor uses a lot of memory and only some of it is our textures. Textures are our biggest use of memory in many cases, so eliminating a copy of the texture data is a big deal, especially on on devices with limited memory, like mobile and AR/VR devices.

azrogers commented 7 months ago

Testing both levels, I see a 14.3% reduction on 01_CesiumWorld with this change (from 2.24GB to 1.92GB) and a 15.6% reduction in 12_CesiumGoogleMapsTiles (from 3.53GB to 2.98GB). Great change!