A new Builder-based API to create a filament Engine
This doesn't add or remove functionality, but merely changes the API to create an Engine, to be more consistant with how we construct other objects in filament. You can now use Engine::Builder to construct an Engine.
This commit is contained in:
committed by
Mathias Agopian
parent
2ae4ee85e0
commit
17664d294e
@@ -17,6 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_ENGINE_H
|
||||
#define TNT_FILAMENT_ENGINE_H
|
||||
|
||||
#include <filament/FilamentAPI.h>
|
||||
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
@@ -165,6 +167,7 @@ class TransformManager;
|
||||
* @see Renderer
|
||||
*/
|
||||
class UTILS_PUBLIC Engine {
|
||||
struct BuilderDetails;
|
||||
public:
|
||||
using Platform = backend::Platform;
|
||||
using Backend = backend::Backend;
|
||||
@@ -266,96 +269,124 @@ public:
|
||||
uint32_t perFrameCommandsSizeMB = FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB;
|
||||
};
|
||||
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
using CreateCallback = void(void* user, void* token);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates an instance of Engine
|
||||
*
|
||||
* @param backend Which driver backend to use.
|
||||
*
|
||||
* @param platform A pointer to an object that implements Platform. If this is
|
||||
* provided, then this object is used to create the hardware context
|
||||
* and expose platform features to it.
|
||||
*
|
||||
* If not provided (or nullptr is used), an appropriate Platform
|
||||
* is created automatically.
|
||||
*
|
||||
* All methods of this interface are called from filament's
|
||||
* render thread, which is different from the main thread.
|
||||
*
|
||||
* The lifetime of \p platform must exceed the lifetime of
|
||||
* the Engine object.
|
||||
*
|
||||
* @param sharedGLContext A platform-dependant OpenGL context used as a shared context
|
||||
* when creating filament's internal context.
|
||||
* Setting this parameter will force filament to use the OpenGL
|
||||
* implementation (instead of Vulkan for instance).
|
||||
*
|
||||
* @param config A pointer to optional parameters to specify memory size
|
||||
* configuration options. If nullptr, then defaults used.
|
||||
*
|
||||
* @return A pointer to the newly created Engine, or nullptr if the Engine couldn't be created.
|
||||
*
|
||||
* nullptr if the GPU driver couldn't be initialized, for instance if it doesn't
|
||||
* support the right version of OpenGL or OpenGL ES.
|
||||
*
|
||||
* @exception utils::PostConditionPanic can be thrown if there isn't enough memory to
|
||||
* allocate the command buffer. If exceptions are disabled, this condition if fatal and
|
||||
* this function will abort.
|
||||
*
|
||||
* \remark
|
||||
* This method is thread-safe.
|
||||
* Engine::Builder is used to create a new filament Engine.
|
||||
*/
|
||||
static Engine* create(Backend backend = Backend::DEFAULT,
|
||||
Platform* platform = nullptr, void* sharedGLContext = nullptr,
|
||||
const Config* config = nullptr);
|
||||
class Builder : public BuilderBase<BuilderDetails> {
|
||||
friend struct BuilderDetails;
|
||||
friend class FEngine;
|
||||
public:
|
||||
Builder() noexcept;
|
||||
Builder(Builder const& rhs) noexcept;
|
||||
Builder(Builder&& rhs) noexcept;
|
||||
~Builder() noexcept;
|
||||
Builder& operator=(Builder const& rhs) noexcept;
|
||||
Builder& operator=(Builder&& rhs) noexcept;
|
||||
|
||||
/**
|
||||
* @param backend Which driver backend to use
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& backend(Backend backend) noexcept;
|
||||
|
||||
/**
|
||||
* @param platform A pointer to an object that implements Platform. If this is
|
||||
* provided, then this object is used to create the hardware context
|
||||
* and expose platform features to it.
|
||||
*
|
||||
* If not provided (or nullptr is used), an appropriate Platform
|
||||
* is created automatically.
|
||||
*
|
||||
* All methods of this interface are called from filament's
|
||||
* render thread, which is different from the main thread.
|
||||
*
|
||||
* The lifetime of \p platform must exceed the lifetime of
|
||||
* the Engine object.
|
||||
*
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& platform(Platform* platform) noexcept;
|
||||
|
||||
/**
|
||||
* @param config A pointer to optional parameters to specify memory size
|
||||
* configuration options. If nullptr, then defaults used.
|
||||
*
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& config(const Config* config) noexcept;
|
||||
|
||||
/**
|
||||
* @param sharedContext A platform-dependant context used as a shared context
|
||||
* when creating filament's internal context.
|
||||
*
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& sharedContext(void* sharedContext) noexcept;
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
/**
|
||||
* Creates the filament Engine asynchronously.
|
||||
*
|
||||
* @param callback Callback called once the engine is initialized and it is safe to
|
||||
* call Engine::getEngine().
|
||||
*/
|
||||
void build(utils::Invocable<void(void* token)>&& callback) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates an instance of Engine.
|
||||
*
|
||||
* @return A pointer to the newly created Engine, or nullptr if the Engine couldn't be
|
||||
* created.
|
||||
* nullptr if the GPU driver couldn't be initialized, for instance if it doesn't
|
||||
* support the right version of OpenGL or OpenGL ES.
|
||||
*
|
||||
* @exception utils::PostConditionPanic can be thrown if there isn't enough memory to
|
||||
* allocate the command buffer. If exceptions are disabled, this condition if
|
||||
* fatal and this function will abort.
|
||||
*/
|
||||
Engine* build() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Backward compatibility helper to create an Engine.
|
||||
* @see Builder
|
||||
*/
|
||||
static inline Engine* create(Backend backend = Backend::DEFAULT,
|
||||
Platform* platform = nullptr, void* sharedContext = nullptr,
|
||||
const Config* config = nullptr) {
|
||||
return Engine::Builder()
|
||||
.backend(backend)
|
||||
.platform(platform)
|
||||
.sharedContext(sharedContext)
|
||||
.config(config)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
/**
|
||||
* A callback used with Engine::createAsync() called once the engine is initialized and it is
|
||||
* safe to call Engine::getEngine(token). This callback is invoked from an arbitrary worker
|
||||
* thread. Engine::getEngine() CANNOT be called from that thread, instead it must be called
|
||||
* from the same thread than Engine::createAsync() was called from.
|
||||
*
|
||||
* @param user User provided parameter given in createAsync().
|
||||
*
|
||||
* @param token An opaque token used to call Engine::getEngine().
|
||||
* Backward compatibility helper to create an Engine asynchronously.
|
||||
* @see Builder
|
||||
*/
|
||||
using CreateCallback = void(void* user, void* token);
|
||||
|
||||
/**
|
||||
* Creates an instance of Engine asynchronously
|
||||
*
|
||||
* @param callback Callback called once the engine is initialized and it is safe to
|
||||
* call Engine::getEngine.
|
||||
*
|
||||
* @param user A user provided pointer that is given back to callback unmodified.
|
||||
*
|
||||
* @param backend Which driver backend to use.
|
||||
*
|
||||
* @param platform A pointer to an object that implements Platform. If this is
|
||||
* provided, then this object is used to create the hardware context
|
||||
* and expose platform features to it.
|
||||
*
|
||||
* If not provided (or nullptr is used), an appropriate Platform
|
||||
* is created automatically.
|
||||
*
|
||||
* All methods of this interface are called from filament's
|
||||
* render thread, which is different from the main thread.
|
||||
*
|
||||
* The lifetime of \p platform must exceed the lifetime of
|
||||
* the Engine object.
|
||||
*
|
||||
* @param sharedGLContext A platform-dependant OpenGL context used as a shared context
|
||||
* when creating filament's internal context.
|
||||
* Setting this parameter will force filament to use the OpenGL
|
||||
* implementation (instead of Vulkan for instance).
|
||||
*
|
||||
* @param config A pointer to optional parameters to specify memory size
|
||||
* configuration options
|
||||
*/
|
||||
static void createAsync(CreateCallback callback, void* user,
|
||||
static inline void createAsync(CreateCallback callback, void* user,
|
||||
Backend backend = Backend::DEFAULT,
|
||||
Platform* platform = nullptr, void* sharedGLContext = nullptr,
|
||||
const Config* config = nullptr);
|
||||
Platform* platform = nullptr, void* sharedContext = nullptr,
|
||||
const Config* config = nullptr) {
|
||||
Engine::Builder()
|
||||
.backend(backend)
|
||||
.platform(platform)
|
||||
.sharedContext(sharedContext)
|
||||
.config(config)
|
||||
.build([callback, user](void* token) {
|
||||
callback(user, token);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an Engine* from createAsync(). This must be called from the same thread than
|
||||
@@ -372,6 +403,7 @@ public:
|
||||
static Engine* getEngine(void* token);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Destroy the Engine instance and all associated resources.
|
||||
*
|
||||
|
||||
@@ -46,20 +46,11 @@ namespace filament {
|
||||
using namespace math;
|
||||
using namespace backend;
|
||||
|
||||
Engine* Engine::create(Backend backend, Platform* platform, void* sharedGLContext, const Config* config) {
|
||||
return FEngine::create(backend, platform, sharedGLContext, config);
|
||||
}
|
||||
|
||||
void Engine::destroy(Engine* engine) {
|
||||
FEngine::destroy(downcast(engine));
|
||||
}
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
void Engine::createAsync(Engine::CreateCallback callback, void* user, Backend backend,
|
||||
Platform* platform, void* sharedGLContext, const Config* config) {
|
||||
FEngine::createAsync(callback, user, backend, platform, sharedGLContext, config);
|
||||
}
|
||||
|
||||
Engine* Engine::getEngine(void* token) {
|
||||
return FEngine::getEngine(token);
|
||||
}
|
||||
|
||||
+122
-71
@@ -36,8 +36,6 @@
|
||||
#include "details/VertexBuffer.h"
|
||||
#include "details/View.h"
|
||||
|
||||
#include <private/filament/SibStructs.h>
|
||||
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <private/backend/PlatformFactory.h>
|
||||
@@ -48,6 +46,7 @@
|
||||
#include <utils/debug.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/PrivateImplementation-impl.h>
|
||||
#include <utils/Systrace.h>
|
||||
#include <utils/ThreadUtils.h>
|
||||
|
||||
@@ -64,13 +63,19 @@ namespace filament {
|
||||
using namespace backend;
|
||||
using namespace filaflat;
|
||||
|
||||
FEngine* FEngine::create(Backend backend, Platform* platform,
|
||||
void* sharedGLContext, const Config *pConfig) {
|
||||
struct Engine::BuilderDetails {
|
||||
Backend mBackend = Backend::DEFAULT;
|
||||
Platform* mPlatform = nullptr;
|
||||
Engine::Config mConfig;
|
||||
void* mSharedContext = nullptr;
|
||||
static Config validateConfig(const Config* pConfig) noexcept;
|
||||
};
|
||||
|
||||
Engine* FEngine::create(Engine::Builder const& builder) {
|
||||
SYSTRACE_ENABLE();
|
||||
SYSTRACE_CALL();
|
||||
|
||||
const Config config{ validateConfig(pConfig) };
|
||||
FEngine* instance = new FEngine(backend, platform, config, sharedGLContext);
|
||||
FEngine* instance = new FEngine(builder);
|
||||
|
||||
// initialize all fields that need an instance of FEngine
|
||||
// (this cannot be done safely in the ctor)
|
||||
@@ -78,6 +83,9 @@ FEngine* FEngine::create(Backend backend, Platform* platform,
|
||||
// Normally we launch a thread and create the context and Driver from there (see FEngine::loop).
|
||||
// In the single-threaded case, we do so in the here and now.
|
||||
if (!UTILS_HAS_THREADING) {
|
||||
Platform* platform = builder->mPlatform;
|
||||
void* const sharedContext = builder->mSharedContext;
|
||||
|
||||
if (platform == nullptr) {
|
||||
platform = PlatformFactory::create(&instance->mBackend);
|
||||
instance->mPlatform = platform;
|
||||
@@ -88,8 +96,9 @@ FEngine* FEngine::create(Backend backend, Platform* platform,
|
||||
delete instance;
|
||||
return nullptr;
|
||||
}
|
||||
DriverConfig driverConfig{ .handleArenaSize = instance->getRequestedDriverHandleArenaSize() };
|
||||
instance->mDriver = platform->createDriver(sharedGLContext, driverConfig);
|
||||
DriverConfig const driverConfig{
|
||||
.handleArenaSize = instance->getRequestedDriverHandleArenaSize() };
|
||||
instance->mDriver = platform->createDriver(sharedContext, driverConfig);
|
||||
|
||||
} else {
|
||||
// start the driver thread
|
||||
@@ -118,20 +127,19 @@ FEngine* FEngine::create(Backend backend, Platform* platform,
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
|
||||
void FEngine::createAsync(CreateCallback callback, void* user,
|
||||
Backend backend, Platform* platform, void* sharedGLContext, const Config* config) {
|
||||
void FEngine::create(Engine::Builder const& builder, Invocable<void(void*)>&& callback) {
|
||||
SYSTRACE_ENABLE();
|
||||
SYSTRACE_CALL();
|
||||
Config validConfig = validateConfig(config);
|
||||
FEngine* instance = new FEngine(backend, platform, validConfig, sharedGLContext);
|
||||
|
||||
FEngine* instance = new FEngine(builder);
|
||||
|
||||
// start the driver thread
|
||||
instance->mDriverThread = std::thread(&FEngine::loop, instance);
|
||||
|
||||
// launch a thread to call the callback -- so it can't do any damage.
|
||||
std::thread callbackThread = std::thread([instance, callback, user]() {
|
||||
std::thread callbackThread = std::thread([instance, callback = std::move(callback)]() {
|
||||
instance->mDriverBarrier.await();
|
||||
callback(user, instance);
|
||||
callback(instance);
|
||||
});
|
||||
|
||||
// let the callback thread die on its own
|
||||
@@ -163,48 +171,6 @@ FEngine* FEngine::getEngine(void* token) {
|
||||
|
||||
#endif
|
||||
|
||||
Engine::Config FEngine::validateConfig(const Config* const pConfig) noexcept
|
||||
{
|
||||
// Rule of thumb: perRenderPassArenaMB must be roughly 1 MB larger than perFrameCommandsMB
|
||||
constexpr uint32_t COMMAND_ARENA_OVERHEAD = 1;
|
||||
constexpr uint32_t CONCURRENT_FRAME_COUNT = 3;
|
||||
|
||||
Config config;
|
||||
if (!pConfig) {
|
||||
return config;
|
||||
}
|
||||
|
||||
// make sure to copy all the fields
|
||||
config = *pConfig;
|
||||
|
||||
// Use at least the defaults set by the build system
|
||||
config.minCommandBufferSizeMB = std::max(
|
||||
config.minCommandBufferSizeMB,
|
||||
(uint32_t)FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB);
|
||||
|
||||
config.perFrameCommandsSizeMB = std::max(
|
||||
config.perFrameCommandsSizeMB,
|
||||
(uint32_t)FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB);
|
||||
|
||||
config.perRenderPassArenaSizeMB = std::max(
|
||||
config.perRenderPassArenaSizeMB,
|
||||
(uint32_t)FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB);
|
||||
|
||||
config.commandBufferSizeMB = std::max(
|
||||
config.commandBufferSizeMB,
|
||||
config.minCommandBufferSizeMB * CONCURRENT_FRAME_COUNT);
|
||||
|
||||
// Enforce pre-render-pass arena rule-of-thumb
|
||||
config.perRenderPassArenaSizeMB = std::max(
|
||||
config.perRenderPassArenaSizeMB,
|
||||
config.perFrameCommandsSizeMB + COMMAND_ARENA_OVERHEAD);
|
||||
|
||||
// This value gets validated during driver creation, so pass it through
|
||||
config.driverHandleArenaSizeMB = config.driverHandleArenaSizeMB;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// these must be static because only a pointer is copied to the render stream
|
||||
// Note that these coordinates are specified in OpenGL clip space. Other backends can transform
|
||||
// these in the vertex shader as needed.
|
||||
@@ -217,24 +183,28 @@ static constexpr float4 sFullScreenTriangleVertices[3] = {
|
||||
// these must be static because only a pointer is copied to the render stream
|
||||
static const uint16_t sFullScreenTriangleIndices[3] = { 0, 1, 2 };
|
||||
|
||||
FEngine::FEngine(Backend backend, Platform* platform, const Config& config, void* sharedGLContext) :
|
||||
mBackend(backend),
|
||||
mPlatform(platform),
|
||||
mSharedGLContext(sharedGLContext),
|
||||
FEngine::FEngine(Engine::Builder const& builder) :
|
||||
mBackend(builder->mBackend),
|
||||
mPlatform(builder->mPlatform),
|
||||
mSharedGLContext(builder->mSharedContext),
|
||||
mPostProcessManager(*this),
|
||||
mEntityManager(EntityManager::get()),
|
||||
mRenderableManager(*this),
|
||||
mTransformManager(),
|
||||
mLightManager(*this),
|
||||
mCameraManager(*this),
|
||||
mCommandBufferQueue(config.minCommandBufferSizeMB * MiB, config.commandBufferSizeMB * MiB),
|
||||
mPerRenderPassAllocator("FEngine::mPerRenderPassAllocator", config.perRenderPassArenaSizeMB * MiB),
|
||||
mCommandBufferQueue(
|
||||
builder->mConfig.minCommandBufferSizeMB * MiB,
|
||||
builder->mConfig.commandBufferSizeMB * MiB),
|
||||
mPerRenderPassAllocator(
|
||||
"FEngine::mPerRenderPassAllocator",
|
||||
builder->mConfig.perRenderPassArenaSizeMB * MiB),
|
||||
mHeapAllocator("FEngine::mHeapAllocator", AreaPolicy::NullArea{}),
|
||||
mJobSystem(getJobSystemThreadPoolSize()),
|
||||
mEngineEpoch(std::chrono::steady_clock::now()),
|
||||
mDriverBarrier(1),
|
||||
mMainThreadId(ThreadUtils::getThreadId()),
|
||||
mConfig(config)
|
||||
mConfig(builder->mConfig)
|
||||
{
|
||||
// we're assuming we're on the main thread here.
|
||||
// (it may not be the case)
|
||||
@@ -411,8 +381,8 @@ void FEngine::shutdown() {
|
||||
|
||||
#ifndef NDEBUG
|
||||
// print out some statistics about this run
|
||||
size_t wm = mCommandBufferQueue.getHighWatermark();
|
||||
size_t wmpct = wm / (getCommandBufferSize() / 100);
|
||||
size_t const wm = mCommandBufferQueue.getHighWatermark();
|
||||
size_t const wmpct = wm / (getCommandBufferSize() / 100);
|
||||
slog.d << "CircularBuffer: High watermark "
|
||||
<< wm / 1024 << " KiB (" << wmpct << "%)" << io::endl;
|
||||
#endif
|
||||
@@ -637,7 +607,7 @@ int FEngine::loop() {
|
||||
JobSystem::setThreadName("FEngine::loop");
|
||||
JobSystem::setThreadPriority(JobSystem::Priority::DISPLAY);
|
||||
|
||||
DriverConfig driverConfig { .handleArenaSize = getRequestedDriverHandleArenaSize() };
|
||||
DriverConfig const driverConfig { .handleArenaSize = getRequestedDriverHandleArenaSize() };
|
||||
mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig);
|
||||
|
||||
mDriverBarrier.latch();
|
||||
@@ -651,7 +621,7 @@ int FEngine::loop() {
|
||||
// configuration. This is also a core not used by the JobSystem.
|
||||
// Either way the main reason to do this is to avoid this thread jumping from core to core
|
||||
// and lose its caches in the process.
|
||||
uint32_t id = std::thread::hardware_concurrency() - 1;
|
||||
uint32_t const id = std::thread::hardware_concurrency() - 1;
|
||||
|
||||
while (true) {
|
||||
// looks like thread affinity needs to be reset regularly (on Android)
|
||||
@@ -792,7 +762,7 @@ FView* FEngine::createView() noexcept {
|
||||
FFence* FEngine::createFence(FFence::Type type) noexcept {
|
||||
FFence* p = mHeapAllocator.make<FFence>(*this, type);
|
||||
if (p) {
|
||||
std::lock_guard guard(mFenceListLock);
|
||||
std::lock_guard const guard(mFenceListLock);
|
||||
mFences.insert(p);
|
||||
}
|
||||
return p;
|
||||
@@ -886,7 +856,7 @@ template<typename T>
|
||||
UTILS_ALWAYS_INLINE
|
||||
inline bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T>& list) {
|
||||
if (ptr == nullptr) return true;
|
||||
bool success = list.remove(ptr);
|
||||
bool const success = list.remove(ptr);
|
||||
|
||||
#if UTILS_HAS_RTTI
|
||||
auto typeName = CallStack::typeName<T>();
|
||||
@@ -908,7 +878,7 @@ UTILS_ALWAYS_INLINE
|
||||
inline bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* ptr, ResourceList<T>& list) {
|
||||
if (ptr == nullptr) return true;
|
||||
lock.lock();
|
||||
bool success = list.remove(ptr);
|
||||
bool const success = list.remove(ptr);
|
||||
lock.unlock();
|
||||
|
||||
#if UTILS_HAS_RTTI
|
||||
@@ -1058,7 +1028,6 @@ void* FEngine::streamAlloc(size_t size, size_t alignment) noexcept {
|
||||
}
|
||||
|
||||
bool FEngine::execute() {
|
||||
|
||||
// wait until we get command buffers to be executed (or thread exit requested)
|
||||
auto buffers = mCommandBufferQueue.waitForCommands();
|
||||
if (UTILS_UNLIKELY(buffers.empty())) {
|
||||
@@ -1100,4 +1069,86 @@ void FEngine::resetBackendState() noexcept {
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
Engine::Builder::Builder() noexcept = default;
|
||||
Engine::Builder::~Builder() noexcept = default;
|
||||
Engine::Builder::Builder(Engine::Builder const& rhs) noexcept = default;
|
||||
Engine::Builder::Builder(Engine::Builder&& rhs) noexcept = default;
|
||||
Engine::Builder& Engine::Builder::operator=(Engine::Builder const& rhs) noexcept = default;
|
||||
Engine::Builder& Engine::Builder::operator=(Engine::Builder&& rhs) noexcept = default;
|
||||
|
||||
Engine::Builder& Engine::Builder::backend(Backend backend) noexcept {
|
||||
mImpl->mBackend = backend;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Engine::Builder& Engine::Builder::platform(Platform* platform) noexcept {
|
||||
mImpl->mPlatform = platform;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Engine::Builder& Engine::Builder::config(Engine::Config const* config) noexcept {
|
||||
mImpl->mConfig = BuilderDetails::validateConfig(config);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Engine::Builder& Engine::Builder::sharedContext(void* sharedContext) noexcept {
|
||||
mImpl->mSharedContext = sharedContext;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
|
||||
void Engine::Builder::build(Invocable<void(void*)>&& callback) const {
|
||||
FEngine::create(*this, std::move(callback));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Engine* Engine::Builder::build() const {
|
||||
return FEngine::create(*this);
|
||||
}
|
||||
|
||||
Engine::Config Engine::BuilderDetails::validateConfig(const Config* const pConfig) noexcept {
|
||||
// Rule of thumb: perRenderPassArenaMB must be roughly 1 MB larger than perFrameCommandsMB
|
||||
constexpr uint32_t COMMAND_ARENA_OVERHEAD = 1;
|
||||
constexpr uint32_t CONCURRENT_FRAME_COUNT = 3;
|
||||
|
||||
Config config;
|
||||
if (!pConfig) {
|
||||
return config;
|
||||
}
|
||||
|
||||
// make sure to copy all the fields
|
||||
config = *pConfig;
|
||||
|
||||
// Use at least the defaults set by the build system
|
||||
config.minCommandBufferSizeMB = std::max(
|
||||
config.minCommandBufferSizeMB,
|
||||
(uint32_t)FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB);
|
||||
|
||||
config.perFrameCommandsSizeMB = std::max(
|
||||
config.perFrameCommandsSizeMB,
|
||||
(uint32_t)FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB);
|
||||
|
||||
config.perRenderPassArenaSizeMB = std::max(
|
||||
config.perRenderPassArenaSizeMB,
|
||||
(uint32_t)FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB);
|
||||
|
||||
config.commandBufferSizeMB = std::max(
|
||||
config.commandBufferSizeMB,
|
||||
config.minCommandBufferSizeMB * CONCURRENT_FRAME_COUNT);
|
||||
|
||||
// Enforce pre-render-pass arena rule-of-thumb
|
||||
config.perRenderPassArenaSizeMB = std::max(
|
||||
config.perRenderPassArenaSizeMB,
|
||||
config.perFrameCommandsSizeMB + COMMAND_ARENA_OVERHEAD);
|
||||
|
||||
// This value gets validated during driver creation, so pass it through
|
||||
config.driverHandleArenaSizeMB = config.driverHandleArenaSizeMB;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -120,16 +120,10 @@ public:
|
||||
using duration = clock::duration;
|
||||
|
||||
public:
|
||||
static FEngine* create(Backend backend = Backend::DEFAULT,
|
||||
Platform* platform = nullptr, void* sharedGLContext = nullptr,
|
||||
const Config* pConfig = nullptr);
|
||||
static Engine* create(Builder const& builder);
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
static void createAsync(CreateCallback callback, void* user,
|
||||
Backend backend = Backend::DEFAULT,
|
||||
Platform* platform = nullptr, void* sharedGLContext = nullptr,
|
||||
const Config* config = nullptr);
|
||||
|
||||
static void create(Builder const& builder, utils::Invocable<void(void* token)>&& callback);
|
||||
static FEngine* getEngine(void* token);
|
||||
#endif
|
||||
|
||||
@@ -385,9 +379,7 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
static Config validateConfig(const Config* pConfig) noexcept;
|
||||
|
||||
FEngine(Backend backend, Platform* platform, const Config& config, void* sharedGLContext);
|
||||
explicit FEngine(Engine::Builder const& builder);
|
||||
void init();
|
||||
void shutdown();
|
||||
|
||||
|
||||
@@ -640,7 +640,7 @@ TEST(FilamentTest, ColorConversion) {
|
||||
TEST(FilamentTest, FroxelData) {
|
||||
using namespace filament;
|
||||
|
||||
FEngine* engine = FEngine::create();
|
||||
FEngine* engine = downcast(Engine::create());
|
||||
|
||||
LinearAllocatorArena arena("FRenderer: per-frame allocator", 3 * 1024 * 1024);
|
||||
utils::ArenaScope<LinearAllocatorArena> scope(arena);
|
||||
|
||||
Reference in New Issue
Block a user