diff --git a/android/filament-android/src/main/cpp/Engine.cpp b/android/filament-android/src/main/cpp/Engine.cpp index 51499a14bc..05893cbd5b 100644 --- a/android/filament-android/src/main/cpp/Engine.cpp +++ b/android/filament-android/src/main/cpp/Engine.cpp @@ -484,7 +484,8 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderConfig(JNIEnv*, jclass, jlong nativeBuilder, jlong commandBufferSizeMB, jlong perRenderPassArenaSizeMB, jlong driverHandleArenaSizeMB, jlong minCommandBufferSizeMB, jlong perFrameCommandsSizeMB, - jlong jobSystemThreadCount, jlong stereoscopicEyeCount) { + jlong jobSystemThreadCount, jlong stereoscopicEyeCount, + jlong resourceAllocatorCacheSizeMB, jlong resourceAllocatorCacheMaxAge) { Engine::Builder* builder = (Engine::Builder*) nativeBuilder; Engine::Config config = { .commandBufferSizeMB = (uint32_t) commandBufferSizeMB, @@ -494,6 +495,8 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu .perFrameCommandsSizeMB = (uint32_t) perFrameCommandsSizeMB, .jobSystemThreadCount = (uint32_t) jobSystemThreadCount, .stereoscopicEyeCount = (uint8_t) stereoscopicEyeCount, + .resourceAllocatorCacheSizeMB = (uint32_t) resourceAllocatorCacheSizeMB, + .resourceAllocatorCacheMaxAge = (uint8_t) resourceAllocatorCacheMaxAge, }; builder->config(&config); } diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java index 014cc33cee..6b4647e2ac 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java @@ -211,7 +211,8 @@ public class Engine { nSetBuilderConfig(mNativeBuilder, config.commandBufferSizeMB, config.perRenderPassArenaSizeMB, config.driverHandleArenaSizeMB, config.minCommandBufferSizeMB, config.perFrameCommandsSizeMB, - config.jobSystemThreadCount, config.stereoscopicEyeCount); + config.jobSystemThreadCount, config.stereoscopicEyeCount, + config.resourceAllocatorCacheSizeMB, config.resourceAllocatorCacheMaxAge); return this; } @@ -356,6 +357,18 @@ public class Engine { * @see Engine#getMaxStereoscopicEyes */ public long stereoscopicEyeCount = 2; + + /* + * Size in MiB of the frame graph texture cache. This should be adjusted based on the + * size of used render targets (typically the screen). + */ + public long resourceAllocatorCacheSizeMB = 64; + + /* + * This value determines for how many frames are texture entries kept in the cache. + * The default value of 30 corresponds to about half a second at 60 fps. + */ + public long resourceAllocatorCacheMaxAge = 30; } private Engine(long nativeEngine, Config config) { @@ -1227,7 +1240,8 @@ public class Engine { private static native void nSetBuilderConfig(long nativeBuilder, long commandBufferSizeMB, long perRenderPassArenaSizeMB, long driverHandleArenaSizeMB, long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount, - long stereoscopicEyeCount); + long stereoscopicEyeCount, + long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge); private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal); private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext); private static native long nBuilderBuild(long nativeBuilder); diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h index 1b5c63a317..904cbda4a3 100644 --- a/filament/include/filament/Engine.h +++ b/filament/include/filament/Engine.h @@ -305,6 +305,18 @@ public: * @see Engine::getMaxStereoscopicEyes */ uint8_t stereoscopicEyeCount = 2; + + /* + * Size in MiB of the frame graph texture cache. This should be adjusted based on the + * size of used render targets (typically the screen). + */ + uint32_t resourceAllocatorCacheSizeMB = 64; + + /* + * This value determines for how many frames are texture entries kept in the cache. + * The default value of 30 corresponds to about half a second at 60 fps. + */ + uint32_t resourceAllocatorCacheMaxAge = 30; }; diff --git a/filament/src/ResourceAllocator.cpp b/filament/src/ResourceAllocator.cpp index 06d21a3de3..eeff5011a6 100644 --- a/filament/src/ResourceAllocator.cpp +++ b/filament/src/ResourceAllocator.cpp @@ -16,15 +16,30 @@ #include "ResourceAllocator.h" -#include "private/backend/DriverApi.h" +#include #include "details/Texture.h" +#include +#include +#include +#include + +#include "private/backend/DriverApi.h" + +#include +#include #include #include -#include +#include +#include +#include #include +#include + +#include +#include using namespace utils; @@ -42,8 +57,7 @@ ResourceAllocator::AssociativeContainer::AssociativeContainer() { template UTILS_NOINLINE -ResourceAllocator::AssociativeContainer::~AssociativeContainer() noexcept { -} +ResourceAllocator::AssociativeContainer::~AssociativeContainer() noexcept = default; template UTILS_NOINLINE @@ -78,9 +92,9 @@ void ResourceAllocator::AssociativeContainer::emplace(ARGS&& ... args) ResourceAllocatorInterface::~ResourceAllocatorInterface() = default; size_t ResourceAllocator::TextureKey::getSize() const noexcept { - size_t pixelCount = width * height * depth; + size_t const pixelCount = width * height * depth; size_t size = pixelCount * FTexture::getFormatSize(format); - size_t s = std::max(uint8_t(1), samples); + size_t const s = std::max(uint8_t(1), samples); if (s > 1) { // if we have MSAA, we assume N times the storage size *= s; @@ -94,8 +108,10 @@ size_t ResourceAllocator::TextureKey::getSize() const noexcept { return size; } -ResourceAllocator::ResourceAllocator(DriverApi& driverApi) noexcept - : mBackend(driverApi) { +ResourceAllocator::ResourceAllocator(Engine::Config const& config, DriverApi& driverApi) noexcept + : mCacheCapacity(config.resourceAllocatorCacheSizeMB), + mCacheMaxAge(config.resourceAllocatorCacheMaxAge), + mBackend(driverApi) { } ResourceAllocator::~ResourceAllocator() noexcept { @@ -112,7 +128,7 @@ void ResourceAllocator::terminate() noexcept { } } -RenderTargetHandle ResourceAllocator::createRenderTarget(const char* name, +RenderTargetHandle ResourceAllocator::createRenderTarget(const char*, TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height, uint8_t samples, MRT color, TargetBufferInfo depth, TargetBufferInfo stencil) noexcept { @@ -181,7 +197,7 @@ void ResourceAllocator::destroyTexture(TextureHandle h) noexcept { // move it to the cache const TextureKey key = it->second; - uint32_t size = key.getSize(); + uint32_t const size = key.getSize(); mTextureCache.emplace(key, TextureCachePayload{ h, mAge, size }); mCacheSize += size; @@ -208,9 +224,9 @@ void ResourceAllocator::gc() noexcept { auto& textureCache = mTextureCache; for (auto it = textureCache.begin(); it != textureCache.end();) { const size_t ageDiff = age - it->second.age; - if (ageDiff >= CACHE_MAX_AGE) { + if (ageDiff >= mCacheMaxAge) { it = purge(it); - if (mCacheSize < CACHE_CAPACITY) { + if (mCacheSize < mCacheCapacity) { // if we're not at capacity, only purge a single entry per gc, trying to // avoid a burst of work. break; @@ -220,7 +236,7 @@ void ResourceAllocator::gc() noexcept { } } - if (UTILS_UNLIKELY(mCacheSize >= CACHE_CAPACITY)) { + if (UTILS_UNLIKELY(mCacheSize >= mCacheCapacity)) { // make a copy of our CacheContainer to a vector using Vector = FixedCapacityVector>; auto cache = Vector::with_capacity(textureCache.size()); @@ -233,14 +249,14 @@ void ResourceAllocator::gc() noexcept { // now remove entries until we're at capacity auto curr = cache.begin(); - while (mCacheSize >= CACHE_CAPACITY) { + while (mCacheSize >= mCacheCapacity) { // by construction this entry must exist purge(textureCache.find(curr->first)); ++curr; } // Since we're sorted already, reset the oldestAge of the whole system - size_t oldestAge = cache.front().second.age; + size_t const oldestAge = cache.front().second.age; for (auto& it : textureCache) { it.second.age -= oldestAge; } diff --git a/filament/src/ResourceAllocator.h b/filament/src/ResourceAllocator.h index d16a046c6c..220b6f6fbf 100644 --- a/filament/src/ResourceAllocator.h +++ b/filament/src/ResourceAllocator.h @@ -17,6 +17,8 @@ #ifndef TNT_FILAMENT_RESOURCEALLOCATOR_H #define TNT_FILAMENT_RESOURCEALLOCATOR_H +#include + #include #include #include @@ -27,7 +29,9 @@ #include #include +#include +#include #include namespace filament { @@ -62,7 +66,8 @@ protected: class ResourceAllocator final : public ResourceAllocatorInterface { public: - explicit ResourceAllocator(backend::DriverApi& driverApi) noexcept; + explicit ResourceAllocator( + Engine::Config const& config, backend::DriverApi& driverApi) noexcept; ~ResourceAllocator() noexcept override; void terminate() noexcept; @@ -89,9 +94,8 @@ public: void gc() noexcept; private: - // TODO: these should be settings of the engine - static constexpr size_t CACHE_CAPACITY = 64u << 20u; // 64 MiB - static constexpr size_t CACHE_MAX_AGE = 30u; + size_t const mCacheCapacity; + size_t const mCacheMaxAge; struct TextureKey { const char* name; // doesn't participate in the hash diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 93915e7b4e..c09711afa1 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -252,7 +252,7 @@ void FEngine::init() { slog.i << "FEngine feature level: " << int(mActiveFeatureLevel) << io::endl; - mResourceAllocator = new ResourceAllocator(driverApi); + mResourceAllocator = new ResourceAllocator(mConfig, driverApi); mFullScreenTriangleVb = downcast(VertexBuffer::Builder() .vertexCount(3)