Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab552d3619 | ||
|
|
4fd7c418e5 | ||
|
|
a3fdca7997 | ||
|
|
7f1704481e | ||
|
|
e6b962b038 | ||
|
|
668fb07ac2 | ||
|
|
f64eef02a3 | ||
|
|
239e98ccec | ||
|
|
919cfae6b2 | ||
|
|
0b9389430b | ||
|
|
1d157677d1 | ||
|
|
ef3f0cb326 | ||
|
|
fcf53f2c3e | ||
|
|
d6fda03b06 | ||
|
|
a76addd2bf | ||
|
|
b1f7731dbe | ||
|
|
e3e12dbf73 | ||
|
|
31a75029f0 | ||
|
|
e5c24cc718 | ||
|
|
2b86c8df6f | ||
|
|
4d8e6eefa1 | ||
|
|
8aeec2ba35 | ||
|
|
4eb4fd5aba | ||
|
|
56355231bd | ||
|
|
9ccb8fce31 | ||
|
|
e674420e9c | ||
|
|
8a9cbcfb99 | ||
|
|
f0d5cd3fa1 |
@@ -0,0 +1,7 @@
|
||||
;;; Directory Local Variables -*- no-byte-compile: t -*-
|
||||
;;; For more information see (info "(emacs) Directory Variables")
|
||||
|
||||
((c++-mode . ((c-file-style . "filament")
|
||||
(apheleia-inhibit . t)))
|
||||
(c-mode . ((c-file-style . "filament")
|
||||
(apheleia-inhibit . t))))
|
||||
@@ -16,3 +16,5 @@ settings.json
|
||||
test*.png
|
||||
test*.json
|
||||
results
|
||||
/compile_commands.json
|
||||
/.cache
|
||||
|
||||
@@ -7,3 +7,12 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
- engine: Allow instantiating Engine at a given feature level via `Engine::Builder::featureLevel`
|
||||
- matc: Enable `GL_OES_standard_derivatives` extension in ESSL 1.0 shaders
|
||||
- matc: Fix code generation of double sided and masked materials in ESSL 1.0 shaders
|
||||
- filagui: Add support for feature level 0
|
||||
- matc: Add support for post-process materials in feature level 0
|
||||
- engine: Add `Material::getFeatureLevel()`
|
||||
- engine: Add missing `Material::getReflectionMode()` method in Java
|
||||
- engine: Support basic usage of post-processing materials on feature level 0
|
||||
|
||||
@@ -128,3 +128,15 @@ Navigate to [Filament's release
|
||||
workflow](https://github.com/google/filament/actions/workflows/release.yml). Hit the _Run workflow_
|
||||
dropdown. Modify _Platform to build_ and _Release tag to build_, then hit _Run workflow_. This will
|
||||
initiate a new release run.
|
||||
|
||||
## 11. Kick off the npm and CocoaPods release jobs
|
||||
|
||||
Navigate to [Filament's npm deploy
|
||||
workflow](https://github.com/google/filament/actions/workflows/npm-deploy.yml).
|
||||
Hit the _Run workflow_ dropdown. Modify _Release tag to deploy_ to the tag corresponding to this
|
||||
release (for example, v1.42.2).
|
||||
|
||||
Navigate to [Filament's CocoaPods deploy
|
||||
workflow](https://github.com/google/filament/actions/workflows/cocopods-deploy.yml).
|
||||
Hit the _Run workflow_ dropdown. Modify _Release tag to deploy_ to the tag corresponding to this
|
||||
release (for example, v1.42.2).
|
||||
|
||||
@@ -483,6 +483,12 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
|
||||
builder->config(&config);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderFeatureLevel(
|
||||
JNIEnv*, jclass, jlong nativeBuilder, jint ordinal) {
|
||||
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||
builder->featureLevel((Engine::FeatureLevel)ordinal);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderSharedContext(
|
||||
JNIEnv*, jclass, jlong nativeBuilder, jlong sharedContext) {
|
||||
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
|
||||
|
||||
@@ -105,6 +105,22 @@ Java_com_google_android_filament_Material_nGetRefractionType(JNIEnv*, jclass,
|
||||
return (jint) material->getRefractionType();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Material_nGetReflectionMode(JNIEnv*, jclass,
|
||||
jlong nativeMaterial) {
|
||||
Material* material = (Material*) nativeMaterial;
|
||||
return (jint) material->getReflectionMode();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Material_nGetFeatureLevel(JNIEnv*, jclass,
|
||||
jlong nativeMaterial) {
|
||||
Material* material = (Material*) nativeMaterial;
|
||||
return (jint) material->getFeatureLevel();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Material_nGetVertexDomain(JNIEnv*, jclass,
|
||||
|
||||
@@ -71,6 +71,13 @@ Java_com_google_android_filament_Scene_nRemoveEntities(JNIEnv *env, jclass type,
|
||||
env->ReleaseIntArrayElements(entities, (jint*) nativeEntities, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Scene_nGetEntityCount(JNIEnv *env, jclass type,
|
||||
jlong nativeScene) {
|
||||
Scene* scene = (Scene*) nativeScene;
|
||||
return (jint) scene->getEntityCount();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Scene_nGetRenderableCount(JNIEnv *env, jclass type,
|
||||
jlong nativeScene) {
|
||||
|
||||
@@ -209,6 +209,17 @@ public class Engine {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial featureLevel for the Engine.
|
||||
*
|
||||
* @param featureLevel The feature level at which initialize Filament.
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
public Builder featureLevel(FeatureLevel featureLevel) {
|
||||
nSetBuilderFeatureLevel(mNativeBuilder, featureLevel.ordinal());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of Engine
|
||||
*
|
||||
@@ -468,17 +479,23 @@ public class Engine {
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate all features of a given feature level. By default FeatureLevel::FEATURE_LEVEL_1 is
|
||||
* active. The selected feature level must not be higher than the value returned by
|
||||
* getActiveFeatureLevel() and it's not possible lower the active feature level.
|
||||
* Activate all features of a given feature level. If an explicit feature level is not specified
|
||||
* at Engine initialization time via {@link Builder#featureLevel}, the default feature level is
|
||||
* {@link FeatureLevel#FEATURE_LEVEL_0} on devices not compatible with GLES 3.0; otherwise, the
|
||||
* default is {@link FeatureLevel::FEATURE_LEVEL_1}. The selected feature level must not be
|
||||
* higher than the value returned by {@link #getActiveFeatureLevel} and it's not possible lower
|
||||
* the active feature level. Additionally, it is not possible to modify the feature level at all
|
||||
* if the Engine was initialized at {@link FeatureLevel#FEATURE_LEVEL_0}.
|
||||
*
|
||||
* @param featureLevel the feature level to activate. If featureLevel is lower than
|
||||
* getActiveFeatureLevel(), the current (higher) feature level is kept.
|
||||
* If featureLevel is higher than getSupportedFeatureLevel(), an exception
|
||||
* is thrown, or the program is terminated if exceptions are disabled.
|
||||
* @param featureLevel the feature level to activate. If featureLevel is lower than {@link
|
||||
* #getActiveFeatureLevel}, the current (higher) feature level is kept. If
|
||||
* featureLevel is higher than {@link #getSupportedFeatureLevel}, or if the
|
||||
* engine was initialized at feature level 0, an exception is thrown, or the
|
||||
* program is terminated if exceptions are disabled.
|
||||
*
|
||||
* @return the active feature level.
|
||||
*
|
||||
* @see Builder#featureLevel
|
||||
* @see #getSupportedFeatureLevel
|
||||
* @see #getActiveFeatureLevel
|
||||
*/
|
||||
@@ -1149,6 +1166,7 @@ public class Engine {
|
||||
private static native void nSetBuilderConfig(long nativeBuilder, long commandBufferSizeMB,
|
||||
long perRenderPassArenaSizeMB, long driverHandleArenaSizeMB,
|
||||
long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount);
|
||||
private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal);
|
||||
private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext);
|
||||
private static native long nBuilderBuild(long nativeBuilder);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Size;
|
||||
|
||||
import com.google.android.filament.proguard.UsedByNative;
|
||||
import com.google.android.filament.Engine.FeatureLevel;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.util.ArrayList;
|
||||
@@ -46,6 +47,8 @@ public class Material {
|
||||
static final BlendingMode[] sBlendingModeValues = BlendingMode.values();
|
||||
static final RefractionMode[] sRefractionModeValues = RefractionMode.values();
|
||||
static final RefractionType[] sRefractionTypeValues = RefractionType.values();
|
||||
static final ReflectionMode[] sReflectionModeValues = ReflectionMode.values();
|
||||
static final FeatureLevel[] sFeatureLevelValues = FeatureLevel.values();
|
||||
static final VertexDomain[] sVertexDomainValues = VertexDomain.values();
|
||||
static final CullingMode[] sCullingModeValues = CullingMode.values();
|
||||
static final VertexBuffer.VertexAttribute[] sVertexAttributeValues =
|
||||
@@ -181,6 +184,18 @@ public class Material {
|
||||
THIN
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported reflection modes
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/lighting:reflections">
|
||||
* Lighting: reflections</a>
|
||||
*/
|
||||
public enum ReflectionMode {
|
||||
DEFAULT,
|
||||
SCREEN_SPACE
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported types of vertex domains
|
||||
*
|
||||
@@ -437,6 +452,28 @@ public class Material {
|
||||
return EnumCache.sRefractionTypeValues[nGetRefractionType(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reflection mode of this material.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/lighting:reflections">
|
||||
* Lighting: reflections</a>
|
||||
*/
|
||||
public ReflectionMode getReflectionMode() {
|
||||
return EnumCache.sReflectionModeValues[nGetReflectionMode(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum required feature level for this material.
|
||||
*
|
||||
* @see
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/general:featurelevel">
|
||||
* General: featureLevel</a>
|
||||
*/
|
||||
public FeatureLevel getFeatureLevel() {
|
||||
return EnumCache.sFeatureLevelValues[nGetFeatureLevel(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex domain of this material.
|
||||
*
|
||||
@@ -932,6 +969,8 @@ public class Material {
|
||||
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterial);
|
||||
private static native int nGetRefractionMode(long nativeMaterial);
|
||||
private static native int nGetRefractionType(long nativeMaterial);
|
||||
private static native int nGetReflectionMode(long nativeMaterial);
|
||||
private static native int nGetFeatureLevel(long nativeMaterial);
|
||||
|
||||
|
||||
private static native int nGetParameterCount(long nativeMaterial);
|
||||
|
||||
@@ -146,18 +146,29 @@ public class Scene {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of {@link RenderableManager} components in the <code>Scene</code>.
|
||||
* Returns the total number of Entities in the <code>Scene</code>, whether alive or not.
|
||||
*
|
||||
* @return number of {@link RenderableManager} components in the <code>Scene</code>..
|
||||
* @return the total number of Entities in the <code>Scene</code>.
|
||||
*/
|
||||
public int getEntityCount() {
|
||||
return nGetEntityCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of active (alive) {@link RenderableManager} components in the
|
||||
* <code>Scene</code>.
|
||||
*
|
||||
* @return number of {@link RenderableManager} components in the <code>Scene</code>.
|
||||
*/
|
||||
public int getRenderableCount() {
|
||||
return nGetRenderableCount(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of {@link LightManager} components in the <code>Scene</code>.
|
||||
* Returns the number of active (alive) {@link LightManager} components in the
|
||||
* <code>Scene</code>.
|
||||
*
|
||||
* @return number of {@link LightManager} components in the <code>Scene</code>..
|
||||
* @return number of {@link LightManager} components in the <code>Scene</code>.
|
||||
*/
|
||||
public int getLightCount() {
|
||||
return nGetLightCount(getNativeObject());
|
||||
@@ -189,6 +200,7 @@ public class Scene {
|
||||
private static native void nAddEntities(long nativeScene, int[] entities);
|
||||
private static native void nRemove(long nativeScene, int entity);
|
||||
private static native void nRemoveEntities(long nativeScene, int[] entities);
|
||||
private static native int nGetEntityCount(long nativeScene);
|
||||
private static native int nGetRenderableCount(long nativeScene);
|
||||
private static native int nGetLightCount(long nativeScene);
|
||||
private static native boolean nHasEntity(long nativeScene, int entity);
|
||||
|
||||
+49
-40
@@ -227,8 +227,10 @@ public class UiHelper {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||
mTextureView.getSurfaceTexture().setDefaultBufferSize(width, height);
|
||||
}
|
||||
// the call above won't cause TextureView.onSurfaceTextureSizeChanged()
|
||||
mRenderCallback.onResized(width, height);
|
||||
if (mRenderCallback != null) {
|
||||
// the call above won't cause TextureView.onSurfaceTextureSizeChanged()
|
||||
mRenderCallback.onResized(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -298,7 +300,6 @@ public class UiHelper {
|
||||
|
||||
/**
|
||||
* Checks whether we are ready to render into the attached surface.
|
||||
*
|
||||
* Using OpenGL ES when this returns true, will result in drawing commands being lost,
|
||||
* HOWEVER, GLES state will be preserved. This is useful to initialize the engine.
|
||||
*
|
||||
@@ -343,7 +344,6 @@ public class UiHelper {
|
||||
/**
|
||||
* Controls whether the render target (SurfaceView or TextureView) is opaque or not.
|
||||
* The render target is considered opaque by default.
|
||||
*
|
||||
* Must be called before calling {@link #attachTo(SurfaceView)}, {@link #attachTo(TextureView)},
|
||||
* or {@link #attachTo(SurfaceHolder)}.
|
||||
*
|
||||
@@ -366,10 +366,8 @@ public class UiHelper {
|
||||
* positioned above other surfaces but below the activity's surface. This property
|
||||
* only has an effect when used in combination with {@link #setOpaque(boolean) setOpaque(false)}
|
||||
* and does not affect TextureView targets.
|
||||
*
|
||||
* Must be called before calling {@link #attachTo(SurfaceView)}
|
||||
* or {@link #attachTo(TextureView)}.
|
||||
*
|
||||
* Has no effect when using {@link #attachTo(SurfaceHolder)}.
|
||||
*
|
||||
* @param overlay Indicates whether the render target should be rendered below the activity's
|
||||
@@ -390,7 +388,6 @@ public class UiHelper {
|
||||
|
||||
/**
|
||||
* Associate UiHelper with a SurfaceView.
|
||||
*
|
||||
* As soon as SurfaceView is ready (i.e. has a Surface), we'll create the
|
||||
* EGL resources needed, and call user callbacks if needed.
|
||||
*/
|
||||
@@ -412,21 +409,23 @@ public class UiHelper {
|
||||
|
||||
final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
public void surfaceCreated(@NonNull SurfaceHolder holder) {
|
||||
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
|
||||
createSwapChain(holder.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(
|
||||
SurfaceHolder holder, int format, int width, int height) {
|
||||
@NonNull SurfaceHolder holder, int format, int width, int height) {
|
||||
// Note: this is always called at least once after surfaceCreated()
|
||||
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
|
||||
mRenderCallback.onResized(width, height);
|
||||
if (mRenderCallback != null) {
|
||||
mRenderCallback.onResized(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
|
||||
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
|
||||
destroySwapChain();
|
||||
}
|
||||
@@ -450,7 +449,6 @@ public class UiHelper {
|
||||
|
||||
/**
|
||||
* Associate UiHelper with a TextureView.
|
||||
*
|
||||
* As soon as TextureView is ready (i.e. has a buffer), we'll create the
|
||||
* EGL resources needed, and call user callbacks if needed.
|
||||
*/
|
||||
@@ -463,7 +461,7 @@ public class UiHelper {
|
||||
TextureView.SurfaceTextureListener listener = new TextureView.SurfaceTextureListener() {
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(
|
||||
SurfaceTexture surfaceTexture, int width, int height) {
|
||||
@NonNull SurfaceTexture surfaceTexture, int width, int height) {
|
||||
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureAvailable()");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|
||||
@@ -478,40 +476,44 @@ public class UiHelper {
|
||||
|
||||
createSwapChain(surface);
|
||||
|
||||
// Call this the first time because onSurfaceTextureSizeChanged()
|
||||
// isn't called at initialization time
|
||||
mRenderCallback.onResized(width, height);
|
||||
if (mRenderCallback != null) {
|
||||
// Call this the first time because onSurfaceTextureSizeChanged()
|
||||
// isn't called at initialization time
|
||||
mRenderCallback.onResized(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(
|
||||
SurfaceTexture surfaceTexture, int width, int height) {
|
||||
@NonNull SurfaceTexture surfaceTexture, int width, int height) {
|
||||
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureSizeChanged()");
|
||||
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
|
||||
surfaceTexture.setDefaultBufferSize(mDesiredWidth, mDesiredHeight);
|
||||
mRenderCallback.onResized(mDesiredWidth, mDesiredHeight);
|
||||
} else {
|
||||
mRenderCallback.onResized(width, height);
|
||||
if (mRenderCallback != null) {
|
||||
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
|
||||
surfaceTexture.setDefaultBufferSize(mDesiredWidth, mDesiredHeight);
|
||||
mRenderCallback.onResized(mDesiredWidth, mDesiredHeight);
|
||||
} else {
|
||||
mRenderCallback.onResized(width, height);
|
||||
}
|
||||
// We must recreate the SwapChain to guarantee that it sees the new size.
|
||||
// More precisely, for an EGL client, the EGLSurface must be recreated. For
|
||||
// a Vulkan client, the SwapChain must be recreated. Calling
|
||||
// onNativeWindowChanged() will accomplish that.
|
||||
// This requirement comes from SurfaceTexture.setDefaultBufferSize()
|
||||
// documentation.
|
||||
TextureViewHandler textureViewHandler = (TextureViewHandler) mRenderSurface;
|
||||
mRenderCallback.onNativeWindowChanged(textureViewHandler.getSurface());
|
||||
}
|
||||
// We must recreate the SwapChain to guarantee that it sees the new size.
|
||||
// More precisely, for an EGL client, the EGLSurface must be recreated. For
|
||||
// a Vulkan client, the SwapChain must be recreated. Calling
|
||||
// onNativeWindowChanged() will accomplish that.
|
||||
// This requirement comes from SurfaceTexture.setDefaultBufferSize()
|
||||
// documentation.
|
||||
TextureViewHandler textureViewHandler = (TextureViewHandler) mRenderSurface;
|
||||
mRenderCallback.onNativeWindowChanged(textureViewHandler.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
|
||||
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
|
||||
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureDestroyed()");
|
||||
destroySwapChain();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) { }
|
||||
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { }
|
||||
};
|
||||
|
||||
view.setSurfaceTextureListener(listener);
|
||||
@@ -519,14 +521,15 @@ public class UiHelper {
|
||||
// in case the View's SurfaceTexture already existed
|
||||
if (view.isAvailable()) {
|
||||
SurfaceTexture surfaceTexture = view.getSurfaceTexture();
|
||||
listener.onSurfaceTextureAvailable(surfaceTexture, mDesiredWidth, mDesiredHeight);
|
||||
if (surfaceTexture != null) {
|
||||
listener.onSurfaceTextureAvailable(surfaceTexture, mDesiredWidth, mDesiredHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate UiHelper with a SurfaceHolder.
|
||||
*
|
||||
* As soon as a Surface is created, we'll create the
|
||||
* EGL resources needed, and call user callbacks if needed.
|
||||
*/
|
||||
@@ -539,20 +542,22 @@ public class UiHelper {
|
||||
|
||||
final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder surfaceHolder) {
|
||||
public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
|
||||
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
|
||||
createSwapChain(holder.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
|
||||
// Note: this is always called at least once after surfaceCreated()
|
||||
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
|
||||
mRenderCallback.onResized(width, height);
|
||||
if (mRenderCallback != null) {
|
||||
mRenderCallback.onResized(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
|
||||
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
|
||||
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
|
||||
destroySwapChain();
|
||||
}
|
||||
@@ -587,7 +592,9 @@ public class UiHelper {
|
||||
}
|
||||
|
||||
private void createSwapChain(@NonNull Surface surface) {
|
||||
mRenderCallback.onNativeWindowChanged(surface);
|
||||
if (mRenderCallback != null) {
|
||||
mRenderCallback.onNativeWindowChanged(surface);
|
||||
}
|
||||
mHasSwapChain = true;
|
||||
}
|
||||
|
||||
@@ -595,7 +602,9 @@ public class UiHelper {
|
||||
if (mRenderSurface != null) {
|
||||
mRenderSurface.detach();
|
||||
}
|
||||
mRenderCallback.onDetachedFromSurface();
|
||||
if (mRenderCallback != null) {
|
||||
mRenderCallback.onDetachedFromSurface();
|
||||
}
|
||||
mHasSwapChain = false;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-8
@@ -110,7 +110,7 @@ class MainActivity : Activity() {
|
||||
}
|
||||
|
||||
private fun setupFilament() {
|
||||
engine = Engine.create()
|
||||
engine = Engine.Builder().featureLevel(Engine.FeatureLevel.FEATURE_LEVEL_0).build()
|
||||
renderer = engine.createRenderer()
|
||||
scene = engine.createScene()
|
||||
view = engine.createView()
|
||||
@@ -120,13 +120,8 @@ class MainActivity : Activity() {
|
||||
private fun setupView() {
|
||||
scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
|
||||
|
||||
if (engine.activeFeatureLevel == Engine.FeatureLevel.FEATURE_LEVEL_0) {
|
||||
// post-processing is not supported at feature level 0
|
||||
view.isPostProcessingEnabled = false
|
||||
} else {
|
||||
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
|
||||
// view.isPostProcessingEnabled = false
|
||||
}
|
||||
// post-processing is not supported at feature level 0
|
||||
view.isPostProcessingEnabled = false
|
||||
|
||||
// Tell the view which camera we want to use
|
||||
view.camera = camera
|
||||
|
||||
@@ -191,6 +191,7 @@ function build_clean {
|
||||
rm -Rf android/filamat-android/build android/filamat-android/.externalNativeBuild android/filamat-android/.cxx
|
||||
rm -Rf android/gltfio-android/build android/gltfio-android/.externalNativeBuild android/gltfio-android/.cxx
|
||||
rm -Rf android/filament-utils-android/build android/filament-utils-android/.externalNativeBuild android/filament-utils-android/.cxx
|
||||
rm -f compile_commands.json
|
||||
}
|
||||
|
||||
function build_clean_aggressive {
|
||||
@@ -232,6 +233,8 @@ function build_desktop_target {
|
||||
${ASAN_UBSAN_OPTION} \
|
||||
${architectures} \
|
||||
../..
|
||||
ln -sf "out/cmake-${lc_target}/compile_commands.json" \
|
||||
../../compile_commands.json
|
||||
fi
|
||||
${BUILD_COMMAND} ${build_targets}
|
||||
|
||||
@@ -287,6 +290,8 @@ function build_webgl_with_target {
|
||||
-DCMAKE_INSTALL_PREFIX="../webgl-${lc_target}/filament" \
|
||||
-DWEBGL=1 \
|
||||
../..
|
||||
ln -sf "out/cmake-webgl-${lc_target}/compile_commands.json" \
|
||||
../../compile_commands.json
|
||||
${BUILD_COMMAND} ${BUILD_TARGETS}
|
||||
)
|
||||
fi
|
||||
@@ -359,6 +364,8 @@ function build_android_target {
|
||||
${MATOPT_OPTION} \
|
||||
${VULKAN_ANDROID_OPTION} \
|
||||
../..
|
||||
ln -sf "out/cmake-android-${lc_target}-${arch}/compile_commands.json" \
|
||||
../../compile_commands.json
|
||||
fi
|
||||
|
||||
# We must always install Android libraries to build the AAR
|
||||
@@ -591,6 +598,8 @@ function build_ios_target {
|
||||
${MATDBG_OPTION} \
|
||||
${MATOPT_OPTION} \
|
||||
../..
|
||||
ln -sf "out/cmake-ios-${lc_target}-${arch}/compile_commands.json" \
|
||||
../../compile_commands.json
|
||||
fi
|
||||
|
||||
${BUILD_COMMAND}
|
||||
|
||||
+2
-22
@@ -218,6 +218,7 @@ set(MATERIAL_SRCS
|
||||
src/materials/colorGrading/customResolveAsSubpass.mat
|
||||
src/materials/debugShadowCascades.mat
|
||||
src/materials/defaultMaterial.mat
|
||||
src/materials/defaultMaterial0.mat
|
||||
src/materials/dof/dof.mat
|
||||
src/materials/dof/dofCoc.mat
|
||||
src/materials/dof/dofDownsample.mat
|
||||
@@ -237,6 +238,7 @@ set(MATERIAL_SRCS
|
||||
src/materials/ssao/bilateralBlurBentNormals.mat
|
||||
src/materials/ssao/mipmapDepth.mat
|
||||
src/materials/skybox.mat
|
||||
src/materials/skybox0.mat
|
||||
src/materials/ssao/sao.mat
|
||||
src/materials/ssao/saoBentNormals.mat
|
||||
src/materials/separableGaussianBlur.mat
|
||||
@@ -245,11 +247,6 @@ set(MATERIAL_SRCS
|
||||
src/materials/vsmMipmap.mat
|
||||
)
|
||||
|
||||
set(MATERIAL_ES2_SRCS
|
||||
src/materials/defaultMaterial0.mat
|
||||
src/materials/skybox0.mat
|
||||
)
|
||||
|
||||
# Embed the binary resource blob for materials.
|
||||
get_resgen_vars(${RESOURCE_DIR} materials)
|
||||
list(APPEND PRIVATE_HDRS ${RESGEN_HEADER})
|
||||
@@ -315,23 +312,6 @@ foreach (mat_src ${MATERIAL_SRCS})
|
||||
list(APPEND MATERIAL_BINS ${output_path})
|
||||
endforeach()
|
||||
|
||||
if (IS_MOBILE_TARGET AND FILAMENT_SUPPORTS_OPENGL)
|
||||
foreach (mat_src ${MATERIAL_ES2_SRCS})
|
||||
get_filename_component(localname "${mat_src}" NAME_WE)
|
||||
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
||||
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path}
|
||||
COMMAND matc -a opengl -p ${MATC_TARGET} ${MATC_OPT_FLAGS} -o ${output_path} ${fullname}
|
||||
MAIN_DEPENDENCY ${fullname}
|
||||
DEPENDS matc
|
||||
COMMENT "Compiling material ${mat_src} to ${output_path}"
|
||||
)
|
||||
list(APPEND MATERIAL_BINS ${output_path})
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
# Additional dependencies on included files for materials
|
||||
|
||||
add_custom_command(
|
||||
|
||||
@@ -154,6 +154,19 @@ enum class ShaderLanguage {
|
||||
MSL = 3,
|
||||
};
|
||||
|
||||
static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) {
|
||||
switch (shaderLanguage) {
|
||||
case ShaderLanguage::ESSL1:
|
||||
return "ESSL 1.0";
|
||||
case ShaderLanguage::ESSL3:
|
||||
return "ESSL 3.0";
|
||||
case ShaderLanguage::SPIRV:
|
||||
return "SPIR-V";
|
||||
case ShaderLanguage::MSL:
|
||||
return "MSL";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitmask for selecting render buffers
|
||||
*/
|
||||
@@ -343,6 +356,13 @@ enum class SamplerFormat : uint8_t {
|
||||
SHADOW = 3 //!< shadow sampler (PCF)
|
||||
};
|
||||
|
||||
//! Texture color space
|
||||
enum class SamplerTransferFunction : uint8_t {
|
||||
UNDEFINED = 0, //!< don't care
|
||||
IDENTITY = 1, //!< sampled as-is
|
||||
SRGB_TO_LINEAR = 2, //!< sampled as sRGB and converted to linear
|
||||
};
|
||||
|
||||
/**
|
||||
* Supported element types
|
||||
*/
|
||||
|
||||
@@ -114,6 +114,7 @@ public:
|
||||
* Platform. The <insert> and <retrieve> Invocables may be called at any time and
|
||||
* from any thread from the time at which setBlobFunc is called until the time that Platform
|
||||
* is destroyed. Concurrent calls to these functions from different threads is also allowed.
|
||||
* Either function can be null.
|
||||
*
|
||||
* @param insertBlob an Invocable that inserts a new value into the cache and associates
|
||||
* it with the given key
|
||||
@@ -123,9 +124,21 @@ public:
|
||||
void setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept;
|
||||
|
||||
/**
|
||||
* @return true if setBlobFunc was called.
|
||||
* @return true if insertBlob is valid.
|
||||
*/
|
||||
bool hasBlobFunc() const noexcept;
|
||||
bool hasInsertBlobFunc() const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if retrieveBlob is valid.
|
||||
*/
|
||||
bool hasRetrieveBlobFunc() const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if either of insertBlob or retrieveBlob are valid.
|
||||
*/
|
||||
bool hasBlobFunc() const noexcept {
|
||||
return hasInsertBlobFunc() || hasRetrieveBlobFunc();
|
||||
}
|
||||
|
||||
/**
|
||||
* To insert a new binary value into the cache and associate it with a given
|
||||
|
||||
@@ -239,14 +239,16 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// FIXME: We should be using a Spinlock here, at least on platforms where mutexes are not
|
||||
// efficient (i.e. non-Linux). However, we've seen some hangs on that spinlock, which
|
||||
// we don't understand well (b/308029108).
|
||||
#ifndef NDEBUG
|
||||
using HandleArena = utils::Arena<Allocator,
|
||||
utils::LockingPolicy::SpinLock,
|
||||
utils::LockingPolicy::Mutex,
|
||||
utils::TrackingPolicy::DebugAndHighWatermark>;
|
||||
#else
|
||||
using HandleArena = utils::Arena<Allocator,
|
||||
utils::LockingPolicy::SpinLock>;
|
||||
utils::LockingPolicy::Mutex>;
|
||||
#endif
|
||||
|
||||
// allocateHandle()/deallocateHandle() selects the pool to use at compile-time based on the
|
||||
|
||||
@@ -28,14 +28,16 @@ bool Platform::pumpEvents() noexcept {
|
||||
}
|
||||
|
||||
void Platform::setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept {
|
||||
if (!mInsertBlob && !mRetrieveBlob) {
|
||||
mInsertBlob = std::move(insertBlob);
|
||||
mRetrieveBlob = std::move(retrieveBlob);
|
||||
}
|
||||
mInsertBlob = std::move(insertBlob);
|
||||
mRetrieveBlob = std::move(retrieveBlob);
|
||||
}
|
||||
|
||||
bool Platform::hasBlobFunc() const noexcept {
|
||||
return mInsertBlob && mRetrieveBlob;
|
||||
bool Platform::hasInsertBlobFunc() const noexcept {
|
||||
return bool(mInsertBlob);
|
||||
}
|
||||
|
||||
bool Platform::hasRetrieveBlobFunc() const noexcept {
|
||||
return bool(mRetrieveBlob);
|
||||
}
|
||||
|
||||
void Platform::insertBlob(void const* key, size_t keySize, void const* value, size_t valueSize) {
|
||||
|
||||
@@ -373,16 +373,19 @@ constexpr inline GLenum getCullingMode(CullingMode mode) noexcept {
|
||||
constexpr inline std::pair<GLenum, GLenum> textureFormatToFormatAndType(
|
||||
TextureFormat format) noexcept {
|
||||
switch (format) {
|
||||
case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE };
|
||||
case TextureFormat::RGBA8: return { GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
case TextureFormat::RGB565: return { GL_RGB, GL_UNSIGNED_SHORT_5_6_5 };
|
||||
case TextureFormat::RGB5_A1: return { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 };
|
||||
case TextureFormat::RGBA4: return { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 };
|
||||
case TextureFormat::DEPTH16: return { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT };
|
||||
case TextureFormat::DEPTH24: return { GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
|
||||
case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE };
|
||||
case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE };
|
||||
case TextureFormat::SRGB8: return { GL_RGB, GL_UNSIGNED_BYTE };
|
||||
case TextureFormat::RGBA8: return { GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
case TextureFormat::SRGB8_A8: return { GL_RGBA, GL_UNSIGNED_BYTE };
|
||||
case TextureFormat::RGB565: return { GL_RGB, GL_UNSIGNED_SHORT_5_6_5 };
|
||||
case TextureFormat::RGB5_A1: return { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 };
|
||||
case TextureFormat::RGBA4: return { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 };
|
||||
case TextureFormat::DEPTH16: return { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT };
|
||||
case TextureFormat::DEPTH24: return { GL_DEPTH_COMPONENT, GL_UNSIGNED_INT };
|
||||
case TextureFormat::DEPTH24_STENCIL8:
|
||||
return { GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8 };
|
||||
default: return { GL_NONE, GL_NONE };
|
||||
return { GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8 };
|
||||
default: return { GL_NONE, GL_NONE };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include "OpenGLBlobCache.h"
|
||||
|
||||
#include "OpenGLContext.h"
|
||||
|
||||
#include <backend/Platform.h>
|
||||
#include <backend/Program.h>
|
||||
|
||||
@@ -28,17 +30,18 @@ struct OpenGLBlobCache::Blob {
|
||||
char data[];
|
||||
};
|
||||
|
||||
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
Program const& program) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
OpenGLBlobCache::OpenGLBlobCache(OpenGLContext& gl) noexcept
|
||||
: mCachingSupported(gl.gets.num_program_binary_formats >= 1) {
|
||||
}
|
||||
|
||||
if (!platform.hasBlobFunc()) {
|
||||
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
Program const& program) const noexcept {
|
||||
SYSTRACE_CALL();
|
||||
if (!mCachingSupported || !platform.hasRetrieveBlobFunc()) {
|
||||
// the key is never updated in that case
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYSTRACE_CONTEXT();
|
||||
|
||||
GLuint programId = 0;
|
||||
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
@@ -64,8 +67,10 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
|
||||
programId = glCreateProgram();
|
||||
|
||||
SYSTRACE_NAME("glProgramBinary");
|
||||
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
|
||||
{ // scope for systrace
|
||||
SYSTRACE_NAME("glProgramBinary");
|
||||
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
|
||||
}
|
||||
|
||||
if (UTILS_UNLIKELY(glGetError() != GL_NO_ERROR)) {
|
||||
// glProgramBinary can fail if for instance the driver has been updated
|
||||
@@ -85,46 +90,36 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
|
||||
void OpenGLBlobCache::insert(Platform& platform,
|
||||
BlobCacheKey const& key, GLuint program) noexcept {
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
SYSTRACE_CALL();
|
||||
if (platform.hasBlobFunc()) {
|
||||
SYSTRACE_CONTEXT();
|
||||
GLenum format;
|
||||
GLint programBinarySize = 0;
|
||||
if (!mCachingSupported || !platform.hasInsertBlobFunc()) {
|
||||
// the key is never updated in that case
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
GLenum format;
|
||||
GLint programBinarySize = 0;
|
||||
{ // scope for systrace
|
||||
SYSTRACE_NAME("glGetProgramiv");
|
||||
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinarySize);
|
||||
if (programBinarySize) {
|
||||
size_t const size = sizeof(Blob) + programBinarySize;
|
||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
||||
if (UTILS_LIKELY(blob)) {
|
||||
}
|
||||
if (programBinarySize) {
|
||||
size_t const size = sizeof(Blob) + programBinarySize;
|
||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
||||
if (UTILS_LIKELY(blob)) {
|
||||
{ // scope for systrace
|
||||
SYSTRACE_NAME("glGetProgramBinary");
|
||||
glGetProgramBinary(program, programBinarySize, &programBinarySize, &format,
|
||||
blob->data);
|
||||
GLenum const error = glGetError();
|
||||
if (error == GL_NO_ERROR) {
|
||||
blob->format = format;
|
||||
platform.insertBlob(key.data(), key.size(), blob.get(), size);
|
||||
}
|
||||
glGetProgramBinary(program, programBinarySize,
|
||||
&programBinarySize, &format, blob->data);
|
||||
}
|
||||
GLenum const error = glGetError();
|
||||
if (error == GL_NO_ERROR) {
|
||||
blob->format = format;
|
||||
platform.insertBlob(key.data(), key.size(), blob.get(), size);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLBlobCache::insert(Platform& platform, BlobCacheKey const& key,
|
||||
GLenum format, void* data, GLsizei programBinarySize) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
if (platform.hasBlobFunc()) {
|
||||
if (programBinarySize) {
|
||||
size_t const size = sizeof(Blob) + programBinarySize;
|
||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
||||
if (UTILS_LIKELY(blob)) {
|
||||
blob->format = format;
|
||||
memcpy(blob->data, data, programBinarySize);
|
||||
platform.insertBlob(key.data(), key.size(), blob.get(), size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -25,20 +25,21 @@ namespace filament::backend {
|
||||
|
||||
class Platform;
|
||||
class Program;
|
||||
class OpenGLContext;
|
||||
|
||||
class OpenGLBlobCache {
|
||||
public:
|
||||
static GLuint retrieve(BlobCacheKey* key, Platform& platform,
|
||||
Program const& program) noexcept;
|
||||
explicit OpenGLBlobCache(OpenGLContext& gl) noexcept;
|
||||
|
||||
static void insert(Platform& platform,
|
||||
GLuint retrieve(BlobCacheKey* key, Platform& platform,
|
||||
Program const& program) const noexcept;
|
||||
|
||||
void insert(Platform& platform,
|
||||
BlobCacheKey const& key, GLuint program) noexcept;
|
||||
|
||||
static void insert(Platform& platform, BlobCacheKey const& key,
|
||||
GLenum format, void* data, GLsizei programBinarySize) noexcept;
|
||||
|
||||
private:
|
||||
struct Blob;
|
||||
bool mCachingSupported = false;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -99,38 +99,41 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
|
||||
if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,
|
||||
&gets.max_uniform_block_size);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
|
||||
&gets.max_uniform_buffer_bindings);
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
|
||||
&gets.uniform_buffer_offset_alignment);
|
||||
glGetIntegerv(GL_MAX_SAMPLES,
|
||||
&gets.max_samples);
|
||||
glGetIntegerv(GL_MAX_DRAW_BUFFERS,
|
||||
&gets.max_draw_buffers);
|
||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
||||
&gets.max_transform_feedback_separate_attribs);
|
||||
#ifdef GL_EXT_texture_filter_anisotropic
|
||||
if (ext.EXT_texture_filter_anisotropic) {
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gets.max_anisotropy);
|
||||
}
|
||||
#endif
|
||||
glGetIntegerv(GL_MAX_DRAW_BUFFERS,
|
||||
&gets.max_draw_buffers);
|
||||
glGetIntegerv(GL_MAX_SAMPLES,
|
||||
&gets.max_samples);
|
||||
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
||||
&gets.max_transform_feedback_separate_attribs);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,
|
||||
&gets.max_uniform_block_size);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
|
||||
&gets.max_uniform_buffer_bindings);
|
||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS,
|
||||
&gets.num_program_binary_formats);
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
|
||||
&gets.uniform_buffer_offset_alignment);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BACKEND_OPENGL_VERSION_GLES
|
||||
else {
|
||||
gets.max_anisotropy = 1;
|
||||
gets.max_draw_buffers = 1;
|
||||
gets.max_samples = 1;
|
||||
gets.max_transform_feedback_separate_attribs = 0;
|
||||
gets.max_uniform_block_size = 0;
|
||||
gets.max_uniform_buffer_bindings = 0;
|
||||
gets.num_program_binary_formats = 0;
|
||||
gets.uniform_buffer_offset_alignment = 0;
|
||||
gets.max_samples = 1;
|
||||
gets.max_draw_buffers = 1;
|
||||
gets.max_transform_feedback_separate_attribs = 0;
|
||||
gets.max_anisotropy = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
slog.v << "Feature level: " << +mFeatureLevel << '\n';
|
||||
slog.v << "Active workarounds: " << '\n';
|
||||
UTILS_NOUNROLL
|
||||
@@ -143,13 +146,29 @@ OpenGLContext::OpenGLContext() noexcept {
|
||||
|
||||
#ifndef NDEBUG
|
||||
// this is useful for development
|
||||
slog.v << "GL_MAX_DRAW_BUFFERS = " << gets.max_draw_buffers << '\n'
|
||||
<< "GL_MAX_RENDERBUFFER_SIZE = " << gets.max_renderbuffer_size << '\n'
|
||||
<< "GL_MAX_SAMPLES = " << gets.max_samples << '\n'
|
||||
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = " << gets.max_anisotropy << '\n'
|
||||
<< "GL_MAX_UNIFORM_BLOCK_SIZE = " << gets.max_uniform_block_size << '\n'
|
||||
<< "GL_MAX_TEXTURE_IMAGE_UNITS = " << gets.max_texture_image_units << '\n'
|
||||
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = " << gets.uniform_buffer_offset_alignment << '\n'
|
||||
slog.v
|
||||
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = "
|
||||
<< gets.max_anisotropy << '\n'
|
||||
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = "
|
||||
<< gets.max_combined_texture_image_units << '\n'
|
||||
<< "GL_MAX_DRAW_BUFFERS = "
|
||||
<< gets.max_draw_buffers << '\n'
|
||||
<< "GL_MAX_RENDERBUFFER_SIZE = "
|
||||
<< gets.max_renderbuffer_size << '\n'
|
||||
<< "GL_MAX_SAMPLES = "
|
||||
<< gets.max_samples << '\n'
|
||||
<< "GL_MAX_TEXTURE_IMAGE_UNITS = "
|
||||
<< gets.max_texture_image_units << '\n'
|
||||
<< "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = "
|
||||
<< gets.max_transform_feedback_separate_attribs << '\n'
|
||||
<< "GL_MAX_UNIFORM_BLOCK_SIZE = "
|
||||
<< gets.max_uniform_block_size << '\n'
|
||||
<< "GL_MAX_UNIFORM_BUFFER_BINDINGS = "
|
||||
<< gets.max_uniform_buffer_bindings << '\n'
|
||||
<< "GL_NUM_PROGRAM_BINARY_FORMATS = "
|
||||
<< gets.num_program_binary_formats << '\n'
|
||||
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = "
|
||||
<< gets.uniform_buffer_offset_alignment << '\n'
|
||||
;
|
||||
flush(slog.v);
|
||||
#endif
|
||||
|
||||
@@ -153,14 +153,15 @@ public:
|
||||
// glGet*() values
|
||||
struct Gets {
|
||||
GLfloat max_anisotropy;
|
||||
GLint max_combined_texture_image_units;
|
||||
GLint max_draw_buffers;
|
||||
GLint max_renderbuffer_size;
|
||||
GLint max_samples;
|
||||
GLint max_uniform_block_size;
|
||||
GLint max_texture_image_units;
|
||||
GLint max_combined_texture_image_units;
|
||||
GLint max_transform_feedback_separate_attribs;
|
||||
GLint max_uniform_buffer_bindings;
|
||||
GLint max_uniform_block_size;
|
||||
GLint max_uniform_buffer_bindings;
|
||||
GLint num_program_binary_formats;
|
||||
GLint uniform_buffer_offset_alignment;
|
||||
} gets = {};
|
||||
|
||||
|
||||
@@ -1290,7 +1290,9 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
checkDimensions(rt->gl.color[i], color[i].level);
|
||||
}
|
||||
}
|
||||
glDrawBuffers((GLsizei)maxDrawBuffers, bufs);
|
||||
if (UTILS_LIKELY(!getContext().isES2())) {
|
||||
glDrawBuffers((GLsizei)maxDrawBuffers, bufs);
|
||||
}
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
#endif
|
||||
@@ -1451,6 +1453,11 @@ void OpenGLDriver::destroySamplerGroup(Handle<HwSamplerGroup> sbh) {
|
||||
DEBUG_MARKER()
|
||||
if (sbh) {
|
||||
GLSamplerGroup* sb = handle_cast<GLSamplerGroup*>(sbh);
|
||||
for (auto& binding : mSamplerBindings) {
|
||||
if (binding == sb) {
|
||||
binding = nullptr;
|
||||
}
|
||||
}
|
||||
destruct(sbh, sb);
|
||||
}
|
||||
}
|
||||
@@ -1459,9 +1466,9 @@ void OpenGLDriver::destroyTexture(Handle<HwTexture> th) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
if (th) {
|
||||
auto& gl = mContext;
|
||||
GLTexture* t = handle_cast<GLTexture*>(th);
|
||||
if (UTILS_LIKELY(!t->gl.imported)) {
|
||||
auto& gl = mContext;
|
||||
if (UTILS_LIKELY(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||
if (UTILS_UNLIKELY(t->hwStream)) {
|
||||
@@ -1479,6 +1486,8 @@ void OpenGLDriver::destroyTexture(Handle<HwTexture> th) {
|
||||
if (t->gl.sidecarRenderBufferMS) {
|
||||
glDeleteRenderbuffers(1, &t->gl.sidecarRenderBufferMS);
|
||||
}
|
||||
} else {
|
||||
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||
}
|
||||
destruct(th, t);
|
||||
}
|
||||
@@ -1775,6 +1784,10 @@ bool OpenGLDriver::isRenderTargetFormatSupported(TextureFormat format) {
|
||||
// support more formats, but it requires querying GL_INTERNALFORMAT_SUPPORTED which is not
|
||||
// available in OpenGL ES.
|
||||
auto& gl = mContext;
|
||||
if (UTILS_UNLIKELY(gl.isES2())) {
|
||||
auto [es2format, type] = textureFormatToFormatAndType(format);
|
||||
return es2format != GL_NONE && type != GL_NONE;
|
||||
}
|
||||
switch (format) {
|
||||
// Core formats.
|
||||
case TextureFormat::R8:
|
||||
@@ -2269,8 +2282,16 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
|
||||
return;
|
||||
}
|
||||
|
||||
GLenum const glFormat = getFormat(p.format);
|
||||
GLenum const glType = getType(p.type);
|
||||
GLenum glFormat;
|
||||
GLenum glType;
|
||||
if (mContext.isES2()) {
|
||||
auto formatAndType = textureFormatToFormatAndType(t->format);
|
||||
glFormat = formatAndType.first;
|
||||
glType = formatAndType.second;
|
||||
} else {
|
||||
glFormat = getFormat(p.format);
|
||||
glType = getType(p.type);
|
||||
}
|
||||
|
||||
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
|
||||
if (!gl.isES2()) {
|
||||
|
||||
@@ -212,6 +212,7 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* const gld) const noexcept {
|
||||
assert_invariant(binding < Program::SAMPLER_BINDING_COUNT);
|
||||
auto const * const sb = samplerBindings[binding];
|
||||
assert_invariant(sb);
|
||||
if (!sb) continue; // should never happen, this would be a user error.
|
||||
for (uint8_t j = 0, m = sb->textureUnitEntries.size(); j < m; ++j, ++tmu) { // "<=" on purpose here
|
||||
const GLTexture* const t = sb->textureUnitEntries[j].texture;
|
||||
if (t) { // program may not use all samplers of sampler group
|
||||
|
||||
@@ -140,6 +140,7 @@ void* ShaderCompilerService::getUserData(const program_token_t& token) noexcept
|
||||
|
||||
ShaderCompilerService::ShaderCompilerService(OpenGLDriver& driver)
|
||||
: mDriver(driver),
|
||||
mBlobCache(driver.getContext()),
|
||||
mCallbackManager(driver),
|
||||
KHR_parallel_shader_compile(driver.getContext().ext.KHR_parallel_shader_compile) {
|
||||
}
|
||||
@@ -219,7 +220,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
||||
token->attributes = std::move(program.getAttributes());
|
||||
}
|
||||
|
||||
token->gl.program = OpenGLBlobCache::retrieve(&token->key, mDriver.mPlatform, program);
|
||||
token->gl.program = mBlobCache.retrieve(&token->key, mDriver.mPlatform, program);
|
||||
if (token->gl.program) {
|
||||
return token;
|
||||
}
|
||||
@@ -264,7 +265,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
||||
// caching must be the last thing we do
|
||||
if (token->key && status == GL_TRUE) {
|
||||
// Attempt to cache. This calls glGetProgramBinary.
|
||||
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, glProgram);
|
||||
mBlobCache.insert(mDriver.mPlatform, token->key, glProgram);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -317,7 +318,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
|
||||
// do this later, maybe depending on CPU usage?
|
||||
// attempt to cache if we don't have a thread pool (otherwise it's done
|
||||
// by the pool).
|
||||
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||
mBlobCache.insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -431,7 +432,7 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) noexcept {
|
||||
mCallbackManager.put(token->handle);
|
||||
|
||||
if (token->key) {
|
||||
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||
mBlobCache.insert(mDriver.mPlatform, token->key, token->gl.program);
|
||||
}
|
||||
} else {
|
||||
// if we don't have a program yet, block until we get it.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "CallbackManager.h"
|
||||
#include "CompilerThreadPool.h"
|
||||
#include "OpenGLBlobCache.h"
|
||||
|
||||
#include <backend/CallbackHandler.h>
|
||||
#include <backend/Program.h>
|
||||
@@ -95,6 +96,7 @@ public:
|
||||
|
||||
private:
|
||||
OpenGLDriver& mDriver;
|
||||
OpenGLBlobCache mBlobCache;
|
||||
CallbackManager mCallbackManager;
|
||||
CompilerThreadPool mCompilerThreadPool;
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ error:
|
||||
}
|
||||
|
||||
bool PlatformWGL::isExtraContextSupported() const noexcept {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PlatformWGL::createContext(bool shared) {
|
||||
|
||||
@@ -272,6 +272,8 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt
|
||||
return;
|
||||
}
|
||||
|
||||
assert_invariant(hostData->size > 0 && "Data is empty");
|
||||
|
||||
// Otherwise, use vkCmdCopyBufferToImage.
|
||||
void* mapped = nullptr;
|
||||
VulkanStage const* stage = mStagePool.acquireStage(hostData->size);
|
||||
|
||||
@@ -110,6 +110,10 @@ public:
|
||||
* @return The maximum capacity of the BufferObject.
|
||||
*/
|
||||
size_t getByteCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~BufferObject() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -565,6 +565,10 @@ public:
|
||||
* @return effective full field of view in degrees
|
||||
*/
|
||||
static double computeEffectiveFov(double fovInDegrees, double focusDistance) noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Camera() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -478,6 +478,10 @@ public:
|
||||
private:
|
||||
friend class FColorGrading;
|
||||
};
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~ColorGrading() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -142,6 +142,10 @@ public:
|
||||
float pid_i = 0.0f;
|
||||
float pid_d = 0.0f;
|
||||
};
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~DebugRegistry() = default;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -172,10 +172,11 @@ public:
|
||||
using Platform = backend::Platform;
|
||||
using Backend = backend::Backend;
|
||||
using DriverConfig = backend::Platform::DriverConfig;
|
||||
using FeatureLevel = backend::FeatureLevel;
|
||||
|
||||
/**
|
||||
* Config is used to define the memory footprint used by the engine, such as the
|
||||
* command buffer size. Config can be used to customize engine requirements based
|
||||
* command buffer size. Config can be used to customize engine requirements based
|
||||
* on the applications needs.
|
||||
*
|
||||
* .perRenderPassArenaSizeMB (default: 3 MiB)
|
||||
@@ -351,6 +352,12 @@ public:
|
||||
*/
|
||||
Builder& sharedContext(void* sharedContext) noexcept;
|
||||
|
||||
/**
|
||||
* @param featureLevel The feature level at which initialize Filament.
|
||||
* @return A reference to this Builder for chaining calls.
|
||||
*/
|
||||
Builder& featureLevel(FeatureLevel featureLevel) noexcept;
|
||||
|
||||
#if UTILS_HAS_THREADING
|
||||
/**
|
||||
* Creates the filament Engine asynchronously.
|
||||
@@ -482,9 +489,6 @@ public:
|
||||
*/
|
||||
static void destroy(Engine* engine);
|
||||
|
||||
using FeatureLevel = backend::FeatureLevel;
|
||||
|
||||
|
||||
/**
|
||||
* Query the feature level supported by the selected backend.
|
||||
*
|
||||
@@ -496,17 +500,23 @@ public:
|
||||
FeatureLevel getSupportedFeatureLevel() const noexcept;
|
||||
|
||||
/**
|
||||
* Activate all features of a given feature level. By default FeatureLevel::FEATURE_LEVEL_1 is
|
||||
* active. The selected feature level must not be higher than the value returned by
|
||||
* getActiveFeatureLevel() and it's not possible lower the active feature level.
|
||||
* Activate all features of a given feature level. If an explicit feature level is not specified
|
||||
* at Engine initialization time via Builder::featureLevel, the default feature level is
|
||||
* FeatureLevel::FEATURE_LEVEL_0 on devices not compatible with GLES 3.0; otherwise, the default
|
||||
* is FeatureLevel::FEATURE_LEVEL_1. The selected feature level must not be higher than the
|
||||
* value returned by getActiveFeatureLevel() and it's not possible lower the active feature
|
||||
* level. Additionally, it is not possible to modify the feature level at all if the Engine was
|
||||
* initialized at FeatureLevel::FEATURE_LEVEL_0.
|
||||
*
|
||||
* @param featureLevel the feature level to activate. If featureLevel is lower than
|
||||
* getActiveFeatureLevel(), the current (higher) feature level is kept.
|
||||
* If featureLevel is higher than getSupportedFeatureLevel(), an exception
|
||||
* is thrown, or the program is terminated if exceptions are disabled.
|
||||
* getActiveFeatureLevel(), the current (higher) feature level is kept. If
|
||||
* featureLevel is higher than getSupportedFeatureLevel(), or if the engine
|
||||
* was initialized at feature level 0, an exception is thrown, or the
|
||||
* program is terminated if exceptions are disabled.
|
||||
*
|
||||
* @return the active feature level.
|
||||
*
|
||||
* @see Builder::featureLevel
|
||||
* @see getSupportedFeatureLevel
|
||||
* @see getActiveFeatureLevel
|
||||
*/
|
||||
@@ -827,14 +837,14 @@ public:
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
/**
|
||||
* WebGL only: Tells the driver to reset any internal state tracking if necessary.
|
||||
*
|
||||
* This is only useful when integrating an external renderer into Filament on platforms
|
||||
*
|
||||
* This is only useful when integrating an external renderer into Filament on platforms
|
||||
* like WebGL, where share contexts do not exist. Filament keeps track of the GL
|
||||
* state it has set (like which texture is bound), and does not re-set that state if
|
||||
* it does not think it needs to. However, if an external renderer has set different
|
||||
* state in the mean time, Filament will use that new state unknowingly.
|
||||
*
|
||||
* If you are in this situation, call this function - ideally only once per frame,
|
||||
*
|
||||
* If you are in this situation, call this function - ideally only once per frame,
|
||||
* immediately after calling Engine::execute().
|
||||
*/
|
||||
void resetBackendState() noexcept;
|
||||
|
||||
@@ -75,6 +75,10 @@ public:
|
||||
* FenceStatus::ERROR otherwise.
|
||||
*/
|
||||
static FenceStatus waitAndDestroy(Fence* fence, Mode mode = Mode::FLUSH);
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Fence() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -49,8 +49,6 @@ public:
|
||||
// prevent heap allocation
|
||||
static void *operator new (size_t) = delete;
|
||||
static void *operator new[] (size_t) = delete;
|
||||
static void operator delete (void*) = delete;
|
||||
static void operator delete[](void*) = delete;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -118,6 +118,10 @@ public:
|
||||
* @return The number of indices the IndexBuffer holds.
|
||||
*/
|
||||
size_t getIndexCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~IndexBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -342,6 +342,10 @@ public:
|
||||
/** @deprecated use static versions instead */
|
||||
UTILS_DEPRECATED
|
||||
math::float4 getColorEstimate(math::float3 direction) const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~IndirectLight() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -91,6 +91,10 @@ public:
|
||||
* @param offset index of the first instance to set local transforms
|
||||
*/
|
||||
void setLocalTransforms(math::mat4f const* localTransforms, size_t count, size_t offset = 0);
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~InstanceBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -143,20 +143,13 @@ public:
|
||||
using Instance = utils::EntityInstance<LightManager>;
|
||||
|
||||
/**
|
||||
* Returns the number of component in the LightManager, not that component are not
|
||||
* Returns the number of component in the LightManager, note that component are not
|
||||
* guaranteed to be active. Use the EntityManager::isAlive() before use if needed.
|
||||
*
|
||||
* @return number of component in the LightManager
|
||||
*/
|
||||
size_t getComponentCount() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the list of Entity for all components. Use getComponentCount() to know the size
|
||||
* of the list.
|
||||
* @return a pointer to Entity
|
||||
*/
|
||||
utils::Entity const* getEntities() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether a particular Entity is associated with a component of this LightManager
|
||||
* @param e An Entity.
|
||||
@@ -164,6 +157,24 @@ public:
|
||||
*/
|
||||
bool hasComponent(utils::Entity e) const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if the this manager has no components
|
||||
*/
|
||||
bool empty() const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the `Entity` of the component from its `Instance`.
|
||||
* @param i Instance of the component obtained from getInstance()
|
||||
* @return
|
||||
*/
|
||||
utils::Entity getEntity(Instance i) const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the Entities of all the components of this manager.
|
||||
* @return A list, in no particular order, of all the entities managed by this manager.
|
||||
*/
|
||||
utils::Entity const* getEntities() const noexcept;
|
||||
|
||||
/**
|
||||
* Gets an Instance representing the Light component associated with the given Entity.
|
||||
* @param e An Entity.
|
||||
@@ -953,19 +964,9 @@ public:
|
||||
*/
|
||||
bool isShadowCaster(Instance i) const noexcept;
|
||||
|
||||
/**
|
||||
* Helper to process all components with a given function
|
||||
* @tparam F a void(Entity entity, Instance instance)
|
||||
* @param func a function of type F
|
||||
*/
|
||||
template<typename F>
|
||||
void forEachComponent(F func) noexcept {
|
||||
utils::Entity const* const pEntity = getEntities();
|
||||
for (size_t i = 0, c = getComponentCount(); i < c; i++) {
|
||||
// Instance 0 is the invalid instance
|
||||
func(pEntity[i], Instance(i + 1));
|
||||
}
|
||||
}
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~LightManager() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -294,6 +294,9 @@ public:
|
||||
//! Returns the reflection mode used by this material.
|
||||
ReflectionMode getReflectionMode() const noexcept;
|
||||
|
||||
//! Returns the minimum required feature level for this material.
|
||||
backend::FeatureLevel getFeatureLevel() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the number of parameters declared by this material.
|
||||
* The returned value can be 0.
|
||||
@@ -375,6 +378,10 @@ public:
|
||||
|
||||
//! Returns this material's default instance.
|
||||
MaterialInstance const* getDefaultInstance() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Material() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -479,6 +479,10 @@ public:
|
||||
*/
|
||||
void setStencilWriteMask(uint8_t writeMask,
|
||||
StencilFace face = StencilFace::FRONT_AND_BACK) noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~MaterialInstance() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -136,6 +136,10 @@ public:
|
||||
* @return The number of targets the MorphTargetBuffer holds.
|
||||
*/
|
||||
size_t getCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~MorphTargetBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -180,6 +180,10 @@ public:
|
||||
* @return Number of color attachments usable in a render target.
|
||||
*/
|
||||
uint8_t getSupportedColorAttachmentsCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~RenderTarget() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -102,6 +102,29 @@ public:
|
||||
*/
|
||||
Instance getInstance(utils::Entity e) const noexcept;
|
||||
|
||||
/**
|
||||
* @return the number of Components
|
||||
*/
|
||||
size_t getComponentCount() const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if the this manager has no components
|
||||
*/
|
||||
bool empty() const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the `Entity` of the component from its `Instance`.
|
||||
* @param i Instance of the component obtained from getInstance()
|
||||
* @return
|
||||
*/
|
||||
utils::Entity getEntity(Instance i) const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the Entities of all the components of this manager.
|
||||
* @return A list, in no particular order, of all the entities managed by this manager.
|
||||
*/
|
||||
utils::Entity const* getEntities() const noexcept;
|
||||
|
||||
/**
|
||||
* The transformation associated with a skinning joint.
|
||||
*
|
||||
@@ -829,6 +852,10 @@ public:
|
||||
typename = typename is_supported_index_type<INDEX>::type>
|
||||
static Box computeAABB(VECTOR const* vertices, INDEX const* indices, size_t count,
|
||||
size_t stride = sizeof(VECTOR)) noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~RenderableManager() = default;
|
||||
};
|
||||
|
||||
RenderableManager::Builder& RenderableManager::Builder::morphing(uint8_t level, size_t primitiveIndex,
|
||||
|
||||
@@ -579,6 +579,10 @@ public:
|
||||
* getUserTime()
|
||||
*/
|
||||
void resetUserTime();
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Renderer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -140,16 +140,22 @@ public:
|
||||
void removeEntities(const utils::Entity* entities, size_t count);
|
||||
|
||||
/**
|
||||
* Returns the number of Renderable objects in the Scene.
|
||||
* Returns the total number of Entities in the Scene, whether alive or not.
|
||||
* @return Total number of Entities in the Scene.
|
||||
*/
|
||||
size_t getEntityCount() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the number of active (alive) Renderable objects in the Scene.
|
||||
*
|
||||
* @return number of Renderable objects in the Scene.
|
||||
* @return The number of active (alive) Renderable objects in the Scene.
|
||||
*/
|
||||
size_t getRenderableCount() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the total number of Light objects in the Scene.
|
||||
* Returns the number of active (alive) Light objects in the Scene.
|
||||
*
|
||||
* @return The total number of Light objects in the Scene.
|
||||
* @return The number of active (alive) Light objects in the Scene.
|
||||
*/
|
||||
size_t getLightCount() const noexcept;
|
||||
|
||||
@@ -168,6 +174,10 @@ public:
|
||||
* @param functor User provided functor called for each entity in the scene
|
||||
*/
|
||||
void forEach(utils::Invocable<void(utils::Entity entity)>&& functor) const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Scene() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -115,6 +115,10 @@ public:
|
||||
* @return The number of bones the SkinningBuffer holds.
|
||||
*/
|
||||
size_t getBoneCount() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~SkinningBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -174,6 +174,10 @@ public:
|
||||
* @return the associated texture, or null if it does not exist
|
||||
*/
|
||||
Texture const* getTexture() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Skybox() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -207,6 +207,10 @@ public:
|
||||
* @return timestamp in nanosecond.
|
||||
*/
|
||||
int64_t getTimestamp() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Stream() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -286,6 +286,10 @@ public:
|
||||
void setFrameCompletedCallback(backend::CallbackHandler* handler = nullptr,
|
||||
FrameCompletedCallback&& callback = {}) noexcept;
|
||||
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~SwapChain() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -541,6 +541,10 @@ public:
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~Texture() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -118,6 +118,29 @@ public:
|
||||
*/
|
||||
Instance getInstance(utils::Entity e) const noexcept;
|
||||
|
||||
/**
|
||||
* @return the number of Components
|
||||
*/
|
||||
size_t getComponentCount() const noexcept;
|
||||
|
||||
/**
|
||||
* @return true if the this manager has no components
|
||||
*/
|
||||
bool empty() const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the `Entity` of the component from its `Instance`.
|
||||
* @param i Instance of the component obtained from getInstance()
|
||||
* @return
|
||||
*/
|
||||
utils::Entity getEntity(Instance i) const noexcept;
|
||||
|
||||
/**
|
||||
* Retrieve the Entities of all the components of this manager.
|
||||
* @return A list, in no particular order, of all the entities managed by this manager.
|
||||
*/
|
||||
utils::Entity const* getEntities() const noexcept;
|
||||
|
||||
/**
|
||||
* Enables or disable the accurate translation mode. Disabled by default.
|
||||
*
|
||||
@@ -261,7 +284,7 @@ public:
|
||||
* returns the value set by setTransform().
|
||||
* @see setTransform()
|
||||
*/
|
||||
const math::mat4 getTransformAccurate(Instance ci) const noexcept;
|
||||
math::mat4 getTransformAccurate(Instance ci) const noexcept;
|
||||
|
||||
/**
|
||||
* Return the world transform of a transform component.
|
||||
@@ -279,7 +302,7 @@ public:
|
||||
* composition of this component's local transform with its parent's world transform.
|
||||
* @see setTransform()
|
||||
*/
|
||||
const math::mat4 getWorldTransformAccurate(Instance ci) const noexcept;
|
||||
math::mat4 getWorldTransformAccurate(Instance ci) const noexcept;
|
||||
|
||||
/**
|
||||
* Opens a local transform transaction. During a transaction, getWorldTransform() can
|
||||
@@ -308,6 +331,10 @@ public:
|
||||
* @see openLocalTransformTransaction(), setTransform()
|
||||
*/
|
||||
void commitLocalTransformTransaction() noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~TransformManager() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -207,6 +207,10 @@ public:
|
||||
* @param bufferObject The handle to the GPU data that will be used in this buffer slot.
|
||||
*/
|
||||
void setBufferObjectAt(Engine& engine, uint8_t bufferIndex, BufferObject const* bufferObject);
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~VertexBuffer() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -894,6 +894,10 @@ public:
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
AmbientOcclusion getAmbientOcclusion() const noexcept;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~View() = default;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -104,12 +104,12 @@ Froxelizer::Froxelizer(FEngine& engine)
|
||||
static_assert(std::is_same_v<RecordBufferType, uint8_t>,
|
||||
"Record Buffer must use bytes");
|
||||
|
||||
if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0)) {
|
||||
DriverApi& driverApi = engine.getDriverApi();
|
||||
|
||||
if (UTILS_UNLIKELY(driverApi.getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DriverApi& driverApi = engine.getDriverApi();
|
||||
|
||||
mFroxelBufferEntryCount = std::min(
|
||||
FROXEL_BUFFER_MAX_ENTRY_COUNT,
|
||||
engine.getDriverApi().getMaxUniformBufferSize() / 16u);
|
||||
|
||||
@@ -22,16 +22,24 @@ namespace filament {
|
||||
|
||||
using namespace math;
|
||||
|
||||
bool LightManager::hasComponent(Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
}
|
||||
|
||||
size_t LightManager::getComponentCount() const noexcept {
|
||||
return downcast(this)->getComponentCount();
|
||||
}
|
||||
|
||||
utils::Entity const* LightManager::getEntities() const noexcept {
|
||||
return downcast(this)->getEntities();
|
||||
bool LightManager::empty() const noexcept {
|
||||
return downcast(this)->empty();
|
||||
}
|
||||
|
||||
bool LightManager::hasComponent(Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
utils::Entity LightManager::getEntity(LightManager::Instance i) const noexcept {
|
||||
return downcast(this)->getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* LightManager::getEntities() const noexcept {
|
||||
return downcast(this)->getEntities();
|
||||
}
|
||||
|
||||
LightManager::Instance LightManager::getInstance(Entity e) const noexcept {
|
||||
|
||||
@@ -120,6 +120,10 @@ ReflectionMode Material::getReflectionMode() const noexcept {
|
||||
return downcast(this)->getReflectionMode();
|
||||
}
|
||||
|
||||
FeatureLevel Material::getFeatureLevel() const noexcept {
|
||||
return downcast(this)->getFeatureLevel();
|
||||
}
|
||||
|
||||
bool Material::hasParameter(const char* name) const noexcept {
|
||||
return downcast(this)->hasParameter(name);
|
||||
}
|
||||
|
||||
@@ -426,6 +426,7 @@ bool ChunkSamplerInterfaceBlock::unflatten(Unflattener& unflattener,
|
||||
uint8_t fieldFormat = 0;
|
||||
uint8_t fieldPrecision = 0;
|
||||
bool fieldMultisample = false;
|
||||
uint8_t fieldTransferFunction = 0;
|
||||
|
||||
if (!unflattener.read(&fieldName)) {
|
||||
return false;
|
||||
@@ -447,10 +448,15 @@ bool ChunkSamplerInterfaceBlock::unflatten(Unflattener& unflattener,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!unflattener.read(&fieldTransferFunction)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.add({ fieldName.data(), fieldName.size() }, SamplerInterfaceBlock::Type(fieldType),
|
||||
SamplerInterfaceBlock::Format(fieldFormat),
|
||||
SamplerInterfaceBlock::Precision(fieldPrecision),
|
||||
fieldMultisample);
|
||||
fieldMultisample,
|
||||
SamplerInterfaceBlock::SamplerTransferFunction(fieldTransferFunction));
|
||||
}
|
||||
|
||||
*sib = builder.build();
|
||||
|
||||
@@ -245,6 +245,7 @@ void PerViewUniforms::prepareMaterialGlobals(
|
||||
}
|
||||
|
||||
void PerViewUniforms::prepareSSR(Handle<HwTexture> ssr,
|
||||
bool disableSSR,
|
||||
float refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept {
|
||||
|
||||
@@ -255,7 +256,7 @@ void PerViewUniforms::prepareSSR(Handle<HwTexture> ssr,
|
||||
|
||||
auto& s = mUniforms.edit();
|
||||
s.refractionLodOffset = refractionLodOffset;
|
||||
s.ssrDistance = ssrOptions.enabled ? ssrOptions.maxDistance : 0.0f;
|
||||
s.ssrDistance = (ssrOptions.enabled && !disableSSR) ? ssrOptions.maxDistance : 0.0f;
|
||||
}
|
||||
|
||||
void PerViewUniforms::prepareHistorySSR(Handle<HwTexture> ssr,
|
||||
|
||||
@@ -95,6 +95,7 @@ public:
|
||||
|
||||
// screen-space reflection and/or refraction (SSR)
|
||||
void prepareSSR(TextureHandle ssr,
|
||||
bool disableSSR,
|
||||
float refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept;
|
||||
|
||||
|
||||
@@ -207,10 +207,13 @@ PostProcessManager::PostProcessMaterial& PostProcessManager::getPostProcessMater
|
||||
|
||||
#define MATERIAL(n) MATERIALS_ ## n ## _DATA, MATERIALS_ ## n ## _SIZE
|
||||
|
||||
static const PostProcessManager::MaterialInfo sMaterialListFeatureLevel0[] = {
|
||||
{ "blitLow", MATERIAL(BLITLOW) },
|
||||
};
|
||||
|
||||
static const PostProcessManager::MaterialInfo sMaterialList[] = {
|
||||
{ "bilateralBlur", MATERIAL(BILATERALBLUR) },
|
||||
{ "bilateralBlurBentNormals", MATERIAL(BILATERALBLURBENTNORMALS) },
|
||||
{ "blitLow", MATERIAL(BLITLOW) },
|
||||
{ "bloomDownsample", MATERIAL(BLOOMDOWNSAMPLE) },
|
||||
{ "bloomDownsample2x", MATERIAL(BLOOMDOWNSAMPLE2X) },
|
||||
{ "bloomDownsample9", MATERIAL(BLOOMDOWNSAMPLE9) },
|
||||
@@ -273,10 +276,17 @@ void PostProcessManager::init() noexcept {
|
||||
driver.isWorkaroundNeeded(Workaround::ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP);
|
||||
|
||||
#pragma nounroll
|
||||
for (auto const& info : sMaterialList) {
|
||||
for (auto const& info : sMaterialListFeatureLevel0) {
|
||||
registerPostProcessMaterial(info.name, info);
|
||||
}
|
||||
|
||||
if (mEngine.getActiveFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1) {
|
||||
#pragma nounroll
|
||||
for (auto const& info : sMaterialList) {
|
||||
registerPostProcessMaterial(info.name, info);
|
||||
}
|
||||
}
|
||||
|
||||
mStarburstTexture = driver.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::R8, 1, 256, 1, 1, TextureUsage::DEFAULT);
|
||||
|
||||
@@ -380,7 +390,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
// generate depth pass at the requested resolution
|
||||
auto& structurePass = fg.addPass<StructurePassData>("Structure Pass",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
bool const isES2 = mEngine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0;
|
||||
bool const isES2 = mEngine.getDriverApi().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0;
|
||||
data.depth = builder.createTexture("Structure Buffer", {
|
||||
.width = width, .height = height,
|
||||
.levels = uint8_t(levelCount),
|
||||
|
||||
@@ -31,6 +31,22 @@ bool RenderableManager::hasComponent(utils::Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
}
|
||||
|
||||
size_t RenderableManager::getComponentCount() const noexcept {
|
||||
return downcast(this)->getComponentCount();
|
||||
}
|
||||
|
||||
bool RenderableManager::empty() const noexcept {
|
||||
return downcast(this)->empty();
|
||||
}
|
||||
|
||||
utils::Entity RenderableManager::getEntity(RenderableManager::Instance i) const noexcept {
|
||||
return downcast(this)->getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* RenderableManager::getEntities() const noexcept {
|
||||
return downcast(this)->getEntities();
|
||||
}
|
||||
|
||||
RenderableManager::Instance
|
||||
RenderableManager::getInstance(utils::Entity e) const noexcept {
|
||||
return downcast(this)->getInstance(e);
|
||||
|
||||
@@ -100,7 +100,7 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
|
||||
"Depth/Stencil Buffer" : "Depth Buffer";
|
||||
|
||||
bool const isES2 =
|
||||
engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0;
|
||||
engine.getDriverApi().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0;
|
||||
|
||||
TextureFormat const stencilFormat = isES2 ?
|
||||
TextureFormat::DEPTH24_STENCIL8 : TextureFormat::DEPTH32F_STENCIL8;
|
||||
@@ -193,8 +193,8 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
|
||||
TextureHandle const ssr = data.ssr ?
|
||||
resources.getTexture(data.ssr) : engine.getOneTextureArray();
|
||||
|
||||
view.prepareSSR(ssr, config.ssrLodOffset,
|
||||
view.getScreenSpaceReflectionsOptions());
|
||||
view.prepareSSR(ssr, config.screenSpaceReflectionHistoryNotReady,
|
||||
config.ssrLodOffset, view.getScreenSpaceReflectionsOptions());
|
||||
|
||||
// Note: here we can't use data.color's descriptor for the viewport because
|
||||
// the actual viewport might be offset when the target is the swapchain.
|
||||
|
||||
@@ -67,6 +67,8 @@ public:
|
||||
bool hasScreenSpaceReflectionsOrRefractions;
|
||||
// Use a depth format with a stencil component.
|
||||
bool enabledStencilBuffer;
|
||||
// whether the screenspace reflections history buffer is initialized
|
||||
bool screenSpaceReflectionHistoryNotReady;
|
||||
};
|
||||
|
||||
static FrameGraphId<FrameGraphTexture> colorPass(
|
||||
|
||||
@@ -55,6 +55,10 @@ void Scene::removeEntities(const Entity* entities, size_t count) {
|
||||
downcast(this)->removeEntities(entities, count);
|
||||
}
|
||||
|
||||
size_t Scene::getEntityCount() const noexcept {
|
||||
return downcast(this)->getEntityCount();
|
||||
}
|
||||
|
||||
size_t Scene::getRenderableCount() const noexcept {
|
||||
return downcast(this)->getRenderableCount();
|
||||
}
|
||||
|
||||
@@ -90,40 +90,39 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::update(FEngine& engine, FVie
|
||||
}
|
||||
|
||||
void ShadowMapManager::reset() noexcept {
|
||||
mCascadeShadowMaps.clear();
|
||||
mSpotShadowMaps.clear();
|
||||
mDirectionalShadowMapCount = 0;
|
||||
mSpotShadowMapCount = 0;
|
||||
}
|
||||
|
||||
void ShadowMapManager::setDirectionalShadowMap(size_t lightIndex,
|
||||
LightManager::ShadowOptions const* options) noexcept {
|
||||
assert_invariant(options->shadowCascades <= CONFIG_MAX_SHADOW_CASCADES);
|
||||
|
||||
// this updates getCascadedShadowMap()
|
||||
mDirectionalShadowMapCount = options->shadowCascades;
|
||||
utils::Slice<ShadowMap> cascadedShadowMap = getCascadedShadowMap();
|
||||
for (size_t c = 0; c < options->shadowCascades; c++) {
|
||||
const size_t i = c;
|
||||
assert_invariant(i < CONFIG_MAX_SHADOW_CASCADES);
|
||||
auto* pShadowMap = getShadowMap(i);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, i, 0, options);
|
||||
mCascadeShadowMaps.push_back(pShadowMap);
|
||||
ShadowMap& shadowMap = cascadedShadowMap[c];
|
||||
shadowMap.initialize(lightIndex, ShadowType::DIRECTIONAL, c, 0, options);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowMapManager::addShadowMap(size_t lightIndex, bool spotlight,
|
||||
LightManager::ShadowOptions const* options) noexcept {
|
||||
if (spotlight) {
|
||||
const size_t c = mSpotShadowMaps.size();
|
||||
const size_t c = mSpotShadowMapCount++;
|
||||
const size_t i = c + CONFIG_MAX_SHADOW_CASCADES;
|
||||
assert_invariant(i < CONFIG_MAX_SHADOWMAPS);
|
||||
auto* pShadowMap = getShadowMap(i);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::SPOT, i, 0, options);
|
||||
mSpotShadowMaps.push_back(pShadowMap);
|
||||
auto& shadowMap = getShadowMap(i);
|
||||
shadowMap.initialize(lightIndex, ShadowType::SPOT, i, 0, options);
|
||||
} else {
|
||||
// point-light, generate 6 independent shadowmaps
|
||||
for (size_t face = 0; face < 6; face++) {
|
||||
const size_t c = mSpotShadowMaps.size();
|
||||
const size_t c = mSpotShadowMapCount++;
|
||||
const size_t i = c + CONFIG_MAX_SHADOW_CASCADES;
|
||||
assert_invariant(i < CONFIG_MAX_SHADOWMAPS);
|
||||
auto* pShadowMap = getShadowMap(i);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::POINT, i, face, options);
|
||||
mSpotShadowMaps.push_back(pShadowMap);
|
||||
auto& shadowMap = getShadowMap(i);
|
||||
shadowMap.initialize(lightIndex, ShadowType::POINT, i, face, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,11 +178,11 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
// Directional, cascaded shadow maps
|
||||
auto const directionalShadowCastersRange = view.getVisibleDirectionalShadowCasters();
|
||||
if (!directionalShadowCastersRange.empty()) {
|
||||
for (auto* pShadowMap : mCascadeShadowMaps) {
|
||||
for (auto& shadowMap : getCascadedShadowMap()) {
|
||||
// for the directional light, we already know if it has visible shadows.
|
||||
if (pShadowMap->hasVisibleShadows()) {
|
||||
if (shadowMap.hasVisibleShadows()) {
|
||||
passList.push_back({
|
||||
{}, pShadowMap, directionalShadowCastersRange,
|
||||
{}, &shadowMap, directionalShadowCastersRange,
|
||||
VISIBLE_DIR_SHADOW_RENDERABLE });
|
||||
}
|
||||
}
|
||||
@@ -192,10 +191,10 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
// Point lights and Spotlight shadow maps
|
||||
auto const spotShadowCastersRange = view.getVisibleSpotShadowCasters();
|
||||
if (!spotShadowCastersRange.empty()) {
|
||||
for (auto* pShadowMap : mSpotShadowMaps) {
|
||||
assert_invariant(!pShadowMap->isDirectionalShadow());
|
||||
for (auto& shadowMap : getSpotShadowMaps()) {
|
||||
assert_invariant(!shadowMap.isDirectionalShadow());
|
||||
passList.push_back({
|
||||
{}, pShadowMap, spotShadowCastersRange,
|
||||
{}, &shadowMap, spotShadowCastersRange,
|
||||
VISIBLE_DYN_SHADOW_RENDERABLE });
|
||||
}
|
||||
}
|
||||
@@ -517,10 +516,11 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
};
|
||||
|
||||
bool hasVisibleShadows = false;
|
||||
if (!mCascadeShadowMaps.empty()) {
|
||||
utils::Slice<ShadowMap> cascadedShadowMaps = getCascadedShadowMap();
|
||||
if (!cascadedShadowMaps.empty()) {
|
||||
// Even if we have more than one cascade, we cull directional shadow casters against the
|
||||
// entire camera frustum, as if we only had a single cascade.
|
||||
ShadowMap& shadowMap = *mCascadeShadowMaps[0];
|
||||
ShadowMap& shadowMap = cascadedShadowMaps[0];
|
||||
|
||||
const auto direction = options.transform * lightData.elementAt<FScene::DIRECTION>(0);
|
||||
|
||||
@@ -558,7 +558,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
vsFar = std::max(vsFar, sceneInfo.vsNearFar.y);
|
||||
}
|
||||
|
||||
const size_t cascadeCount = mCascadeShadowMaps.size();
|
||||
const size_t cascadeCount = cascadedShadowMaps.size();
|
||||
|
||||
// We divide the camera frustum into N cascades. This gives us N + 1 split positions.
|
||||
// The first split position is the near plane; the last split position is the far plane.
|
||||
@@ -592,11 +592,9 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
// note: normalBias is set to zero for VSM
|
||||
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * lcm.getShadowNormalBias(0);
|
||||
|
||||
for (size_t i = 0, c = mCascadeShadowMaps.size(); i < c; i++) {
|
||||
assert_invariant(mCascadeShadowMaps[i]);
|
||||
|
||||
for (size_t i = 0, c = cascadedShadowMaps.size(); i < c; i++) {
|
||||
// Compute the frustum for the directional light.
|
||||
ShadowMap& shadowMap = *mCascadeShadowMaps[i];
|
||||
ShadowMap& shadowMap = cascadedShadowMaps[i];
|
||||
assert_invariant(shadowMap.getLightIndex() == 0);
|
||||
|
||||
sceneInfo.csNearFar = { csSplitPosition[i], csSplitPosition[i + 1] };
|
||||
@@ -643,7 +641,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
}
|
||||
|
||||
uint32_t cascades = 0;
|
||||
cascades |= uint32_t(mCascadeShadowMaps.size());
|
||||
cascades |= uint32_t(cascadedShadowMaps.size());
|
||||
cascades |= cascadeHasVisibleShadows << 8u;
|
||||
|
||||
mShadowMappingUniforms.directionalShadows = directionalShadowsMask;
|
||||
@@ -852,16 +850,17 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine
|
||||
lightData.data<FScene::SHADOW_INFO>());
|
||||
|
||||
ShadowTechnique shadowTechnique{};
|
||||
if (!mSpotShadowMaps.empty()) {
|
||||
utils::Slice<ShadowMap> const spotShadowMaps = getSpotShadowMaps();
|
||||
if (!spotShadowMaps.empty()) {
|
||||
shadowTechnique |= ShadowTechnique::SHADOW_MAP;
|
||||
for (auto const* pShadowMap : mSpotShadowMaps) {
|
||||
const size_t lightIndex = pShadowMap->getLightIndex();
|
||||
for (ShadowMap const& shadowMap : spotShadowMaps) {
|
||||
const size_t lightIndex = shadowMap.getLightIndex();
|
||||
// gather the per-light (not per shadow map) information. For point lights we will
|
||||
// "see" 6 shadowmaps (one per face), we must use the first face one, the shader
|
||||
// knows how to find the entry for other faces (they're guaranteed to be sequential).
|
||||
if (pShadowMap->getFace() == 0) {
|
||||
if (shadowMap.getFace() == 0) {
|
||||
shadowInfo[lightIndex].castsShadows = true; // FIXME: is that set correctly?
|
||||
shadowInfo[lightIndex].index = pShadowMap->getShadowIndex();
|
||||
shadowInfo[lightIndex].index = shadowMap.getShadowIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -891,18 +890,18 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view
|
||||
uint8_t layer = 0;
|
||||
uint32_t maxDimension = 0;
|
||||
bool elvsm = false;
|
||||
for (auto* pShadowMap : mCascadeShadowMaps) {
|
||||
for (ShadowMap& shadowMap : getCascadedShadowMap()) {
|
||||
// Shadow map size should be the same for all cascades.
|
||||
auto const& options = pShadowMap->getShadowOptions();
|
||||
auto const& options = shadowMap.getShadowOptions();
|
||||
maxDimension = std::max(maxDimension, options->mapSize);
|
||||
elvsm = elvsm || options->vsm.elvsm;
|
||||
pShadowMap->setLayer(layer++);
|
||||
shadowMap.setLayer(layer++);
|
||||
}
|
||||
for (auto& pShadowMap : mSpotShadowMaps) {
|
||||
auto const& options = pShadowMap->getShadowOptions();
|
||||
for (ShadowMap& shadowMap : getSpotShadowMaps()) {
|
||||
auto const& options = shadowMap.getShadowOptions();
|
||||
maxDimension = std::max(maxDimension, options->mapSize);
|
||||
elvsm = elvsm || options->vsm.elvsm;
|
||||
pShadowMap->setLayer(layer++);
|
||||
shadowMap.setLayer(layer++);
|
||||
}
|
||||
|
||||
const uint8_t layersNeeded = layer;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Slice.h>
|
||||
|
||||
#include <math/vec3.h>
|
||||
|
||||
@@ -89,15 +89,6 @@ public:
|
||||
FrameGraphId<FrameGraphTexture> render(FEngine& engine, FrameGraph& fg, RenderPass const& pass,
|
||||
FView& view, CameraInfo const& mainCameraInfo, math::float4 const& userTime) noexcept;
|
||||
|
||||
ShadowMap* getShadowMap(size_t index) noexcept {
|
||||
assert_invariant(index < CONFIG_MAX_SHADOWMAPS);
|
||||
return std::launder(reinterpret_cast<ShadowMap*>(&mShadowMapCache[index]));
|
||||
}
|
||||
|
||||
ShadowMap const* getShadowMap(size_t index) const noexcept {
|
||||
return const_cast<ShadowMapManager*>(this)->getShadowMap(index);
|
||||
}
|
||||
|
||||
// valid after calling update() above
|
||||
ShadowMappingUniforms getShadowMappingUniforms() const noexcept {
|
||||
return mShadowMappingUniforms;
|
||||
@@ -105,7 +96,12 @@ public:
|
||||
|
||||
auto& getShadowUniformsHandle() const { return mShadowUbh; }
|
||||
|
||||
bool hasSpotShadows() const { return !mSpotShadowMaps.empty(); }
|
||||
bool hasSpotShadows() const { return !mSpotShadowMapCount; }
|
||||
|
||||
// for debugging only
|
||||
FCamera const* getDirectionalLightCamera() const noexcept {
|
||||
return &getShadowMap(0).getDebugCamera();
|
||||
}
|
||||
|
||||
private:
|
||||
ShadowMapManager::ShadowTechnique updateCascadeShadowMaps(FEngine& engine,
|
||||
@@ -184,19 +180,33 @@ private:
|
||||
|
||||
ShadowMap::SceneInfo mSceneInfo;
|
||||
|
||||
utils::FixedCapacityVector<ShadowMap*> mCascadeShadowMaps{
|
||||
utils::FixedCapacityVector<ShadowMap*>::with_capacity(
|
||||
CONFIG_MAX_SHADOW_CASCADES) };
|
||||
|
||||
utils::FixedCapacityVector<ShadowMap*> mSpotShadowMaps{
|
||||
utils::FixedCapacityVector<ShadowMap*>::with_capacity(
|
||||
CONFIG_MAX_SHADOWMAPS - CONFIG_MAX_SHADOW_CASCADES) };
|
||||
|
||||
// Inline storage for all our ShadowMap objects, we can't easily use a std::array<> directly.
|
||||
// Because ShadowMap doesn't have a default ctor, and we avoid out-of-line allocations.
|
||||
// Each ShadowMap is currently 40 bytes (total of 2.5KB for 64 shadow maps)
|
||||
using ShadowMapStorage = std::aligned_storage<sizeof(ShadowMap), alignof(ShadowMap)>::type;
|
||||
std::array<ShadowMapStorage, CONFIG_MAX_SHADOWMAPS> mShadowMapCache;
|
||||
using ShadowMapCacheContainer = std::array<ShadowMapStorage, CONFIG_MAX_SHADOWMAPS>;
|
||||
ShadowMapCacheContainer mShadowMapCache;
|
||||
uint32_t mDirectionalShadowMapCount = 0;
|
||||
uint32_t mSpotShadowMapCount = 0;
|
||||
|
||||
ShadowMap& getShadowMap(size_t index) noexcept {
|
||||
assert_invariant(index < CONFIG_MAX_SHADOWMAPS);
|
||||
return *std::launder(reinterpret_cast<ShadowMap*>(&mShadowMapCache[index]));
|
||||
}
|
||||
|
||||
ShadowMap const& getShadowMap(size_t index) const noexcept {
|
||||
return const_cast<ShadowMapManager*>(this)->getShadowMap(index);
|
||||
}
|
||||
|
||||
utils::Slice<ShadowMap> getCascadedShadowMap() noexcept {
|
||||
ShadowMap* const p = &getShadowMap(0);
|
||||
return { p, mDirectionalShadowMapCount };
|
||||
}
|
||||
|
||||
utils::Slice<ShadowMap> getSpotShadowMaps() noexcept {
|
||||
ShadowMap* const p = &getShadowMap(CONFIG_MAX_SHADOW_CASCADES);
|
||||
return { p, mSpotShadowMapCount };
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -22,6 +22,30 @@ namespace filament {
|
||||
|
||||
using namespace math;
|
||||
|
||||
bool TransformManager::hasComponent(Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
}
|
||||
|
||||
size_t TransformManager::getComponentCount() const noexcept {
|
||||
return downcast(this)->getComponentCount();
|
||||
}
|
||||
|
||||
bool TransformManager::empty() const noexcept {
|
||||
return downcast(this)->empty();
|
||||
}
|
||||
|
||||
utils::Entity TransformManager::getEntity(TransformManager::Instance i) const noexcept {
|
||||
return downcast(this)->getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* TransformManager::getEntities() const noexcept {
|
||||
return downcast(this)->getEntities();
|
||||
}
|
||||
|
||||
TransformManager::Instance TransformManager::getInstance(Entity e) const noexcept {
|
||||
return downcast(this)->getInstance(e);
|
||||
}
|
||||
|
||||
void TransformManager::create(Entity entity, Instance parent, const mat4f& worldTransform) {
|
||||
downcast(this)->create(entity, parent, worldTransform);
|
||||
}
|
||||
@@ -38,14 +62,6 @@ void TransformManager::destroy(Entity e) noexcept {
|
||||
downcast(this)->destroy(e);
|
||||
}
|
||||
|
||||
bool TransformManager::hasComponent(Entity e) const noexcept {
|
||||
return downcast(this)->hasComponent(e);
|
||||
}
|
||||
|
||||
TransformManager::Instance TransformManager::getInstance(Entity e) const noexcept {
|
||||
return downcast(this)->getInstance(e);
|
||||
}
|
||||
|
||||
void TransformManager::setTransform(Instance ci, const mat4f& model) noexcept {
|
||||
downcast(this)->setTransform(ci, model);
|
||||
}
|
||||
@@ -58,7 +74,7 @@ const mat4f& TransformManager::getTransform(Instance ci) const noexcept {
|
||||
return downcast(this)->getTransform(ci);
|
||||
}
|
||||
|
||||
const mat4 TransformManager::getTransformAccurate(Instance ci) const noexcept {
|
||||
mat4 TransformManager::getTransformAccurate(Instance ci) const noexcept {
|
||||
return downcast(this)->getTransformAccurate(ci);
|
||||
}
|
||||
|
||||
@@ -66,7 +82,7 @@ const mat4f& TransformManager::getWorldTransform(Instance ci) const noexcept {
|
||||
return downcast(this)->getWorldTransform(ci);
|
||||
}
|
||||
|
||||
const mat4 TransformManager::getWorldTransformAccurate(Instance ci) const noexcept {
|
||||
mat4 TransformManager::getWorldTransformAccurate(Instance ci) const noexcept {
|
||||
return downcast(this)->getWorldTransformAccurate(ci);
|
||||
}
|
||||
|
||||
@@ -110,7 +126,7 @@ void TransformManager::setAccurateTranslationsEnabled(bool enable) noexcept {
|
||||
}
|
||||
|
||||
bool TransformManager::isAccurateTranslationsEnabled() const noexcept {
|
||||
return downcast(this)->isAccurateTranslationsEnabled();;
|
||||
return downcast(this)->isAccurateTranslationsEnabled();
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -23,70 +23,82 @@
|
||||
#include <utils/Log.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <math/mat4.h>
|
||||
|
||||
using namespace utils;
|
||||
using namespace filament::math;
|
||||
|
||||
namespace filament {
|
||||
|
||||
FCameraManager::FCameraManager(FEngine& engine) noexcept
|
||||
: mEngine(engine) {
|
||||
FCameraManager::FCameraManager(FEngine&) noexcept {
|
||||
}
|
||||
|
||||
FCameraManager::~FCameraManager() noexcept {
|
||||
}
|
||||
FCameraManager::~FCameraManager() noexcept = default;
|
||||
|
||||
void FCameraManager::terminate() noexcept {
|
||||
void FCameraManager::terminate(FEngine& engine) noexcept {
|
||||
auto& manager = mManager;
|
||||
if (!manager.empty()) {
|
||||
#ifndef NDEBUG
|
||||
slog.d << "cleaning up " << manager.getComponentCount()
|
||||
<< " leaked Camera components" << io::endl;
|
||||
#endif
|
||||
while (!manager.empty()) {
|
||||
Instance const ci = manager.end() - 1;
|
||||
destroy(manager.getEntity(ci));
|
||||
utils::Slice<Entity> const entities{ manager.getEntities(), manager.getComponentCount() };
|
||||
for (Entity const e : entities) {
|
||||
destroy(engine, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FCameraManager::gc(utils::EntityManager& em) noexcept {
|
||||
void FCameraManager::gc(FEngine& engine, utils::EntityManager& em) noexcept {
|
||||
auto& manager = mManager;
|
||||
manager.gc(em, 4, [this](Entity e) {
|
||||
destroy(e);
|
||||
manager.gc(em, [this, &engine](Entity e) {
|
||||
destroy(engine, e);
|
||||
});
|
||||
}
|
||||
|
||||
FCamera* FCameraManager::create(Entity entity) {
|
||||
FEngine& engine = mEngine;
|
||||
FCamera* FCameraManager::create(FEngine& engine, Entity entity) {
|
||||
auto& manager = mManager;
|
||||
|
||||
// if this entity already has Camera component, destroy it.
|
||||
if (UTILS_UNLIKELY(manager.hasComponent(entity))) {
|
||||
destroy(entity);
|
||||
destroy(engine, entity);
|
||||
}
|
||||
|
||||
// add the Camera component to the entity
|
||||
Instance const i = manager.addComponent(entity);
|
||||
|
||||
FCamera* camera = engine.getHeapAllocator().make<FCamera>(engine, entity);
|
||||
// For historical reasons, FCamera must not move. So the CameraManager stores a pointer.
|
||||
FCamera* const camera = engine.getHeapAllocator().make<FCamera>(engine, entity);
|
||||
manager.elementAt<CAMERA>(i) = camera;
|
||||
manager.elementAt<OWNS_TRANSFORM_COMPONENT>(i) = false;
|
||||
|
||||
// Make sure we have a transform component
|
||||
FTransformManager& transformManager = engine.getTransformManager();
|
||||
if (!transformManager.hasComponent(entity)) {
|
||||
transformManager.create(entity);
|
||||
FTransformManager& tcm = engine.getTransformManager();
|
||||
if (!tcm.hasComponent(entity)) {
|
||||
tcm.create(entity);
|
||||
manager.elementAt<OWNS_TRANSFORM_COMPONENT>(i) = true;
|
||||
}
|
||||
return camera;
|
||||
}
|
||||
|
||||
void FCameraManager::destroy(Entity e) noexcept {
|
||||
void FCameraManager::destroy(FEngine& engine, Entity e) noexcept {
|
||||
auto& manager = mManager;
|
||||
Instance const i = manager.getInstance(e);
|
||||
if (i) {
|
||||
FCamera* camera = manager.elementAt<CAMERA>(i);
|
||||
assert_invariant(camera);
|
||||
camera->terminate(mEngine);
|
||||
mEngine.getHeapAllocator().destroy(camera);
|
||||
manager.removeComponent(e);
|
||||
if (Instance const i = manager.getInstance(e) ; i) {
|
||||
// destroy the FCamera object
|
||||
bool const ownsTransformComponent = manager.elementAt<OWNS_TRANSFORM_COMPONENT>(i);
|
||||
|
||||
{ // scope for camera -- it's invalid after this scope.
|
||||
FCamera* const camera = manager.elementAt<CAMERA>(i);
|
||||
assert_invariant(camera);
|
||||
camera->terminate(engine);
|
||||
engine.getHeapAllocator().destroy(camera);
|
||||
|
||||
// Remove the camera component
|
||||
manager.removeComponent(e);
|
||||
}
|
||||
|
||||
// if we added the transform component, remove it.
|
||||
if (ownsTransformComponent) {
|
||||
engine.getTransformManager().destroy(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@ public:
|
||||
~FCameraManager() noexcept;
|
||||
|
||||
// free-up all resources
|
||||
void terminate() noexcept;
|
||||
void terminate(FEngine& engine) noexcept;
|
||||
|
||||
void gc(utils::EntityManager& em) noexcept;
|
||||
void gc(FEngine& engine, utils::EntityManager& em) noexcept;
|
||||
|
||||
/*
|
||||
* Component Manager APIs
|
||||
@@ -57,32 +57,47 @@ public:
|
||||
}
|
||||
|
||||
Instance getInstance(utils::Entity e) const noexcept {
|
||||
return Instance(mManager.getInstance(e));
|
||||
return { mManager.getInstance(e) };
|
||||
}
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return mManager.empty();
|
||||
}
|
||||
|
||||
utils::Entity getEntity(Instance i) const noexcept {
|
||||
return mManager.getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
|
||||
FCamera* getCamera(Instance i) noexcept {
|
||||
return mManager.elementAt<CAMERA>(i);
|
||||
}
|
||||
|
||||
FCamera* create(utils::Entity entity);
|
||||
FCamera* create(FEngine& engine, utils::Entity entity);
|
||||
|
||||
void destroy(utils::Entity e) noexcept;
|
||||
void destroy(FEngine& engine, utils::Entity e) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
CAMERA
|
||||
CAMERA,
|
||||
OWNS_TRANSFORM_COMPONENT
|
||||
};
|
||||
|
||||
using Base = utils::SingleInstanceComponentManager<FCamera *>;
|
||||
using Base = utils::SingleInstanceComponentManager<FCamera*, bool>;
|
||||
|
||||
struct CameraManagerImpl : public Base {
|
||||
using Base::gc;
|
||||
using Base::swap;
|
||||
using Base::hasComponent;
|
||||
} mManager;
|
||||
|
||||
FEngine& mEngine;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -227,7 +227,9 @@ void FLightManager::terminate() noexcept {
|
||||
}
|
||||
}
|
||||
void FLightManager::gc(utils::EntityManager& em) noexcept {
|
||||
mManager.gc(em);
|
||||
mManager.gc(em, [this](Entity e) {
|
||||
destroy(e);
|
||||
});
|
||||
}
|
||||
|
||||
void FLightManager::setShadowOptions(Instance i, ShadowOptions const& options) noexcept {
|
||||
|
||||
@@ -46,20 +46,32 @@ public:
|
||||
|
||||
void gc(utils::EntityManager& em) noexcept;
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
/*
|
||||
* Component Manager APIs
|
||||
*/
|
||||
|
||||
bool hasComponent(utils::Entity e) const noexcept {
|
||||
return mManager.hasComponent(e);
|
||||
}
|
||||
|
||||
Instance getInstance(utils::Entity e) const noexcept {
|
||||
return mManager.getInstance(e);
|
||||
return { mManager.getInstance(e) };
|
||||
}
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return mManager.empty();
|
||||
}
|
||||
|
||||
utils::Entity getEntity(Instance i) const noexcept {
|
||||
return mManager.getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
|
||||
void create(const FLightManager::Builder& builder, utils::Entity entity);
|
||||
|
||||
@@ -214,12 +214,12 @@ RenderableManager::Builder& RenderableManager::Builder::enableSkinningBuffers(bo
|
||||
|
||||
RenderableManager::Builder& RenderableManager::Builder::boneIndicesAndWeights(size_t primitiveIndex,
|
||||
math::float2 const* indicesAndWeights, size_t count, size_t bonesPerVertex) noexcept {
|
||||
size_t vertexCount = count / bonesPerVertex;
|
||||
size_t const vertexCount = count / bonesPerVertex;
|
||||
utils::FixedCapacityVector<utils::FixedCapacityVector<filament::math::float2>> bonePairs(vertexCount);
|
||||
for ( size_t iVertex = 0; iVertex < vertexCount; iVertex++) {
|
||||
for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) {
|
||||
utils::FixedCapacityVector<float2> vertexData(bonesPerVertex);
|
||||
std::copy_n(indicesAndWeights + iVertex * bonesPerVertex,
|
||||
bonesPerVertex, vertexData.data());
|
||||
bonesPerVertex, vertexData.data());
|
||||
bonePairs[iVertex] = std::move(vertexData);
|
||||
}
|
||||
return boneIndicesAndWeights(primitiveIndex, bonePairs);
|
||||
@@ -275,13 +275,13 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi
|
||||
size_t maxPairsCount = 0; //size of texture, number of bone pairs
|
||||
size_t maxPairsCountPerVertex = 0; //maximum of number of bone per vertex
|
||||
|
||||
for (auto iBonePair = mBonePairs.begin(); iBonePair != mBonePairs.end(); ++iBonePair){
|
||||
auto primitiveIndex = iBonePair->first;
|
||||
for (auto& bonePair: mBonePairs) {
|
||||
auto primitiveIndex = bonePair.first;
|
||||
auto entries = mEntries;
|
||||
ASSERT_PRECONDITION(primitiveIndex < entries.size() && primitiveIndex >= 0,
|
||||
"[primitive @ %u] primitiveindex is out of size (%u)", primitiveIndex, entries.size());
|
||||
auto entry = mEntries[primitiveIndex];
|
||||
auto bonePairsForPrimitive = iBonePair->second;
|
||||
auto bonePairsForPrimitive = bonePair.second;
|
||||
auto vertexCount = entry.vertices->getVertexCount();
|
||||
ASSERT_PRECONDITION(bonePairsForPrimitive.size() == vertexCount,
|
||||
"[primitive @ %u] bone indices and weights pairs count (%u) must be equal to vertex count (%u)",
|
||||
@@ -292,7 +292,7 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi
|
||||
"[entity=%u, primitive @ %u] for advanced skinning set VertexBuffer::Builder::advancedSkinning()",
|
||||
entity.getId(), primitiveIndex);
|
||||
for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) {
|
||||
size_t bonesPerVertex = bonePairsForPrimitive[iVertex].size();
|
||||
size_t const bonesPerVertex = bonePairsForPrimitive[iVertex].size();
|
||||
maxPairsCount += bonesPerVertex;
|
||||
maxPairsCountPerVertex = std::max(bonesPerVertex, maxPairsCountPerVertex);
|
||||
}
|
||||
@@ -303,29 +303,28 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi
|
||||
// final texture data, indices and weights
|
||||
mBoneIndicesAndWeights = utils::FixedCapacityVector<float2>(maxPairsCount);
|
||||
// temporary indices and weights for one vertex
|
||||
std::unique_ptr<float2[]> tempPairs = std::make_unique<float2[]>
|
||||
(maxPairsCountPerVertex);
|
||||
for (auto iBonePair = mBonePairs.begin(); iBonePair != mBonePairs.end(); ++iBonePair) {
|
||||
auto primitiveIndex = iBonePair->first;
|
||||
auto bonePairsForPrimitive = iBonePair->second;
|
||||
if (!bonePairsForPrimitive.size()) {
|
||||
continue;
|
||||
auto const tempPairs = std::make_unique<float2[]>(maxPairsCountPerVertex);
|
||||
for (auto& bonePair: mBonePairs) {
|
||||
auto primitiveIndex = bonePair.first;
|
||||
auto bonePairsForPrimitive = bonePair.second;
|
||||
if (bonePairsForPrimitive.empty()) {
|
||||
continue;
|
||||
}
|
||||
size_t vertexCount = mEntries[primitiveIndex].vertices->getVertexCount();
|
||||
std::unique_ptr<uint16_t[]> skinJoints = std::make_unique<uint16_t[]>
|
||||
(4 * vertexCount); // temporary indices for one vertex
|
||||
std::unique_ptr<float[]> skinWeights = std::make_unique<float[]>
|
||||
(4 * vertexCount); // temporary weights for one vertex
|
||||
size_t const vertexCount = mEntries[primitiveIndex].vertices->getVertexCount();
|
||||
// temporary indices for one vertex
|
||||
auto skinJoints = std::make_unique<uint16_t[]>(4 * vertexCount);
|
||||
// temporary weights for one vertex
|
||||
auto skinWeights = std::make_unique<float[]>(4 * vertexCount);
|
||||
for (size_t iVertex = 0; iVertex < vertexCount; iVertex++) {
|
||||
size_t tempPairCount = 0;
|
||||
float boneWeightsSum = 0;
|
||||
double boneWeightsSum = 0;
|
||||
for (size_t k = 0; k < bonePairsForPrimitive[iVertex].size(); k++) {
|
||||
auto boneWeight = bonePairsForPrimitive[iVertex][k][1];
|
||||
auto boneIndex = bonePairsForPrimitive[iVertex][k][0];
|
||||
ASSERT_PRECONDITION(boneWeight >= 0,
|
||||
"[entity=%u, primitive @ %u] bone weight (%f) of vertex=%u is negative ",
|
||||
entity.getId(), primitiveIndex, boneWeight, iVertex);
|
||||
if (boneWeight) {
|
||||
if (boneWeight > 0.0f) {
|
||||
ASSERT_PRECONDITION(boneIndex >= 0,
|
||||
"[entity=%u, primitive @ %u] bone index (%i) of vertex=%u is negative ",
|
||||
entity.getId(), primitiveIndex, (int) boneIndex, iVertex);
|
||||
@@ -342,26 +341,37 @@ void RenderableManager::BuilderDetails::processBoneIndicesAndWights(Engine& engi
|
||||
ASSERT_PRECONDITION(boneWeightsSum > 0,
|
||||
"[entity=%u, primitive @ %u] sum of bone weights of vertex=%u is %f, it should be positive.",
|
||||
entity.getId(), primitiveIndex, iVertex, boneWeightsSum);
|
||||
if (abs(boneWeightsSum - 1.f) > std::numeric_limits<float>::epsilon()) {
|
||||
|
||||
// see https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes
|
||||
double const epsilon = 2e-7 * double(tempPairCount);
|
||||
if (abs(boneWeightsSum - 1.0) <= epsilon) {
|
||||
boneWeightsSum = 1.0;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
else {
|
||||
utils::slog.w << "Warning of skinning: [entity=%" << entity.getId()
|
||||
<< ", primitive @ %" << primitiveIndex
|
||||
<< "] sum of bone weights of vertex=" << iVertex << " is " << boneWeightsSum
|
||||
<< ", it should be one. Weights will be normalized." << utils::io::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// prepare data for vertex attributes
|
||||
auto offset = iVertex * 4;
|
||||
// set attributes, indices and weights, for <= 4 pairs
|
||||
for (size_t j = 0, c = std::min((int) tempPairCount, 4); j < c; j++) {
|
||||
skinJoints[j + offset] = tempPairs[j][0];
|
||||
skinWeights[j + offset] = tempPairs[j][1] / boneWeightsSum;
|
||||
for (size_t j = 0, c = std::min((int)tempPairCount, 4); j < c; j++) {
|
||||
skinJoints[j + offset] = uint16_t(tempPairs[j][0]);
|
||||
skinWeights[j + offset] = tempPairs[j][1] / float(boneWeightsSum);
|
||||
}
|
||||
// prepare data for texture
|
||||
if (tempPairCount > 4) { // set attributes, indices and weights, for > 4 pairs
|
||||
skinWeights[3 + offset] = -(float) (pairsCount + 1); // negative offset to texture 0..-1, 1..-2
|
||||
skinJoints[3 + offset] = (uint16_t) tempPairCount; // number pairs per vertex in texture
|
||||
// number pairs per vertex in texture
|
||||
skinJoints[3 + offset] = (uint16_t)tempPairCount;
|
||||
// negative offset to texture 0..-1, 1..-2
|
||||
skinWeights[3 + offset] = -float(pairsCount + 1);
|
||||
for (size_t j = 3; j < tempPairCount; j++) {
|
||||
mBoneIndicesAndWeights[pairsCount][0] = tempPairs[j][0];
|
||||
mBoneIndicesAndWeights[pairsCount][1] = tempPairs[j][1] / boneWeightsSum;
|
||||
mBoneIndicesAndWeights[pairsCount][1] = tempPairs[j][1] / float(boneWeightsSum);
|
||||
pairsCount++;
|
||||
}
|
||||
}
|
||||
@@ -386,7 +396,7 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng
|
||||
mImpl->mInstanceCount,
|
||||
CONFIG_MAX_INSTANCES);
|
||||
if (mImpl->mInstanceBuffer) {
|
||||
size_t bufferInstanceCount = mImpl->mInstanceBuffer->mInstanceCount;
|
||||
size_t const bufferInstanceCount = mImpl->mInstanceBuffer->mInstanceCount;
|
||||
ASSERT_PRECONDITION(mImpl->mInstanceCount <= bufferInstanceCount,
|
||||
"instance count (%zu) must be less than or equal to the InstanceBuffer's instance "
|
||||
"count "
|
||||
@@ -402,7 +412,7 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng
|
||||
auto& entry = mImpl->mEntries[i];
|
||||
|
||||
// entry.materialInstance must be set to something even if indices/vertices are null
|
||||
FMaterial const* material = nullptr;
|
||||
FMaterial const* material;
|
||||
if (!entry.materialInstance) {
|
||||
material = downcast(engine.getDefaultMaterial());
|
||||
entry.materialInstance = material->getDefaultInstance();
|
||||
@@ -678,7 +688,9 @@ void FRenderableManager::terminate() noexcept {
|
||||
}
|
||||
|
||||
void FRenderableManager::gc(utils::EntityManager& em) noexcept {
|
||||
mManager.gc(em);
|
||||
mManager.gc(em, [this](Entity e) {
|
||||
destroy(e);
|
||||
});
|
||||
}
|
||||
|
||||
// This is basically a Renderable's destructor.
|
||||
|
||||
@@ -92,7 +92,23 @@ public:
|
||||
}
|
||||
|
||||
Instance getInstance(utils::Entity e) const noexcept {
|
||||
return mManager.getInstance(e);
|
||||
return { mManager.getInstance(e) };
|
||||
}
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return mManager.empty();
|
||||
}
|
||||
|
||||
utils::Entity getEntity(Instance i) const noexcept {
|
||||
return mManager.getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
|
||||
void create(const RenderableManager::Builder& builder, utils::Entity entity);
|
||||
@@ -176,10 +192,6 @@ public:
|
||||
static_assert(sizeof(InstancesInfo) == 16);
|
||||
inline InstancesInfo getInstancesInfo(Instance instance) const noexcept;
|
||||
|
||||
utils::Entity getEntity(Instance instance) const noexcept {
|
||||
return mManager.getEntity(instance);
|
||||
}
|
||||
|
||||
inline size_t getLevelCount(Instance) const noexcept { return 1u; }
|
||||
size_t getPrimitiveCount(Instance instance, uint8_t level) const noexcept;
|
||||
void setMaterialInstanceAt(Instance instance, uint8_t level,
|
||||
|
||||
@@ -471,8 +471,7 @@ void FTransformManager::validateNode(UTILS_UNUSED_IN_RELEASE Instance i) noexcep
|
||||
}
|
||||
|
||||
void FTransformManager::gc(utils::EntityManager& em) noexcept {
|
||||
auto& manager = mManager;
|
||||
manager.gc(em, 4, [this](Entity e) {
|
||||
mManager.gc(em, [this](Entity e) {
|
||||
destroy(e);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,7 +50,23 @@ public:
|
||||
}
|
||||
|
||||
Instance getInstance(utils::Entity e) const noexcept {
|
||||
return Instance(mManager.getInstance(e));
|
||||
return { mManager.getInstance(e) };
|
||||
}
|
||||
|
||||
size_t getComponentCount() const noexcept {
|
||||
return mManager.getComponentCount();
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return mManager.empty();
|
||||
}
|
||||
|
||||
utils::Entity getEntity(Instance i) const noexcept {
|
||||
return mManager.getEntity(i);
|
||||
}
|
||||
|
||||
utils::Entity const* getEntities() const noexcept {
|
||||
return mManager.getEntities();
|
||||
}
|
||||
|
||||
void setAccurateTranslationsEnabled(bool enable) noexcept;
|
||||
@@ -103,7 +119,7 @@ public:
|
||||
|
||||
math::mat4 getTransformAccurate(Instance ci) const noexcept {
|
||||
math::mat4f const& local = mManager[ci].local;
|
||||
math::float3 localTranslationLo = mManager[ci].localTranslationLo;
|
||||
math::float3 const localTranslationLo = mManager[ci].localTranslationLo;
|
||||
math::mat4 r(local);
|
||||
r[3].xyz += localTranslationLo;
|
||||
return r;
|
||||
@@ -111,7 +127,7 @@ public:
|
||||
|
||||
math::mat4 getWorldTransformAccurate(Instance ci) const noexcept {
|
||||
math::mat4f const& world = mManager[ci].world;
|
||||
math::float3 worldTranslationLo = mManager[ci].worldTranslationLo;
|
||||
math::float3 const worldTranslationLo = mManager[ci].worldTranslationLo;
|
||||
math::mat4 r(world);
|
||||
r[3].xyz += worldTranslationLo;
|
||||
return r;
|
||||
|
||||
@@ -67,6 +67,7 @@ struct Engine::BuilderDetails {
|
||||
Backend mBackend = Backend::DEFAULT;
|
||||
Platform* mPlatform = nullptr;
|
||||
Engine::Config mConfig;
|
||||
FeatureLevel mFeatureLevel = FeatureLevel::FEATURE_LEVEL_1;
|
||||
void* mSharedContext = nullptr;
|
||||
static Config validateConfig(const Config* pConfig) noexcept;
|
||||
};
|
||||
@@ -185,6 +186,7 @@ static const uint16_t sFullScreenTriangleIndices[3] = { 0, 1, 2 };
|
||||
|
||||
FEngine::FEngine(Engine::Builder const& builder) :
|
||||
mBackend(builder->mBackend),
|
||||
mActiveFeatureLevel(builder->mFeatureLevel),
|
||||
mPlatform(builder->mPlatform),
|
||||
mSharedGLContext(builder->mSharedContext),
|
||||
mPostProcessManager(*this),
|
||||
@@ -326,15 +328,12 @@ void FEngine::init() {
|
||||
driverApi.update3DImage(mDummyZeroTexture, 0, 0, 0, 0, 1, 1, 1,
|
||||
{ zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
|
||||
#ifdef FILAMENT_TARGET_MOBILE
|
||||
if (UTILS_UNLIKELY(mActiveFeatureLevel == FeatureLevel::FEATURE_LEVEL_0)) {
|
||||
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
|
||||
defaultMaterialBuilder.package(
|
||||
MATERIALS_DEFAULTMATERIAL0_DATA, MATERIALS_DEFAULTMATERIAL0_SIZE);
|
||||
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast<FEngine*>(this)));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
|
||||
|
||||
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
|
||||
@@ -359,11 +358,12 @@ void FEngine::init() {
|
||||
driverApi.update3DImage(mDummyZeroTextureArray, 0, 0, 0, 0, 1, 1, 1,
|
||||
{ zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
|
||||
mPostProcessManager.init();
|
||||
mLightManager.init(*this);
|
||||
mDFG.init(*this);
|
||||
}
|
||||
|
||||
mPostProcessManager.init();
|
||||
|
||||
mDebugRegistry.registerProperty("d.shadowmap.debug_directional_shadowmap",
|
||||
&debug.shadowmap.debug_directional_shadowmap, [this]() {
|
||||
mMaterials.forEach([](FMaterial* material) {
|
||||
@@ -424,7 +424,7 @@ void FEngine::shutdown() {
|
||||
mDFG.terminate(*this); // free-up the DFG
|
||||
mRenderableManager.terminate(); // free-up all renderables
|
||||
mLightManager.terminate(); // free-up all lights
|
||||
mCameraManager.terminate(); // free-up all cameras
|
||||
mCameraManager.terminate(*this); // free-up all cameras
|
||||
|
||||
driver.destroyRenderPrimitive(mFullScreenTriangleRph);
|
||||
destroy(mFullScreenTriangleIb);
|
||||
@@ -537,7 +537,7 @@ void FEngine::gc() {
|
||||
mRenderableManager.gc(em);
|
||||
mLightManager.gc(em);
|
||||
mTransformManager.gc(em);
|
||||
mCameraManager.gc(em);
|
||||
mCameraManager.gc(*this, em);
|
||||
}
|
||||
|
||||
void FEngine::flush() {
|
||||
@@ -828,7 +828,7 @@ FSwapChain* FEngine::createSwapChain(uint32_t width, uint32_t height, uint64_t f
|
||||
|
||||
|
||||
FCamera* FEngine::createCamera(Entity entity) noexcept {
|
||||
return mCameraManager.create(entity);
|
||||
return mCameraManager.create(*this, entity);
|
||||
}
|
||||
|
||||
FCamera* FEngine::getCameraComponent(Entity entity) noexcept {
|
||||
@@ -837,7 +837,7 @@ FCamera* FEngine::getCameraComponent(Entity entity) noexcept {
|
||||
}
|
||||
|
||||
void FEngine::destroyCameraComponent(utils::Entity entity) noexcept {
|
||||
mCameraManager.destroy(entity);
|
||||
mCameraManager.destroy(*this, entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -1053,7 +1053,7 @@ void FEngine::destroy(Entity e) {
|
||||
mRenderableManager.destroy(e);
|
||||
mLightManager.destroy(e);
|
||||
mTransformManager.destroy(e);
|
||||
mCameraManager.destroy(e);
|
||||
mCameraManager.destroy(*this, e);
|
||||
}
|
||||
|
||||
bool FEngine::isValid(const FBufferObject* p) {
|
||||
@@ -1171,6 +1171,8 @@ Engine::FeatureLevel FEngine::getSupportedFeatureLevel() const noexcept {
|
||||
Engine::FeatureLevel FEngine::setActiveFeatureLevel(FeatureLevel featureLevel) {
|
||||
ASSERT_PRECONDITION(featureLevel <= getSupportedFeatureLevel(),
|
||||
"Feature level %u not supported", (unsigned)featureLevel);
|
||||
ASSERT_PRECONDITION(mActiveFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1,
|
||||
"Cannot adjust feature level beyond 0 at runtime");
|
||||
return (mActiveFeatureLevel = std::max(mActiveFeatureLevel, featureLevel));
|
||||
}
|
||||
|
||||
@@ -1204,6 +1206,11 @@ Engine::Builder& Engine::Builder::config(Engine::Config const* config) noexcept
|
||||
return *this;
|
||||
}
|
||||
|
||||
Engine::Builder& Engine::Builder::featureLevel(FeatureLevel featureLevel) noexcept {
|
||||
mImpl->mFeatureLevel = featureLevel;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Engine::Builder& Engine::Builder::sharedContext(void* sharedContext) noexcept {
|
||||
mImpl->mSharedContext = sharedContext;
|
||||
return *this;
|
||||
|
||||
@@ -231,7 +231,7 @@ public:
|
||||
default:
|
||||
return backend::ShaderLanguage::ESSL3;
|
||||
case Backend::OPENGL:
|
||||
return mActiveFeatureLevel == FeatureLevel::FEATURE_LEVEL_0
|
||||
return getDriver().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0
|
||||
? backend::ShaderLanguage::ESSL1 : backend::ShaderLanguage::ESSL3;
|
||||
case Backend::VULKAN:
|
||||
return backend::ShaderLanguage::SPIRV;
|
||||
@@ -487,7 +487,7 @@ private:
|
||||
ResourceList<FRenderTarget> mRenderTargets{ "RenderTarget" };
|
||||
|
||||
// the fence list is accessed from multiple threads
|
||||
utils::SpinLock mFenceListLock;
|
||||
utils::Mutex mFenceListLock;
|
||||
ResourceList<FFence> mFences{"Fence"};
|
||||
|
||||
mutable uint32_t mMaterialId = 0;
|
||||
|
||||
@@ -57,7 +57,9 @@ static MaterialParser* createParser(Backend backend, ShaderLanguage language,
|
||||
}
|
||||
|
||||
ASSERT_PRECONDITION(materialResult != MaterialParser::ParseResult::ERROR_MISSING_BACKEND,
|
||||
"the material was not built for the %s backend\n", backendToString(backend));
|
||||
"the material was not built for the %s backend and %s shader language\n",
|
||||
backendToString(backend),
|
||||
shaderLanguageToString(language));
|
||||
|
||||
ASSERT_PRECONDITION(materialResult == MaterialParser::ParseResult::SUCCESS,
|
||||
"could not parse the material package");
|
||||
@@ -184,7 +186,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
|
||||
success = parser->getUIB(&mUniformInterfaceBlock);
|
||||
assert_invariant(success);
|
||||
|
||||
if (engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0) {
|
||||
if (UTILS_UNLIKELY(engine.getShaderLanguage() == ShaderLanguage::ESSL1)) {
|
||||
success = parser->getBindingUniformInfo(&mBindingUniformInfo);
|
||||
assert_invariant(success);
|
||||
|
||||
@@ -258,7 +260,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
|
||||
mSpecializationConstants.push_back({
|
||||
+ReservedSpecializationConstants::CONFIG_POWER_VR_SHADER_WORKAROUNDS,
|
||||
(bool)powerVrShaderWorkarounds });
|
||||
if (engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0) {
|
||||
if (UTILS_UNLIKELY(engine.getShaderLanguage() == ShaderLanguage::ESSL1)) {
|
||||
// The actual value of this spec-constant is set in the OpenGLDriver backend.
|
||||
mSpecializationConstants.push_back({
|
||||
+ReservedSpecializationConstants::CONFIG_SRGB_SWAPCHAIN_EMULATION,
|
||||
@@ -640,7 +642,6 @@ Program FMaterial::getProgramWithVariants(
|
||||
FEngine const& engine = mEngine;
|
||||
const ShaderModel sm = engine.getShaderModel();
|
||||
const bool isNoop = engine.getBackend() == Backend::NOOP;
|
||||
const FeatureLevel engineFeatureLevel = engine.getActiveFeatureLevel();
|
||||
/*
|
||||
* Vertex shader
|
||||
*/
|
||||
@@ -694,7 +695,7 @@ Program FMaterial::getProgramWithVariants(
|
||||
}
|
||||
}
|
||||
|
||||
if (engineFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) {
|
||||
if (UTILS_UNLIKELY(mEngine.getShaderLanguage() == ShaderLanguage::ESSL1)) {
|
||||
assert_invariant(!mBindingUniformInfo.empty());
|
||||
for (auto const& [index, uniforms] : mBindingUniformInfo) {
|
||||
program.uniforms(uint32_t(index), uniforms);
|
||||
|
||||
@@ -859,6 +859,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
PostProcessManager::generateMipmapSSR(ppm, fg,
|
||||
reflections, ssrConfig.reflection, false, ssrConfig);
|
||||
}
|
||||
config.screenSpaceReflectionHistoryNotReady = !reflections;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -55,7 +55,7 @@ class FSkybox;
|
||||
class FScene : public Scene {
|
||||
public:
|
||||
/*
|
||||
* Filaments-scope Public API
|
||||
* Filament-scope Public API
|
||||
*/
|
||||
|
||||
FSkybox* getSkybox() const noexcept { return mSkybox; }
|
||||
@@ -197,6 +197,7 @@ private:
|
||||
void addEntities(const utils::Entity* entities, size_t count);
|
||||
void remove(utils::Entity entity);
|
||||
void removeEntities(const utils::Entity* entities, size_t count);
|
||||
size_t getEntityCount() const noexcept { return mEntities.size(); }
|
||||
size_t getRenderableCount() const noexcept;
|
||||
size_t getLightCount() const noexcept;
|
||||
bool hasEntity(utils::Entity entity) const noexcept;
|
||||
|
||||
@@ -118,12 +118,9 @@ FSkybox::FSkybox(FEngine& engine, const Builder& builder) noexcept
|
||||
|
||||
FMaterial const* FSkybox::createMaterial(FEngine& engine) {
|
||||
Material::Builder builder;
|
||||
#ifdef FILAMENT_TARGET_MOBILE
|
||||
if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == Engine::FeatureLevel::FEATURE_LEVEL_0)) {
|
||||
builder.package(MATERIALS_SKYBOX0_DATA, MATERIALS_SKYBOX0_SIZE);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
builder.package(MATERIALS_SKYBOX_DATA, MATERIALS_SKYBOX_SIZE);
|
||||
}
|
||||
auto material = builder.build(engine);
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
|
||||
// Returns the max number of levels for a texture of given dimensions
|
||||
static inline uint8_t maxLevelCount(uint32_t width, uint32_t height) noexcept {
|
||||
uint32_t maxDimension = std::max(width, height);
|
||||
uint32_t const maxDimension = std::max(width, height);
|
||||
return maxLevelCount(maxDimension);
|
||||
}
|
||||
|
||||
|
||||
@@ -662,7 +662,6 @@ void FView::bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noe
|
||||
mPerViewUniforms.bind(driver);
|
||||
|
||||
if (UTILS_UNLIKELY(driver.getFeatureLevel() == backend::FeatureLevel::FEATURE_LEVEL_0)) {
|
||||
// FIXME: should be okay to use driver (instead of engine) for FEATURE_LEVEL_0 checks
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -747,9 +746,11 @@ void FView::prepareSSAO(Handle<HwTexture> ssao) const noexcept {
|
||||
mPerViewUniforms.prepareSSAO(ssao, mAmbientOcclusionOptions);
|
||||
}
|
||||
|
||||
void FView::prepareSSR(Handle<HwTexture> ssr, float refractionLodOffset,
|
||||
void FView::prepareSSR(Handle<HwTexture> ssr,
|
||||
bool disableSSR,
|
||||
float refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept {
|
||||
mPerViewUniforms.prepareSSR(ssr, refractionLodOffset, ssrOptions);
|
||||
mPerViewUniforms.prepareSSR(ssr, disableSSR, refractionLodOffset, ssrOptions);
|
||||
}
|
||||
|
||||
void FView::prepareStructure(Handle<HwTexture> structure) const noexcept {
|
||||
|
||||
@@ -145,7 +145,8 @@ public:
|
||||
void prepareLighting(FEngine& engine, ArenaScope& arena, CameraInfo const& cameraInfo) noexcept;
|
||||
|
||||
void prepareSSAO(backend::Handle<backend::HwTexture> ssao) const noexcept;
|
||||
void prepareSSR(backend::Handle<backend::HwTexture> ssr, float refractionLodOffset,
|
||||
void prepareSSR(backend::Handle<backend::HwTexture> ssr, bool disableSSR,
|
||||
float refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
|
||||
void prepareStructure(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadow(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
@@ -194,7 +195,7 @@ public:
|
||||
void setStereoscopicOptions(StereoscopicOptions const& options);
|
||||
|
||||
FCamera const* getDirectionalLightCamera() const noexcept {
|
||||
return &mShadowMapManager.getShadowMap(0)->getDebugCamera();
|
||||
return mShadowMapManager.getDirectionalLightCamera();
|
||||
}
|
||||
|
||||
void setRenderTarget(FRenderTarget* renderTarget) noexcept {
|
||||
|
||||
@@ -22,7 +22,8 @@ material {
|
||||
],
|
||||
depthWrite : false,
|
||||
depthCulling : false,
|
||||
domain: postprocess
|
||||
domain: postprocess,
|
||||
featureLevel : 0
|
||||
}
|
||||
|
||||
vertex {
|
||||
@@ -34,7 +35,10 @@ vertex {
|
||||
|
||||
fragment {
|
||||
void postProcess(inout PostProcessInputs postProcess) {
|
||||
#if __VERSION__ == 100
|
||||
postProcess.color = texture2D(materialParams_color, variable_vertex.xy);
|
||||
#else
|
||||
postProcess.color = textureLod(materialParams_color, variable_vertex.xy, 0.0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
;;; c-filament-style.el --- Filament C++ style -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2023 Google LLC
|
||||
|
||||
;; Author: Eliza Velasquez
|
||||
;; Version: 0.1.0
|
||||
;; Created: 2023-10-31
|
||||
;; Package-Requires: ((emacs "24.1"))
|
||||
;; Keywords: c
|
||||
;; URL: https://github.com/google/filament
|
||||
;; SPDX-License-Identifier: Apache-2
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Defines a basic Filament style for C++ code in Emacs.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cc-mode)
|
||||
(defvar c-syntactic-context)
|
||||
|
||||
(defun c-filament-style-lineup-brace-list-intro (langelem)
|
||||
"Indent first line of braced lists in the Filament style.
|
||||
|
||||
This properly indents doubled-up arglists + lists, e.g. ({. It
|
||||
also properly indents enums at 1x and other lists at 2x.
|
||||
|
||||
LANGELEM is the cons of the syntactic symbol and the anchor
|
||||
position (or nil if there is none)."
|
||||
(save-excursion
|
||||
(let (case-fold-search)
|
||||
(goto-char (c-langelem-pos langelem))
|
||||
(if (looking-at "enum\\b")
|
||||
c-basic-offset
|
||||
(if (assq 'arglist-cont-nonempty c-syntactic-context)
|
||||
(- c-basic-offset)
|
||||
(* 2 c-basic-offset))))))
|
||||
|
||||
(defun c-filament-style-lineup-brace-list-entry (_langelem)
|
||||
"Indent following lines in braced lists in the Filament style.
|
||||
|
||||
This properly indents doubled-up arglists + lists, e.g. ({."
|
||||
(if (assq 'arglist-cont-nonempty c-syntactic-context)
|
||||
(- (* c-basic-offset 2))
|
||||
0))
|
||||
|
||||
(defun c-filament-style-lineup-arglist (langelem)
|
||||
"Indent following lines in braced lists in the Filament style.
|
||||
|
||||
This properly indents arglists nested in if statements. LANGELEM
|
||||
is the cons of the syntactic symbol and the anchor position (or
|
||||
nil if there is none)."
|
||||
(save-excursion
|
||||
(let (case-fold-search)
|
||||
(goto-char (c-langelem-pos langelem))
|
||||
(if (and (cdr c-syntactic-context)
|
||||
(looking-at "if\\b"))
|
||||
c-basic-offset
|
||||
(* 2 c-basic-offset)))))
|
||||
|
||||
(c-add-style "filament"
|
||||
'((c-basic-offset . 4)
|
||||
(c-offsets-alist
|
||||
(innamespace . 0)
|
||||
(inextern-lang . 0)
|
||||
(arglist-intro . c-filament-style-lineup-arglist)
|
||||
(arglist-cont . 0)
|
||||
(arglist-cont-nonempty . c-filament-style-lineup-arglist)
|
||||
(arglist-close . c-filament-style-lineup-arglist)
|
||||
(statement-cont . ++)
|
||||
(case-label . +)
|
||||
(brace-list-intro . c-filament-style-lineup-brace-list-intro)
|
||||
(brace-list-entry . c-filament-style-lineup-brace-list-entry)
|
||||
(brace-list-close . c-filament-style-lineup-brace-list-entry)
|
||||
(label . [0]))))
|
||||
|
||||
(provide 'c-filament-style)
|
||||
|
||||
;;; c-filament-style.el ends here
|
||||
+18
-10
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina6_5" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina6_5" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
@@ -20,24 +20,24 @@
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" fixedFrame="YES" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="B3q-vU-ULy">
|
||||
<rect key="frame" x="68" y="80" width="279" height="636"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<mutableString key="text">This is a native UITextView. The triangle is rendered by Filament.
|
||||
<string key="text">This is a native UITextView. The triangle is rendered by Filament.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras tincidunt neque a metus laoreet imperdiet. In cursus arcu quis turpis viverra convallis. Sed eu laoreet metus. Nunc id est lacus. Sed hendrerit elementum velit a finibus. Mauris vitae scelerisque erat. Proin ultricies quam nec justo vehicula, sed porta nulla facilisis.
|
||||
|
||||
Phasellus orci lectus, ullamcorper efficitur urna non, sodales venenatis sem. Suspendisse auctor, enim non dapibus malesuada, est urna sollicitudin sapien, in sodales mi nulla quis odio. Suspendisse viverra vel orci vitae vestibulum. Fusce tristique ligula nisi, bibendum gravida est volutpat sed. Vivamus ut justo porttitor, feugiat lorem eget, rutrum orci. Donec nec nibh vitae ex consectetur pulvinar. Sed dignissim, metus a tincidunt finibus, justo massa auctor nunc, sit amet cursus ligula sapien ut enim. Quisque ut congue libero, in ultricies tortor. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean ac justo in tortor commodo efficitur et ut leo.
|
||||
</mutableString>
|
||||
</string>
|
||||
<color key="textColor" systemColor="labelColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2KD-1D-oAh" customClass="FilamentView">
|
||||
<view opaque="NO" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2KD-1D-oAh" customClass="FilamentView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<viewLayoutGuide key="safeArea" id="cdP-0z-J5l"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
@@ -45,4 +45,12 @@ Phasellus orci lectus, ullamcorper efficitur urna non, sodales venenatis sem. Su
|
||||
<point key="canvasLocation" x="140.57971014492756" y="133.25892857142856"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<systemColor name="labelColor">
|
||||
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -89,6 +89,7 @@ static constexpr uint8_t BAKED_COLOR_PACKAGE[] = {
|
||||
#elif FILAMENT_APP_USE_METAL
|
||||
[self initializeMetalLayer];
|
||||
#endif
|
||||
self.opaque = NO;
|
||||
[self initializeFilament];
|
||||
self.contentScaleFactor = UIScreen.mainScreen.nativeScale;
|
||||
}
|
||||
|
||||
@@ -160,6 +160,8 @@ public:
|
||||
|
||||
bool isEmpty() const noexcept { return mFieldInfoList.empty(); }
|
||||
|
||||
bool isEmptyForFeatureLevel(backend::FeatureLevel featureLevel) const noexcept;
|
||||
|
||||
Alignment getAlignment() const noexcept { return mAlignment; }
|
||||
|
||||
Target getTarget() const noexcept { return mTarget; }
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
using Format = backend::SamplerFormat;
|
||||
using Precision = backend::Precision;
|
||||
using SamplerParams = backend::SamplerParams;
|
||||
using SamplerTransferFunction = backend::SamplerTransferFunction;
|
||||
|
||||
struct SamplerInfo { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
utils::CString name; // name of this sampler
|
||||
@@ -55,6 +56,7 @@ public:
|
||||
Format format; // format of this sampler
|
||||
Precision precision; // precision of this sampler
|
||||
bool multisample; // multisample capable
|
||||
SamplerTransferFunction transferFunction;
|
||||
};
|
||||
|
||||
class Builder {
|
||||
@@ -73,6 +75,7 @@ public:
|
||||
Format format; // format of this sampler
|
||||
Precision precision; // precision of this sampler
|
||||
bool multisample = false; // multisample capable
|
||||
SamplerTransferFunction transferFunction;
|
||||
};
|
||||
|
||||
// Give a name to this sampler interface block
|
||||
@@ -83,7 +86,8 @@ public:
|
||||
// Add a sampler
|
||||
Builder& add(std::string_view samplerName, Type type, Format format,
|
||||
Precision precision = Precision::MEDIUM,
|
||||
bool multisample = false) noexcept;
|
||||
bool multisample = false,
|
||||
SamplerTransferFunction transferFunction = SamplerTransferFunction::UNDEFINED) noexcept;
|
||||
|
||||
// Add multiple samplers
|
||||
Builder& add(std::initializer_list<ListEntry> list) noexcept;
|
||||
|
||||
@@ -171,6 +171,14 @@ BufferInterfaceBlock::FieldInfo const* BufferInterfaceBlock::getFieldInfo(
|
||||
return &mFieldInfoList[pos->second];
|
||||
}
|
||||
|
||||
bool BufferInterfaceBlock::isEmptyForFeatureLevel(
|
||||
backend::FeatureLevel featureLevel) const noexcept {
|
||||
return std::all_of(mFieldInfoList.begin(), mFieldInfoList.end(),
|
||||
[featureLevel](auto const &info) {
|
||||
return featureLevel < info.minFeatureLevel;
|
||||
});
|
||||
}
|
||||
|
||||
uint8_t UTILS_NOINLINE BufferInterfaceBlock::baseAlignmentForType(BufferInterfaceBlock::Type type) noexcept {
|
||||
switch (type) {
|
||||
case Type::BOOL:
|
||||
@@ -230,4 +238,3 @@ uint8_t UTILS_NOINLINE BufferInterfaceBlock::strideForType(BufferInterfaceBlock:
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
|
||||
@@ -44,10 +44,10 @@ SamplerInterfaceBlock::Builder::stageFlags(backend::ShaderStageFlags stageFlags)
|
||||
|
||||
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
|
||||
std::string_view samplerName, Type type, Format format,
|
||||
Precision precision, bool multisample) noexcept {
|
||||
Precision precision, bool multisample, SamplerTransferFunction transferFunction) noexcept {
|
||||
mEntries.push_back({
|
||||
{ samplerName.data(), samplerName.size() }, { },
|
||||
uint8_t(mEntries.size()), type, format, precision, multisample });
|
||||
uint8_t(mEntries.size()), type, format, precision, multisample, transferFunction });
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ SamplerInterfaceBlock SamplerInterfaceBlock::Builder::build() {
|
||||
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
|
||||
std::initializer_list<ListEntry> list) noexcept {
|
||||
for (auto& e : list) {
|
||||
add(e.name, e.type, e.format, e.precision, e.multisample);
|
||||
add(e.name, e.type, e.format, e.precision, e.multisample, e.transferFunction);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ material {
|
||||
shadingModel : unlit,
|
||||
culling : none,
|
||||
depthCulling: false,
|
||||
blending : transparent
|
||||
blending : transparent,
|
||||
featureLevel : 0
|
||||
}
|
||||
|
||||
fragment {
|
||||
@@ -21,7 +22,7 @@ fragment {
|
||||
prepareMaterial(material);
|
||||
vec2 uv = getUV0();
|
||||
uv.y = 1.0 - uv.y;
|
||||
vec4 albedo = texture(materialParams_albedo, uv);
|
||||
vec4 albedo = texture2D(materialParams_albedo, uv);
|
||||
material.baseColor = getColor() * albedo;
|
||||
material.baseColor.rgb *= material.baseColor.a;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ using SamplerType = MaterialBuilder::SamplerType;
|
||||
using SubpassType = MaterialBuilder::SubpassType;
|
||||
using SamplerFormat = MaterialBuilder::SamplerFormat;
|
||||
using ParameterPrecision = MaterialBuilder::ParameterPrecision;
|
||||
using SamplerTransferFunction = MaterialBuilder::SamplerTransferFunction;
|
||||
using OutputTarget = MaterialBuilder::OutputTarget;
|
||||
using OutputQualifier = MaterialBuilder::VariableQualifier;
|
||||
using OutputType = MaterialBuilder::OutputType;
|
||||
@@ -75,6 +76,7 @@ private:
|
||||
static std::unordered_map<std::string, SubpassType> mStringToSubpassType;
|
||||
static std::unordered_map<std::string, SamplerFormat> mStringToSamplerFormat;
|
||||
static std::unordered_map<std::string, ParameterPrecision> mStringToSamplerPrecision;
|
||||
static std::unordered_map<std::string, SamplerTransferFunction> mStringToSamplerTransferFunction;
|
||||
static std::unordered_map<std::string, OutputTarget> mStringToOutputTarget;
|
||||
static std::unordered_map<std::string, OutputQualifier> mStringToOutputQualifier;
|
||||
static std::unordered_map<std::string, OutputType> mStringToOutputType;
|
||||
|
||||
@@ -239,6 +239,7 @@ public:
|
||||
using SubpassType = filament::backend::SubpassType;
|
||||
using SamplerFormat = filament::backend::SamplerFormat;
|
||||
using ParameterPrecision = filament::backend::Precision;
|
||||
using SamplerTransferFunction = filament::backend::SamplerTransferFunction;
|
||||
using Precision = filament::backend::Precision;
|
||||
using CullingMode = filament::backend::CullingMode;
|
||||
using FeatureLevel = filament::backend::FeatureLevel;
|
||||
@@ -307,11 +308,8 @@ public:
|
||||
*/
|
||||
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format = SamplerFormat::FLOAT,
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT) noexcept;
|
||||
|
||||
/// @copydoc parameter(SamplerType, SamplerFormat, ParameterPrecision, const char*)
|
||||
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
|
||||
ParameterPrecision precision) noexcept;
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT,
|
||||
SamplerTransferFunction transferFunction = SamplerTransferFunction::UNDEFINED) noexcept;
|
||||
|
||||
|
||||
MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept;
|
||||
@@ -618,16 +616,20 @@ public:
|
||||
Parameter() noexcept: parameterType(INVALID) {}
|
||||
|
||||
// Sampler
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER) { }
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p,
|
||||
SamplerTransferFunction tf)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f),
|
||||
parameterType(SAMPLER), transferFunction(tf) { }
|
||||
|
||||
// Uniform
|
||||
Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p)
|
||||
: name(paramName), size(typeSize), uniformType(t), precision(p), parameterType(UNIFORM) { }
|
||||
: name(paramName), size(typeSize), uniformType(t), precision(p),
|
||||
parameterType(UNIFORM) { }
|
||||
|
||||
// Subpass
|
||||
Parameter(const char* paramName, SubpassType t, SamplerFormat f, ParameterPrecision p)
|
||||
: name(paramName), size(1), precision(p), subpassType(t), format(f), parameterType(SUBPASS) { }
|
||||
: name(paramName), size(1), precision(p), subpassType(t), format(f),
|
||||
parameterType(SUBPASS) { }
|
||||
|
||||
utils::CString name;
|
||||
size_t size;
|
||||
@@ -636,6 +638,7 @@ public:
|
||||
SamplerType samplerType;
|
||||
SubpassType subpassType;
|
||||
SamplerFormat format;
|
||||
SamplerTransferFunction transferFunction;
|
||||
enum {
|
||||
INVALID,
|
||||
UNIFORM,
|
||||
|
||||
@@ -117,6 +117,17 @@ std::unordered_map<std::string, ParameterPrecision>& Enums::getMap<ParameterPrec
|
||||
return mStringToSamplerPrecision;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, SamplerTransferFunction> Enums::mStringToSamplerTransferFunction = {
|
||||
{ "undefined", SamplerTransferFunction::UNDEFINED },
|
||||
{ "identity", SamplerTransferFunction::IDENTITY },
|
||||
{ "srgbToLinear", SamplerTransferFunction::SRGB_TO_LINEAR },
|
||||
};
|
||||
|
||||
template <>
|
||||
std::unordered_map<std::string, SamplerTransferFunction>& Enums::getMap<SamplerTransferFunction>() noexcept {
|
||||
return mStringToSamplerTransferFunction;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, OutputTarget> Enums::mStringToOutputTarget = {
|
||||
{ "color", OutputTarget::COLOR },
|
||||
{ "depth", OutputTarget::DEPTH }
|
||||
|
||||
@@ -248,19 +248,14 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, UniformType type,
|
||||
return parameter(name, 1, type, precision);
|
||||
}
|
||||
|
||||
|
||||
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format, ParameterPrecision precision) noexcept {
|
||||
SamplerFormat format, ParameterPrecision precision,
|
||||
SamplerTransferFunction transferFunction) noexcept {
|
||||
ASSERT_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT, "Too many parameters");
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision };
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision, transferFunction };
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
|
||||
ParameterPrecision precision) noexcept {
|
||||
return parameter(name, samplerType, SamplerFormat::FLOAT, precision);
|
||||
}
|
||||
|
||||
template<typename T, typename>
|
||||
MaterialBuilder& MaterialBuilder::constant(const char* name, ConstantType type, T defaultValue) {
|
||||
auto result = std::find_if(mConstants.begin(), mConstants.end(), [name](const Constant& c) {
|
||||
@@ -556,7 +551,8 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
|
||||
assert_invariant(!param.isSubpass());
|
||||
if (param.isSampler()) {
|
||||
sbb.add({ param.name.data(), param.name.size() },
|
||||
param.samplerType, param.format, param.precision);
|
||||
param.samplerType, param.format, param.precision, /*multisample=*/false,
|
||||
param.transferFunction);
|
||||
} else if (param.isUniform()) {
|
||||
ibb.add({{{ param.name.data(), param.name.size() },
|
||||
uint32_t(param.size == 1u ? 0u : param.size), param.uniformType,
|
||||
@@ -587,11 +583,11 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
|
||||
}
|
||||
|
||||
if (mBlendingMode == BlendingMode::MASKED) {
|
||||
ibb.add({{ "_maskThreshold", 0, UniformType::FLOAT }});
|
||||
ibb.add({{ "_maskThreshold", 0, UniformType::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }});
|
||||
}
|
||||
|
||||
if (mDoubleSidedCapability) {
|
||||
ibb.add({{ "_doubleSided", 0, UniformType::BOOL }});
|
||||
ibb.add({{ "_doubleSided", 0, UniformType::BOOL, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }});
|
||||
}
|
||||
|
||||
mRequiredAttributes.set(VertexAttribute::POSITION);
|
||||
@@ -1098,6 +1094,12 @@ error:
|
||||
return Package::invalidPackage();
|
||||
}
|
||||
|
||||
// Force post process materials to be unlit. This prevents imposing a lot of extraneous
|
||||
// data, code, and expectations for materials which do not need them.
|
||||
if (mMaterialDomain == MaterialDomain::POST_PROCESS) {
|
||||
mShading = Shading::UNLIT;
|
||||
}
|
||||
|
||||
// Add a default color output.
|
||||
if (mMaterialDomain == MaterialDomain::POST_PROCESS && mOutputs.empty()) {
|
||||
output(VariableQualifier::OUT,
|
||||
|
||||
@@ -65,6 +65,7 @@ void MaterialSamplerInterfaceBlockChunk::flatten(Flattener& f) {
|
||||
f.writeUint8(static_cast<uint8_t>(sInfo.format));
|
||||
f.writeUint8(static_cast<uint8_t>(sInfo.precision));
|
||||
f.writeBool(sInfo.multisample);
|
||||
f.writeUint8(static_cast<uint8_t>(sInfo.transferFunction));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user