Compare commits

..
Author SHA1 Message Date
Benjamin Doherty 6dbee125b3 Make some headers public so JobSystem.h can be used 2022-11-03 09:39:01 -07:00
79 changed files with 831 additions and 1495 deletions
+32 -56
View File
@@ -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
View File
@@ -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)
+4 -4
View File
@@ -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
View File
@@ -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
},
@@ -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 -1
View File
@@ -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.
+14
View File
@@ -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
+93
View File
@@ -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
View File
@@ -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"
}
}
-1
View File
@@ -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.
+1 -8
View File
@@ -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.
+1 -3
View File
@@ -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);
+14 -16
View File
@@ -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);
+37 -13
View File
@@ -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()) };
+2 -4
View File
@@ -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;
+1 -6
View File
@@ -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]));
+12 -31
View File
@@ -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));
+8
View File
@@ -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
-8
View File
@@ -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"
+19 -35
View File
@@ -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;
}
}
+3 -19
View File
@@ -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.
+1
View File
@@ -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();
}
+40 -1
View File
@@ -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);
+5 -1
View File
@@ -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
+4
View File
@@ -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,
-10
View File
@@ -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;
-1
View File
@@ -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
View File
@@ -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);
}
+9 -20
View File
@@ -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;
+76 -75
View File
@@ -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
};
}
+21 -8
View File
@@ -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
+1
View File
@@ -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);
}
+8 -18
View File
@@ -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);
+3 -10
View File
@@ -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)
+16 -14
View File
@@ -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);
+7 -2
View File
@@ -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;
+11 -37
View File
@@ -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);
}
+2 -2
View File
@@ -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");
+2 -5
View File
@@ -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
+21 -29
View File
@@ -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
+2 -13
View File
@@ -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;
+4 -3
View File
@@ -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();
+3 -3
View File
@@ -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) {
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -603,7 +603,7 @@ void FAssetLoader::recurseEntities(const cgltf_data* srcAsset, const cgltf_node*
}
}
if (node->light) {
if (node->light ) {
createLight(node->light, entity);
}
+4 -3
View File
@@ -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());
-20
View File
@@ -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
+4
View File
@@ -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
+2 -2
View File
@@ -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,
+4 -1
View File
@@ -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"
-3
View File
@@ -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"
+1 -1
View File
@@ -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 -2
View File
@@ -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;
};
+3 -3
View File
@@ -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
+5 -8
View File
@@ -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 {
+4 -4
View File
@@ -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
+4
View File
@@ -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.
+3 -2
View File
@@ -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) {
+13 -13
View File
@@ -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
View File
@@ -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)
+3 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
*/
-1
View File
@@ -164,7 +164,6 @@ Filament.loadGeneratedExtensions = function() {
const options = {
anisotropy: 0,
mipmapping: false,
msaaSamples: 1,
highPrecision: false,
minVarianceScale: 0.5,
lightBleedReduction: 0.15,
+2 -20
View File
@@ -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"
-29
View File
@@ -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);
-1
View File
@@ -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)
-4
View File
@@ -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 -1
View File
@@ -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",