Internal Caches

Overview

Gameface has various internal caches that control how CPU and GPU memory is reused. The caches are there to avoid expensive allocations - of CPU and GPU memory - every frame. This improves performance at the cost of higher memory usage. The default cache sizes are set to reasonable defaults but depending on the given UI, the sizes might not be optimal. There are situations where user code might have to adjust the caches:

  • If a given UI scene normally uses less memory than the default cache sizes, then memory is probably retained in the caches while not being actively used. In this situation, it might be worth considering lowering the cache sizes.
  • If a given UI scene normally uses more memory than the default cache sizes, the caches will be pruned every frame only to allocate memory again in the next frame. In this case, it makes sense to increase the cache size.

The setting of cache sizes is done with the cohtml::View::QueueSetCacheCountSize and cohtml::View::QueueSetCacheBytesSize APIs. The current cache sizes can be inspected with cohtml::View::GetCacheBytesStats and cohtml::View::GetCacheCountStats. The caches can also be force cleared at any given time with cohtml::View::QueueClearCaches.

Caches

The types of internal caches are given by the cohtml::InternalCaches enumeration. The APIs for the cache control operate on different cache depending on the provided cache argument.

cohtml::View* view;
...

// set the cache size for the Global GPU Resources Pool
view->QueueSetCacheBytesSize(cohtml::ICACHE_GPUResourcesPool, 128 * 1024 * 1024); // 128MB

// set the cache size for the SVG Textures
view->QueueSetCacheBytesSize(cohtml::ICACHE_SVGSurfaces, 20 * 1024 * 1024); // 20MB

Here is an overview with the types of caches that Gameface has:

  • ICACHE_Shadows - GPU textures used for shadow shapes created due to box-shadow and text-shadow
  • ICACHE_Paths - cache for CPU objects for complex path shapes
  • ICACHE_GfxCommandBuffers - cache for CPU objects used for recording paint commands for the Gameface’s rendering library
  • ICACHE_GfxCommandProcessors - cache for CPU objects used for processing paint commands and generating backend commands for the rendering backend
  • ICACHE_SVGSurfaces - GPU textures used for caching and reusing already painted SVGs
  • ICACHE_BackdropFilterSurfaces - GPU textures used as intermediate textures when rendering backdrop filter effects
  • ICACHE_GPUResourcesPool - Global cache for GPU rendering resources as intermediate rendering targets, vertex buffers, index buffers, and constant buffers.

For more information on how to monitor and diagnose the state of some of the GPU caches, check out the “Precise Scratch Texture Manager monitoring” section on the Inspector Features page.

Global GPU Resources Pool

Previously, Gameface had several types of internal rendering caches for different types of GPU objects. The size of each cache had to be adjusted individually, and their fine-tuning and optimization were cumbersome and inconvenient. For these reasons, the Gameface’s rendering library, Renoir, has transitioned to a single, unified cache for GPU resources: the global GPU resources pool. With this cache, the client code can set a single number that will be used for target GPU memory. Renoir will clear the global cache once it reaches the threshold and will deallocate unused GPU resources.

The global GPU resources pool helps with avoiding large GPU memory allocations for:

  • textures used as intermediate rendering targets
  • vertex buffers and index buffers used for general geometry as well as geometry for path objects
  • constant buffers used throughout the rendering of Gameface

The Global GPU Resources Pool can be controlled through the usual cohtml::View methods for control over caches:

  • cohtml::View::QueueSetCacheBytesSize - for setting the size of the cache. This is the target memory for GPU resources in the cache.
  • cohtml::View::GetCacheBytesStats - for getting the current size of the cache.
  • cohtml::View::QueueClearCaches - for queuing a command so that the cache is flushed during the next cohtml::ViewRenderer::Paint call. During such a flush, Renoir will release as many GPU resources as possible, and those actively being used won’t be destroyed.
    • The clearing of the cache does have some performance impact on the corresponding cohtml::ViewRenderer::Paint call, as Gameface figures out which resource should be destroyed.
    • The clearing of the global GPU Resources Cache is the main way to make Gameface release the internally held GPU resource, which may no longer be needed. As previously mentioned, Gameface tries to avoid frequent expensive GPU object allocations by caching and reusing already allocated ones. This, however, does lead to increased memory pressure. Clearing the global GPU Resources Cache enables client code to release some of the internally held GPU memory.

Example usage of those methods:

// Set the capacity (in bytes) of the global GPU Resources Pool
view->QueueSetCacheBytesSize(cohtml::ICACHE_GPUResourcesPool, 256 * 1024 * 1024); // 256MB

// Get current cache size and usage (in bytes)
unsigned cacheCurrentUsage, cacheCapacity;
view->GetCacheBytesStats(cohtml::ICACHE_GPUResourcesPool, cacheCurrentUsage, cacheCapacity);

// Clear everything in the global GPU Resources Pool
view->QueueClearCaches(cohtml::ICACHE_GPUResourcesPool);