Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions package/cpp/core/RNFEngineImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "RNFEngineImpl.h"

#include "RNFEngineBackendEnum.h"
#include "RNFReferences.h"
#include "utils/RNFConverter.h"

Expand Down Expand Up @@ -392,4 +393,18 @@ void EngineImpl::flushAndWait() {
_engine->flushAndWait();
}

std::string EngineImpl::getBackend() {
std::string result;
EnumMapper::convertEnumToJSUnion(_engine->getBackend(), &result);
return result;
}

int EngineImpl::getSupportedFeatureLevel() {
return static_cast<int>(_engine->getSupportedFeatureLevel());
}

int EngineImpl::getActiveFeatureLevel() {
return static_cast<int>(_engine->getActiveFeatureLevel());
}

} // namespace margelo
5 changes: 5 additions & 0 deletions package/cpp/core/RNFEngineImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ class EngineImpl : public std::enable_shared_from_this<EngineImpl> {

void flushAndWait();

// Engine capability queries — thin wrappers around filament::Engine const getters.
std::string getBackend();
int getSupportedFeatureLevel();
int getActiveFeatureLevel();

private:
std::mutex _mutex;
std::shared_ptr<Engine> _engine;
Expand Down
12 changes: 12 additions & 0 deletions package/cpp/core/RNFEngineWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ void EngineWrapper::loadHybridMethods() {
registerHybridMethod("clearSkybox", &EngineWrapper::clearSkybox, this);
registerHybridMethod("setAutomaticInstancingEnabled", &EngineWrapper::setAutomaticInstancingEnabled, this);
registerHybridMethod("flushAndWait", &EngineWrapper::flushAndWait, this);
registerHybridMethod("getBackend", &EngineWrapper::getBackend, this);
registerHybridMethod("getSupportedFeatureLevel", &EngineWrapper::getSupportedFeatureLevel, this);
registerHybridMethod("getActiveFeatureLevel", &EngineWrapper::getActiveFeatureLevel, this);
}
void EngineWrapper::setSurfaceProvider(std::shared_ptr<SurfaceProvider> surfaceProvider) {
pointee()->setSurfaceProvider(surfaceProvider);
Expand Down Expand Up @@ -196,5 +199,14 @@ void EngineWrapper::setAutomaticInstancingEnabled(bool enabled) {
void EngineWrapper::flushAndWait() {
pointee()->flushAndWait();
}
std::string EngineWrapper::getBackend() {
return pointee()->getBackend();
}
int EngineWrapper::getSupportedFeatureLevel() {
return pointee()->getSupportedFeatureLevel();
}
int EngineWrapper::getActiveFeatureLevel() {
return pointee()->getActiveFeatureLevel();
}

} // namespace margelo
3 changes: 3 additions & 0 deletions package/cpp/core/RNFEngineWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class EngineWrapper : public PointerHolder<EngineImpl> {
void clearSkybox();
void setAutomaticInstancingEnabled(bool enabled);
void flushAndWait();
std::string getBackend();
int getSupportedFeatureLevel();
int getActiveFeatureLevel();

private:
static constexpr auto TAG = "EngineWrapper";
Expand Down
82 changes: 82 additions & 0 deletions package/docs/engine-info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Engine Backend & Feature Level Info

`react-native-filament` exposes three read-only getters from the underlying Filament engine that describe the GPU backend and its capabilities. These are useful for adaptive quality, diagnostics, and telemetry.

## API

### `engine.getBackend()`

Returns the resolved graphics backend as a string:

| Value | Meaning |
|-------|---------|
| `"metal"` | Apple Metal (default on iOS/macOS) |
| `"opengl"` | OpenGL ES (default on Android) |
| `"vulkan"` | Vulkan (opt-in on Android/Linux/Windows) |
| `"default"` | Should not appear at runtime -- the engine always resolves to a concrete backend |

### `engine.getSupportedFeatureLevel()`

Returns the highest feature level the device's GPU supports, as an integer `0`-`3`:

| Level | Capabilities |
|-------|-------------|
| `0` | OpenGL ES 2.0 features only |
| `1` | OpenGL ES 3.0 features (default on most modern devices) |
| `2` | OpenGL ES 3.1 + 16 texture units + cubemap arrays |
| `3` | OpenGL ES 3.1 + 31 texture units + cubemap arrays |

On iOS with Metal, devices typically report feature level `3`. On Android the level depends on the GPU -- budget GPUs may report `1`, while mid-range and flagship GPUs report `2` or `3`.

### `engine.getActiveFeatureLevel()`

Returns the currently active feature level. This equals the supported level unless a lower level was explicitly set via `Engine.Builder.featureLevel()`.

## Example: Adaptive Quality

```tsx
import { useFilamentContext } from 'react-native-filament';
import { useEffect } from 'react';

function AdaptiveScene() {
const { engine } = useFilamentContext();

useEffect(() => {
const backend = engine.getBackend();
const featureLevel = engine.getSupportedFeatureLevel();

console.log(`Backend: ${backend}, Feature Level: ${featureLevel}`);

// Use feature level as a GPU capability signal:
// Level 0-1: budget GPU -- use lower-poly models, fewer draw calls
// Level 2+: capable GPU -- enable full-quality rendering
}, [engine]);

return (
// ... your scene
);
}
```

## Example: Device Diagnostics Screen

```tsx
import { useFilamentContext } from 'react-native-filament';
import { Text, View } from 'react-native';

function DiagnosticsPanel() {
const { engine } = useFilamentContext();

return (
<View>
<Text>Backend: {engine.getBackend()}</Text>
<Text>Supported Feature Level: {engine.getSupportedFeatureLevel()}</Text>
<Text>Active Feature Level: {engine.getActiveFeatureLevel()}</Text>
</View>
);
}
```

## Background

Filament's C++ `Engine` class has always had `getBackend()`, `getSupportedFeatureLevel()`, and `getActiveFeatureLevel()` -- zero-cost const getters that return immediately. This change bridges them through the JSI layer so they are accessible from JavaScript, following the same `EngineImpl` -> `EngineWrapper` -> TypeScript pattern used by all other Engine methods.
49 changes: 49 additions & 0 deletions package/src/types/Engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,53 @@ export interface Engine extends PointerHolder {
* Note: during on screen rendering this is handled automatically, typically used for offscreen rendering (recording).
*/
flushAndWait(): void

/**
* Returns the resolved graphics backend as a string.
*
* On iOS this is typically `"metal"`, on Android `"opengl"` (or `"vulkan"` if explicitly
* selected). This returns the **actual** backend in use, even if `"default"` was requested
* at engine creation time.
*
* Useful for telemetry, diagnostics, and adaptive rendering decisions.
*
* @example
* ```ts
* const { engine } = useFilamentContext();
* console.log(engine.getBackend()); // "opengl" on most Android devices
* ```
*/
getBackend(): 'opengl' | 'vulkan' | 'metal' | 'default'

/**
* Returns the highest feature level supported by the device's GPU.
*
* Feature levels map to OpenGL ES capabilities:
* - `0` — OpenGL ES 2.0 features only
* - `1` — OpenGL ES 3.0 features (default on most modern devices)
* - `2` — OpenGL ES 3.1 + 16 texture units + cubemap arrays
* - `3` — OpenGL ES 3.1 + 31 texture units + cubemap arrays
*
* This is a useful GPU capability signal for adaptive quality decisions. A device
* supporting feature level 2+ has a meaningfully more capable GPU than one at level 0-1.
*
* @example
* ```ts
* const { engine } = useFilamentContext();
* const level = engine.getSupportedFeatureLevel();
* if (level >= 2) {
* // Enable higher-quality rendering options
* }
* ```
*/
getSupportedFeatureLevel(): 0 | 1 | 2 | 3

/**
* Returns the currently active feature level.
*
* This may differ from {@link getSupportedFeatureLevel} if a lower level was explicitly
* set via `Engine.Builder.featureLevel()`. By default the active level equals the
* supported level.
*/
getActiveFeatureLevel(): 0 | 1 | 2 | 3
}