Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dbee125b3 |
@@ -45,23 +45,18 @@ jobs:
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
WORKFLOW_OS=`echo \`uname\` | sed "s/Darwin/mac/" | tr [:upper:] [:lower:]`
|
||||
cd build/$WORKFLOW_OS && printf "y" | ./build.sh release
|
||||
cd ../..
|
||||
- name: Upload release assets
|
||||
run: |
|
||||
xargs -L 1 sudo pip3 install < build/common/requirements.txt
|
||||
if [ -f out/filament-release-darwin.tgz ]; then mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz; fi;
|
||||
if [ -f out/filament-release-linux.tgz ]; then mv out/filament-release-linux.tgz out/filament-${TAG}-linux.tgz; fi;
|
||||
- uses: actions/github-script@v6
|
||||
python3 build/common/upload-assets.py ${TAG} out/*.tgz
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
with:
|
||||
script: |
|
||||
const upload = require('./build/common/upload-release-assets');
|
||||
const { TAG } = process.env;
|
||||
const globber = await glob.create('out/*.tgz');
|
||||
await upload({ github, context }, await globber.glob(), TAG);
|
||||
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
@@ -80,21 +75,16 @@ jobs:
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
cd build/web && printf "y" | ./build.sh release
|
||||
cd ../..
|
||||
- name: Upload release assets
|
||||
run: |
|
||||
xargs -L 1 sudo pip3 install < build/common/requirements.txt
|
||||
mv out/filament-release-web.tgz out/filament-${TAG}-web.tgz
|
||||
- uses: actions/github-script@v6
|
||||
python3 build/common/upload-assets.py ${TAG} out/*.tgz
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
with:
|
||||
script: |
|
||||
const upload = require('./build/common/upload-release-assets');
|
||||
const { TAG } = process.env;
|
||||
const globber = await glob.create('out/*.tgz');
|
||||
await upload({ github, context }, await globber.glob(), TAG);
|
||||
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
|
||||
|
||||
build-android:
|
||||
name: build-android
|
||||
@@ -113,16 +103,8 @@ jobs:
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
cd build/android && printf "y" | ./build.sh release
|
||||
cd ../..
|
||||
mv out/filament-android-release.aar out/filament-${TAG}-android.aar
|
||||
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
|
||||
mv out/filamat-android-lite-release.aar out/filamat-${TAG}-lite-android.aar
|
||||
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
|
||||
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
|
||||
- name: Sign sample-gltf-viewer
|
||||
run: |
|
||||
echo "${APK_KEYSTORE_BASE64}" > filament.jks.base64
|
||||
@@ -137,15 +119,18 @@ jobs:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
APK_KEYSTORE_BASE64: ${{ secrets.APK_KEYSTORE_BASE64 }}
|
||||
APK_KEYSTORE_PASS: ${{ secrets.APK_KEYSTORE_PASS }}
|
||||
- uses: actions/github-script@v6
|
||||
- name: Upload release assets
|
||||
run: |
|
||||
xargs -L 1 sudo pip3 install < build/common/requirements.txt
|
||||
mv out/filament-android-release.aar out/filament-${TAG}-android.aar
|
||||
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
|
||||
mv out/filamat-android-lite-release.aar out/filamat-${TAG}-lite-android.aar
|
||||
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
|
||||
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
|
||||
python3 build/common/upload-assets.py ${TAG} out/*.aar out/*.apk
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
with:
|
||||
script: |
|
||||
const upload = require('./build/common/upload-release-assets');
|
||||
const { TAG } = process.env;
|
||||
const globber = await glob.create(['out/*.aar', 'out/*.apk'].join('\n'));
|
||||
await upload({ github, context }, await globber.glob(), TAG);
|
||||
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
|
||||
|
||||
build-ios:
|
||||
name: build-ios
|
||||
@@ -164,21 +149,16 @@ jobs:
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
cd build/ios && printf "y" | ./build.sh release
|
||||
cd ../..
|
||||
- name: Upload release assets
|
||||
run: |
|
||||
xargs -L 1 sudo pip3 install < build/common/requirements.txt
|
||||
mv out/filament-release-ios.tgz out/filament-${TAG}-ios.tgz
|
||||
- uses: actions/github-script@v6
|
||||
python3 build/common/upload-assets.py ${TAG} out/*.tgz
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
with:
|
||||
script: |
|
||||
const upload = require('./build/common/upload-release-assets');
|
||||
const { TAG } = process.env;
|
||||
const globber = await glob.create('out/*.tgz');
|
||||
await upload({ github, context }, await globber.glob(), TAG);
|
||||
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
|
||||
|
||||
build-windows:
|
||||
name: build-windows
|
||||
@@ -198,19 +178,15 @@ jobs:
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
build\windows\build-github.bat release
|
||||
cd ..\..
|
||||
move out\filament-windows.tgz out\filament-%TAG%-windows.tgz
|
||||
shell: cmd
|
||||
- uses: actions/github-script@v6
|
||||
- name: Upload release assets
|
||||
run: |
|
||||
pip3 install PyGithub
|
||||
mv out/filament-windows.tgz out/filament-${TAG}-windows.tgz
|
||||
python build/common/upload-assets.py ${TAG} out/*.tgz
|
||||
shell: bash
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
with:
|
||||
script: |
|
||||
const upload = require('./build/common/upload-release-assets');
|
||||
const { TAG } = process.env;
|
||||
const globber = await glob.create('out/*.tgz');
|
||||
await upload({ github, context }, await globber.glob(), TAG);
|
||||
GITHUB_API_KEY: ${{ secrets.GITHUB_API_KEY }}
|
||||
|
||||
+8
-12
@@ -74,18 +74,18 @@ if (CCACHE_PROGRAM)
|
||||
configure_file(build/launch-cxx.in launch-cxx)
|
||||
|
||||
execute_process(COMMAND chmod a+rx
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/launch-c"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/launch-cxx"
|
||||
"${CMAKE_BINARY_DIR}/launch-c"
|
||||
"${CMAKE_BINARY_DIR}/launch-cxx"
|
||||
)
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_CURRENT_BINARY_DIR}/launch-c")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_CURRENT_BINARY_DIR}/launch-cxx")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_CURRENT_BINARY_DIR}/launch-c")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_CURRENT_BINARY_DIR}/launch-cxx")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_BINARY_DIR}/launch-c")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_BINARY_DIR}/launch-cxx")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_BINARY_DIR}/launch-c")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_BINARY_DIR}/launch-cxx")
|
||||
else()
|
||||
set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_CURRENT_BINARY_DIR}/launch-c")
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${CMAKE_CURRENT_BINARY_DIR}/launch-cxx")
|
||||
set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-c")
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-cxx")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -99,10 +99,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
# ==================================================================================================
|
||||
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT WEBGL)
|
||||
set(LINUX TRUE)
|
||||
else()
|
||||
# since cmake 3.25 LINUX is automatically set based on CMAKE_SYSTEM_NAME, which the android
|
||||
# cmake files are setting to "Linux".
|
||||
set(LINUX FALSE)
|
||||
endif()
|
||||
|
||||
if (LINUX)
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.30.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.28.2'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```
|
||||
pod 'Filament', '~> 1.30.0'
|
||||
pod 'Filament', '~> 1.28.2'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
@@ -117,9 +117,9 @@ steps:
|
||||
- Image-based lighting
|
||||
- Physically-based camera (shutter speed, sensitivity and aperture)
|
||||
- Physical light units
|
||||
- Point lights, spot lights, and directional light
|
||||
- Point lights, spot lights and directional light
|
||||
- Specular anti-aliasing
|
||||
- Point, spot, and directional light shadows
|
||||
- Spot and directional light shadows
|
||||
- Cascaded shadows
|
||||
- EVSM, PCSS, DPCF, or PCF shadows
|
||||
- Transparent shadows
|
||||
|
||||
+4
-16
@@ -5,24 +5,12 @@ A new header is inserted each time a *tag* is created.
|
||||
|
||||
## main branch
|
||||
|
||||
## v1.30.0
|
||||
|
||||
- engine: optimize per-shadow UBO [⚠️ **Recompile Materials**]
|
||||
- engine: fix potential memory corruption with larger scenes
|
||||
- engine: VSM's MSAA setting is now per-view instead of per-light [⚠️ **API Change**]
|
||||
|
||||
## v1.29.0
|
||||
|
||||
- gltfio: calculate primitive's AABB correctly.
|
||||
- gltfio: recompute bounding boxes with morph targets
|
||||
- engine: add missing getters on `MaterialInstance`
|
||||
- WebGL: add missing `ColorGrading` JS bindings
|
||||
- engine: improvements/cleanup of Shadow mapping code [⚠️ **Recompile Materials**]
|
||||
|
||||
## v1.28.3
|
||||
|
||||
- backend: add support for GGP platform
|
||||
- gltfio: calculate primitive's AABB correctly.
|
||||
- gltfio: fix glTF breaking issue
|
||||
- gltfio: recompute bounding boxes with morph targets
|
||||
- engine: primitives with `CullingMode::FRONT_AND_BACK` are now skipped.
|
||||
- engine: add missing getters on `MaterialInstance`
|
||||
|
||||
## v1.28.2
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
|
||||
jfloat shadowFarHint, jboolean stable, jboolean lispsm,
|
||||
jfloat polygonOffsetConstant, jfloat polygonOffsetSlope,
|
||||
jboolean screenSpaceContactShadows, jint stepCount,
|
||||
jfloat maxShadowDistance, jboolean elvsm, jfloat blurWidth, jfloat shadowBulbRadius) {
|
||||
jfloat maxShadowDistance, jint vsmMsaaSamples, jboolean elvsm, jfloat blurWidth, jfloat shadowBulbRadius) {
|
||||
LightManager::Builder *builder = (LightManager::Builder *) nativeBuilder;
|
||||
LightManager::ShadowOptions shadowOptions {
|
||||
.mapSize = (uint32_t)mapSize,
|
||||
@@ -97,6 +97,7 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
|
||||
.stepCount = uint8_t(stepCount),
|
||||
.maxShadowDistance = maxShadowDistance,
|
||||
.vsm = {
|
||||
.msaaSamples = (uint8_t) vsmMsaaSamples,
|
||||
.elvsm = (bool)elvsm,
|
||||
.blurWidth = blurWidth
|
||||
},
|
||||
|
||||
+16
-2
@@ -349,6 +349,20 @@ public class LightManager {
|
||||
* @see View#setShadowType
|
||||
*/
|
||||
|
||||
/**
|
||||
* The number of MSAA samples to use when rendering VSM shadow maps.
|
||||
* Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns
|
||||
* off MSAA.
|
||||
* Higher values may not be available depending on the underlying hardware.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Warning: This API is still experimental and subject to change.</strong>
|
||||
* </p>
|
||||
*/
|
||||
@IntRange(from = 1)
|
||||
public int vsmMsaaSamples = 1;
|
||||
|
||||
|
||||
/**
|
||||
* When elvsm is set to true, "Exponential Layered VSM without Layers" are used. It is
|
||||
* an improvement to the default EVSM which suffers important light leaks. Enabling
|
||||
@@ -505,7 +519,7 @@ public class LightManager {
|
||||
options.shadowFarHint, options.stable, options.lispsm,
|
||||
options.polygonOffsetConstant, options.polygonOffsetSlope,
|
||||
options.screenSpaceContactShadows,
|
||||
options.stepCount, options.maxShadowDistance,
|
||||
options.stepCount, options.maxShadowDistance, options.vsmMsaaSamples,
|
||||
options.elvsm, options.blurWidth, options.shadowBulbRadius);
|
||||
return this;
|
||||
}
|
||||
@@ -1171,7 +1185,7 @@ public class LightManager {
|
||||
boolean stable, boolean lispsm,
|
||||
float polygonOffsetConstant, float polygonOffsetSlope,
|
||||
boolean screenSpaceContactShadows, int stepCount, float maxShadowDistance,
|
||||
boolean elvsm, float blurWidth, float shadowBulbRadius);
|
||||
int vsmMsaaSamples, boolean elvsm, float blurWidth, float shadowBulbRadius);
|
||||
private static native void nBuilderCastLight(long nativeBuilder, boolean enabled);
|
||||
private static native void nBuilderPosition(long nativeBuilder, float x, float y, float z);
|
||||
private static native void nBuilderDirection(long nativeBuilder, float x, float y, float z);
|
||||
|
||||
@@ -1817,13 +1817,6 @@ public class View {
|
||||
* Whether to generate mipmaps for all VSM shadow maps.
|
||||
*/
|
||||
public boolean mipmapping = false;
|
||||
/**
|
||||
* The number of MSAA samples to use when rendering VSM shadow maps.
|
||||
* Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns
|
||||
* off MSAA.
|
||||
* Higher values may not be available depending on the underlying hardware.
|
||||
*/
|
||||
public int msaaSamples = 1;
|
||||
/**
|
||||
* Whether to use a 32-bits or 16-bits texture format for VSM shadow maps. 32-bits
|
||||
* precision is rarely needed, but it does reduces light leaks as well as "fading"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.30.0
|
||||
VERSION_NAME=1.28.2
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
setuptools==40.6.2
|
||||
wheel==0.37.1
|
||||
certifi==2021.10.8
|
||||
cffi==1.15.0
|
||||
charset-normalizer==2.0.12
|
||||
Deprecated==1.2.13
|
||||
idna==3.3
|
||||
pycparser==2.21
|
||||
PyGithub==1.55
|
||||
PyJWT==2.4.0
|
||||
PyNaCl==1.5.0
|
||||
requests==2.27.1
|
||||
urllib3==1.26.9
|
||||
wrapt==1.14.0
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
# Copyright (C) 2019 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
# requirements.txt created via:
|
||||
#
|
||||
# pip3 install virtualenv
|
||||
# python3 -m venv env
|
||||
# pip3 install PyGithub
|
||||
# pip3 install wheel
|
||||
# --all includes wheel and setuputils, which is needed for GitHub Actions
|
||||
# pip3 freeze --all > requirements.txt
|
||||
# Manually move 'setuptools' and 'wheel' lines to the beginning of the file.
|
||||
# Manually remove the 'pip' line.
|
||||
#
|
||||
# Requirements are installed in GitHub Actions via:
|
||||
# xargs -L 1 sudo pip3 install < build/common/requirements.txt
|
||||
# xargs must be used because the ordering of the dependencies matters (namely, setuptools).
|
||||
# sudo must be used to uninstall non-matching versions of packages.
|
||||
# pip is removed to avoid conflicts with the pre-installed pip version on Actions.
|
||||
# This technique does not work with Windows, unfortunately.
|
||||
|
||||
from github import Github
|
||||
import os, sys
|
||||
|
||||
def print_usage():
|
||||
print('Upload assets to a Filament GitHub release.')
|
||||
print()
|
||||
print('Usage:')
|
||||
print(' upload-assets.py <tag> <asset>...')
|
||||
print()
|
||||
print('Notes:')
|
||||
print(' The GitHub release must already be created prior to running this script. This is typically done')
|
||||
print(' through the GitHub web UI.')
|
||||
print()
|
||||
print(' <tag> is the Git tag for the desired release to attach assets to, for example, "v1.4.2".')
|
||||
print()
|
||||
print(' <asset> is a path to the asset file to upload. The file name will be used as the name of the')
|
||||
print(' asset.')
|
||||
print()
|
||||
print(' The GITHUB_API_KEY environment variable must be set to a valid authentication token for a')
|
||||
print(' collaborator account of the Filament repository.')
|
||||
|
||||
# The first argument is the path to this script.
|
||||
if len(sys.argv) < 3:
|
||||
print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
tag = sys.argv[1]
|
||||
assets = sys.argv[2:]
|
||||
|
||||
authentication_token = os.environ.get('GITHUB_API_KEY')
|
||||
if not authentication_token:
|
||||
sys.stderr.write('Error: the GITHUB_API_KEY is not set.\n')
|
||||
sys.exit(1)
|
||||
|
||||
g = Github(authentication_token)
|
||||
|
||||
FILAMENT_REPO = "google/filament"
|
||||
filament = g.get_repo(FILAMENT_REPO)
|
||||
|
||||
def find_release_from_tag(repo, tag):
|
||||
""" Find a release in the repo for the given Git tag string. """
|
||||
releases = repo.get_releases()
|
||||
for r in releases:
|
||||
if r.tag_name == tag:
|
||||
return r
|
||||
return None
|
||||
|
||||
release = find_release_from_tag(filament, tag)
|
||||
if not release:
|
||||
sys.stderr.write(f"Error: Could not find release with tag '{tag}'.\n")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Found release with tag '{tag}'.")
|
||||
|
||||
for asset_path in assets:
|
||||
sys.stdout.write(f'Uploding asset: {asset_path}... ')
|
||||
asset_name = os.path.basename(asset_path)
|
||||
asset = release.upload_asset(asset_path, name=asset_name)
|
||||
if asset:
|
||||
sys.stdout.write('Success!\n')
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const uploadReleaseAssets = async ({github, context}, assetPathsToUpload, releaseTag) => {
|
||||
const fs = require('fs/promises');
|
||||
const path = require('path');
|
||||
|
||||
const filesToUpload = assetPathsToUpload.map(assetPath => ({
|
||||
buffer: fs.readFile(assetPath),
|
||||
assetName: path.basename(assetPath)
|
||||
}));
|
||||
|
||||
const findReleaseMatchingTag = async tag => {
|
||||
const { data: releases } = await github.rest.repos.listReleases(context.repo);
|
||||
const release = releases.find(release => release.tag_name === releaseTag);
|
||||
if (!release) {
|
||||
throw new Error(`Could not locate release with tag '${releaseTag}'`);
|
||||
}
|
||||
return release;
|
||||
};
|
||||
|
||||
const release = await findReleaseMatchingTag(releaseTag);
|
||||
|
||||
console.log(`Found release named '${release.name}' matching tag '${release.tag_name}'.`);
|
||||
|
||||
const uploadPromises = [];
|
||||
for (const file of filesToUpload) {
|
||||
console.log(`Uploading asset ${file.assetName}.`);
|
||||
const p = github.rest.repos.uploadReleaseAsset({
|
||||
...context.repo,
|
||||
release_id: release.id,
|
||||
name: file.assetName,
|
||||
data: await file.buffer
|
||||
});
|
||||
uploadPromises.push(p);
|
||||
}
|
||||
|
||||
await Promise.all(uploadPromises);
|
||||
console.log("Done!");
|
||||
}
|
||||
|
||||
module.exports = uploadReleaseAssets;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// To test this script locally, uncomment the code below and run:
|
||||
//
|
||||
// npm install
|
||||
// node index.js
|
||||
|
||||
// const { Octokit } = require("@octokit/rest");
|
||||
// const glob = require("@actions/glob");
|
||||
// (async () => {
|
||||
// const github = new Octokit({
|
||||
// auth: "" // <-- paste GitHub auth token here
|
||||
// });
|
||||
// const context = {
|
||||
// repo: {
|
||||
// owner: "bejado",
|
||||
// repo: "filament",
|
||||
// },
|
||||
// };
|
||||
// const globber = await glob.create('*.txt');
|
||||
// await uploadReleaseAssets({ github, context }, await globber.glob(), 'vtest-28');
|
||||
// })();
|
||||
-546
@@ -1,546 +0,0 @@
|
||||
{
|
||||
"name": "upload-release-assets",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@actions/glob": "^0.3.0",
|
||||
"@octokit/rest": "^19.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/glob": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.3.0.tgz",
|
||||
"integrity": "sha512-tJP1ZhF87fd6LBnaXWlahkyvdgvsLl7WnreW1EZaC8JWjpMXmzqWzQVe/IEYslrkT9ymibVrKyJN4UMD7uQM2w==",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.2.6",
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/http-client": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
||||
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz",
|
||||
"integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz",
|
||||
"integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^3.0.0",
|
||||
"@octokit/graphql": "^5.0.0",
|
||||
"@octokit/request": "^6.0.0",
|
||||
"@octokit/request-error": "^3.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz",
|
||||
"integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz",
|
||||
"integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==",
|
||||
"dependencies": {
|
||||
"@octokit/request": "^6.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
|
||||
"integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-5.0.1.tgz",
|
||||
"integrity": "sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-request-log": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
|
||||
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz",
|
||||
"integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"deprecation": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz",
|
||||
"integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^7.0.0",
|
||||
"@octokit/request-error": "^3.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz",
|
||||
"integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest": {
|
||||
"version": "19.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.5.tgz",
|
||||
"integrity": "sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^4.1.0",
|
||||
"@octokit/plugin-paginate-rest": "^5.0.0",
|
||||
"@octokit/plugin-request-log": "^1.0.4",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^6.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
|
||||
"integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||
"engines": {
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
|
||||
"requires": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"@actions/glob": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.3.0.tgz",
|
||||
"integrity": "sha512-tJP1ZhF87fd6LBnaXWlahkyvdgvsLl7WnreW1EZaC8JWjpMXmzqWzQVe/IEYslrkT9ymibVrKyJN4UMD7uQM2w==",
|
||||
"requires": {
|
||||
"@actions/core": "^1.2.6",
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"@actions/http-client": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
||||
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
||||
"requires": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"@octokit/auth-token": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz",
|
||||
"integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==",
|
||||
"requires": {
|
||||
"@octokit/types": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz",
|
||||
"integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==",
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^3.0.0",
|
||||
"@octokit/graphql": "^5.0.0",
|
||||
"@octokit/request": "^6.0.0",
|
||||
"@octokit/request-error": "^3.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz",
|
||||
"integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==",
|
||||
"requires": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz",
|
||||
"integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==",
|
||||
"requires": {
|
||||
"@octokit/request": "^6.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
|
||||
"integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw=="
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-5.0.1.tgz",
|
||||
"integrity": "sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==",
|
||||
"requires": {
|
||||
"@octokit/types": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-request-log": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
|
||||
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
|
||||
"requires": {}
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz",
|
||||
"integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==",
|
||||
"requires": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"deprecation": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz",
|
||||
"integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==",
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^7.0.0",
|
||||
"@octokit/request-error": "^3.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz",
|
||||
"integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==",
|
||||
"requires": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"@octokit/rest": {
|
||||
"version": "19.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.5.tgz",
|
||||
"integrity": "sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==",
|
||||
"requires": {
|
||||
"@octokit/core": "^4.1.0",
|
||||
"@octokit/plugin-paginate-rest": "^5.0.0",
|
||||
"@octokit/plugin-request-log": "^1.0.4",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^6.7.0"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
|
||||
"integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^14.0.0"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "upload-release-assets",
|
||||
"version": "1.0.0",
|
||||
"description": "Upload Filament release assets",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Google",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@actions/glob": "^0.3.0",
|
||||
"@octokit/rest": "^19.0.5"
|
||||
}
|
||||
}
|
||||
@@ -405,7 +405,6 @@ if (APPLE)
|
||||
backend
|
||||
getopt
|
||||
gtest
|
||||
filamat
|
||||
SPIRV
|
||||
spirv-cross-glsl)
|
||||
|
||||
|
||||
@@ -96,8 +96,6 @@ struct MetalContext {
|
||||
SamplerStateCache samplerStateCache;
|
||||
ArgumentEncoderCache argumentEncoderCache;
|
||||
|
||||
PolygonOffset currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
MetalSamplerGroup* samplerBindings[Program::SAMPLER_BINDING_COUNT] = {};
|
||||
|
||||
// Keeps track of sampler groups we've finalized for the current render pass.
|
||||
|
||||
@@ -1005,7 +1005,6 @@ void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
mContext->depthStencilState.invalidate();
|
||||
mContext->cullModeState.invalidate();
|
||||
mContext->windingState.invalidate();
|
||||
mContext->currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
mContext->finalizedSamplerGroups.clear();
|
||||
}
|
||||
@@ -1184,12 +1183,8 @@ void MetalDriver::startCapture(int) {
|
||||
if (@available(iOS 13, *)) {
|
||||
MTLCaptureDescriptor* descriptor = [MTLCaptureDescriptor new];
|
||||
descriptor.captureObject = mContext->device;
|
||||
#if defined(IOS)
|
||||
descriptor.destination = MTLCaptureDestinationDeveloperTools;
|
||||
#else
|
||||
descriptor.destination = MTLCaptureDestinationGPUTraceDocument;
|
||||
descriptor.outputURL = [[NSURL alloc] initFileURLWithPath:@"filament.gputrace"];
|
||||
#endif
|
||||
NSError* error = nil;
|
||||
[[MTLCaptureManager sharedCaptureManager] startCaptureWithDescriptor:descriptor
|
||||
error:&error];
|
||||
@@ -1591,12 +1586,10 @@ void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t
|
||||
[mContext->currentRenderPassEncoder setDepthStencilState:state];
|
||||
}
|
||||
|
||||
if (ps.polygonOffset.constant != mContext->currentPolygonOffset.constant ||
|
||||
ps.polygonOffset.slope != mContext->currentPolygonOffset.slope) {
|
||||
if (ps.polygonOffset.constant != 0.0 || ps.polygonOffset.slope != 0.0) {
|
||||
[mContext->currentRenderPassEncoder setDepthBias:ps.polygonOffset.constant
|
||||
slopeScale:ps.polygonOffset.slope
|
||||
clamp:0.0];
|
||||
mContext->currentPolygonOffset = ps.polygonOffset;
|
||||
}
|
||||
|
||||
// Set scissor-rectangle.
|
||||
|
||||
@@ -2360,10 +2360,8 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
mRenderPassDepthWrite = any(clearFlags & TargetBufferFlags::DEPTH);
|
||||
mRenderPassStencilWrite = any(clearFlags & TargetBufferFlags::STENCIL);
|
||||
|
||||
static_assert(sizeof(GLsizei) >= sizeof(uint32_t));
|
||||
gl.viewport(params.viewport.left, params.viewport.bottom,
|
||||
(GLsizei)std::min(uint32_t(std::numeric_limits<int32_t>::max()), params.viewport.width),
|
||||
(GLsizei)std::min(uint32_t(std::numeric_limits<int32_t>::max()), params.viewport.height));
|
||||
(GLsizei)params.viewport.width, (GLsizei)params.viewport.height);
|
||||
|
||||
gl.depthRange(params.depthRange.near, params.depthRange.far);
|
||||
|
||||
|
||||
@@ -105,16 +105,16 @@ void OpenGLProgram::compileShaders(OpenGLContext& context,
|
||||
GLuint shaderIds[Program::SHADER_TYPE_COUNT],
|
||||
std::array<CString, Program::SHADER_TYPE_COUNT>& outShaderSourceCode) noexcept {
|
||||
|
||||
std::string specializationConstantString;
|
||||
std::string specificationConstantString;
|
||||
for (auto const& sc : specializationConstants) {
|
||||
specializationConstantString += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
|
||||
specializationConstantString += std::visit([](auto&& arg) {
|
||||
specificationConstantString += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
|
||||
specificationConstantString += std::visit([](auto&& arg) {
|
||||
return std::to_string(arg);
|
||||
}, sc.value);
|
||||
specializationConstantString += '\n';
|
||||
specificationConstantString += '\n';
|
||||
}
|
||||
if (!specializationConstantString.empty()) {
|
||||
specializationConstantString += '\n';
|
||||
if (!specificationConstantString.empty()) {
|
||||
specificationConstantString += '\n';
|
||||
}
|
||||
|
||||
// build all shaders
|
||||
@@ -143,14 +143,14 @@ void OpenGLProgram::compileShaders(OpenGLContext& context,
|
||||
|
||||
const std::array<const char*, 4> sources = {
|
||||
prolog.data(),
|
||||
specializationConstantString.c_str(),
|
||||
specificationConstantString.c_str(),
|
||||
packingFunctions.data(),
|
||||
body.data()
|
||||
};
|
||||
|
||||
const std::array<GLint, 4> lengths = {
|
||||
(GLint)prolog.length(),
|
||||
(GLint)specializationConstantString.length(),
|
||||
(GLint)specificationConstantString.length(),
|
||||
(GLint)packingFunctions.length(),
|
||||
(GLint)body.length() - 1 // null terminated
|
||||
};
|
||||
@@ -286,15 +286,13 @@ bool OpenGLProgram::checkProgramStatus(const char* name,
|
||||
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
||||
const ShaderStage type = static_cast<ShaderStage>(i);
|
||||
const GLuint shader = shaderIds[i];
|
||||
if (shader) {
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
if (status != GL_TRUE) {
|
||||
logCompilationError(slog.e, type, name, shader, shaderSourceCode[i]);
|
||||
}
|
||||
glDetachShader(program, shader);
|
||||
glDeleteShader(shader);
|
||||
shaderIds[i] = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
if (status != GL_TRUE) {
|
||||
logCompilationError(slog.e, type, name, shader, shaderSourceCode[i]);
|
||||
}
|
||||
glDetachShader(program, shader);
|
||||
glDeleteShader(shader);
|
||||
shaderIds[i] = 0;
|
||||
}
|
||||
// log the link error as well
|
||||
logProgramLinkError(slog.e, name, program);
|
||||
|
||||
@@ -22,12 +22,8 @@
|
||||
#include <spirv_glsl.hpp>
|
||||
#include <spirv_msl.hpp>
|
||||
|
||||
#include "../src/GLSLPostProcessor.h"
|
||||
|
||||
#include "builtinResource.h"
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -63,6 +59,38 @@ void SpvToGlsl(const SpirvBlob* spirv, std::string* outGlsl) {
|
||||
*outGlsl = glslCompiler.compile();
|
||||
}
|
||||
|
||||
void SpvToMsl(const SpirvBlob* spirv, std::string* outMsl) {
|
||||
CompilerMSL mslCompiler(*spirv);
|
||||
mslCompiler.set_msl_options(CompilerMSL::Options {
|
||||
.msl_version = CompilerMSL::Options::make_msl_version(1, 1)
|
||||
});
|
||||
|
||||
auto executionModel = mslCompiler.get_execution_model();
|
||||
|
||||
auto duplicateResourceBinding = [executionModel, &mslCompiler](const auto& resource) {
|
||||
auto set = mslCompiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||
auto binding = mslCompiler.get_decoration(resource.id, spv::DecorationBinding);
|
||||
MSLResourceBinding newBinding;
|
||||
newBinding.stage = executionModel;
|
||||
newBinding.desc_set = set;
|
||||
newBinding.binding = binding;
|
||||
newBinding.msl_texture = binding;
|
||||
newBinding.msl_sampler = binding;
|
||||
newBinding.msl_buffer = binding;
|
||||
mslCompiler.add_msl_resource_binding(newBinding);
|
||||
};
|
||||
|
||||
auto resources = mslCompiler.get_shader_resources();
|
||||
for (const auto& resource : resources.sampled_images) {
|
||||
duplicateResourceBinding(resource);
|
||||
}
|
||||
for (const auto& resource : resources.uniform_buffers) {
|
||||
duplicateResourceBinding(resource);
|
||||
}
|
||||
|
||||
*outMsl = mslCompiler.compile();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void ShaderGenerator::init() {
|
||||
@@ -74,16 +102,15 @@ void ShaderGenerator::shutdown() {
|
||||
}
|
||||
|
||||
ShaderGenerator::ShaderGenerator(std::string vertex, std::string fragment,
|
||||
Backend backend, bool isMobile, const filament::SamplerInterfaceBlock* sib) noexcept
|
||||
Backend backend, bool isMobile) noexcept
|
||||
: mBackend(backend),
|
||||
mVertexBlob(transpileShader(ShaderStage::VERTEX, std::move(vertex), backend, isMobile, sib)),
|
||||
mVertexBlob(transpileShader(ShaderStage::VERTEX, std::move(vertex), backend, isMobile)),
|
||||
mFragmentBlob(transpileShader(ShaderStage::FRAGMENT, std::move(fragment), backend,
|
||||
isMobile, sib)) {
|
||||
isMobile)) {
|
||||
}
|
||||
|
||||
ShaderGenerator::Blob ShaderGenerator::transpileShader(
|
||||
ShaderStage stage, std::string shader, Backend backend, bool isMobile,
|
||||
const filament::SamplerInterfaceBlock* sib) noexcept {
|
||||
ShaderStage stage, std::string shader, Backend backend, bool isMobile) noexcept {
|
||||
TProgram program;
|
||||
const EShLanguage language = stage == ShaderStage::VERTEX ? EShLangVertex : EShLangFragment;
|
||||
TShader tShader(language);
|
||||
@@ -146,10 +173,7 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(
|
||||
}
|
||||
return { result.c_str(), result.c_str() + result.length() + 1 };
|
||||
} else if (backend == Backend::METAL) {
|
||||
const auto sm = isMobile ? ShaderModel::MOBILE : ShaderModel::DESKTOP;
|
||||
filamat::SibVector sibs = filamat::SibVector::with_capacity(1);
|
||||
if (sib) { sibs.emplace_back(0, sib); }
|
||||
filamat::GLSLPostProcessor::spirvToMsl(&spirv, &result, sm, false, sibs, nullptr);
|
||||
SpvToMsl(&spirv, &result);
|
||||
return { result.c_str(), result.c_str() + result.length() + 1 };
|
||||
} else if (backend == Backend::VULKAN) {
|
||||
return { (uint8_t*)spirv.data(), (uint8_t*)(spirv.data() + spirv.size()) };
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "PlatformRunner.h"
|
||||
|
||||
#include "private/filament/SamplerInterfaceBlock.h"
|
||||
#include "private/backend/DriverApi.h"
|
||||
#include "backend/Program.h"
|
||||
|
||||
@@ -39,8 +38,7 @@ public:
|
||||
* @param vertex The vertex shader, written in GLSL 450 core.
|
||||
* @param fragment The fragment shader, written in GLSL 450 core.
|
||||
*/
|
||||
ShaderGenerator(std::string vertex, std::string fragment, Backend backend, bool isMobile,
|
||||
const filament::SamplerInterfaceBlock* sib = nullptr) noexcept;
|
||||
ShaderGenerator(std::string vertex, std::string fragment, Backend backend, bool isMobile) noexcept;
|
||||
|
||||
ShaderGenerator(const ShaderGenerator& rhs) = delete;
|
||||
ShaderGenerator& operator=(const ShaderGenerator& rhs) = delete;
|
||||
@@ -52,7 +50,7 @@ private:
|
||||
|
||||
using Blob = std::vector<char>;
|
||||
static Blob transpileShader(ShaderStage stage, std::string shader, Backend backend,
|
||||
bool isMobile, const filament::SamplerInterfaceBlock* sib = nullptr) noexcept;
|
||||
bool isMobile) noexcept;
|
||||
|
||||
Backend mBackend;
|
||||
|
||||
|
||||
@@ -133,12 +133,7 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
// Create a program.
|
||||
ProgramHandle program;
|
||||
{
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("backend_test_sib")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
ShaderGenerator shaderGen(fullscreenVs, fullscreenFs, sBackend, sIsMobilePlatform, &sib);
|
||||
ShaderGenerator shaderGen(fullscreenVs, fullscreenFs, sBackend, sIsMobilePlatform);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
#include "private/filament/SamplerInterfaceBlock.h"
|
||||
#include "private/backend/SamplerGroup.h"
|
||||
|
||||
#include <math/half.h>
|
||||
@@ -55,7 +54,7 @@ layout(location = 0) out vec4 fragColor;
|
||||
|
||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||
// This parameter is ignored for other backends.
|
||||
layout(location = 0, set = 1) uniform {samplerType} test_tex;
|
||||
layout(location = 0, set = 1) uniform {samplerType} tex;
|
||||
|
||||
void main() {
|
||||
vec2 fbsize = vec2(512);
|
||||
@@ -63,7 +62,7 @@ void main() {
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
fragColor = vec4(texture(test_tex, uv).rgb, 1.0f);
|
||||
fragColor = vec4(texture(tex, uv).rgb, 1.0f);
|
||||
}
|
||||
|
||||
)");
|
||||
@@ -73,7 +72,8 @@ std::string fragmentUpdateImage3DTemplate (R"(#version 450 core
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||
layout(location = 0, set = 1) uniform {samplerType} test_tex;
|
||||
// This parameter is ignored for other backends.
|
||||
layout(location = 0, set = 1) uniform {samplerType} tex;
|
||||
|
||||
float getLayer(in sampler3D s) { return 2.5f / 4.0f; }
|
||||
float getLayer(in sampler2DArray s) { return 2.0f; }
|
||||
@@ -84,7 +84,7 @@ void main() {
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
fragColor = vec4(texture(test_tex, vec3(uv, getLayer(test_tex))).rgb, 1.0f);
|
||||
fragColor = vec4(texture(tex, vec3(uv, getLayer(tex))).rgb, 1.0f);
|
||||
}
|
||||
|
||||
)");
|
||||
@@ -94,7 +94,8 @@ std::string fragmentUpdateImageMip (R"(#version 450 core
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||
layout(location = 0, set = 1) uniform sampler2D test_tex;
|
||||
// This parameter is ignored for other backends.
|
||||
layout(location = 0, set = 1) uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
vec2 fbsize = vec2(512);
|
||||
@@ -102,7 +103,7 @@ void main() {
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
fragColor = vec4(textureLod(test_tex, uv, 1.0f).rgb, 1.0f);
|
||||
fragColor = vec4(textureLod(tex, uv, 1.0f).rgb, 1.0f);
|
||||
}
|
||||
|
||||
)");
|
||||
@@ -344,15 +345,10 @@ TEST_F(BackendTest, UpdateImage2D) {
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a program.
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("Test")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
ProgramHandle program;
|
||||
std::string fragment = stringReplace("{samplerType}",
|
||||
getSamplerTypeName(t.textureFormat), fragmentTemplate);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
@@ -429,14 +425,9 @@ TEST_F(BackendTest, UpdateImageSRGB) {
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a program.
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("Test")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
std::string fragment = stringReplace("{samplerType}",
|
||||
getSamplerTypeName(textureFormat), fragmentTemplate);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
@@ -520,14 +511,9 @@ TEST_F(BackendTest, UpdateImageMipLevel) {
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a program.
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("Test")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
std::string fragment = stringReplace("{samplerType}",
|
||||
getSamplerTypeName(textureFormat), fragmentUpdateImageMip);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
@@ -597,14 +583,9 @@ TEST_F(BackendTest, UpdateImage3D) {
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a program.
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("Test")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
std::string fragment = stringReplace("{samplerType}",
|
||||
getSamplerTypeName(samplerType), fragmentUpdateImage3DTemplate);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
|
||||
@@ -45,7 +45,7 @@ std::string fragment (R"(#version 450 core
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 0) in vec2 uv;
|
||||
|
||||
layout(location = 0, set = 1) uniform sampler2D tex;
|
||||
layout(set = 1, binding = 6) uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
fragColor = texture(tex, uv);
|
||||
@@ -65,16 +65,11 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||
|
||||
auto swapChain = createSwapChain();
|
||||
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("backend_test_sib")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
|
||||
// Create a program that samples a texture.
|
||||
Program p = shaderGen.getProgram(getDriverApi());
|
||||
Program::Sampler sampler { utils::CString("tex"), 0 };
|
||||
Program::Sampler sampler { utils::CString("tex"), 6 };
|
||||
p.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, &sampler, 1);
|
||||
backend::Handle<HwProgram> program = getDriverApi().createProgram(std::move(p));
|
||||
|
||||
@@ -144,16 +139,11 @@ TEST_F(BackendTest, RenderExternalImage) {
|
||||
|
||||
auto swapChain = createSwapChain();
|
||||
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("backend_test_sib")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
|
||||
// Create a program that samples a texture.
|
||||
Program p = shaderGen.getProgram(getDriverApi());
|
||||
Program::Sampler sampler { utils::CString("tex"), 0 };
|
||||
Program::Sampler sampler { utils::CString("tex"), 6 };
|
||||
p.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, &sampler, 1);
|
||||
auto program = getDriverApi().createProgram(std::move(p));
|
||||
|
||||
|
||||
@@ -340,6 +340,14 @@ public:
|
||||
* @see View::setShadowType
|
||||
*/
|
||||
struct Vsm {
|
||||
/**
|
||||
* The number of MSAA samples to use when rendering VSM shadow maps.
|
||||
* Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns
|
||||
* off MSAA.
|
||||
* Higher values may not be available depending on the underlying hardware.
|
||||
*/
|
||||
uint8_t msaaSamples = 1;
|
||||
|
||||
/**
|
||||
* When elvsm is set to true, "Exponential Layered VSM without Layers" are used. It is
|
||||
* an improvement to the default EVSM which suffers important light leaks. Enabling
|
||||
|
||||
@@ -390,14 +390,6 @@ struct VsmShadowOptions {
|
||||
*/
|
||||
bool mipmapping = false;
|
||||
|
||||
/**
|
||||
* The number of MSAA samples to use when rendering VSM shadow maps.
|
||||
* Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns
|
||||
* off MSAA.
|
||||
* Higher values may not be available depending on the underlying hardware.
|
||||
*/
|
||||
uint8_t msaaSamples = 1;
|
||||
|
||||
/**
|
||||
* Whether to use a 32-bits or 16-bits texture format for VSM shadow maps. 32-bits
|
||||
* precision is rarely needed, but it does reduces light leaks as well as "fading"
|
||||
|
||||
@@ -35,8 +35,8 @@ AtlasAllocator::AtlasAllocator(size_t maxTextureSize) noexcept {
|
||||
mMaxTextureSizePot = (sizeof(maxTextureSize) * 8 - 1u) - utils::clz(maxTextureSize);
|
||||
}
|
||||
|
||||
AtlasAllocator::Allocation AtlasAllocator::allocate(size_t textureSize) noexcept {
|
||||
Allocation result{};
|
||||
Viewport AtlasAllocator::allocate(size_t textureSize) noexcept {
|
||||
Viewport result{};
|
||||
const size_t powerOfTwo = (sizeof(textureSize) * 8 - 1u) - utils::clz(textureSize);
|
||||
|
||||
// asked for a texture size too large
|
||||
@@ -45,24 +45,22 @@ AtlasAllocator::Allocation AtlasAllocator::allocate(size_t textureSize) noexcept
|
||||
}
|
||||
|
||||
// asked for a texture size too small
|
||||
if (UTILS_UNLIKELY(mMaxTextureSizePot - powerOfTwo >= QUAD_TREE_DEPTH)) {
|
||||
if (UTILS_UNLIKELY(mMaxTextureSizePot - powerOfTwo >= QuadTree::height())) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const size_t layer = (mMaxTextureSizePot - powerOfTwo);
|
||||
const NodeId loc = allocateInLayer(LAYERS_DEPTH + layer);
|
||||
const size_t layer = mMaxTextureSizePot - powerOfTwo;
|
||||
const NodeId loc = allocateInLayer(layer);
|
||||
if (loc.l >= 0) {
|
||||
assert_invariant(loc.l - LAYERS_DEPTH == int8_t(layer));
|
||||
const size_t dimension = 1u << powerOfTwo;
|
||||
assert_invariant(loc.l == int8_t(layer));
|
||||
size_t dimension = 1u << powerOfTwo;
|
||||
// find the location of in the texture from the morton code (quadtree position)
|
||||
const auto [x, y] = unmorton(loc.code);
|
||||
auto [x, y] = unmorton(loc.code);
|
||||
// scale to our maximum allocation size
|
||||
const uint32_t mask = (1u << layer) - 1u;
|
||||
result.viewport.left = int32_t(x & mask) << powerOfTwo;
|
||||
result.viewport.bottom = int32_t(y & mask) << powerOfTwo;
|
||||
result.viewport.width = dimension;
|
||||
result.viewport.height = dimension;
|
||||
result.layer = loc.code >> (2 * layer);
|
||||
result.left = int32_t(x) << powerOfTwo;
|
||||
result.bottom = int32_t(y) << powerOfTwo;
|
||||
result.width = dimension;
|
||||
result.height = dimension;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -110,9 +108,9 @@ AtlasAllocator::NodeId AtlasAllocator::allocateInLayer(size_t maxHeight) noexcep
|
||||
}
|
||||
|
||||
// We only want to find a fitting node that already has siblings, in order
|
||||
// to accomplish a "best fit" allocation. So if a parent (of what we're looking for)
|
||||
// has no children, we skip the whole tree below it.
|
||||
if (!node.hasChildren()) {
|
||||
// to accomplish a "best fit" allocation. So if we're a parent of a 'fitting'
|
||||
// node and don't have children, we skip the children recursion.
|
||||
if (curr.l == n - 1 && !node.hasChildren()) {
|
||||
return QuadTree::TraversalResult::SKIP_CHILDREN;
|
||||
}
|
||||
|
||||
@@ -123,8 +121,6 @@ AtlasAllocator::NodeId AtlasAllocator::allocateInLayer(size_t maxHeight) noexcep
|
||||
if (candidate.l >= 0) {
|
||||
const size_t i = index(candidate.l, candidate.code);
|
||||
Node& allocation = mQuadTree[i];
|
||||
assert_invariant(!allocation.isAllocated());
|
||||
assert_invariant(!allocation.hasChildren());
|
||||
|
||||
if (candidate.l == n) {
|
||||
allocation.allocated = true;
|
||||
@@ -136,38 +132,26 @@ AtlasAllocator::NodeId AtlasAllocator::allocateInLayer(size_t maxHeight) noexcep
|
||||
assert_invariant(parent.hasChildren());
|
||||
assert_invariant(!parent.hasAllChildren());
|
||||
parent.children++;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// check that all the parents are not allocated and have at least 1 child.
|
||||
NodeId ppp = candidate;
|
||||
while (ppp.l > 0) {
|
||||
const size_t pi = QuadTreeUtils::parent(ppp.l, ppp.code);
|
||||
ppp = NodeId{ int8_t(ppp.l - 1), uint8_t(ppp.code >> 2) };
|
||||
Node& node = mQuadTree[pi];
|
||||
assert_invariant(!node.isAllocated());
|
||||
assert_invariant(node.hasChildren());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else if (candidate.l < int8_t(QuadTree::height())) {
|
||||
// we need to create the hierarchy down to the level we need
|
||||
NodeId found{ -1, 0 };
|
||||
assert_invariant(!allocation.isAllocated());
|
||||
assert_invariant(!allocation.hasChildren());
|
||||
|
||||
NodeId found{};
|
||||
QuadTree::traverse(candidate.l, candidate.code,
|
||||
[this, n, &found](NodeId const& curr) -> QuadTree::TraversalResult {
|
||||
size_t i = index(curr.l, curr.code);
|
||||
Node& node = mQuadTree[i];
|
||||
if (curr.l == n) {
|
||||
found = curr;
|
||||
assert_invariant(!node.hasChildren());
|
||||
node.allocated = true;
|
||||
return QuadTree::TraversalResult::EXIT;
|
||||
}
|
||||
assert_invariant(!node.hasAllChildren());
|
||||
node.children++;
|
||||
return QuadTree::TraversalResult::RECURSE;
|
||||
});
|
||||
|
||||
assert_invariant(found.l != -1);
|
||||
candidate = found;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
#include <filament/Viewport.h>
|
||||
|
||||
#include <private/filament/EngineEnums.h>
|
||||
|
||||
class AtlasAllocator_AllocateFirstLevel_Test;
|
||||
class AtlasAllocator_AllocateSecondLevel_Test;
|
||||
class AtlasAllocator_AllocateMixed0_Test;
|
||||
@@ -55,18 +53,8 @@ class AtlasAllocator {
|
||||
uint8_t children : 3; // 0, 1, 2, 3, 4
|
||||
};
|
||||
|
||||
// this determines the number of layers we can use (3 layers == 64 quadtree entries)
|
||||
static constexpr size_t LAYERS_DEPTH = 3u;
|
||||
|
||||
// this determines how many "sub-sizes" we can have from the base size.
|
||||
// e.g. with a max texture size of 1024, we can allocate 1024, 512, 256 and 128 textures.
|
||||
static constexpr size_t QUAD_TREE_DEPTH = 4u;
|
||||
|
||||
// LAYERS_DEPTH limits the number of layers
|
||||
static_assert(CONFIG_MAX_SHADOW_LAYERS <= 1u << (LAYERS_DEPTH * 2u));
|
||||
|
||||
// QuadTreeArray is limited to a maximum depth of 7
|
||||
using QuadTree = utils::QuadTreeArray<Node, LAYERS_DEPTH + QUAD_TREE_DEPTH>;
|
||||
using QuadTree = utils::QuadTreeArray<Node, QUAD_TREE_DEPTH>;
|
||||
using NodeId = QuadTree::NodeId;
|
||||
|
||||
public:
|
||||
@@ -74,18 +62,14 @@ public:
|
||||
* Create allocator and specify the maximum texture size. Must be a power of two.
|
||||
* Allocations size allowed are the four power-of-two smaller or equal to this size.
|
||||
*/
|
||||
explicit AtlasAllocator(size_t maxTextureSize) noexcept;
|
||||
explicit AtlasAllocator(size_t maxTextureSize = 1024) noexcept;
|
||||
|
||||
/*
|
||||
* Allocates a square of size `textureSize`. Must be one of the power-of-two allowed
|
||||
* (see above).
|
||||
* Returns the location of the allocation within the maxTextureSize^2 square.
|
||||
*/
|
||||
struct Allocation {
|
||||
int32_t layer = -1;
|
||||
Viewport viewport;
|
||||
};
|
||||
Allocation allocate(size_t textureSize) noexcept;
|
||||
Viewport allocate(size_t textureSize) noexcept;
|
||||
|
||||
/*
|
||||
* Frees all allocations and reset the maximum texture size.
|
||||
|
||||
@@ -92,6 +92,7 @@ private:
|
||||
|
||||
template<size_t POOL_SIZE, size_t ALIGNMENT, typename AllocatorPolicy, typename LockingPolicy>
|
||||
BufferPoolAllocator<POOL_SIZE, ALIGNMENT, AllocatorPolicy, LockingPolicy>::~BufferPoolAllocator() noexcept {
|
||||
assert_invariant(mOutstandingBuffers == mEntries.size());
|
||||
clearInternal();
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ void PerShadowMapUniforms::prepareLodBias(Transaction const& transaction,
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::prepareViewport(Transaction const& transaction,
|
||||
backend::Viewport const& viewport,
|
||||
const filament::Viewport& viewport,
|
||||
uint32_t xoffset, uint32_t yoffset) noexcept {
|
||||
const float w = float(viewport.width);
|
||||
const float h = float(viewport.height);
|
||||
@@ -98,6 +98,45 @@ void PerShadowMapUniforms::prepareTime(Transaction const& transaction,
|
||||
s.userTime = userTime;
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::prepareDirectionalLight(Transaction const& transaction,
|
||||
FEngine& engine,
|
||||
float exposure,
|
||||
float3 const& sceneSpaceDirection,
|
||||
PerShadowMapUniforms::LightManagerInstance directionalLight) noexcept {
|
||||
FLightManager& lcm = engine.getLightManager();
|
||||
auto& s = edit(transaction);
|
||||
|
||||
const float3 l = -sceneSpaceDirection; // guaranteed normalized
|
||||
|
||||
if (directionalLight.isValid()) {
|
||||
const float4 colorIntensity = {
|
||||
lcm.getColor(directionalLight), lcm.getIntensity(directionalLight) * exposure };
|
||||
|
||||
s.lightDirection = l;
|
||||
s.lightColorIntensity = colorIntensity;
|
||||
s.lightChannels = lcm.getLightChannels(directionalLight);
|
||||
|
||||
const bool isSun = lcm.isSunLight(directionalLight);
|
||||
// The last parameter must be < 0.0f for regular directional lights
|
||||
float4 sun{ 0.0f, 0.0f, 0.0f, -1.0f };
|
||||
if (UTILS_UNLIKELY(isSun && colorIntensity.w > 0.0f)) {
|
||||
// currently we have only a single directional light, so it's probably likely that it's
|
||||
// also the Sun. However, conceptually, most directional lights won't be sun lights.
|
||||
float radius = lcm.getSunAngularRadius(directionalLight);
|
||||
float haloSize = lcm.getSunHaloSize(directionalLight);
|
||||
float haloFalloff = lcm.getSunHaloFalloff(directionalLight);
|
||||
sun.x = std::cos(radius);
|
||||
sun.y = std::sin(radius);
|
||||
sun.z = 1.0f / (std::cos(radius * haloSize) - sun.x);
|
||||
sun.w = haloFalloff;
|
||||
}
|
||||
s.sun = sun;
|
||||
} else {
|
||||
// Disable the sun if there's no directional light
|
||||
s.sun = float4{ 0.0f, 0.0f, 0.0f, -1.0f };
|
||||
}
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::prepareShadowMapping(Transaction const& transaction,
|
||||
bool highPrecision) noexcept {
|
||||
auto& s = edit(transaction);
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
float bias) noexcept;
|
||||
|
||||
static void prepareViewport(Transaction const& transaction,
|
||||
backend::Viewport const& viewport, uint32_t xoffset, uint32_t yoffset) noexcept;
|
||||
const filament::Viewport& viewport, uint32_t xoffset, uint32_t yoffset) noexcept;
|
||||
|
||||
static void prepareTime(Transaction const& transaction,
|
||||
FEngine& engine, math::float4 const& userTime) noexcept;
|
||||
@@ -73,6 +73,10 @@ public:
|
||||
static void prepareShadowMapping(Transaction const& transaction,
|
||||
bool highPrecision) noexcept;
|
||||
|
||||
static void prepareDirectionalLight(Transaction const& transaction,
|
||||
FEngine& engine, float exposure,
|
||||
math::float3 const& sceneSpaceDirection, LightManagerInstance instance) noexcept;
|
||||
|
||||
static Transaction open(backend::DriverApi& driver) noexcept;
|
||||
|
||||
// update local data into GPU UBO
|
||||
|
||||
@@ -290,10 +290,14 @@ void PerViewUniforms::prepareShadowMapping(bool highPrecision) noexcept {
|
||||
|
||||
void PerViewUniforms::prepareShadowSampling(PerViewUib& uniforms,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
|
||||
uniforms.lightFromWorldMatrix = shadowMappingUniforms.lightFromWorldMatrix;
|
||||
uniforms.cascadeSplits = shadowMappingUniforms.cascadeSplits;
|
||||
uniforms.shadowBulbRadiusLs = shadowMappingUniforms.shadowBulbRadiusLs;
|
||||
uniforms.shadowBias = shadowMappingUniforms.shadowBias;
|
||||
uniforms.ssContactShadowDistance = shadowMappingUniforms.ssContactShadowDistance;
|
||||
uniforms.directionalShadows = shadowMappingUniforms.directionalShadows;
|
||||
uniforms.cascades = shadowMappingUniforms.cascades;
|
||||
uniforms.cascades |= uint32_t(shadowMappingUniforms.elvsm) << 31u;
|
||||
}
|
||||
|
||||
void PerViewUniforms::prepareShadowVSM(Handle<HwTexture> texture,
|
||||
|
||||
@@ -707,11 +707,6 @@ void RenderPass::Executor::overrideScissor(backend::Viewport const* scissor) noe
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPass::Executor::overrideScissor(backend::Viewport const& scissor) noexcept {
|
||||
mScissorOverride = true;
|
||||
mScissor = scissor;
|
||||
}
|
||||
|
||||
void RenderPass::Executor::execute(FEngine& engine, const char* name) const noexcept {
|
||||
execute(engine.getDriverApi(), mCommands.begin(), mCommands.end());
|
||||
}
|
||||
@@ -755,11 +750,6 @@ void RenderPass::Executor::execute(backend::DriverApi& driver,
|
||||
continue;
|
||||
}
|
||||
|
||||
// primitiveHandle may be invalid if no geometry was set on the renderable.
|
||||
if (UTILS_UNLIKELY(!first->primitive.primitiveHandle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// per-renderable uniform
|
||||
const PrimitiveInfo info = first->primitive;
|
||||
pipeline.rasterState = info.rasterState;
|
||||
|
||||
@@ -349,7 +349,6 @@ public:
|
||||
|
||||
// if non-null, overrides the material's scissor
|
||||
void overrideScissor(backend::Viewport const* scissor) noexcept;
|
||||
void overrideScissor(backend::Viewport const& scissor) noexcept;
|
||||
|
||||
void execute(FEngine& engine, const char* name) const noexcept;
|
||||
};
|
||||
|
||||
+135
-100
@@ -368,9 +368,8 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
|
||||
// Computes St the transform to use in the shader to access the shadow map texture
|
||||
// i.e. it transforms a world-space vertex to a texture coordinate in the shadowmap
|
||||
const backend::Viewport viewport = getViewport();
|
||||
const auto [Mt, Mn] = ShadowMap::getTextureCoordsMapping(shadowMapInfo, viewport);
|
||||
const mat4f St = math::highPrecisionMultiply(Mt, S);
|
||||
const mat4 MbMt = getTextureCoordsMapping(shadowMapInfo);
|
||||
const mat4f St = mat4f(MbMt * S);
|
||||
|
||||
ShadowMap::ShaderParameters shaderParameters;
|
||||
|
||||
@@ -378,7 +377,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
// L * Mp * Mv is a rigid transform for directional lights, and doesn't matter.
|
||||
// if Wp[3][1] is 0, then LISPSM was cancelled.
|
||||
if (useLispsm && Wp[3][1] != 0.0f) {
|
||||
shaderParameters.texelSizeAtOneMeterWs = texelSizeWorldSpace(Wp, mat4f(Mt * F),
|
||||
shaderParameters.texelSizeAtOneMeterWs = texelSizeWorldSpace(Wp, mat4f(MbMt * F),
|
||||
shadowMapInfo.shadowDimension);
|
||||
} else {
|
||||
// We know we're using an ortho projection
|
||||
@@ -391,8 +390,6 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
shaderParameters.lightSpace = computeVsmLightSpaceMatrix(St, Mv, znear, zfar);
|
||||
}
|
||||
|
||||
shaderParameters.scissorNormalized = getViewportNormalized(shadowMapInfo);
|
||||
|
||||
// We apply the constant bias in world space (as opposed to light-space) to account
|
||||
// for perspective and lispsm shadow maps. This also allows us to do this at zero-cost
|
||||
// by baking it in the shadow-map itself.
|
||||
@@ -407,8 +404,8 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
// The model matrix below is in fact inverted to get the view matrix and passed to the
|
||||
// shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric.
|
||||
// (see depth_main.fs). Note that in the case of VSM, 'b' below is identity.
|
||||
mCamera->setModelMatrix(FCamera::rigidTransformInverse(math::highPrecisionMultiplyd(Mv, b)));
|
||||
mCamera->setCustomProjection(mat4(Mn * F * W * L * Mp), znear, zfar);
|
||||
mCamera->setModelMatrix(mat4{ FCamera::rigidTransformInverse(Mv * b) });
|
||||
mCamera->setCustomProjection(mat4(F * W * L * Mp), znear, zfar);
|
||||
|
||||
// for the debug camera, we need to undo the world origin
|
||||
mDebugCamera->setCustomProjection(mat4(S * b * camera.worldOrigin), znear, zfar);
|
||||
@@ -416,18 +413,48 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
return shaderParameters;
|
||||
}
|
||||
|
||||
ShadowMap::ShaderParameters ShadowMap::updatePunctual(
|
||||
mat4f const& Mv, float outerConeAngle, float nearPlane, float farPlane,
|
||||
const ShadowMapInfo& shadowMapInfo, const FLightManager::ShadowParams& params) noexcept {
|
||||
const mat4f Mp = mat4f::perspective(outerConeAngle * f::RAD_TO_DEG * 2.0f, 1.0f, nearPlane, farPlane);
|
||||
ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
|
||||
const FScene::LightSoa& lightData, size_t index,
|
||||
filament::CameraInfo const& camera,
|
||||
const ShadowMapInfo& shadowMapInfo,
|
||||
FScene const& scene, SceneInfo sceneInfo) noexcept {
|
||||
|
||||
assert_invariant(shadowMapInfo.textureDimension == mOptions->mapSize);
|
||||
ShaderParameters shaderParameters;
|
||||
|
||||
auto& lcm = engine.getLightManager();
|
||||
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
auto position = lightData.elementAt<FScene::POSITION_RADIUS>(index).xyz;
|
||||
auto direction = lightData.elementAt<FScene::DIRECTION>(index);
|
||||
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
|
||||
auto outerConeAngle = lcm.getSpotLightOuterCone(li);
|
||||
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
|
||||
|
||||
/*
|
||||
* Compute the light model matrix.
|
||||
*/
|
||||
|
||||
// Choose a reasonable value for the near plane.
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, position);
|
||||
|
||||
// find decent near/far
|
||||
ShadowMap::updateSceneInfoSpot(Mv, scene, sceneInfo);
|
||||
|
||||
// if the scene was empty, near > far
|
||||
mHasVisibleShadows = -sceneInfo.lsNearFar[0] < -sceneInfo.lsNearFar[1];
|
||||
|
||||
// FIXME: we need a configuration for minimum near plane (for now hardcoded to 1cm)
|
||||
float nearPlane = std::max(0.01f, -sceneInfo.lsNearFar[0]);
|
||||
float farPlane = std::min(radius, -sceneInfo.lsNearFar[1]);
|
||||
|
||||
float outerConeAngleDegrees = outerConeAngle * f::RAD_TO_DEG;
|
||||
const mat4f Mp = mat4f::perspective(outerConeAngleDegrees * 2.0f, 1.0f, nearPlane, farPlane);
|
||||
const mat4f MpMv(math::highPrecisionMultiply(Mp, Mv));
|
||||
|
||||
// Final shadow transform
|
||||
const backend::Viewport viewport = getViewport();
|
||||
const mat4f S = math::highPrecisionMultiply(Mp, Mv);
|
||||
const auto [Mt, Mn] = ShadowMap::getTextureCoordsMapping(shadowMapInfo, viewport);
|
||||
const mat4f St = math::highPrecisionMultiply(Mt, S);
|
||||
const mat4f S = MpMv;
|
||||
|
||||
const mat4 MbMt = getTextureCoordsMapping(shadowMapInfo);
|
||||
const mat4f St = mat4f(MbMt * S);
|
||||
|
||||
// TODO: focus projection
|
||||
// 1) focus on the casters
|
||||
@@ -442,9 +469,7 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual(
|
||||
// = zInLightSpace * texelSizeAtOneMeter
|
||||
// = zInLightSpace * (2*tan(halfConeAngle)/dimension)
|
||||
// Note: this would not work with LISPSM, which warps the texture space.
|
||||
ShaderParameters shaderParameters;
|
||||
shaderParameters.texelSizeAtOneMeterWs =
|
||||
(2.0f * std::tan(outerConeAngle) / float(shadowMapInfo.shadowDimension));
|
||||
shaderParameters.texelSizeAtOneMeterWs = (2.0f * std::tan(outerConeAngle) / float(shadowMapInfo.shadowDimension));
|
||||
shaderParameters.lightFromWorldZ = -transpose(Mv)[2]; // negate because camera looks in -Z
|
||||
|
||||
if (!shadowMapInfo.vsm) {
|
||||
@@ -453,11 +478,9 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual(
|
||||
shaderParameters.lightSpace = computeVsmLightSpaceMatrix(St, Mv, nearPlane, farPlane);
|
||||
}
|
||||
|
||||
shaderParameters.scissorNormalized = getViewportNormalized(shadowMapInfo);
|
||||
|
||||
const float3 direction = -transpose(Mv)[2].xyz;
|
||||
const float constantBias = shadowMapInfo.vsm ? 0.0f : params.options.constantBias;
|
||||
const mat4f b = mat4f::translation(direction * constantBias);
|
||||
const mat4f Sb = S * b;
|
||||
|
||||
// It's important to set the light camera's model matrix separately from its projection, so that
|
||||
// the cameraPosition uniform gets set correctly.
|
||||
@@ -467,47 +490,22 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual(
|
||||
// The model matrix below is in fact inverted to get the view matrix and passed to the
|
||||
// shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric.
|
||||
// (see depth_main.fs). Note that in the case of VSM, 'b' below is identity.
|
||||
mCamera->setModelMatrix(FCamera::rigidTransformInverse(math::highPrecisionMultiplyd(Mv, b)));
|
||||
mCamera->setCustomProjection(math::highPrecisionMultiplyd(Mn, Mp), nearPlane, farPlane);
|
||||
mCamera->setModelMatrix(mat4{ FCamera::rigidTransformInverse(Mv * b) });
|
||||
mCamera->setCustomProjection(mat4(Mp), nearPlane, farPlane);
|
||||
|
||||
// for the debug camera, we need to undo the world origin
|
||||
mDebugCamera->setCustomProjection(mat4(Sb * camera.worldOrigin), nearPlane, radius);
|
||||
|
||||
return shaderParameters;
|
||||
}
|
||||
|
||||
ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
|
||||
const FScene::LightSoa& lightData, size_t index,
|
||||
filament::CameraInfo const& camera,
|
||||
const ShadowMapInfo& shadowMapInfo,
|
||||
FScene const& scene, SceneInfo sceneInfo) noexcept {
|
||||
|
||||
auto& lcm = engine.getLightManager();
|
||||
auto position = lightData.elementAt<FScene::POSITION_RADIUS>(index).xyz;
|
||||
auto direction = lightData.elementAt<FScene::DIRECTION>(index);
|
||||
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
|
||||
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, position);
|
||||
|
||||
// find decent near/far
|
||||
ShadowMap::updateSceneInfoSpot(Mv, scene, sceneInfo);
|
||||
|
||||
// if the scene was empty, near > far
|
||||
mHasVisibleShadows = -sceneInfo.lsNearFar[0] < -sceneInfo.lsNearFar[1];
|
||||
if (!mHasVisibleShadows) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// FIXME: we need a configuration for minimum near plane (for now hardcoded to 1cm)
|
||||
float nearPlane = std::max(0.01f, -sceneInfo.lsNearFar[0]);
|
||||
float farPlane = std::min(radius, -sceneInfo.lsNearFar[1]);
|
||||
auto outerConeAngle = lcm.getSpotLightOuterCone(li);
|
||||
return updatePunctual(Mv, outerConeAngle, nearPlane, farPlane, shadowMapInfo, params);
|
||||
}
|
||||
|
||||
ShadowMap::ShaderParameters ShadowMap::updatePoint(FEngine& engine,
|
||||
const FScene::LightSoa& lightData, size_t index,
|
||||
filament::CameraInfo const& camera, const ShadowMapInfo& shadowMapInfo, FScene const& scene,
|
||||
SceneInfo, uint8_t face) noexcept {
|
||||
|
||||
ShaderParameters shaderParameters;
|
||||
|
||||
// check if this shadow map has anything to render
|
||||
mHasVisibleShadows = false;
|
||||
FScene::RenderableSoa const& UTILS_RESTRICT soa = scene.getRenderableData();
|
||||
@@ -520,16 +518,53 @@ ShadowMap::ShaderParameters ShadowMap::updatePoint(FEngine& engine,
|
||||
}
|
||||
}
|
||||
if (!mHasVisibleShadows) {
|
||||
return {};
|
||||
return shaderParameters;
|
||||
}
|
||||
|
||||
auto& lcm = engine.getLightManager();
|
||||
|
||||
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
auto position = lightData.elementAt<FScene::POSITION_RADIUS>(index).xyz;
|
||||
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
|
||||
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
|
||||
|
||||
/*
|
||||
* Compute the light model matrix.
|
||||
*/
|
||||
|
||||
const mat4f Mv = getPointLightViewMatrix(TextureCubemapFace(face), position);
|
||||
return updatePunctual(Mv, 45.0f * f::DEG_TO_RAD, 0.01f, radius, shadowMapInfo, params);
|
||||
const float3 direction = -transpose(Mv)[2].xyz;
|
||||
|
||||
// TODO: don't hardcode near plane
|
||||
// Choose a reasonable value for the near plane.
|
||||
float nearPlane = 0.01f;
|
||||
float farPlane = radius;
|
||||
const mat4f Mp = mat4f::perspective(90.0f, 1.0f, nearPlane, farPlane);
|
||||
|
||||
// For calculating the point light normal bias, we need the texel size in world space at the
|
||||
// sample location. Using Thales's theorem, we find:
|
||||
// texelSize(zInLightSpace) = zInLightSpace * texelSizeOnTheNearPlane / near
|
||||
// = zInLightSpace * texelSizeAtOneMeter
|
||||
// = zInLightSpace * (2*tan(halfConeAngle)/dimension)
|
||||
// Note: this would not work with LISPSM, which warps the texture space.
|
||||
shaderParameters.texelSizeAtOneMeterWs =
|
||||
(2.0f * std::tan(f::PI_4) / float(shadowMapInfo.shadowDimension));
|
||||
|
||||
const float constantBias = shadowMapInfo.vsm ? 0.0f : params.options.constantBias;
|
||||
const mat4f b = mat4f::translation(direction * constantBias);
|
||||
|
||||
// It's important to set the light camera's model matrix separately from its projection, so that
|
||||
// the cameraPosition uniform gets set correctly.
|
||||
// mLightSpace is used in the shader to access the shadow map texture, and has the model matrix
|
||||
// baked in.
|
||||
|
||||
// The model matrix below is in fact inverted to get the view matrix and passed to the
|
||||
// shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric.
|
||||
// (see depth_main.fs). Note that in the case of VSM, 'b' below is identity.
|
||||
mCamera->setModelMatrix(mat4{ FCamera::rigidTransformInverse(Mv * b) });
|
||||
mCamera->setCustomProjection(mat4(Mp), nearPlane, farPlane);
|
||||
|
||||
return shaderParameters;
|
||||
}
|
||||
|
||||
mat4f ShadowMap::applyLISPSM(mat4f& Wp,
|
||||
@@ -611,8 +646,7 @@ mat4f ShadowMap::applyLISPSM(mat4f& Wp,
|
||||
|
||||
|
||||
// Apply these remapping in double to maintain a high precision for the depth axis
|
||||
ShadowMap::TextureCoordsMapping ShadowMap::getTextureCoordsMapping(ShadowMapInfo const& info,
|
||||
backend::Viewport const& viewport) noexcept {
|
||||
mat4 ShadowMap::getTextureCoordsMapping(ShadowMapInfo const& info) noexcept {
|
||||
// remapping from NDC to texture coordinates (i.e. [-1,1] -> [0, 1])
|
||||
// ([1, 0] for depth mapping)
|
||||
const mat4f Mt(info.clipSpaceFlipped ? mat4f::row_major_init{
|
||||
@@ -627,12 +661,22 @@ ShadowMap::TextureCoordsMapping ShadowMap::getTextureCoordsMapping(ShadowMapInfo
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
});
|
||||
|
||||
// apply the viewport transform
|
||||
const float2 o = float2{ viewport.left, viewport.bottom } / float(info.atlasDimension);
|
||||
const float2 s = float2{ viewport.width, viewport.height } / float(info.atlasDimension);
|
||||
// the shadow map texture might be larger than the shadow map dimension, so we add a scaling
|
||||
// factor
|
||||
const float v = float(info.textureDimension) / float(info.atlasDimension);
|
||||
const mat4f Mv(mat4f::row_major_init{
|
||||
s.x, 0.0f, 0.0f, o.x,
|
||||
0.0f, s.y, 0.0f, o.y,
|
||||
v, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, v, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
});
|
||||
|
||||
// apply the 1-texel border viewport transform
|
||||
const float o = 1.0f / float(info.atlasDimension);
|
||||
const float s = 1.0f - 2.0f * (1.0f / float(info.textureDimension));
|
||||
const mat4f Mb(mat4f::row_major_init{
|
||||
s, 0.0f, 0.0f, o,
|
||||
0.0f, s, 0.0f, o,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
});
|
||||
@@ -644,8 +688,8 @@ ShadowMap::TextureCoordsMapping ShadowMap::getTextureCoordsMapping(ShadowMapInfo
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
}) : mat4f();
|
||||
|
||||
// Compute shadow-map texture access and viewport transform
|
||||
return { Mf * (Mv * Mt), inverse(Mt) * (Mv * Mt) };
|
||||
// Compute shadow-map texture access transform
|
||||
return mat4(Mf * Mb * Mv * Mt);
|
||||
}
|
||||
|
||||
mat4f ShadowMap::computeVsmLightSpaceMatrix(const mat4f& lightSpacePcf,
|
||||
@@ -1140,8 +1184,6 @@ void ShadowMap::visitScene(const FScene& scene, uint32_t visibleLayers,
|
||||
|
||||
void ShadowMap::initSceneInfo(ShadowMap::SceneInfo& sceneInfo,
|
||||
uint8_t visibleLayers, FScene const& scene, mat4f const& viewMatrix) {
|
||||
sceneInfo.csNearFar = { -1.0f, 1.0f };
|
||||
sceneInfo.lsNearFar = {};
|
||||
sceneInfo.visibleLayers = visibleLayers;
|
||||
sceneInfo.vsNearFar = { std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max() };
|
||||
|
||||
@@ -1201,40 +1243,26 @@ void ShadowMap::updateSceneInfoSpot(mat4f const& Mv, FScene const& scene,
|
||||
);
|
||||
}
|
||||
|
||||
backend::Viewport ShadowMap::getViewport() const noexcept {
|
||||
filament::Viewport ShadowMap::getViewport() const noexcept {
|
||||
// We set a viewport with a 1-texel border for when we index outside the
|
||||
// texture. This can only happen for the directional light when "focus shadow casters is used".
|
||||
// texture.
|
||||
// DON'T CHANGE this unless ShadowMap::getTextureCoordsMapping() is updated too.
|
||||
// see: ShadowMap::getTextureCoordsMapping()
|
||||
//
|
||||
// For floating-point depth textures, the 1-texel border could be set to
|
||||
// FLOAT_MAX to avoid clamping in the shadow shader (see sampleDepth inside
|
||||
// shadowing.fs). Unfortunately, the APIs don't seem let us clear depth
|
||||
// attachments to anything greater than 1.0, so we'd need a way to do this other
|
||||
// than clearing.
|
||||
const uint32_t dim = mOptions->mapSize;
|
||||
const uint16_t border = 1u;
|
||||
return { border, border, dim - 2u * border, dim - 2u * border };
|
||||
}
|
||||
|
||||
backend::Viewport ShadowMap::getScissor() const noexcept {
|
||||
// We set a viewport with a 1-texel border for when we index outside the
|
||||
// texture. This can only happen for the directional light when "focus shadow casters is used".
|
||||
const uint32_t dim = mOptions->mapSize;
|
||||
const uint16_t border = 1u;
|
||||
|
||||
switch (mShadowType) {
|
||||
case ShadowType::DIRECTIONAL:
|
||||
return { border, border, dim - 2u * border, dim - 2u * border };
|
||||
case ShadowType::SPOT:
|
||||
case ShadowType::POINT:
|
||||
default:
|
||||
return { 0, 0, dim, dim };
|
||||
if (isPointShadow()) {
|
||||
// for point-light we don't have a border
|
||||
return { 0, 0, dim, dim };
|
||||
} else {
|
||||
return { 1, 1, dim - 2, dim - 2 };
|
||||
}
|
||||
}
|
||||
|
||||
math::float4 ShadowMap::getViewportNormalized(ShadowMapInfo const& shadowMapInfo) const noexcept {
|
||||
const auto [l, b, w, h] = getViewport();
|
||||
const float texel = 1.0f / float(shadowMapInfo.atlasDimension);
|
||||
const float4 v = float4{ l, b, l + w, b + h } * texel;
|
||||
if (shadowMapInfo.textureSpaceFlipped) {
|
||||
return { v.x, 1.0f - v.w, v.z, 1.0f - v.y };
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void ShadowMap::prepareCamera(Transaction const& transaction,
|
||||
@@ -1244,7 +1272,7 @@ void ShadowMap::prepareCamera(Transaction const& transaction,
|
||||
}
|
||||
|
||||
void ShadowMap::prepareViewport(Transaction const& transaction,
|
||||
backend::Viewport const& viewport) noexcept {
|
||||
const filament::Viewport& viewport) noexcept {
|
||||
PerShadowMapUniforms::prepareViewport(transaction, viewport, 0, 0);
|
||||
}
|
||||
|
||||
@@ -1253,6 +1281,13 @@ void ShadowMap::prepareTime(Transaction const& transaction,
|
||||
PerShadowMapUniforms::prepareTime(transaction, engine, userTime);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareDirectionalLight(Transaction const& transaction,
|
||||
FEngine& engine, math::float3 const& sceneSpaceDirection,
|
||||
LightManager::Instance instance) noexcept {
|
||||
PerShadowMapUniforms::prepareDirectionalLight(transaction,
|
||||
engine, 1.0f, sceneSpaceDirection, instance);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareShadowMapping(Transaction const& transaction,
|
||||
bool highPrecision) noexcept {
|
||||
PerShadowMapUniforms::prepareShadowMapping(transaction, highPrecision);
|
||||
@@ -1267,7 +1302,7 @@ void ShadowMap::commit(Transaction& transaction,
|
||||
mPerShadowMapUniforms.commit(transaction, driver);
|
||||
}
|
||||
|
||||
void ShadowMap::bind(backend::DriverApi& driver) const noexcept {
|
||||
void ShadowMap::bindPerViewUniformsAndSamplers(backend::DriverApi& driver) const noexcept {
|
||||
mPerShadowMapUniforms.bind(driver);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "details/Camera.h"
|
||||
#include "details/Scene.h"
|
||||
|
||||
#include <backend/DriverApiForward.h>
|
||||
#include "private/backend/DriverApi.h"
|
||||
|
||||
#include <filament/Viewport.h>
|
||||
|
||||
@@ -130,7 +130,6 @@ public:
|
||||
struct ShaderParameters {
|
||||
math::mat4f lightSpace{};
|
||||
math::float4 lightFromWorldZ{};
|
||||
math::float4 scissorNormalized{};
|
||||
float texelSizeAtOneMeterWs{};
|
||||
};
|
||||
|
||||
@@ -175,14 +174,13 @@ public:
|
||||
static void updateSceneInfoSpot(const math::mat4f& Mv, FScene const& scene,
|
||||
SceneInfo& sceneInfo);
|
||||
|
||||
filament::Viewport getViewport() const noexcept;
|
||||
|
||||
LightManager::ShadowOptions const* getShadowOptions() const noexcept { return mOptions; }
|
||||
size_t getLightIndex() const { return mLightIndex; }
|
||||
uint16_t getShadowIndex() const { return mShadowIndex; }
|
||||
void setLayer(uint8_t layer) noexcept { mLayer = layer; }
|
||||
uint8_t getLayer() const noexcept { return mLayer; }
|
||||
backend::Viewport getViewport() const noexcept;
|
||||
backend::Viewport getScissor() const noexcept;
|
||||
|
||||
bool isDirectionalShadow() const noexcept { return mShadowType == ShadowType::DIRECTIONAL; }
|
||||
bool isSpotShadow() const noexcept { return mShadowType == ShadowType::SPOT; }
|
||||
bool isPointShadow() const noexcept { return mShadowType == ShadowType::POINT; }
|
||||
@@ -194,15 +192,18 @@ public:
|
||||
static void prepareCamera(Transaction const& transaction,
|
||||
FEngine& engine, const CameraInfo& cameraInfo) noexcept;
|
||||
static void prepareViewport(Transaction const& transaction,
|
||||
backend::Viewport const& viewport) noexcept;
|
||||
const filament::Viewport& viewport) noexcept;
|
||||
static void prepareTime(Transaction const& transaction,
|
||||
FEngine& engine, math::float4 const& userTime) noexcept;
|
||||
static void prepareDirectionalLight(Transaction const& transaction,
|
||||
FEngine& engine, math::float3 const& sceneSpaceDirection,
|
||||
LightManager::Instance instance) noexcept;
|
||||
static void prepareShadowMapping(Transaction const& transaction,
|
||||
bool highPrecision) noexcept;
|
||||
static PerShadowMapUniforms::Transaction open(backend::DriverApi& driver) noexcept;
|
||||
void commit(Transaction& transaction,
|
||||
backend::DriverApi& driver) const noexcept;
|
||||
void bind(backend::DriverApi& driver) const noexcept;
|
||||
void bindPerViewUniformsAndSamplers(backend::DriverApi& driver) const noexcept;
|
||||
|
||||
private:
|
||||
struct Segment {
|
||||
@@ -216,11 +217,6 @@ private:
|
||||
// 8 corners, 12 segments w/ 2 intersection max -- all of this twice (8 + 12 * 2) * 2 (768 bytes)
|
||||
using FrustumBoxIntersection = std::array<math::float3, 64>;
|
||||
|
||||
ShaderParameters updatePunctual(
|
||||
math::mat4f const& Mv, float outerConeAngle, float nearPlane, float farPlane,
|
||||
const ShadowMapInfo& shadowMapInfo,
|
||||
const FLightManager::ShadowParams& params) noexcept;
|
||||
|
||||
static math::mat4f applyLISPSM(math::mat4f& Wp,
|
||||
filament::CameraInfo const& camera, FLightManager::ShadowParams const& params,
|
||||
const math::mat4f& LMpMv,
|
||||
@@ -280,18 +276,11 @@ private:
|
||||
|
||||
static math::mat4f directionalLightFrustum(float n, float f) noexcept;
|
||||
|
||||
struct TextureCoordsMapping {
|
||||
math::mat4f clipToTexture;
|
||||
math::mat4f clipToNdc;
|
||||
};
|
||||
static TextureCoordsMapping getTextureCoordsMapping(ShadowMapInfo const& info,
|
||||
backend::Viewport const& viewport) noexcept;
|
||||
static math::mat4 getTextureCoordsMapping(ShadowMapInfo const& info) noexcept;
|
||||
|
||||
static math::mat4f computeVsmLightSpaceMatrix(const math::mat4f& lightSpacePcf,
|
||||
const math::mat4f& Mv, float znear, float zfar) noexcept;
|
||||
|
||||
math::float4 getViewportNormalized(ShadowMapInfo const& shadowMapInfo) const noexcept;
|
||||
|
||||
float texelSizeWorldSpace(const math::mat3f& worldToShadowTexture,
|
||||
uint16_t shadowDimension) const noexcept;
|
||||
|
||||
|
||||
@@ -97,10 +97,8 @@ void ShadowMapManager::setDirectionalShadowMap(size_t lightIndex,
|
||||
LightManager::ShadowOptions const* options) noexcept {
|
||||
assert_invariant(options->shadowCascades <= CONFIG_MAX_SHADOW_CASCADES);
|
||||
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);
|
||||
auto* pShadowMap = getCascadeShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, c, 0, options);
|
||||
mCascadeShadowMaps.push_back(pShadowMap);
|
||||
}
|
||||
}
|
||||
@@ -109,19 +107,17 @@ void ShadowMapManager::addShadowMap(size_t lightIndex, bool spotlight,
|
||||
LightManager::ShadowOptions const* options) noexcept {
|
||||
if (spotlight) {
|
||||
const size_t c = mSpotShadowMaps.size();
|
||||
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);
|
||||
assert_invariant(c < CONFIG_MAX_SHADOWMAP_PUNCTUAL);
|
||||
auto* pShadowMap = getPointOrSpotShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::SPOT, c, 0, options);
|
||||
mSpotShadowMaps.push_back(pShadowMap);
|
||||
} else {
|
||||
// point-light, generate 6 independent shadowmaps
|
||||
// point-light
|
||||
for (size_t face = 0; face < 6; face++) {
|
||||
const size_t c = mSpotShadowMaps.size();
|
||||
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);
|
||||
assert_invariant(c < CONFIG_MAX_SHADOWMAP_PUNCTUAL);
|
||||
auto* pShadowMap = getPointOrSpotShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::POINT, c, face, options);
|
||||
mSpotShadowMaps.push_back(pShadowMap);
|
||||
}
|
||||
}
|
||||
@@ -159,11 +155,9 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
utils::FixedCapacityVector<ShadowPass> passList;
|
||||
};
|
||||
|
||||
VsmShadowOptions const& vsmShadowOptions = view.getVsmShadowOptions();
|
||||
|
||||
auto& prepareShadowPass = fg.addPass<PrepareShadowPassData>("Prepare Shadow Pass",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
data.passList.reserve(CONFIG_MAX_SHADOWMAPS);
|
||||
data.passList.reserve(CONFIG_MAX_SHADOW_LAYERS);
|
||||
data.shadows = builder.createTexture("Shadowmap", {
|
||||
.width = textureRequirements.size, .height = textureRequirements.size,
|
||||
.depth = textureRequirements.layers,
|
||||
@@ -205,8 +199,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
// "read" from one of its resource (only writes), so the FrameGraph culls it.
|
||||
builder.sideEffect();
|
||||
},
|
||||
[this, &engine, &view, vsmShadowOptions,
|
||||
scene, mainCameraInfo, userTime, passTemplate = pass](
|
||||
[this, &engine, &view, scene, mainCameraInfo, userTime, passTemplate = pass](
|
||||
FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
|
||||
// Note: we could almost parallel_for the loop below, the problem currently is
|
||||
@@ -236,15 +229,15 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
}
|
||||
|
||||
if (shadowMap.hasVisibleShadows()) {
|
||||
// Note: this loop can generate a lot of commands that come out of the
|
||||
// "per frame command arena". The allocation persists until the
|
||||
// end of the frame.
|
||||
// One way to possibly mitigate this, would be to always use the
|
||||
// same command buffer for all shadow map, but then we'd generate
|
||||
// a lot of unneeded draw calls.
|
||||
// To do this efficiently, we'd need a way to cull draw calls already
|
||||
// recorded in the command buffer, per shadow map.
|
||||
// TODO: this loop can generate a lot of commands. investigate if
|
||||
// we could compact or reduce the number of commands.
|
||||
// - we could move this into the execute of each pass, but
|
||||
// then we would have to update the UBO each time.
|
||||
// - we could also always use the same commands for all
|
||||
// shadow maps, but then we'd generate a lot of
|
||||
// unneeded draw call.
|
||||
|
||||
// generate and sort the commands for rendering the shadow map
|
||||
|
||||
// cameraInfo only valid after calling update
|
||||
const CameraInfo cameraInfo{ shadowMap.getCamera() };
|
||||
@@ -254,14 +247,18 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
ShadowMap::prepareViewport(transaction, shadowMap.getViewport());
|
||||
ShadowMap::prepareTime(transaction, engine, userTime);
|
||||
ShadowMap::prepareShadowMapping(transaction,
|
||||
vsmShadowOptions.highPrecision);
|
||||
view.getVsmShadowOptions().highPrecision);
|
||||
if (shadowMap.getShadowType() == ShadowType::DIRECTIONAL) {
|
||||
ShadowMap::prepareDirectionalLight(transaction, engine,
|
||||
scene->getLightData().elementAt<FScene::DIRECTION>(0),
|
||||
scene->getLightData().elementAt<FScene::LIGHT_INSTANCE>(0));
|
||||
}
|
||||
shadowMap.commit(transaction, driver);
|
||||
|
||||
// updatePrimitivesLod must be run before RenderPass::appendCommands.
|
||||
view.updatePrimitivesLod(engine,
|
||||
cameraInfo, scene->getRenderableData(), entry.range);
|
||||
|
||||
// generate and sort the commands for rendering the shadow map
|
||||
RenderPass pass(passTemplate);
|
||||
pass.setCamera(cameraInfo);
|
||||
pass.setVisibilityMask(entry.visibilityMask);
|
||||
@@ -273,13 +270,22 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
entry.executor = pass.getExecutor();
|
||||
|
||||
if (!view.hasVSM()) {
|
||||
auto const* options = shadowMap.getShadowOptions();
|
||||
auto li = scene->getLightData().elementAt<FScene::LIGHT_INSTANCE>(
|
||||
entry.shadowMap->getLightIndex());
|
||||
|
||||
auto const& params = engine.getLightManager().getShadowParams(li);
|
||||
|
||||
const PolygonOffset polygonOffset = { // handle reversed Z
|
||||
.slope = -options->polygonOffsetSlope,
|
||||
.constant = -options->polygonOffsetConstant
|
||||
.slope = -params.options.polygonOffsetSlope,
|
||||
.constant = -params.options.polygonOffsetConstant
|
||||
};
|
||||
entry.executor.overridePolygonOffset(&polygonOffset);
|
||||
}
|
||||
|
||||
constexpr const backend::Viewport disabledScissor{ 0, 0,
|
||||
(uint32_t)std::numeric_limits<int32_t>::max(),
|
||||
(uint32_t)std::numeric_limits<int32_t>::max() };
|
||||
entry.executor.overrideScissor(&disabledScissor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +314,6 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
|
||||
const uint8_t layer = entry.shadowMap->getLayer();
|
||||
const auto* options = entry.shadowMap->getShadowOptions();
|
||||
const auto msaaSamples = textureRequirements.msaaSamples;
|
||||
|
||||
auto& shadowPass = fg.addPass<ShadowPassData>("Shadow Pass",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
@@ -327,7 +332,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
// We specify the sample count here because we don't need automatic resolve.
|
||||
auto depth = builder.createTexture("Temporary VSM Depth Texture", {
|
||||
.width = textureRequirements.size, .height = textureRequirements.size,
|
||||
.samples = msaaSamples,
|
||||
.samples = options->vsm.msaaSamples,
|
||||
.format = TextureFormat::DEPTH16,
|
||||
});
|
||||
|
||||
@@ -350,7 +355,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH;
|
||||
// we need to clear the shadow map with the max EVSM moments
|
||||
renderTargetDesc.clearColor = vsmClearColor;
|
||||
renderTargetDesc.samples = msaaSamples;
|
||||
renderTargetDesc.samples = options->vsm.msaaSamples;
|
||||
|
||||
if (blur) {
|
||||
data.tempBlurSrc = builder.write(data.tempBlurSrc,
|
||||
@@ -361,7 +366,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
.color = { data.tempBlurSrc },
|
||||
.depth = depth },
|
||||
.clearColor = vsmClearColor,
|
||||
.samples = msaaSamples,
|
||||
.samples = options->vsm.msaaSamples,
|
||||
.clearFlags = TargetBufferFlags::COLOR
|
||||
| TargetBufferFlags::DEPTH
|
||||
});
|
||||
@@ -388,15 +393,16 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
// `entry` lives in `PrepareShadowPassData` which is guaranteed to still
|
||||
// be alive when we execute here (all passes stay alive until the FrameGraph
|
||||
// is destroyed).
|
||||
// It wouldn't work to capture by copy because entry.executor wouldn't be
|
||||
// It wouldn't work to capture by copy because entry.pass wouldn't be
|
||||
// initialized, as this happens in an `execute` block.
|
||||
|
||||
entry.shadowMap->bindPerViewUniformsAndSamplers(driver);
|
||||
|
||||
auto rt = resources.getRenderPassInfo(data.rt);
|
||||
rt.params.viewport = entry.shadowMap->getViewport();
|
||||
|
||||
engine.flush();
|
||||
driver.beginRenderPass(rt.target, rt.params);
|
||||
entry.shadowMap->bind(driver);
|
||||
entry.executor.overrideScissor(entry.shadowMap->getScissor());
|
||||
entry.executor.execute(engine, "Shadow Pass");
|
||||
driver.endRenderPass();
|
||||
});
|
||||
@@ -458,7 +464,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
// entire camera frustum, as if we only had a single cascade.
|
||||
ShadowMap& shadowMap = *mCascadeShadowMaps[0];
|
||||
|
||||
shadowMap.updateDirectional(mEngine,
|
||||
auto shaderParameters = shadowMap.updateDirectional(mEngine,
|
||||
lightData, 0, cameraInfo, shadowMapInfo, *scene, sceneInfo);
|
||||
|
||||
hasVisibleShadows = shadowMap.hasVisibleShadows();
|
||||
@@ -467,6 +473,18 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
Frustum const& frustum = shadowMap.getCamera().getCullingFrustum();
|
||||
FView::cullRenderables(engine.getJobSystem(), renderableData, frustum,
|
||||
VISIBLE_DIR_SHADOW_RENDERABLE_BIT);
|
||||
|
||||
// Set shadowBias, using the first directional cascade.
|
||||
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
|
||||
// note: normalBias is set to zero for VSM
|
||||
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * lcm.getShadowNormalBias(0);
|
||||
// Texel size is constant for directional light (although that's not true when LISPSM
|
||||
// is used, but in that case we're pretending it is).
|
||||
const float wsTexelSize = shaderParameters.texelSizeAtOneMeterWs;
|
||||
mShadowMappingUniforms.shadowBias = normalBias * wsTexelSize;
|
||||
mShadowMappingUniforms.shadowBulbRadiusLs =
|
||||
mSoftShadowOptions.penumbraScale * options.shadowBulbRadius / wsTexelSize;
|
||||
mShadowMappingUniforms.elvsm = options.vsm.elvsm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,10 +537,6 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
|
||||
mShadowMappingUniforms.cascadeSplits = wsSplitPositionUniform;
|
||||
|
||||
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
|
||||
// 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]);
|
||||
|
||||
@@ -536,23 +550,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
lightData, 0, cameraInfo, shadowMapInfo, *scene, sceneInfo);
|
||||
|
||||
if (shadowMap.hasVisibleShadows()) {
|
||||
const size_t shadowIndex = shadowMap.getShadowIndex();
|
||||
assert_invariant(shadowIndex == i);
|
||||
|
||||
// Texel size is constant for directional light (although that's not true when LISPSM
|
||||
// is used, but in that case we're pretending it is).
|
||||
const float wsTexelSize = shaderParameters.texelSizeAtOneMeterWs;
|
||||
|
||||
auto& s = mShadowUb.edit();
|
||||
s.shadows[shadowIndex].layer = shadowMap.getLayer();
|
||||
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
|
||||
s.shadows[shadowIndex].scissorNormalized = shaderParameters.scissorNormalized;
|
||||
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSize;
|
||||
s.shadows[shadowIndex].texelSizeAtOneMeter = wsTexelSize;
|
||||
s.shadows[shadowIndex].elvsm = options.vsm.elvsm;
|
||||
s.shadows[shadowIndex].bulbRadiusLs =
|
||||
mSoftShadowOptions.penumbraScale * options.shadowBulbRadius / wsTexelSize;
|
||||
|
||||
mShadowMappingUniforms.lightFromWorldMatrix[i] = shaderParameters.lightSpace;
|
||||
shadowTechnique |= ShadowTechnique::SHADOW_MAP;
|
||||
cascadeHasVisibleShadows |= 0x1u << i;
|
||||
}
|
||||
@@ -632,7 +630,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
|
||||
// compute shadow map frustum for culling
|
||||
const mat4f Mv = ShadowMap::getDirectionalLightViewMatrix(direction, position);
|
||||
const mat4f Mp = mat4f::perspective(outerConeAngle * f::RAD_TO_DEG * 2.0f, 1.0f, 0.01f, radius);
|
||||
const mat4f MpMv = math::highPrecisionMultiply(Mp, Mv);
|
||||
const mat4f MpMv(math::highPrecisionMultiply(Mp, Mv));
|
||||
const Frustum frustum(MpMv);
|
||||
|
||||
// Cull shadow casters
|
||||
@@ -680,9 +678,8 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
|
||||
auto& s = mShadowUb.edit();
|
||||
const double n = shadowMap.getCamera().getNear();
|
||||
const double f = shadowMap.getCamera().getCullingFar();
|
||||
s.shadows[shadowIndex].layer = shadowMap.getLayer();
|
||||
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
|
||||
s.shadows[shadowIndex].scissorNormalized = shaderParameters.scissorNormalized;
|
||||
s.shadows[shadowIndex].direction = direction;
|
||||
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter;
|
||||
s.shadows[shadowIndex].lightFromWorldZ = shaderParameters.lightFromWorldZ;
|
||||
s.shadows[shadowIndex].texelSizeAtOneMeter = wsTexelSizeAtOneMeter;
|
||||
@@ -690,8 +687,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
|
||||
s.shadows[shadowIndex].elvsm = options->vsm.elvsm;
|
||||
s.shadows[shadowIndex].bulbRadiusLs =
|
||||
mSoftShadowOptions.penumbraScale * options->shadowBulbRadius
|
||||
/ wsTexelSizeAtOneMeter;
|
||||
|
||||
/ wsTexelSizeAtOneMeter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,6 +749,7 @@ void ShadowMapManager::preparePointShadowMap(ShadowMap& shadowMap,
|
||||
|
||||
|
||||
// and if we need to generate it, update all the UBO data
|
||||
// Note: this below is done for all six faces even if it sets identical values each time
|
||||
if (shadowMap.hasVisibleShadows()) {
|
||||
const size_t shadowIndex = shadowMap.getShadowIndex();
|
||||
const float wsTexelSizeAtOneMeter = shaderParameters.texelSizeAtOneMeterWs;
|
||||
@@ -762,11 +759,16 @@ void ShadowMapManager::preparePointShadowMap(ShadowMap& shadowMap,
|
||||
auto& s = mShadowUb.edit();
|
||||
const double n = shadowMap.getCamera().getNear();
|
||||
const double f = shadowMap.getCamera().getCullingFar();
|
||||
s.shadows[shadowIndex].layer = shadowMap.getLayer();
|
||||
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
|
||||
s.shadows[shadowIndex].scissorNormalized = shaderParameters.scissorNormalized;
|
||||
|
||||
s.shadows[shadowIndex].lightFromWorldMatrix = {}; // no texture matrix for point lights
|
||||
s.shadows[shadowIndex].direction = {}; // no direction of point lights
|
||||
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter;
|
||||
s.shadows[shadowIndex].lightFromWorldZ = shaderParameters.lightFromWorldZ;
|
||||
s.shadows[shadowIndex].lightFromWorldZ = {
|
||||
-((n + f) / (f - n)) * 0.5f + 0.5f,
|
||||
(f * n) / (f - n),
|
||||
-n / (f - n),
|
||||
1.0f / (f - n),
|
||||
};
|
||||
s.shadows[shadowIndex].texelSizeAtOneMeter = wsTexelSizeAtOneMeter;
|
||||
s.shadows[shadowIndex].nearOverFarMinusNear = float(n / (f - n));
|
||||
s.shadows[shadowIndex].elvsm = options->vsm.elvsm;
|
||||
@@ -786,12 +788,14 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine
|
||||
shadowTechnique |= ShadowTechnique::SHADOW_MAP;
|
||||
for (auto const* pShadowMap : mSpotShadowMaps) {
|
||||
const size_t lightIndex = pShadowMap->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).
|
||||
|
||||
// FIXME: currently we have one slot per shadowmap in the UBO, but we now have up to
|
||||
// 6 shadowmap per light. So for now, we only write the data of the face 0,
|
||||
// and the shader will figure out where to find the other face (layer+face)
|
||||
if (pShadowMap->getFace() == 0) {
|
||||
shadowInfo[lightIndex].castsShadows = true; // FIXME: is that set correctly?
|
||||
shadowInfo[lightIndex].index = pShadowMap->getShadowIndex();
|
||||
shadowInfo[lightIndex].layer = pShadowMap->getLayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -842,8 +846,6 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view
|
||||
const bool useMipmapping = view.hasVSM() &&
|
||||
((vsmShadowOptions.anisotropy > 0) || vsmShadowOptions.mipmapping);
|
||||
|
||||
const uint8_t msaaSamples = vsmShadowOptions.msaaSamples;
|
||||
|
||||
TextureFormat format = TextureFormat::DEPTH16;
|
||||
if (view.hasVSM()) {
|
||||
if (vsmShadowOptions.highPrecision) {
|
||||
@@ -875,7 +877,6 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view
|
||||
(uint16_t)maxDimension,
|
||||
layersNeeded,
|
||||
mipLevels,
|
||||
msaaSamples,
|
||||
format
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,10 +45,14 @@ class FrameGraph;
|
||||
class RenderPass;
|
||||
|
||||
struct ShadowMappingUniforms {
|
||||
std::array<math::mat4f, CONFIG_MAX_SHADOW_CASCADES> lightFromWorldMatrix;
|
||||
math::float4 cascadeSplits;
|
||||
float shadowBulbRadiusLs;
|
||||
float shadowBias;
|
||||
float ssContactShadowDistance;
|
||||
uint32_t directionalShadows;
|
||||
uint32_t cascades;
|
||||
bool elvsm;
|
||||
};
|
||||
|
||||
class ShadowMapManager {
|
||||
@@ -89,13 +93,23 @@ 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* getCascadeShadowMap(size_t cascade) noexcept {
|
||||
assert_invariant(cascade < CONFIG_MAX_SHADOW_CASCADES);
|
||||
return std::launder(reinterpret_cast<ShadowMap*>(&mShadowMapCache[cascade]));
|
||||
}
|
||||
|
||||
ShadowMap const* getShadowMap(size_t index) const noexcept {
|
||||
return const_cast<ShadowMapManager*>(this)->getShadowMap(index);
|
||||
ShadowMap const* getCascadeShadowMap(size_t cascade) const noexcept {
|
||||
return const_cast<ShadowMapManager*>(this)->getCascadeShadowMap(cascade);
|
||||
}
|
||||
|
||||
ShadowMap* getPointOrSpotShadowMap(size_t index) noexcept {
|
||||
assert_invariant(index < CONFIG_MAX_SHADOWMAP_PUNCTUAL);
|
||||
return std::launder(reinterpret_cast<ShadowMap*>(
|
||||
&mShadowMapCache[CONFIG_MAX_SHADOW_CASCADES + index]));
|
||||
}
|
||||
|
||||
ShadowMap const* getPointOrSpotShadowMap(size_t spot) const noexcept {
|
||||
return const_cast<ShadowMapManager*>(this)->getPointOrSpotShadowMap(spot);
|
||||
}
|
||||
|
||||
// valid after calling update() above
|
||||
@@ -180,7 +194,6 @@ private:
|
||||
uint16_t size = 0;
|
||||
uint8_t layers = 0;
|
||||
uint8_t levels = 0;
|
||||
uint8_t msaaSamples = 1;
|
||||
backend::TextureFormat format = backend::TextureFormat::DEPTH16;
|
||||
} mTextureAtlasRequirements;
|
||||
|
||||
@@ -202,13 +215,13 @@ private:
|
||||
|
||||
utils::FixedCapacityVector<ShadowMap*> mSpotShadowMaps{
|
||||
utils::FixedCapacityVector<ShadowMap*>::with_capacity(
|
||||
CONFIG_MAX_SHADOWMAPS - CONFIG_MAX_SHADOW_CASCADES) };
|
||||
CONFIG_MAX_SHADOWMAP_PUNCTUAL) };
|
||||
|
||||
// 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;
|
||||
std::array<ShadowMapStorage, CONFIG_MAX_SHADOW_LAYERS> mShadowMapCache;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -240,6 +240,7 @@ void FLightManager::setShadowOptions(Instance i, ShadowOptions const& options) n
|
||||
params.options.shadowFar = std::max(options.shadowFar, 0.0f);
|
||||
params.options.shadowNearHint = std::max(options.shadowNearHint, 0.0f);
|
||||
params.options.shadowFarHint = std::max(options.shadowFarHint, 0.0f);
|
||||
params.options.vsm.msaaSamples = std::max(uint8_t(0), options.vsm.msaaSamples);
|
||||
params.options.vsm.blurWidth = std::max(0.0f, options.vsm.blurWidth);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace filament {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
FScene::FScene(FEngine& engine) :
|
||||
mEngine(engine), mSharedState(std::make_shared<SharedState>()) {
|
||||
mEngine(engine) {
|
||||
}
|
||||
|
||||
FScene::~FScene() noexcept = default;
|
||||
@@ -268,8 +268,7 @@ void FScene::updateUBOs(
|
||||
PerRenderableData* buffer = [&]{
|
||||
if (count >= MAX_STREAM_ALLOCATION_COUNT) {
|
||||
// use the heap allocator
|
||||
auto& bufferPoolAllocator = mSharedState->mBufferPoolAllocator;
|
||||
return (PerRenderableData*)bufferPoolAllocator.get(count * sizeof(PerRenderableData));
|
||||
return (PerRenderableData*)mBufferPoolAllocator.get(count * sizeof(PerRenderableData));
|
||||
} else {
|
||||
// allocate space into the command stream directly
|
||||
return driver.allocatePod<PerRenderableData>(count);
|
||||
@@ -282,24 +281,16 @@ void FScene::updateUBOs(
|
||||
buffer[i] = uboData[i];
|
||||
}
|
||||
|
||||
// We capture state shared between Scene and the update buffer callback, because the Scene could
|
||||
// be destroyed before the callback executes.
|
||||
std::weak_ptr<SharedState>* const weakShared = new std::weak_ptr<SharedState>(mSharedState);
|
||||
|
||||
// update the UBO
|
||||
driver.resetBufferObject(renderableUbh);
|
||||
driver.updateBufferObjectUnsynchronized(renderableUbh, {
|
||||
buffer, count * sizeof(PerRenderableData),
|
||||
+[](void* p, size_t s, void* user) {
|
||||
std::weak_ptr<SharedState>* const weakShared =
|
||||
static_cast<std::weak_ptr<SharedState>*>(user);
|
||||
if (s >= MAX_STREAM_ALLOCATION_COUNT * sizeof(PerRenderableData)) {
|
||||
if (auto state = weakShared->lock()) {
|
||||
state->mBufferPoolAllocator.put(p);
|
||||
}
|
||||
FScene* const that = static_cast<FScene*>(user);
|
||||
that->mBufferPoolAllocator.put(p);
|
||||
}
|
||||
delete weakShared;
|
||||
}, weakShared
|
||||
}, this
|
||||
}, 0);
|
||||
|
||||
// update skybox
|
||||
@@ -352,10 +343,9 @@ void FScene::prepareDynamicLights(const CameraInfo& camera, ArenaScope& rootAren
|
||||
lp[gpuIndex].typeShadow = LightsUib::packTypeShadow(
|
||||
lcm.isPointLight(li) ? 0u : 1u,
|
||||
shadowInfo[i].contactShadows,
|
||||
shadowInfo[i].index);
|
||||
lp[gpuIndex].channels = LightsUib::packChannels(
|
||||
lcm.getLightChannels(li),
|
||||
shadowInfo[i].castsShadows);
|
||||
shadowInfo[i].index,
|
||||
shadowInfo[i].layer);
|
||||
lp[gpuIndex].channels = LightsUib::packChannels(lcm.getLightChannels(li), shadowInfo[i].castsShadows);
|
||||
}
|
||||
|
||||
driver.updateBufferObject(lightUbh, { lp, positionalLightCount * sizeof(LightsUib) }, 0);
|
||||
|
||||
@@ -42,8 +42,6 @@
|
||||
|
||||
#include <tsl/robin_set.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace filament {
|
||||
|
||||
struct CameraInfo;
|
||||
@@ -157,6 +155,7 @@ public:
|
||||
bool castsShadows = false; // whether this light casts shadows
|
||||
bool contactShadows = false; // whether this light casts contact shadows
|
||||
uint8_t index = 0; // an index into the arrays in the Shadows uniform buffer
|
||||
uint8_t layer = 0; // which layer of the shadow texture array to sample from
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -180,8 +179,7 @@ public:
|
||||
LightSoa const& getLightData() const noexcept { return mLightData; }
|
||||
LightSoa& getLightData() noexcept { return mLightData; }
|
||||
|
||||
void updateUBOs(utils::Range<uint32_t> visibleRenderables,
|
||||
backend::Handle<backend::HwBufferObject> renderableUbh) noexcept;
|
||||
void updateUBOs(utils::Range<uint32_t> visibleRenderables, backend::Handle<backend::HwBufferObject> renderableUbh) noexcept;
|
||||
|
||||
bool hasContactShadows() const noexcept;
|
||||
|
||||
@@ -223,12 +221,7 @@ private:
|
||||
LightSoa mLightData;
|
||||
backend::Handle<backend::HwBufferObject> mRenderableViewUbh; // This is actually owned by the view.
|
||||
bool mHasContactShadows = false;
|
||||
|
||||
// State shared between Scene and driver callbacks.
|
||||
struct SharedState {
|
||||
BufferPoolAllocator<3> mBufferPoolAllocator = {};
|
||||
};
|
||||
std::shared_ptr<SharedState> mSharedState;
|
||||
BufferPoolAllocator<3> mBufferPoolAllocator;
|
||||
};
|
||||
|
||||
FILAMENT_DOWNCAST(Scene)
|
||||
|
||||
@@ -294,11 +294,10 @@ void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
|
||||
}
|
||||
|
||||
// Find all shadow-casting spotlights.
|
||||
size_t shadowMapCount = CONFIG_MAX_SHADOW_CASCADES;
|
||||
size_t shadowLayerCount = 0;
|
||||
|
||||
// We allow a max of CONFIG_MAX_SHADOWMAPS point/spotlight shadows. Any additional
|
||||
// We allow a max of CONFIG_MAX_SHADOW_CASTING_SPOTS spotlight shadows. Any additional
|
||||
// shadow-casting spotlights are ignored.
|
||||
// Note that pointlight shadows cost 6 shadowmaps, reducing the total count.
|
||||
for (size_t l = FScene::DIRECTIONAL_LIGHTS_COUNT; l < lightData.size(); l++) {
|
||||
|
||||
// when we get here all the lights should be visible
|
||||
@@ -314,16 +313,16 @@ void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
|
||||
continue; // doesn't cast shadows
|
||||
}
|
||||
|
||||
const bool spotLight = lcm.isSpotLight(li);
|
||||
const auto& shadowOptions = lcm.getShadowOptions(li);
|
||||
mShadowMapManager.addShadowMap(l, lcm.isSpotLight(li), &shadowOptions);
|
||||
|
||||
const size_t shadowMapCountNeeded = spotLight ? 1 : 6;
|
||||
if (shadowMapCount + shadowMapCountNeeded <= CONFIG_MAX_SHADOWMAPS) {
|
||||
shadowMapCount += shadowMapCountNeeded;
|
||||
const auto& shadowOptions = lcm.getShadowOptions(li);
|
||||
mShadowMapManager.addShadowMap(l, spotLight, &shadowOptions);
|
||||
if (lcm.isSpotLight(li)) {
|
||||
shadowLayerCount += 6;
|
||||
} else {
|
||||
shadowLayerCount += 1;
|
||||
}
|
||||
|
||||
if (shadowMapCount >= CONFIG_MAX_SHADOWMAPS) {
|
||||
if (shadowLayerCount > CONFIG_MAX_SHADOWMAP_PUNCTUAL - 1) {
|
||||
break; // we ran out of spotlight shadow casting
|
||||
}
|
||||
}
|
||||
@@ -694,6 +693,13 @@ void FView::prepareSSR(Handle<HwTexture> ssr, float refractionLodOffset,
|
||||
mPerViewUniforms.prepareSSR(ssr, refractionLodOffset, ssrOptions);
|
||||
}
|
||||
|
||||
void FView::prepareHistorySSR(Handle<HwTexture> ssr,
|
||||
mat4f const& historyProjection, mat4f const& uvFromViewMatrix,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept {
|
||||
mPerViewUniforms.prepareHistorySSR(ssr,
|
||||
historyProjection, uvFromViewMatrix, ssrOptions);
|
||||
}
|
||||
|
||||
void FView::prepareStructure(Handle<HwTexture> structure) const noexcept {
|
||||
// sampler must be NEAREST
|
||||
mPerViewUniforms.prepareStructure(structure);
|
||||
@@ -994,10 +1000,6 @@ void FView::setAmbientOcclusionOptions(AmbientOcclusionOptions options) noexcept
|
||||
options.ssct.rayCount = math::clamp((unsigned)options.ssct.rayCount, 1u, 255u);
|
||||
mAmbientOcclusionOptions = options;
|
||||
}
|
||||
void FView::setVsmShadowOptions(VsmShadowOptions options) noexcept {
|
||||
options.msaaSamples = std::max(uint8_t(0), options.msaaSamples);
|
||||
mVsmShadowOptions = options;
|
||||
}
|
||||
|
||||
void FView::setSoftShadowOptions(SoftShadowOptions options) noexcept {
|
||||
options.penumbraScale = std::max(0.0f, options.penumbraScale);
|
||||
|
||||
@@ -145,6 +145,9 @@ public:
|
||||
void prepareSSAO(backend::Handle<backend::HwTexture> ssao) const noexcept;
|
||||
void prepareSSR(backend::Handle<backend::HwTexture> ssr, float refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
|
||||
void prepareHistorySSR(backend::Handle<backend::HwTexture> ssr,
|
||||
math::mat4f const& historyProjection, math::mat4f const& uvFromViewMatrix,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
|
||||
void prepareStructure(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadow(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadowMapping(bool highPrecision) const noexcept;
|
||||
@@ -187,7 +190,7 @@ public:
|
||||
bool isStencilBufferEnabled() const noexcept { return mStencilBufferEnabled; }
|
||||
|
||||
FCamera const* getDirectionalLightCamera() const noexcept {
|
||||
return &mShadowMapManager.getShadowMap(0)->getDebugCamera();
|
||||
return &mShadowMapManager.getCascadeShadowMap(0)->getDebugCamera();
|
||||
}
|
||||
|
||||
void setRenderTarget(FRenderTarget* renderTarget) noexcept {
|
||||
@@ -305,7 +308,9 @@ public:
|
||||
mShadowType = shadow;
|
||||
}
|
||||
|
||||
void setVsmShadowOptions(VsmShadowOptions options) noexcept;
|
||||
void setVsmShadowOptions(VsmShadowOptions const& options) noexcept {
|
||||
mVsmShadowOptions = options;
|
||||
}
|
||||
|
||||
VsmShadowOptions getVsmShadowOptions() const noexcept {
|
||||
return mVsmShadowOptions;
|
||||
|
||||
@@ -22,7 +22,7 @@ using namespace filament;
|
||||
|
||||
TEST(AtlasAllocator, AllocateFirstLevel) {
|
||||
|
||||
AtlasAllocator allocator(1024);
|
||||
AtlasAllocator allocator;
|
||||
|
||||
auto a = allocator.allocateInLayer(0);
|
||||
EXPECT_TRUE(a.l == 0 && a.code == 0);
|
||||
@@ -39,7 +39,7 @@ TEST(AtlasAllocator, AllocateFirstLevel) {
|
||||
|
||||
TEST(AtlasAllocator, AllocateSecondLevel) {
|
||||
|
||||
AtlasAllocator allocator(1024);
|
||||
AtlasAllocator allocator;
|
||||
|
||||
auto d0 = allocator.allocateInLayer(1);
|
||||
EXPECT_TRUE(d0.l == 1 && d0.code == 0);
|
||||
@@ -55,7 +55,7 @@ TEST(AtlasAllocator, AllocateSecondLevel) {
|
||||
}
|
||||
|
||||
TEST(AtlasAllocator, AllocateMixed0) {
|
||||
AtlasAllocator allocator(1024);
|
||||
AtlasAllocator allocator;
|
||||
|
||||
auto e0 = allocator.allocateInLayer(1);
|
||||
EXPECT_TRUE(e0.l == 1 && e0.code == 0);
|
||||
@@ -74,7 +74,7 @@ TEST(AtlasAllocator, AllocateMixed0) {
|
||||
}
|
||||
|
||||
TEST(AtlasAllocator, AllocateMixed1) {
|
||||
AtlasAllocator allocator(1024);
|
||||
AtlasAllocator allocator;
|
||||
|
||||
auto e0 = allocator.allocateInLayer(1);
|
||||
EXPECT_TRUE(e0.l == 1 && e0.code == 0);
|
||||
@@ -90,7 +90,7 @@ TEST(AtlasAllocator, AllocateMixed1) {
|
||||
}
|
||||
|
||||
TEST(AtlasAllocator, AllocateMixed2) {
|
||||
AtlasAllocator allocator(1024);
|
||||
AtlasAllocator allocator;
|
||||
|
||||
auto e0 = allocator.allocateInLayer(1);
|
||||
EXPECT_TRUE(e0.l == 1 && e0.code == 0);
|
||||
@@ -122,11 +122,10 @@ TEST(AtlasAllocator, AllocateBySize) {
|
||||
|
||||
Viewport vp(0,0,256,256);
|
||||
auto vp0 = allocator.allocate(256);
|
||||
EXPECT_EQ(vp0.viewport, vp);
|
||||
EXPECT_EQ(vp0.layer, 0);
|
||||
EXPECT_EQ(vp0, vp);
|
||||
|
||||
auto vp1 = allocator.allocate(128);
|
||||
EXPECT_EQ(vp1.layer, 1);
|
||||
EXPECT_TRUE(vp1.empty());
|
||||
}
|
||||
|
||||
TEST(AtlasAllocator, AllocateBySizeOneOfEach) {
|
||||
@@ -141,35 +140,10 @@ TEST(AtlasAllocator, AllocateBySizeOneOfEach) {
|
||||
auto vp2 = allocator.allocate(32);
|
||||
auto vp3 = allocator.allocate(16);
|
||||
|
||||
EXPECT_EQ(vp0.layer, 0);
|
||||
EXPECT_EQ(vp1.layer, 0);
|
||||
EXPECT_EQ(vp2.layer, 0);
|
||||
|
||||
EXPECT_EQ(vp0.viewport, r0);
|
||||
EXPECT_EQ(vp1.viewport, r1);
|
||||
EXPECT_EQ(vp2.viewport, r2);
|
||||
EXPECT_TRUE(vp3.viewport.empty());
|
||||
EXPECT_EQ(vp0, r0);
|
||||
EXPECT_EQ(vp1, r1);
|
||||
EXPECT_EQ(vp2, r2);
|
||||
EXPECT_TRUE(vp3.empty());
|
||||
|
||||
}
|
||||
|
||||
TEST(AtlasAllocator, AllocateBySizeFullLayers) {
|
||||
AtlasAllocator allocator(512);
|
||||
|
||||
Viewport r(0,0,512,512);
|
||||
|
||||
auto vp0 = allocator.allocate(512);
|
||||
auto vp1 = allocator.allocate(512);
|
||||
auto vp2 = allocator.allocate(512);
|
||||
auto vp3 = allocator.allocate(512);
|
||||
|
||||
EXPECT_EQ(vp0.layer, 0);
|
||||
EXPECT_EQ(vp1.layer, 1);
|
||||
EXPECT_EQ(vp2.layer, 2);
|
||||
EXPECT_EQ(vp3.layer, 3);
|
||||
|
||||
EXPECT_EQ(vp0.viewport, r);
|
||||
EXPECT_EQ(vp1.viewport, r);
|
||||
EXPECT_EQ(vp2.viewport, r);
|
||||
EXPECT_EQ(vp3.viewport, r);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.30.0"
|
||||
spec.version = "1.28.2"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.30.0/filament-v1.30.0-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.28.2/filament-v1.28.2-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 30;
|
||||
static constexpr size_t MATERIAL_VERSION = 28;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -60,23 +60,29 @@ enum class SamplerBindingPoints : uint8_t {
|
||||
constexpr size_t CONFIG_MAX_LIGHT_COUNT = 256;
|
||||
constexpr size_t CONFIG_MAX_LIGHT_INDEX = CONFIG_MAX_LIGHT_COUNT - 1;
|
||||
|
||||
// The maximum number of shadowmaps.
|
||||
// There is currently a maximum limit of 128 shadowmaps.
|
||||
// Factors contributing to this limit:
|
||||
// - minspec for UBOs is 16KiB, which currently can hold a maximum of 128 entries
|
||||
constexpr size_t CONFIG_MAX_SHADOWMAPS = 64;
|
||||
|
||||
// The maximum number of shadow layers.
|
||||
// There is currently a maximum limit of 255 layers.
|
||||
// There is currently a limit to 146 layers.
|
||||
// Several factors are contributing to this limit:
|
||||
// - minspec for 2d texture arrays layer is 256
|
||||
// - we're using uint8_t to store the number of layers (255 max)
|
||||
// - nonsensical to be larger than the number of shadowmaps
|
||||
constexpr size_t CONFIG_MAX_SHADOW_LAYERS = CONFIG_MAX_SHADOWMAPS;
|
||||
// - minspec for UBOs is 16KiB, which currently can hold a maximum of 146 entries
|
||||
// - we need to reserve 4 entries for the cascaded shadow map
|
||||
//
|
||||
// CONFIG_MAX_SHADOW_LAYERS determines how many shadows can be used in the
|
||||
// scene. Currently, a spotlight uses 1 layer, a cascaded directional light uses up to 4
|
||||
// and a point light uses 6.
|
||||
//
|
||||
constexpr size_t CONFIG_MAX_SHADOW_LAYERS = 64;
|
||||
|
||||
// The maximum number of shadow cascades that can be used for directional lights.
|
||||
constexpr size_t CONFIG_MAX_SHADOW_CASCADES = 4;
|
||||
|
||||
// Maximum number of shadowmap for point and spotlights
|
||||
// spotlights use 1, point lights use 6
|
||||
constexpr size_t CONFIG_MAX_SHADOWMAP_PUNCTUAL =
|
||||
CONFIG_MAX_SHADOW_LAYERS - CONFIG_MAX_SHADOW_CASCADES;
|
||||
|
||||
|
||||
// The maximum UBO size, in bytes. This value is set to 16 KiB due to the ES3.0 spec.
|
||||
// Note that this value constrains the maximum number of skinning bones, morph targets,
|
||||
// instances, and shadow casting spotlights.
|
||||
|
||||
@@ -124,10 +124,12 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
// bit 0-3: cascade count
|
||||
// bit 4: visualize cascades
|
||||
// bit 8-11: cascade has visible shadows
|
||||
// bit 31: elvsm
|
||||
uint32_t cascades;
|
||||
float reserved0;
|
||||
float reserved1; // normal bias
|
||||
float shadowBulbRadiusLs; // light radius in light-space
|
||||
float shadowBias; // normal bias
|
||||
float shadowPenumbraRatioScale; // For DPCF or PCSS, scale penumbra ratio for artistic use
|
||||
std::array<math::mat4f, CONFIG_MAX_SHADOW_CASCADES> lightFromWorldMatrix;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// VSM shadows [variant: VSM]
|
||||
@@ -162,7 +164,7 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
float ssrStride; // ssr texel stride, >= 1.0
|
||||
|
||||
// bring PerViewUib to 2 KiB
|
||||
math::float4 reserved[63];
|
||||
math::float4 reserved[47];
|
||||
};
|
||||
|
||||
// 2 KiB == 128 float4s
|
||||
@@ -227,11 +229,11 @@ struct LightsUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
math::float2 spotScaleOffset; // { scale, offset }
|
||||
float reserved3; // 0
|
||||
float intensity; // float
|
||||
uint32_t typeShadow; // 0x00.00.ii.ct (t: 0=point, 1=spot, c:contact, ii: index)
|
||||
uint32_t typeShadow; // 0x00.ll.ii.ct (t: 0=point, 1=spot, c:contact, ii: index, ll: layer)
|
||||
uint32_t channels; // 0x000c00ll (ll: light channels, c: caster)
|
||||
|
||||
static uint32_t packTypeShadow(uint8_t type, bool contactShadow, uint8_t index) noexcept {
|
||||
return (type & 0xF) | (contactShadow ? 0x10 : 0x00) | (index << 8);
|
||||
static uint32_t packTypeShadow(uint8_t type, bool contactShadow, uint8_t index, uint8_t layer) noexcept {
|
||||
return (type & 0xF) | (contactShadow ? 0x10 : 0x00) | (index << 8) | (layer << 16);
|
||||
}
|
||||
static uint32_t packChannels(uint8_t lightChannels, bool castShadows) noexcept {
|
||||
return lightChannels | (castShadows ? 0x10000 : 0);
|
||||
@@ -247,19 +249,17 @@ static_assert(sizeof(LightsUib) == 64,
|
||||
struct ShadowUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
static constexpr std::string_view _name{ "ShadowUniforms" };
|
||||
struct alignas(16) ShadowData {
|
||||
math::mat4f lightFromWorldMatrix; // 64
|
||||
math::float4 lightFromWorldZ; // 16
|
||||
math::float4 scissorNormalized; // 16
|
||||
math::mat4f lightFromWorldMatrix; // 64 - unused for point lights
|
||||
math::float3 direction; // 12 - unused for point lights
|
||||
float normalBias; // 4 - unused for point lights
|
||||
math::float4 lightFromWorldZ; // 16 - point lights { depth reconstruction values }
|
||||
|
||||
float texelSizeAtOneMeter; // 4
|
||||
float bulbRadiusLs; // 4
|
||||
float nearOverFarMinusNear; // 4
|
||||
float normalBias; // 4
|
||||
bool elvsm; // 4
|
||||
uint32_t layer; // 4
|
||||
uint32_t reserved1; // 4
|
||||
uint32_t reserved2; // 4
|
||||
};
|
||||
ShadowData shadows[CONFIG_MAX_SHADOWMAPS];
|
||||
ShadowData shadows[CONFIG_MAX_SHADOWMAP_PUNCTUAL];
|
||||
};
|
||||
static_assert(sizeof(ShadowUib) <= CONFIG_MINSPEC_UBO_SIZE,
|
||||
"ShadowUib exceeds max UBO size");
|
||||
|
||||
@@ -35,11 +35,6 @@ Variant Variant::filterUserVariant(
|
||||
if (filterMask & (uint32_t)UserVariantFilterBit::FOG) {
|
||||
variant.key &= ~(filterMask & FOG);
|
||||
}
|
||||
} else {
|
||||
// depth variants can have their VSM bit filtered
|
||||
if (filterMask & (uint32_t)UserVariantFilterBit::VSM) {
|
||||
variant.key &= ~(filterMask & VSM);
|
||||
}
|
||||
}
|
||||
if (!isSSRVariant(variant)) {
|
||||
// SSR variant needs to be handled separately
|
||||
@@ -58,6 +53,8 @@ Variant Variant::filterUserVariant(
|
||||
return variant;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
// compile time sanity-check tests
|
||||
|
||||
@@ -54,7 +54,9 @@ namespace msl { // this is only used for MSL
|
||||
|
||||
using BindingIndexMap = std::unordered_map<std::string, uint16_t>;
|
||||
|
||||
static void collectSibs(const GLSLPostProcessor::Config& config, SibVector& sibs) {
|
||||
template<typename F>
|
||||
static void forEachSib(const GLSLPostProcessor::Config& config, F fn) {
|
||||
const auto& samplerBindings = config.materialInfo->samplerBindings;
|
||||
switch (config.domain) {
|
||||
case MaterialDomain::SURFACE:
|
||||
UTILS_NOUNROLL
|
||||
@@ -65,15 +67,14 @@ static void collectSibs(const GLSLPostProcessor::Config& config, SibVector& sibs
|
||||
auto const* sib =
|
||||
SibGenerator::getSib((SamplerBindingPoints)blockIndex, config.variant);
|
||||
if (sib && hasShaderType(sib->getStageFlags(), config.shaderType)) {
|
||||
sibs.emplace_back(blockIndex, sib);
|
||||
fn(blockIndex, sib);
|
||||
}
|
||||
}
|
||||
case MaterialDomain::POST_PROCESS:
|
||||
case MaterialDomain::COMPUTE:
|
||||
break;
|
||||
}
|
||||
sibs.emplace_back((uint8_t) SamplerBindingPoints::PER_MATERIAL_INSTANCE,
|
||||
&config.materialInfo->sib);
|
||||
fn((uint8_t) SamplerBindingPoints::PER_MATERIAL_INSTANCE, &config.materialInfo->sib);
|
||||
}
|
||||
|
||||
}; // namespace msl
|
||||
@@ -137,9 +138,8 @@ static std::string stringifySpvOptimizerMessage(spv_message_level_t level, const
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void GLSLPostProcessor::spirvToMsl(const SpirvBlob *spirv, std::string *outMsl,
|
||||
filament::backend::ShaderModel shaderModel, bool useFramebufferFetch, const SibVector& sibs,
|
||||
const ShaderMinifier* minifier) {
|
||||
void GLSLPostProcessor::spirvToToMsl(const SpirvBlob *spirv, std::string *outMsl,
|
||||
const Config &config, ShaderMinifier& minifier) {
|
||||
|
||||
using namespace msl;
|
||||
|
||||
@@ -148,19 +148,19 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob *spirv, std::string *outMsl,
|
||||
mslCompiler.set_common_options(options);
|
||||
|
||||
const CompilerMSL::Options::Platform platform =
|
||||
shaderModel == ShaderModel::MOBILE ?
|
||||
config.shaderModel == ShaderModel::MOBILE ?
|
||||
CompilerMSL::Options::Platform::iOS : CompilerMSL::Options::Platform::macOS;
|
||||
|
||||
CompilerMSL::Options mslOptions = {};
|
||||
mslOptions.platform = platform,
|
||||
mslOptions.msl_version = shaderModel == ShaderModel::MOBILE ?
|
||||
mslOptions.msl_version = config.shaderModel == ShaderModel::MOBILE ?
|
||||
CompilerMSL::Options::make_msl_version(2, 0) : CompilerMSL::Options::make_msl_version(2, 2);
|
||||
|
||||
if (useFramebufferFetch) {
|
||||
if (config.hasFramebufferFetch) {
|
||||
mslOptions.use_framebuffer_fetch_subpasses = true;
|
||||
// On macOS, framebuffer fetch is only available starting with MSL 2.3. Filament will only
|
||||
// use framebuffer fetch materials on devices that support it.
|
||||
if (shaderModel == ShaderModel::DESKTOP) {
|
||||
if (config.shaderModel == ShaderModel::DESKTOP) {
|
||||
mslOptions.msl_version = CompilerMSL::Options::make_msl_version(2, 3);
|
||||
}
|
||||
}
|
||||
@@ -221,7 +221,9 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob *spirv, std::string *outMsl,
|
||||
//
|
||||
// Which is then bound to the vertex/fragment functions:
|
||||
// constant spvDescriptorSetBuffer1& spvDescriptorSet1 [[buffer(27)]]
|
||||
for (auto [bindingPoint, sib] : sibs) {
|
||||
forEachSib(config,
|
||||
[&executionModel, &mslCompiler, &argumentBuffers](
|
||||
uint8_t bindingPoint, const SamplerInterfaceBlock* sib) {
|
||||
const auto& infoList = sib->getSamplerInfoList();
|
||||
|
||||
// bindingPoint + 1, because the first descriptor set is for uniforms
|
||||
@@ -249,7 +251,7 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob *spirv, std::string *outMsl,
|
||||
argBufferBinding.msl_buffer =
|
||||
CodeGenerator::METAL_SAMPLER_GROUP_BINDING_START + bindingPoint;
|
||||
mslCompiler.add_msl_resource_binding(argBufferBinding);
|
||||
}
|
||||
});
|
||||
|
||||
auto updateResourceBindingDefault = [executionModel, &mslCompiler]
|
||||
(const auto& resource, const BindingIndexMap* map = nullptr) {
|
||||
@@ -281,9 +283,7 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob *spirv, std::string *outMsl,
|
||||
mslCompiler.add_discrete_descriptor_set(0);
|
||||
|
||||
*outMsl = mslCompiler.compile();
|
||||
if (minifier) {
|
||||
*outMsl = minifier->removeWhitespace(*outMsl);
|
||||
}
|
||||
*outMsl = minifier.removeWhitespace(*outMsl);
|
||||
|
||||
// Replace spirv-cross' generated argument buffers with our own.
|
||||
for (auto* argBuffer : argumentBuffers) {
|
||||
@@ -374,11 +374,8 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
|
||||
GlslangToSpv(*program.getIntermediate(internalConfig.shLang),
|
||||
*internalConfig.spirvOutput, &options);
|
||||
if (internalConfig.mslOutput) {
|
||||
auto sibs = SibVector::with_capacity(CONFIG_SAMPLER_BINDING_COUNT);
|
||||
msl::collectSibs(config, sibs);
|
||||
spirvToMsl(internalConfig.spirvOutput, internalConfig.mslOutput,
|
||||
config.shaderModel, config.hasFramebufferFetch, sibs,
|
||||
&internalConfig.minifier);
|
||||
spirvToToMsl(internalConfig.spirvOutput, internalConfig.mslOutput, config,
|
||||
internalConfig.minifier);
|
||||
}
|
||||
} else {
|
||||
slog.e << "GLSL post-processor invoked with optimization level NONE"
|
||||
@@ -456,10 +453,8 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
}
|
||||
|
||||
if (internalConfig.mslOutput) {
|
||||
auto sibs = SibVector::with_capacity(CONFIG_SAMPLER_BINDING_COUNT);
|
||||
msl::collectSibs(config, sibs);
|
||||
spirvToMsl(internalConfig.spirvOutput, internalConfig.mslOutput, config.shaderModel,
|
||||
config.hasFramebufferFetch, sibs, &internalConfig.minifier);
|
||||
spirvToToMsl(internalConfig.spirvOutput, internalConfig.mslOutput, config,
|
||||
internalConfig.minifier);
|
||||
}
|
||||
|
||||
if (internalConfig.glslOutput) {
|
||||
@@ -485,10 +480,7 @@ void GLSLPostProcessor::fullOptimization(const TShader& tShader,
|
||||
}
|
||||
|
||||
if (internalConfig.mslOutput) {
|
||||
auto sibs = SibVector::with_capacity(CONFIG_SAMPLER_BINDING_COUNT);
|
||||
msl::collectSibs(config, sibs);
|
||||
spirvToMsl(&spirv, internalConfig.mslOutput, config.shaderModel, config.hasFramebufferFetch,
|
||||
sibs, &internalConfig.minifier);
|
||||
spirvToToMsl(&spirv, internalConfig.mslOutput, config, internalConfig.minifier);
|
||||
}
|
||||
|
||||
// Transpile back to GLSL
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
#include "filamat/MaterialBuilder.h" // for MaterialBuilder:: enums
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
|
||||
#include "ShaderMinifier.h"
|
||||
|
||||
#include <ShaderLang.h>
|
||||
@@ -36,15 +34,9 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace filament {
|
||||
class SamplerInterfaceBlock;
|
||||
};
|
||||
|
||||
namespace filamat {
|
||||
|
||||
using SpirvBlob = std::vector<uint32_t>;
|
||||
using BindingPointAndSib = std::pair<uint8_t, const filament::SamplerInterfaceBlock*>;
|
||||
using SibVector = utils::FixedCapacityVector<BindingPointAndSib>;
|
||||
|
||||
class GLSLPostProcessor {
|
||||
public:
|
||||
@@ -77,11 +69,6 @@ public:
|
||||
SpirvBlob* outputSpirv,
|
||||
std::string* outputMsl);
|
||||
|
||||
// public so backend_test can also use it
|
||||
static void spirvToMsl(const SpirvBlob* spirv, std::string* outMsl,
|
||||
filament::backend::ShaderModel shaderModel, bool useFramebufferFetch,
|
||||
const SibVector& sibs, const ShaderMinifier* minifier);
|
||||
|
||||
private:
|
||||
struct InternalConfig {
|
||||
std::string* glslOutput = nullptr;
|
||||
@@ -110,6 +97,8 @@ private:
|
||||
static void registerPerformancePasses(spvtools::Optimizer& optimizer, Config const& config);
|
||||
|
||||
void optimizeSpirv(OptimizerPtr optimizer, SpirvBlob& spirv) const;
|
||||
static void spirvToToMsl(const SpirvBlob* spirv, std::string* outMsl, const Config& config,
|
||||
ShaderMinifier& minifier);
|
||||
|
||||
const MaterialBuilder::Optimization mOptimization;
|
||||
const bool mPrintShaders;
|
||||
|
||||
@@ -105,9 +105,10 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
|
||||
|
||||
{ "cascadeSplits", 0, Type::FLOAT4, Precision::HIGH },
|
||||
{ "cascades", 0, Type::UINT },
|
||||
{ "reserved0", 0, Type::FLOAT },
|
||||
{ "reserved1", 0, Type::FLOAT },
|
||||
{ "shadowBulbRadiusLs", 0, Type::FLOAT },
|
||||
{ "shadowBias", 0, Type::FLOAT },
|
||||
{ "shadowPenumbraRatioScale", 0, Type::FLOAT },
|
||||
{ "lightFromWorldMatrix", 4, Type::MAT4, Precision::HIGH },
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// VSM shadows [variant: VSM]
|
||||
@@ -170,7 +171,7 @@ BufferInterfaceBlock const& UibGenerator::getLightsUib() noexcept {
|
||||
BufferInterfaceBlock const& UibGenerator::getShadowUib() noexcept {
|
||||
static BufferInterfaceBlock uib = BufferInterfaceBlock::Builder()
|
||||
.name(ShadowUib::_name)
|
||||
.add({{ "shadows", CONFIG_MAX_SHADOWMAPS,
|
||||
.add({{ "shadows", CONFIG_MAX_SHADOWMAP_PUNCTUAL,
|
||||
BufferInterfaceBlock::Type::STRUCT, {},
|
||||
"ShadowData", sizeof(ShadowUib::ShadowData) }})
|
||||
.build();
|
||||
|
||||
@@ -121,8 +121,8 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
|
||||
|
||||
// specification constants
|
||||
out << '\n';
|
||||
generateSpecializationConstant(out, "BACKEND_FEATURE_LEVEL", 0, 1);
|
||||
generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES", 1, (int)CONFIG_MAX_INSTANCES);
|
||||
generateSpecificationConstant(out, "BACKEND_FEATURE_LEVEL", 0, 1);
|
||||
generateSpecificationConstant(out, "CONFIG_MAX_INSTANCES", 1, (int)CONFIG_MAX_INSTANCES);
|
||||
|
||||
out << '\n';
|
||||
out << SHADERS_COMMON_DEFINES_GLSL_DATA;
|
||||
@@ -597,7 +597,7 @@ io::sstream& CodeGenerator::generateIndexedDefine(io::sstream& out, const char*
|
||||
return out;
|
||||
}
|
||||
|
||||
utils::io::sstream& CodeGenerator::generateSpecializationConstant(utils::io::sstream& out,
|
||||
utils::io::sstream& CodeGenerator::generateSpecificationConstant(utils::io::sstream& out,
|
||||
const char* name, uint32_t id, std::variant<int, float, bool> value) const {
|
||||
static const char* types[] = { "int", "float", "bool" };
|
||||
if (mTargetLanguage == MaterialBuilderBase::TargetLanguage::SPIRV) {
|
||||
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
static utils::io::sstream& generateIndexedDefine(utils::io::sstream& out, const char* name,
|
||||
uint32_t index, uint32_t value);
|
||||
|
||||
utils::io::sstream& generateSpecializationConstant(utils::io::sstream& out,
|
||||
utils::io::sstream& generateSpecificationConstant(utils::io::sstream& out,
|
||||
const char* name, uint32_t id, std::variant<int, float, bool> value) const;
|
||||
|
||||
static utils::io::sstream& generatePostProcessGetters(utils::io::sstream& out, ShaderStage type);
|
||||
|
||||
@@ -287,10 +287,6 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
|
||||
UniformBindingPoints::PER_VIEW, UibGenerator::getPerViewUib());
|
||||
cg.generateUniforms(vs, ShaderStage::VERTEX,
|
||||
UniformBindingPoints::PER_RENDERABLE, UibGenerator::getPerRenderableUib());
|
||||
if (litVariants && filament::Variant::isShadowReceiverVariant(variant)) {
|
||||
cg.generateUniforms(vs, ShaderStage::FRAGMENT,
|
||||
UniformBindingPoints::SHADOW, UibGenerator::getShadowUib());
|
||||
}
|
||||
if (variant.hasSkinningOrMorphing()) {
|
||||
cg.generateUniforms(vs, ShaderStage::VERTEX,
|
||||
UniformBindingPoints::PER_RENDERABLE_BONES,
|
||||
|
||||
@@ -603,7 +603,7 @@ void FAssetLoader::recurseEntities(const cgltf_data* srcAsset, const cgltf_node*
|
||||
}
|
||||
}
|
||||
|
||||
if (node->light) {
|
||||
if (node->light ) {
|
||||
createLight(node->light, entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -145,10 +145,11 @@ void FFilamentInstance::recomputeBoundingBoxes() {
|
||||
}
|
||||
|
||||
const cgltf_accessor* targetAccessor = targetAttribute.data;
|
||||
const cgltf_size targetCount = targetAccessor->count;
|
||||
const cgltf_size targetDim = cgltf_num_components(targetAccessor->type);
|
||||
|
||||
assert_invariant(targetAccessor);
|
||||
assert_invariant(targetAccessor->count == accessor->count);
|
||||
assert_invariant(cgltf_num_components(targetAccessor->type) == dim);
|
||||
assert_invariant(targetCount == accessor->count);
|
||||
assert_invariant(targetDim == dim);
|
||||
|
||||
cgltf_accessor_unpack_floats(targetAccessor, unpacked.data(), unpacked.size());
|
||||
|
||||
|
||||
@@ -588,26 +588,6 @@ constexpr mat4f highPrecisionMultiply(mat4f const& lhs, mat4f const& rhs) noexce
|
||||
};
|
||||
}
|
||||
|
||||
// mat4 * float4, with double precision intermediates
|
||||
constexpr double4 highPrecisionMultiplyd(mat4f const& lhs, float4 const& rhs) noexcept {
|
||||
double4 result{};
|
||||
result += lhs[0] * rhs[0];
|
||||
result += lhs[1] * rhs[1];
|
||||
result += lhs[2] * rhs[2];
|
||||
result += lhs[3] * rhs[3];
|
||||
return result;
|
||||
}
|
||||
|
||||
// mat4 * mat4, with double precision intermediates
|
||||
constexpr mat4 highPrecisionMultiplyd(mat4f const& lhs, mat4f const& rhs) noexcept {
|
||||
return {
|
||||
highPrecisionMultiplyd(lhs, rhs[0]),
|
||||
highPrecisionMultiplyd(lhs, rhs[1]),
|
||||
highPrecisionMultiplyd(lhs, rhs[2]),
|
||||
highPrecisionMultiplyd(lhs, rhs[3])
|
||||
};
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
@@ -13,6 +13,7 @@ file(GLOB_RECURSE PUBLIC_HDRS ${PUBLIC_HDR_DIR}/${TARGET}/*.h)
|
||||
|
||||
set(DIST_HDRS
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/algorithm.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/architecture.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/bitset.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/CallStack.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/debug.h
|
||||
@@ -26,6 +27,7 @@ set(DIST_HDRS
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/EntityManager.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/FixedCapacityVector.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/Invocable.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/JobSystem.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/Log.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/memalign.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/Mutex.h
|
||||
@@ -40,6 +42,7 @@ set(DIST_HDRS
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/SpinLock.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/StructureOfArrays.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/unwindows.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET}/WorkStealingDequeue.h
|
||||
)
|
||||
|
||||
# Use our custom mutex/condition only on ANDROID
|
||||
@@ -49,6 +52,7 @@ set(DIST_ANDROID_HDRS
|
||||
|
||||
set(DIST_GENERIC_HDRS
|
||||
${PUBLIC_HDR_DIR}/${TARGET_GENERIC}/Mutex.h
|
||||
${PUBLIC_HDR_DIR}/${TARGET_GENERIC}/Condition.h
|
||||
)
|
||||
|
||||
set(SRCS
|
||||
|
||||
@@ -87,11 +87,11 @@ static_assert(size(4) == 85);
|
||||
/**
|
||||
* A Quad-tree encoded as an array.
|
||||
* @tparam T Type of the quad-tree nodes
|
||||
* @tparam HEIGHT Height of the quad-tree
|
||||
* @tparam HEIGHT Height of the quad-tree, muse be <= 4
|
||||
*/
|
||||
template<typename T, size_t HEIGHT>
|
||||
class QuadTreeArray : public std::array<T, QuadTreeUtils::size(HEIGHT)> {
|
||||
static_assert(HEIGHT <= 7, "QuadTreeArray height must be <= 7 (16-bits morton)");
|
||||
static_assert(HEIGHT <= 4, "QuadTreeArray height must be <= 4");
|
||||
|
||||
// Simple fixed capacity stack
|
||||
template<typename TYPE, size_t CAPACITY,
|
||||
|
||||
@@ -320,7 +320,9 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk,
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (compare(tok, jsonChunk, "elvsm") == 0) {
|
||||
if (compare(tok, jsonChunk, "msaaSamples") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->msaaSamples);
|
||||
} else if (compare(tok, jsonChunk, "elvsm") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->elvsm);
|
||||
} else if (compare(tok, jsonChunk, "blurWidth") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->blurWidth);
|
||||
@@ -676,6 +678,7 @@ static std::ostream& operator<<(std::ostream& out, const LightManager::ShadowOpt
|
||||
math::float3 splitsVector = { splits[0], splits[1], splits[2] };
|
||||
return out << "{\n"
|
||||
<< "\"vsm\": {\n"
|
||||
<< "\"msaaSamples\": " << int(in.vsm.msaaSamples) << ",\n"
|
||||
<< "\"elvsm\": " << to_string(in.vsm.elvsm) << ",\n"
|
||||
<< "\"blurWidth\": " << in.vsm.blurWidth << "\n"
|
||||
<< "},\n"
|
||||
|
||||
@@ -800,8 +800,6 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, VsmShadowOption
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->anisotropy);
|
||||
} else if (compare(tok, jsonChunk, "mipmapping") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->mipmapping);
|
||||
} else if (compare(tok, jsonChunk, "msaaSamples") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->msaaSamples);
|
||||
} else if (compare(tok, jsonChunk, "highPrecision") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->highPrecision);
|
||||
} else if (compare(tok, jsonChunk, "minVarianceScale") == 0) {
|
||||
@@ -824,7 +822,6 @@ std::ostream& operator<<(std::ostream& out, const VsmShadowOptions& in) {
|
||||
return out << "{\n"
|
||||
<< "\"anisotropy\": " << int(in.anisotropy) << ",\n"
|
||||
<< "\"mipmapping\": " << to_string(in.mipmapping) << ",\n"
|
||||
<< "\"msaaSamples\": " << int(in.msaaSamples) << ",\n"
|
||||
<< "\"highPrecision\": " << to_string(in.highPrecision) << ",\n"
|
||||
<< "\"minVarianceScale\": " << (in.minVarianceScale) << ",\n"
|
||||
<< "\"lightBleedReduction\": " << (in.lightBleedReduction) << "\n"
|
||||
|
||||
@@ -846,7 +846,7 @@ void ViewerGui::updateUserInterface() {
|
||||
char label[32];
|
||||
snprintf(label, 32, "%d", 1 << mVsmMsaaSamplesLog2);
|
||||
ImGui::SliderInt("VSM MSAA samples", &mVsmMsaaSamplesLog2, 0, 3, label);
|
||||
mSettings.view.vsmShadowOptions.msaaSamples =
|
||||
light.shadowOptions.vsm.msaaSamples =
|
||||
static_cast<uint8_t>(1u << mVsmMsaaSamplesLog2);
|
||||
|
||||
int vsmAnisotropy = mSettings.view.vsmShadowOptions.anisotropy;
|
||||
|
||||
@@ -2,14 +2,14 @@ struct Light {
|
||||
vec4 colorIntensity; // rgb, pre-exposed intensity
|
||||
vec3 l;
|
||||
float attenuation;
|
||||
highp vec3 worldPosition;
|
||||
vec3 worldPosition;
|
||||
float NoL;
|
||||
highp vec3 direction;
|
||||
float zLight;
|
||||
bool castsShadows;
|
||||
bool contactShadows;
|
||||
uint type;
|
||||
uint shadowIndex;
|
||||
uint shadowLayer;
|
||||
uint channels;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
*/
|
||||
|
||||
highp vec4 computeLightSpacePosition(highp vec3 p, const highp vec3 n,
|
||||
const highp vec3 dir, const float b, const highp mat4 lightFromWorldMatrix) {
|
||||
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
|
||||
|
||||
#if !defined(VARIANT_HAS_VSM)
|
||||
highp float cosTheta = saturate(dot(n, dir));
|
||||
highp float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
|
||||
highp float NoL = saturate(dot(n, l));
|
||||
highp float sinTheta = sqrt(1.0 - NoL * NoL);
|
||||
p += n * (sinTheta * b);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,16 +2,13 @@
|
||||
// UBOs, which is is the case here.
|
||||
struct ShadowData {
|
||||
highp mat4 lightFromWorldMatrix;
|
||||
highp vec3 direction;
|
||||
float normalBias;
|
||||
highp vec4 lightFromWorldZ;
|
||||
highp vec4 scissorNormalized;
|
||||
mediump float texelSizeAtOneMeter;
|
||||
mediump float bulbRadiusLs;
|
||||
mediump float nearOverFarMinusNear;
|
||||
mediump float normalBias;
|
||||
float texelSizeAtOneMeter;
|
||||
float bulbRadiusLs;
|
||||
float nearOverFarMinusNear;
|
||||
bool elvsm;
|
||||
mediump uint layer;
|
||||
mediump uint reserved1;
|
||||
mediump uint reserved2;
|
||||
};
|
||||
|
||||
struct BoneData {
|
||||
|
||||
@@ -94,8 +94,9 @@ highp vec3 getNormalizedViewportCoord2() {
|
||||
}
|
||||
|
||||
#if defined(VARIANT_HAS_SHADOWING) && defined(VARIANT_HAS_DYNAMIC_LIGHTING)
|
||||
highp vec4 getSpotLightSpacePosition(uint index, highp vec3 dir, highp float zLight) {
|
||||
highp vec4 getSpotLightSpacePosition(uint index, highp float zLight) {
|
||||
highp mat4 lightFromWorldMatrix = shadowUniforms.shadows[index].lightFromWorldMatrix;
|
||||
highp vec3 dir = shadowUniforms.shadows[index].direction;
|
||||
|
||||
// for spotlights, the bias depends on z
|
||||
float bias = shadowUniforms.shadows[index].normalBias * zLight;
|
||||
@@ -133,9 +134,8 @@ highp vec4 getCascadeLightSpacePosition(uint cascade) {
|
||||
}
|
||||
|
||||
return computeLightSpacePosition(getWorldPosition(), getWorldNormalVector(),
|
||||
frameUniforms.lightDirection,
|
||||
shadowUniforms.shadows[cascade].normalBias,
|
||||
shadowUniforms.shadows[cascade].lightFromWorldMatrix);
|
||||
frameUniforms.lightDirection, frameUniforms.shadowBias,
|
||||
frameUniforms.lightFromWorldMatrix[cascade]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,6 +13,10 @@ int getInstanceIndex() {
|
||||
// Uniforms access
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
mat4 getLightFromWorldMatrix() {
|
||||
return frameUniforms.lightFromWorldMatrix[0];
|
||||
}
|
||||
|
||||
PerRenderableData getObjectUniforms() {
|
||||
#if defined(MATERIAL_HAS_INSTANCES)
|
||||
// the material manages instancing, all instances share the same uniform block.
|
||||
|
||||
@@ -56,8 +56,9 @@ void evaluateDirectionalLight(const MaterialInputs material,
|
||||
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u));
|
||||
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
|
||||
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
|
||||
highp vec4 shadowPosition = getShadowPosition(cascade);
|
||||
visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
|
||||
uint layer = cascade;
|
||||
highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f);
|
||||
visibility = shadow(true, light_shadowMap, layer, 0u, shadowPosition, 0.0f);
|
||||
}
|
||||
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
|
||||
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
|
||||
@@ -150,23 +150,21 @@ Light getLight(const uint lightIndex) {
|
||||
light.colorIntensity.w = computePreExposedIntensity(intensity, frameUniforms.exposure);
|
||||
light.l = normalize(posToLight);
|
||||
light.attenuation = getDistanceAttenuation(posToLight, positionFalloff.w);
|
||||
light.direction = direction;
|
||||
light.NoL = saturate(dot(shading_normal, light.l));
|
||||
light.worldPosition = positionFalloff.xyz;
|
||||
light.channels = channels;
|
||||
light.contactShadows = bool(typeShadow & 0x10u);
|
||||
#if defined(VARIANT_HAS_DYNAMIC_LIGHTING)
|
||||
light.type = (typeShadow & 0x1u);
|
||||
#if defined(VARIANT_HAS_SHADOWING)
|
||||
#if defined(VARIANT_HAS_DYNAMIC_LIGHTING)
|
||||
light.shadowIndex = (typeShadow >> 8u) & 0xFFu;
|
||||
light.shadowLayer = (typeShadow >> 16u) & 0xFFu;
|
||||
light.castsShadows = bool(channels & 0x10000u);
|
||||
light.type = (typeShadow & 0x1u);
|
||||
if (light.type == LIGHT_TYPE_SPOT) {
|
||||
light.attenuation *= getAngleAttenuation(-direction, light.l, scaleOffset);
|
||||
light.zLight = dot(shadowUniforms.shadows[light.shadowIndex].lightFromWorldZ, vec4(worldPosition, 1.0));
|
||||
}
|
||||
#endif
|
||||
if (light.type == LIGHT_TYPE_SPOT) {
|
||||
light.attenuation *= getAngleAttenuation(-direction, light.l, scaleOffset);
|
||||
}
|
||||
#endif
|
||||
return light;
|
||||
}
|
||||
@@ -211,17 +209,19 @@ void evaluatePunctualLights(const MaterialInputs material,
|
||||
#if defined(VARIANT_HAS_SHADOWING)
|
||||
if (light.NoL > 0.0) {
|
||||
if (light.castsShadows) {
|
||||
uint shadowIndex = light.shadowIndex;
|
||||
uint layer = light.shadowLayer;
|
||||
highp vec4 shadowPosition;
|
||||
if (light.type == LIGHT_TYPE_POINT) {
|
||||
// point-light shadows are sampled from a direction
|
||||
highp vec3 r = getWorldPosition() - light.worldPosition;
|
||||
uint face = getPointLightFace(r);
|
||||
shadowIndex += face;
|
||||
light.zLight = dot(shadowUniforms.shadows[shadowIndex].lightFromWorldZ,
|
||||
vec4(getWorldPosition(), 1.0));
|
||||
highp vec4 nf = shadowUniforms.shadows[light.shadowIndex].lightFromWorldZ;
|
||||
// getShadowPosition returns zLight which is needed for PCSS/DPCF
|
||||
shadowPosition = getShadowPosition(r, nf, layer, light.zLight);
|
||||
} else {
|
||||
// getShadowPosition needs zLight for applying the normal bias
|
||||
shadowPosition = getShadowPosition(false, light.shadowIndex, 0u, light.zLight);
|
||||
}
|
||||
highp vec4 shadowPosition = getShadowPosition(shadowIndex, light.direction, light.zLight);
|
||||
visibility = shadow(false, light_shadowMap, shadowIndex,
|
||||
visibility = shadow(false, light_shadowMap, layer, light.shadowIndex,
|
||||
shadowPosition, light.zLight);
|
||||
}
|
||||
if (light.contactShadows && visibility > 0.0) {
|
||||
|
||||
+1
-3
@@ -143,9 +143,7 @@ void main() {
|
||||
#if defined(VARIANT_HAS_SHADOWING) && defined(VARIANT_HAS_DIRECTIONAL_LIGHTING)
|
||||
vertex_lightSpacePosition = computeLightSpacePosition(
|
||||
vertex_worldPosition.xyz, vertex_worldNormal,
|
||||
frameUniforms.lightDirection,
|
||||
shadowUniforms.shadows[0].normalBias,
|
||||
shadowUniforms.shadows[0].lightFromWorldMatrix);
|
||||
frameUniforms.lightDirection, frameUniforms.shadowBias, getLightFromWorldMatrix());
|
||||
#endif
|
||||
|
||||
#endif // !defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER)
|
||||
|
||||
@@ -50,8 +50,9 @@ vec4 evaluateMaterial(const MaterialInputs material) {
|
||||
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u));
|
||||
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
|
||||
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
|
||||
highp vec4 shadowPosition = getShadowPosition(cascade);
|
||||
visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
|
||||
uint layer = cascade;
|
||||
highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f);
|
||||
visibility = shadow(true, light_shadowMap, layer, 0u, shadowPosition, 0.0f);
|
||||
}
|
||||
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
|
||||
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
|
||||
+89
-85
@@ -17,33 +17,27 @@
|
||||
// PCF Shadow Sampling
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
float sampleDepth(const mediump sampler2DArrayShadow map,
|
||||
const highp vec4 scissorNormalized,
|
||||
const uint layer, highp vec2 uv, float depth) {
|
||||
|
||||
// clamp needed for directional lights and/or large kernels
|
||||
uv = clamp(uv, scissorNormalized.xy, scissorNormalized.zw);
|
||||
|
||||
// depth must be clamped to support floating-point depth formats which are always in
|
||||
// the range [0, 1].
|
||||
float sampleDepth(const mediump sampler2DArrayShadow map, const uint layer,
|
||||
const highp vec2 uv, float depth) {
|
||||
// depth must be clamped to support floating-point depth formats. This is to avoid comparing a
|
||||
// value from the depth texture (which is never greater than 1.0) with a greater-than-one
|
||||
// comparison value (which is possible with floating-point formats).
|
||||
return texture(map, vec4(uv, layer, saturate(depth)));
|
||||
}
|
||||
|
||||
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
|
||||
// use hardware assisted PCF
|
||||
float ShadowSample_PCF_Hard(const mediump sampler2DArrayShadow map,
|
||||
const highp vec4 scissorNormalized,
|
||||
const uint layer, const highp vec4 shadowPosition) {
|
||||
highp vec3 position = shadowPosition.xyz * (1.0 / shadowPosition.w);
|
||||
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
|
||||
return sampleDepth(map, scissorNormalized, layer, position.xy, position.z);
|
||||
return sampleDepth(map, layer, position.xy, position.z);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
|
||||
// use hardware assisted PCF + 3x3 gaussian filter
|
||||
float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
|
||||
const highp vec4 scissorNormalized,
|
||||
const uint layer, const highp vec4 shadowPosition) {
|
||||
highp vec3 position = shadowPosition.xyz * (1.0 / shadowPosition.w);
|
||||
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
|
||||
@@ -71,35 +65,31 @@ float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
|
||||
v *= texelSize.y;
|
||||
|
||||
float sum = 0.0;
|
||||
sum += uw.x * vw.x * sampleDepth(map, scissorNormalized, layer, base + vec2(u.x, v.x), depth);
|
||||
sum += uw.y * vw.x * sampleDepth(map, scissorNormalized, layer, base + vec2(u.y, v.x), depth);
|
||||
sum += uw.x * vw.y * sampleDepth(map, scissorNormalized, layer, base + vec2(u.x, v.y), depth);
|
||||
sum += uw.y * vw.y * sampleDepth(map, scissorNormalized, layer, base + vec2(u.y, v.y), depth);
|
||||
sum += uw.x * vw.x * sampleDepth(map, layer, base + vec2(u.x, v.x), depth);
|
||||
sum += uw.y * vw.x * sampleDepth(map, layer, base + vec2(u.y, v.x), depth);
|
||||
sum += uw.x * vw.y * sampleDepth(map, layer, base + vec2(u.x, v.y), depth);
|
||||
sum += uw.y * vw.y * sampleDepth(map, layer, base + vec2(u.y, v.y), depth);
|
||||
return sum * (1.0 / 16.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// use manual PCF
|
||||
float ShadowSample_PCF(const mediump sampler2DArray map,
|
||||
const highp vec4 scissorNormalized,
|
||||
const uint layer, const highp vec4 shadowPosition) {
|
||||
highp vec3 position = shadowPosition.xyz * (1.0 / shadowPosition.w);
|
||||
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
|
||||
highp vec2 size = vec2(textureSize(map, 0));
|
||||
highp vec2 tc = clamp(position.xy, scissorNormalized.xy, scissorNormalized.zw);
|
||||
highp vec2 st = tc.xy * size - 0.5;
|
||||
|
||||
highp vec2 st = position.xy * size - 0.5;
|
||||
vec4 d;
|
||||
#if defined(FILAMENT_HAS_FEATURE_TEXTURE_GATHER)
|
||||
d = textureGather(map, vec3(tc, layer), 0); // 01, 11, 10, 00
|
||||
d = textureGather(map, vec3(position.xy, layer), 0); // 01, 11, 10, 00
|
||||
#else
|
||||
// we must use texelFetchOffset before texelLodOffset filters
|
||||
d[0] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(0, 1)).r;
|
||||
d[1] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(1, 1)).r;
|
||||
d[2] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(1, 0)).r;
|
||||
d[3] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(0, 0)).r;
|
||||
highp ivec3 tc = ivec3(st, layer);
|
||||
d[0] = texelFetchOffset(map, tc, 0, ivec2(0, 1)).r;
|
||||
d[1] = texelFetchOffset(map, tc, 0, ivec2(1, 1)).r;
|
||||
d[2] = texelFetchOffset(map, tc, 0, ivec2(1, 0)).r;
|
||||
d[3] = texelFetchOffset(map, tc, 0, ivec2(0, 0)).r;
|
||||
#endif
|
||||
|
||||
vec4 pcf = step(0.0, position.zzzz - d);
|
||||
highp vec2 grad = fract(st);
|
||||
return mix(mix(pcf.w, pcf.z, grad.x), mix(pcf.x, pcf.y, grad.x), grad.y);
|
||||
@@ -171,7 +161,7 @@ float getPenumbraLs(const bool DIRECTIONAL, const uint index, const highp float
|
||||
float penumbra;
|
||||
// This conditional is resolved at compile time
|
||||
if (DIRECTIONAL) {
|
||||
penumbra = shadowUniforms.shadows[index].bulbRadiusLs;
|
||||
penumbra = frameUniforms.shadowBulbRadiusLs;
|
||||
} else {
|
||||
// the penumbra radius depends on the light-space z for spotlights
|
||||
penumbra = shadowUniforms.shadows[index].bulbRadiusLs / zLight;
|
||||
@@ -202,17 +192,14 @@ float getPenumbraRatio(const bool DIRECTIONAL, const uint index,
|
||||
}
|
||||
|
||||
void blockerSearchAndFilter(out float occludedCount, out float z_occSum,
|
||||
const mediump sampler2DArray map, const highp vec4 scissorNormalized, const highp vec2 uv,
|
||||
const float z_rec, const uint layer,
|
||||
const mediump sampler2DArray map, const highp vec2 uv, const float z_rec, const uint layer,
|
||||
const highp vec2 filterRadii, const mat2 R, const highp vec2 dz_duv,
|
||||
const uint tapCount) {
|
||||
occludedCount = 0.0;
|
||||
z_occSum = 0.0;
|
||||
for (uint i = 0u; i < tapCount; i++) {
|
||||
highp vec2 duv = R * (poissonDisk[i] * filterRadii);
|
||||
highp vec2 tc = clamp(uv + duv, scissorNormalized.xy, scissorNormalized.zw);
|
||||
|
||||
float z_occ = textureLod(map, vec3(tc, layer), 0.0).r;
|
||||
float z_occ = textureLod(map, vec3(uv + duv, layer), 0.0).r;
|
||||
|
||||
// note: z_occ and z_rec are not necessarily linear here, comparing them is always okay for
|
||||
// the regular PCF, but the "distance" is meaningless unless they are actually linear
|
||||
@@ -230,9 +217,7 @@ void blockerSearchAndFilter(out float occludedCount, out float z_occSum,
|
||||
}
|
||||
}
|
||||
|
||||
float filterPCSS(const mediump sampler2DArray map,
|
||||
const highp vec4 scissorNormalized,
|
||||
const highp vec2 size,
|
||||
float filterPCSS(const mediump sampler2DArray map, const highp vec2 size,
|
||||
const highp vec2 uv, const float z_rec, const uint layer,
|
||||
const highp vec2 filterRadii, const mat2 R, const highp vec2 dz_duv,
|
||||
const uint tapCount) {
|
||||
@@ -243,14 +228,11 @@ float filterPCSS(const mediump sampler2DArray map,
|
||||
|
||||
// sample the shadow map with a 2x2 PCF, this helps a lot in low resolution areas
|
||||
vec4 d;
|
||||
highp vec2 tc = clamp(uv + duv, scissorNormalized.xy, scissorNormalized.zw);
|
||||
highp vec2 st = tc.xy * size - 0.5;
|
||||
highp vec2 st = (uv + duv) * size - 0.5;
|
||||
highp vec2 grad = fract(st);
|
||||
|
||||
#if defined(FILAMENT_HAS_FEATURE_TEXTURE_GATHER)
|
||||
d = textureGather(map, vec3(tc, layer), 0); // 01, 11, 10, 00
|
||||
d = textureGather(map, vec3(uv + duv, layer), 0); // 01, 11, 10, 00
|
||||
#else
|
||||
// we must use texelFetchOffset before texelLodOffset filters
|
||||
d[0] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(0, 1)).r;
|
||||
d[1] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(1, 1)).r;
|
||||
d[2] = texelFetchOffset(map, ivec3(st, layer), 0, ivec2(1, 0)).r;
|
||||
@@ -271,9 +253,7 @@ float filterPCSS(const mediump sampler2DArray map,
|
||||
* see "Shadow of Cold War", A scalable approach to shadowing -- by Kevin Myers
|
||||
*/
|
||||
float ShadowSample_DPCF(const bool DIRECTIONAL,
|
||||
const mediump sampler2DArray map,
|
||||
const highp vec4 scissorNormalized,
|
||||
const uint layer, const uint index,
|
||||
const mediump sampler2DArray map, const uint layer, const uint index,
|
||||
const highp vec4 shadowPosition, const highp float zLight) {
|
||||
highp vec3 position = shadowPosition.xyz * (1.0 / shadowPosition.w);
|
||||
highp vec2 texelSize = vec2(1.0) / vec2(textureSize(map, 0));
|
||||
@@ -291,7 +271,7 @@ float ShadowSample_DPCF(const bool DIRECTIONAL,
|
||||
float z_occSum = 0.0;
|
||||
|
||||
blockerSearchAndFilter(occludedCount, z_occSum,
|
||||
map, scissorNormalized, position.xy, position.z, layer, texelSize * penumbra, R, dz_duv,
|
||||
map, position.xy, position.z, layer, texelSize * penumbra, R, dz_duv,
|
||||
DPCF_SHADOW_TAP_COUNT);
|
||||
|
||||
// early exit if there is no occluders at all, also avoids a divide-by-zero below.
|
||||
@@ -318,9 +298,7 @@ float ShadowSample_DPCF(const bool DIRECTIONAL,
|
||||
}
|
||||
|
||||
float ShadowSample_PCSS(const bool DIRECTIONAL,
|
||||
const mediump sampler2DArray map,
|
||||
const highp vec4 scissorNormalized,
|
||||
const uint layer, const uint index,
|
||||
const mediump sampler2DArray map, const uint layer, const uint index,
|
||||
const highp vec4 shadowPosition, const highp float zLight) {
|
||||
highp vec2 size = vec2(textureSize(map, 0));
|
||||
highp vec2 texelSize = vec2(1.0) / size;
|
||||
@@ -339,7 +317,7 @@ float ShadowSample_PCSS(const bool DIRECTIONAL,
|
||||
float z_occSum = 0.0;
|
||||
|
||||
blockerSearchAndFilter(occludedCount, z_occSum,
|
||||
map, scissorNormalized, position.xy, position.z, layer, texelSize * penumbra, R, dz_duv,
|
||||
map, position.xy, position.z, layer, texelSize * penumbra, R, dz_duv,
|
||||
PCSS_SHADOW_BLOCKER_SEARCH_TAP_COUNT);
|
||||
|
||||
// early exit if there is no occluders at all, also avoids a divide-by-zero below.
|
||||
@@ -349,8 +327,7 @@ float ShadowSample_PCSS(const bool DIRECTIONAL,
|
||||
|
||||
float penumbraRatio = getPenumbraRatio(DIRECTIONAL, index, position.z, z_occSum / occludedCount);
|
||||
|
||||
float percentageOccluded = filterPCSS(map, scissorNormalized, size,
|
||||
position.xy, position.z, layer,
|
||||
float percentageOccluded = filterPCSS(map, size, position.xy, position.z, layer,
|
||||
texelSize * (penumbra * penumbraRatio),
|
||||
R, dz_duv, PCSS_SHADOW_FILTER_TAP_COUNT);
|
||||
|
||||
@@ -467,7 +444,6 @@ float evaluateShadowVSM(const highp vec2 moments, const highp float depth) {
|
||||
}
|
||||
|
||||
float ShadowSample_VSM(const bool ELVSM, const mediump sampler2DArray shadowMap,
|
||||
const highp vec4 scissorNormalized,
|
||||
const uint layer, const highp vec4 shadowPosition) {
|
||||
|
||||
// note: shadowPosition.z is in linear light-space normalized to [0, 1]
|
||||
@@ -475,10 +451,6 @@ float ShadowSample_VSM(const bool ELVSM, const mediump sampler2DArray shadowMap,
|
||||
// see: computeLightSpacePosition() in common_shadowing.fs
|
||||
highp vec3 position = vec3(shadowPosition.xy * (1.0 / shadowPosition.w), shadowPosition.z);
|
||||
|
||||
// Note: we don't need to clamp to `scissorNormalized` in the VSM case because this is only
|
||||
// needed when the shadow casters and receivers are different, which is never the case with VSM
|
||||
// (see ShadowMap.cpp).
|
||||
|
||||
// Read the shadow map with all available filtering
|
||||
highp vec4 moments = texture(shadowMap, vec3(position.xy, layer));
|
||||
highp float depth = position.z;
|
||||
@@ -506,75 +478,107 @@ float ShadowSample_VSM(const bool ELVSM, const mediump sampler2DArray shadowMap,
|
||||
*/
|
||||
|
||||
// get texture coordinate for directional and spot shadow maps
|
||||
highp vec4 getShadowPosition(const bool DIRECTIONAL,
|
||||
const uint index, const uint cascade, const highp float zLight) {
|
||||
highp vec4 p;
|
||||
// This conditional is resolved at compile time
|
||||
if (DIRECTIONAL) {
|
||||
#if defined(VARIANT_HAS_DIRECTIONAL_LIGHTING)
|
||||
highp vec4 getShadowPosition(const uint cascade) {
|
||||
return getCascadeLightSpacePosition(cascade);
|
||||
}
|
||||
p = getCascadeLightSpacePosition(cascade);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
#if defined(VARIANT_HAS_DYNAMIC_LIGHTING)
|
||||
highp vec4 getShadowPosition(const uint index, const highp vec3 dir, const highp float zLight) {
|
||||
return getSpotLightSpacePosition(index, dir, zLight);
|
||||
}
|
||||
p = getSpotLightSpacePosition(index, zLight);
|
||||
#endif
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
uint getPointLightFace(const highp vec3 r) {
|
||||
// get {texture coordinate, layer} for point shadow maps
|
||||
highp vec4 getShadowPosition(const highp vec3 r, const highp vec4 nf,
|
||||
inout uint layer, out highp float d) {
|
||||
highp vec4 tc;
|
||||
highp float rx = abs(r.x);
|
||||
highp float ry = abs(r.y);
|
||||
highp float rz = abs(r.z);
|
||||
highp float d = max(rx, max(ry, rz));
|
||||
d = max(rx, max(ry, rz));
|
||||
highp float ma = 1.0 / d;
|
||||
if (d == rx) {
|
||||
return (r.x >= 0.0 ? 0u : 1u);
|
||||
tc.x = r.x >= 0.0 ? r.z : -r.z;
|
||||
tc.y = r.y;
|
||||
layer += (r.x >= 0.0 ? 0u : 1u);
|
||||
} else if (d == ry) {
|
||||
return (r.y >= 0.0 ? 2u : 3u);
|
||||
tc.x = r.y >= 0.0 ? r.x : -r.x;
|
||||
tc.y = r.z;
|
||||
layer += (r.y >= 0.0 ? 2u : 3u);
|
||||
} else {
|
||||
return (r.z >= 0.0 ? 4u : 5u);
|
||||
tc.x = r.z >= 0.0 ? -r.x : r.x;
|
||||
tc.y = r.y;
|
||||
layer += (r.z >= 0.0 ? 4u : 5u);
|
||||
}
|
||||
|
||||
// ma is guaranteed to be >= sc and tc
|
||||
tc.xy = (tc.xy * ma + vec2(1.0)) * 0.5;
|
||||
|
||||
// z coordinate of the normalized fragment position in light-space
|
||||
// i.e.: remap [near, far] to [0,1] : d = (d - n) / (f - n)
|
||||
d = nf[2] + nf[3] * d;
|
||||
|
||||
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_EVSM) {
|
||||
// for VSM, the depth metric is linear normalized in light-space
|
||||
tc.z = d;
|
||||
} else {
|
||||
// for other types of shadows it's clip-space depth. Below is an optimized version of
|
||||
// (lightProjection * position).z
|
||||
tc.z = nf[0] + nf[1] * ma;
|
||||
}
|
||||
|
||||
// FIXME: the normal bias is not applied
|
||||
|
||||
tc.w = 1.0;
|
||||
return tc;
|
||||
}
|
||||
|
||||
// PCF sampling
|
||||
float shadow(const bool DIRECTIONAL,
|
||||
const mediump sampler2DArrayShadow shadowMap,
|
||||
const uint index, highp vec4 shadowPosition, highp float zLight) {
|
||||
highp vec4 scissorNormalized = shadowUniforms.shadows[index].scissorNormalized;
|
||||
uint layer = shadowUniforms.shadows[index].layer;
|
||||
const uint layer, const uint index, highp vec4 shadowPosition, highp float zLight) {
|
||||
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
|
||||
return ShadowSample_PCF_Hard(shadowMap, scissorNormalized, layer, shadowPosition);
|
||||
return ShadowSample_PCF_Hard(shadowMap, layer, shadowPosition);
|
||||
#elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
|
||||
return ShadowSample_PCF_Low(shadowMap, scissorNormalized, layer, shadowPosition);
|
||||
return ShadowSample_PCF_Low(shadowMap, layer, shadowPosition);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Shadow requiring a sampler2D sampler (VSM, DPCF and PCSS)
|
||||
float shadow(const bool DIRECTIONAL,
|
||||
const mediump sampler2DArray shadowMap,
|
||||
const uint index, highp vec4 shadowPosition, highp float zLight) {
|
||||
highp vec4 scissorNormalized = shadowUniforms.shadows[index].scissorNormalized;
|
||||
uint layer = shadowUniforms.shadows[index].layer;
|
||||
const uint layer, const uint index, highp vec4 shadowPosition, highp float zLight) {
|
||||
|
||||
// This conditional is resolved at compile time
|
||||
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_EVSM) {
|
||||
bool elvsm = shadowUniforms.shadows[index].elvsm;
|
||||
return ShadowSample_VSM(elvsm, shadowMap, scissorNormalized, layer,
|
||||
shadowPosition);
|
||||
bool elvsm = false;
|
||||
if (DIRECTIONAL) {
|
||||
elvsm = bool((frameUniforms.cascades >> 31u) & 1u);
|
||||
} else {
|
||||
elvsm = shadowUniforms.shadows[index].elvsm;
|
||||
}
|
||||
return ShadowSample_VSM(elvsm, shadowMap, layer, shadowPosition);
|
||||
}
|
||||
|
||||
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_DPCF) {
|
||||
return ShadowSample_DPCF(DIRECTIONAL, shadowMap, scissorNormalized, layer, index,
|
||||
shadowPosition, zLight);
|
||||
return ShadowSample_DPCF(DIRECTIONAL, shadowMap, layer, index, shadowPosition, zLight);
|
||||
}
|
||||
|
||||
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_PCSS) {
|
||||
return ShadowSample_PCSS(DIRECTIONAL, shadowMap, scissorNormalized, layer, index,
|
||||
shadowPosition, zLight);
|
||||
return ShadowSample_PCSS(DIRECTIONAL, shadowMap, layer, index, shadowPosition, zLight);
|
||||
}
|
||||
|
||||
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_PCF) {
|
||||
// This is here mostly for debugging at this point.
|
||||
// Note: In this codepath, the normal bias is not applied because we're in the VSM variant.
|
||||
// (see: get{Cascade|Spot}LightSpacePosition)
|
||||
return ShadowSample_PCF(shadowMap, scissorNormalized,
|
||||
layer, shadowPosition);
|
||||
return ShadowSample_PCF(shadowMap, layer, shadowPosition);
|
||||
}
|
||||
|
||||
// should not happen
|
||||
|
||||
+6
-6
@@ -33,6 +33,12 @@
|
||||
#include "SDL_video.h"
|
||||
#include "SDL_version.h"
|
||||
|
||||
#include "begin_code.h"
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \file SDL_syswm.h
|
||||
*
|
||||
@@ -104,12 +110,6 @@ typedef void *EGLSurface;
|
||||
#include "SDL_egl.h"
|
||||
#endif
|
||||
|
||||
#include "begin_code.h"
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* These are the various supported windowing subsystems
|
||||
*/
|
||||
|
||||
@@ -164,7 +164,6 @@ Filament.loadGeneratedExtensions = function() {
|
||||
const options = {
|
||||
anisotropy: 0,
|
||||
mipmapping: false,
|
||||
msaaSamples: 1,
|
||||
highPrecision: false,
|
||||
minVarianceScale: 0.5,
|
||||
lightBleedReduction: 0.15,
|
||||
|
||||
Vendored
+2
-20
@@ -417,13 +417,7 @@ export class Camera {
|
||||
|
||||
export class ColorGrading$Builder {
|
||||
public quality(qualityLevel: ColorGrading$QualityLevel): ColorGrading$Builder;
|
||||
public format(format: ColorGrading$LutFormat): ColorGrading$Builder;
|
||||
public dimensions(dim: number): ColorGrading$Builder;
|
||||
public toneMapping(toneMapping: ColorGrading$ToneMapping): ColorGrading$Builder;
|
||||
public luminanceScaling(luminanceScaling: boolean): ColorGrading$Builder;
|
||||
public gamutMapping(gamutMapping: boolean): ColorGrading$Builder;
|
||||
public exposure(exposure: number): ColorGrading$Builder;
|
||||
public nightAdaptation(adaptation: boolean): ColorGrading$Builder;
|
||||
public whiteBalance(temperature: number, tint: number): ColorGrading$Builder;
|
||||
public channelMixer(outRed: float3, outGreen: float3, outBlue: float3): ColorGrading$Builder;
|
||||
public shadowsMidtonesHighlights(shadows: float4, midtones: float4, highlights: float4,
|
||||
@@ -677,17 +671,12 @@ export enum Camera$Projection {
|
||||
ORTHO,
|
||||
}
|
||||
|
||||
export enum ColorGrading$QualityLevel {
|
||||
export enum ColorGrading$QualityLevel {
|
||||
LOW,
|
||||
MEDIUM,
|
||||
HIGH,
|
||||
ULTRA,
|
||||
}
|
||||
|
||||
export enum ColorGrading$LutFormat {
|
||||
INTEGER,
|
||||
FLOAT,
|
||||
}
|
||||
}
|
||||
|
||||
export enum ColorGrading$ToneMapping {
|
||||
LINEAR,
|
||||
@@ -1678,13 +1667,6 @@ export interface View$VsmShadowOptions {
|
||||
* Whether to generate mipmaps for all VSM shadow maps.
|
||||
*/
|
||||
mipmapping?: boolean;
|
||||
/**
|
||||
* The number of MSAA samples to use when rendering VSM shadow maps.
|
||||
* Must be a power-of-two and greater than or equal to 1. A value of 1 effectively turns
|
||||
* off MSAA.
|
||||
* Higher values may not be available depending on the underlying hardware.
|
||||
*/
|
||||
msaaSamples?: number;
|
||||
/**
|
||||
* Whether to use a 32-bits or 16-bits texture format for VSM shadow maps. 32-bits
|
||||
* precision is rarely needed, but it does reduces light leaks as well as "fading"
|
||||
|
||||
@@ -747,40 +747,11 @@ class_<ColorBuilder>("ColorGrading$Builder")
|
||||
return &builder->quality(ql);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("format", ColorBuilder, (ColorBuilder* builder,
|
||||
ColorGrading::LutFormat format), {
|
||||
return &builder->format(format);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("dimensions", ColorBuilder, (ColorBuilder* builder, uint8_t dim), {
|
||||
return &builder->dimensions(dim);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("toneMapping", ColorBuilder, (ColorBuilder* builder,
|
||||
ColorGrading::ToneMapping tm), {
|
||||
return &builder->toneMapping(tm);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("luminanceScaling", ColorBuilder, (ColorBuilder* builder,
|
||||
bool luminanceScaling), {
|
||||
return &builder->luminanceScaling(luminanceScaling);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("gamutMapping", ColorBuilder, (ColorBuilder* builder,
|
||||
bool gamutMapping), {
|
||||
return &builder->gamutMapping(gamutMapping);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("exposure", ColorBuilder, (ColorBuilder* builder,
|
||||
float exposure), {
|
||||
return &builder->exposure(exposure);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("nightAdaptation", ColorBuilder, (ColorBuilder* builder,
|
||||
float adaptation), {
|
||||
return &builder->nightAdaptation(adaptation);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("whiteBalance", ColorBuilder, (ColorBuilder* builder, float temp,
|
||||
float tint), {
|
||||
return &builder->whiteBalance(temp, tint);
|
||||
|
||||
@@ -135,7 +135,6 @@ value_object<View::GuardBandOptions>("View$GuardBandOptions")
|
||||
value_object<View::VsmShadowOptions>("View$VsmShadowOptions")
|
||||
.field("anisotropy", &View::VsmShadowOptions::anisotropy)
|
||||
.field("mipmapping", &View::VsmShadowOptions::mipmapping)
|
||||
.field("msaaSamples", &View::VsmShadowOptions::msaaSamples)
|
||||
.field("highPrecision", &View::VsmShadowOptions::highPrecision)
|
||||
.field("minVarianceScale", &View::VsmShadowOptions::minVarianceScale)
|
||||
.field("lightBleedReduction", &View::VsmShadowOptions::lightBleedReduction)
|
||||
|
||||
@@ -147,10 +147,6 @@ enum_<ColorGrading::ToneMapping>("ColorGrading$ToneMapping")
|
||||
.value("FILMIC", ColorGrading::ToneMapping::FILMIC)
|
||||
.value("DISPLAY_RANGE", ColorGrading::ToneMapping::DISPLAY_RANGE);
|
||||
|
||||
enum_<ColorGrading::LutFormat>("ColorGrading$LutFormat")
|
||||
.value("INTEGER", ColorGrading::LutFormat::INTEGER)
|
||||
.value("FLOAT", ColorGrading::LutFormat::FLOAT);
|
||||
|
||||
enum_<Frustum::Plane>("Frustum$Plane")
|
||||
.value("LEFT", Frustum::Plane::LEFT)
|
||||
.value("RIGHT", Frustum::Plane::RIGHT)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.30.0",
|
||||
"version": "1.28.2",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user