Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d9bdcc008 | ||
|
|
b5c634045e | ||
|
|
1f05531d53 | ||
|
|
88f382f0e3 | ||
|
|
3e59925900 | ||
|
|
ea404f8d4f | ||
|
|
602a550d93 | ||
|
|
12abbe2d23 | ||
|
|
5fea428243 | ||
|
|
fb0ee97588 | ||
|
|
56ef48c9c3 | ||
|
|
47c3dd3dd1 | ||
|
|
9a3c9ccbf3 | ||
|
|
ef4dfcecd6 | ||
|
|
5943382d23 | ||
|
|
c181648bfa | ||
|
|
1dcf347b87 | ||
|
|
47714007f7 | ||
|
|
54277572d2 | ||
|
|
52f2c0e107 | ||
|
|
59abc8cc20 | ||
|
|
e15796b348 | ||
|
|
1711eaa4d6 | ||
|
|
acbd6a5ca8 | ||
|
|
775090fdda | ||
|
|
0915b86927 | ||
|
|
c10f7b01f4 | ||
|
|
84142ac506 | ||
|
|
ff190847a1 | ||
|
|
3ceec28189 | ||
|
|
481038152f | ||
|
|
60bd72730d |
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.12.9'
|
||||
implementation 'com.google.android.filament:filament-android:1.12.11'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -52,7 +52,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```
|
||||
pod 'Filament', '~> 1.12.9'
|
||||
pod 'Filament', '~> 1.12.11'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -3,7 +3,21 @@
|
||||
This file contains one line summaries of commits that are worthy of mentioning in release notes.
|
||||
A new header is inserted each time a *tag* is created.
|
||||
|
||||
## v1.12.9 (currently main branch)
|
||||
## v1.12.12 (currently main branch)
|
||||
|
||||
## v1.12.11
|
||||
|
||||
- Metal: Color grading performance improvement on M1 devices.
|
||||
- samples: Fix glitchy animation seen in gltf-viewer iOS sample.
|
||||
|
||||
## v1.12.10
|
||||
|
||||
- engine: rewrite dynamic resolution scaling controller for better accuracy and less jittering.
|
||||
- Java: fix missing ASTC texture enum.
|
||||
- tools: Fix normal map issues in mipgen.
|
||||
- WebGL: expose some `SurfaceOrientation` functions.
|
||||
|
||||
## v1.12.9
|
||||
|
||||
- engine: New API: `MultiSampleAntiAliasingOptions` and HDR-aware MSAA resolve. When `customResolve`
|
||||
is enabled, improves anti-aliasing quality [**NEW API**].
|
||||
|
||||
@@ -63,7 +63,7 @@ buildscript {
|
||||
'minSdk': 19,
|
||||
'targetSdk': 30,
|
||||
'compileSdk': 30,
|
||||
'kotlin': '1.5.30',
|
||||
'kotlin': '1.5.31',
|
||||
'buildTools': '30.0.3',
|
||||
'ndk': '22.1.7171670'
|
||||
]
|
||||
@@ -77,7 +77,7 @@ buildscript {
|
||||
]
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.0.2'
|
||||
classpath 'com.android.tools.build:gradle:7.0.3'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
|
||||
plugins {
|
||||
id 'groovy-gradle-plugin'
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
create("filament-tools-plugin") {
|
||||
id = "filament-tools-plugin"
|
||||
implementationClass = "FilamentToolsPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
@@ -18,21 +18,15 @@
|
||||
|
||||
#include "private/backend/VirtualMachineEnv.h"
|
||||
|
||||
namespace filament {
|
||||
extern jint JNI_OnLoad(JavaVM* vm, void* reserved);
|
||||
};
|
||||
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
JNIEnv* env;
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
::filament::JNI_OnLoad(vm, reserved);
|
||||
#else
|
||||
// This must be called when the library is loaded. We need this to get a reference to the
|
||||
// global VM
|
||||
::filament::VirtualMachineEnv::JNI_OnLoad(vm);
|
||||
#endif
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
@@ -107,12 +107,12 @@ public class Renderer {
|
||||
/**
|
||||
* Rate at which the scale will change to reach the target frame rate.
|
||||
*/
|
||||
public float scaleRate = 0.125f;
|
||||
public float scaleRate = 1.0f / 15.0f;
|
||||
|
||||
/**
|
||||
* History size. higher values, tend to filter more (clamped to 30).
|
||||
* History size. higher values, tend to filter more (clamped to 31).
|
||||
*/
|
||||
public int history = 9;
|
||||
public int history = 15;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -216,7 +216,38 @@ public class Texture {
|
||||
ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8,
|
||||
|
||||
// Available everywhere except Android/iOS
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA,
|
||||
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA,
|
||||
|
||||
// ASTC formats are available with a GLES extension
|
||||
RGBA_ASTC_4x4,
|
||||
RGBA_ASTC_5x4,
|
||||
RGBA_ASTC_5x5,
|
||||
RGBA_ASTC_6x5,
|
||||
RGBA_ASTC_6x6,
|
||||
RGBA_ASTC_8x5,
|
||||
RGBA_ASTC_8x6,
|
||||
RGBA_ASTC_8x8,
|
||||
RGBA_ASTC_10x5,
|
||||
RGBA_ASTC_10x6,
|
||||
RGBA_ASTC_10x8,
|
||||
RGBA_ASTC_10x10,
|
||||
RGBA_ASTC_12x10,
|
||||
RGBA_ASTC_12x12,
|
||||
SRGB8_ALPHA8_ASTC_4x4,
|
||||
SRGB8_ALPHA8_ASTC_5x4,
|
||||
SRGB8_ALPHA8_ASTC_5x5,
|
||||
SRGB8_ALPHA8_ASTC_6x5,
|
||||
SRGB8_ALPHA8_ASTC_6x6,
|
||||
SRGB8_ALPHA8_ASTC_8x5,
|
||||
SRGB8_ALPHA8_ASTC_8x6,
|
||||
SRGB8_ALPHA8_ASTC_8x8,
|
||||
SRGB8_ALPHA8_ASTC_10x5,
|
||||
SRGB8_ALPHA8_ASTC_10x6,
|
||||
SRGB8_ALPHA8_ASTC_10x8,
|
||||
SRGB8_ALPHA8_ASTC_10x10,
|
||||
SRGB8_ALPHA8_ASTC_12x10,
|
||||
SRGB8_ALPHA8_ASTC_12x12
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,7 +262,38 @@ public class Texture {
|
||||
ETC2_EAC_RGBA8, ETC2_EAC_SRGBA8,
|
||||
|
||||
// Available everywhere except Android/iOS
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA
|
||||
DXT1_RGB, DXT1_RGBA, DXT3_RGBA, DXT5_RGBA,
|
||||
DXT1_SRGB, DXT1_SRGBA, DXT3_SRGBA, DXT5_SRGBA,
|
||||
|
||||
// ASTC formats are available with a GLES extension
|
||||
RGBA_ASTC_4x4,
|
||||
RGBA_ASTC_5x4,
|
||||
RGBA_ASTC_5x5,
|
||||
RGBA_ASTC_6x5,
|
||||
RGBA_ASTC_6x6,
|
||||
RGBA_ASTC_8x5,
|
||||
RGBA_ASTC_8x6,
|
||||
RGBA_ASTC_8x8,
|
||||
RGBA_ASTC_10x5,
|
||||
RGBA_ASTC_10x6,
|
||||
RGBA_ASTC_10x8,
|
||||
RGBA_ASTC_10x10,
|
||||
RGBA_ASTC_12x10,
|
||||
RGBA_ASTC_12x12,
|
||||
SRGB8_ALPHA8_ASTC_4x4,
|
||||
SRGB8_ALPHA8_ASTC_5x4,
|
||||
SRGB8_ALPHA8_ASTC_5x5,
|
||||
SRGB8_ALPHA8_ASTC_6x5,
|
||||
SRGB8_ALPHA8_ASTC_6x6,
|
||||
SRGB8_ALPHA8_ASTC_8x5,
|
||||
SRGB8_ALPHA8_ASTC_8x6,
|
||||
SRGB8_ALPHA8_ASTC_8x8,
|
||||
SRGB8_ALPHA8_ASTC_10x5,
|
||||
SRGB8_ALPHA8_ASTC_10x6,
|
||||
SRGB8_ALPHA8_ASTC_10x8,
|
||||
SRGB8_ALPHA8_ASTC_10x10,
|
||||
SRGB8_ALPHA8_ASTC_12x10,
|
||||
SRGB8_ALPHA8_ASTC_12x12
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.12.9
|
||||
VERSION_NAME=1.12.11
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -17,7 +19,7 @@ android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
defaultConfig {
|
||||
applicationId "com.google.android.filament.hellocamera"
|
||||
minSdkVersion versions.minSdk
|
||||
minSdkVersion 23
|
||||
targetSdkVersion versions.targetSdk
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,9 @@ import android.graphics.ImageFormat
|
||||
import android.hardware.HardwareBuffer
|
||||
import android.media.ImageReader
|
||||
import android.opengl.Matrix
|
||||
import android.view.Display
|
||||
import android.os.Build
|
||||
import android.os.Looper
|
||||
import androidx.annotation.RequiresApi
|
||||
|
||||
import com.google.android.filament.*
|
||||
|
||||
@@ -44,7 +46,7 @@ import java.util.concurrent.TimeUnit
|
||||
* Toy class that handles all interaction with the Android camera2 API.
|
||||
* Sets the "textureTransform" and "videoTexture" parameters on the given Filament material.
|
||||
*/
|
||||
class CameraHelper(val activity: Activity, private val filamentEngine: Engine, private val filamentMaterial: MaterialInstance, private val display: Display) {
|
||||
class CameraHelper(val activity: Activity, private val filamentEngine: Engine, private val filamentMaterial: MaterialInstance) {
|
||||
private lateinit var cameraId: String
|
||||
private lateinit var captureRequest: CaptureRequest
|
||||
|
||||
@@ -63,6 +65,20 @@ class CameraHelper(val activity: Activity, private val filamentEngine: Engine, p
|
||||
kImageReaderMaxImages,
|
||||
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
|
||||
|
||||
@Suppress("deprecation")
|
||||
private val display = if (Build.VERSION.SDK_INT >= 30) {
|
||||
Api30Impl.getDisplay(activity)
|
||||
} else {
|
||||
activity.windowManager.defaultDisplay!!
|
||||
}
|
||||
|
||||
@RequiresApi(30)
|
||||
class Api30Impl {
|
||||
companion object {
|
||||
fun getDisplay(context: Context) = context.display!!
|
||||
}
|
||||
}
|
||||
|
||||
private val cameraCallback = object : CameraDevice.StateCallback() {
|
||||
override fun onOpened(cameraDevice: CameraDevice) {
|
||||
cameraOpenCloseLock.release()
|
||||
@@ -87,7 +103,9 @@ class CameraHelper(val activity: Activity, private val filamentEngine: Engine, p
|
||||
val stream = filamentStream
|
||||
if (stream != null) {
|
||||
imageReader.acquireLatestImage()?.also {
|
||||
stream.setAcquiredImage(it.hardwareBuffer, Handler()) { it.close() }
|
||||
stream.setAcquiredImage(it.hardwareBuffer, Handler(Looper.getMainLooper())) {
|
||||
it.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
|
||||
setupView()
|
||||
setupScene()
|
||||
|
||||
cameraHelper = CameraHelper(this, engine, materialInstance, windowManager.defaultDisplay)
|
||||
cameraHelper = CameraHelper(this, engine, materialInstance)
|
||||
cameraHelper.openCamera()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -14,5 +14,6 @@ android {
|
||||
|
||||
dependencies {
|
||||
implementation deps.kotlin
|
||||
implementation deps.androidx.annotations
|
||||
implementation project(':filament-android')
|
||||
}
|
||||
|
||||
@@ -18,19 +18,21 @@ package com.google.android.filament.livewallpaper
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.PixelFormat
|
||||
import android.os.Build
|
||||
import android.service.wallpaper.WallpaperService
|
||||
import android.view.Choreographer
|
||||
import android.view.Surface
|
||||
import android.view.SurfaceHolder
|
||||
import android.view.WindowManager
|
||||
import android.view.animation.LinearInterpolator
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.google.android.filament.*
|
||||
import com.google.android.filament.android.DisplayHelper
|
||||
import com.google.android.filament.android.UiHelper
|
||||
|
||||
|
||||
class FilamentLiveWallpaper : WallpaperService() {
|
||||
// Make sure to initialize Filament first
|
||||
// This loads the JNI library needed by most API calls
|
||||
@@ -196,9 +198,14 @@ class FilamentLiveWallpaper : WallpaperService() {
|
||||
override fun onNativeWindowChanged(surface: Surface) {
|
||||
swapChain?.let { engine.destroySwapChain(it) }
|
||||
swapChain = engine.createSwapChain(surface)
|
||||
val display =
|
||||
(application.getSystemService(Service.WINDOW_SERVICE) as WindowManager)
|
||||
.defaultDisplay
|
||||
|
||||
@Suppress("deprecation")
|
||||
val display = if (Build.VERSION.SDK_INT >= 30) {
|
||||
Api30Impl.getDisplay(displayContext!!)
|
||||
} else {
|
||||
(getSystemService(Service.WINDOW_SERVICE) as WindowManager).defaultDisplay
|
||||
}
|
||||
|
||||
displayHelper.attach(renderer, display)
|
||||
}
|
||||
|
||||
@@ -222,4 +229,11 @@ class FilamentLiveWallpaper : WallpaperService() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(30)
|
||||
class Api30Impl {
|
||||
companion object {
|
||||
fun getDisplay(context: Context) = context.display!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -17,7 +19,7 @@ android {
|
||||
compileSdkVersion versions.compileSdk
|
||||
defaultConfig {
|
||||
applicationId "com.google.android.filament.streamtest"
|
||||
minSdkVersion versions.minSdk
|
||||
minSdkVersion 23
|
||||
targetSdkVersion versions.targetSdk
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.google.android.filament.streamtest
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.Choreographer
|
||||
import android.view.Surface
|
||||
@@ -33,7 +34,9 @@ import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.channels.Channels
|
||||
import android.opengl.*
|
||||
import android.os.Build
|
||||
import android.view.MotionEvent
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.google.android.filament.android.DisplayHelper
|
||||
|
||||
|
||||
@@ -78,6 +81,13 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
|
||||
|
||||
private var externalTextureID: Int = 0
|
||||
|
||||
@RequiresApi(30)
|
||||
class Api30Impl {
|
||||
companion object {
|
||||
fun getDisplay(context: Context) = context.display!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@@ -94,7 +104,15 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
|
||||
setupScene()
|
||||
|
||||
externalTextureID = createExternalTexture()
|
||||
streamHelper = StreamHelper(engine, materialInstance, windowManager.defaultDisplay, externalTextureID)
|
||||
|
||||
@Suppress("deprecation")
|
||||
val display = if (Build.VERSION.SDK_INT >= 30) {
|
||||
Api30Impl.getDisplay(this)
|
||||
} else {
|
||||
windowManager.defaultDisplay!!
|
||||
}
|
||||
|
||||
streamHelper = StreamHelper(engine, materialInstance, display, externalTextureID)
|
||||
this.title = streamHelper.getTestName()
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.view.Surface
|
||||
import android.graphics.*
|
||||
import android.media.ImageReader
|
||||
import android.opengl.Matrix
|
||||
import android.os.Looper
|
||||
import android.view.Display
|
||||
|
||||
import com.google.android.filament.*
|
||||
@@ -32,7 +33,12 @@ import com.google.android.filament.*
|
||||
/**
|
||||
* Demonstrates Filament's various texture sharing mechanisms.
|
||||
*/
|
||||
class StreamHelper(private val filamentEngine: Engine, private val filamentMaterial: MaterialInstance, private val display: Display, private val externalTextureId: Int) {
|
||||
class StreamHelper(
|
||||
private val filamentEngine: Engine,
|
||||
private val filamentMaterial: MaterialInstance,
|
||||
private val display: Display,
|
||||
private val externalTextureId: Int
|
||||
) {
|
||||
/**
|
||||
* The StreamSource configures the source data for the texture.
|
||||
*
|
||||
@@ -50,7 +56,7 @@ class StreamHelper(private val filamentEngine: Engine, private val filamentMater
|
||||
}
|
||||
|
||||
private var streamSource = StreamSource.CANVAS_STREAM_NATIVE
|
||||
private val directImageHandler = Handler()
|
||||
private val directImageHandler = Handler(Looper.getMainLooper())
|
||||
private var resolution = Size(640, 480)
|
||||
private var surfaceTexture: SurfaceTexture? = null
|
||||
private var imageReader: ImageReader? = null
|
||||
@@ -93,11 +99,30 @@ class StreamHelper(private val filamentEngine: Engine, private val filamentMater
|
||||
val canvas = surface.lockCanvas(null)
|
||||
|
||||
val movingPaint = Paint()
|
||||
movingPaint.shader = LinearGradient(kGradientOffset, 0.0f, kGradientOffset + kGradientScale, 0.0f, kGradientColors, kGradientStops, Shader.TileMode.REPEAT)
|
||||
canvas.drawRect(Rect(0, resolution.height / 2, resolution.width, resolution.height), movingPaint)
|
||||
movingPaint.shader = LinearGradient(
|
||||
kGradientOffset,
|
||||
0.0f,
|
||||
kGradientOffset + kGradientScale,
|
||||
0.0f,
|
||||
kGradientColors,
|
||||
kGradientStops,
|
||||
Shader.TileMode.REPEAT
|
||||
)
|
||||
canvas.drawRect(
|
||||
Rect(0, resolution.height / 2, resolution.width, resolution.height),
|
||||
movingPaint
|
||||
)
|
||||
|
||||
val staticPaint = Paint()
|
||||
staticPaint.shader = LinearGradient(0.0f, 0.0f, kGradientScale, 0.0f, kGradientColors, kGradientStops, Shader.TileMode.REPEAT)
|
||||
staticPaint.shader = LinearGradient(
|
||||
0.0f,
|
||||
0.0f,
|
||||
kGradientScale,
|
||||
0.0f,
|
||||
kGradientColors,
|
||||
kGradientStops,
|
||||
Shader.TileMode.REPEAT
|
||||
)
|
||||
canvas.drawRect(Rect(0, 0, resolution.width, resolution.height / 2), staticPaint)
|
||||
|
||||
surface.unlockCanvasAndPost(canvas)
|
||||
@@ -108,7 +133,10 @@ class StreamHelper(private val filamentEngine: Engine, private val filamentMater
|
||||
|
||||
if (streamSource == StreamSource.CANVAS_STREAM_ACQUIRED) {
|
||||
val image = imageReader!!.acquireLatestImage()
|
||||
filamentStream!!.setAcquiredImage(image.hardwareBuffer!!, directImageHandler) { image.close() }
|
||||
filamentStream!!.setAcquiredImage(
|
||||
image.hardwareBuffer!!,
|
||||
directImageHandler
|
||||
) { image.close() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +164,9 @@ class StreamHelper(private val filamentEngine: Engine, private val filamentMater
|
||||
|
||||
val filamentTexture = this.filamentTexture!!
|
||||
|
||||
val sampler = TextureSampler(TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR, TextureSampler.WrapMode.REPEAT)
|
||||
val sampler = TextureSampler(
|
||||
TextureSampler.MinFilter.LINEAR, TextureSampler.MagFilter.LINEAR,
|
||||
TextureSampler.WrapMode.REPEAT)
|
||||
|
||||
// We are texturing a front-facing square shape so we need to generate a matrix that transforms (u, v, 0, 1)
|
||||
// into a new UV coordinate according to the screen rotation and the aspect ratio of the camera image.
|
||||
@@ -164,7 +194,8 @@ class StreamHelper(private val filamentEngine: Engine, private val filamentMater
|
||||
|
||||
// Connect the Stream to the Texture and the Texture to the MaterialInstance.
|
||||
filamentMaterial.setParameter("videoTexture", filamentTexture, sampler)
|
||||
filamentMaterial.setParameter("textureTransform", MaterialInstance.FloatElement.MAT4, textureTransform, 0, 1)
|
||||
filamentMaterial.setParameter("textureTransform",
|
||||
MaterialInstance.FloatElement.MAT4, textureTransform, 0, 1)
|
||||
|
||||
if (streamSource == StreamSource.CANVAS_STREAM_NATIVE) {
|
||||
|
||||
@@ -207,7 +238,9 @@ class StreamHelper(private val filamentEngine: Engine, private val filamentMater
|
||||
|
||||
filamentTexture.setExternalStream(filamentEngine, filamentStream!!)
|
||||
|
||||
this.imageReader = ImageReader.newInstance(resolution.width, resolution.height, ImageFormat.RGB_565, kImageReaderMaxImages).apply {
|
||||
this.imageReader = ImageReader.newInstance(
|
||||
resolution.width, resolution.height, ImageFormat.RGB_565, kImageReaderMaxImages
|
||||
).apply {
|
||||
canvasSurface = surface
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: FilamentToolsPlugin
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'filament-tools-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@ set(PRIVATE_HDRS
|
||||
src/Intersections.h
|
||||
src/MaterialParser.h
|
||||
src/PerViewUniforms.h
|
||||
src/PIDController.h
|
||||
src/PostProcessManager.h
|
||||
src/RenderPass.h
|
||||
src/RenderPrimitive.h
|
||||
|
||||
@@ -79,7 +79,7 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMEN
|
||||
include/private/backend/OpenGLPlatform.h
|
||||
)
|
||||
if (EGL)
|
||||
list(APPEND SRCS src/opengl/PlatformEGL.cpp)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformEGL.cpp)
|
||||
endif()
|
||||
if (ANDROID)
|
||||
# FIXME: this should be included when we build for JAVA (which is implied by ANDROID)
|
||||
@@ -87,22 +87,22 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMEN
|
||||
list(APPEND SRCS src/VirtualMachineEnv.cpp)
|
||||
endif ()
|
||||
if (ANDROID)
|
||||
list(APPEND SRCS src/android/ExternalStreamManagerAndroid.cpp)
|
||||
list(APPEND SRCS src/opengl/platforms/ExternalStreamManagerAndroid.cpp)
|
||||
list(APPEND SRCS src/android/ExternalTextureManagerAndroid.cpp)
|
||||
list(APPEND SRCS src/opengl/PlatformEGLAndroid.cpp)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformEGLAndroid.cpp)
|
||||
elseif (IOS)
|
||||
list(APPEND SRCS src/opengl/PlatformCocoaTouchGL.mm)
|
||||
list(APPEND SRCS src/opengl/CocoaTouchExternalImage.mm)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformCocoaTouchGL.mm)
|
||||
list(APPEND SRCS src/opengl/platforms/CocoaTouchExternalImage.mm)
|
||||
elseif (APPLE)
|
||||
list(APPEND SRCS src/opengl/PlatformCocoaGL.mm)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformCocoaGL.mm)
|
||||
elseif (WEBGL)
|
||||
list(APPEND SRCS src/opengl/PlatformWebGL.cpp)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformWebGL.cpp)
|
||||
elseif (LINUX)
|
||||
list(APPEND SRCS src/opengl/PlatformGLX.cpp)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformGLX.cpp)
|
||||
elseif (WIN32)
|
||||
list(APPEND SRCS src/opengl/PlatformWGL.cpp)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformWGL.cpp)
|
||||
else()
|
||||
list(APPEND SRCS src/opengl/PlatformDummyGL.cpp)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformDummyGL.cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -133,9 +133,9 @@ if (FILAMENT_SUPPORTS_METAL)
|
||||
# Objective-C++ sources need an additional compiler flag on iOS to disable exceptions.
|
||||
set_property(SOURCE
|
||||
${METAL_SRCS}
|
||||
src/opengl/PlatformCocoaTouchGL.mm
|
||||
src/opengl/CocoaTouchExternalImage.mm
|
||||
src/opengl/PlatformCocoaGL.mm
|
||||
src/opengl/platforms/PlatformCocoaTouchGL.mm
|
||||
src/opengl/platforms/CocoaTouchExternalImage.mm
|
||||
src/opengl/platforms/PlatformCocoaGL.mm
|
||||
PROPERTY COMPILE_FLAGS -fno-objc-exceptions)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -43,18 +43,6 @@ public:
|
||||
return env;
|
||||
}
|
||||
|
||||
VirtualMachineEnv() noexcept : mVirtualMachine(sVirtualMachine) {
|
||||
// We're not initializing the JVM here -- but we could -- because most of the time
|
||||
// we don't need the jvm. Instead we do the initialization on first use. This means we could get
|
||||
// a nasty slow down the very first time, but we'll live with it for now.
|
||||
}
|
||||
|
||||
~VirtualMachineEnv() {
|
||||
if (mVirtualMachine) {
|
||||
mVirtualMachine->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
inline JNIEnv* getEnvironment() noexcept {
|
||||
assert_invariant(mVirtualMachine);
|
||||
JNIEnv* env = mJniEnv;
|
||||
@@ -67,6 +55,18 @@ public:
|
||||
static void handleException(JNIEnv* env) noexcept;
|
||||
|
||||
private:
|
||||
VirtualMachineEnv() noexcept : mVirtualMachine(sVirtualMachine) {
|
||||
// We're not initializing the JVM here -- but we could -- because most of the time
|
||||
// we don't need the jvm. Instead we do the initialization on first use. This means we could get
|
||||
// a nasty slow down the very first time, but we'll live with it for now.
|
||||
}
|
||||
|
||||
~VirtualMachineEnv() {
|
||||
if (mVirtualMachine) {
|
||||
mVirtualMachine->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv* getEnvironmentSlow() noexcept;
|
||||
static JavaVM* sVirtualMachine;
|
||||
JNIEnv* mJniEnv = nullptr;
|
||||
|
||||
@@ -22,44 +22,44 @@
|
||||
#if defined(ANDROID)
|
||||
#include <sys/system_properties.h>
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#include "opengl/PlatformEGLAndroid.h"
|
||||
#include "opengl/platforms/PlatformEGLAndroid.h"
|
||||
#endif
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
#include "vulkan/PlatformVkAndroid.h"
|
||||
#endif
|
||||
#elif defined(IOS)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#include "opengl/PlatformCocoaTouchGL.h"
|
||||
#include "opengl/platforms/PlatformCocoaTouchGL.h"
|
||||
#endif
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
#include "vulkan/PlatformVkCocoaTouch.h"
|
||||
#endif
|
||||
#elif defined(__APPLE__)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) && !defined(FILAMENT_USE_SWIFTSHADER)
|
||||
#include "opengl/PlatformCocoaGL.h"
|
||||
#include "opengl/platforms/PlatformCocoaGL.h"
|
||||
#endif
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
#include "vulkan/PlatformVkCocoa.h"
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) && !defined(FILAMENT_USE_SWIFTSHADER)
|
||||
#include "opengl/PlatformGLX.h"
|
||||
#include "opengl/platforms/PlatformGLX.h"
|
||||
#endif
|
||||
#if defined (FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
#include "vulkan/PlatformVkLinux.h"
|
||||
#endif
|
||||
#elif defined(WIN32)
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3) && !defined(FILAMENT_USE_SWIFTSHADER)
|
||||
#include "opengl/PlatformWGL.h"
|
||||
#include "opengl/platforms/PlatformWGL.h"
|
||||
#endif
|
||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
||||
#include "vulkan/PlatformVkWindows.h"
|
||||
#endif
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#include "opengl/PlatformWebGL.h"
|
||||
#include "opengl/platforms/PlatformWebGL.h"
|
||||
#else
|
||||
#if defined(FILAMENT_SUPPORTS_OPENGL) && !defined(FILAMENT_USE_EXTERNAL_GLES3)
|
||||
#include "opengl/PlatformDummyGL.h"
|
||||
#include "opengl/platforms/PlatformDummyGL.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -84,9 +84,12 @@ struct EGLExternalTexture : public ExternalTextureManagerAndroid::ExternalTextur
|
||||
GraphicBufferWrapper* graphicBufferWrapper = nullptr;
|
||||
};
|
||||
|
||||
ExternalTextureManagerAndroid& ExternalTextureManagerAndroid::get() noexcept {
|
||||
static ExternalTextureManagerAndroid instance;
|
||||
return instance;
|
||||
ExternalTextureManagerAndroid& ExternalTextureManagerAndroid::create() noexcept {
|
||||
return *(new ExternalTextureManagerAndroid{});
|
||||
}
|
||||
|
||||
void ExternalTextureManagerAndroid::destroy(ExternalTextureManagerAndroid* pExternalTextureManager) noexcept {
|
||||
delete pExternalTextureManager;
|
||||
}
|
||||
|
||||
// called on gl thread
|
||||
@@ -116,7 +119,7 @@ ExternalTextureManagerAndroid::~ExternalTextureManagerAndroid() noexcept {
|
||||
}
|
||||
|
||||
// called on gl thread
|
||||
backend::Platform::ExternalTexture* ExternalTextureManagerAndroid::create() noexcept {
|
||||
backend::Platform::ExternalTexture* ExternalTextureManagerAndroid::createExternalTexture() noexcept {
|
||||
#ifndef PLATFORM_HAS_HARDWAREBUFFER
|
||||
if (!AHardwareBuffer_allocate) {
|
||||
// initialize java stuff on-demand
|
||||
|
||||
@@ -31,6 +31,15 @@
|
||||
|
||||
namespace filament {
|
||||
|
||||
/*
|
||||
* ExternalTextureManagerAndroid::ExternalTexture is basically a wrapper for AHardwareBuffer.
|
||||
*
|
||||
* This class doesn't rely on GL or EGL, and could be used for other Android platform if needed
|
||||
* (e.g. Vulkan).
|
||||
*
|
||||
* ExternalTextureManagerAndroid handle allocation/destruction using either Java or the NDK,
|
||||
* whichever is available.
|
||||
*/
|
||||
class ExternalTextureManagerAndroid {
|
||||
public:
|
||||
|
||||
@@ -39,26 +48,27 @@ public:
|
||||
AHardwareBuffer* hardwareBuffer = nullptr;
|
||||
};
|
||||
|
||||
static ExternalTextureManagerAndroid& get() noexcept;
|
||||
// must be called on backend thread
|
||||
static ExternalTextureManagerAndroid& create() noexcept;
|
||||
|
||||
// called on gl thread
|
||||
ExternalTextureManagerAndroid() noexcept;
|
||||
// must be called on backend thread
|
||||
static void destroy(ExternalTextureManagerAndroid* pExternalTextureManager) noexcept;
|
||||
|
||||
// not quite sure on which thread this is going to be called
|
||||
~ExternalTextureManagerAndroid() noexcept;
|
||||
|
||||
// called on gl thread
|
||||
backend::Platform::ExternalTexture* create() noexcept;
|
||||
// must be called on backend thread (only because we don't synchronize
|
||||
backend::Platform::ExternalTexture* createExternalTexture() noexcept;
|
||||
|
||||
// called on app thread
|
||||
void reallocate(
|
||||
backend::Platform::ExternalTexture* ets, uint32_t w, uint32_t h,
|
||||
backend::TextureFormat format, uint64_t usage) noexcept;
|
||||
|
||||
// called on gl thread
|
||||
// must be called on backend thread
|
||||
void destroy(backend::Platform::ExternalTexture* ets) noexcept;
|
||||
|
||||
private:
|
||||
ExternalTextureManagerAndroid() noexcept;
|
||||
~ExternalTextureManagerAndroid() noexcept;
|
||||
|
||||
// called on app thread
|
||||
void alloc(backend::Platform::ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, backend::TextureFormat format, uint64_t usage) noexcept;
|
||||
|
||||
@@ -64,16 +64,19 @@ MetalDriver::MetalDriver(backend::MetalPlatform* platform) noexcept
|
||||
|
||||
initializeSupportedGpuFamilies(mContext);
|
||||
|
||||
utils::slog.d << "Supported GPU families: " << utils::io::endl;
|
||||
utils::slog.v << "Supported GPU families: " << utils::io::endl;
|
||||
if (mContext->highestSupportedGpuFamily.common > 0) {
|
||||
utils::slog.d << " MTLGPUFamilyCommon" << (int) mContext->highestSupportedGpuFamily.common << utils::io::endl;
|
||||
utils::slog.v << " MTLGPUFamilyCommon" << (int) mContext->highestSupportedGpuFamily.common << utils::io::endl;
|
||||
}
|
||||
if (mContext->highestSupportedGpuFamily.apple > 0) {
|
||||
utils::slog.d << " MTLGPUFamilyApple" << (int) mContext->highestSupportedGpuFamily.apple << utils::io::endl;
|
||||
utils::slog.v << " MTLGPUFamilyApple" << (int) mContext->highestSupportedGpuFamily.apple << utils::io::endl;
|
||||
}
|
||||
if (mContext->highestSupportedGpuFamily.mac > 0) {
|
||||
utils::slog.d << " MTLGPUFamilyMac" << (int) mContext->highestSupportedGpuFamily.mac << utils::io::endl;
|
||||
utils::slog.v << " MTLGPUFamilyMac" << (int) mContext->highestSupportedGpuFamily.mac << utils::io::endl;
|
||||
}
|
||||
utils::slog.v << "Features:" << utils::io::endl;
|
||||
utils::slog.v << " readWriteTextureSupport: " <<
|
||||
(bool) mContext->device.readWriteTextureSupport << utils::io::endl;
|
||||
|
||||
// In order to support texture swizzling, the GPU needs to support it and the system be running
|
||||
// iOS 13+.
|
||||
@@ -650,11 +653,10 @@ bool MetalDriver::isRenderTargetFormatSupported(TextureFormat format) {
|
||||
}
|
||||
|
||||
bool MetalDriver::isFrameBufferFetchSupported() {
|
||||
#if defined(IOS) && !defined(FILAMENT_IOS_SIMULATOR)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
// FrameBuffer fetch is achievable via "programmable blending" in Metal, and only supported on
|
||||
// Apple GPUs with readWriteTextureSupport.
|
||||
return mContext->highestSupportedGpuFamily.apple >= 1 &&
|
||||
mContext->device.readWriteTextureSupport;
|
||||
}
|
||||
|
||||
bool MetalDriver::isFrameBufferFetchMultiSampleSupported() {
|
||||
|
||||
@@ -352,8 +352,7 @@ MetalProgram::MetalProgram(id<MTLDevice> device, const Program& program) noexcep
|
||||
length:source.size()
|
||||
encoding:NSUTF8StringEncoding];
|
||||
NSError* error = nil;
|
||||
MTLCompileOptions* options = [MTLCompileOptions new];
|
||||
options.languageVersion = MTLLanguageVersion1_1;
|
||||
// When options is nil, Metal uses the most recent language version available.
|
||||
id<MTLLibrary> library = [device newLibraryWithSource:objcSource
|
||||
options:nil
|
||||
error:&error];
|
||||
|
||||
@@ -75,6 +75,16 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
|
||||
// Figure out which driver bugs we need to workaround
|
||||
if (strstr(renderer, "Adreno")) {
|
||||
int maj, min, driverMajor, driverMinor;
|
||||
int c = sscanf(version, "OpenGL ES %d.%d V@%d.%d", // NOLINT(cert-err34-c)
|
||||
&maj, &min, &driverMajor, &driverMinor);
|
||||
if (c == 4) {
|
||||
// workarounds based on version here.
|
||||
// notes:
|
||||
// bugs.invalidate_end_only_if_invalidate_start
|
||||
// - appeared at least in "OpenGL ES 3.2 V@0490.0 (GIT@85da404, I46ff5fc46f, 1606794520) (Date:11/30/20)"
|
||||
// - wasn't present in "OpenGL ES 3.2 V@0490.0 (GIT@0905e9f, Ia11ce2d146, 1599072951) (Date:09/02/20)"
|
||||
}
|
||||
// On Adreno (As of 3/20) timer query seem to return the CPU time, not the GPU time.
|
||||
bugs.dont_use_timer_query = true;
|
||||
// Blits to texture arrays are failing
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef FILAMENT_DRIVER_OPENGL_COCOA_TOUCH_EXTERNAL_IMAGE
|
||||
#define FILAMENT_DRIVER_OPENGL_COCOA_TOUCH_EXTERNAL_IMAGE
|
||||
|
||||
#include "gl_headers.h"
|
||||
#include "../gl_headers.h"
|
||||
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <OpenGLES/ES3/gl.h>
|
||||
#include <OpenGLES/ES3/glext.h>
|
||||
|
||||
#include "GLUtils.h"
|
||||
#include "../GLUtils.h"
|
||||
|
||||
#include <math/vec2.h>
|
||||
|
||||
@@ -37,10 +37,12 @@ static void loadSymbol(T*& pfn, const char *symbol) noexcept {
|
||||
pfn = (T*)dlsym(RTLD_DEFAULT, symbol);
|
||||
}
|
||||
|
||||
ExternalStreamManagerAndroid& ExternalStreamManagerAndroid::get() noexcept {
|
||||
// declaring this thread local, will ensure it's destroyed with the calling thread
|
||||
static thread_local ExternalStreamManagerAndroid instance;
|
||||
return instance;
|
||||
ExternalStreamManagerAndroid& ExternalStreamManagerAndroid::create() noexcept {
|
||||
return *(new ExternalStreamManagerAndroid{});
|
||||
}
|
||||
|
||||
void ExternalStreamManagerAndroid::destroy(ExternalStreamManagerAndroid* pExternalStreamManagerAndroid) noexcept {
|
||||
delete pExternalStreamManagerAndroid;
|
||||
}
|
||||
|
||||
ExternalStreamManagerAndroid::ExternalStreamManagerAndroid() noexcept
|
||||
@@ -61,6 +63,8 @@ ExternalStreamManagerAndroid::ExternalStreamManagerAndroid() noexcept
|
||||
}
|
||||
}
|
||||
|
||||
ExternalStreamManagerAndroid::~ExternalStreamManagerAndroid() noexcept = default;
|
||||
|
||||
UTILS_NOINLINE
|
||||
JNIEnv* ExternalStreamManagerAndroid::getEnvironmentSlow() noexcept {
|
||||
JNIEnv * env = mVm.getEnvironment();
|
||||
@@ -31,20 +31,37 @@ typedef struct ASurfaceTexture ASurfaceTexture;
|
||||
|
||||
namespace filament {
|
||||
|
||||
/*
|
||||
* ExternalStreamManagerAndroid::Stream is basically a wrapper for SurfaceTexture.
|
||||
*
|
||||
* This class DOES DEPEND on having a GLES context, because that's how SurfaceTexture works.
|
||||
*/
|
||||
class ExternalStreamManagerAndroid {
|
||||
public:
|
||||
using Stream = backend::Platform::Stream;
|
||||
|
||||
ExternalStreamManagerAndroid() noexcept;
|
||||
static ExternalStreamManagerAndroid& get() noexcept;
|
||||
// must be called on GLES thread
|
||||
static ExternalStreamManagerAndroid& create() noexcept;
|
||||
|
||||
// must be called on GLES thread
|
||||
static void destroy(ExternalStreamManagerAndroid* pExternalStreamManagerAndroid) noexcept;
|
||||
|
||||
Stream* acquire(jobject surfaceTexture) noexcept;
|
||||
void release(Stream* stream) noexcept;
|
||||
|
||||
// attach Stream to current GLES context
|
||||
void attach(Stream* stream, intptr_t tname) noexcept;
|
||||
|
||||
// detach Stream to current GLES context
|
||||
void detach(Stream* stream) noexcept;
|
||||
|
||||
// must be called on GLES context thread, updates the stream content
|
||||
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept;
|
||||
|
||||
private:
|
||||
ExternalStreamManagerAndroid() noexcept;
|
||||
~ExternalStreamManagerAndroid() noexcept;
|
||||
|
||||
VirtualMachineEnv& mVm;
|
||||
JNIEnv* mJniEnv = nullptr;
|
||||
|
||||
@@ -63,17 +80,17 @@ private:
|
||||
|
||||
JNIEnv* getEnvironmentSlow() noexcept;
|
||||
|
||||
jmethodID mSurfaceTextureClass_updateTexImage;
|
||||
jmethodID mSurfaceTextureClass_getTimestamp;
|
||||
jmethodID mSurfaceTextureClass_attachToGLContext;
|
||||
jmethodID mSurfaceTextureClass_detachFromGLContext;
|
||||
jmethodID mSurfaceTextureClass_updateTexImage{};
|
||||
jmethodID mSurfaceTextureClass_getTimestamp{};
|
||||
jmethodID mSurfaceTextureClass_attachToGLContext{};
|
||||
jmethodID mSurfaceTextureClass_detachFromGLContext{};
|
||||
|
||||
ASurfaceTexture* (*ASurfaceTexture_fromSurfaceTexture)(JNIEnv*, jobject);
|
||||
void (*ASurfaceTexture_release)(ASurfaceTexture*);
|
||||
int (*ASurfaceTexture_attachToGLContext)(ASurfaceTexture*, uint32_t);
|
||||
int (*ASurfaceTexture_detachFromGLContext)(ASurfaceTexture*);
|
||||
int (*ASurfaceTexture_updateTexImage)(ASurfaceTexture*);
|
||||
int64_t (*ASurfaceTexture_getTimestamp)(ASurfaceTexture*); // available since api 28
|
||||
ASurfaceTexture* (*ASurfaceTexture_fromSurfaceTexture)(JNIEnv*, jobject){};
|
||||
void (*ASurfaceTexture_release)(ASurfaceTexture*){};
|
||||
int (*ASurfaceTexture_attachToGLContext)(ASurfaceTexture*, uint32_t){};
|
||||
int (*ASurfaceTexture_detachFromGLContext)(ASurfaceTexture*){};
|
||||
int (*ASurfaceTexture_updateTexImage)(ASurfaceTexture*){};
|
||||
int64_t (*ASurfaceTexture_getTimestamp)(ASurfaceTexture*){}; // available since api 28
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
#include "PlatformCocoaGL.h"
|
||||
|
||||
#include "OpenGLDriverFactory.h"
|
||||
#include "gl_headers.h"
|
||||
#include "opengl/OpenGLDriverFactory.h"
|
||||
#include "opengl/gl_headers.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Panic.h>
|
||||
@@ -30,9 +30,9 @@
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include "OpenGLDriverFactory.h"
|
||||
#include "../OpenGLDriverFactory.h"
|
||||
|
||||
#include "OpenGLDriver.h"
|
||||
#include "../OpenGLDriver.h"
|
||||
#include "CocoaTouchExternalImage.h"
|
||||
|
||||
namespace filament {
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
#include "PlatformEGL.h"
|
||||
|
||||
#include "OpenGLDriver.h"
|
||||
#include "OpenGLContext.h"
|
||||
#include "OpenGLDriverFactory.h"
|
||||
#include "opengl/OpenGLDriver.h"
|
||||
#include "opengl/OpenGLContext.h"
|
||||
#include "opengl/OpenGLDriverFactory.h"
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
#include "PlatformEGLAndroid.h"
|
||||
|
||||
#include "OpenGLDriver.h"
|
||||
#include "OpenGLContext.h"
|
||||
#include "opengl/OpenGLDriver.h"
|
||||
#include "opengl/OpenGLContext.h"
|
||||
|
||||
#include "android/ExternalTextureManagerAndroid.h"
|
||||
#include "android/ExternalStreamManagerAndroid.h"
|
||||
#include "ExternalStreamManagerAndroid.h"
|
||||
#include "private/backend/VirtualMachineEnv.h"
|
||||
|
||||
#include <android/api-level.h>
|
||||
@@ -73,8 +73,8 @@ using EGLStream = Platform::Stream;
|
||||
|
||||
PlatformEGLAndroid::PlatformEGLAndroid() noexcept
|
||||
: PlatformEGL(),
|
||||
mExternalStreamManager(ExternalStreamManagerAndroid::get()),
|
||||
mExternalTextureManager(ExternalTextureManagerAndroid::get()) {
|
||||
mExternalStreamManager(ExternalStreamManagerAndroid::create()),
|
||||
mExternalTextureManager(ExternalTextureManagerAndroid::create()) {
|
||||
|
||||
char scratch[PROP_VALUE_MAX + 1];
|
||||
int length = __system_property_get("ro.build.version.release", scratch);
|
||||
@@ -87,6 +87,15 @@ PlatformEGLAndroid::PlatformEGLAndroid() noexcept
|
||||
}
|
||||
}
|
||||
|
||||
PlatformEGLAndroid::~PlatformEGLAndroid() noexcept = default;
|
||||
|
||||
|
||||
void PlatformEGLAndroid::terminate() noexcept {
|
||||
ExternalStreamManagerAndroid::destroy(&mExternalStreamManager);
|
||||
ExternalTextureManagerAndroid::destroy(&mExternalTextureManager);
|
||||
PlatformEGL::terminate();
|
||||
}
|
||||
|
||||
Driver* PlatformEGLAndroid::createDriver(void* sharedContext) noexcept {
|
||||
Driver* driver = PlatformEGL::createDriver(sharedContext);
|
||||
auto extensions = GLUtils::split(eglQueryString(mEGLDisplay, EGL_EXTENSIONS));
|
||||
@@ -146,7 +155,7 @@ void PlatformEGLAndroid::updateTexImage(Stream* stream, int64_t* timestamp) noex
|
||||
}
|
||||
|
||||
Platform::ExternalTexture* PlatformEGLAndroid::createExternalTextureStorage() noexcept {
|
||||
return mExternalTextureManager.create();
|
||||
return mExternalTextureManager.createExternalTexture();
|
||||
}
|
||||
|
||||
void PlatformEGLAndroid::reallocateExternalStorage(
|
||||
@@ -236,11 +245,6 @@ AcquiredImage PlatformEGLAndroid::transformAcquiredImage(AcquiredImage source) n
|
||||
return { eglImage, patchedCallback, closure, source.handler };
|
||||
}
|
||||
|
||||
// This must be called when the library is loaded. We need this to get a reference to the global VM
|
||||
void JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
::filament::VirtualMachineEnv::JNI_OnLoad(vm);
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
@@ -28,6 +28,9 @@ class PlatformEGLAndroid final : public PlatformEGL {
|
||||
public:
|
||||
|
||||
PlatformEGLAndroid() noexcept;
|
||||
~PlatformEGLAndroid() noexcept override;
|
||||
|
||||
void terminate() noexcept override;
|
||||
|
||||
backend::Driver* createDriver(void* sharedContext) noexcept final;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <GL/glx.h>
|
||||
#include <GL/glxext.h>
|
||||
|
||||
#include "OpenGLDriverFactory.h"
|
||||
#include "../OpenGLDriverFactory.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#include <Wingdi.h>
|
||||
|
||||
#include "OpenGLDriverFactory.h"
|
||||
#include "../OpenGLDriverFactory.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// this variable is checked in BlueGL.h (included from "gl_headers.h" right after this),
|
||||
@@ -27,7 +27,7 @@
|
||||
#define FILAMENT_PLATFORM_WGL
|
||||
#endif
|
||||
|
||||
#include "gl_headers.h"
|
||||
#include "../gl_headers.h"
|
||||
|
||||
#include "Windows.h"
|
||||
#include <GL/gl.h>
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "PlatformWebGL.h"
|
||||
#include "OpenGLDriverFactory.h"
|
||||
#include "../OpenGLDriverFactory.h"
|
||||
|
||||
namespace filament {
|
||||
|
||||
@@ -54,18 +54,6 @@ public:
|
||||
Type type; //!< property type
|
||||
};
|
||||
|
||||
struct PropertyArray {
|
||||
Property const* array;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Queries the list of all available properties.
|
||||
*
|
||||
* @return A pair containing a pointer to a Property array and the size of this array.
|
||||
*/
|
||||
PropertyArray getProperties() const noexcept;
|
||||
|
||||
/**
|
||||
* Queries whether a property exists
|
||||
* @param name The name of the property to query
|
||||
@@ -123,6 +111,24 @@ public:
|
||||
bool getProperty(const char* name, math::float4* v) const noexcept;
|
||||
/** @}*/
|
||||
|
||||
struct DataSource {
|
||||
void const* data;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
DataSource getDataSource(const char* name) const noexcept;
|
||||
|
||||
struct FrameHistory {
|
||||
using duration_ms = float;
|
||||
duration_ms target{};
|
||||
duration_ms targetWithHeadroom{};
|
||||
duration_ms frameTime{};
|
||||
duration_ms frameTimeDenoised{};
|
||||
float scale = 1.0f;
|
||||
float pid_e = 0.0f;
|
||||
float pid_i = 0.0f;
|
||||
float pid_d = 0.0f;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
* headRoomRatio: additional headroom for the GPU as a ratio of the targetFrameTime.
|
||||
* Useful for taking into account constant costs like post-processing or
|
||||
* GPU drivers on different platforms.
|
||||
* history: History size. higher values, tend to filter more (clamped to 30)
|
||||
* history: History size. higher values, tend to filter more (clamped to 31)
|
||||
* scaleRate: rate at which the gpu load is adjusted to reach the target frame rate
|
||||
* This value can be computed as 1 / N, where N is the number of frames
|
||||
* needed to reach 64% of the target scale factor.
|
||||
@@ -110,10 +110,10 @@ public:
|
||||
*
|
||||
*/
|
||||
struct FrameRateOptions {
|
||||
float headRoomRatio = 0.0f; //!< additional headroom for the GPU
|
||||
float scaleRate = 0.125f; //!< rate at which the system reacts to load changes
|
||||
uint8_t history = 3; //!< history size
|
||||
uint8_t interval = 1; //!< desired frame interval in unit of 1.0 / DisplayInfo::refreshRate
|
||||
float headRoomRatio = 0.0f; //!< additional headroom for the GPU
|
||||
float scaleRate = 1.0f / 8.0f; //!< rate at which the system reacts to load changes
|
||||
uint8_t history = 15; //!< history size
|
||||
uint8_t interval = 1; //!< desired frame interval in unit of 1.0 / DisplayInfo::refreshRate
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,9 +31,7 @@ using namespace utils;
|
||||
|
||||
namespace filament {
|
||||
|
||||
FDebugRegistry::FDebugRegistry() noexcept {
|
||||
mProperties.reserve(8);
|
||||
}
|
||||
FDebugRegistry::FDebugRegistry() noexcept = default;
|
||||
|
||||
UTILS_NOINLINE
|
||||
void *FDebugRegistry::getPropertyAddress(const char *name) noexcept {
|
||||
@@ -48,15 +46,10 @@ void *FDebugRegistry::getPropertyAddress(const char *name) noexcept {
|
||||
void FDebugRegistry::registerProperty(utils::StaticString name, void *p, Type type) noexcept {
|
||||
auto& propertyMap = mPropertyMap;
|
||||
if (propertyMap.find(name) == propertyMap.end()) {
|
||||
mProperties.push_back({ name.c_str(), type });
|
||||
propertyMap[name] = p;
|
||||
}
|
||||
}
|
||||
|
||||
DebugRegistry::PropertyArray FDebugRegistry::getProperties() const noexcept {
|
||||
return {mProperties.data(), mProperties.size()};
|
||||
}
|
||||
|
||||
inline bool FDebugRegistry::hasProperty(const char *name) const noexcept {
|
||||
return const_cast<FDebugRegistry *>(this)->getPropertyAddress(name) != nullptr;
|
||||
}
|
||||
@@ -83,14 +76,27 @@ inline bool FDebugRegistry::getProperty(const char* name, T* UTILS_RESTRICT p) c
|
||||
return false;
|
||||
}
|
||||
|
||||
void FDebugRegistry::registerDataSource(StaticString name, void const* data, size_t count) noexcept {
|
||||
auto& dataSourceMap = mDataSourceMap;
|
||||
if (dataSourceMap.find(name) == dataSourceMap.end()) {
|
||||
dataSourceMap[name] = { data, count };
|
||||
}
|
||||
}
|
||||
|
||||
DebugRegistry::DataSource FDebugRegistry::getDataSource(const char* name) const noexcept {
|
||||
StaticString key = StaticString::make(name, strlen(name));
|
||||
auto &dataSourceMap = mDataSourceMap;
|
||||
auto const& it = dataSourceMap.find(key);
|
||||
if (it == dataSourceMap.end()) {
|
||||
return { nullptr, 0u };
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Trampoline calling into private implementation
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
DebugRegistry::PropertyArray DebugRegistry::getProperties() const noexcept {
|
||||
return upcast(this)->getProperties();
|
||||
}
|
||||
|
||||
bool DebugRegistry::hasProperty(const char* name) const noexcept {
|
||||
return upcast(this)->hasProperty(name);
|
||||
}
|
||||
@@ -148,5 +154,10 @@ void *DebugRegistry::getPropertyAddress(const char *name) noexcept {
|
||||
return upcast(this)->getPropertyAddress(name);
|
||||
}
|
||||
|
||||
DebugRegistry::DataSource DebugRegistry::getDataSource(const char* name) const noexcept {
|
||||
return upcast(this)->getDataSource(name);
|
||||
}
|
||||
|
||||
|
||||
} // namespace filament
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
#include <cmath>
|
||||
|
||||
namespace filament {
|
||||
|
||||
using namespace utils;
|
||||
using namespace backend;
|
||||
|
||||
// this is to avoid a call to memmove
|
||||
template<class InputIterator, class OutputIterator>
|
||||
@@ -35,8 +37,7 @@ void move_backward(InputIterator first, InputIterator last, OutputIterator resul
|
||||
}
|
||||
}
|
||||
|
||||
FrameInfoManager::FrameInfoManager(FEngine& engine) : mEngine(engine) {
|
||||
backend::DriverApi& driver = mEngine.getDriverApi();
|
||||
FrameInfoManager::FrameInfoManager(DriverApi& driver) noexcept {
|
||||
for (auto& query : mQueries) {
|
||||
query = driver.createTimerQuery();
|
||||
}
|
||||
@@ -44,15 +45,13 @@ FrameInfoManager::FrameInfoManager(FEngine& engine) : mEngine(engine) {
|
||||
|
||||
FrameInfoManager::~FrameInfoManager() noexcept = default;
|
||||
|
||||
void FrameInfoManager::terminate() {
|
||||
backend::DriverApi& driver = mEngine.getDriverApi();
|
||||
void FrameInfoManager::terminate(DriverApi& driver) noexcept {
|
||||
for (auto& query : mQueries) {
|
||||
driver.destroyTimerQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
void FrameInfoManager::beginFrame(Config const& config, uint32_t frameId) {
|
||||
backend::DriverApi& driver = mEngine.getDriverApi();
|
||||
void FrameInfoManager::beginFrame(DriverApi& driver,Config const& config, uint32_t frameId) noexcept {
|
||||
driver.beginTimerQuery(mQueries[mIndex]);
|
||||
uint64_t elapsed = 0;
|
||||
if (driver.getTimerQueryValue(mQueries[mLast], &elapsed)) {
|
||||
@@ -60,16 +59,15 @@ void FrameInfoManager::beginFrame(Config const& config, uint32_t frameId) {
|
||||
// conversion to our duration happens here
|
||||
mFrameTime = std::chrono::duration<uint64_t, std::nano>(elapsed);
|
||||
}
|
||||
update(config,mFrameTime);
|
||||
update(config, mFrameTime);
|
||||
}
|
||||
|
||||
void FrameInfoManager::endFrame() {
|
||||
backend::DriverApi& driver = mEngine.getDriverApi();
|
||||
void FrameInfoManager::endFrame(DriverApi& driver) noexcept {
|
||||
driver.endTimerQuery(mQueries[mIndex]);
|
||||
mIndex = (mIndex + 1) % POOL_COUNT;
|
||||
}
|
||||
|
||||
void FrameInfoManager::update(Config const& config, FrameInfoManager::duration lastFrameTime) {
|
||||
void FrameInfoManager::update(Config const& config, FrameInfoManager::duration lastFrameTime) noexcept {
|
||||
// keep an history of frame times
|
||||
auto& history = mFrameTimeHistory;
|
||||
|
||||
@@ -95,34 +93,7 @@ void FrameInfoManager::update(Config const& config, FrameInfoManager::duration l
|
||||
duration denoisedFrameTime = median[size / 2];
|
||||
|
||||
history[0].denoisedFrameTime = denoisedFrameTime;
|
||||
|
||||
// how much we need to scale the current workload to fit in our target, at this instant
|
||||
const duration targetWithHeadroom = config.targetFrameTime * (1.0f - config.headRoomRatio);
|
||||
const duration measured = denoisedFrameTime;
|
||||
|
||||
// We use a P.I.D. controller below to figure out the scaling factor to apply. In practice, we
|
||||
// don't use the Derivative gain (so it's really a PI controller).
|
||||
const float Kp = (1.0f - std::exp(-config.oneOverTau));
|
||||
const float Ki = Kp / 10.0f;
|
||||
const float Kd = 0.0f;
|
||||
|
||||
history[0].pid.error = (targetWithHeadroom - measured) / targetWithHeadroom;
|
||||
history[0].pid.integral = history[1].pid.integral + Ki * history[0].pid.error;
|
||||
history[0].pid.integral = math::clamp(history[0].pid.integral, -6.0f, 2.0f);
|
||||
|
||||
const float derivative = Kd * (history[0].pid.error - history[1].pid.error);
|
||||
const float out = Kp * history[0].pid.error + history[0].pid.integral + derivative;
|
||||
|
||||
// maps the command to a ratio, it really doesn't matter much how the conversion is done
|
||||
// the system will find the right value automatically
|
||||
const float scale = std::exp2(out);
|
||||
history[0].scale = scale;
|
||||
history[0].valid = true;
|
||||
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_VALUE32("info_e", history[0].pid.error * 100);
|
||||
SYSTRACE_VALUE32("info_s", scale * 100);
|
||||
// slog.d << history[0].pid.error * 100 << "%, " << scale << io::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
#ifndef TNT_FILAMENT_FRAMEINFO_H
|
||||
#define TNT_FILAMENT_FRAMEINFO_H
|
||||
|
||||
#include "details/Engine.h"
|
||||
|
||||
#include "backend/Handle.h"
|
||||
#include <private/backend/DriverApi.h>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
@@ -30,38 +29,35 @@ namespace filament {
|
||||
class FEngine;
|
||||
|
||||
struct FrameInfo {
|
||||
using duration = std::chrono::duration<float>;
|
||||
using duration = std::chrono::duration<float, std::milli>;
|
||||
duration frameTime{}; // frame period
|
||||
duration denoisedFrameTime{}; // frame period (median filter)
|
||||
bool valid = false;
|
||||
float scale = 1.0f;
|
||||
struct {
|
||||
float integral{};
|
||||
float error{};
|
||||
} pid;
|
||||
};
|
||||
|
||||
class FrameInfoManager {
|
||||
static constexpr size_t POOL_COUNT = 8;
|
||||
static constexpr size_t MAX_FRAMETIME_HISTORY = 32u;
|
||||
static constexpr size_t POOL_COUNT = 4;
|
||||
static constexpr size_t MAX_FRAMETIME_HISTORY = 31u;
|
||||
|
||||
public:
|
||||
using duration = FrameInfo::duration;
|
||||
|
||||
struct Config {
|
||||
duration targetFrameTime;
|
||||
float headRoomRatio;
|
||||
float oneOverTau;
|
||||
uint32_t historySize;
|
||||
};
|
||||
|
||||
explicit FrameInfoManager(FEngine& engine);
|
||||
~FrameInfoManager() noexcept;
|
||||
void terminate();
|
||||
void beginFrame(Config const& config, uint32_t frameId); // call this immediately after "make current"
|
||||
void endFrame(); // call this immediately before "swap buffers"
|
||||
explicit FrameInfoManager(backend::DriverApi& driver) noexcept;
|
||||
|
||||
FrameInfo const& getLastFrameInfo() const {
|
||||
~FrameInfoManager() noexcept;
|
||||
void terminate(backend::DriverApi& driver) noexcept;
|
||||
|
||||
// call this immediately after "make current"
|
||||
void beginFrame(backend::DriverApi& driver, Config const& config, uint32_t frameId) noexcept;
|
||||
|
||||
// call this immediately before "swap buffers"
|
||||
void endFrame(backend::DriverApi& driver) noexcept;
|
||||
|
||||
FrameInfo const& getLastFrameInfo() const noexcept {
|
||||
return mFrameTimeHistory[0];
|
||||
}
|
||||
|
||||
@@ -69,10 +65,8 @@ public:
|
||||
return getLastFrameInfo().frameTime;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void update(Config const& config, duration lastFrameTime);
|
||||
FEngine& mEngine;
|
||||
void update(Config const& config, duration lastFrameTime) noexcept;
|
||||
backend::Handle<backend::HwTimerQuery> mQueries[POOL_COUNT];
|
||||
duration mFrameTime{};
|
||||
uint32_t mIndex = 0;
|
||||
|
||||
@@ -26,13 +26,14 @@ namespace filament {
|
||||
using namespace utils;
|
||||
using namespace backend;
|
||||
|
||||
FrameSkipper::FrameSkipper(FEngine& engine, size_t latency) noexcept
|
||||
: mEngine(engine), mLast(latency) {
|
||||
FrameSkipper::FrameSkipper(size_t latency) noexcept
|
||||
: mLast(latency) {
|
||||
assert_invariant(latency <= MAX_FRAME_LATENCY);
|
||||
}
|
||||
|
||||
FrameSkipper::~FrameSkipper() noexcept {
|
||||
auto& driver = mEngine.getDriverApi();
|
||||
FrameSkipper::~FrameSkipper() noexcept = default;
|
||||
|
||||
void FrameSkipper::terminate(DriverApi& driver) noexcept {
|
||||
for (auto sync : mDelayedSyncs) {
|
||||
if (sync) {
|
||||
driver.destroySync(sync);
|
||||
@@ -40,8 +41,7 @@ FrameSkipper::~FrameSkipper() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
bool FrameSkipper::beginFrame() noexcept {
|
||||
auto& driver = mEngine.getDriverApi();
|
||||
bool FrameSkipper::beginFrame(DriverApi& driver) noexcept {
|
||||
auto& syncs = mDelayedSyncs;
|
||||
auto sync = syncs.front();
|
||||
if (sync) {
|
||||
@@ -58,11 +58,10 @@ bool FrameSkipper::beginFrame() noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
void FrameSkipper::endFrame() noexcept {
|
||||
void FrameSkipper::endFrame(DriverApi& driver) noexcept {
|
||||
// if the user produced a new frame despite the fact that the previous one wasn't finished
|
||||
// (i.e. FrameSkipper::beginFrame() returned false), we need to make sure to replace
|
||||
// a fence that might be here already)
|
||||
auto& driver = mEngine.getDriverApi();
|
||||
auto& sync = mDelayedSyncs[mLast];
|
||||
if (sync) {
|
||||
driver.destroySync(sync);
|
||||
|
||||
@@ -18,28 +18,28 @@
|
||||
#define TNT_FILAMENT_DETAILS_FRAMESKIPPER_H
|
||||
|
||||
#include <backend/Handle.h>
|
||||
#include <private/backend/DriverApi.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace filament {
|
||||
|
||||
class FEngine;
|
||||
|
||||
class FrameSkipper {
|
||||
static constexpr size_t MAX_FRAME_LATENCY = 4;
|
||||
public:
|
||||
explicit FrameSkipper(FEngine& engine, size_t latency = 2) noexcept;
|
||||
explicit FrameSkipper(size_t latency = 2) noexcept;
|
||||
~FrameSkipper() noexcept;
|
||||
|
||||
void terminate(backend::DriverApi& driver) noexcept;
|
||||
|
||||
// returns false if we need to skip this frame, because the gpu is running behind the cpu.
|
||||
// in that case, don't call endFrame().
|
||||
// returns true if rendering can proceed. Always call endFrame() when done.
|
||||
bool beginFrame() noexcept;
|
||||
bool beginFrame(backend::DriverApi& driver) noexcept;
|
||||
|
||||
void endFrame() noexcept;
|
||||
void endFrame(backend::DriverApi& driver) noexcept;
|
||||
|
||||
private:
|
||||
FEngine& mEngine;
|
||||
using Container = std::array<backend::Handle<backend::HwSync>, MAX_FRAME_LATENCY>;
|
||||
mutable Container mDelayedSyncs{};
|
||||
size_t mLast;
|
||||
|
||||
128
filament/src/PIDController.h
Normal file
128
filament/src/PIDController.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_PIDCONTROLLER_H
|
||||
#define TNT_FILAMENT_PIDCONTROLLER_H
|
||||
|
||||
#include <math/scalar.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace filament {
|
||||
|
||||
class PIDController {
|
||||
public:
|
||||
PIDController() noexcept = default;
|
||||
|
||||
void setStandardGains(float Kp, float Ti, float Td) noexcept {
|
||||
mKp = Kp;
|
||||
mKi = Kp / Ti;
|
||||
mKd = Kp * Td;
|
||||
}
|
||||
|
||||
void setParallelGains(float Kp, float Ki, float Kd) noexcept {
|
||||
mKp = Kp;
|
||||
mKi = Ki;
|
||||
mKd = Kd;
|
||||
}
|
||||
|
||||
// output is kept steady in the dead band
|
||||
void setOutputDeadBand(float low, float high) noexcept {
|
||||
mDeadBandLow = low;
|
||||
mDeadBandHigh = high;
|
||||
}
|
||||
|
||||
// integral bounds to prevent windup
|
||||
void setIntegralLimits(float low, float high) noexcept {
|
||||
mIntegralLimitLow = low;
|
||||
mIntegralLimitHigh = high;
|
||||
}
|
||||
|
||||
// output bounds
|
||||
void setOutputLimits(float low, float high) noexcept {
|
||||
mOutputLimitLow = low;
|
||||
mOutputLimitHigh = high;
|
||||
}
|
||||
|
||||
// disable integral term to prevent windup
|
||||
void setIntegralInhibitionEnabled(bool enabled) noexcept {
|
||||
mIntegralInhibition = enabled ? 0.0f : 1.0f;
|
||||
}
|
||||
|
||||
// update PID output
|
||||
float update(float measure, float target, float dt) const noexcept {
|
||||
// compute error
|
||||
const float error = target - measure;
|
||||
|
||||
// compute error integration
|
||||
float integral = mIntegral + error * mIntegralInhibition * dt;
|
||||
|
||||
// compute derivative
|
||||
const float derivative = (error - mLastError) / dt;
|
||||
|
||||
// prevent integral windup
|
||||
integral = math::clamp(integral, mIntegralLimitLow, mIntegralLimitHigh);
|
||||
|
||||
// PID controller output
|
||||
float out = mKp * error + mKi * integral + mKd * derivative;
|
||||
|
||||
// Apply dead band
|
||||
if (out > mDeadBandLow && out < mDeadBandHigh) {
|
||||
out = 0.0f;
|
||||
}
|
||||
|
||||
// Apply output limits
|
||||
out = math::clamp(out, mOutputLimitLow, mOutputLimitHigh);
|
||||
|
||||
// save state for next round
|
||||
mIntegral = integral;
|
||||
mLastError = error;
|
||||
mDerivative = derivative;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
float getError() const noexcept {
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
float getIntegral() const noexcept {
|
||||
return mIntegral;
|
||||
}
|
||||
|
||||
float getDerivative() const noexcept {
|
||||
return mDerivative;
|
||||
}
|
||||
|
||||
private:
|
||||
float mKp = 0.1f;
|
||||
float mKi = 0.0f;
|
||||
float mKd = 0.0f;
|
||||
float mIntegralInhibition = 1.0f;
|
||||
float mIntegralLimitLow = -std::numeric_limits<float>::infinity();
|
||||
float mIntegralLimitHigh = std::numeric_limits<float>::infinity();
|
||||
float mOutputLimitLow = -std::numeric_limits<float>::infinity();
|
||||
float mOutputLimitHigh = std::numeric_limits<float>::infinity();
|
||||
float mDeadBandLow = 0.0f;
|
||||
float mDeadBandHigh = 0.0f;
|
||||
mutable float mLastError = 0.0f;
|
||||
mutable float mIntegral = 0.0f;
|
||||
mutable float mDerivative = 0.0f;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_FILAMENT_PIDCONTROLLER_H
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "details/Renderer.h"
|
||||
|
||||
#include "PostProcessManager.h"
|
||||
#include "RenderPass.h"
|
||||
#include "ResourceAllocator.h"
|
||||
|
||||
@@ -53,8 +54,8 @@ using namespace backend;
|
||||
|
||||
FRenderer::FRenderer(FEngine& engine) :
|
||||
mEngine(engine),
|
||||
mFrameSkipper(engine, 1u),
|
||||
mFrameInfoManager(engine),
|
||||
mFrameSkipper(1u),
|
||||
mFrameInfoManager(engine.getDriverApi()),
|
||||
mIsRGB8Supported(false),
|
||||
mPerRenderPassArena(engine.getPerRenderPassAllocator())
|
||||
{
|
||||
@@ -129,7 +130,8 @@ void FRenderer::terminate(FEngine& engine) {
|
||||
// to initialize themselves, otherwise the engine tries to destroy invalid handles.
|
||||
engine.execute();
|
||||
}
|
||||
mFrameInfoManager.terminate();
|
||||
mFrameInfoManager.terminate(driver);
|
||||
mFrameSkipper.terminate(driver);
|
||||
}
|
||||
|
||||
void FRenderer::resetUserTime() {
|
||||
@@ -229,7 +231,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
bool hasColorGrading = hasPostProcess;
|
||||
bool hasDithering = view.getDithering() == Dithering::TEMPORAL;
|
||||
bool hasFXAA = view.getAntiAliasing() == AntiAliasing::FXAA;
|
||||
float2 scale = view.updateScale(mFrameInfoManager.getLastFrameInfo());
|
||||
float2 scale = view.updateScale(engine, mFrameInfoManager.getLastFrameInfo(), mFrameRateOptions, mDisplayInfo);
|
||||
auto msaaOptions = view.getMultiSampleAntiAliasingOptions();
|
||||
auto dsrOptions = view.getDynamicResolutionOptions();
|
||||
auto bloomOptions = view.getBloomOptions();
|
||||
@@ -632,7 +634,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
// * This is because the default render target is not multi-sampled, so we need an
|
||||
// intermediate buffer when MSAA is enabled.
|
||||
// * We also need an extra buffer for blending the result to the framebuffer if the view
|
||||
// is translucent.
|
||||
// is translucent AND we've not already done it as part of upscaling.
|
||||
// * And we can't use the default rendertarget if MRT is required (e.g. with color grading
|
||||
// as a subpass)
|
||||
// The intermediate buffer is accomplished with a "fake" opaqueBlit (i.e. blit) operation.
|
||||
@@ -645,7 +647,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
if (UTILS_LIKELY(!blending)) {
|
||||
input = ppm.opaqueBlit(fg, input, {
|
||||
.width = vp.width, .height = vp.height,
|
||||
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::LINEAR);
|
||||
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::NEAREST);
|
||||
} else {
|
||||
input = ppm.blendBlit(fg, blending, {
|
||||
.quality = QualityLevel::LOW
|
||||
@@ -1058,12 +1060,8 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
|
||||
|
||||
// This need to occur after the backend beginFrame() because some backends need to start
|
||||
// a command buffer before creating a fence.
|
||||
mFrameInfoManager.beginFrame({
|
||||
.targetFrameTime = FrameInfo::duration{
|
||||
float(mFrameRateOptions.interval) / mDisplayInfo.refreshRate
|
||||
},
|
||||
.headRoomRatio = mFrameRateOptions.headRoomRatio,
|
||||
.oneOverTau = mFrameRateOptions.scaleRate,
|
||||
|
||||
mFrameInfoManager.beginFrame(driver, {
|
||||
.historySize = mFrameRateOptions.history
|
||||
}, mFrameId);
|
||||
|
||||
@@ -1103,7 +1101,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
|
||||
engine.prepare();
|
||||
};
|
||||
|
||||
if (mFrameSkipper.beginFrame()) {
|
||||
if (mFrameSkipper.beginFrame(driver)) {
|
||||
// if beginFrame() returns true, we are expecting a call to endFrame(),
|
||||
// so do the beginFrame work right now, instead of requiring a call to render()
|
||||
beginFrameInternal();
|
||||
@@ -1137,8 +1135,8 @@ void FRenderer::endFrame() {
|
||||
driver.debugThreading();
|
||||
}
|
||||
|
||||
mFrameInfoManager.endFrame();
|
||||
mFrameSkipper.endFrame();
|
||||
mFrameInfoManager.endFrame(driver);
|
||||
mFrameSkipper.endFrame(driver);
|
||||
|
||||
if (mSwapChain) {
|
||||
mSwapChain->commit(driver);
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace filament {
|
||||
using namespace backend;
|
||||
using namespace math;
|
||||
|
||||
static constexpr float PID_CONTROLLER_Ki = 0.002f;
|
||||
static constexpr float PID_CONTROLLER_Kd = 0.0f;
|
||||
|
||||
FView::FView(FEngine& engine)
|
||||
: mFroxelizer(engine),
|
||||
mPerViewUniforms(engine),
|
||||
@@ -60,9 +63,30 @@ FView::FView(FEngine& engine)
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
FDebugRegistry& debugRegistry = engine.getDebugRegistry();
|
||||
|
||||
debugRegistry.registerProperty("d.view.camera_at_origin",
|
||||
&engine.debug.view.camera_at_origin);
|
||||
|
||||
// Integral term is used to fight back the dead-band below, we limit how much it can act.
|
||||
mPidController.setIntegralLimits(-100.0f, 100.0f);
|
||||
|
||||
// dead-band, 1% for scaling down, 5% for scaling up. This stabilizes all the jitters.
|
||||
mPidController.setOutputDeadBand(-0.01f, 0.05f);
|
||||
|
||||
#ifndef NDEBUG
|
||||
debugRegistry.registerDataSource("d.view.frame_info",
|
||||
mDebugFrameHistory.data(), mDebugFrameHistory.size());
|
||||
debugRegistry.registerProperty("d.view.pid.kp", &engine.debug.view.pid.kp);
|
||||
debugRegistry.registerProperty("d.view.pid.ki", &engine.debug.view.pid.ki);
|
||||
debugRegistry.registerProperty("d.view.pid.kd", &engine.debug.view.pid.kd);
|
||||
// default parameters for debugging UI
|
||||
engine.debug.view.pid.kp = 1.0f - std::exp(-1.0f / 8.0f);
|
||||
engine.debug.view.pid.ki = PID_CONTROLLER_Ki;
|
||||
engine.debug.view.pid.kd = PID_CONTROLLER_Kd;
|
||||
mPidController.setParallelGains(
|
||||
engine.debug.view.pid.kp, engine.debug.view.pid.ki, engine.debug.view.pid.kd);
|
||||
#endif
|
||||
|
||||
// allocate ubos
|
||||
mLightUbh = driver.createBufferObject(CONFIG_MAX_LIGHT_COUNT * sizeof(LightsUib),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
|
||||
@@ -131,7 +155,15 @@ void FView::setDynamicLightingOptions(float zLightNear, float zLightFar) noexcep
|
||||
mFroxelizer.setOptions(zLightNear, zLightFar);
|
||||
}
|
||||
|
||||
float2 FView::updateScale(FrameInfo const& info) noexcept {
|
||||
float2 FView::updateScale(FEngine& engine,
|
||||
FrameInfo const& info,
|
||||
Renderer::FrameRateOptions const& frameRateOptions,
|
||||
Renderer::DisplayInfo const& displayInfo) noexcept {
|
||||
|
||||
// scale factor returned to the caller is modified so the scaled viewport is rounded to
|
||||
// 8 pixels. The internal scale factor, mScale, doesn't have this rounding.
|
||||
float2 roundedScale = mScale;
|
||||
|
||||
DynamicResolutionOptions const& options = mDynamicResolution;
|
||||
if (options.enabled) {
|
||||
if (!UTILS_UNLIKELY(info.valid)) {
|
||||
@@ -140,10 +172,42 @@ float2 FView::updateScale(FrameInfo const& info) noexcept {
|
||||
return mScale;
|
||||
}
|
||||
|
||||
// scaling factor we need to apply on the whole surface
|
||||
const float scale = info.scale;
|
||||
const float w = mViewport.width;
|
||||
const float h = mViewport.height;
|
||||
#ifndef NDEBUG
|
||||
const float Kp = engine.debug.view.pid.kp;
|
||||
const float Ki = engine.debug.view.pid.ki;
|
||||
const float Kd = engine.debug.view.pid.kd;
|
||||
#else
|
||||
const float Kp = (1.0f - std::exp(-frameRateOptions.scaleRate));
|
||||
const float Ki = PID_CONTROLLER_Ki;
|
||||
const float Kd = PID_CONTROLLER_Kd;
|
||||
#endif
|
||||
mPidController.setParallelGains(Kp, Ki, Kd);
|
||||
|
||||
// all values in ms below
|
||||
using std::chrono::duration;
|
||||
const float dt = 1.0f; // we don't really need dt here, setting it to 1, means our parameters are in "frames"
|
||||
const float target = (1000.0f * float(frameRateOptions.interval)) / displayInfo.refreshRate;
|
||||
const float targetWithHeadroom = target * (1.0f - frameRateOptions.headRoomRatio);
|
||||
float measured = duration<float, std::milli>{ info.denoisedFrameTime }.count();
|
||||
float out = mPidController.update(measured / targetWithHeadroom, 1.0f, dt);
|
||||
|
||||
// maps pid command to a scale (absolute or relative, see below)
|
||||
const float command = out < 0.0f ? (1.0f / (1.0f - out)) : (1.0f + out);
|
||||
|
||||
/*
|
||||
* There is two ways we can control the scale factor, either by having the PID controller
|
||||
* output a new scale factor directly (like a "position" control), or having it evaluate
|
||||
* a relative scale factor (like a "velocity" control).
|
||||
* More experimentation is needed to figure out which works better in more cases.
|
||||
*/
|
||||
|
||||
// direct scaling ("position" control)
|
||||
//const float scale = command;
|
||||
// relative scaling ("velocity" control)
|
||||
const float scale = mScale.x * mScale.y * command;
|
||||
|
||||
const float w = float(mViewport.width);
|
||||
const float h = float(mViewport.height);
|
||||
if (scale < 1.0f && !options.homogeneousScaling) {
|
||||
// figure out the major and minor axis
|
||||
const float major = std::max(w, h);
|
||||
@@ -159,7 +223,7 @@ float2 FView::updateScale(FrameInfo const& info) noexcept {
|
||||
// if we have some scaling capacity left, scale homogeneously
|
||||
const float homogeneousScale = scale / (majorScale * minorScale);
|
||||
|
||||
// finally write the scale factors
|
||||
// finally, write the scale factors
|
||||
float& majorRef = w > h ? mScale.x : mScale.y;
|
||||
float& minorRef = w > h ? mScale.y : mScale.x;
|
||||
majorRef = std::sqrt(homogeneousScale) * majorScale;
|
||||
@@ -169,32 +233,44 @@ float2 FView::updateScale(FrameInfo const& info) noexcept {
|
||||
mScale = std::sqrt(scale);
|
||||
}
|
||||
|
||||
// always clamp to the min/max scale range
|
||||
const auto s = mScale;
|
||||
mScale = clamp(s, options.minScale, options.maxScale);
|
||||
|
||||
// disable the integration term when we're outside the controllable range
|
||||
// (i.e. we clamped). This help not to have to wait too long for the Integral term
|
||||
// to kick in after a clamping event.
|
||||
mPidController.setIntegralInhibitionEnabled(mScale != s);
|
||||
|
||||
// now tweak the scaling factor to get multiples of 8 (to help quad-shading)
|
||||
// i.e. 8x8=64 fragments, to try to help with warp sizes.
|
||||
mScale = (floor(mScale * float2{ w, h } / 8) * 8) / float2{ w, h };
|
||||
|
||||
// always clamp to the min/max scale range
|
||||
mScale = clamp(mScale, options.minScale, options.maxScale);
|
||||
|
||||
//#define DEBUG_DYNAMIC_RESOLUTION
|
||||
#if defined(DEBUG_DYNAMIC_RESOLUTION)
|
||||
static int sLogCounter = 15;
|
||||
if (!--sLogCounter) {
|
||||
sLogCounter = 15;
|
||||
slog.d << info.denoisedFrameTime.count() * 1000.0f << " ms"
|
||||
<< ", " << info.smoothedWorkLoad
|
||||
<< ", " << mScale.x
|
||||
<< ", " << mScale.y
|
||||
<< ", " << mViewport.width * mScale.x
|
||||
<< ", " << mViewport.height * mScale.y
|
||||
<< io::endl;
|
||||
}
|
||||
#endif
|
||||
roundedScale.x = mScale.x == 1.0f ? 1.0f : (std::floor(mScale.x * float{ w } / 8) * 8) / float{ w };
|
||||
roundedScale.y = mScale.y == 1.0f ? 1.0f : (std::floor(mScale.y * float{ h } / 8) * 8) / float{ h };
|
||||
} else {
|
||||
mScale = 1.0f;
|
||||
roundedScale = 1.0f;
|
||||
}
|
||||
|
||||
return mScale;
|
||||
#ifndef NDEBUG
|
||||
// only for debugging...
|
||||
using duration_ms = std::chrono::duration<float, std::milli>;
|
||||
const float target = (1000.0f * float(frameRateOptions.interval)) / displayInfo.refreshRate;
|
||||
const float targetWithHeadroom = target * (1.0f - frameRateOptions.headRoomRatio);
|
||||
std::move(mDebugFrameHistory.begin() + 1,
|
||||
mDebugFrameHistory.end(), mDebugFrameHistory.begin());
|
||||
mDebugFrameHistory.back() = {
|
||||
.target = target,
|
||||
.targetWithHeadroom = targetWithHeadroom,
|
||||
.frameTime = std::chrono::duration_cast<duration_ms>(info.frameTime).count(),
|
||||
.frameTimeDenoised = std::chrono::duration_cast<duration_ms>(info.denoisedFrameTime).count(),
|
||||
.scale = mScale.x * mScale.y,
|
||||
.pid_e = mPidController.getError(),
|
||||
.pid_i = mPidController.getIntegral(),
|
||||
.pid_d = mPidController.getDerivative()
|
||||
};
|
||||
#endif
|
||||
|
||||
return roundedScale;
|
||||
}
|
||||
|
||||
void FView::setVisibleLayers(uint8_t select, uint8_t values) noexcept {
|
||||
|
||||
@@ -24,8 +24,8 @@ Viewport Viewport::scale(math::float2 s) const noexcept {
|
||||
|
||||
// round to nearest to avoid overlapping viewports
|
||||
// this could result to empty viewport, though.
|
||||
float l = std::floor(0.5f + s.x * left);
|
||||
float b = std::floor(0.5f + s.y * bottom);
|
||||
float l = std::floor(0.5f + s.x * float(left));
|
||||
float b = std::floor(0.5f + s.y * float(bottom));
|
||||
float r = std::floor(0.5f + s.x * float(left + width));
|
||||
float t = std::floor(0.5f + s.y * float(bottom + height));
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/CString.h>
|
||||
|
||||
#include <tsl/robin_map.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace filament {
|
||||
|
||||
@@ -34,8 +34,6 @@ class FDebugRegistry : public DebugRegistry {
|
||||
public:
|
||||
FDebugRegistry() noexcept;
|
||||
|
||||
PropertyArray getProperties() const noexcept;
|
||||
|
||||
bool hasProperty(const char* name) const noexcept;
|
||||
|
||||
void* getPropertyAddress(const char* name) noexcept;
|
||||
@@ -58,10 +56,14 @@ public:
|
||||
registerProperty(name, p, type);
|
||||
}
|
||||
|
||||
void registerDataSource(utils::StaticString name, void const* data, size_t count) noexcept;
|
||||
|
||||
DataSource getDataSource(const char* name) const noexcept;
|
||||
|
||||
private:
|
||||
void registerProperty(utils::StaticString name, void* p, Type type) noexcept;
|
||||
std::vector<Property> mProperties;
|
||||
tsl::robin_map<utils::StaticString, void*> mPropertyMap;
|
||||
std::unordered_map<utils::StaticString, void*> mPropertyMap;
|
||||
std::unordered_map<utils::StaticString, DataSource> mDataSourceMap;
|
||||
};
|
||||
|
||||
FILAMENT_UPCAST(DebugRegistry)
|
||||
|
||||
@@ -443,6 +443,11 @@ public:
|
||||
} ssao;
|
||||
struct {
|
||||
bool camera_at_origin = true;
|
||||
struct {
|
||||
float kp = 0.0f;
|
||||
float ki = 0.0f;
|
||||
float kd = 0.0f;
|
||||
} pid;
|
||||
} view;
|
||||
struct {
|
||||
// When set to true, the backend will attempt to capture the next frame and write the
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "Allocators.h"
|
||||
#include "FrameInfo.h"
|
||||
#include "FrameSkipper.h"
|
||||
#include "PostProcessManager.h"
|
||||
#include "RenderPass.h"
|
||||
|
||||
#include "details/SwapChain.h"
|
||||
@@ -29,9 +30,11 @@
|
||||
#include "private/backend/DriverApiForward.h"
|
||||
|
||||
#include <fg2/FrameGraphId.h>
|
||||
#include <fg2/FrameGraphTexture.h>
|
||||
|
||||
#include <filament/Renderer.h>
|
||||
#include <filament/View.h>
|
||||
#include <filament/Viewport.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
@@ -61,7 +64,7 @@ class ShadowMap;
|
||||
* A concrete implementation of the Renderer Interface.
|
||||
*/
|
||||
class FRenderer : public Renderer {
|
||||
static constexpr size_t MAX_FRAMETIME_HISTORY = 32u;
|
||||
static constexpr unsigned MAX_FRAMETIME_HISTORY = 32u;
|
||||
|
||||
public:
|
||||
explicit FRenderer(FEngine& engine);
|
||||
@@ -107,9 +110,9 @@ public:
|
||||
FrameRateOptions& frameRateOptions = mFrameRateOptions;
|
||||
frameRateOptions = options;
|
||||
|
||||
// History can't be more than 32 frames (~0.5s)
|
||||
frameRateOptions.history = std::min(frameRateOptions.history,
|
||||
uint8_t(MAX_FRAMETIME_HISTORY));
|
||||
// History can't be more than 31 frames (~0.5s), make it odd.
|
||||
frameRateOptions.history = std::min(frameRateOptions.history / 2u * 2u + 1u,
|
||||
MAX_FRAMETIME_HISTORY);
|
||||
|
||||
// History must at least be 3 frames
|
||||
frameRateOptions.history = std::max(frameRateOptions.history, uint8_t(3));
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include <filament/View.h>
|
||||
|
||||
#include <filament/Renderer.h>
|
||||
|
||||
#include "upcast.h"
|
||||
|
||||
#include "Allocators.h"
|
||||
@@ -26,6 +28,7 @@
|
||||
#include "FrameInfo.h"
|
||||
#include "Froxelizer.h"
|
||||
#include "PerViewUniforms.h"
|
||||
#include "PIDController.h"
|
||||
#include "ShadowMap.h"
|
||||
#include "ShadowMapManager.h"
|
||||
#include "TypedUniformBuffer.h"
|
||||
@@ -270,7 +273,10 @@ public:
|
||||
return mHasPostProcessPass;
|
||||
}
|
||||
|
||||
math::float2 updateScale(FrameInfo const& info) noexcept;
|
||||
math::float2 updateScale(FEngine& engine,
|
||||
FrameInfo const& info,
|
||||
Renderer::FrameRateOptions const& frameRateOptions,
|
||||
Renderer::DisplayInfo const& displayInfo) noexcept;
|
||||
|
||||
void setDynamicResolutionOptions(View::DynamicResolutionOptions const& options) noexcept;
|
||||
|
||||
@@ -555,6 +561,7 @@ private:
|
||||
const FColorGrading* mColorGrading = nullptr;
|
||||
const FColorGrading* mDefaultColorGrading = nullptr;
|
||||
|
||||
PIDController mPidController;
|
||||
DynamicResolutionOptions mDynamicResolution;
|
||||
math::float2 mScale = 1.0f;
|
||||
bool mIsDynamicResolutionSupported = false;
|
||||
@@ -581,6 +588,10 @@ private:
|
||||
mutable bool mNeedsShadowMap = false;
|
||||
|
||||
ShadowMapManager mShadowMapManager;
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::array<DebugRegistry::FrameHistory, 5*60> mDebugFrameHistory;
|
||||
#endif
|
||||
};
|
||||
|
||||
FILAMENT_UPCAST(View)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.12.9"
|
||||
spec.version = "1.12.11"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.12.9/filament-v1.12.9-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.12.11/filament-v1.12.11-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -45,6 +45,7 @@ using namespace utils;
|
||||
|
||||
@implementation FILViewController {
|
||||
CADisplayLink* _displayLink;
|
||||
CFTimeInterval _startTime;
|
||||
viewer::RemoteServer* _server;
|
||||
viewer::AutomationEngine* _automation;
|
||||
|
||||
@@ -102,6 +103,7 @@ using namespace utils;
|
||||
[self stopDisplayLink];
|
||||
|
||||
// Call our render method 60 times a second.
|
||||
_startTime = CACurrentMediaTime();
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render)];
|
||||
_displayLink.preferredFramesPerSecond = 60;
|
||||
[_displayLink addToRunLoop:NSRunLoop.currentRunLoop forMode:NSDefaultRunLoopMode];
|
||||
@@ -230,7 +232,8 @@ using namespace utils;
|
||||
auto* animator = self.modelView.animator;
|
||||
if (animator) {
|
||||
if (animator->getAnimationCount() > 0) {
|
||||
animator->applyAnimation(0, CACurrentMediaTime());
|
||||
CFTimeInterval elapsedTime = CACurrentMediaTime() - _startTime;
|
||||
animator->applyAnimation(0, static_cast<float>(elapsedTime));
|
||||
}
|
||||
animator->updateBoneMatrices();
|
||||
}
|
||||
|
||||
@@ -121,10 +121,16 @@ void GLSLPostProcessor::spirvToToMsl(const SpirvBlob *spirv, std::string *outMsl
|
||||
|
||||
CompilerMSL::Options mslOptions = {};
|
||||
mslOptions.platform = platform,
|
||||
mslOptions.msl_version = CompilerMSL::Options::make_msl_version(1, 1);
|
||||
mslOptions.msl_version = config.shaderModel == filament::backend::ShaderModel::GL_ES_30 ?
|
||||
CompilerMSL::Options::make_msl_version(2, 0) : CompilerMSL::Options::make_msl_version(2, 2);
|
||||
|
||||
if (config.shaderModel == filament::backend::ShaderModel::GL_ES_30) {
|
||||
if (config.hasFramebufferFetch) {
|
||||
mslOptions.use_framebuffer_fetch_subpasses = true;
|
||||
// On macOS, framebuffer fetch is only available starting with MSL 2.3. Filament will only
|
||||
// use framebuffer fetch materials on devices that support it.
|
||||
if (config.shaderModel == filament::backend::ShaderModel::GL_CORE_41) {
|
||||
mslOptions.msl_version = CompilerMSL::Options::make_msl_version(2, 3);
|
||||
}
|
||||
}
|
||||
|
||||
mslCompiler.set_msl_options(mslOptions);
|
||||
|
||||
@@ -234,8 +234,13 @@ LinearImage PNGDecoder::decode() {
|
||||
png_set_tRNS_to_alpha(mPNG);
|
||||
}
|
||||
if (getColorSpace() == ImageDecoder::ColorSpace::SRGB) {
|
||||
png_set_alpha_mode(mPNG, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
|
||||
double gamma = 1.0;
|
||||
png_get_gAMA(mPNG, mInfo, &gamma);
|
||||
if (gamma != 1.0) {
|
||||
png_set_alpha_mode(mPNG, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
|
||||
}
|
||||
} else {
|
||||
png_set_gamma_fixed(mPNG, PNG_FP_1, PNG_FP_1);
|
||||
png_set_alpha_mode(mPNG, PNG_ALPHA_PNG, PNG_GAMMA_LINEAR);
|
||||
}
|
||||
if (bitDepth < 16) {
|
||||
|
||||
@@ -52,7 +52,7 @@ void updateOrCompare(LinearImage limgResult, const utils::Path& fnameGolden,
|
||||
// Load the PNG file at the given path.
|
||||
std::ifstream in(fnameGolden, std::ios::binary);
|
||||
ASSERT_PRECONDITION(in, "Unable to open: %s", fnameGolden.c_str());
|
||||
LinearImage limgGolden = ImageDecoder::decode(in, fnameGolden, ImageDecoder::ColorSpace::LINEAR);
|
||||
LinearImage limgGolden = ImageDecoder::decode(in, fnameGolden);
|
||||
|
||||
// Convert 4-channel RGBM into proper RGB.
|
||||
if (fnameGolden.getExtension() == "rgbm" && limgGolden.getChannels() == 4) {
|
||||
|
||||
@@ -564,12 +564,48 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Debug")) {
|
||||
auto& debug = engine->getDebugRegistry();
|
||||
if (ImGui::Button("Capture frame")) {
|
||||
auto& debug = engine->getDebugRegistry();
|
||||
bool* captureFrame =
|
||||
debug.getPropertyAddress<bool>("d.renderer.doFrameCapture");
|
||||
*captureFrame = true;
|
||||
}
|
||||
auto dataSource = debug.getDataSource("d.view.frame_info");
|
||||
if (dataSource.data) {
|
||||
ImGuiExt::PlotLinesSeries("FrameInfo", 6,
|
||||
[](int series) {
|
||||
const ImVec4 colors[] = {
|
||||
{ 1, 0, 0, 1 }, // target
|
||||
{ 0, 0.5f, 0, 1 }, // frame-time
|
||||
{ 0, 1, 0, 1 }, // frame-time denoised
|
||||
{ 1, 1, 0, 1 }, // i
|
||||
{ 1, 0, 1, 1 }, // d
|
||||
{ 0, 1, 1, 1 }, // e
|
||||
|
||||
};
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotLines, colors[series]);
|
||||
},
|
||||
[](int series, void* buffer, int i) -> float {
|
||||
auto const* p = (DebugRegistry::FrameHistory const*)buffer + i;
|
||||
switch (series) {
|
||||
case 0: return 0.03f * p->target;
|
||||
case 1: return 0.03f * p->frameTime;
|
||||
case 2: return 0.03f * p->frameTimeDenoised;
|
||||
case 3: return p->pid_i * 0.5f / 100.0f + 0.5f;
|
||||
case 4: return p->pid_d * 0.5f / 0.100f + 0.5f;
|
||||
case 5: return p->pid_e * 0.5f / 1.000f + 0.5f;
|
||||
default: return 0.0f;
|
||||
}
|
||||
},
|
||||
[](int series) {
|
||||
if (series < 6) ImGui::PopStyleColor();
|
||||
},
|
||||
const_cast<void*>(dataSource.data), int(dataSource.count), 0,
|
||||
nullptr, 0.0f, 1.0f, { 0, 100 });
|
||||
}
|
||||
ImGui::SliderFloat("Kp", debug.getPropertyAddress<float>("d.view.pid.kp"), 0, 2);
|
||||
ImGui::SliderFloat("Ki", debug.getPropertyAddress<float>("d.view.pid.ki"), 0, 10);
|
||||
ImGui::SliderFloat("Kd", debug.getPropertyAddress<float>("d.view.pid.kd"), 0, 10);
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupModal("MessageBox", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
|
||||
@@ -440,6 +440,9 @@ int main(int argc, char* argv[]) {
|
||||
if (!outputStream) {
|
||||
cerr << "The output file cannot be opened: " << path << endl;
|
||||
} else {
|
||||
if (g_filter == Filter::GAUSSIAN_NORMALS) {
|
||||
image = vectorsToColors(image);
|
||||
}
|
||||
if (!ImageEncoder::encode(outputStream, g_format, image, g_compression, path)) {
|
||||
cerr << "An error occurred while encoding the image." << endl;
|
||||
return 1;
|
||||
|
||||
@@ -502,6 +502,26 @@ Filament.loadClassExtensions = function() {
|
||||
return new Int16Array(arrayBuffer);
|
||||
};
|
||||
|
||||
Filament.SurfaceOrientation.prototype.getQuatsHalf4 = function (nverts) {
|
||||
const attribType = Filament.VertexBuffer$AttributeType.HALF4;
|
||||
const quatsBufferSize = 8 * nverts;
|
||||
const quatsBuffer = Filament._malloc(quatsBufferSize);
|
||||
this._getQuats(quatsBuffer, nverts, attribType);
|
||||
const arrayBuffer = Filament.HEAPU8.subarray(quatsBuffer, quatsBuffer + quatsBufferSize).slice().buffer;
|
||||
Filament._free(quatsBuffer);
|
||||
return new Uint16Array(arrayBuffer);
|
||||
};
|
||||
|
||||
Filament.SurfaceOrientation.prototype.getQuatsFloat4 = function (nverts) {
|
||||
const attribType = Filament.VertexBuffer$AttributeType.FLOAT4;
|
||||
const quatsBufferSize = 16 * nverts;
|
||||
const quatsBuffer = Filament._malloc(quatsBufferSize);
|
||||
this._getQuats(quatsBuffer, nverts, attribType);
|
||||
const arrayBuffer = Filament.HEAPU8.subarray(quatsBuffer, quatsBuffer + quatsBufferSize).slice().buffer;
|
||||
Filament._free(quatsBuffer);
|
||||
return new Float32Array(arrayBuffer);
|
||||
};
|
||||
|
||||
Filament.gltfio$AssetLoader.prototype.createAssetFromJson = function(buffer) {
|
||||
if ('string' == typeof buffer && buffer.endsWith('.glb')) {
|
||||
console.error('Please use createAssetFromBinary for glb files.');
|
||||
|
||||
2
web/filament-js/filament.d.ts
vendored
2
web/filament-js/filament.d.ts
vendored
@@ -653,6 +653,8 @@ export class SurfaceOrientation$Builder {
|
||||
|
||||
export class SurfaceOrientation {
|
||||
public getQuats(quatCount: number): Int16Array;
|
||||
public getQuatsHalf4(quatCount: number): Uint16Array;
|
||||
public getQuatsFloat4(quatCount: number): Float32Array;
|
||||
public delete(): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.12.9",
|
||||
"version": "1.12.11",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user