Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31f96c9065 | ||
|
|
1305303f2e | ||
|
|
8532511107 | ||
|
|
b762ccb78c | ||
|
|
3296eb153c | ||
|
|
ae6d1028f7 | ||
|
|
92579b6307 | ||
|
|
315b53c339 | ||
|
|
c55d459986 | ||
|
|
7876695545 | ||
|
|
e1a1464c5d | ||
|
|
67ed5141bf | ||
|
|
b9d7a25b91 | ||
|
|
ba63ac63a0 | ||
|
|
1e77947758 | ||
|
|
53df4012fe | ||
|
|
d880fab93f | ||
|
|
fb8030b80a | ||
|
|
e2d009ff2a | ||
|
|
0a67ef4d80 | ||
|
|
79d6f46f1a | ||
|
|
6481fa2acf | ||
|
|
7638b3ddd9 | ||
|
|
fe474a9d7e | ||
|
|
81008abe06 | ||
|
|
ef1d079c53 | ||
|
|
5286dec70b | ||
|
|
d748dc590e | ||
|
|
93a0aec246 | ||
|
|
f3fa734793 | ||
|
|
33d3c3a897 | ||
|
|
bbabf3480b | ||
|
|
e7a8f471a1 | ||
|
|
d45a5cc926 | ||
|
|
361ba2afea | ||
|
|
78419cd992 | ||
|
|
cc7361dba5 | ||
|
|
5c0841ff56 | ||
|
|
10af183756 | ||
|
|
56e0e9a424 | ||
|
|
86a500c846 | ||
|
|
5b3f13fc1d | ||
|
|
1b1dfaa57c | ||
|
|
bf8c84bbe5 | ||
|
|
fb179cabbc | ||
|
|
a80ea743e8 | ||
|
|
97f8106909 | ||
|
|
d455899b93 | ||
|
|
63fe439a5e | ||
|
|
7847220aba | ||
|
|
d76ae4395b | ||
|
|
f994cb58ce | ||
|
|
52eb682498 | ||
|
|
5a5168a191 | ||
|
|
e85dfe75c8 | ||
|
|
6beb40b0a1 | ||
|
|
5cb96e5732 | ||
|
|
927aa57a4e | ||
|
|
36e775902d | ||
|
|
53e28f3b33 | ||
|
|
7ccbdb4633 | ||
|
|
f10d226565 | ||
|
|
28ecf5c35d | ||
|
|
9683eb649c | ||
|
|
3d10ae3ee3 | ||
|
|
44a75dd44b | ||
|
|
de7bcd2df7 | ||
|
|
6adf140fb4 | ||
|
|
b94c802076 | ||
|
|
b231de0b5b | ||
|
|
fca200d549 | ||
|
|
ba1d3f6c76 | ||
|
|
7734fd4ad9 | ||
|
|
7e6839f535 | ||
|
|
3d78322058 | ||
|
|
3e1ea7cdfd | ||
|
|
6d413a4faf | ||
|
|
af09c517b6 |
@@ -3,5 +3,5 @@ runs:
|
|||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- name: Set up dependency versions
|
- name: Set up dependency versions
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cat ./build/common/versions >> $GITHUB_ENV
|
run: cat ./build/common/versions >> $GITHUB_ENV
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
name: 'Web Preqrequisites'
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- uses: ./.github/actions/dep-versions
|
||||||
|
- name: Cache EMSDK
|
||||||
|
id: emsdk-cache
|
||||||
|
uses: actions/cache@v4 # Use a specific version
|
||||||
|
with:
|
||||||
|
path: emsdk
|
||||||
|
key: ${{ runner.os }}-emsdk-${{ env.GITHUB_EMSDK_VERSION }}
|
||||||
|
- name: Install Web Prerequisites
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
bash ./build/common/get-emscripten.sh
|
||||||
|
echo "EMSDK=$PWD/emsdk" >> $GITHUB_ENV
|
||||||
@@ -26,4 +26,4 @@ jobs:
|
|||||||
path: out/filament-release-darwin.tgz
|
path: out/filament-release-darwin.tgz
|
||||||
- name: Check public headers
|
- name: Check public headers
|
||||||
run: |
|
run: |
|
||||||
build/common/check-headers.sh out/release/filament/include
|
test/check-headers/test.sh out/release/filament/include
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: ./.github/actions/linux-prereq
|
- uses: ./.github/actions/linux-prereq
|
||||||
|
- uses: ./.github/actions/web-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
cd build/web && printf "y" | ./build.sh presubmit
|
cd build/web && printf "y" | ./build.sh presubmit
|
||||||
@@ -123,13 +124,15 @@ jobs:
|
|||||||
- uses: ./.github/actions/mac-prereq
|
- uses: ./.github/actions/mac-prereq
|
||||||
- name: Cache Mesa and deps
|
- name: Cache Mesa and deps
|
||||||
id: mesa-cache
|
id: mesa-cache
|
||||||
uses: actions/cache@v4 # Use a specific version
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: mesa
|
path: mesa
|
||||||
key: ${{ runner.os }}-mesa-deps-2-${{ vars.MESA_VERSION }}
|
key: ${{ runner.os }}-mesa-deps-2-${{ vars.MESA_VERSION }}
|
||||||
- name: Get Mesa
|
- name: Prerequisites
|
||||||
id: mesa-prereq
|
id: prereqs
|
||||||
run: bash test/utils/get_mesa.sh
|
run: |
|
||||||
|
bash build/common/get-mesa.sh
|
||||||
|
pip install tifffile numpy
|
||||||
- name: Run Test
|
- name: Run Test
|
||||||
run: bash test/renderdiff/test.sh
|
run: bash test/renderdiff/test.sh
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
@@ -150,8 +153,8 @@ jobs:
|
|||||||
- name: Run test
|
- name: Run test
|
||||||
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
||||||
|
|
||||||
code-correcteness:
|
test-code-correctness:
|
||||||
name: code-correctness
|
name: test-code-correctness
|
||||||
runs-on: 'macos-14-xlarge'
|
runs-on: 'macos-14-xlarge'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v4.1.6
|
||||||
|
|||||||
@@ -65,13 +65,9 @@ jobs:
|
|||||||
|
|
||||||
build-mac:
|
build-mac:
|
||||||
name: build-mac
|
name: build-mac
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: macos-14-xlarge
|
||||||
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
|
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [macos-14-xlarge, ubuntu-22.04-32core]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Decide Git ref
|
- name: Decide Git ref
|
||||||
id: git_ref
|
id: git_ref
|
||||||
@@ -118,6 +114,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: ${{ steps.git_ref.outputs.ref }}
|
ref: ${{ steps.git_ref.outputs.ref }}
|
||||||
- uses: ./.github/actions/linux-prereq
|
- uses: ./.github/actions/linux-prereq
|
||||||
|
- uses: ./.github/actions/web-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
env:
|
env:
|
||||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||||
@@ -166,6 +163,9 @@ jobs:
|
|||||||
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
|
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
|
||||||
mv out/gltfio-android-release.aar out/gltfio-${TAG}-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
|
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
|
||||||
|
cd out/android-release/filament
|
||||||
|
tar -czf ../../filament-${TAG}-android-native.tgz .
|
||||||
|
cd ../../..
|
||||||
- name: Sign sample-gltf-viewer
|
- name: Sign sample-gltf-viewer
|
||||||
run: |
|
run: |
|
||||||
echo "${APK_KEYSTORE_BASE64}" > filament.jks.base64
|
echo "${APK_KEYSTORE_BASE64}" > filament.jks.base64
|
||||||
@@ -187,7 +187,7 @@ jobs:
|
|||||||
script: |
|
script: |
|
||||||
const upload = require('./build/common/upload-release-assets');
|
const upload = require('./build/common/upload-release-assets');
|
||||||
const { TAG } = process.env;
|
const { TAG } = process.env;
|
||||||
const globber = await glob.create(['out/*.aar', 'out/*.apk'].join('\n'));
|
const globber = await glob.create(['out/*.aar', 'out/*.apk', 'out/*.tgz'].join('\n'));
|
||||||
await upload({ github, context }, await globber.glob(), TAG);
|
await upload({ github, context }, await globber.glob(), TAG);
|
||||||
|
|
||||||
build-ios:
|
build-ios:
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: ./.github/actions/linux-prereq
|
- uses: ./.github/actions/linux-prereq
|
||||||
|
- uses: ./.github/actions/web-prereq
|
||||||
- name: Run build script
|
- name: Run build script
|
||||||
run: |
|
run: |
|
||||||
cd build/web && printf "y" | ./build.sh continuous
|
cd build/web && printf "y" | ./build.sh continuous
|
||||||
|
|||||||
@@ -363,6 +363,8 @@ python ./emsdk.py activate latest
|
|||||||
source ./emsdk_env.sh
|
source ./emsdk_env.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Alternatively, you can try running the script `build/common/get-emscripten.sh`.
|
||||||
|
|
||||||
After this you can invoke the [easy build](#easy-build) script as follows:
|
After this you can invoke the [easy build](#easy-build) script as follows:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.google.android.filament:filament-android:1.59.4'
|
implementation 'com.google.android.filament:filament-android:1.60.1'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -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:
|
iOS projects can use CocoaPods to install the latest release:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pod 'Filament', '~> 1.59.4'
|
pod 'Filament', '~> 1.60.1'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|||||||
@@ -7,6 +7,22 @@ A new header is inserted each time a *tag* is created.
|
|||||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||||
|
|
||||||
|
## v1.61.0
|
||||||
|
|
||||||
|
- materials: sampler now export their type in the material binary [⚠️ **New Material Version**]
|
||||||
|
- samples/texturedquad.cpp now has CLI to select backend api
|
||||||
|
- samples/hellopbr.cpp CLI now allows for selecting webgpu
|
||||||
|
|
||||||
|
## v1.60.1
|
||||||
|
|
||||||
|
|
||||||
|
## v1.60.0
|
||||||
|
|
||||||
|
- materials: remove dependence on per-view descset layout from filamat. [⚠️ **New Material Version**]
|
||||||
|
- matc non-functional change: Update GLSL postprocessor to
|
||||||
|
isolate calls to SPVRemap from calls to SPIRV-Cross.
|
||||||
|
|
||||||
|
|
||||||
## v1.59.5
|
## v1.59.5
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1801,6 +1801,22 @@ public class View {
|
|||||||
* @see setAmbientOcclusionOptions()
|
* @see setAmbientOcclusionOptions()
|
||||||
*/
|
*/
|
||||||
public static class AmbientOcclusionOptions {
|
public static class AmbientOcclusionOptions {
|
||||||
|
public enum AmbientOcclusionType {
|
||||||
|
/**
|
||||||
|
* use Scalable Ambient Occlusion
|
||||||
|
*/
|
||||||
|
SAO,
|
||||||
|
/**
|
||||||
|
* use Ground Truth-Based Ambient Occlusion
|
||||||
|
*/
|
||||||
|
GTAO,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of ambient occlusion algorithm.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public AmbientOcclusionOptions.AmbientOcclusionType aoType = AmbientOcclusionOptions.AmbientOcclusionType.SAO;
|
||||||
/**
|
/**
|
||||||
* Ambient Occlusion radius in meters, between 0 and ~10.
|
* Ambient Occlusion radius in meters, between 0 and ~10.
|
||||||
*/
|
*/
|
||||||
@@ -1810,7 +1826,8 @@ public class View {
|
|||||||
*/
|
*/
|
||||||
public float power = 1.0f;
|
public float power = 1.0f;
|
||||||
/**
|
/**
|
||||||
* Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
* Self-occlusion bias in meters. Use to avoid self-occlusion.
|
||||||
|
* Between 0 and a few mm. No effect when aoType set to GTAO
|
||||||
*/
|
*/
|
||||||
public float bias = 0.0005f;
|
public float bias = 0.0005f;
|
||||||
/**
|
/**
|
||||||
@@ -1826,12 +1843,12 @@ public class View {
|
|||||||
*/
|
*/
|
||||||
public float bilateralThreshold = 0.05f;
|
public float bilateralThreshold = 0.05f;
|
||||||
/**
|
/**
|
||||||
* affects # of samples used for AO.
|
* affects # of samples used for AO and params for filtering
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public QualityLevel quality = QualityLevel.LOW;
|
public QualityLevel quality = QualityLevel.LOW;
|
||||||
/**
|
/**
|
||||||
* affects AO smoothness
|
* affects AO smoothness. Recommend setting to HIGH when aoType set to GTAO.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public QualityLevel lowPassFilter = QualityLevel.MEDIUM;
|
public QualityLevel lowPassFilter = QualityLevel.MEDIUM;
|
||||||
@@ -1849,7 +1866,7 @@ public class View {
|
|||||||
*/
|
*/
|
||||||
public boolean bentNormals = false;
|
public boolean bentNormals = false;
|
||||||
/**
|
/**
|
||||||
* min angle in radian to consider
|
* min angle in radian to consider. No effect when aoType set to GTAO.
|
||||||
*/
|
*/
|
||||||
public float minHorizonAngleRad = 0.0f;
|
public float minHorizonAngleRad = 0.0f;
|
||||||
/**
|
/**
|
||||||
@@ -1904,6 +1921,19 @@ public class View {
|
|||||||
*/
|
*/
|
||||||
public boolean ssctEnabled = false;
|
public boolean ssctEnabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||||
|
*/
|
||||||
|
public int gtaoSampleSliceCount = 4;
|
||||||
|
/**
|
||||||
|
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||||
|
*/
|
||||||
|
public int gtaoSampleStepsPerSlice = 3;
|
||||||
|
/**
|
||||||
|
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||||
|
*/
|
||||||
|
public float gtaoThicknessHeuristic = 0.004f;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
GROUP=com.google.android.filament
|
GROUP=com.google.android.filament
|
||||||
VERSION_NAME=1.59.4
|
VERSION_NAME=1.60.1
|
||||||
|
|
||||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ function print_fgviewer_help {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Unless explicitly specified, NDK version will be selected as highest available version within same major release chain
|
# Unless explicitly specified, NDK version will be selected as highest available version within same major release chain
|
||||||
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/android/ndk.version | cut -f 1 -d ".")}
|
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/common/versions | grep GITHUB_NDK_VERSION | sed s/GITHUB_NDK_VERSION=//g | cut -f 1 -d ".")}
|
||||||
|
|
||||||
# Requirements
|
# Requirements
|
||||||
CMAKE_MAJOR=3
|
CMAKE_MAJOR=3
|
||||||
@@ -463,16 +463,6 @@ function ensure_android_build {
|
|||||||
echo "Error: Android NDK side-by-side version ${FILAMENT_NDK_VERSION} or compatible must be installed, exiting"
|
echo "Error: Android NDK side-by-side version ${FILAMENT_NDK_VERSION} or compatible must be installed, exiting"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local cmake_version=$(cmake --version)
|
|
||||||
if [[ "${cmake_version}" =~ ([0-9]+)\.([0-9]+)\.[0-9]+ ]]; then
|
|
||||||
if [[ "${BASH_REMATCH[1]}" -lt "${CMAKE_MAJOR}" ]] || \
|
|
||||||
[[ "${BASH_REMATCH[2]}" -lt "${CMAKE_MINOR}" ]]; then
|
|
||||||
echo "Error: cmake version ${CMAKE_MAJOR}.${CMAKE_MINOR}+ is required," \
|
|
||||||
"${BASH_REMATCH[1]}.${BASH_REMATCH[2]} installed, exiting"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_android {
|
function build_android {
|
||||||
|
|||||||
@@ -1,28 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Usage: the first argument selects the build type:
|
source `dirname $0`/../common/ci-check.sh
|
||||||
# - release, to build release only
|
|
||||||
# - debug, to build debug only
|
|
||||||
# - continuous, to build release and debug
|
|
||||||
# - presubmit, for presubmit builds
|
|
||||||
#
|
|
||||||
# The default is release
|
|
||||||
|
|
||||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
|
||||||
echo "Please refer to BUILDING.md for more information."
|
|
||||||
|
|
||||||
read -r -p "Do you wish to proceed (y/n)? " choice
|
|
||||||
case "${choice}" in
|
|
||||||
y|Y)
|
|
||||||
echo "Build will proceed..."
|
|
||||||
;;
|
|
||||||
n|N)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
@@ -30,11 +8,6 @@ set -x
|
|||||||
UNAME=`echo $(uname)`
|
UNAME=`echo $(uname)`
|
||||||
LC_UNAME=`echo $UNAME | tr '[:upper:]' '[:lower:]'`
|
LC_UNAME=`echo $UNAME | tr '[:upper:]' '[:lower:]'`
|
||||||
|
|
||||||
# build-common.sh will generate the following variables:
|
|
||||||
# $GENERATE_ARCHIVES
|
|
||||||
# $BUILD_DEBUG
|
|
||||||
# $BUILD_RELEASE
|
|
||||||
source `dirname $0`/../common/ci-common.sh
|
|
||||||
source `dirname $0`/../common/build-common.sh
|
source `dirname $0`/../common/build-common.sh
|
||||||
|
|
||||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# build-common.sh will generate the following variables:
|
||||||
|
# $GENERATE_ARCHIVES
|
||||||
|
# $BUILD_DEBUG
|
||||||
|
# $BUILD_RELEASE
|
||||||
|
|
||||||
|
# Typically a build script (build.sh) would source this script. For example,
|
||||||
|
# source `dirname $0`/../common/build-common.sh
|
||||||
|
|
||||||
|
# Usage: the first argument selects the build type:
|
||||||
|
# - release, to build release only
|
||||||
|
# - debug, to build debug only
|
||||||
|
# - continuous, to build release and debug
|
||||||
|
# - presubmit, for presubmit builds
|
||||||
|
#
|
||||||
|
# The default is release
|
||||||
if [[ ! "$TARGET" ]]; then
|
if [[ ! "$TARGET" ]]; then
|
||||||
if [[ "$1" ]]; then
|
if [[ "$1" ]]; then
|
||||||
TARGET=$1
|
TARGET=$1
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
echo "This script is intended to run in a CI environment and may modify your current environment."
|
||||||
|
echo "Please refer to BUILDING.md for more information."
|
||||||
|
|
||||||
|
read -r -p "Do you wish to proceed (y/n)? " choice
|
||||||
|
case "${choice}" in
|
||||||
|
y|Y)
|
||||||
|
echo "Build will proceed..."
|
||||||
|
;;
|
||||||
|
n|N)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||||
|
echo "Running workflow $GITHUB_WORKFLOW (event: $GITHUB_EVENT_NAME, action: $GITHUB_ACTION)"
|
||||||
|
fi
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
|
||||||
echo "Running workflow $GITHUB_WORKFLOW (event: $GITHUB_EVENT_NAME, action: $GITHUB_ACTION)"
|
|
||||||
fi
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -d "./emsdk" ]; then
|
||||||
|
echo "emsdk folder found. Assume emsdk has been installed."
|
||||||
|
cd emsdk
|
||||||
|
./emsdk activate latest
|
||||||
|
source ./emsdk_env.sh
|
||||||
|
export EMSDK="$PWD"
|
||||||
|
cd ..
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install emscripten.
|
||||||
|
EMSDK_VERSION=${GITHUB_EMSDK_VERSION-3.1.60}
|
||||||
|
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/${EMSDK_VERSION}.zip > emsdk.zip
|
||||||
|
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
|
||||||
|
./emsdk install latest
|
||||||
|
./emsdk activate latest
|
||||||
|
source ./emsdk_env.sh
|
||||||
|
|
||||||
|
export EMSDK="$PWD"
|
||||||
|
cd ..
|
||||||
@@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
set -x
|
set -e
|
||||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||||
set -e
|
set -x
|
||||||
fi
|
fi
|
||||||
|
|
||||||
OS_NAME=$(uname -s)
|
OS_NAME=$(uname -s)
|
||||||
@@ -35,7 +35,7 @@ source ${ORIG_DIR}/venv/bin/activate
|
|||||||
|
|
||||||
NEEDED_PYTHON_DEPS=("mako" "setuptools" "pyyaml")
|
NEEDED_PYTHON_DEPS=("mako" "setuptools" "pyyaml")
|
||||||
for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
|
for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
|
||||||
if ! python3 -m pip show "${cmd}" >/dev/null 2>&1; then
|
if ! python3 -m pip show -q "${cmd}" >/dev/null 2>&1; then
|
||||||
python3 -m pip install ${cmd}
|
python3 -m pip install ${cmd}
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -145,6 +145,6 @@ deactivate
|
|||||||
popd
|
popd
|
||||||
|
|
||||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||||
set +e
|
set +x
|
||||||
fi
|
fi
|
||||||
set +x
|
set +e
|
||||||
@@ -3,4 +3,5 @@ GITHUB_CMAKE_VERSION=3.19.5
|
|||||||
GITHUB_NINJA_VERSION=1.10.2
|
GITHUB_NINJA_VERSION=1.10.2
|
||||||
GITHUB_MESA_VERSION=24.2.1
|
GITHUB_MESA_VERSION=24.2.1
|
||||||
GITHUB_LLVM_VERSION=16
|
GITHUB_LLVM_VERSION=16
|
||||||
GITHUB_NDK_VERSION=27.0.11718014
|
GITHUB_NDK_VERSION=27.0.11718014
|
||||||
|
GITHUB_EMSDK_VERSION=3.1.60
|
||||||
@@ -1,35 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Usage: the first argument selects the build type:
|
source `dirname $0`/../common/ci-check.sh
|
||||||
# - release, to build release only
|
|
||||||
# - debug, to build debug only
|
|
||||||
# - continuous, to build release and debug
|
|
||||||
# - presubmit, for presubmit builds
|
|
||||||
#
|
|
||||||
# The default is release
|
|
||||||
|
|
||||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
|
||||||
echo "Please refer to BUILDING.md for more information."
|
|
||||||
|
|
||||||
read -r -p "Do you wish to proceed (y/n)? " choice
|
|
||||||
case "${choice}" in
|
|
||||||
y|Y)
|
|
||||||
echo "Build will proceed..."
|
|
||||||
;;
|
|
||||||
n|N)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
source `dirname $0`/../common/ci-common.sh
|
|
||||||
source `dirname $0`/../common/build-common.sh
|
source `dirname $0`/../common/build-common.sh
|
||||||
|
|
||||||
pushd `dirname $0`/../.. > /dev/null
|
pushd `dirname $0`/../.. > /dev/null
|
||||||
|
|
||||||
# If we're generating an archive for release or continuous builds, then we'll also build for the
|
# If we're generating an archive for release or continuous builds, then we'll also build for the
|
||||||
|
|||||||
@@ -1,38 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Usage: the first argument selects the build type:
|
source `dirname $0`/../common/ci-check.sh
|
||||||
# - release, to build release only
|
|
||||||
# - debug, to build debug only
|
|
||||||
# - continuous, to build release and debug
|
|
||||||
# - presubmit, for presubmit builds
|
|
||||||
#
|
|
||||||
# The default is release
|
|
||||||
|
|
||||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
|
||||||
echo "Please refer to BUILDING.md for more information."
|
|
||||||
|
|
||||||
read -r -p "Do you wish to proceed (y/n)? " choice
|
|
||||||
case "${choice}" in
|
|
||||||
y|Y)
|
|
||||||
echo "Build will proceed..."
|
|
||||||
;;
|
|
||||||
n|N)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
# build-common.sh will generate the following variables:
|
|
||||||
# $GENERATE_ARCHIVES
|
|
||||||
# $BUILD_DEBUG
|
|
||||||
# $BUILD_RELEASE
|
|
||||||
source `dirname $0`/../common/ci-common.sh
|
|
||||||
source `dirname $0`/../common/build-common.sh
|
source `dirname $0`/../common/build-common.sh
|
||||||
|
|
||||||
pushd `dirname $0`/../.. > /dev/null
|
pushd `dirname $0`/../.. > /dev/null
|
||||||
|
|
||||||
./build.sh -c $RUN_TESTS $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
./build.sh -c $RUN_TESTS $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
||||||
|
|||||||
@@ -1,34 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Usage: the first argument selects the build type:
|
source `dirname $0`/../common/ci-check.sh
|
||||||
# - release, to build release only
|
|
||||||
# - debug, to build debug only
|
|
||||||
# - continuous, to build release and debug
|
|
||||||
# - presubmit, for presubmit builds
|
|
||||||
#
|
|
||||||
# The default is release
|
|
||||||
|
|
||||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
|
||||||
echo "Please refer to BUILDING.md for more information."
|
|
||||||
|
|
||||||
read -r -p "Do you wish to proceed (y/n)? " choice
|
|
||||||
case "${choice}" in
|
|
||||||
y|Y)
|
|
||||||
echo "Build will proceed..."
|
|
||||||
;;
|
|
||||||
n|N)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
source `dirname $0`/../common/ci-common.sh
|
|
||||||
source `dirname $0`/../common/build-common.sh
|
source `dirname $0`/../common/build-common.sh
|
||||||
|
|
||||||
pushd `dirname $0`/../.. > /dev/null
|
pushd `dirname $0`/../.. > /dev/null
|
||||||
|
|
||||||
./build.sh -c $RUN_TESTS $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
./build.sh -c $RUN_TESTS $GENERATE_ARCHIVES $BUILD_DEBUG $BUILD_RELEASE
|
||||||
|
|||||||
@@ -1,34 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Usage: the first argument selects the build type:
|
source `dirname $0`/../common/ci-check.sh
|
||||||
# - release, to build release only
|
|
||||||
# - debug, to build debug only
|
|
||||||
# - continuous, to build release and debug
|
|
||||||
# - presubmit, for presubmit builds
|
|
||||||
#
|
|
||||||
# The default is release
|
|
||||||
|
|
||||||
echo "This script is intended to run in a CI environment and may modify your current environment."
|
|
||||||
echo "Please refer to BUILDING.md for more information."
|
|
||||||
|
|
||||||
read -r -p "Do you wish to proceed (y/n)? " choice
|
|
||||||
case "${choice}" in
|
|
||||||
y|Y)
|
|
||||||
echo "Build will proceed..."
|
|
||||||
;;
|
|
||||||
n|N)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
source `dirname $0`/../common/ci-common.sh
|
|
||||||
source `dirname $0`/ci-common.sh
|
|
||||||
source `dirname $0`/../common/build-common.sh
|
source `dirname $0`/../common/build-common.sh
|
||||||
pushd `dirname $0`/../.. > /dev/null
|
pushd `dirname $0`/../.. > /dev/null
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Install emscripten.
|
|
||||||
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.60.zip > emsdk.zip
|
|
||||||
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
|
|
||||||
./emsdk install latest
|
|
||||||
./emsdk activate latest
|
|
||||||
source ./emsdk_env.sh
|
|
||||||
|
|
||||||
export EMSDK="$PWD"
|
|
||||||
cd ..
|
|
||||||
@@ -1023,8 +1023,12 @@ samplerCubemap | Cubemap texture
|
|||||||
[Table [materialParamsTypes]: Material parameter types]
|
[Table [materialParamsTypes]: Material parameter types]
|
||||||
|
|
||||||
Samplers
|
Samplers
|
||||||
: Sampler types can also specify a `format` which can be either `int` or `float` (defaults to
|
: Sampler types can specify additional options:
|
||||||
`float`).
|
|
||||||
|
- `format`: either `int` or `float` (defaults to `float`).
|
||||||
|
- `stages`: array of strings containing the list of shader stages this
|
||||||
|
sampler can be accessed from. Each entry must be either `vertex` or
|
||||||
|
`fragment` (defaults to both).
|
||||||
|
|
||||||
Arrays
|
Arrays
|
||||||
: A parameter can define an array of values by appending `[size]` after the type name, where
|
: A parameter can define an array of values by appending `[size]` after the type name, where
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
- [Metal](./notes/metal_debugging.md)
|
- [Metal](./notes/metal_debugging.md)
|
||||||
- [Vulkan](./notes/vulkan_debugging.md)
|
- [Vulkan](./notes/vulkan_debugging.md)
|
||||||
- [SPIR-V](./notes/spirv_debugging.md)
|
- [SPIR-V](./notes/spirv_debugging.md)
|
||||||
|
- [Running with ASAN and UBSAN](./notes/asan_ubsan.md)
|
||||||
|
- [Using Instruments on macOS](./notes/instruments.md)
|
||||||
- [Libraries](./notes/libs.md)
|
- [Libraries](./notes/libs.md)
|
||||||
- [bluegl](./dup/bluegl.md)
|
- [bluegl](./dup/bluegl.md)
|
||||||
- [bluevk](./dup/bluevk.md)
|
- [bluevk](./dup/bluevk.md)
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Running with ASAN/UBSAN
|
||||||
|
|
||||||
|
## Enabling
|
||||||
|
|
||||||
|
When building though build.sh, pass the `-b` flag. This sets the cmake variable
|
||||||
|
`FILAMENT_ENABLE_ASAN_UBSAN=ON` which eventually passes `"-fsanitize=address -fsanitize=undefined"`
|
||||||
|
to all compile and link operations.
|
||||||
|
|
||||||
|
If building through CMake directly, or an IDE like CLion that doesn't use build.sh, instead pass
|
||||||
|
`-DFILAMENT_ENABLE_ASAN_UBSAN=ON` to cmake in order to get the same result.
|
||||||
|
|
||||||
|
## Getting memory leak detection on Mac
|
||||||
|
|
||||||
|
Memory leak detection isn't enabled by default on MacOS. There are two issues to address, first is
|
||||||
|
using a version of clang that supports memory leak detection and second is enabling it at runtime.
|
||||||
|
|
||||||
|
The version of clang distributed by Apple (with a version like "Apple clang version 16.0.0") doesn't
|
||||||
|
currently support leak detection at all. Instead you will need to get or build a different LLVM,
|
||||||
|
such as the one distributed through homebrew and get CMake to use that instead.
|
||||||
|
|
||||||
|
Then during runtime you'll need to have the environment variable `ASAN_OPTIONS` include the option
|
||||||
|
`detect_leaks=1`. Multiple `ASAN_OPTIONS` values are concatenated with `:`.
|
||||||
|
|
||||||
|
## Getting memory leak output in CLion
|
||||||
|
|
||||||
|
### Setting variables
|
||||||
|
|
||||||
|
Under `Settings | Build, Execution, Deployment | Dynamic Analysis Tools | Sanitizers` there is an
|
||||||
|
ASAN Settings field that overrides whatever other `ASAN_OPTIONS` you might set elsewhere, so you
|
||||||
|
must use that instead of setting it through your Run/Debug Configuration.
|
||||||
|
|
||||||
|
To pass `-DFILAMENT_ENABLE_ASAN_UBSAN=ON` to CMake you'll want to create a new CMake Profile and
|
||||||
|
pass it as a CMake argument.
|
||||||
|
|
||||||
|
### Avoiding losing output
|
||||||
|
|
||||||
|
CMake will consume ASAN output and display it through a separate "Sanitizers" tab. Unfortunately
|
||||||
|
certain leak detection errors that interrupt the executable seem to not show up in this tab, but are
|
||||||
|
still removed from the user-visible console output. If this is happening and you need to see the
|
||||||
|
unfiltered console output you'll need to go to `Settings | Build, Execution, Deployment | Dynamic
|
||||||
|
Analysis Tools | Sanitizers` and uncheck "Use visual representation for Sanitizer's output".
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Using Instruments on macOS
|
||||||
|
|
||||||
|
When running a binary under Instruments on macOS, you may run into the following issue when
|
||||||
|
launching or attaching to an executable:
|
||||||
|
|
||||||
|
```
|
||||||
|
Failed to gain authorization
|
||||||
|
Recovery Suggestion: Target binary needs to be debuggable and signed with 'get-task-allow'
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a security precaution; the solution is to code sign the binary with the
|
||||||
|
`com.apple.security.get-task-allow` entitlement.
|
||||||
|
|
||||||
|
1. Create an `entitlements.plist` file with the following contents:
|
||||||
|
|
||||||
|
```
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.get-task-allow</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
codesign -s - --entitlements entitlements.plist <binary>
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `<binary>` with the name of the binary, for example: `out/cmake-debug/samples/gltf_viewer`.
|
||||||
|
|
||||||
|
Afterwards, you should be able to successfully launch and attach to the executable using
|
||||||
|
Instruments.
|
||||||
@@ -262,6 +262,8 @@ set(MATERIAL_SRCS
|
|||||||
src/materials/ssao/mipmapDepth.mat
|
src/materials/ssao/mipmapDepth.mat
|
||||||
src/materials/ssao/sao.mat
|
src/materials/ssao/sao.mat
|
||||||
src/materials/ssao/saoBentNormals.mat
|
src/materials/ssao/saoBentNormals.mat
|
||||||
|
src/materials/ssao/gtao.mat
|
||||||
|
src/materials/ssao/gtaoBentNormals.mat
|
||||||
src/materials/vsmMipmap.mat
|
src/materials/vsmMipmap.mat
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -318,8 +320,6 @@ endif()
|
|||||||
# Definitions
|
# Definitions
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
|
|
||||||
# "2" corresponds to SYSTRACE_TAG_FILEMENT (See: utils/Systrace.h)
|
|
||||||
add_definitions(-DSYSTRACE_TAG=2)
|
|
||||||
add_definitions(-DFILAMENT_DFG_LUT_SIZE=${DFG_LUT_SIZE})
|
add_definitions(-DFILAMENT_DFG_LUT_SIZE=${DFG_LUT_SIZE})
|
||||||
add_definitions(
|
add_definitions(
|
||||||
-DFILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB=${FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB}
|
-DFILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB=${FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB}
|
||||||
@@ -463,6 +463,28 @@ add_custom_command(
|
|||||||
APPEND
|
APPEND
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${MATERIAL_DIR}/gtao.filamat"
|
||||||
|
DEPENDS src/materials/ssao/ssaoUtils.fs
|
||||||
|
DEPENDS src/materials/ssao/ssct.fs
|
||||||
|
DEPENDS src/materials/utils/depthUtils.fs
|
||||||
|
DEPENDS src/materials/utils/geometry.fs
|
||||||
|
DEPENDS src/materials/ssao/gtaoImpl.fs
|
||||||
|
DEPENDS src/materials/ssao/ssctImpl.fs
|
||||||
|
APPEND
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${MATERIAL_DIR}/gtaoBentNormals.filamat"
|
||||||
|
DEPENDS src/materials/ssao/ssaoUtils.fs
|
||||||
|
DEPENDS src/materials/ssao/ssct.fs
|
||||||
|
DEPENDS src/materials/utils/depthUtils.fs
|
||||||
|
DEPENDS src/materials/utils/geometry.fs
|
||||||
|
DEPENDS src/materials/ssao/gtaoImpl.fs
|
||||||
|
DEPENDS src/materials/ssao/ssctImpl.fs
|
||||||
|
APPEND
|
||||||
|
)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT "${MATERIAL_DIR}/bilateralBlur.filamat"
|
OUTPUT "${MATERIAL_DIR}/bilateralBlur.filamat"
|
||||||
DEPENDS src/materials/ssao/ssaoUtils.fs
|
DEPENDS src/materials/ssao/ssaoUtils.fs
|
||||||
|
|||||||
@@ -5,18 +5,6 @@ set(TARGET backend)
|
|||||||
set(PUBLIC_HDR_DIR include)
|
set(PUBLIC_HDR_DIR include)
|
||||||
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
# ==================================================================================================
|
|
||||||
# Compilation options
|
|
||||||
# ==================================================================================================
|
|
||||||
#
|
|
||||||
set(BACKEND_SANITIZATION "" CACHE STRING "Sanitization option")
|
|
||||||
set_property(CACHE BACKEND_SANITIZATION PROPERTY STRINGS ";ASAN")
|
|
||||||
|
|
||||||
set(BACKEND_SANITIZERS)
|
|
||||||
if (BACKEND_SANITIZATION STREQUAL "ASAN")
|
|
||||||
set(BACKEND_SANITIZERS -fsanitize=address)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
# Sources and headers
|
# Sources and headers
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
@@ -302,12 +290,6 @@ if (ANDROID)
|
|||||||
list(APPEND SRCS src/BackendUtilsAndroid.cpp)
|
list(APPEND SRCS src/BackendUtilsAndroid.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# ==================================================================================================
|
|
||||||
# Definitions
|
|
||||||
# ==================================================================================================
|
|
||||||
# "2" corresponds to SYSTRACE_TAG_FILEMENT (See: utils/Systrace.h)
|
|
||||||
add_definitions(-DSYSTRACE_TAG=2 )
|
|
||||||
|
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
# Includes & target definition
|
# Includes & target definition
|
||||||
# ==================================================================================================
|
# ==================================================================================================
|
||||||
@@ -484,7 +466,6 @@ target_compile_options(${TARGET} PRIVATE
|
|||||||
${OSMESA_COMPILE_FLAGS}
|
${OSMESA_COMPILE_FLAGS}
|
||||||
$<$<CONFIG:Release>:${OPTIMIZATION_FLAGS}>
|
$<$<CONFIG:Release>:${OPTIMIZATION_FLAGS}>
|
||||||
$<$<AND:$<PLATFORM_ID:Darwin>,$<CONFIG:Release>>:${DARWIN_OPTIMIZATION_FLAGS}>
|
$<$<AND:$<PLATFORM_ID:Darwin>,$<CONFIG:Release>>:${DARWIN_OPTIMIZATION_FLAGS}>
|
||||||
${BACKEND_SANITIZERS}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (FILAMENT_SUPPORTS_METAL)
|
if (FILAMENT_SUPPORTS_METAL)
|
||||||
@@ -495,8 +476,6 @@ if (FILAMENT_SUPPORTS_WEBGPU)
|
|||||||
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
|
target_compile_definitions(${TARGET} PRIVATE $<$<BOOL:${FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING}>:FILAMENT_WEBGPU_IMMEDIATE_ERROR_HANDLING>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_options(${TARGET} PRIVATE ${BACKEND_SANITIZERS})
|
|
||||||
|
|
||||||
target_link_libraries(${TARGET} PRIVATE
|
target_link_libraries(${TARGET} PRIVATE
|
||||||
${OSMESA_LINKER_FLAGS}
|
${OSMESA_LINKER_FLAGS}
|
||||||
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
$<$<AND:$<PLATFORM_ID:Linux>,$<CONFIG:Release>>:${LINUX_LINKER_OPTIMIZATION_FLAGS}>
|
||||||
@@ -566,8 +545,6 @@ if (APPLE AND NOT IOS)
|
|||||||
test/test_RenderExternalImage.cpp)
|
test/test_RenderExternalImage.cpp)
|
||||||
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
|
add_library(backend_test STATIC ${BACKEND_TEST_SRC})
|
||||||
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
|
target_link_libraries(backend_test PUBLIC ${BACKEND_TEST_LIBS})
|
||||||
target_compile_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
|
|
||||||
target_link_options(backend_test PRIVATE ${BACKEND_SANITIZERS})
|
|
||||||
|
|
||||||
set(BACKEND_TEST_DEPS
|
set(BACKEND_TEST_DEPS
|
||||||
OSDependent
|
OSDependent
|
||||||
@@ -606,7 +583,6 @@ if (APPLE AND NOT IOS)
|
|||||||
# linker from removing "unused" symbols.
|
# linker from removing "unused" symbols.
|
||||||
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
|
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
|
||||||
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
|
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
|
||||||
target_link_options(backend_test_mac PRIVATE ${BACKEND_SANITIZERS})
|
|
||||||
|
|
||||||
# This is needed after XCode 15.3
|
# This is needed after XCode 15.3
|
||||||
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
|
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
|
||||||
@@ -616,8 +592,6 @@ endif()
|
|||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
|
add_executable(backend_test_linux test/linux_runner.cpp ${BACKEND_TEST_SRC})
|
||||||
target_compile_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
|
|
||||||
target_link_options(backend_test_linux PRIVATE ${BACKEND_SANITIZERS})
|
|
||||||
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
|
target_link_libraries(backend_test_linux PRIVATE ${BACKEND_TEST_LIBS})
|
||||||
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
|
set_target_properties(backend_test_linux PROPERTIES FOLDER Tests)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -20,10 +20,15 @@
|
|||||||
#define TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H
|
#define TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
class ostream;
|
||||||
|
} // namespace utils::io
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
class CallbackHandler;
|
class CallbackHandler;
|
||||||
@@ -89,8 +94,8 @@ public:
|
|||||||
* @param callback A callback used to release the CPU buffer from this BufferDescriptor
|
* @param callback A callback used to release the CPU buffer from this BufferDescriptor
|
||||||
* @param user An opaque user pointer passed to the callback function when it's called
|
* @param user An opaque user pointer passed to the callback function when it's called
|
||||||
*/
|
*/
|
||||||
BufferDescriptor(void const* buffer, size_t size,
|
BufferDescriptor(void const* buffer, size_t const size,
|
||||||
Callback callback = nullptr, void* user = nullptr) noexcept
|
Callback const callback = nullptr, void* user = nullptr) noexcept
|
||||||
: buffer(const_cast<void*>(buffer)), size(size), mCallback(callback), mUser(user) {
|
: buffer(const_cast<void*>(buffer)), size(size), mCallback(callback), mUser(user) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,11 +103,12 @@ public:
|
|||||||
* Creates a BufferDescriptor that references a CPU memory-buffer
|
* Creates a BufferDescriptor that references a CPU memory-buffer
|
||||||
* @param buffer Memory address of the CPU buffer to reference
|
* @param buffer Memory address of the CPU buffer to reference
|
||||||
* @param size Size of the CPU buffer in bytes
|
* @param size Size of the CPU buffer in bytes
|
||||||
|
* @param handler A custom handler for the callback
|
||||||
* @param callback A callback used to release the CPU buffer from this BufferDescriptor
|
* @param callback A callback used to release the CPU buffer from this BufferDescriptor
|
||||||
* @param user An opaque user pointer passed to the callback function when it's called
|
* @param user An opaque user pointer passed to the callback function when it's called
|
||||||
*/
|
*/
|
||||||
BufferDescriptor(void const* buffer, size_t size,
|
BufferDescriptor(void const* buffer, size_t const size,
|
||||||
CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept
|
CallbackHandler* handler, Callback const callback, void* user = nullptr) noexcept
|
||||||
: buffer(const_cast<void*>(buffer)), size(size),
|
: buffer(const_cast<void*>(buffer)), size(size),
|
||||||
mCallback(callback), mUser(user), mHandler(handler) {
|
mCallback(callback), mUser(user), mHandler(handler) {
|
||||||
}
|
}
|
||||||
@@ -116,8 +122,9 @@ public:
|
|||||||
*
|
*
|
||||||
* @param buffer Memory address of the CPU buffer to reference
|
* @param buffer Memory address of the CPU buffer to reference
|
||||||
* @param size Size of the CPU buffer in bytes
|
* @param size Size of the CPU buffer in bytes
|
||||||
|
* @param data A pointer to the data
|
||||||
* @param handler Handler to use to dispatch the callback, or nullptr for the default handler
|
* @param handler Handler to use to dispatch the callback, or nullptr for the default handler
|
||||||
* @return a new BufferDescriptor
|
* @return A new BufferDescriptor
|
||||||
*/
|
*/
|
||||||
template<typename T, void(T::*method)(void const*, size_t)>
|
template<typename T, void(T::*method)(void const*, size_t)>
|
||||||
static BufferDescriptor make(void const* buffer, size_t size, T* data,
|
static BufferDescriptor make(void const* buffer, size_t size, T* data,
|
||||||
@@ -164,7 +171,7 @@ public:
|
|||||||
* @param callback The new callback function
|
* @param callback The new callback function
|
||||||
* @param user An opaque user pointer passed to the callbeck function when it's called
|
* @param user An opaque user pointer passed to the callbeck function when it's called
|
||||||
*/
|
*/
|
||||||
void setCallback(Callback callback, void* user = nullptr) noexcept {
|
void setCallback(Callback const callback, void* user = nullptr) noexcept {
|
||||||
this->mCallback = callback;
|
this->mCallback = callback;
|
||||||
this->mUser = user;
|
this->mUser = user;
|
||||||
this->mHandler = nullptr;
|
this->mHandler = nullptr;
|
||||||
@@ -176,7 +183,7 @@ public:
|
|||||||
* @param callback The new callback function
|
* @param callback The new callback function
|
||||||
* @param user An opaque user pointer passed to the callbeck function when it's called
|
* @param user An opaque user pointer passed to the callbeck function when it's called
|
||||||
*/
|
*/
|
||||||
void setCallback(CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept {
|
void setCallback(CallbackHandler* handler, Callback const callback, void* user = nullptr) noexcept {
|
||||||
mCallback = callback;
|
mCallback = callback;
|
||||||
mUser = user;
|
mUser = user;
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
|
|
||||||
#include <backend/DriverApiForward.h>
|
#include <backend/DriverApiForward.h>
|
||||||
|
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -28,6 +26,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
class ostream;
|
||||||
|
} // namespace utils::io
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
void* allocateFromCommandStream(DriverApi& driver, size_t size, size_t alignment) noexcept;
|
void* allocateFromCommandStream(DriverApi& driver, size_t size, size_t alignment) noexcept;
|
||||||
|
|||||||
@@ -25,21 +25,26 @@
|
|||||||
#include <backend/PresentCallable.h>
|
#include <backend/PresentCallable.h>
|
||||||
|
|
||||||
#include <utils/BitmaskEnum.h>
|
#include <utils/BitmaskEnum.h>
|
||||||
|
#include <utils/CString.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/Invocable.h>
|
#include <utils/Invocable.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/StaticString.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <math/vec4.h>
|
#include <math/vec4.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
class ostream;
|
||||||
|
} // namespace utils::io
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types and enums used by filament's driver.
|
* Types and enums used by filament's driver.
|
||||||
*
|
*
|
||||||
@@ -158,7 +163,7 @@ enum class TimerQueryResult : int8_t {
|
|||||||
AVAILABLE = 1, // result is available
|
AVAILABLE = 1, // result is available
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr const char* backendToString(Backend backend) {
|
constexpr std::string_view to_string(Backend const backend) noexcept {
|
||||||
switch (backend) {
|
switch (backend) {
|
||||||
case Backend::NOOP:
|
case Backend::NOOP:
|
||||||
return "Noop";
|
return "Noop";
|
||||||
@@ -170,9 +175,10 @@ static constexpr const char* backendToString(Backend backend) {
|
|||||||
return "Metal";
|
return "Metal";
|
||||||
case Backend::WEBGPU:
|
case Backend::WEBGPU:
|
||||||
return "WebGPU";
|
return "WebGPU";
|
||||||
default:
|
case Backend::DEFAULT:
|
||||||
return "Unknown";
|
return "Default";
|
||||||
}
|
}
|
||||||
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,7 +195,7 @@ enum class ShaderLanguage {
|
|||||||
WGSL = 5,
|
WGSL = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) {
|
constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) noexcept {
|
||||||
switch (shaderLanguage) {
|
switch (shaderLanguage) {
|
||||||
case ShaderLanguage::ESSL1:
|
case ShaderLanguage::ESSL1:
|
||||||
return "ESSL 1.0";
|
return "ESSL 1.0";
|
||||||
@@ -204,6 +210,7 @@ static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguag
|
|||||||
case ShaderLanguage::WGSL:
|
case ShaderLanguage::WGSL:
|
||||||
return "WGSL";
|
return "WGSL";
|
||||||
}
|
}
|
||||||
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ShaderStage : uint8_t {
|
enum class ShaderStage : uint8_t {
|
||||||
@@ -221,7 +228,7 @@ enum class ShaderStageFlags : uint8_t {
|
|||||||
ALL_SHADER_STAGE_FLAGS = VERTEX | FRAGMENT | COMPUTE
|
ALL_SHADER_STAGE_FLAGS = VERTEX | FRAGMENT | COMPUTE
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage type) noexcept {
|
constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage type) noexcept {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ShaderStage::VERTEX:
|
case ShaderStage::VERTEX:
|
||||||
return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::VERTEX));
|
return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::VERTEX));
|
||||||
@@ -232,14 +239,239 @@ static inline constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class DescriptorType : uint8_t {
|
enum class TextureType : uint8_t {
|
||||||
UNIFORM_BUFFER,
|
FLOAT,
|
||||||
SHADER_STORAGE_BUFFER,
|
INT,
|
||||||
SAMPLER,
|
UINT,
|
||||||
INPUT_ATTACHMENT,
|
DEPTH,
|
||||||
SAMPLER_EXTERNAL
|
STENCIL,
|
||||||
|
DEPTH_STENCIL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::string_view to_string(TextureType type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case TextureType::FLOAT: return "FLOAT";
|
||||||
|
case TextureType::INT: return "INT";
|
||||||
|
case TextureType::UINT: return "UINT";
|
||||||
|
case TextureType::DEPTH: return "DEPTH";
|
||||||
|
case TextureType::STENCIL: return "STENCIL";
|
||||||
|
case TextureType::DEPTH_STENCIL: return "DEPTH_STENCIL";
|
||||||
|
}
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class DescriptorType : uint8_t {
|
||||||
|
SAMPLER_2D_FLOAT,
|
||||||
|
SAMPLER_2D_INT,
|
||||||
|
SAMPLER_2D_UINT,
|
||||||
|
SAMPLER_2D_DEPTH,
|
||||||
|
|
||||||
|
SAMPLER_2D_ARRAY_FLOAT,
|
||||||
|
SAMPLER_2D_ARRAY_INT,
|
||||||
|
SAMPLER_2D_ARRAY_UINT,
|
||||||
|
SAMPLER_2D_ARRAY_DEPTH,
|
||||||
|
|
||||||
|
SAMPLER_CUBE_FLOAT,
|
||||||
|
SAMPLER_CUBE_INT,
|
||||||
|
SAMPLER_CUBE_UINT,
|
||||||
|
SAMPLER_CUBE_DEPTH,
|
||||||
|
|
||||||
|
SAMPLER_CUBE_ARRAY_FLOAT,
|
||||||
|
SAMPLER_CUBE_ARRAY_INT,
|
||||||
|
SAMPLER_CUBE_ARRAY_UINT,
|
||||||
|
SAMPLER_CUBE_ARRAY_DEPTH,
|
||||||
|
|
||||||
|
SAMPLER_3D_FLOAT,
|
||||||
|
SAMPLER_3D_INT,
|
||||||
|
SAMPLER_3D_UINT,
|
||||||
|
|
||||||
|
SAMPLER_2D_MS_FLOAT,
|
||||||
|
SAMPLER_2D_MS_INT,
|
||||||
|
SAMPLER_2D_MS_UINT,
|
||||||
|
|
||||||
|
SAMPLER_2D_MS_ARRAY_FLOAT,
|
||||||
|
SAMPLER_2D_MS_ARRAY_INT,
|
||||||
|
SAMPLER_2D_MS_ARRAY_UINT,
|
||||||
|
|
||||||
|
SAMPLER_EXTERNAL,
|
||||||
|
UNIFORM_BUFFER,
|
||||||
|
SHADER_STORAGE_BUFFER,
|
||||||
|
INPUT_ATTACHMENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr bool isDepthDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool isFloatDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool isIntDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_2D_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_3D_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool isUnsignedIntDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_2D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_3D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is3dTypeDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_3D_INT:
|
||||||
|
case DescriptorType::SAMPLER_3D_UINT:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is2dTypeDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is2dArrayTypeDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool isCubeTypeDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool isCubeArrayTypeDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool isMultiSampledTypeDescriptor(DescriptorType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||||
|
return true;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::string_view to_string(DescriptorType type) noexcept {
|
||||||
|
#define DESCRIPTOR_TYPE_CASE(TYPE) case DescriptorType::TYPE: return #TYPE;
|
||||||
|
switch (type) {
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_FLOAT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_INT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_UINT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_DEPTH)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_FLOAT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_INT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_UINT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_DEPTH)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_FLOAT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_INT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_UINT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_DEPTH)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_FLOAT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_INT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_UINT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_DEPTH)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_3D_FLOAT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_3D_INT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_3D_UINT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_FLOAT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_INT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_UINT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_ARRAY_FLOAT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_ARRAY_INT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_ARRAY_UINT)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SAMPLER_EXTERNAL)
|
||||||
|
DESCRIPTOR_TYPE_CASE(UNIFORM_BUFFER)
|
||||||
|
DESCRIPTOR_TYPE_CASE(SHADER_STORAGE_BUFFER)
|
||||||
|
DESCRIPTOR_TYPE_CASE(INPUT_ATTACHMENT)
|
||||||
|
}
|
||||||
|
return "UNKNOWN";
|
||||||
|
#undef DESCRIPTOR_TYPE_CASE
|
||||||
|
}
|
||||||
|
|
||||||
enum class DescriptorFlags : uint8_t {
|
enum class DescriptorFlags : uint8_t {
|
||||||
NONE = 0x00,
|
NONE = 0x00,
|
||||||
DYNAMIC_OFFSET = 0x01
|
DYNAMIC_OFFSET = 0x01
|
||||||
@@ -250,6 +482,13 @@ using descriptor_set_t = uint8_t;
|
|||||||
using descriptor_binding_t = uint8_t;
|
using descriptor_binding_t = uint8_t;
|
||||||
|
|
||||||
struct DescriptorSetLayoutBinding {
|
struct DescriptorSetLayoutBinding {
|
||||||
|
static bool isSampler(DescriptorType type) noexcept {
|
||||||
|
return int(type) <= int(DescriptorType::SAMPLER_EXTERNAL);
|
||||||
|
}
|
||||||
|
static bool isBuffer(DescriptorType type) noexcept {
|
||||||
|
return type == DescriptorType::UNIFORM_BUFFER ||
|
||||||
|
type == DescriptorType::SHADER_STORAGE_BUFFER;
|
||||||
|
}
|
||||||
DescriptorType type;
|
DescriptorType type;
|
||||||
ShaderStageFlags stageFlags;
|
ShaderStageFlags stageFlags;
|
||||||
descriptor_binding_t binding;
|
descriptor_binding_t binding;
|
||||||
@@ -260,7 +499,7 @@ struct DescriptorSetLayoutBinding {
|
|||||||
// no uninitialized padding bytes.
|
// no uninitialized padding bytes.
|
||||||
// uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
|
// uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
|
||||||
|
|
||||||
friend inline bool operator==(DescriptorSetLayoutBinding const& lhs,
|
friend bool operator==(DescriptorSetLayoutBinding const& lhs,
|
||||||
DescriptorSetLayoutBinding const& rhs) noexcept {
|
DescriptorSetLayoutBinding const& rhs) noexcept {
|
||||||
return lhs.type == rhs.type &&
|
return lhs.type == rhs.type &&
|
||||||
lhs.flags == rhs.flags &&
|
lhs.flags == rhs.flags &&
|
||||||
@@ -293,7 +532,7 @@ enum class TargetBufferFlags : uint32_t {
|
|||||||
ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected.
|
ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected.
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept {
|
constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept {
|
||||||
if (index == 0u) return TargetBufferFlags::COLOR0;
|
if (index == 0u) return TargetBufferFlags::COLOR0;
|
||||||
if (index == 1u) return TargetBufferFlags::COLOR1;
|
if (index == 1u) return TargetBufferFlags::COLOR1;
|
||||||
if (index == 2u) return TargetBufferFlags::COLOR2;
|
if (index == 2u) return TargetBufferFlags::COLOR2;
|
||||||
@@ -450,6 +689,24 @@ enum class SamplerType : uint8_t {
|
|||||||
SAMPLER_CUBEMAP_ARRAY, //!< Cube map array texture (feature level 2)
|
SAMPLER_CUBEMAP_ARRAY, //!< Cube map array texture (feature level 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::string_view to_string(SamplerType const type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case SamplerType::SAMPLER_2D:
|
||||||
|
return "SAMPLER_2D";
|
||||||
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
|
return "SAMPLER_2D_ARRAY";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
return "SAMPLER_CUBEMAP";
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL:
|
||||||
|
return "SAMPLER_EXTERNAL";
|
||||||
|
case SamplerType::SAMPLER_3D:
|
||||||
|
return "SAMPLER_3D";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
return "SAMPLER_CUBEMAP_ARRAY";
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
//! Subpass type
|
//! Subpass type
|
||||||
enum class SubpassType : uint8_t {
|
enum class SubpassType : uint8_t {
|
||||||
SUBPASS_INPUT
|
SUBPASS_INPUT
|
||||||
@@ -463,6 +720,20 @@ enum class SamplerFormat : uint8_t {
|
|||||||
SHADOW = 3 //!< shadow sampler (PCF)
|
SHADOW = 3 //!< shadow sampler (PCF)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::string_view to_string(SamplerFormat const format) noexcept {
|
||||||
|
switch (format) {
|
||||||
|
case SamplerFormat::INT:
|
||||||
|
return "INT";
|
||||||
|
case SamplerFormat::UINT:
|
||||||
|
return "UINT";
|
||||||
|
case SamplerFormat::FLOAT:
|
||||||
|
return "FLOAT";
|
||||||
|
case SamplerFormat::SHADOW:
|
||||||
|
return "SHADOW";
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported element types
|
* Supported element types
|
||||||
*/
|
*/
|
||||||
@@ -502,6 +773,15 @@ enum class BufferObjectBinding : uint8_t {
|
|||||||
SHADER_STORAGE
|
SHADER_STORAGE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::string_view to_string(BufferObjectBinding type) noexcept {
|
||||||
|
switch (type) {
|
||||||
|
case BufferObjectBinding::VERTEX: return "VERTEX";
|
||||||
|
case BufferObjectBinding::UNIFORM: return "UNIFORM";
|
||||||
|
case BufferObjectBinding::SHADER_STORAGE: return "SHADER_STORAGE";
|
||||||
|
}
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
//! Face culling Mode
|
//! Face culling Mode
|
||||||
enum class CullingMode : uint8_t {
|
enum class CullingMode : uint8_t {
|
||||||
NONE, //!< No culling, front and back faces are visible
|
NONE, //!< No culling, front and back faces are visible
|
||||||
@@ -763,6 +1043,8 @@ enum class TextureFormat : uint16_t {
|
|||||||
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
|
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TextureType getTextureType(TextureFormat format) noexcept;
|
||||||
|
|
||||||
//! Bitmask describing the intended Texture Usage
|
//! Bitmask describing the intended Texture Usage
|
||||||
enum class TextureUsage : uint16_t {
|
enum class TextureUsage : uint16_t {
|
||||||
NONE = 0x0000,
|
NONE = 0x0000,
|
||||||
@@ -790,7 +1072,7 @@ enum class TextureSwizzle : uint8_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//! returns whether this format a depth format
|
//! returns whether this format a depth format
|
||||||
static constexpr bool isDepthFormat(TextureFormat format) noexcept {
|
constexpr bool isDepthFormat(TextureFormat format) noexcept {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case TextureFormat::DEPTH32F:
|
case TextureFormat::DEPTH32F:
|
||||||
case TextureFormat::DEPTH24:
|
case TextureFormat::DEPTH24:
|
||||||
@@ -803,7 +1085,7 @@ static constexpr bool isDepthFormat(TextureFormat format) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool isStencilFormat(TextureFormat format) noexcept {
|
constexpr bool isStencilFormat(TextureFormat format) noexcept {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case TextureFormat::STENCIL8:
|
case TextureFormat::STENCIL8:
|
||||||
case TextureFormat::DEPTH24_STENCIL8:
|
case TextureFormat::DEPTH24_STENCIL8:
|
||||||
@@ -814,7 +1096,7 @@ static constexpr bool isStencilFormat(TextureFormat format) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr bool isColorFormat(TextureFormat format) noexcept {
|
constexpr bool isColorFormat(TextureFormat format) noexcept {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
// Standard color formats
|
// Standard color formats
|
||||||
case TextureFormat::R8:
|
case TextureFormat::R8:
|
||||||
@@ -841,7 +1123,7 @@ inline constexpr bool isColorFormat(TextureFormat format) noexcept {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool isUnsignedIntFormat(TextureFormat format) {
|
constexpr bool isUnsignedIntFormat(TextureFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case TextureFormat::R8UI:
|
case TextureFormat::R8UI:
|
||||||
case TextureFormat::R16UI:
|
case TextureFormat::R16UI:
|
||||||
@@ -862,7 +1144,7 @@ static constexpr bool isUnsignedIntFormat(TextureFormat format) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool isSignedIntFormat(TextureFormat format) {
|
constexpr bool isSignedIntFormat(TextureFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case TextureFormat::R8I:
|
case TextureFormat::R8I:
|
||||||
case TextureFormat::R16I:
|
case TextureFormat::R16I:
|
||||||
@@ -884,35 +1166,35 @@ static constexpr bool isSignedIntFormat(TextureFormat format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! returns whether this format is a compressed format
|
//! returns whether this format is a compressed format
|
||||||
static constexpr bool isCompressedFormat(TextureFormat format) noexcept {
|
constexpr bool isCompressedFormat(TextureFormat format) noexcept {
|
||||||
return format >= TextureFormat::EAC_R11;
|
return format >= TextureFormat::EAC_R11;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! returns whether this format is an ETC2 compressed format
|
//! returns whether this format is an ETC2 compressed format
|
||||||
static constexpr bool isETC2Compression(TextureFormat format) noexcept {
|
constexpr bool isETC2Compression(TextureFormat format) noexcept {
|
||||||
return format >= TextureFormat::EAC_R11 && format <= TextureFormat::ETC2_EAC_SRGBA8;
|
return format >= TextureFormat::EAC_R11 && format <= TextureFormat::ETC2_EAC_SRGBA8;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! returns whether this format is an S3TC compressed format
|
//! returns whether this format is an S3TC compressed format
|
||||||
static constexpr bool isS3TCCompression(TextureFormat format) noexcept {
|
constexpr bool isS3TCCompression(TextureFormat format) noexcept {
|
||||||
return format >= TextureFormat::DXT1_RGB && format <= TextureFormat::DXT5_SRGBA;
|
return format >= TextureFormat::DXT1_RGB && format <= TextureFormat::DXT5_SRGBA;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept {
|
constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept {
|
||||||
return format >= TextureFormat::DXT1_SRGB && format <= TextureFormat::DXT5_SRGBA;
|
return format >= TextureFormat::DXT1_SRGB && format <= TextureFormat::DXT5_SRGBA;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! returns whether this format is an RGTC compressed format
|
//! returns whether this format is an RGTC compressed format
|
||||||
static constexpr bool isRGTCCompression(TextureFormat format) noexcept {
|
constexpr bool isRGTCCompression(TextureFormat format) noexcept {
|
||||||
return format >= TextureFormat::RED_RGTC1 && format <= TextureFormat::SIGNED_RED_GREEN_RGTC2;
|
return format >= TextureFormat::RED_RGTC1 && format <= TextureFormat::SIGNED_RED_GREEN_RGTC2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! returns whether this format is an BPTC compressed format
|
//! returns whether this format is an BPTC compressed format
|
||||||
static constexpr bool isBPTCCompression(TextureFormat format) noexcept {
|
constexpr bool isBPTCCompression(TextureFormat format) noexcept {
|
||||||
return format >= TextureFormat::RGB_BPTC_SIGNED_FLOAT && format <= TextureFormat::SRGB_ALPHA_BPTC_UNORM;
|
return format >= TextureFormat::RGB_BPTC_SIGNED_FLOAT && format <= TextureFormat::SRGB_ALPHA_BPTC_UNORM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool isASTCCompression(TextureFormat format) noexcept {
|
constexpr bool isASTCCompression(TextureFormat format) noexcept {
|
||||||
return format >= TextureFormat::RGBA_ASTC_4x4 && format <= TextureFormat::SRGB8_ALPHA8_ASTC_12x12;
|
return format >= TextureFormat::RGBA_ASTC_4x4 && format <= TextureFormat::SRGB8_ALPHA8_ASTC_12x12;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1033,19 +1315,23 @@ struct SamplerParams { // NOLINT
|
|||||||
assert_invariant(lhs.padding2 == 0);
|
assert_invariant(lhs.padding2 == 0);
|
||||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||||
return *pLhs == *pRhs;
|
return *pLhs < *pRhs;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool isFiltered() const noexcept {
|
||||||
|
return filterMag != SamplerMagFilter::NEAREST || filterMin != SamplerMinFilter::NEAREST;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend inline bool operator == (SamplerParams lhs, SamplerParams rhs) noexcept {
|
friend bool operator == (SamplerParams lhs, SamplerParams rhs) noexcept {
|
||||||
return SamplerParams::EqualTo{}(lhs, rhs);
|
return EqualTo{}(lhs, rhs);
|
||||||
}
|
}
|
||||||
friend inline bool operator != (SamplerParams lhs, SamplerParams rhs) noexcept {
|
friend bool operator != (SamplerParams lhs, SamplerParams rhs) noexcept {
|
||||||
return !SamplerParams::EqualTo{}(lhs, rhs);
|
return !EqualTo{}(lhs, rhs);
|
||||||
}
|
}
|
||||||
friend inline bool operator < (SamplerParams lhs, SamplerParams rhs) noexcept {
|
friend bool operator < (SamplerParams lhs, SamplerParams rhs) noexcept {
|
||||||
return SamplerParams::LessThan{}(lhs, rhs);
|
return LessThan{}(lhs, rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1095,15 +1381,15 @@ struct SamplerYcbcrConversion {// NOLINT
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend inline bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
friend bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||||
noexcept {
|
noexcept {
|
||||||
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||||
}
|
}
|
||||||
friend inline bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
friend bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||||
noexcept {
|
noexcept {
|
||||||
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||||
}
|
}
|
||||||
friend inline bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
friend bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||||
noexcept {
|
noexcept {
|
||||||
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
|
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
|
||||||
}
|
}
|
||||||
@@ -1139,6 +1425,7 @@ struct ExternalSamplerDatum {
|
|||||||
static_assert(sizeof(ExternalSamplerDatum) == 12);
|
static_assert(sizeof(ExternalSamplerDatum) == 12);
|
||||||
|
|
||||||
struct DescriptorSetLayout {
|
struct DescriptorSetLayout {
|
||||||
|
std::variant<utils::StaticString, utils::CString, std::monostate> label;
|
||||||
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
utils::FixedCapacityVector<DescriptorSetLayoutBinding> bindings;
|
||||||
|
|
||||||
// TODO: uncomment when needed
|
// TODO: uncomment when needed
|
||||||
|
|||||||
@@ -17,9 +17,6 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_HANDLE_H
|
#ifndef TNT_FILAMENT_BACKEND_HANDLE_H
|
||||||
#define TNT_FILAMENT_BACKEND_HANDLE_H
|
#define TNT_FILAMENT_BACKEND_HANDLE_H
|
||||||
|
|
||||||
#if !defined(NDEBUG)
|
|
||||||
#include <utils/ostream.h>
|
|
||||||
#endif
|
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
|
|
||||||
#include <type_traits> // FIXME: STL headers are not allowed in public headers
|
#include <type_traits> // FIXME: STL headers are not allowed in public headers
|
||||||
@@ -27,6 +24,10 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
class ostream;
|
||||||
|
} // namespace utils::io
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
struct HwBufferObject;
|
struct HwBufferObject;
|
||||||
|
|||||||
@@ -20,12 +20,14 @@
|
|||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/Handle.h>
|
#include <backend/Handle.h>
|
||||||
|
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
class ostream;
|
||||||
|
} // namespace utils::io
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
//! \privatesection
|
//! \privatesection
|
||||||
|
|||||||
@@ -24,11 +24,14 @@
|
|||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
class ostream;
|
||||||
|
} // namespace utils::io
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,23 +204,15 @@ public:
|
|||||||
}, new T(std::forward<T>(functor))
|
}, new T(std::forward<T>(functor))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the size in bytes needed to fit an image of given dimensions and format
|
* Computes the size in bytes for a pixel of given dimensions and format
|
||||||
*
|
*
|
||||||
* @param format Format of the image pixels
|
* @param format Format of the image pixels
|
||||||
* @param type Type of the image pixels
|
* @param type Type of the image pixels
|
||||||
* @param stride Stride of a row in pixels
|
* @return The size of the specified pixel in bytes
|
||||||
* @param height Height of the image in rows
|
|
||||||
* @param alignment Alignment in bytes of pixel rows
|
|
||||||
* @return The buffer size needed to fit this image in bytes
|
|
||||||
*/
|
*/
|
||||||
static constexpr size_t computeDataSize(PixelDataFormat format, PixelDataType type,
|
|
||||||
size_t stride, size_t height, size_t alignment) noexcept {
|
|
||||||
assert_invariant(alignment);
|
|
||||||
|
|
||||||
|
static constexpr size_t computePixelSize(PixelDataFormat format, PixelDataType type) noexcept {
|
||||||
if (type == PixelDataType::COMPRESSED) {
|
if (type == PixelDataType::COMPRESSED) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -239,7 +234,7 @@ public:
|
|||||||
case PixelDataFormat::RGB_INTEGER:
|
case PixelDataFormat::RGB_INTEGER:
|
||||||
n = 3;
|
n = 3;
|
||||||
break;
|
break;
|
||||||
case PixelDataFormat::UNUSED: // shouldn't happen (used to be rgbm)
|
case PixelDataFormat::UNUSED:// shouldn't happen (used to be rgbm)
|
||||||
case PixelDataFormat::RGBA:
|
case PixelDataFormat::RGBA:
|
||||||
case PixelDataFormat::RGBA_INTEGER:
|
case PixelDataFormat::RGBA_INTEGER:
|
||||||
n = 4;
|
n = 4;
|
||||||
@@ -248,7 +243,7 @@ public:
|
|||||||
|
|
||||||
size_t bpp = n;
|
size_t bpp = n;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PixelDataType::COMPRESSED: // Impossible -- to squash the IDE warnings
|
case PixelDataType::COMPRESSED:// Impossible -- to squash the IDE warnings
|
||||||
case PixelDataType::UBYTE:
|
case PixelDataType::UBYTE:
|
||||||
case PixelDataType::BYTE:
|
case PixelDataType::BYTE:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
@@ -279,16 +274,35 @@ public:
|
|||||||
bpp = 2;
|
bpp = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return bpp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the size in bytes needed to fit an image of given dimensions and format
|
||||||
|
*
|
||||||
|
* @param format Format of the image pixels
|
||||||
|
* @param type Type of the image pixels
|
||||||
|
* @param stride Stride of a row in pixels
|
||||||
|
* @param height Height of the image in rows
|
||||||
|
* @param alignment Alignment in bytes of pixel rows
|
||||||
|
* @return The buffer size needed to fit this image in bytes
|
||||||
|
*/
|
||||||
|
static constexpr size_t computeDataSize(PixelDataFormat format, PixelDataType type,
|
||||||
|
size_t stride, size_t height, size_t alignment) noexcept {
|
||||||
|
assert_invariant(alignment);
|
||||||
|
|
||||||
|
size_t bpp = computePixelSize(format, type);
|
||||||
size_t const bpr = bpp * stride;
|
size_t const bpr = bpp * stride;
|
||||||
size_t const bprAligned = (bpr + (alignment - 1)) & (~alignment + 1);
|
size_t const bprAligned = (bpr + (alignment - 1)) & (~alignment + 1);
|
||||||
return bprAligned * height;
|
return bprAligned * height;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! left coordinate in pixels
|
//! left coordinate in pixels
|
||||||
uint32_t left = 0;
|
uint32_t left = 0;
|
||||||
//! top coordinate in pixels
|
//! top coordinate in pixels
|
||||||
uint32_t top = 0;
|
uint32_t top = 0;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
//! stride in pixels
|
//! stride in pixels
|
||||||
|
|||||||
@@ -20,12 +20,10 @@
|
|||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/Invocable.h>
|
#include <utils/Invocable.h>
|
||||||
#include <utils/ostream.h>
|
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <unordered_map>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
@@ -33,6 +31,10 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
class ostream;
|
||||||
|
} // namespace utils::io
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
class Program {
|
class Program {
|
||||||
@@ -44,8 +46,8 @@ public:
|
|||||||
|
|
||||||
struct Descriptor {
|
struct Descriptor {
|
||||||
utils::CString name;
|
utils::CString name;
|
||||||
backend::DescriptorType type;
|
DescriptorType type;
|
||||||
backend::descriptor_binding_t binding;
|
descriptor_binding_t binding;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpecializationConstant {
|
struct SpecializationConstant {
|
||||||
|
|||||||
@@ -19,22 +19,26 @@
|
|||||||
|
|
||||||
#include <backend/Handle.h>
|
#include <backend/Handle.h>
|
||||||
|
|
||||||
#include <utils/ostream.h>
|
#include <utility>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
class ostream;
|
||||||
|
} // namespace utils::io
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
//! \privatesection
|
//! \privatesection
|
||||||
|
|
||||||
struct TargetBufferInfo {
|
struct TargetBufferInfo {
|
||||||
// note: the parameters of this constructor are not in the order of this structure's fields
|
// note: the parameters of this constructor are not in the order of this structure's fields
|
||||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
|
TargetBufferInfo(Handle<HwTexture> handle, uint8_t const level, uint16_t const layer) noexcept
|
||||||
: handle(handle), level(level), layer(layer) {
|
: handle(std::move(handle)), level(level), layer(layer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level) noexcept
|
TargetBufferInfo(Handle<HwTexture> handle, uint8_t const level) noexcept
|
||||||
: handle(handle), level(level) {
|
: handle(handle), level(level) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +74,11 @@ private:
|
|||||||
TargetBufferInfo mInfos[MAX_SUPPORTED_RENDER_TARGET_COUNT];
|
TargetBufferInfo mInfos[MAX_SUPPORTED_RENDER_TARGET_COUNT];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TargetBufferInfo const& operator[](size_t i) const noexcept {
|
TargetBufferInfo const& operator[](size_t const i) const noexcept {
|
||||||
return mInfos[i];
|
return mInfos[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetBufferInfo& operator[](size_t i) noexcept {
|
TargetBufferInfo& operator[](size_t const i) noexcept {
|
||||||
return mInfos[i];
|
return mInfos[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,18 +39,40 @@ public:
|
|||||||
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override;
|
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override;
|
||||||
int getOSVersion() const noexcept override { return 0; }
|
int getOSVersion() const noexcept override { return 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optionally initializes the Metal platform by acquiring resources necessary for rendering.
|
||||||
|
*
|
||||||
|
* This method attempts to acquire a Metal device and command queue, returning true if both are
|
||||||
|
* successfully obtained, or false otherwise. Typically, these objects are acquired when
|
||||||
|
* the Metal backend is initialized. This method allows clients to check for their availability
|
||||||
|
* earlier.
|
||||||
|
*
|
||||||
|
* Calling initialize() is optional and safe to do so multiple times. After initialize() returns
|
||||||
|
* true, subsequent calls will continue to return true but have no effect.
|
||||||
|
*
|
||||||
|
* initialize() must be called from the main thread.
|
||||||
|
*
|
||||||
|
* @returns true if the device and command queue have been successfully obtained; false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
bool initialize() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the preferred Metal device object for the backend to use.
|
* Obtain the preferred Metal device object for the backend to use.
|
||||||
*
|
*
|
||||||
* On desktop platforms, there may be multiple GPUs suitable for rendering, and this method is
|
* On desktop platforms, there may be multiple GPUs suitable for rendering, and this method is
|
||||||
* free to decide which one to use. On mobile systems with a single GPU, implementations should
|
* free to decide which one to use. On mobile systems with a single GPU, implementations should
|
||||||
* simply return the result of MTLCreateSystemDefaultDevice();
|
* simply return the result of MTLCreateSystemDefaultDevice();
|
||||||
|
*
|
||||||
|
* createDevice is called by the Metal backend from the backend thread.
|
||||||
*/
|
*/
|
||||||
virtual void createDevice(MetalDevice& outDevice) noexcept;
|
virtual void createDevice(MetalDevice& outDevice) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a command submission queue on the Metal device object.
|
* Create a command submission queue on the Metal device object.
|
||||||
*
|
*
|
||||||
|
* createCommandQueue is called by the Metal backend from the backend thread.
|
||||||
|
*
|
||||||
* @param device The device which was returned from createDevice()
|
* @param device The device which was returned from createDevice()
|
||||||
*/
|
*/
|
||||||
virtual void createCommandQueue(
|
virtual void createCommandQueue(
|
||||||
@@ -60,6 +82,8 @@ public:
|
|||||||
* Obtain a MTLCommandBuffer enqueued on this Platform's MTLCommandQueue. The command buffer is
|
* Obtain a MTLCommandBuffer enqueued on this Platform's MTLCommandQueue. The command buffer is
|
||||||
* guaranteed to execute before all subsequent command buffers created either by Filament, or
|
* guaranteed to execute before all subsequent command buffers created either by Filament, or
|
||||||
* further calls to this method.
|
* further calls to this method.
|
||||||
|
*
|
||||||
|
* createAndEnqueueCommandBuffer must be called from the main thread.
|
||||||
*/
|
*/
|
||||||
void createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept;
|
void createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept;
|
||||||
|
|
||||||
@@ -68,6 +92,8 @@ public:
|
|||||||
*
|
*
|
||||||
* Each frame rendered requires a CAMetalDrawable texture, which is presented on-screen at the
|
* Each frame rendered requires a CAMetalDrawable texture, which is presented on-screen at the
|
||||||
* completion of each frame. These are limited and provided round-robin style by the system.
|
* completion of each frame. These are limited and provided round-robin style by the system.
|
||||||
|
*
|
||||||
|
* setDrawableFailureBehavior must be called from the main thread.
|
||||||
*/
|
*/
|
||||||
enum class DrawableFailureBehavior : uint8_t {
|
enum class DrawableFailureBehavior : uint8_t {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,8 +27,11 @@
|
|||||||
#include <utils/Hash.h>
|
#include <utils/Hash.h>
|
||||||
#include <utils/PrivateImplementation.h>
|
#include <utils/PrivateImplementation.h>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <functional>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include "DataReshaper.h"
|
#include "DataReshaper.h"
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -223,6 +225,143 @@ size_t getFormatSize(TextureFormat format) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextureType getTextureType(TextureFormat const format) noexcept {
|
||||||
|
switch (format) {
|
||||||
|
case TextureFormat::UNUSED:
|
||||||
|
// should not happen
|
||||||
|
return TextureType::FLOAT;
|
||||||
|
|
||||||
|
case TextureFormat::R8:
|
||||||
|
case TextureFormat::R16F:
|
||||||
|
case TextureFormat::RG8:
|
||||||
|
case TextureFormat::RGB565:
|
||||||
|
case TextureFormat::RGB5_A1:
|
||||||
|
case TextureFormat::RGBA4:
|
||||||
|
case TextureFormat::R32F:
|
||||||
|
case TextureFormat::RGB8:
|
||||||
|
case TextureFormat::SRGB8:
|
||||||
|
case TextureFormat::RG16F:
|
||||||
|
case TextureFormat::R11F_G11F_B10F:
|
||||||
|
case TextureFormat::RGB9_E5:
|
||||||
|
case TextureFormat::RGBA8:
|
||||||
|
case TextureFormat::SRGB8_A8:
|
||||||
|
case TextureFormat::RGB10_A2:
|
||||||
|
case TextureFormat::RGB16F:
|
||||||
|
case TextureFormat::RG32F:
|
||||||
|
case TextureFormat::RGBA16F:
|
||||||
|
case TextureFormat::RGB32F:
|
||||||
|
case TextureFormat::RGBA32F:
|
||||||
|
return TextureType::FLOAT;
|
||||||
|
|
||||||
|
case TextureFormat::R8_SNORM:
|
||||||
|
case TextureFormat::RG8_SNORM:
|
||||||
|
case TextureFormat::RGB8_SNORM:
|
||||||
|
case TextureFormat::RGBA8_SNORM:
|
||||||
|
// SNORM are treated as float
|
||||||
|
return TextureType::FLOAT;
|
||||||
|
|
||||||
|
case TextureFormat::R8UI:
|
||||||
|
case TextureFormat::R16UI:
|
||||||
|
case TextureFormat::RG8UI:
|
||||||
|
case TextureFormat::RGB8UI:
|
||||||
|
case TextureFormat::R32UI:
|
||||||
|
case TextureFormat::RG16UI:
|
||||||
|
case TextureFormat::RGBA8UI:
|
||||||
|
case TextureFormat::RGB16UI:
|
||||||
|
case TextureFormat::RG32UI:
|
||||||
|
case TextureFormat::RGBA16UI:
|
||||||
|
case TextureFormat::RGB32UI:
|
||||||
|
case TextureFormat::RGBA32UI:
|
||||||
|
return TextureType::UINT;
|
||||||
|
|
||||||
|
case TextureFormat::R8I:
|
||||||
|
case TextureFormat::R16I:
|
||||||
|
case TextureFormat::RG8I:
|
||||||
|
case TextureFormat::RGB8I:
|
||||||
|
case TextureFormat::R32I:
|
||||||
|
case TextureFormat::RG16I:
|
||||||
|
case TextureFormat::RGBA8I:
|
||||||
|
case TextureFormat::RGB16I:
|
||||||
|
case TextureFormat::RG32I:
|
||||||
|
case TextureFormat::RGBA16I:
|
||||||
|
case TextureFormat::RGB32I:
|
||||||
|
case TextureFormat::RGBA32I:
|
||||||
|
return TextureType::INT;
|
||||||
|
|
||||||
|
case TextureFormat::DEPTH16:
|
||||||
|
case TextureFormat::DEPTH24:
|
||||||
|
case TextureFormat::DEPTH32F:
|
||||||
|
return TextureType::DEPTH;
|
||||||
|
|
||||||
|
case TextureFormat::STENCIL8:
|
||||||
|
return TextureType::STENCIL;
|
||||||
|
|
||||||
|
case TextureFormat::DEPTH24_STENCIL8:
|
||||||
|
case TextureFormat::DEPTH32F_STENCIL8:
|
||||||
|
return TextureType::DEPTH_STENCIL;
|
||||||
|
|
||||||
|
// Compressed formats ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
case TextureFormat::EAC_RG11:
|
||||||
|
case TextureFormat::EAC_RG11_SIGNED:
|
||||||
|
case TextureFormat::ETC2_EAC_RGBA8:
|
||||||
|
case TextureFormat::ETC2_EAC_SRGBA8:
|
||||||
|
case TextureFormat::EAC_R11:
|
||||||
|
case TextureFormat::EAC_R11_SIGNED:
|
||||||
|
case TextureFormat::ETC2_RGB8:
|
||||||
|
case TextureFormat::ETC2_SRGB8:
|
||||||
|
case TextureFormat::ETC2_RGB8_A1:
|
||||||
|
case TextureFormat::ETC2_SRGB8_A1:
|
||||||
|
case TextureFormat::DXT1_RGB:
|
||||||
|
case TextureFormat::DXT1_RGBA:
|
||||||
|
case TextureFormat::DXT1_SRGB:
|
||||||
|
case TextureFormat::DXT1_SRGBA:
|
||||||
|
case TextureFormat::DXT3_RGBA:
|
||||||
|
case TextureFormat::DXT3_SRGBA:
|
||||||
|
case TextureFormat::DXT5_RGBA:
|
||||||
|
case TextureFormat::DXT5_SRGBA:
|
||||||
|
case TextureFormat::RED_RGTC1:
|
||||||
|
case TextureFormat::SIGNED_RED_RGTC1:
|
||||||
|
case TextureFormat::RED_GREEN_RGTC2:
|
||||||
|
case TextureFormat::SIGNED_RED_GREEN_RGTC2:
|
||||||
|
case TextureFormat::RGB_BPTC_SIGNED_FLOAT:
|
||||||
|
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
|
||||||
|
case TextureFormat::RGBA_BPTC_UNORM:
|
||||||
|
case TextureFormat::SRGB_ALPHA_BPTC_UNORM:
|
||||||
|
case TextureFormat::RGBA_ASTC_4x4:
|
||||||
|
case TextureFormat::RGBA_ASTC_5x4:
|
||||||
|
case TextureFormat::RGBA_ASTC_5x5:
|
||||||
|
case TextureFormat::RGBA_ASTC_6x5:
|
||||||
|
case TextureFormat::RGBA_ASTC_6x6:
|
||||||
|
case TextureFormat::RGBA_ASTC_8x5:
|
||||||
|
case TextureFormat::RGBA_ASTC_8x6:
|
||||||
|
case TextureFormat::RGBA_ASTC_8x8:
|
||||||
|
case TextureFormat::RGBA_ASTC_10x5:
|
||||||
|
case TextureFormat::RGBA_ASTC_10x6:
|
||||||
|
case TextureFormat::RGBA_ASTC_10x8:
|
||||||
|
case TextureFormat::RGBA_ASTC_10x10:
|
||||||
|
case TextureFormat::RGBA_ASTC_12x10:
|
||||||
|
case TextureFormat::RGBA_ASTC_12x12:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_4x4:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_5x4:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_5x5:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_6x5:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_6x6:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_8x5:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_8x6:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_8x8:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_10x5:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_10x6:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_10x8:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_10x10:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_12x10:
|
||||||
|
case TextureFormat::SRGB8_ALPHA8_ASTC_12x12:
|
||||||
|
return TextureType::FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextureType::FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
size_t getFormatComponentCount(TextureFormat format) noexcept {
|
size_t getFormatComponentCount(TextureFormat format) noexcept {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case TextureFormat::R8:
|
case TextureFormat::R8:
|
||||||
|
|||||||
@@ -18,12 +18,13 @@
|
|||||||
#include "private/backend/CircularBuffer.h"
|
#include "private/backend/CircularBuffer.h"
|
||||||
#include "private/backend/CommandStream.h"
|
#include "private/backend/CommandStream.h"
|
||||||
|
|
||||||
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/Mutex.h>
|
#include <utils/Mutex.h>
|
||||||
#include <utils/ostream.h>
|
#include <utils/ostream.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include <utils/Systrace.h>
|
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -79,7 +80,7 @@ bool CommandBufferQueue::isExitRequested() const {
|
|||||||
|
|
||||||
|
|
||||||
void CommandBufferQueue::flush() noexcept {
|
void CommandBufferQueue::flush() noexcept {
|
||||||
SYSTRACE_CALL();
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
|
|
||||||
CircularBuffer& circularBuffer = mCircularBuffer;
|
CircularBuffer& circularBuffer = mCircularBuffer;
|
||||||
if (circularBuffer.empty()) {
|
if (circularBuffer.empty()) {
|
||||||
@@ -129,7 +130,7 @@ void CommandBufferQueue::flush() noexcept {
|
|||||||
mHighWatermark = std::max(mHighWatermark, totalUsed);
|
mHighWatermark = std::max(mHighWatermark, totalUsed);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SYSTRACE_NAME("waiting: CircularBuffer::flush()");
|
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "waiting: CircularBuffer::flush()");
|
||||||
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(!mPaused) <<
|
FILAMENT_CHECK_POSTCONDITION(!mPaused) <<
|
||||||
"CommandStream is full, but since the rendering thread is paused, "
|
"CommandStream is full, but since the rendering thread is paused, "
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include "private/backend/CommandStream.h"
|
#include "private/backend/CommandStream.h"
|
||||||
|
|
||||||
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#if DEBUG_COMMAND_STREAM
|
#if DEBUG_COMMAND_STREAM
|
||||||
#include <utils/CallStack.h>
|
#include <utils/CallStack.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -24,7 +26,6 @@
|
|||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/ostream.h>
|
#include <utils/ostream.h>
|
||||||
#include <utils/Profiler.h>
|
#include <utils/Profiler.h>
|
||||||
#include <utils/Systrace.h>
|
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -79,12 +80,13 @@ CommandStream::CommandStream(Driver& driver, CircularBuffer& buffer) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CommandStream::execute(void* buffer) {
|
void CommandStream::execute(void* buffer) {
|
||||||
// NOTE: we can't use SYSTRACE_CALL() or similar here because, execute() below, also
|
// NOTE: we can't use FILAMENT_TRACING_CALL() or similar here because, execute() below, also
|
||||||
// uses systrace BEGIN/END and the END is not guaranteed to be happening in this scope.
|
// uses systrace BEGIN/END and the END is not guaranteed to be happening in this scope.
|
||||||
|
|
||||||
Profiler profiler;
|
Profiler profiler;
|
||||||
|
|
||||||
if constexpr (SYSTRACE_TAG) {
|
|
||||||
|
if constexpr (FILAMENT_TRACING_ENABLED) {
|
||||||
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
||||||
// we want to remove all this when tracing is completely disabled
|
// we want to remove all this when tracing is completely disabled
|
||||||
profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_BPU_MISSES);
|
profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_BPU_MISSES);
|
||||||
@@ -100,17 +102,17 @@ void CommandStream::execute(void* buffer) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if constexpr (SYSTRACE_TAG) {
|
if constexpr (FILAMENT_TRACING_ENABLED) {
|
||||||
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
||||||
// we want to remove all this when tracing is completely disabled
|
// we want to remove all this when tracing is completely disabled
|
||||||
profiler.stop();
|
profiler.stop();
|
||||||
UTILS_UNUSED Profiler::Counters const counters = profiler.readCounters();
|
UTILS_UNUSED Profiler::Counters const counters = profiler.readCounters();
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_VALUE32("GLThread (I)", counters.getInstructions());
|
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (I)", counters.getInstructions());
|
||||||
SYSTRACE_VALUE32("GLThread (C)", counters.getCpuCycles());
|
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (C)", counters.getCpuCycles());
|
||||||
SYSTRACE_VALUE32("GLThread (CPI x10)", counters.getCPI() * 10);
|
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (CPI x10)", counters.getCPI() * 10);
|
||||||
SYSTRACE_VALUE32("GLThread (BPU miss)", counters.getBranchMisses());
|
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (BPU miss)", counters.getBranchMisses());
|
||||||
SYSTRACE_VALUE32("GLThread (I / BPU miss)",
|
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (I / BPU miss)",
|
||||||
counters.getInstructions() / counters.getBranchMisses());
|
counters.getInstructions() / counters.getBranchMisses());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,9 @@
|
|||||||
#include "private/backend/Driver.h"
|
#include "private/backend/Driver.h"
|
||||||
#include "private/backend/CommandStream.h"
|
#include "private/backend/CommandStream.h"
|
||||||
|
|
||||||
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/Systrace.h>
|
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@
|
|||||||
#if DEBUG_LEVEL == DEBUG_LEVEL_NONE
|
#if DEBUG_LEVEL == DEBUG_LEVEL_NONE
|
||||||
# define SYSTRACE()
|
# define SYSTRACE()
|
||||||
#elif DEBUG_LEVEL == DEBUG_LEVEL_SYSTRACE
|
#elif DEBUG_LEVEL == DEBUG_LEVEL_SYSTRACE
|
||||||
# define SYSTRACE() SYSTRACE_CALL();
|
# define SYSTRACE() FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
#else
|
#else
|
||||||
# error "invalid debug level"
|
# error "invalid debug level"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "CompilerThreadPool.h"
|
#include "CompilerThreadPool.h"
|
||||||
|
|
||||||
#include <utils/Systrace.h>
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ void CompilerThreadPool::init(uint32_t threadCount,
|
|||||||
|
|
||||||
for (size_t i = 0; i < threadCount; i++) {
|
for (size_t i = 0; i < threadCount; i++) {
|
||||||
mCompilerThreads.emplace_back([this, setup, cleanup]() {
|
mCompilerThreads.emplace_back([this, setup, cleanup]() {
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
|
|
||||||
(*setup)();
|
(*setup)();
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ void CompilerThreadPool::init(uint32_t threadCount,
|
|||||||
[](auto&& q) { return q.empty(); }));
|
[](auto&& q) { return q.empty(); }));
|
||||||
});
|
});
|
||||||
|
|
||||||
SYSTRACE_VALUE32("CompilerThreadPool Jobs",
|
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "CompilerThreadPool Jobs",
|
||||||
mQueues[0].size() + mQueues[1].size());
|
mQueues[0].size() + mQueues[1].size());
|
||||||
|
|
||||||
if (UTILS_LIKELY(!mExitRequested)) {
|
if (UTILS_LIKELY(!mExitRequested)) {
|
||||||
|
|||||||
@@ -23,11 +23,12 @@
|
|||||||
#include <backend/BufferDescriptor.h>
|
#include <backend/BufferDescriptor.h>
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/ostream.h>
|
#include <utils/ostream.h>
|
||||||
#include <utils/Systrace.h>
|
|
||||||
|
|
||||||
#include <math/half.h>
|
#include <math/half.h>
|
||||||
#include <math/vec2.h>
|
#include <math/vec2.h>
|
||||||
@@ -151,30 +152,31 @@ void DriverBase::debugCommandBegin(CommandStream* cmds, bool synchronous, const
|
|||||||
utils::slog.d << methodName << utils::io::endl;
|
utils::slog.d << methodName << utils::io::endl;
|
||||||
}
|
}
|
||||||
if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
|
if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_NAME_BEGIN(methodName);
|
FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, methodName);
|
||||||
|
|
||||||
if (!synchronous) {
|
if (!synchronous) {
|
||||||
cmds->queueCommand([=]() {
|
cmds->queueCommand([=]() {
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_NAME_BEGIN(methodName);
|
FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, methodName);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept {
|
void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous,
|
||||||
|
const char* methodName) noexcept {
|
||||||
if constexpr (bool(FILAMENT_DEBUG_COMMANDS > FILAMENT_DEBUG_COMMANDS_NONE)) {
|
if constexpr (bool(FILAMENT_DEBUG_COMMANDS > FILAMENT_DEBUG_COMMANDS_NONE)) {
|
||||||
if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
|
if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
|
||||||
if (!synchronous) {
|
if (!synchronous) {
|
||||||
cmds->queueCommand([]() {
|
cmds->queueCommand([]() {
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_NAME_END();
|
FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_NAME_END();
|
FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <backend/Platform.h>
|
#include <backend/Platform.h>
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
|
#include <utils/ostream.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|||||||
@@ -16,7 +16,8 @@
|
|||||||
|
|
||||||
#include <private/backend/PlatformFactory.h>
|
#include <private/backend/PlatformFactory.h>
|
||||||
|
|
||||||
#include <utils/Systrace.h>
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
|
|
||||||
// We need to keep this up top for the linux (X11) name collisions.
|
// We need to keep this up top for the linux (X11) name collisions.
|
||||||
@@ -85,7 +86,7 @@ namespace filament::backend {
|
|||||||
// responsible for destroying it. Initialization of the backend API is deferred until
|
// responsible for destroying it. Initialization of the backend API is deferred until
|
||||||
// createDriver(). The passed-in backend hint is replaced with the resolved backend.
|
// createDriver(). The passed-in backend hint is replaced with the resolved backend.
|
||||||
Platform* PlatformFactory::create(Backend* backend) noexcept {
|
Platform* PlatformFactory::create(Backend* backend) noexcept {
|
||||||
SYSTRACE_CALL();
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
assert_invariant(backend);
|
assert_invariant(backend);
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_SYSTRACEPROFILE_H
|
#ifndef TNT_FILAMENT_BACKEND_SYSTRACEPROFILE_H
|
||||||
#define TNT_FILAMENT_BACKEND_SYSTRACEPROFILE_H
|
#define TNT_FILAMENT_BACKEND_SYSTRACEPROFILE_H
|
||||||
|
|
||||||
#include <utils/Systrace.h>
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#define PROFILE_SCOPE(marker) SYSTRACE_NAME(marker)
|
#define PROFILE_SCOPE(marker) SYSTRACE_NAME(marker)
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "MetalContext.h"
|
#include "MetalContext.h"
|
||||||
|
|
||||||
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
namespace filament {
|
namespace filament {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
|
|
||||||
|
|||||||
@@ -672,22 +672,8 @@ void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
|||||||
// nothing to do, timer query was constructed in createTimerQueryS
|
// nothing to do, timer query was constructed in createTimerQueryS
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* toString(DescriptorType type) {
|
UTILS_UNUSED
|
||||||
switch (type) {
|
static const char* toString(ShaderStageFlags flags) {
|
||||||
case DescriptorType::UNIFORM_BUFFER:
|
|
||||||
return "UNIFORM_BUFFER";
|
|
||||||
case DescriptorType::SHADER_STORAGE_BUFFER:
|
|
||||||
return "SHADER_STORAGE_BUFFER";
|
|
||||||
case DescriptorType::SAMPLER:
|
|
||||||
return "SAMPLER";
|
|
||||||
case DescriptorType::INPUT_ATTACHMENT:
|
|
||||||
return "INPUT_ATTACHMENT";
|
|
||||||
case DescriptorType::SAMPLER_EXTERNAL:
|
|
||||||
return "SAMPLER_EXTERNAL";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* toString(ShaderStageFlags flags) {
|
|
||||||
std::vector<const char*> stages;
|
std::vector<const char*> stages;
|
||||||
if (any(flags & ShaderStageFlags::VERTEX)) {
|
if (any(flags & ShaderStageFlags::VERTEX)) {
|
||||||
stages.push_back("VERTEX");
|
stages.push_back("VERTEX");
|
||||||
@@ -721,15 +707,25 @@ const char* toString(DescriptorFlags flags) {
|
|||||||
|
|
||||||
void MetalDriver::createDescriptorSetLayoutR(
|
void MetalDriver::createDescriptorSetLayoutR(
|
||||||
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info) {
|
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info) {
|
||||||
|
#if FILAMENT_METAL_DEBUG_LOG == 1
|
||||||
|
const char* labelStr = "";
|
||||||
|
std::visit([&labelStr](auto&& arg) {
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, utils::CString> || std::is_same_v<T, utils::StaticString>) {
|
||||||
|
labelStr = arg.c_str();
|
||||||
|
}
|
||||||
|
}, info.label);
|
||||||
std::sort(info.bindings.begin(), info.bindings.end(),
|
std::sort(info.bindings.begin(), info.bindings.end(),
|
||||||
[](const auto& a, const auto& b) { return a.binding < b.binding; });
|
[](const auto& a, const auto& b) { return a.binding < b.binding; });
|
||||||
DEBUG_LOG("createDescriptorSetLayoutR(dslh = %d, info = {\n", dslh.getId());
|
DEBUG_LOG("createDescriptorSetLayoutR(dslh = %d, info = { label = %s,\n", dslh.getId(),
|
||||||
|
labelStr);
|
||||||
for (size_t i = 0; i < info.bindings.size(); i++) {
|
for (size_t i = 0; i < info.bindings.size(); i++) {
|
||||||
DEBUG_LOG(" {binding = %d, type = %s, count = %d, stage = %s, flags = %s},\n",
|
DEBUG_LOG(" {binding = %d, type = %s, count = %d, stage = %s, flags = %s},\n",
|
||||||
info.bindings[i].binding, toString(info.bindings[i].type), info.bindings[i].count,
|
info.bindings[i].binding, toString(info.bindings[i].type), info.bindings[i].count,
|
||||||
toString(info.bindings[i].stageFlags), toString(info.bindings[i].flags));
|
toString(info.bindings[i].stageFlags), toString(info.bindings[i].flags));
|
||||||
}
|
}
|
||||||
DEBUG_LOG("})\n");
|
DEBUG_LOG("})\n");
|
||||||
|
#endif
|
||||||
construct_handle<MetalDescriptorSetLayout>(dslh, std::move(info));
|
construct_handle<MetalDescriptorSetLayout>(dslh, std::move(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ inline MTLPixelFormat getMetalFormat(PixelDataFormat format, PixelDataType type)
|
|||||||
CONVERT(RGBA_INTEGER, UINT, RGBA32Uint);
|
CONVERT(RGBA_INTEGER, UINT, RGBA32Uint);
|
||||||
CONVERT(RGBA_INTEGER, INT, RGBA32Sint);
|
CONVERT(RGBA_INTEGER, INT, RGBA32Sint);
|
||||||
CONVERT(RGBA, FLOAT, RGBA32Float);
|
CONVERT(RGBA, FLOAT, RGBA32Float);
|
||||||
|
CONVERT(DEPTH_COMPONENT, FLOAT, Depth32Float);
|
||||||
#undef CONVERT
|
#undef CONVERT
|
||||||
|
|
||||||
return MTLPixelFormatInvalid;
|
return MTLPixelFormatInvalid;
|
||||||
|
|||||||
@@ -1356,7 +1356,31 @@ id<MTLArgumentEncoder> MetalDescriptorSetLayout::getArgumentEncoderSlow(id<MTLDe
|
|||||||
[arguments addObject:bufferArgument];
|
[arguments addObject:bufferArgument];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DescriptorType::SAMPLER:
|
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_3D_INT:
|
||||||
|
case DescriptorType::SAMPLER_3D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||||
case DescriptorType::SAMPLER_EXTERNAL: {
|
case DescriptorType::SAMPLER_EXTERNAL: {
|
||||||
MTLArgumentDescriptor* textureArgument = [MTLArgumentDescriptor argumentDescriptor];
|
MTLArgumentDescriptor* textureArgument = [MTLArgumentDescriptor argumentDescriptor];
|
||||||
textureArgument.index = binding.binding * 2;
|
textureArgument.index = binding.binding * 2;
|
||||||
@@ -1382,6 +1406,9 @@ id<MTLArgumentEncoder> MetalDescriptorSetLayout::getArgumentEncoderSlow(id<MTLDe
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (arguments.count == 0) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
return [device newArgumentEncoderWithArguments:arguments];
|
return [device newArgumentEncoderWithArguments:arguments];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1442,6 +1469,9 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
|
|||||||
|
|
||||||
id<MTLArgumentEncoder> encoder =
|
id<MTLArgumentEncoder> encoder =
|
||||||
layout->getArgumentEncoder(context.device, stage, textureTypes);
|
layout->getArgumentEncoder(context.device, stage, textureTypes);
|
||||||
|
if (!encoder) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ScopedAllocationTimer timer("descriptor_set");
|
ScopedAllocationTimer timer("descriptor_set");
|
||||||
@@ -1472,7 +1502,31 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
|
|||||||
atIndex:binding.binding * 2];
|
atIndex:binding.binding * 2];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DescriptorType::SAMPLER:
|
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_3D_INT:
|
||||||
|
case DescriptorType::SAMPLER_3D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||||
case DescriptorType::SAMPLER_EXTERNAL: {
|
case DescriptorType::SAMPLER_EXTERNAL: {
|
||||||
auto found = textures.find(binding.binding);
|
auto found = textures.find(binding.binding);
|
||||||
if (found == textures.end()) {
|
if (found == textures.end()) {
|
||||||
|
|||||||
@@ -20,18 +20,19 @@
|
|||||||
#include <Metal/Metal.h>
|
#include <Metal/Metal.h>
|
||||||
|
|
||||||
#include "private/backend/Driver.h"
|
#include "private/backend/Driver.h"
|
||||||
#include "backend/Program.h"
|
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
#include <backend/Program.h>
|
||||||
|
|
||||||
|
#include <utils/bitset.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <tsl/robin_map.h>
|
|
||||||
|
|
||||||
#include <utils/Hash.h>
|
#include <utils/Hash.h>
|
||||||
#include <utils/Invocable.h>
|
#include <utils/Invocable.h>
|
||||||
|
|
||||||
|
#include <tsl/robin_map.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace filament {
|
namespace filament {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
|
|
||||||
|
|||||||
@@ -24,14 +24,22 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
struct PlatformMetalImpl {
|
struct PlatformMetalImpl {
|
||||||
|
std::mutex mLock; // locks mDevice and mCommandQueue
|
||||||
|
id<MTLDevice> mDevice = nil;
|
||||||
id<MTLCommandQueue> mCommandQueue = nil;
|
id<MTLCommandQueue> mCommandQueue = nil;
|
||||||
|
|
||||||
// read form driver thread, read/written to from client thread
|
// read form driver thread, read/written to from client thread
|
||||||
std::atomic<PlatformMetal::DrawableFailureBehavior> mDrawableFailureBehavior =
|
std::atomic<PlatformMetal::DrawableFailureBehavior> mDrawableFailureBehavior =
|
||||||
PlatformMetal::DrawableFailureBehavior::PANIC;
|
PlatformMetal::DrawableFailureBehavior::PANIC;
|
||||||
|
|
||||||
|
// These methods must be called with mLock held
|
||||||
|
void createDeviceImpl(MetalDevice& outDevice);
|
||||||
|
void createCommandQueueImpl(MetalDevice& device, MetalCommandQueue& outCommandQueue);
|
||||||
};
|
};
|
||||||
|
|
||||||
Platform* createDefaultMetalPlatform() {
|
Platform* createDefaultMetalPlatform() {
|
||||||
@@ -48,7 +56,59 @@ Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::Dri
|
|||||||
return MetalDriverFactory::create(this, driverConfig);
|
return MetalDriverFactory::create(this, driverConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PlatformMetal::initialize() noexcept {
|
||||||
|
std::lock_guard<std::mutex> lock(pImpl->mLock);
|
||||||
|
|
||||||
|
MetalDevice device{};
|
||||||
|
pImpl->createDeviceImpl(device);
|
||||||
|
if (device.device == nil) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetalCommandQueue commandQueue{};
|
||||||
|
pImpl->createCommandQueueImpl(device, commandQueue);
|
||||||
|
if (commandQueue.commandQueue == nil) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
|
void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
|
||||||
|
std::lock_guard<std::mutex> lock(pImpl->mLock);
|
||||||
|
pImpl->createDeviceImpl(outDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformMetal::createCommandQueue(
|
||||||
|
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept {
|
||||||
|
std::lock_guard<std::mutex> lock(pImpl->mLock);
|
||||||
|
pImpl->createCommandQueueImpl(device, outCommandQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformMetal::createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept {
|
||||||
|
std::lock_guard<std::mutex> lock(pImpl->mLock);
|
||||||
|
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
|
||||||
|
[commandBuffer enqueue];
|
||||||
|
outCommandBuffer.commandBuffer = commandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
|
||||||
|
pImpl->mDrawableFailureBehavior = behavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformMetal::DrawableFailureBehavior PlatformMetal::getDrawableFailureBehavior() const noexcept {
|
||||||
|
return pImpl->mDrawableFailureBehavior;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void PlatformMetalImpl::createDeviceImpl(MetalDevice& outDevice) {
|
||||||
|
if (mDevice) {
|
||||||
|
outDevice.device = mDevice;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
id<MTLDevice> result;
|
id<MTLDevice> result;
|
||||||
|
|
||||||
#if !defined(FILAMENT_IOS)
|
#if !defined(FILAMENT_IOS)
|
||||||
@@ -74,27 +134,17 @@ void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
|
|||||||
<< utils::io::endl;
|
<< utils::io::endl;
|
||||||
|
|
||||||
outDevice.device = result;
|
outDevice.device = result;
|
||||||
|
mDevice = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformMetal::createCommandQueue(
|
void PlatformMetalImpl::createCommandQueueImpl(MetalDevice& device, MetalCommandQueue& outCommandQueue) {
|
||||||
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept {
|
if (mCommandQueue) {
|
||||||
pImpl->mCommandQueue = [device.device newCommandQueue];
|
outCommandQueue.commandQueue = mCommandQueue;
|
||||||
pImpl->mCommandQueue.label = @"Filament";
|
return;
|
||||||
outCommandQueue.commandQueue = pImpl->mCommandQueue;
|
}
|
||||||
}
|
mCommandQueue = [device.device newCommandQueue];
|
||||||
|
mCommandQueue.label = @"Filament";
|
||||||
void PlatformMetal::createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept {
|
outCommandQueue.commandQueue = mCommandQueue;
|
||||||
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
|
|
||||||
[commandBuffer enqueue];
|
|
||||||
outCommandBuffer.commandBuffer = commandBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
|
|
||||||
pImpl->mDrawableFailureBehavior = behavior;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlatformMetal::DrawableFailureBehavior PlatformMetal::getDrawableFailureBehavior() const noexcept {
|
|
||||||
return pImpl->mDrawableFailureBehavior;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace filament
|
} // namespace filament
|
||||||
|
|||||||
@@ -69,9 +69,8 @@ public:
|
|||||||
assert_invariant(set < MAX_DESCRIPTOR_SET_COUNT);
|
assert_invariant(set < MAX_DESCRIPTOR_SET_COUNT);
|
||||||
assert_invariant(binding < MAX_DESCRIPTOR_COUNT);
|
assert_invariant(binding < MAX_DESCRIPTOR_COUNT);
|
||||||
assert_invariant(entry.binding < 128); // we reserve 1 bit for the type right now
|
assert_invariant(entry.binding < 128); // we reserve 1 bit for the type right now
|
||||||
mStorage[set][binding] = { (uint8_t)entry.binding,
|
mStorage[set][binding] = { uint8_t(entry.binding),
|
||||||
entry.type == DescriptorType::SAMPLER ||
|
DescriptorSetLayoutBinding::isSampler(entry.type) };
|
||||||
entry.type == DescriptorType::SAMPLER_EXTERNAL };
|
|
||||||
mActiveDescriptors[set].set(binding);
|
mActiveDescriptors[set].set(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,32 @@ GLDescriptorSet::GLDescriptorSet(OpenGLContext& gl, DescriptorSetLayoutHandle ds
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DescriptorType::SAMPLER:
|
|
||||||
|
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_3D_INT:
|
||||||
|
case DescriptorType::SAMPLER_3D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||||
case DescriptorType::SAMPLER_EXTERNAL:
|
case DescriptorType::SAMPLER_EXTERNAL:
|
||||||
if (UTILS_UNLIKELY(gl.isES2())) {
|
if (UTILS_UNLIKELY(gl.isES2())) {
|
||||||
desc.emplace<SamplerGLES2>();
|
desc.emplace<SamplerGLES2>();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include <backend/Platform.h>
|
#include <backend/Platform.h>
|
||||||
#include <backend/Program.h>
|
#include <backend/Program.h>
|
||||||
|
|
||||||
#include <utils/Systrace.h>
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ OpenGLBlobCache::OpenGLBlobCache(OpenGLContext& gl) noexcept
|
|||||||
|
|
||||||
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||||
Program const& program) const noexcept {
|
Program const& program) const noexcept {
|
||||||
SYSTRACE_CALL();
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
if (!mCachingSupported || !platform.hasRetrieveBlobFunc()) {
|
if (!mCachingSupported || !platform.hasRetrieveBlobFunc()) {
|
||||||
// the key is never updated in that case
|
// the key is never updated in that case
|
||||||
return 0;
|
return 0;
|
||||||
@@ -68,7 +68,7 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
|||||||
programId = glCreateProgram();
|
programId = glCreateProgram();
|
||||||
|
|
||||||
{ // scope for systrace
|
{ // scope for systrace
|
||||||
SYSTRACE_NAME("glProgramBinary");
|
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "glProgramBinary");
|
||||||
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
|
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
|||||||
|
|
||||||
void OpenGLBlobCache::insert(Platform& platform,
|
void OpenGLBlobCache::insert(Platform& platform,
|
||||||
BlobCacheKey const& key, GLuint program) noexcept {
|
BlobCacheKey const& key, GLuint program) noexcept {
|
||||||
SYSTRACE_CALL();
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
if (!mCachingSupported || !platform.hasInsertBlobFunc()) {
|
if (!mCachingSupported || !platform.hasInsertBlobFunc()) {
|
||||||
// the key is never updated in that case
|
// the key is never updated in that case
|
||||||
return;
|
return;
|
||||||
@@ -100,7 +100,7 @@ void OpenGLBlobCache::insert(Platform& platform,
|
|||||||
GLenum format;
|
GLenum format;
|
||||||
GLint programBinarySize = 0;
|
GLint programBinarySize = 0;
|
||||||
{ // scope for systrace
|
{ // scope for systrace
|
||||||
SYSTRACE_NAME("glGetProgramiv");
|
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "glGetProgramiv");
|
||||||
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinarySize);
|
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinarySize);
|
||||||
}
|
}
|
||||||
if (programBinarySize) {
|
if (programBinarySize) {
|
||||||
@@ -108,7 +108,7 @@ void OpenGLBlobCache::insert(Platform& platform,
|
|||||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
||||||
if (UTILS_LIKELY(blob)) {
|
if (UTILS_LIKELY(blob)) {
|
||||||
{ // scope for systrace
|
{ // scope for systrace
|
||||||
SYSTRACE_NAME("glGetProgramBinary");
|
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "glGetProgramBinary");
|
||||||
glGetProgramBinary(program, programBinarySize,
|
glGetProgramBinary(program, programBinarySize,
|
||||||
&programBinarySize, &format, blob->data);
|
&programBinarySize, &format, blob->data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -542,6 +542,13 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
|||||||
} else if (strstr(renderer, "Intel")) {
|
} else if (strstr(renderer, "Intel")) {
|
||||||
// Intel GPU
|
// Intel GPU
|
||||||
bugs->vao_doesnt_store_element_array_buffer_binding = true;
|
bugs->vao_doesnt_store_element_array_buffer_binding = true;
|
||||||
|
|
||||||
|
if (strstr(renderer, "Mesa")) {
|
||||||
|
// Mesa Intel driver on Linux/Android
|
||||||
|
// Renderer of the form [Mesa Intel(R) HD Graphics 505 (APL 3)]
|
||||||
|
// b/405252622
|
||||||
|
bugs->disable_invalidate_framebuffer = true;
|
||||||
|
}
|
||||||
} else if (strstr(renderer, "PowerVR")) {
|
} else if (strstr(renderer, "PowerVR")) {
|
||||||
// PowerVR GPU
|
// PowerVR GPU
|
||||||
// On PowerVR (Rogue GE8320) glFlush doesn't seem to do anything, in particular,
|
// On PowerVR (Rogue GE8320) glFlush doesn't seem to do anything, in particular,
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
#include "private/backend/Dispatcher.h"
|
#include "private/backend/Dispatcher.h"
|
||||||
#include "private/backend/DriverApi.h"
|
#include "private/backend/DriverApi.h"
|
||||||
|
|
||||||
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utils/BitmaskEnum.h>
|
#include <utils/BitmaskEnum.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
@@ -51,7 +53,6 @@
|
|||||||
#include <utils/Invocable.h>
|
#include <utils/Invocable.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include <utils/Systrace.h>
|
|
||||||
#include <utils/Slice.h>
|
#include <utils/Slice.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
@@ -98,13 +99,13 @@
|
|||||||
|
|
||||||
#define DEBUG_GROUP_MARKER_NONE 0x00 // no debug marker
|
#define DEBUG_GROUP_MARKER_NONE 0x00 // no debug marker
|
||||||
#define DEBUG_GROUP_MARKER_OPENGL 0x01 // markers in the gl command queue (req. driver support)
|
#define DEBUG_GROUP_MARKER_OPENGL 0x01 // markers in the gl command queue (req. driver support)
|
||||||
#define DEBUG_GROUP_MARKER_BACKEND 0x02 // markers on the backend side (systrace)
|
#define DEBUG_GROUP_MARKER_BACKEND 0x02 // markers on the backend side (perfetto)
|
||||||
#define DEBUG_GROUP_MARKER_ALL 0xFF // all markers
|
#define DEBUG_GROUP_MARKER_ALL 0xFF // all markers
|
||||||
|
|
||||||
#define DEBUG_MARKER_NONE 0x00 // no debug marker
|
#define DEBUG_MARKER_NONE 0x00 // no debug marker
|
||||||
#define DEBUG_MARKER_OPENGL 0x01 // markers in the gl command queue (req. driver support)
|
#define DEBUG_MARKER_OPENGL 0x01 // markers in the gl command queue (req. driver support)
|
||||||
#define DEBUG_MARKER_BACKEND 0x02 // markers on the backend side (systrace)
|
#define DEBUG_MARKER_BACKEND 0x02 // markers on the backend side (perfetto)
|
||||||
#define DEBUG_MARKER_PROFILE 0x04 // profiling on the backend side (systrace)
|
#define DEBUG_MARKER_PROFILE 0x04 // profiling on the backend side (perfetto)
|
||||||
#define DEBUG_MARKER_ALL (0xFF & ~DEBUG_MARKER_PROFILE) // all markers
|
#define DEBUG_MARKER_ALL (0xFF & ~DEBUG_MARKER_PROFILE) // all markers
|
||||||
|
|
||||||
// set to the desired debug marker level (for user markers [default: All])
|
// set to the desired debug marker level (for user markers [default: All])
|
||||||
@@ -248,8 +249,8 @@ OpenGLDriver::DebugMarker::DebugMarker(OpenGLDriver& driver, const char* string)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEBUG_MARKER_LEVEL & DEBUG_MARKER_BACKEND
|
#if DEBUG_MARKER_LEVEL & DEBUG_MARKER_BACKEND
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_NAME_BEGIN(string);
|
FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, string);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -265,8 +266,8 @@ OpenGLDriver::DebugMarker::~DebugMarker() noexcept {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEBUG_MARKER_LEVEL & DEBUG_MARKER_BACKEND
|
#if DEBUG_MARKER_LEVEL & DEBUG_MARKER_BACKEND
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_NAME_END();
|
FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -3348,8 +3349,8 @@ void OpenGLDriver::pushGroupMarker(char const* string) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEBUG_GROUP_MARKER_LEVEL & DEBUG_GROUP_MARKER_BACKEND
|
#if DEBUG_GROUP_MARKER_LEVEL & DEBUG_GROUP_MARKER_BACKEND
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_NAME_BEGIN(string);
|
FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, string);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -3365,8 +3366,8 @@ void OpenGLDriver::popGroupMarker(int) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEBUG_GROUP_MARKER_LEVEL & DEBUG_GROUP_MARKER_BACKEND
|
#if DEBUG_GROUP_MARKER_LEVEL & DEBUG_GROUP_MARKER_BACKEND
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_NAME_END();
|
FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -3685,7 +3686,7 @@ void OpenGLDriver::endFrame(UTILS_UNUSED uint32_t frameId) {
|
|||||||
gl.depthFunc(GL_LESS);
|
gl.depthFunc(GL_LESS);
|
||||||
gl.disable(GL_SCISSOR_TEST);
|
gl.disable(GL_SCISSOR_TEST);
|
||||||
#endif
|
#endif
|
||||||
//SYSTRACE_NAME("glFinish");
|
//FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "glFinish");
|
||||||
//glFinish();
|
//glFinish();
|
||||||
mPlatform.endFrame(frameId);
|
mPlatform.endFrame(frameId);
|
||||||
insertEventMarker("endFrame");
|
insertEventMarker("endFrame");
|
||||||
|
|||||||
@@ -25,12 +25,13 @@
|
|||||||
#include <backend/Program.h>
|
#include <backend/Program.h>
|
||||||
#include <backend/Handle.h>
|
#include <backend/Handle.h>
|
||||||
|
|
||||||
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#include <utils/BitmaskEnum.h>
|
#include <utils/BitmaskEnum.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/Systrace.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -96,8 +97,7 @@ OpenGLProgram::~OpenGLProgram() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLProgram::initialize(OpenGLDriver& gld) {
|
void OpenGLProgram::initialize(OpenGLDriver& gld) {
|
||||||
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_CALL();
|
|
||||||
|
|
||||||
assert_invariant(gl.program == 0);
|
assert_invariant(gl.program == 0);
|
||||||
assert_invariant(mToken);
|
assert_invariant(mToken);
|
||||||
@@ -122,8 +122,7 @@ void OpenGLProgram::initialize(OpenGLDriver& gld) {
|
|||||||
*/
|
*/
|
||||||
void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint program,
|
void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint program,
|
||||||
LazyInitializationData& lazyInitializationData) noexcept {
|
LazyInitializationData& lazyInitializationData) noexcept {
|
||||||
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_CALL();
|
|
||||||
|
|
||||||
// from the pipeline layout we compute a mapping from {set, binding} to {binding}
|
// from the pipeline layout we compute a mapping from {set, binding} to {binding}
|
||||||
// for both buffers and textures
|
// for both buffers and textures
|
||||||
@@ -175,7 +174,31 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DescriptorType::SAMPLER:
|
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_3D_INT:
|
||||||
|
case DescriptorType::SAMPLER_3D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||||
case DescriptorType::SAMPLER_EXTERNAL: {
|
case DescriptorType::SAMPLER_EXTERNAL: {
|
||||||
if (!entry.name.empty()) {
|
if (!entry.name.empty()) {
|
||||||
GLint const loc = glGetUniformLocation(program, entry.name.c_str());
|
GLint const loc = glGetUniformLocation(program, entry.name.c_str());
|
||||||
|
|||||||
@@ -23,12 +23,13 @@
|
|||||||
#include <backend/platforms/OpenGLPlatform.h>
|
#include <backend/platforms/OpenGLPlatform.h>
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/JobSystem.h>
|
#include <utils/JobSystem.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/Mutex.h>
|
#include <utils/Mutex.h>
|
||||||
#include <utils/Systrace.h>
|
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -240,8 +241,8 @@ void TimerQueryFenceFactory::beginTimeElapsedQuery(GLTimerQuery* tq) {
|
|||||||
if (state) {
|
if (state) {
|
||||||
platform.waitFence(fence, FENCE_WAIT_FOR_EVER);
|
platform.waitFence(fence, FENCE_WAIT_FOR_EVER);
|
||||||
state->then = clock::now().time_since_epoch().count();
|
state->then = clock::now().time_since_epoch().count();
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_ASYNC_BEGIN("OpenGLTimerQueryFence", intptr_t(state.get()));
|
FILAMENT_TRACING_ASYNC_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, "OpenGLTimerQueryFence", intptr_t(state.get()));
|
||||||
}
|
}
|
||||||
platform.destroyFence(fence);
|
platform.destroyFence(fence);
|
||||||
});
|
});
|
||||||
@@ -257,8 +258,8 @@ void TimerQueryFenceFactory::endTimeElapsedQuery(OpenGLDriver&, GLTimerQuery* tq
|
|||||||
platform.waitFence(fence, FENCE_WAIT_FOR_EVER);
|
platform.waitFence(fence, FENCE_WAIT_FOR_EVER);
|
||||||
int64_t const now = clock::now().time_since_epoch().count();
|
int64_t const now = clock::now().time_since_epoch().count();
|
||||||
state->elapsed.store(now - state->then, std::memory_order_relaxed);
|
state->elapsed.store(now - state->then, std::memory_order_relaxed);
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_ASYNC_END("OpenGLTimerQueryFence", intptr_t(state.get()));
|
FILAMENT_TRACING_ASYNC_END(FILAMENT_TRACING_CATEGORY_FILAMENT, "OpenGLTimerQueryFence", intptr_t(state.get()));
|
||||||
}
|
}
|
||||||
platform.destroyFence(fence);
|
platform.destroyFence(fence);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/Program.h>
|
#include <backend/Program.h>
|
||||||
|
|
||||||
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
@@ -36,7 +38,6 @@
|
|||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/ostream.h>
|
#include <utils/ostream.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include <utils/Systrace.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -367,7 +368,7 @@ void ShaderCompilerService::notifyWhenAllProgramsAreReady(
|
|||||||
|
|
||||||
GLuint ShaderCompilerService::initialize(program_token_t& token) {
|
GLuint ShaderCompilerService::initialize(program_token_t& token) {
|
||||||
|
|
||||||
SYSTRACE_CALL();
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
|
|
||||||
assert_invariant(token);// This function should be called when the token is still alive.
|
assert_invariant(token);// This function should be called when the token is still alive.
|
||||||
|
|
||||||
@@ -454,8 +455,8 @@ void ShaderCompilerService::runAtNextTick(CompilerPriorityQueue priority,
|
|||||||
});
|
});
|
||||||
ops.emplace(pos, priority, token, std::move(job));
|
ops.emplace(pos, priority, token, std::move(job));
|
||||||
|
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_VALUE32("ShaderCompilerService Jobs", mRunAtNextTickOps.size());
|
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "ShaderCompilerService Jobs", mRunAtNextTickOps.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShaderCompilerService::cancelTickOp(program_token_t const& token) noexcept {
|
bool ShaderCompilerService::cancelTickOp(program_token_t const& token) noexcept {
|
||||||
@@ -468,8 +469,8 @@ bool ShaderCompilerService::cancelTickOp(program_token_t const& token) noexcept
|
|||||||
ops.erase(pos);
|
ops.erase(pos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_VALUE32("ShaderCompilerService Jobs", ops.size());
|
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "ShaderCompilerService Jobs", ops.size());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,15 +486,15 @@ void ShaderCompilerService::executeTickOps() noexcept {
|
|||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SYSTRACE_CONTEXT();
|
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
SYSTRACE_VALUE32("ShaderCompilerService Jobs", ops.size());
|
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "ShaderCompilerService Jobs", ops.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void ShaderCompilerService::compileShaders(OpenGLContext& context,
|
/* static */ void ShaderCompilerService::compileShaders(OpenGLContext& context,
|
||||||
Program::ShaderSource shadersSource,
|
Program::ShaderSource shadersSource,
|
||||||
FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
|
FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
|
||||||
bool multiview, program_token_t const& token) noexcept {
|
bool multiview, program_token_t const& token) noexcept {
|
||||||
SYSTRACE_CALL();
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
|
|
||||||
auto const appendSpecConstantString = +[](std::string& s, Program::SpecializationConstant const& sc) {
|
auto const appendSpecConstantString = +[](std::string& s, Program::SpecializationConstant const& sc) {
|
||||||
s += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
|
s += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
|
||||||
@@ -616,7 +617,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void ShaderCompilerService::checkCompileStatus(program_token_t const& token) noexcept {
|
/* static */ void ShaderCompilerService::checkCompileStatus(program_token_t const& token) noexcept {
|
||||||
SYSTRACE_CALL();
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
|
|
||||||
UTILS_NOUNROLL
|
UTILS_NOUNROLL
|
||||||
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
||||||
@@ -639,7 +640,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
|
|||||||
|
|
||||||
/* static */ void ShaderCompilerService::linkProgram(OpenGLContext const& context,
|
/* static */ void ShaderCompilerService::linkProgram(OpenGLContext const& context,
|
||||||
program_token_t const& token) noexcept {
|
program_token_t const& token) noexcept {
|
||||||
SYSTRACE_CALL();
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
|
|
||||||
// Shader compilation should be completed by now. Check the status and log errors on failure.
|
// Shader compilation should be completed by now. Check the status and log errors on failure.
|
||||||
checkCompileStatus(token);
|
checkCompileStatus(token);
|
||||||
@@ -675,7 +676,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
|
|||||||
|
|
||||||
/* static */ bool ShaderCompilerService::checkLinkStatusAndCleanupShaders(
|
/* static */ bool ShaderCompilerService::checkLinkStatusAndCleanupShaders(
|
||||||
program_token_t const& token) noexcept {
|
program_token_t const& token) noexcept {
|
||||||
SYSTRACE_CALL();
|
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||||
assert_invariant(token->gl.program);
|
assert_invariant(token->gl.program);
|
||||||
|
|
||||||
bool linked = true;
|
bool linked = true;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ struct PlatformCocoaGLImpl {
|
|||||||
CVOpenGLTextureCacheRef mTextureCache = nullptr;
|
CVOpenGLTextureCacheRef mTextureCache = nullptr;
|
||||||
std::unique_ptr<CocoaExternalImage::SharedGl> mExternalImageSharedGl;
|
std::unique_ptr<CocoaExternalImage::SharedGl> mExternalImageSharedGl;
|
||||||
void updateOpenGLContext(NSView *nsView, bool resetView, bool clearView);
|
void updateOpenGLContext(NSView *nsView, bool resetView, bool clearView);
|
||||||
struct ExternalImageCocoaGL : public Platform::ExternalImage {
|
struct ExternalImageCocoaGL final : public Platform::ExternalImage {
|
||||||
CVPixelBufferRef cvBuffer;
|
CVPixelBufferRef cvBuffer;
|
||||||
protected:
|
protected:
|
||||||
~ExternalImageCocoaGL() noexcept final;
|
~ExternalImageCocoaGL() noexcept final;
|
||||||
|
|||||||
@@ -255,6 +255,7 @@ Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareB
|
|||||||
p->height = hardwareBufferDescription.height;
|
p->height = hardwareBufferDescription.height;
|
||||||
p->width = hardwareBufferDescription.width;
|
p->width = hardwareBufferDescription.width;
|
||||||
auto textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
|
auto textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
|
||||||
|
p->format = textureFormat;
|
||||||
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
|
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
|
||||||
return ExternalImageHandle{ p };
|
return ExternalImageHandle{ p };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ VulkanBuffer::VulkanBuffer(VmaAllocator allocator, VulkanStagePool& stagePool,
|
|||||||
: mAllocator(allocator),
|
: mAllocator(allocator),
|
||||||
mStagePool(stagePool),
|
mStagePool(stagePool),
|
||||||
mUsage(usage),
|
mUsage(usage),
|
||||||
mUpdatedOffset(0),
|
mUpdatedOffset(0),
|
||||||
mUpdatedBytes(0) {
|
mUpdatedBytes(0) {
|
||||||
// for now make sure that only 1 bit is set in usage
|
// for now make sure that only 1 bit is set in usage
|
||||||
// (because loadFromCpu() assumes that somewhat)
|
// (because loadFromCpu() assumes that somewhat)
|
||||||
@@ -56,11 +56,12 @@ void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint
|
|||||||
vmaMapMemory(mAllocator, stage->memory, &mapped);
|
vmaMapMemory(mAllocator, stage->memory, &mapped);
|
||||||
memcpy(mapped, cpuData, numBytes);
|
memcpy(mapped, cpuData, numBytes);
|
||||||
vmaUnmapMemory(mAllocator, stage->memory);
|
vmaUnmapMemory(mAllocator, stage->memory);
|
||||||
vmaFlushAllocation(mAllocator, stage->memory, byteOffset, numBytes);
|
vmaFlushAllocation(mAllocator, stage->memory, 0, numBytes);
|
||||||
|
|
||||||
// If there was a previous update, then we need to make sure the following write is properly
|
// If there was a previous update, then we need to make sure the following write is properly
|
||||||
// synced with the previous read.
|
// synced with the previous read.
|
||||||
if (mUpdatedBytes > 0) {
|
if (mUpdatedBytes > 0 &&
|
||||||
|
(byteOffset >= mUpdatedOffset && byteOffset <= (mUpdatedOffset + mUpdatedBytes))) {
|
||||||
VkAccessFlags srcAccess = 0;
|
VkAccessFlags srcAccess = 0;
|
||||||
VkPipelineStageFlags srcStage = 0;
|
VkPipelineStageFlags srcStage = 0;
|
||||||
if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
|
if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
|
||||||
@@ -74,28 +75,28 @@ void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint
|
|||||||
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBufferMemoryBarrier barrier{
|
VkBufferMemoryBarrier barrier = {
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||||
.srcAccessMask = srcAccess,
|
.srcAccessMask = srcAccess,
|
||||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.buffer = mGpuBuffer,
|
.buffer = mGpuBuffer,
|
||||||
.offset = mUpdatedOffset,
|
.offset = byteOffset,
|
||||||
.size = mUpdatedBytes,
|
.size = numBytes,
|
||||||
};
|
};
|
||||||
vkCmdPipelineBarrier(cmdbuf, srcStage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1,
|
vkCmdPipelineBarrier(cmdbuf, srcStage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1,
|
||||||
&barrier, 0, nullptr);
|
&barrier, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBufferCopy region {
|
VkBufferCopy region = {
|
||||||
.srcOffset = 0,
|
.srcOffset = 0,
|
||||||
.dstOffset = byteOffset,
|
.dstOffset = byteOffset,
|
||||||
.size = numBytes,
|
.size = numBytes,
|
||||||
};
|
};
|
||||||
vkCmdCopyBuffer(cmdbuf, stage->buffer, mGpuBuffer, 1, ®ion);
|
vkCmdCopyBuffer(cmdbuf, stage->buffer, mGpuBuffer, 1, ®ion);
|
||||||
|
|
||||||
mUpdatedOffset = byteOffset;
|
mUpdatedOffset = byteOffset;
|
||||||
mUpdatedBytes = numBytes;
|
mUpdatedBytes = numBytes;
|
||||||
|
|
||||||
// Firstly, ensure that the copy finishes before the next draw call.
|
// Firstly, ensure that the copy finishes before the next draw call.
|
||||||
@@ -112,21 +113,21 @@ void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint
|
|||||||
dstAccessMask |= VK_ACCESS_INDEX_READ_BIT;
|
dstAccessMask |= VK_ACCESS_INDEX_READ_BIT;
|
||||||
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||||
} else if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
|
} else if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
|
||||||
dstAccessMask |= VK_ACCESS_UNIFORM_READ_BIT;
|
dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
|
||||||
dstStageMask |=
|
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||||
(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
|
||||||
} else if (mUsage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
|
} else if (mUsage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
|
||||||
// TODO: implement me
|
// TODO: implement me
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBufferMemoryBarrier barrier{
|
VkBufferMemoryBarrier barrier = {
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
.dstAccessMask = dstAccessMask,
|
.dstAccessMask = dstAccessMask,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.buffer = mGpuBuffer,
|
.buffer = mGpuBuffer,
|
||||||
.size = VK_WHOLE_SIZE,
|
.offset = byteOffset,
|
||||||
|
.size = numBytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 0, nullptr, 1,
|
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 0, nullptr, 1,
|
||||||
|
|||||||
@@ -151,13 +151,13 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION));
|
|||||||
|
|
||||||
#elif FVK_ENABLED(FVK_DEBUG_SYSTRACE)
|
#elif FVK_ENABLED(FVK_DEBUG_SYSTRACE)
|
||||||
|
|
||||||
#include <utils/Systrace.h>
|
#include <private/utils/Tracing.h>
|
||||||
|
|
||||||
#define FVK_SYSTRACE_CONTEXT() SYSTRACE_CONTEXT()
|
#define FVK_SYSTRACE_CONTEXT() FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT)
|
||||||
#define FVK_SYSTRACE_START(marker) SYSTRACE_NAME_BEGIN(marker)
|
#define FVK_SYSTRACE_START(marker) FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, marker)
|
||||||
#define FVK_SYSTRACE_END() SYSTRACE_NAME_END()
|
#define FVK_SYSTRACE_END() FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT)
|
||||||
#define FVK_SYSTRACE_SCOPE() SYSTRACE_CALL()
|
#define FVK_SYSTRACE_SCOPE() FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT)
|
||||||
#define FVK_PROFILE_MARKER(marker) SYSTRACE_CALL()
|
#define FVK_PROFILE_MARKER(marker) FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define FVK_SYSTRACE_CONTEXT()
|
#define FVK_SYSTRACE_CONTEXT()
|
||||||
|
|||||||
@@ -142,6 +142,10 @@ public:
|
|||||||
return mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
|
return mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool isUnifiedMemoryArchitecture() const noexcept {
|
||||||
|
return mIsUnifiedMemoryArchitecture;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
||||||
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
||||||
@@ -164,6 +168,7 @@ private:
|
|||||||
bool mDebugUtilsSupported = false;
|
bool mDebugUtilsSupported = false;
|
||||||
bool mLazilyAllocatedMemorySupported = false;
|
bool mLazilyAllocatedMemorySupported = false;
|
||||||
bool mProtectedMemorySupported = false;
|
bool mProtectedMemorySupported = false;
|
||||||
|
bool mIsUnifiedMemoryArchitecture = false;
|
||||||
|
|
||||||
fvkutils::VkFormatList mDepthStencilFormats;
|
fvkutils::VkFormatList mDepthStencilFormats;
|
||||||
fvkutils::VkFormatList mBlittableDepthStencilFormats;
|
fvkutils::VkFormatList mBlittableDepthStencilFormats;
|
||||||
|
|||||||
@@ -358,12 +358,11 @@ void VulkanDescriptorSetCache::updateSamplerImpl(VkDescriptorSet vkset, uint8_t
|
|||||||
range.levelCount = 1;
|
range.levelCount = 1;
|
||||||
range.layerCount = 1;
|
range.layerCount = 1;
|
||||||
}
|
}
|
||||||
VkDescriptorImageInfo info{
|
VkDescriptorImageInfo info = {
|
||||||
.sampler = sampler,
|
.sampler = sampler,
|
||||||
.imageView = texture->getView(range),
|
.imageView = texture->getView(range),
|
||||||
.imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout()),
|
.imageLayout = fvkutils::getVkLayout(texture->getSamplerLayout()),
|
||||||
};
|
};
|
||||||
|
|
||||||
VkWriteDescriptorSet descriptorWrite = {
|
VkWriteDescriptorSet descriptorWrite = {
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
|
|||||||
@@ -622,7 +622,7 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::S
|
|||||||
auto& commands = mCommands.get();
|
auto& commands = mCommands.get();
|
||||||
// Unlike uploaded textures or swapchains, we need to explicit transition this
|
// Unlike uploaded textures or swapchains, we need to explicit transition this
|
||||||
// texture into the read layout.
|
// texture into the read layout.
|
||||||
texture->transitionLayout(&commands, texture->getPrimaryViewRange(), VulkanLayout::READ_ONLY);
|
texture->transitionLayout(&commands, texture->getPrimaryViewRange(), VulkanLayout::FRAG_READ);
|
||||||
|
|
||||||
if (imgData.external.valid()) {
|
if (imgData.external.valid()) {
|
||||||
mExternalImageManager.addExternallySampledTexture(texture, externalImage);
|
mExternalImageManager.addExternallySampledTexture(texture, externalImage);
|
||||||
|
|||||||
@@ -93,7 +93,32 @@ BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
|
|||||||
case DescriptorType::SAMPLER_EXTERNAL:
|
case DescriptorType::SAMPLER_EXTERNAL:
|
||||||
fromStageFlags(binding.stageFlags, binding.binding, mask.externalSampler);
|
fromStageFlags(binding.stageFlags, binding.binding, mask.externalSampler);
|
||||||
UTILS_FALLTHROUGH;
|
UTILS_FALLTHROUGH;
|
||||||
case DescriptorType::SAMPLER: {
|
|
||||||
|
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_3D_INT:
|
||||||
|
case DescriptorType::SAMPLER_3D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT: {
|
||||||
fromStageFlags(binding.stageFlags, binding.binding, mask.sampler);
|
fromStageFlags(binding.stageFlags, binding.binding, mask.sampler);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -495,7 +520,8 @@ void VulkanRenderTarget::emitBarriersEndRenderPass(VulkanCommandBuffer& commands
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
texture->setLayout(range, VulkanFboCache::FINAL_COLOR_ATTACHMENT_LAYOUT);
|
texture->setLayout(range, VulkanFboCache::FINAL_COLOR_ATTACHMENT_LAYOUT);
|
||||||
if (!texture->transitionLayout(&commands, range, VulkanLayout::READ_WRITE)) {
|
if (texture->isSampleable() &&
|
||||||
|
!texture->transitionLayout(&commands, range, VulkanLayout::FRAG_READ)) {
|
||||||
texture->attachmentToSamplerBarrier(&commands, range);
|
texture->attachmentToSamplerBarrier(&commands, range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,6 +234,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
|
|||||||
|
|
||||||
VulkanAttachment const srcAttachment = srcTarget->getColor0();
|
VulkanAttachment const srcAttachment = srcTarget->getColor0();
|
||||||
VkImageSubresourceRange const srcRange = srcAttachment.getSubresourceRange();
|
VkImageSubresourceRange const srcRange = srcAttachment.getSubresourceRange();
|
||||||
|
VulkanLayout const srcLayout = srcAttachment.getLayout();
|
||||||
srcTexture->transitionLayout(cmdbuffer, srcRange, VulkanLayout::TRANSFER_SRC);
|
srcTexture->transitionLayout(cmdbuffer, srcRange, VulkanLayout::TRANSFER_SRC);
|
||||||
|
|
||||||
VkImageCopy const imageCopyRegion = {
|
VkImageCopy const imageCopyRegion = {
|
||||||
@@ -270,7 +271,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
|
|||||||
fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST), 1, &imageCopyRegion);
|
fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST), 1, &imageCopyRegion);
|
||||||
|
|
||||||
// Restore the source image layout.
|
// Restore the source image layout.
|
||||||
srcTexture->transitionLayout(cmdbuffer, srcRange, srcTexture->getDefaultLayout());
|
srcTexture->transitionLayout(cmdbuffer, srcRange, srcLayout);
|
||||||
|
|
||||||
vkEndCommandBuffer(cmdbuffer);
|
vkEndCommandBuffer(cmdbuffer);
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi
|
|||||||
fvkutils::transitionLayout(cmdbuffer, {
|
fvkutils::transitionLayout(cmdbuffer, {
|
||||||
.image = image->image,
|
.image = image->image,
|
||||||
.oldLayout = VulkanLayout::UNDEFINED,
|
.oldLayout = VulkanLayout::UNDEFINED,
|
||||||
.newLayout = VulkanLayout::READ_WRITE, // (= VK_IMAGE_LAYOUT_GENERAL)
|
.newLayout = VulkanLayout::STAGING, // (= VK_IMAGE_LAYOUT_GENERAL)
|
||||||
.subresources = { aspectFlags, 0, 1, 0, 1 },
|
.subresources = { aspectFlags, 0, 1, 0, 1 },
|
||||||
});
|
});
|
||||||
return image;
|
return image;
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ inline VulkanLayout getDefaultLayoutImpl(TextureUsage usage) {
|
|||||||
return VulkanLayout::COLOR_ATTACHMENT;
|
return VulkanLayout::COLOR_ATTACHMENT;
|
||||||
}
|
}
|
||||||
// Finally, the layout for an immutable texture is optimal read-only.
|
// Finally, the layout for an immutable texture is optimal read-only.
|
||||||
return VulkanLayout::READ_ONLY;
|
return VulkanLayout::FRAG_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VulkanLayout getDefaultLayoutImpl(VkImageUsageFlags vkusage) {
|
inline VulkanLayout getDefaultLayoutImpl(VkImageUsageFlags vkusage) {
|
||||||
@@ -187,7 +187,7 @@ VkImageUsageFlags getUsage(VulkanContext const& context, uint8_t samples,
|
|||||||
VkFormatProperties props;
|
VkFormatProperties props;
|
||||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, vkFormat, &props);
|
vkGetPhysicalDeviceFormatProperties(physicalDevice, vkFormat, &props);
|
||||||
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
|
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
|
||||||
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << mState->mVkFormat << " is not "
|
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << vkFormat << " is not "
|
||||||
"sampleable with optimal tiling." << utils::io::endl;
|
"sampleable with optimal tiling." << utils::io::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -691,6 +691,7 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR
|
|||||||
<< " is skipped because of no change in layout" << utils::io::endl;
|
<< " is skipped because of no change in layout" << utils::io::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasTransitions;
|
return hasTransitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,16 +701,15 @@ void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands,
|
|||||||
VkImageLayout const layout =
|
VkImageLayout const layout =
|
||||||
fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel));
|
fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel));
|
||||||
VkImageMemoryBarrier barrier = {
|
VkImageMemoryBarrier barrier = {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||||
.dstAccessMask =
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
.oldLayout = layout,
|
||||||
.oldLayout = layout,
|
.newLayout = layout,
|
||||||
.newLayout = layout,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.image = mState->mTextureImage,
|
||||||
.image = mState->mTextureImage,
|
.subresourceRange = range,
|
||||||
.subresourceRange = range,
|
|
||||||
};
|
};
|
||||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||||
@@ -723,15 +723,15 @@ void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands,
|
|||||||
VkImageLayout const layout
|
VkImageLayout const layout
|
||||||
= fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel));
|
= fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel));
|
||||||
VkImageMemoryBarrier barrier = {
|
VkImageMemoryBarrier barrier = {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||||
.oldLayout = layout,
|
.oldLayout = layout,
|
||||||
.newLayout = layout,
|
.newLayout = layout,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.image = mState->mTextureImage,
|
.image = mState->mTextureImage,
|
||||||
.subresourceRange = range,
|
.subresourceRange = range,
|
||||||
};
|
};
|
||||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||||
|
|||||||
@@ -145,8 +145,14 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
|||||||
|
|
||||||
VkImageSubresourceRange const& getPrimaryViewRange() const { return mPrimaryViewRange; }
|
VkImageSubresourceRange const& getPrimaryViewRange() const { return mPrimaryViewRange; }
|
||||||
|
|
||||||
VulkanLayout getPrimaryImageLayout() const {
|
VulkanLayout getSamplerLayout() const {
|
||||||
return getLayout(mPrimaryViewRange.baseArrayLayer, mPrimaryViewRange.baseMipLevel);
|
if (!isSampleable()) {
|
||||||
|
return VulkanLayout::UNDEFINED;
|
||||||
|
}
|
||||||
|
if (mState->mUsage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||||
|
return VulkanLayout::DEPTH_SAMPLER;
|
||||||
|
}
|
||||||
|
return VulkanLayout::FRAG_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the layout for the intended use of this texture (and not the expected layout at the
|
// Returns the layout for the intended use of this texture (and not the expected layout at the
|
||||||
@@ -180,6 +186,10 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
|||||||
return mState->mUsage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
|
return mState->mUsage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isSampleable() const {
|
||||||
|
return mState->mUsage & VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
bool getIsProtected() const {
|
bool getIsProtected() const {
|
||||||
return mState->mIsProtected;
|
return mState->mIsProtected;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -631,6 +631,21 @@ fvkutils::VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the GPU has a unified memory architecture.
|
||||||
|
*/
|
||||||
|
bool hasUnifiedMemoryArchitecture(VkPhysicalDeviceMemoryProperties memoryProperties) noexcept {
|
||||||
|
// Try to identify if the platform is running on a Unified Memory Architecture by inspecting the
|
||||||
|
// memory heap flags, if they are all VK_MEMORY_HEAP_DEVICE_LOCAL_BIT it's UMA, otherwise not
|
||||||
|
// enough information to make a decision, so default to false.
|
||||||
|
for (uint32_t i = 0; i < memoryProperties.memoryHeapCount; ++i) {
|
||||||
|
if ((memoryProperties.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}// anonymous namespace
|
}// anonymous namespace
|
||||||
|
|
||||||
using SwapChainPtr = VulkanPlatform::SwapChainPtr;
|
using SwapChainPtr = VulkanPlatform::SwapChainPtr;
|
||||||
@@ -864,6 +879,8 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.mIsUnifiedMemoryArchitecture = hasUnifiedMemoryArchitecture(context.mMemoryProperties);
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
// If we are in release build, we should not have turned on debug extensions
|
// If we are in release build, we should not have turned on debug extensions
|
||||||
FILAMENT_CHECK_POSTCONDITION(!context.mDebugUtilsSupported && !context.mDebugMarkersSupported)
|
FILAMENT_CHECK_POSTCONDITION(!context.mDebugUtilsSupported && !context.mDebugMarkersSupported)
|
||||||
|
|||||||
@@ -42,20 +42,22 @@ getVkTransition(const VulkanLayoutTransition& transition) {
|
|||||||
srcStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
srcStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::COLOR_ATTACHMENT:
|
case VulkanLayout::COLOR_ATTACHMENT:
|
||||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::READ_WRITE:
|
case VulkanLayout::STAGING:
|
||||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::READ_ONLY:
|
case VulkanLayout::FRAG_READ:
|
||||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
break;
|
break;
|
||||||
|
case VulkanLayout::VERT_READ:
|
||||||
|
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||||
|
break;
|
||||||
case VulkanLayout::TRANSFER_SRC:
|
case VulkanLayout::TRANSFER_SRC:
|
||||||
srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
@@ -69,7 +71,7 @@ getVkTransition(const VulkanLayoutTransition& transition) {
|
|||||||
srcStage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
srcStage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::DEPTH_SAMPLER:
|
case VulkanLayout::DEPTH_SAMPLER:
|
||||||
srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::COLOR_ATTACHMENT_RESOLVE:
|
case VulkanLayout::COLOR_ATTACHMENT_RESOLVE:
|
||||||
@@ -84,19 +86,21 @@ getVkTransition(const VulkanLayoutTransition& transition) {
|
|||||||
|
|
||||||
switch (transition.newLayout) {
|
switch (transition.newLayout) {
|
||||||
case VulkanLayout::COLOR_ATTACHMENT:
|
case VulkanLayout::COLOR_ATTACHMENT:
|
||||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT
|
dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
|
||||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
dstStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
|
dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::READ_WRITE:
|
case VulkanLayout::STAGING:
|
||||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||||
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::READ_ONLY:
|
case VulkanLayout::FRAG_READ:
|
||||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
|
break;
|
||||||
|
case VulkanLayout::VERT_READ:
|
||||||
|
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
dstStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::TRANSFER_SRC:
|
case VulkanLayout::TRANSFER_SRC:
|
||||||
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
@@ -112,10 +116,8 @@ getVkTransition(const VulkanLayoutTransition& transition) {
|
|||||||
dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::DEPTH_SAMPLER:
|
case VulkanLayout::DEPTH_SAMPLER:
|
||||||
dstAccessMask =
|
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
|
||||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
|
||||||
break;
|
break;
|
||||||
case VulkanLayout::PRESENT:
|
case VulkanLayout::PRESENT:
|
||||||
case VulkanLayout::COLOR_ATTACHMENT_RESOLVE:
|
case VulkanLayout::COLOR_ATTACHMENT_RESOLVE:
|
||||||
@@ -138,7 +140,6 @@ bool transitionLayout(VkCommandBuffer cmdbuffer,
|
|||||||
}
|
}
|
||||||
auto [srcAccessMask, dstAccessMask, srcStage, dstStage, oldLayout, newLayout]
|
auto [srcAccessMask, dstAccessMask, srcStage, dstStage, oldLayout, newLayout]
|
||||||
= getVkTransition(transition);
|
= getVkTransition(transition);
|
||||||
|
|
||||||
if (oldLayout == newLayout) {
|
if (oldLayout == newLayout) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -155,7 +156,7 @@ bool transitionLayout(VkCommandBuffer cmdbuffer,
|
|||||||
.image = transition.image,
|
.image = transition.image,
|
||||||
.subresourceRange = transition.subresources,
|
.subresourceRange = transition.subresources,
|
||||||
};
|
};
|
||||||
vkCmdPipelineBarrier(cmdbuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
vkCmdPipelineBarrier(cmdbuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,8 +265,9 @@ utils::io::ostream& operator<<(utils::io::ostream& out,
|
|||||||
const filament::backend::VulkanLayout& layout) {
|
const filament::backend::VulkanLayout& layout) {
|
||||||
switch (layout) {
|
switch (layout) {
|
||||||
CASE(UNDEFINED)
|
CASE(UNDEFINED)
|
||||||
CASE(READ_ONLY)
|
CASE(FRAG_READ)
|
||||||
CASE(READ_WRITE)
|
CASE(VERT_READ)
|
||||||
|
CASE(STAGING)
|
||||||
CASE(TRANSFER_SRC)
|
CASE(TRANSFER_SRC)
|
||||||
CASE(TRANSFER_DST)
|
CASE(TRANSFER_DST)
|
||||||
CASE(DEPTH_ATTACHMENT)
|
CASE(DEPTH_ATTACHMENT)
|
||||||
|
|||||||
@@ -32,9 +32,11 @@ enum class VulkanLayout : uint8_t {
|
|||||||
// any transition.
|
// any transition.
|
||||||
UNDEFINED,
|
UNDEFINED,
|
||||||
// Fragment/vertex shader accessible layout for reading and writing.
|
// Fragment/vertex shader accessible layout for reading and writing.
|
||||||
READ_WRITE,
|
STAGING,
|
||||||
// Fragment/vertex shader accessible layout for reading only.
|
// Fragment shader accessible layout for reading only.
|
||||||
READ_ONLY,
|
FRAG_READ,
|
||||||
|
// Vertex shader accessible layout for reading only.
|
||||||
|
VERT_READ,
|
||||||
// For the source of a copy operation.
|
// For the source of a copy operation.
|
||||||
TRANSFER_SRC,
|
TRANSFER_SRC,
|
||||||
// For the destination of a copy operation.
|
// For the destination of a copy operation.
|
||||||
@@ -65,9 +67,10 @@ constexpr inline VkImageLayout getVkLayout(VulkanLayout layout) {
|
|||||||
switch (layout) {
|
switch (layout) {
|
||||||
case VulkanLayout::UNDEFINED:
|
case VulkanLayout::UNDEFINED:
|
||||||
return VK_IMAGE_LAYOUT_UNDEFINED;
|
return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
case VulkanLayout::READ_WRITE:
|
case VulkanLayout::STAGING:
|
||||||
return VK_IMAGE_LAYOUT_GENERAL;
|
return VK_IMAGE_LAYOUT_GENERAL;
|
||||||
case VulkanLayout::READ_ONLY:
|
case VulkanLayout::FRAG_READ:
|
||||||
|
case VulkanLayout::VERT_READ:
|
||||||
return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
case VulkanLayout::TRANSFER_SRC:
|
case VulkanLayout::TRANSFER_SRC:
|
||||||
return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
@@ -80,9 +83,8 @@ constexpr inline VkImageLayout getVkLayout(VulkanLayout layout) {
|
|||||||
case VulkanLayout::PRESENT:
|
case VulkanLayout::PRESENT:
|
||||||
return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
// Filament sometimes samples from one miplevel while writing to another level in the
|
// Filament sometimes samples from one miplevel while writing to another level in the
|
||||||
// same texture (e.g. bloom does this). Moreover we'd like to avoid lots of expensive
|
// same texture (e.g. bloom does this). So, keep it simple and use GENERAL for all
|
||||||
// layout transitions. So, keep it simple and use GENERAL for all color-attachable
|
// color-attachable textures.
|
||||||
// textures.
|
|
||||||
case VulkanLayout::COLOR_ATTACHMENT:
|
case VulkanLayout::COLOR_ATTACHMENT:
|
||||||
return VK_IMAGE_LAYOUT_GENERAL;
|
return VK_IMAGE_LAYOUT_GENERAL;
|
||||||
case VulkanLayout::COLOR_ATTACHMENT_RESOLVE:
|
case VulkanLayout::COLOR_ATTACHMENT_RESOLVE:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
#include <utils/Hash.h>
|
||||||
#include "webgpu/WebGPUDriver.h"
|
#include "webgpu/WebGPUDriver.h"
|
||||||
|
|
||||||
#include "WebGPUPipelineCreation.h"
|
#include "WebGPUPipelineCreation.h"
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/Handle.h>
|
#include <backend/Handle.h>
|
||||||
#include <backend/TargetBufferInfo.h>
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
#include <private/backend/BackendUtils.h>
|
||||||
#include <math/mat3.h>
|
#include <math/mat3.h>
|
||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -234,6 +235,9 @@ WebGPUDriver::WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfi
|
|||||||
printAdapterDetails(mAdapter);
|
printAdapterDetails(mAdapter);
|
||||||
#endif
|
#endif
|
||||||
mDevice = mPlatform.requestDevice(mAdapter);
|
mDevice = mPlatform.requestDevice(mAdapter);
|
||||||
|
wgpu::Limits supportedLimits{};
|
||||||
|
mDevice.GetLimits(&supportedLimits);
|
||||||
|
mMinUniformBufferOffsetAlignment = supportedLimits.minUniformBufferOffsetAlignment;
|
||||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||||
printDeviceDetails(mDevice);
|
printDeviceDetails(mDevice);
|
||||||
#endif
|
#endif
|
||||||
@@ -350,6 +354,17 @@ void WebGPUDriver::destroyProgram(Handle<HwProgram> ph) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
void WebGPUDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
||||||
|
if (rth) {
|
||||||
|
WGPURenderTarget* rt = handleCast<WGPURenderTarget>(rth);
|
||||||
|
if (rt == mDefaultRenderTarget) {
|
||||||
|
mDefaultRenderTarget = nullptr;
|
||||||
|
}
|
||||||
|
// WGPURenderTarget destructor is trivial.
|
||||||
|
// The HwTexture handles stored within WGPURenderTarget (via MRT, TargetBufferInfo)
|
||||||
|
// are not owned by WGPURenderTarget, so they are not destroyed here.
|
||||||
|
// They are destroyed via WebGPUDriver::destroyTexture.
|
||||||
|
destructHandle<WGPURenderTarget>(rth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::destroySwapChain(Handle<HwSwapChain> sch) {
|
void WebGPUDriver::destroySwapChain(Handle<HwSwapChain> sch) {
|
||||||
@@ -468,11 +483,10 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
|||||||
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
|
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
|
||||||
mDevice, flags);
|
mDevice, flags);
|
||||||
assert_invariant(mSwapChain);
|
assert_invariant(mSwapChain);
|
||||||
WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(mDevice,
|
|
||||||
mSwapChain->getColorFormat());
|
FWGPU_LOGW << "WebGPU support is highly experimental, in development, and tested for only a "
|
||||||
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
|
"small set of simple samples (e.g. hellotriangle and texturedquad), thus issues "
|
||||||
"background components have been instantiated/selected, such as surface/screen, "
|
"are likely to be encountered at this stage."
|
||||||
"graphics device/GPU, etc.), thus nothing is being drawn to the screen."
|
|
||||||
<< utils::io::endl;
|
<< utils::io::endl;
|
||||||
#if !FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) && !defined(NDEBUG)
|
#if !FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) && !defined(NDEBUG)
|
||||||
FWGPU_LOGI << "If the FILAMENT_BACKEND_DEBUG_FLAG variable were set with the " << utils::io::hex
|
FWGPU_LOGI << "If the FILAMENT_BACKEND_DEBUG_FLAG variable were set with the " << utils::io::hex
|
||||||
@@ -577,7 +591,21 @@ void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {
|
|||||||
|
|
||||||
void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> rth, TargetBufferFlags targets,
|
void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> rth, TargetBufferFlags targets,
|
||||||
uint32_t width, uint32_t height, uint8_t samples, uint8_t layerCount, MRT color,
|
uint32_t width, uint32_t height, uint8_t samples, uint8_t layerCount, MRT color,
|
||||||
TargetBufferInfo depth, TargetBufferInfo stencil) {}
|
TargetBufferInfo depth, TargetBufferInfo stencil) {
|
||||||
|
// The `targets` flags indicate which of the `color`, `depth`, `stencil` TargetBufferInfo
|
||||||
|
// are actually active for this render target.
|
||||||
|
// We'll pass all TargetBufferInfo to WGPURenderTarget; it will use them if their handles are valid.
|
||||||
|
|
||||||
|
// Ensure that textures intended for use as attachments were created with
|
||||||
|
// wgpu::TextureUsage::RenderAttachment. This check should ideally be in createTextureR
|
||||||
|
// or validated here if possible.
|
||||||
|
|
||||||
|
// The `layerCount` parameter might be for creating array textures that this RT targets.
|
||||||
|
// Individual attachments (color[i].layer, depth.layer, stencil.layer) specify which layer
|
||||||
|
// of an array texture to bind. For now, we assume textures are pre-configured.
|
||||||
|
|
||||||
|
constructHandle<WGPURenderTarget>(rth, width, height, samples, color, depth, stencil);
|
||||||
|
}
|
||||||
|
|
||||||
void WebGPUDriver::createFenceR(Handle<HwFence> fh, int) {}
|
void WebGPUDriver::createFenceR(Handle<HwFence> fh, int) {}
|
||||||
|
|
||||||
@@ -721,17 +749,20 @@ size_t WebGPUDriver::getMaxArrayTextureLayers() {
|
|||||||
|
|
||||||
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
updateGPUBuffer(handleCast<WGPUIndexBuffer>(ibh), std::move(p), byteOffset);
|
handleCast<WGPUIndexBuffer>(ibh)->updateGPUBuffer(p, byteOffset, mQueue);
|
||||||
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> ibh, BufferDescriptor&& p,
|
void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> ibh, BufferDescriptor&& p,
|
||||||
uint32_t byteOffset) {
|
uint32_t byteOffset) {
|
||||||
updateGPUBuffer(handleCast<WGPUBufferObject>(ibh), std::move(p), byteOffset);
|
handleCast<WGPUBufferObject>(ibh)->updateGPUBuffer(p, byteOffset, mQueue);
|
||||||
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> ibh,
|
void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> ibh,
|
||||||
BufferDescriptor&& p, uint32_t byteOffset) {
|
BufferDescriptor&& p, uint32_t byteOffset) {
|
||||||
updateGPUBuffer(handleCast<WGPUBufferObject>(ibh), std::move(p), byteOffset);
|
handleCast<WGPUBufferObject>(ibh)->updateGPUBuffer(p, byteOffset, mQueue);
|
||||||
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::resetBufferObject(Handle<HwBufferObject> boh) {
|
void WebGPUDriver::resetBufferObject(Handle<HwBufferObject> boh) {
|
||||||
@@ -743,15 +774,76 @@ void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t in
|
|||||||
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
|
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
|
||||||
auto* bufferObject = handleCast<WGPUBufferObject>(boh);
|
auto* bufferObject = handleCast<WGPUBufferObject>(boh);
|
||||||
assert_invariant(index < vertexBuffer->buffers.size());
|
assert_invariant(index < vertexBuffer->buffers.size());
|
||||||
assert_invariant(bufferObject->buffer.GetUsage() & wgpu::BufferUsage::Vertex);
|
assert_invariant(bufferObject->getBuffer().GetUsage() & wgpu::BufferUsage::Vertex);
|
||||||
vertexBuffer->buffers[index] = bufferObject->buffer;
|
vertexBuffer->buffers[index] = bufferObject->getBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::update3DImage(Handle<HwTexture> th,
|
void WebGPUDriver::update3DImage(Handle<HwTexture> th, uint32_t level, uint32_t xoffset,
|
||||||
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
uint32_t yoffset, uint32_t zoffset, uint32_t width, uint32_t height, uint32_t depth,
|
||||||
uint32_t width, uint32_t height, uint32_t depth,
|
PixelBufferDescriptor&& p) {
|
||||||
PixelBufferDescriptor&& data) {
|
PixelBufferDescriptor* data = &p;
|
||||||
scheduleDestroy(std::move(data));
|
PixelBufferDescriptor reshapedData;
|
||||||
|
if (reshape(p, reshapedData)) {
|
||||||
|
data = &reshapedData;
|
||||||
|
}
|
||||||
|
auto texture = handleCast<WGPUTexture>(th);
|
||||||
|
|
||||||
|
// TODO: Writing to a depth texture is illegal and errors. I'm not sure why Filament is trying
|
||||||
|
// to do so, but early returning is working?
|
||||||
|
if(texture->getAspect() == wgpu::TextureAspect::DepthOnly){
|
||||||
|
scheduleDestroy(std::move(p));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t blockWidth = texture->getBlockWidth();
|
||||||
|
size_t blockHeight = texture->getBlockHeight();
|
||||||
|
// WebGPU specification requires that for compressed textures, the x and y offsets
|
||||||
|
// must be a multiple of the compressed texture format's block width and height.
|
||||||
|
// See: https://www.w3.org/TR/webgpu/#abstract-opdef-validating-gputexelcopytextureinfo
|
||||||
|
if (blockWidth > 1 || blockHeight > 1) {
|
||||||
|
FILAMENT_CHECK_PRECONDITION(xoffset % blockWidth == 0)
|
||||||
|
<< "xoffset must be aligned to blockwidth, but offset is " << blockWidth
|
||||||
|
<< "and offset is " << xoffset;
|
||||||
|
FILAMENT_CHECK_PRECONDITION(yoffset % blockHeight == 0)
|
||||||
|
<< "yoffset must be aligned to blockHeight, but offset is " << blockHeight
|
||||||
|
<< "and offset is " << yoffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto copyInfo = wgpu::TexelCopyTextureInfo{ .texture = texture->getTexture(),
|
||||||
|
.mipLevel = level,
|
||||||
|
.origin = { .x = xoffset, .y = yoffset, .z = zoffset },
|
||||||
|
.aspect = texture->getAspect() };
|
||||||
|
uint32_t bytesPerRow = static_cast<uint32_t>(
|
||||||
|
PixelBufferDescriptor::computePixelSize(data->format, data->type) * width);
|
||||||
|
auto extent = wgpu::Extent3D{ .width = width, .height = height, .depthOrArrayLayers = depth };
|
||||||
|
|
||||||
|
const uint8_t* dataBuff = static_cast<const uint8_t*>(data->buffer);
|
||||||
|
size_t dataSize = data->size;
|
||||||
|
std::unique_ptr<uint8_t[]> paddedBuffer;
|
||||||
|
|
||||||
|
if (bytesPerRow % 256 != 0) {
|
||||||
|
uint32_t padding = 256 - (bytesPerRow % 256);
|
||||||
|
uint32_t paddedBytesPerRow = bytesPerRow + padding;
|
||||||
|
|
||||||
|
size_t paddedBufferSize = static_cast<size_t>(paddedBytesPerRow) * height * depth;
|
||||||
|
paddedBuffer = std::make_unique<uint8_t[]>(paddedBufferSize);
|
||||||
|
uint8_t* dest = paddedBuffer.get();
|
||||||
|
|
||||||
|
for (uint32_t z = 0; z < depth; ++z) {
|
||||||
|
for (uint32_t y = 0; y < height; ++y) {
|
||||||
|
std::memcpy(dest, dataBuff, bytesPerRow);
|
||||||
|
dest += paddedBytesPerRow;
|
||||||
|
dataBuff += bytesPerRow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataBuff = paddedBuffer.get();
|
||||||
|
dataSize = paddedBufferSize;
|
||||||
|
bytesPerRow = paddedBytesPerRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto layout = wgpu::TexelCopyBufferLayout{ .bytesPerRow = bytesPerRow, .rowsPerImage = height };
|
||||||
|
|
||||||
|
mQueue.WriteTexture(©Info, dataBuff, dataSize, &layout, &extent);
|
||||||
|
scheduleDestroy(std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::setupExternalImage(void* image) {
|
void WebGPUDriver::setupExternalImage(void* image) {
|
||||||
@@ -778,56 +870,74 @@ void WebGPUDriver::compilePrograms(CompilerPriorityQueue priority,
|
|||||||
|
|
||||||
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, RenderPassParams const& params) {
|
void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, RenderPassParams const& params) {
|
||||||
assert_invariant(mCommandEncoder);
|
assert_invariant(mCommandEncoder);
|
||||||
|
|
||||||
auto* renderTarget = handleCast<WGPURenderTarget>(rth);
|
auto* renderTarget = handleCast<WGPURenderTarget>(rth);
|
||||||
// if (renderTarget == mDefaultRenderTarget) {
|
|
||||||
// FWGPU_LOGW << "Default render target"
|
wgpu::RenderPassDescriptor renderPassDescriptor{};
|
||||||
// << utils::io::endl;
|
wgpu::TextureView defaultColorView = nullptr;
|
||||||
// } else {
|
wgpu::TextureView defaultDepthStencilView = nullptr;
|
||||||
// FWGPU_LOGW << "Non Default render target"
|
|
||||||
// << utils::io::endl;
|
std::array<wgpu::TextureView, MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT> customColorViews{};
|
||||||
// }
|
uint32_t customColorViewCount = 0;
|
||||||
wgpu::RenderPassDescriptor renderPassDescriptor2;
|
wgpu::TextureView customDepthView = nullptr;
|
||||||
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{
|
wgpu::TextureView customStencilView = nullptr;
|
||||||
.view = mSwapChain->getDepthTextureView(),
|
|
||||||
.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH),
|
if (renderTarget->isDefaultRenderTarget()) {
|
||||||
.depthStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::DEPTH),
|
assert_invariant(mSwapChain && mTextureView);
|
||||||
.depthClearValue = static_cast<float>(params.clearDepth),
|
defaultColorView = mTextureView;
|
||||||
.depthReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) > 0,
|
defaultDepthStencilView = mSwapChain->getDepthTextureView();
|
||||||
.stencilLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::STENCIL),
|
|
||||||
.stencilStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::STENCIL),
|
|
||||||
.stencilClearValue = params.clearStencil,
|
|
||||||
.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0
|
|
||||||
};
|
|
||||||
renderTarget->setUpRenderPassAttachments(renderPassDescriptor2, mTextureView, params);
|
|
||||||
renderPassDescriptor2.depthStencilAttachment = &depthStencilAttachment;
|
|
||||||
// TODO: Remove this code once WebGPU pipeline is implemented
|
|
||||||
static float red = 1.0f;
|
|
||||||
if (red - 0.01 > 0) {
|
|
||||||
red -= 0.01;
|
|
||||||
} else {
|
} else {
|
||||||
red = 1.0f;
|
// Resolve views for custom render target
|
||||||
|
const auto& colorInfos = renderTarget->getColorAttachmentInfos();
|
||||||
|
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; ++i) {
|
||||||
|
if (colorInfos[i].handle) {
|
||||||
|
auto* hwTexture = handleCast<WGPUTexture>(colorInfos[i].handle);
|
||||||
|
if (hwTexture) {
|
||||||
|
// TODO: Consider colorInfos[i].level and colorInfos[i].layer for view creation
|
||||||
|
// if WGPUTexture::getTexView() isn't sufficient or needs parameters.
|
||||||
|
customColorViews[customColorViewCount++] = hwTexture->getTexView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& depthInfo = renderTarget->getDepthAttachmentInfo();
|
||||||
|
if (depthInfo.handle) {
|
||||||
|
auto* hwTexture = handleCast<WGPUTexture>(depthInfo.handle);
|
||||||
|
if (hwTexture) {
|
||||||
|
customDepthView = hwTexture->getTexView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& stencilInfo = renderTarget->getStencilAttachmentInfo();
|
||||||
|
if (stencilInfo.handle) {
|
||||||
|
// If depth and stencil use the same texture handle, this will re-cast but that's fine.
|
||||||
|
auto* hwTexture = handleCast<WGPUTexture>(stencilInfo.handle);
|
||||||
|
if (hwTexture) {
|
||||||
|
customStencilView = hwTexture->getTexView();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
assert_invariant(mTextureView);
|
|
||||||
wgpu::RenderPassColorAttachment renderPassColorAttachment = {
|
|
||||||
.view = mTextureView,
|
|
||||||
// TODO: remove this code once WebGPU Pipeline is implemented with render targets, pipeline and buffers.
|
|
||||||
.depthSlice = wgpu::kDepthSliceUndefined,
|
|
||||||
.loadOp = wgpu::LoadOp::Clear,
|
|
||||||
.storeOp = wgpu::StoreOp::Store,
|
|
||||||
.clearValue = wgpu::Color{red, 0 , 0 , 1},
|
|
||||||
};
|
|
||||||
|
|
||||||
wgpu::RenderPassDescriptor renderPassDescriptor = {
|
renderTarget->setUpRenderPassAttachments(renderPassDescriptor,
|
||||||
.colorAttachmentCount = 1,
|
params,
|
||||||
.colorAttachments = &renderPassColorAttachment,
|
defaultColorView,
|
||||||
.depthStencilAttachment = nullptr,
|
defaultDepthStencilView,
|
||||||
.timestampWrites = nullptr,
|
customColorViews.data(),
|
||||||
};
|
customColorViewCount,
|
||||||
|
customDepthView,
|
||||||
|
customStencilView);
|
||||||
|
|
||||||
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor2);
|
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor);
|
||||||
mRenderPassEncoder.SetViewport(params.viewport.left, params.viewport.bottom,
|
// Ensure viewport dimensions are positive
|
||||||
params.viewport.width, params.viewport.height, params.depthRange.near, params.depthRange.far);
|
uint32_t viewportWidth = params.viewport.width > 0 ? params.viewport.width : 1;
|
||||||
|
uint32_t viewportHeight = params.viewport.height > 0 ? params.viewport.height : 1;
|
||||||
|
|
||||||
|
mRenderPassEncoder.SetViewport(
|
||||||
|
static_cast<float>(params.viewport.left),
|
||||||
|
static_cast<float>(params.viewport.bottom),
|
||||||
|
static_cast<float>(viewportWidth),
|
||||||
|
static_cast<float>(viewportHeight),
|
||||||
|
params.depthRange.near,
|
||||||
|
params.depthRange.far);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::endRenderPass(int /* dummy */) {
|
void WebGPUDriver::endRenderPass(int /* dummy */) {
|
||||||
@@ -916,6 +1026,14 @@ void WebGPUDriver::blit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||||
|
// TODO Investigate implications of this hash more closely. Vulkan has a whole class
|
||||||
|
// VulkanPipelineCache to handle this, may be missing nuance
|
||||||
|
static auto pipleineStateHasher = utils::hash::MurmurHashFn<filament::backend::PipelineState>();
|
||||||
|
auto hash = pipleineStateHasher(pipelineState);
|
||||||
|
if(mPipelineMap.find(hash) != mPipelineMap.end()){
|
||||||
|
mRenderPassEncoder.SetPipeline(mPipelineMap[hash]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto* program = handleCast<WGPUProgram>(pipelineState.program);
|
const auto* program = handleCast<WGPUProgram>(pipelineState.program);
|
||||||
assert_invariant(program);
|
assert_invariant(program);
|
||||||
assert_invariant(program->computeShaderModule == nullptr &&
|
assert_invariant(program->computeShaderModule == nullptr &&
|
||||||
@@ -952,7 +1070,7 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
|||||||
*vertexBufferInfo, layout, pipelineState.rasterState, pipelineState.stencilState,
|
*vertexBufferInfo, layout, pipelineState.rasterState, pipelineState.stencilState,
|
||||||
pipelineState.polygonOffset, pipelineState.primitiveType, mSwapChain->getColorFormat(),
|
pipelineState.polygonOffset, pipelineState.primitiveType, mSwapChain->getColorFormat(),
|
||||||
mSwapChain->getDepthFormat());
|
mSwapChain->getDepthFormat());
|
||||||
// TODO: uncomment once we have a valid pipeline to set
|
mPipelineMap[hash] = pipeline;
|
||||||
mRenderPassEncoder.SetPipeline(pipeline);
|
mRenderPassEncoder.SetPipeline(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,18 +1086,12 @@ void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
|||||||
mRenderPassEncoder.SetVertexBuffer(i, renderPrimitive->vertexBuffer->buffers[i]);
|
mRenderPassEncoder.SetVertexBuffer(i, renderPrimitive->vertexBuffer->buffers[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mRenderPassEncoder.SetIndexBuffer(renderPrimitive->indexBuffer->buffer,
|
mRenderPassEncoder.SetIndexBuffer(renderPrimitive->indexBuffer->getBuffer(),
|
||||||
renderPrimitive->indexBuffer->indexFormat);
|
renderPrimitive->indexBuffer->indexFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
||||||
// Calling DrawIndexed with "firstInstance = 0" results in a NON spinning triangle
|
mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 0);
|
||||||
// mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 0);
|
|
||||||
// Calling DrawIndexed with "firstInstance = 1" results in a spinning triangle
|
|
||||||
mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 1);
|
|
||||||
// Calling Draw with "firstInstance = 0" results in a NON spinning triangle
|
|
||||||
// Calling Draw with "firstInstance = 1" results in a spinning triangle
|
|
||||||
// mRenderPassEncoder.Draw(indexCount, instanceCount, 0, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::draw(PipelineState, Handle<HwRenderPrimitive>, uint32_t indexOffset,
|
void WebGPUDriver::draw(PipelineState, Handle<HwRenderPrimitive>, uint32_t indexOffset,
|
||||||
@@ -1010,8 +1122,11 @@ void WebGPUDriver::updateDescriptorSetBuffer(Handle<HwDescriptorSet> dsh,
|
|||||||
auto buffer = handleCast<WGPUBufferObject>(boh);
|
auto buffer = handleCast<WGPUBufferObject>(boh);
|
||||||
if (!bindGroup->getIsLocked()) {
|
if (!bindGroup->getIsLocked()) {
|
||||||
// TODO making assumptions that size and offset mean the same thing here.
|
// TODO making assumptions that size and offset mean the same thing here.
|
||||||
|
FILAMENT_CHECK_PRECONDITION(offset % mMinUniformBufferOffsetAlignment == 0)
|
||||||
|
<< "Binding offset must be multiple of " << mMinUniformBufferOffsetAlignment
|
||||||
|
<< "But requested offset is " << offset;
|
||||||
wgpu::BindGroupEntry entry{ .binding = static_cast<uint32_t>(binding * 2),
|
wgpu::BindGroupEntry entry{ .binding = static_cast<uint32_t>(binding * 2),
|
||||||
.buffer = buffer->buffer,
|
.buffer = buffer->getBuffer(),
|
||||||
.offset = offset,
|
.offset = offset,
|
||||||
.size = size };
|
.size = size };
|
||||||
bindGroup->addEntry(entry.binding, std::move(entry));
|
bindGroup->addEntry(entry.binding, std::move(entry));
|
||||||
@@ -1043,115 +1158,105 @@ void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> dsh,
|
|||||||
const auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
const auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
||||||
const auto wbg = bindGroup->lockAndReturn(mDevice);
|
const auto wbg = bindGroup->lockAndReturn(mDevice);
|
||||||
assert_invariant(mRenderPassEncoder);
|
assert_invariant(mRenderPassEncoder);
|
||||||
// TODO is this how we should be getting the dynamic offsets?
|
|
||||||
// should we add offsets for unused entries or is the input already have them?
|
|
||||||
// this implementation assumes unused entries are not provided, and adds dummy values.
|
|
||||||
// The count also includes unused entities, as not doing so produces errors
|
|
||||||
const size_t dynamicOffsetCount = bindGroup->countEntitiesWithDynamicOffsets();
|
const size_t dynamicOffsetCount = bindGroup->countEntitiesWithDynamicOffsets();
|
||||||
uint32_t const* const dynamicOffsetsWithUnused = bindGroup->setDynamicOffsets(offsets.data());
|
mRenderPassEncoder.SetBindGroup(setIndex, wbg, dynamicOffsetCount, offsets.data());
|
||||||
mRenderPassEncoder.SetBindGroup(setIndex, wbg, dynamicOffsetCount, dynamicOffsetsWithUnused);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
||||||
}
|
}
|
||||||
wgpu::Sampler WebGPUDriver::makeSampler(SamplerParams const& params) {
|
wgpu::Sampler WebGPUDriver::makeSampler(SamplerParams const& params) {
|
||||||
wgpu::SamplerDescriptor desc;
|
wgpu::SamplerDescriptor desc{};
|
||||||
|
|
||||||
desc.label = "TODO";
|
desc.label = "TODO";
|
||||||
desc.addressModeU = fWrapModeToWAddressMode(params.wrapS);
|
desc.addressModeU = fWrapModeToWAddressMode(params.wrapS);
|
||||||
desc.addressModeV = fWrapModeToWAddressMode(params.wrapR);
|
desc.addressModeV = fWrapModeToWAddressMode(params.wrapR);
|
||||||
desc.addressModeW = fWrapModeToWAddressMode(params.wrapT);
|
desc.addressModeW = fWrapModeToWAddressMode(params.wrapT);
|
||||||
switch (params.filterMag) {
|
if (params.compareMode == SamplerCompareMode::COMPARE_TO_TEXTURE) {
|
||||||
case SamplerMagFilter::NEAREST: {
|
switch (params.filterMag) {
|
||||||
desc.magFilter = wgpu::FilterMode::Nearest;
|
case SamplerMagFilter::NEAREST: {
|
||||||
break;
|
desc.magFilter = wgpu::FilterMode::Nearest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SamplerMagFilter::LINEAR: {
|
||||||
|
desc.magFilter = wgpu::FilterMode::Linear;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case SamplerMagFilter::LINEAR: {
|
switch (params.filterMin) {
|
||||||
desc.magFilter = wgpu::FilterMode::Linear;
|
case SamplerMinFilter::NEAREST: {
|
||||||
break;
|
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||||
}
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Undefined;
|
||||||
}
|
break;
|
||||||
switch (params.filterMin) {
|
}
|
||||||
case SamplerMinFilter::NEAREST: {
|
case SamplerMinFilter::LINEAR: {
|
||||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
desc.minFilter = wgpu::FilterMode::Linear;
|
||||||
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Undefined;
|
||||||
// suffice
|
break;
|
||||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
}
|
||||||
break;
|
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: {
|
||||||
}
|
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||||
case SamplerMinFilter::LINEAR: {
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||||
desc.minFilter = wgpu::FilterMode::Linear;
|
break;
|
||||||
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
|
}
|
||||||
// suffice
|
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: {
|
||||||
|
desc.minFilter = wgpu::FilterMode::Linear;
|
||||||
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||||
|
|
||||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: {
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: {
|
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: {
|
|
||||||
desc.minFilter = wgpu::FilterMode::Linear;
|
|
||||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: {
|
||||||
|
desc.minFilter = wgpu::FilterMode::Linear;
|
||||||
|
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: {
|
switch (params.compareFunc) {
|
||||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
case SamplerCompareFunc::LE: {
|
||||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
desc.compare = wgpu::CompareFunction::LessEqual;
|
||||||
|
break;
|
||||||
break;
|
}
|
||||||
}
|
case SamplerCompareFunc::GE: {
|
||||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: {
|
desc.compare = wgpu::CompareFunction::GreaterEqual;
|
||||||
desc.minFilter = wgpu::FilterMode::Linear;
|
break;
|
||||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
}
|
||||||
break;
|
case SamplerCompareFunc::L: {
|
||||||
}
|
desc.compare = wgpu::CompareFunction::Less;
|
||||||
}
|
break;
|
||||||
switch (params.compareFunc) {
|
}
|
||||||
case SamplerCompareFunc::LE: {
|
case SamplerCompareFunc::G: {
|
||||||
desc.compare = wgpu::CompareFunction::LessEqual;
|
desc.compare = wgpu::CompareFunction::Greater;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SamplerCompareFunc::GE: {
|
case SamplerCompareFunc::E: {
|
||||||
desc.compare = wgpu::CompareFunction::GreaterEqual;
|
desc.compare = wgpu::CompareFunction::Equal;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SamplerCompareFunc::L: {
|
case SamplerCompareFunc::NE: {
|
||||||
desc.compare = wgpu::CompareFunction::Less;
|
desc.compare = wgpu::CompareFunction::NotEqual;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SamplerCompareFunc::G: {
|
case SamplerCompareFunc::A: {
|
||||||
desc.compare = wgpu::CompareFunction::Greater;
|
desc.compare = wgpu::CompareFunction::Always;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SamplerCompareFunc::E: {
|
case SamplerCompareFunc::N: {
|
||||||
desc.compare = wgpu::CompareFunction::Equal;
|
desc.compare = wgpu::CompareFunction::Never;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SamplerCompareFunc::NE: {
|
|
||||||
desc.compare = wgpu::CompareFunction::NotEqual;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SamplerCompareFunc::A: {
|
|
||||||
desc.compare = wgpu::CompareFunction::Always;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SamplerCompareFunc::N: {
|
|
||||||
desc.compare = wgpu::CompareFunction::Never;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
desc.maxAnisotropy = 1u << params.anisotropyLog2;
|
desc.maxAnisotropy = 1u << params.anisotropyLog2;
|
||||||
|
|
||||||
|
// Unused: WGPU lodMinClamp/lodMaxClamp unnecessary
|
||||||
|
|
||||||
// Unused: Filament's compareMode, WGPU lodMinClamp/lodMaxClamp
|
return mDevice.CreateSampler(&desc);
|
||||||
|
|
||||||
//TODO Once we can properly map to descriptorsetlayout use the sampler.
|
|
||||||
return mDevice.CreateSampler(/*&desc*/);
|
|
||||||
}
|
}
|
||||||
wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& fWrapMode) {
|
wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& fWrapMode) {
|
||||||
switch (fWrapMode) {
|
switch (fWrapMode) {
|
||||||
@@ -1171,5 +1276,4 @@ wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& f
|
|||||||
return wgpu::AddressMode::Undefined;
|
return wgpu::AddressMode::Undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace filament
|
} // namespace filament
|
||||||
|
|||||||
@@ -58,32 +58,13 @@ private:
|
|||||||
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
||||||
[[nodiscard]] wgpu::Sampler makeSampler(SamplerParams const& params);
|
[[nodiscard]] wgpu::Sampler makeSampler(SamplerParams const& params);
|
||||||
[[nodiscard]] static wgpu::AddressMode fWrapModeToWAddressMode(const filament::backend::SamplerWrapMode& fUsage);
|
[[nodiscard]] static wgpu::AddressMode fWrapModeToWAddressMode(const filament::backend::SamplerWrapMode& fUsage);
|
||||||
template<typename GPUBufferObject>
|
|
||||||
void updateGPUBuffer(GPUBufferObject* gpuBufferObject, BufferDescriptor&& bufferDescriptor,
|
|
||||||
uint32_t byteOffset) {
|
|
||||||
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer)
|
|
||||||
<< "copyIntoBuffer called with a null buffer";
|
|
||||||
FILAMENT_CHECK_PRECONDITION(
|
|
||||||
bufferDescriptor.size + byteOffset <= gpuBufferObject->buffer.GetSize())
|
|
||||||
<< "Attempting to copy " << bufferDescriptor.size << " bytes into a buffer of size "
|
|
||||||
<< gpuBufferObject->buffer.GetSize() << " at offset " << byteOffset;
|
|
||||||
|
|
||||||
// TODO: All buffer objects are created with CopyDst usage.
|
|
||||||
// This may have some performance implications. That should be investigated later.
|
|
||||||
assert_invariant(gpuBufferObject->buffer.GetUsage() & wgpu::BufferUsage::CopyDst);
|
|
||||||
|
|
||||||
// WriteBuffer is an async call. But cpu buffer data is already written to the staging
|
|
||||||
// buffer on return from the WriteBuffer.
|
|
||||||
mQueue.WriteBuffer(gpuBufferObject->buffer, byteOffset, bufferDescriptor.buffer,
|
|
||||||
bufferDescriptor.size);
|
|
||||||
scheduleDestroy(std::move(bufferDescriptor));
|
|
||||||
}
|
|
||||||
|
|
||||||
// the platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
|
// the platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
|
||||||
// handled in the WebGPUPlatform
|
// handled in the WebGPUPlatform
|
||||||
WebGPUPlatform& mPlatform;
|
WebGPUPlatform& mPlatform;
|
||||||
wgpu::Adapter mAdapter = nullptr;
|
wgpu::Adapter mAdapter = nullptr;
|
||||||
wgpu::Device mDevice = nullptr;
|
wgpu::Device mDevice = nullptr;
|
||||||
|
uint32_t mMinUniformBufferOffsetAlignment;
|
||||||
wgpu::Queue mQueue = nullptr;
|
wgpu::Queue mQueue = nullptr;
|
||||||
void* mNativeWindow = nullptr;
|
void* mNativeWindow = nullptr;
|
||||||
WebGPUSwapChain* mSwapChain = nullptr;
|
WebGPUSwapChain* mSwapChain = nullptr;
|
||||||
@@ -93,6 +74,8 @@ private:
|
|||||||
wgpu::RenderPassEncoder mRenderPassEncoder = nullptr;
|
wgpu::RenderPassEncoder mRenderPassEncoder = nullptr;
|
||||||
wgpu::CommandBuffer mCommandBuffer = nullptr;
|
wgpu::CommandBuffer mCommandBuffer = nullptr;
|
||||||
WGPURenderTarget* mDefaultRenderTarget = nullptr;
|
WGPURenderTarget* mDefaultRenderTarget = nullptr;
|
||||||
|
|
||||||
|
tsl::robin_map<uint32_t, wgpu::RenderPipeline> mPipelineMap;
|
||||||
/*
|
/*
|
||||||
* Driver interface
|
* Driver interface
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
#include <utils/BitmaskEnum.h>
|
#include <utils/BitmaskEnum.h>
|
||||||
|
#include <utils/Panic.h>
|
||||||
|
#include <private/backend/BackendUtils.h>
|
||||||
#include <webgpu/webgpu_cpp.h>
|
#include <webgpu/webgpu_cpp.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -40,15 +41,6 @@ constexpr wgpu::BufferUsage getBufferObjectUsage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::Buffer createBuffer(wgpu::Device const& device, wgpu::BufferUsage usage, uint32_t size,
|
|
||||||
char const* label) {
|
|
||||||
wgpu::BufferDescriptor descriptor{ .label = label,
|
|
||||||
.usage = usage,
|
|
||||||
.size = size,
|
|
||||||
.mappedAtCreation = false };
|
|
||||||
return device.CreateBuffer(&descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
wgpu::VertexFormat getVertexFormat(filament::backend::ElementType type, bool normalized, bool integer) {
|
wgpu::VertexFormat getVertexFormat(filament::backend::ElementType type, bool normalized, bool integer) {
|
||||||
using ElementType = filament::backend::ElementType;
|
using ElementType = filament::backend::ElementType;
|
||||||
using VertexFormat = wgpu::VertexFormat;
|
using VertexFormat = wgpu::VertexFormat;
|
||||||
@@ -76,7 +68,7 @@ wgpu::VertexFormat getVertexFormat(filament::backend::ElementType type, bool nor
|
|||||||
case ElementType::BYTE4: return VertexFormat::Snorm8x4;
|
case ElementType::BYTE4: return VertexFormat::Snorm8x4;
|
||||||
case ElementType::UBYTE4: return VertexFormat::Unorm8x4;
|
case ElementType::UBYTE4: return VertexFormat::Unorm8x4;
|
||||||
case ElementType::SHORT4: return VertexFormat::Snorm16x4;
|
case ElementType::SHORT4: return VertexFormat::Snorm16x4;
|
||||||
case ElementType::USHORT4: return VertexFormat::Unorm8x4;
|
case ElementType::USHORT4: return VertexFormat::Unorm16x4;
|
||||||
default:
|
default:
|
||||||
FILAMENT_CHECK_POSTCONDITION(false) << "Normalized format does not exist.";
|
FILAMENT_CHECK_POSTCONDITION(false) << "Normalized format does not exist.";
|
||||||
return VertexFormat::Float32x3;
|
return VertexFormat::Float32x3;
|
||||||
@@ -119,10 +111,91 @@ wgpu::VertexFormat getVertexFormat(filament::backend::ElementType type, bool nor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wgpu::StringView getUserTextureLabel(filament::backend::SamplerType target) {
|
||||||
|
// TODO will be helpful to get more useful info than this
|
||||||
|
using filament::backend::SamplerType;
|
||||||
|
switch (target) {
|
||||||
|
case SamplerType::SAMPLER_2D:
|
||||||
|
return "a_2D_user_texture";
|
||||||
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
|
return "a_2D_array_user_texture";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
return "a_cube_map_user_texture";
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL:
|
||||||
|
return "an_external_user_texture";
|
||||||
|
case SamplerType::SAMPLER_3D:
|
||||||
|
return "a_3D_user_texture";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
return "a_cube_map_array_user_texture";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::StringView getUserTextureViewLabel(filament::backend::SamplerType target) {
|
||||||
|
// TODO will be helpful to get more useful info than this
|
||||||
|
using filament::backend::SamplerType;
|
||||||
|
switch (target) {
|
||||||
|
case SamplerType::SAMPLER_2D:
|
||||||
|
return "a_2D_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
|
return "a_2D_array_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
return "a_cube_map_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL:
|
||||||
|
return "an_external_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_3D:
|
||||||
|
return "a_3D_user_texture_view";
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
return "a_cube_map_array_user_texture_view";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}// namespace
|
}// namespace
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
void WGPUBufferBase::createBuffer(const wgpu::Device& device, wgpu::BufferUsage usage,
|
||||||
|
uint32_t size, const char* label) {
|
||||||
|
// Write size must be divisible by 4. If the whole buffer is written to as is common, so must
|
||||||
|
// the buffer size.
|
||||||
|
size += (4 - (size % 4)) % 4;
|
||||||
|
wgpu::BufferDescriptor descriptor{ .label = label,
|
||||||
|
.usage = usage,
|
||||||
|
.size = size,
|
||||||
|
.mappedAtCreation = false };
|
||||||
|
buffer = device.CreateBuffer(&descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WGPUBufferBase::updateGPUBuffer(BufferDescriptor& bufferDescriptor, uint32_t byteOffset,
|
||||||
|
wgpu::Queue queue) {
|
||||||
|
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer)
|
||||||
|
<< "copyIntoBuffer called with a null buffer";
|
||||||
|
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.size + byteOffset <= buffer.GetSize())
|
||||||
|
<< "Attempting to copy " << bufferDescriptor.size << " bytes into a buffer of size "
|
||||||
|
<< buffer.GetSize() << " at offset " << byteOffset;
|
||||||
|
FILAMENT_CHECK_PRECONDITION(byteOffset % 4 == 0)
|
||||||
|
<< "Byte offset must be a multiple of 4 but is " << byteOffset;
|
||||||
|
|
||||||
|
// TODO: All buffer objects are created with CopyDst usage.
|
||||||
|
// This may have some performance implications. That should be investigated later.
|
||||||
|
assert_invariant(buffer.GetUsage() & wgpu::BufferUsage::CopyDst);
|
||||||
|
|
||||||
|
size_t remainder = bufferDescriptor.size % 4;
|
||||||
|
|
||||||
|
// WriteBuffer is an async call. But cpu buffer data is already written to the staging
|
||||||
|
// buffer on return from the WriteBuffer.
|
||||||
|
auto legalSize = bufferDescriptor.size - remainder;
|
||||||
|
queue.WriteBuffer(buffer, byteOffset, bufferDescriptor.buffer, legalSize);
|
||||||
|
if (remainder != 0) {
|
||||||
|
const uint8_t* remainderStart =
|
||||||
|
static_cast<const uint8_t*>(bufferDescriptor.buffer) + legalSize;
|
||||||
|
memcpy(mRemainderChunk.data(), remainderStart, remainder);
|
||||||
|
// Pad the remainder with zeros to ensure deterministic behavior, though GPU shouldn't
|
||||||
|
// access this
|
||||||
|
std::memset(mRemainderChunk.data() + remainder, 0, 4 - remainder);
|
||||||
|
|
||||||
|
queue.WriteBuffer(buffer, byteOffset + legalSize, &mRemainderChunk, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
|
WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
|
||||||
AttributeArray const& attributes)
|
AttributeArray const& attributes)
|
||||||
: HwVertexBufferInfo(bufferCount, attributeCount),
|
: HwVertexBufferInfo(bufferCount, attributeCount),
|
||||||
@@ -165,9 +238,10 @@ WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attribut
|
|||||||
|
|
||||||
WGPUIndexBuffer::WGPUIndexBuffer(wgpu::Device const& device, uint8_t elementSize,
|
WGPUIndexBuffer::WGPUIndexBuffer(wgpu::Device const& device, uint8_t elementSize,
|
||||||
uint32_t indexCount)
|
uint32_t indexCount)
|
||||||
: buffer(createBuffer(device, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Index,
|
: indexFormat(elementSize == 2 ? wgpu::IndexFormat::Uint16 : wgpu::IndexFormat::Uint32) {
|
||||||
elementSize * indexCount, "index_buffer")),
|
createBuffer(device, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Index,
|
||||||
indexFormat(elementSize == 2 ? wgpu::IndexFormat::Uint16 : wgpu::IndexFormat::Uint32) {}
|
elementSize * indexCount, "index_buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
WGPUVertexBuffer::WGPUVertexBuffer(wgpu::Device const& device, uint32_t vertexCount,
|
WGPUVertexBuffer::WGPUVertexBuffer(wgpu::Device const& device, uint32_t vertexCount,
|
||||||
@@ -178,10 +252,10 @@ WGPUVertexBuffer::WGPUVertexBuffer(wgpu::Device const& device, uint32_t vertexCo
|
|||||||
|
|
||||||
WGPUBufferObject::WGPUBufferObject(wgpu::Device const& device, BufferObjectBinding bindingType,
|
WGPUBufferObject::WGPUBufferObject(wgpu::Device const& device, BufferObjectBinding bindingType,
|
||||||
uint32_t byteCount)
|
uint32_t byteCount)
|
||||||
: HwBufferObject(byteCount),
|
: HwBufferObject(byteCount) {
|
||||||
buffer(createBuffer(device, wgpu::BufferUsage::CopyDst | getBufferObjectUsage(bindingType),
|
createBuffer(device, wgpu::BufferUsage::CopyDst | getBufferObjectUsage(bindingType), byteCount,
|
||||||
byteCount, "buffer_object")),
|
"buffer_object");
|
||||||
bufferObjectBinding(bindingType) {}
|
}
|
||||||
|
|
||||||
wgpu::ShaderStage WebGPUDescriptorSetLayout::filamentStageToWGPUStage(ShaderStageFlags fFlags) {
|
wgpu::ShaderStage WebGPUDescriptorSetLayout::filamentStageToWGPUStage(ShaderStageFlags fFlags) {
|
||||||
wgpu::ShaderStage retStages = wgpu::ShaderStage::None;
|
wgpu::ShaderStage retStages = wgpu::ShaderStage::None;
|
||||||
@@ -201,14 +275,22 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
|||||||
wgpu::Device const& device) {
|
wgpu::Device const& device) {
|
||||||
assert_invariant(device);
|
assert_invariant(device);
|
||||||
|
|
||||||
|
std::string baseLabel;
|
||||||
|
if (std::holds_alternative<utils::StaticString>(layout.label)) {
|
||||||
|
const auto& temp = std::get_if<utils::StaticString>(&layout.label);
|
||||||
|
baseLabel = temp->c_str();
|
||||||
|
} else if (std::holds_alternative<utils::CString>(layout.label)) {
|
||||||
|
const auto& temp = std::get_if<utils::CString>(&layout.label);
|
||||||
|
baseLabel = temp->c_str();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
|
// TODO: layoutDescriptor has a "Label". Ideally we can get info on what this layout is for
|
||||||
// debugging. For now, hack an incrementing value.
|
// debugging. For now, hack an incrementing value.
|
||||||
static int layoutNum = 0;
|
static int layoutNum = 0;
|
||||||
|
|
||||||
unsigned int samplerCount =
|
unsigned int samplerCount =
|
||||||
std::count_if(layout.bindings.begin(), layout.bindings.end(), [](auto& fEntry) {
|
std::count_if(layout.bindings.begin(), layout.bindings.end(), [](auto& fEntry) {
|
||||||
return fEntry.type == DescriptorType::SAMPLER ||
|
return DescriptorSetLayoutBinding::isSampler(fEntry.type);
|
||||||
fEntry.type == DescriptorType::SAMPLER_EXTERNAL;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -224,18 +306,44 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
|||||||
entryInfo.binding = wEntry.binding;
|
entryInfo.binding = wEntry.binding;
|
||||||
|
|
||||||
switch (fEntry.type) {
|
switch (fEntry.type) {
|
||||||
case DescriptorType::SAMPLER_EXTERNAL:
|
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||||
case DescriptorType::SAMPLER: {
|
case DescriptorType::SAMPLER_2D_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||||
|
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||||
|
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_3D_INT:
|
||||||
|
case DescriptorType::SAMPLER_3D_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||||
|
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT: {
|
||||||
auto& samplerEntry = wEntries.emplace_back();
|
auto& samplerEntry = wEntries.emplace_back();
|
||||||
auto& samplerEntryInfo = mBindGroupEntries.emplace_back();
|
auto& samplerEntryInfo = mBindGroupEntries.emplace_back();
|
||||||
samplerEntry.binding = fEntry.binding * 2 + 1;
|
samplerEntry.binding = fEntry.binding * 2 + 1;
|
||||||
samplerEntryInfo.binding = samplerEntry.binding;
|
samplerEntryInfo.binding = samplerEntry.binding;
|
||||||
samplerEntryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER;
|
|
||||||
samplerEntry.visibility = wEntry.visibility;
|
samplerEntry.visibility = wEntry.visibility;
|
||||||
// We are simply hoping that undefined and defaults suffices here.
|
wEntry.texture.multisampled = isMultiSampledTypeDescriptor(fEntry.type);
|
||||||
samplerEntry.sampler.type = wgpu::SamplerBindingType::NonFiltering; // Example default
|
// TODO: Set once we have the filtering values
|
||||||
wEntry.texture.sampleType = wgpu::TextureSampleType::Float; // Example default
|
if (isDepthDescriptor(fEntry.type)) {
|
||||||
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW;
|
samplerEntry.sampler.type = wgpu::SamplerBindingType::Comparison;
|
||||||
|
} else {
|
||||||
|
samplerEntry.sampler.type =
|
||||||
|
wgpu::SamplerBindingType::NonFiltering;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DescriptorType::UNIFORM_BUFFER: {
|
case DescriptorType::UNIFORM_BUFFER: {
|
||||||
@@ -246,7 +354,6 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
|||||||
// TODO: Ideally we fill minBindingSize
|
// TODO: Ideally we fill minBindingSize
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DescriptorType::INPUT_ATTACHMENT: {
|
case DescriptorType::INPUT_ATTACHMENT: {
|
||||||
PANIC_POSTCONDITION("Input Attachment is not supported");
|
PANIC_POSTCONDITION("Input Attachment is not supported");
|
||||||
break;
|
break;
|
||||||
@@ -255,10 +362,52 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
|||||||
PANIC_POSTCONDITION("Shader storage is not supported");
|
PANIC_POSTCONDITION("Shader storage is not supported");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DescriptorType::SAMPLER_EXTERNAL: {
|
||||||
|
PANIC_POSTCONDITION("External Sampler is not supported");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isDepthDescriptor(fEntry.type))
|
||||||
|
{
|
||||||
|
wEntry.texture.sampleType = wgpu::TextureSampleType::Depth;
|
||||||
|
}
|
||||||
|
else if (isFloatDescriptor(fEntry.type))
|
||||||
|
{
|
||||||
|
// TODO: Set once we have the filtering values
|
||||||
|
wEntry.texture.sampleType = wgpu::TextureSampleType::UnfilterableFloat;
|
||||||
|
}
|
||||||
|
else if (isIntDescriptor(fEntry.type))
|
||||||
|
{
|
||||||
|
wEntry.texture.sampleType = wgpu::TextureSampleType::Sint;
|
||||||
|
}
|
||||||
|
else if (isUnsignedIntDescriptor(fEntry.type))
|
||||||
|
{
|
||||||
|
wEntry.texture.sampleType = wgpu::TextureSampleType::Uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is3dTypeDescriptor(fEntry.type))
|
||||||
|
{
|
||||||
|
wEntry.texture.viewDimension = wgpu::TextureViewDimension::e3D;
|
||||||
|
}
|
||||||
|
else if (is2dTypeDescriptor(fEntry.type))
|
||||||
|
{
|
||||||
|
wEntry.texture.viewDimension = wgpu::TextureViewDimension::e2D;
|
||||||
|
}
|
||||||
|
else if (is2dArrayTypeDescriptor(fEntry.type))
|
||||||
|
{
|
||||||
|
wEntry.texture.viewDimension = wgpu::TextureViewDimension::e2DArray;
|
||||||
|
}
|
||||||
|
else if (isCubeTypeDescriptor(fEntry.type))
|
||||||
|
{
|
||||||
|
wEntry.texture.viewDimension = wgpu::TextureViewDimension::Cube;
|
||||||
|
}
|
||||||
|
else if (isCubeArrayTypeDescriptor(fEntry.type))
|
||||||
|
{
|
||||||
|
wEntry.texture.viewDimension = wgpu::TextureViewDimension::CubeArray;
|
||||||
}
|
}
|
||||||
// fEntry.count is unused currently
|
// fEntry.count is unused currently
|
||||||
}
|
}
|
||||||
std::string label = "layout_"+ std::to_string(++layoutNum) ;
|
std::string label = "layout_" + baseLabel + std::to_string(++layoutNum) ;
|
||||||
wgpu::BindGroupLayoutDescriptor layoutDescriptor{
|
wgpu::BindGroupLayoutDescriptor layoutDescriptor{
|
||||||
.label{label.c_str()}, // Use .c_str() if label needs to be const char*
|
.label{label.c_str()}, // Use .c_str() if label needs to be const char*
|
||||||
.entryCount = wEntries.size(),
|
.entryCount = wEntries.size(),
|
||||||
@@ -269,114 +418,26 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
|||||||
|
|
||||||
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
|
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
|
||||||
|
|
||||||
wgpu::Buffer WebGPUDescriptorSet::sDummyUniformBuffer = nullptr;
|
|
||||||
wgpu::Texture WebGPUDescriptorSet::sDummyTexture = nullptr;
|
|
||||||
wgpu::TextureView WebGPUDescriptorSet::sDummyTextureView = nullptr;
|
|
||||||
wgpu::Sampler WebGPUDescriptorSet::sDummySampler = nullptr;
|
|
||||||
|
|
||||||
void WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(wgpu::Device const& device,
|
|
||||||
wgpu::TextureFormat aColorFormat) {
|
|
||||||
if (!sDummyUniformBuffer) {
|
|
||||||
wgpu::BufferDescriptor bufferDescriptor{
|
|
||||||
.label = "dummy_uniform_not_to_be_used",
|
|
||||||
.usage = wgpu::BufferUsage::Uniform,
|
|
||||||
.size = 4
|
|
||||||
};
|
|
||||||
sDummyUniformBuffer = device.CreateBuffer(&bufferDescriptor);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
|
|
||||||
<< "Failed to create dummy uniform buffer?";
|
|
||||||
}
|
|
||||||
if (!sDummyTexture || !sDummyTextureView) {
|
|
||||||
wgpu::TextureDescriptor textureDescriptor{
|
|
||||||
.label = "dummy_texture_not_to_be_used",
|
|
||||||
.usage = wgpu::TextureUsage::TextureBinding,
|
|
||||||
.dimension = wgpu::TextureDimension::e2D,
|
|
||||||
.size = wgpu::Extent3D{ .width = 4, .height = 4, .depthOrArrayLayers = 1 },
|
|
||||||
.format = aColorFormat,
|
|
||||||
};
|
|
||||||
if (!sDummyTexture) {
|
|
||||||
sDummyTexture = device.CreateTexture(&textureDescriptor);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy texture?";
|
|
||||||
}
|
|
||||||
if (!sDummyTextureView) {
|
|
||||||
wgpu::TextureViewDescriptor textureViewDescriptor{
|
|
||||||
.label = "dummy_texture_view_not_to_be_used"
|
|
||||||
};
|
|
||||||
sDummyTextureView = sDummyTexture.CreateView(&textureViewDescriptor);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
|
|
||||||
<< "Failed to create dummy texture view?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!sDummySampler) {
|
|
||||||
wgpu::SamplerDescriptor samplerDescriptor{
|
|
||||||
.label = "dummy_sampler_not_to_be_used"
|
|
||||||
};
|
|
||||||
sDummySampler = device.CreateSampler(&samplerDescriptor);
|
|
||||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy sampler?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<wgpu::BindGroupEntry> WebGPUDescriptorSet::createDummyEntriesSortedByBinding(
|
|
||||||
std::vector<filament::backend::WebGPUDescriptorSetLayout::BindGroupEntryInfo> const&
|
|
||||||
bindGroupEntries) {
|
|
||||||
assert_invariant(WebGPUDescriptorSet::sDummyUniformBuffer &&
|
|
||||||
"Dummy uniform buffer must have been created before "
|
|
||||||
"creating dummy bind group entries.");
|
|
||||||
assert_invariant(
|
|
||||||
WebGPUDescriptorSet::sDummyTexture &&
|
|
||||||
"Dummy texture must have been created before creating dummy bind group entries.");
|
|
||||||
assert_invariant(
|
|
||||||
WebGPUDescriptorSet::sDummyTextureView &&
|
|
||||||
"Dummy texture view must have been created before creating dummy bind group entries.");
|
|
||||||
assert_invariant(
|
|
||||||
WebGPUDescriptorSet::sDummySampler &&
|
|
||||||
"Dummy sampler must have been created before creating dummy bind group entries.");
|
|
||||||
using filament::backend::WebGPUDescriptorSetLayout;
|
|
||||||
std::vector<wgpu::BindGroupEntry> entries;
|
|
||||||
entries.reserve(bindGroupEntries.size());
|
|
||||||
for (auto const& entryInfo: bindGroupEntries) {
|
|
||||||
auto& entry = entries.emplace_back();
|
|
||||||
entry.binding = entryInfo.binding;
|
|
||||||
switch (entryInfo.type) {
|
|
||||||
case WebGPUDescriptorSetLayout::BindGroupEntryType::UNIFORM_BUFFER:
|
|
||||||
entry.buffer = WebGPUDescriptorSet::sDummyUniformBuffer;
|
|
||||||
break;
|
|
||||||
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW:
|
|
||||||
entry.textureView = WebGPUDescriptorSet::sDummyTextureView;
|
|
||||||
break;
|
|
||||||
case WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER:
|
|
||||||
entry.sampler = WebGPUDescriptorSet::sDummySampler;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::sort(entries.begin(), entries.end(),
|
|
||||||
[](wgpu::BindGroupEntry const& a, wgpu::BindGroupEntry const& b) {
|
|
||||||
return a.binding < b.binding;
|
|
||||||
});
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebGPUDescriptorSet::WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
WebGPUDescriptorSet::WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
||||||
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries)
|
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries)
|
||||||
: mLayout(layout),
|
: mLayout(layout),
|
||||||
mEntriesSortedByBinding(createDummyEntriesSortedByBinding(bindGroupEntries)) {
|
mEntriesWithDynamicOffsetsCount(std::count_if(bindGroupEntries.begin(),
|
||||||
|
bindGroupEntries.end(), [](auto const& entry) { return entry.hasDynamicOffset; })) {
|
||||||
|
|
||||||
|
mEntries.resize(bindGroupEntries.size());
|
||||||
|
for (size_t i = 0; i < bindGroupEntries.size(); ++i) {
|
||||||
|
mEntries[i].binding = bindGroupEntries[i].binding;
|
||||||
|
}
|
||||||
// Establish the size of entries based on the layout. This should be reliable and efficient.
|
// Establish the size of entries based on the layout. This should be reliable and efficient.
|
||||||
assert_invariant(INVALID_INDEX > mEntryIndexByBinding.size());
|
assert_invariant(INVALID_INDEX > mEntryIndexByBinding.size());
|
||||||
for (size_t i = 0; i < mEntryIndexByBinding.size(); i++) {
|
for (size_t i = 0; i < mEntryIndexByBinding.size(); i++) {
|
||||||
mEntryIndexByBinding[i] = INVALID_INDEX;
|
mEntryIndexByBinding[i] = INVALID_INDEX;
|
||||||
}
|
}
|
||||||
for (size_t index = 0; index < mEntriesSortedByBinding.size(); index++) {
|
for (size_t index = 0; index < mEntries.size(); index++) {
|
||||||
wgpu::BindGroupEntry const& entry = mEntriesSortedByBinding[index];
|
wgpu::BindGroupEntry const& entry = mEntries[index];
|
||||||
assert_invariant(entry.binding < mEntryIndexByBinding.size());
|
assert_invariant(entry.binding < mEntryIndexByBinding.size());
|
||||||
mEntryIndexByBinding[entry.binding] = static_cast<uint8_t>(index);
|
mEntryIndexByBinding[entry.binding] = static_cast<uint8_t>(index);
|
||||||
}
|
}
|
||||||
for (auto const& entry : bindGroupEntries) {
|
|
||||||
if (entry.hasDynamicOffset) {
|
|
||||||
assert_invariant(entry.binding < mEntriesByBindingWithDynamicOffsets.size());
|
|
||||||
mEntriesByBindingWithDynamicOffsets[entry.binding] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mDynamicOffsets.reserve(mEntriesSortedByBinding.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebGPUDescriptorSet::~WebGPUDescriptorSet() {
|
WebGPUDescriptorSet::~WebGPUDescriptorSet() {
|
||||||
@@ -391,15 +452,15 @@ wgpu::BindGroup WebGPUDescriptorSet::lockAndReturn(const wgpu::Device& device) {
|
|||||||
// TODO label? Should we just copy layout label?
|
// TODO label? Should we just copy layout label?
|
||||||
wgpu::BindGroupDescriptor desc{
|
wgpu::BindGroupDescriptor desc{
|
||||||
.layout = mLayout,
|
.layout = mLayout,
|
||||||
.entryCount = mEntriesSortedByBinding.size(),
|
.entryCount = mEntries.size(),
|
||||||
.entries = mEntriesSortedByBinding.data()
|
.entries = mEntries.data()
|
||||||
};
|
};
|
||||||
mBindGroup = device.CreateBindGroup(&desc);
|
mBindGroup = device.CreateBindGroup(&desc);
|
||||||
FILAMENT_CHECK_POSTCONDITION(mBindGroup) << "Failed to create bind group?";
|
FILAMENT_CHECK_POSTCONDITION(mBindGroup) << "Failed to create bind group?";
|
||||||
// once we have created the bind group itself we should no longer need any other state
|
// once we have created the bind group itself we should no longer need any other state
|
||||||
mLayout = nullptr;
|
mLayout = nullptr;
|
||||||
mEntriesSortedByBinding.clear();
|
mEntries.clear();
|
||||||
mEntriesSortedByBinding.shrink_to_fit();
|
mEntries.shrink_to_fit();
|
||||||
return mBindGroup;
|
return mBindGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,85 +478,86 @@ void WebGPUDescriptorSet::addEntry(unsigned int index, wgpu::BindGroupEntry&& en
|
|||||||
<< index;
|
<< index;
|
||||||
uint8_t entryIndex = mEntryIndexByBinding[index];
|
uint8_t entryIndex = mEntryIndexByBinding[index];
|
||||||
FILAMENT_CHECK_POSTCONDITION(
|
FILAMENT_CHECK_POSTCONDITION(
|
||||||
entryIndex != INVALID_INDEX && entryIndex < mEntriesSortedByBinding.size())
|
entryIndex != INVALID_INDEX && entryIndex < mEntries.size())
|
||||||
<< "Invalid binding " << index;
|
<< "Invalid binding " << index;
|
||||||
entry.binding = index;
|
entry.binding = index;
|
||||||
mEntriesSortedByBinding[entryIndex] = std::move(entry);
|
mEntries[entryIndex] = std::move(entry);
|
||||||
mEntriesByBindingAdded[index] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t const* WebGPUDescriptorSet::setDynamicOffsets(uint32_t const* offsets) {
|
|
||||||
// mDynamicOffsets already reserves enough memory for the number of entries in the set
|
|
||||||
mDynamicOffsets.clear();
|
|
||||||
// this implementation copies the offsets to mDynamicOffsets, but also adds values for
|
|
||||||
// unused entries TODO: is this necessary?
|
|
||||||
size_t inputIndex = 0;
|
|
||||||
size_t outputIndex = 0;
|
|
||||||
for (auto const& entry : mEntriesSortedByBinding) {
|
|
||||||
if (mEntriesByBindingWithDynamicOffsets[entry.binding]) {
|
|
||||||
if (mEntriesByBindingAdded[entry.binding]) {
|
|
||||||
mDynamicOffsets[outputIndex++] = offsets[inputIndex++];
|
|
||||||
} else {
|
|
||||||
mDynamicOffsets[outputIndex++] = 0; // dummy offset, as it was never added
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mDynamicOffsets.data();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WebGPUDescriptorSet::countEntitiesWithDynamicOffsets() const {
|
size_t WebGPUDescriptorSet::countEntitiesWithDynamicOffsets() const {
|
||||||
return mEntriesByBindingWithDynamicOffsets.count();
|
return mEntriesWithDynamicOffsetsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// From createTextureR
|
|
||||||
WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||||
wgpu::Device device) noexcept {
|
wgpu::Device const& device) noexcept {
|
||||||
|
assert_invariant(
|
||||||
// First the texture aspect
|
samples == 1 ||
|
||||||
wgpu::TextureDescriptor desc;
|
samples == 4 &&
|
||||||
|
"An invalid number of samples were requested, as WGPU requires the sample "
|
||||||
|
"count to either be 1 (no multisampling) or 4, at least as of April 2025 of "
|
||||||
|
"the spec. See https://www.w3.org/TR/webgpu/#texture-creation or "
|
||||||
|
"https://gpuweb.github.io/gpuweb/#multisample-state");
|
||||||
|
// First, the texture aspect, starting with the defaults/basic configuration
|
||||||
|
mUsage = fToWGPUTextureUsage(usage);
|
||||||
|
mFormat = fToWGPUTextureFormat(format);
|
||||||
|
mAspect = fToWGPUTextureViewAspect(usage, format);
|
||||||
|
mBlockWidth = filament::backend::getBlockWidth(format);
|
||||||
|
mBlockHeight = filament::backend::getBlockHeight(format);
|
||||||
|
wgpu::TextureDescriptor textureDescriptor{
|
||||||
|
.label = getUserTextureLabel(target),
|
||||||
|
.usage = mUsage,
|
||||||
|
.dimension = target == SamplerType::SAMPLER_3D ? wgpu::TextureDimension::e3D
|
||||||
|
: wgpu::TextureDimension::e2D,
|
||||||
|
.size = { .width = width, .height = height, .depthOrArrayLayers = depth },
|
||||||
|
.format = mFormat,
|
||||||
|
.mipLevelCount = levels,
|
||||||
|
.sampleCount = samples,
|
||||||
|
// TODO Is this fine? Could do all-the-things, a naive mapping or get something from
|
||||||
|
// Filament
|
||||||
|
.viewFormatCount = 0,
|
||||||
|
.viewFormats = nullptr,
|
||||||
|
};
|
||||||
|
// adjust for specific cases
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case SamplerType::SAMPLER_CUBEMAP:
|
|
||||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
|
||||||
case SamplerType::SAMPLER_2D:
|
case SamplerType::SAMPLER_2D:
|
||||||
|
mArrayLayerCount = 1;
|
||||||
|
break;
|
||||||
case SamplerType::SAMPLER_2D_ARRAY:
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
// Should be safe to assume external is 2d
|
mArrayLayerCount = textureDescriptor.size.depthOrArrayLayers;
|
||||||
case SamplerType::SAMPLER_EXTERNAL: {
|
|
||||||
desc.dimension = wgpu::TextureDimension::e2D;
|
|
||||||
break;
|
break;
|
||||||
}
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
case SamplerType::SAMPLER_3D: {
|
textureDescriptor.size.depthOrArrayLayers = 6;
|
||||||
desc.dimension = wgpu::TextureDimension::e3D;
|
mArrayLayerCount = textureDescriptor.size.depthOrArrayLayers;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL:
|
||||||
|
case SamplerType::SAMPLER_3D:
|
||||||
|
mArrayLayerCount = 1;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
textureDescriptor.size.depthOrArrayLayers = depth * 6;
|
||||||
|
mArrayLayerCount = textureDescriptor.size.depthOrArrayLayers;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
desc.size = { .width = width, .height = height, .depthOrArrayLayers = depth };
|
assert_invariant(textureDescriptor.format != wgpu::TextureFormat::Undefined &&
|
||||||
desc.format = fToWGPUTextureFormat(format);
|
"Could not find appropriate WebGPU format");
|
||||||
assert_invariant(desc.format != wgpu::TextureFormat::Undefined);
|
mTexture = device.CreateTexture(&textureDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(mTexture)
|
||||||
// WGPU requires this to be true. Filament should comply
|
<< "Failed to create texture for " << textureDescriptor.label;
|
||||||
assert(samples == 1 || samples || 4);
|
// Second, the texture view aspect
|
||||||
|
mTexView = makeTextureView(0, levels, target);
|
||||||
desc.sampleCount = samples;
|
|
||||||
desc.usage = fToWGPUTextureUsage(usage);
|
|
||||||
desc.mipLevelCount = levels;
|
|
||||||
|
|
||||||
// TODO Is this fine? Could do all-the-things, a naive mapping or get something from Filament
|
|
||||||
desc.viewFormats = nullptr;
|
|
||||||
|
|
||||||
texture = device.CreateTexture(&desc);
|
|
||||||
|
|
||||||
// TODO should a default levelCount be something other than 0? Sample count?
|
|
||||||
texView = makeTextureView(0, 1);
|
|
||||||
}
|
}
|
||||||
// From createTextureViewR
|
|
||||||
WGPUTexture::WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept {
|
WGPUTexture::WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept {
|
||||||
texture = src->texture;
|
mTexture = src->mTexture;
|
||||||
texView = makeTextureView(baseLevel, levelCount);
|
mAspect = src->mAspect;
|
||||||
|
mBlockWidth = src->mBlockWidth;
|
||||||
|
mBlockHeight = src->mBlockHeight;
|
||||||
|
|
||||||
|
mTexView = makeTextureView(baseLevel, levelCount, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(const TextureUsage& fUsage) {
|
wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(TextureUsage const& fUsage) {
|
||||||
wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;
|
wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;
|
||||||
|
|
||||||
// Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
|
// Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
|
||||||
@@ -543,8 +605,9 @@ wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(const TextureUsage& fUsage)
|
|||||||
// PROTECTED
|
// PROTECTED
|
||||||
return retUsage;
|
return retUsage;
|
||||||
}
|
}
|
||||||
wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(const TextureFormat& fUsage) {
|
|
||||||
switch (fUsage) {
|
wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(TextureFormat const& fFormat) {
|
||||||
|
switch (fFormat) {
|
||||||
case filament::backend::TextureFormat::R8:
|
case filament::backend::TextureFormat::R8:
|
||||||
return wgpu::TextureFormat::R8Unorm;
|
return wgpu::TextureFormat::R8Unorm;
|
||||||
case filament::backend::TextureFormat::R8_SNORM:
|
case filament::backend::TextureFormat::R8_SNORM:
|
||||||
@@ -783,80 +846,224 @@ wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(const TextureFormat& fUsag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::TextureView WGPUTexture::makeTextureView(const uint8_t& baseLevel,
|
wgpu::TextureAspect WGPUTexture::fToWGPUTextureViewAspect(TextureUsage const& fUsage,
|
||||||
const uint8_t& levelCount) {
|
TextureFormat const& fFormat) {
|
||||||
wgpu::TextureViewDescriptor desc;
|
|
||||||
desc.baseMipLevel = baseLevel;
|
|
||||||
desc.mipLevelCount = levelCount;
|
|
||||||
|
|
||||||
// baseArrayLayer is required, making a guess
|
const bool isDepth = any(fUsage & TextureUsage::DEPTH_ATTACHMENT);
|
||||||
desc.baseArrayLayer = 0;
|
const bool isStencil = any(fUsage & TextureUsage::STENCIL_ATTACHMENT);
|
||||||
// Have not found an analouge to aspect in other drivers, but ALL should be unrestrictive.
|
const bool isColor = any(fUsage & TextureUsage::COLOR_ATTACHMENT);
|
||||||
// TODO Can we make this better?
|
const bool isSample = (fUsage == TextureUsage::SAMPLEABLE);
|
||||||
desc.aspect = wgpu::TextureAspect::All;
|
|
||||||
|
|
||||||
// The rest of the properties should be fine to leave as default, using the texture params.
|
|
||||||
desc.label = "TODO";
|
|
||||||
|
|
||||||
desc.format = wgpu::TextureFormat::Undefined;
|
|
||||||
desc.dimension = wgpu::TextureViewDimension::Undefined;
|
|
||||||
desc.usage = wgpu::TextureUsage::None;
|
|
||||||
|
|
||||||
return texture.CreateView(&desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
WGPURenderTarget::Attachment WGPURenderTarget::getDrawColorAttachment(size_t index) {
|
|
||||||
assert_invariant( index < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
|
||||||
auto result = color[index];
|
|
||||||
if (index == 0 && defaultRenderTarget) {
|
|
||||||
|
|
||||||
|
if (isDepth && !isColor && !isStencil) {
|
||||||
|
return wgpu::TextureAspect::DepthOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
if (isStencil && !isColor && !isDepth) {
|
||||||
|
return wgpu::TextureAspect::StencilOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fFormat == filament::backend::TextureFormat::DEPTH32F ||
|
||||||
|
fFormat == filament::backend::TextureFormat::DEPTH24 ||
|
||||||
|
fFormat == filament::backend::TextureFormat::DEPTH16) {
|
||||||
|
return wgpu::TextureAspect::DepthOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fFormat == filament::backend::TextureFormat::STENCIL8) {
|
||||||
|
return wgpu::TextureAspect::StencilOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fFormat == filament::backend::TextureFormat::DEPTH24_STENCIL8 ||
|
||||||
|
fFormat == filament::backend::TextureFormat::DEPTH32F_STENCIL8) {
|
||||||
|
if (isSample) {
|
||||||
|
return wgpu::TextureAspect::DepthOnly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wgpu::TextureAspect::All;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wgpu::TextureView WGPUTexture::makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
|
||||||
|
SamplerType target) {
|
||||||
|
|
||||||
|
wgpu::TextureViewDescriptor textureViewDescriptor{
|
||||||
|
.label = getUserTextureViewLabel(target),
|
||||||
|
.format = mFormat,
|
||||||
|
.baseMipLevel = baseLevel,
|
||||||
|
.mipLevelCount = levelCount,
|
||||||
|
// TODO: check if this baseArrayLayer assumption is correct
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.arrayLayerCount = mArrayLayerCount,
|
||||||
|
.aspect = mAspect,
|
||||||
|
.usage = mUsage
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (target) {
|
||||||
|
case SamplerType::SAMPLER_2D:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_2D_ARRAY:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2DArray;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::Cube;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_EXTERNAL:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_3D:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e3D;
|
||||||
|
break;
|
||||||
|
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||||
|
textureViewDescriptor.dimension = wgpu::TextureViewDimension::CubeArray;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wgpu::TextureView textureView = mTexture.CreateView(&textureViewDescriptor);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(textureView)
|
||||||
|
<< "Failed to create texture view " << textureViewDescriptor.label;
|
||||||
|
return textureView;
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPURenderTarget::WGPURenderTarget(uint32_t width, uint32_t height, uint8_t samples,
|
||||||
|
const MRT& colorAttachmentsMRT,
|
||||||
|
const Attachment& depthAttachmentInfo,
|
||||||
|
const Attachment& stencilAttachmentInfo)
|
||||||
|
: HwRenderTarget(width, height),
|
||||||
|
defaultRenderTarget(false),
|
||||||
|
samples(samples),
|
||||||
|
mColorAttachments(colorAttachmentsMRT),
|
||||||
|
mDepthAttachment(depthAttachmentInfo),
|
||||||
|
mStencilAttachment(stencilAttachmentInfo) {
|
||||||
|
mColorAttachmentDescriptors.reserve(MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static helper to map MRT index to TargetBufferFlags
|
||||||
|
TargetBufferFlags WGPURenderTarget::getTargetBufferFlagsAt(int mrtIndex) {
|
||||||
|
if (mrtIndex < 0 || mrtIndex >= MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT) {
|
||||||
|
return TargetBufferFlags::NONE;
|
||||||
|
}
|
||||||
|
// This mapping assumes TargetBufferFlags::COLOR_0, COLOR_1 etc. are contiguous
|
||||||
|
return static_cast<TargetBufferFlags>(
|
||||||
|
static_cast<uint32_t>(TargetBufferFlags::COLOR0) << mrtIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Corrected getLoadOperation
|
||||||
wgpu::LoadOp WGPURenderTarget::getLoadOperation(RenderPassParams const& params,
|
wgpu::LoadOp WGPURenderTarget::getLoadOperation(RenderPassParams const& params,
|
||||||
TargetBufferFlags buffer) {
|
TargetBufferFlags bufferToOperateOn) {
|
||||||
auto clearFlags = params.flags.clear;
|
if (any(params.flags.clear & bufferToOperateOn)) {
|
||||||
auto discardStartFlags = params.flags.discardStart;
|
|
||||||
if (any(clearFlags & buffer)) {
|
|
||||||
return wgpu::LoadOp::Clear;
|
|
||||||
} else if (any(discardStartFlags & buffer)) {
|
|
||||||
return wgpu::LoadOp::Clear;
|
return wgpu::LoadOp::Clear;
|
||||||
}
|
}
|
||||||
|
if (any(params.flags.discardStart & bufferToOperateOn)) {
|
||||||
|
return wgpu::LoadOp::Clear; // Or wgpu::LoadOp::Undefined if clear is not desired on discard
|
||||||
|
}
|
||||||
return wgpu::LoadOp::Load;
|
return wgpu::LoadOp::Load;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Corrected getStoreOperation
|
||||||
wgpu::StoreOp WGPURenderTarget::getStoreOperation(RenderPassParams const& params,
|
wgpu::StoreOp WGPURenderTarget::getStoreOperation(RenderPassParams const& params,
|
||||||
TargetBufferFlags buffer) {
|
TargetBufferFlags bufferToOperateOn) {
|
||||||
const auto discardEndFlags = params.flags.discardEnd;
|
if (any(params.flags.discardEnd & bufferToOperateOn)) {
|
||||||
if (any(discardEndFlags & buffer)) {
|
|
||||||
return wgpu::StoreOp::Discard;
|
return wgpu::StoreOp::Discard;
|
||||||
}
|
}
|
||||||
return wgpu::StoreOp::Store;
|
return wgpu::StoreOp::Store;
|
||||||
}
|
}
|
||||||
void WGPURenderTarget::setUpRenderPassAttachments(wgpu::RenderPassDescriptor& descriptor,
|
|
||||||
wgpu::TextureView const& textureView, RenderPassParams const& params) {
|
void WGPURenderTarget::setUpRenderPassAttachments(
|
||||||
// auto discardFlags = params.flags.discardEnd;
|
wgpu::RenderPassDescriptor& descriptor,
|
||||||
// (void) discardFlags;
|
RenderPassParams const& params,
|
||||||
// std::vector<wgpu::RenderPassColorAttachment> colorAttachments;
|
wgpu::TextureView const& defaultColorTextureView,
|
||||||
colorAttachments.clear();
|
wgpu::TextureView const& defaultDepthStencilTextureView,
|
||||||
for (size_t i = 0; i < 1/*MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT*/; i++) {
|
wgpu::TextureView const* customColorTextureViews,
|
||||||
// auto attachment = getDrawColorAttachment(i);
|
uint32_t customColorTextureViewCount,
|
||||||
// if (attachment) {
|
wgpu::TextureView const& customDepthTextureView,
|
||||||
wgpu::RenderPassColorAttachment colorAttachment;
|
wgpu::TextureView const& customStencilTextureView) {
|
||||||
colorAttachment.view = textureView;
|
mColorAttachmentDescriptors.clear();
|
||||||
colorAttachment.loadOp = getLoadOperation(params, getTargetBufferFlagsAt(i));
|
mHasDepthStencilAttachment = false;
|
||||||
colorAttachment.storeOp = getStoreOperation(params, getTargetBufferFlagsAt(i));
|
|
||||||
colorAttachment.clearValue = { params.clearColor.r, params.clearColor.g, params.clearColor.b, params.clearColor.a };
|
if (defaultRenderTarget) {
|
||||||
colorAttachments.emplace_back(colorAttachment);
|
assert_invariant(defaultColorTextureView);
|
||||||
// }
|
wgpu::RenderPassColorAttachment colorAttDesc{};
|
||||||
|
colorAttDesc.view = defaultColorTextureView;
|
||||||
|
colorAttDesc.resolveTarget = nullptr;
|
||||||
|
colorAttDesc.loadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::COLOR0);
|
||||||
|
colorAttDesc.storeOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::COLOR0);
|
||||||
|
colorAttDesc.clearValue = {params.clearColor.r, params.clearColor.g,
|
||||||
|
params.clearColor.b, params.clearColor.a};
|
||||||
|
mColorAttachmentDescriptors.push_back(colorAttDesc);
|
||||||
|
|
||||||
|
if (defaultDepthStencilTextureView) {
|
||||||
|
mDepthStencilAttachmentDescriptor = {
|
||||||
|
.view = defaultDepthStencilTextureView,
|
||||||
|
.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH),
|
||||||
|
.depthStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::DEPTH),
|
||||||
|
.depthClearValue = static_cast<float>(params.clearDepth),
|
||||||
|
.depthReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) > 0,
|
||||||
|
.stencilLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::STENCIL),
|
||||||
|
.stencilStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::STENCIL),
|
||||||
|
.stencilClearValue = params.clearStencil,
|
||||||
|
.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0,
|
||||||
|
};
|
||||||
|
mHasDepthStencilAttachment = true;
|
||||||
|
}
|
||||||
|
} else { // Custom Render Target
|
||||||
|
for (uint32_t i = 0; i < customColorTextureViewCount; ++i) {
|
||||||
|
if (customColorTextureViews[i]) {
|
||||||
|
wgpu::RenderPassColorAttachment colorAttDesc{};
|
||||||
|
colorAttDesc.view = customColorTextureViews[i];
|
||||||
|
colorAttDesc.resolveTarget = nullptr; // TODO: MSAA resolve for custom RT
|
||||||
|
colorAttDesc.loadOp = WGPURenderTarget::getLoadOperation(params, getTargetBufferFlagsAt(i));
|
||||||
|
colorAttDesc.storeOp = WGPURenderTarget::getStoreOperation(params, getTargetBufferFlagsAt(i));
|
||||||
|
colorAttDesc.clearValue = {params.clearColor.r, params.clearColor.g,
|
||||||
|
params.clearColor.b, params.clearColor.a};
|
||||||
|
mColorAttachmentDescriptors.push_back(colorAttDesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::TextureView combinedDsView = customDepthTextureView ? customDepthTextureView : customStencilTextureView;
|
||||||
|
|
||||||
|
if (combinedDsView) {
|
||||||
|
mDepthStencilAttachmentDescriptor = {};
|
||||||
|
mDepthStencilAttachmentDescriptor.view = combinedDsView;
|
||||||
|
|
||||||
|
if (customDepthTextureView) {
|
||||||
|
mDepthStencilAttachmentDescriptor.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH);
|
||||||
|
mDepthStencilAttachmentDescriptor.depthStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::DEPTH);
|
||||||
|
mDepthStencilAttachmentDescriptor.depthClearValue = static_cast<float>(params.clearDepth);
|
||||||
|
mDepthStencilAttachmentDescriptor.depthReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH) > 0;
|
||||||
|
} else {
|
||||||
|
mDepthStencilAttachmentDescriptor.depthLoadOp = wgpu::LoadOp::Undefined;
|
||||||
|
mDepthStencilAttachmentDescriptor.depthStoreOp = wgpu::StoreOp::Undefined;
|
||||||
|
mDepthStencilAttachmentDescriptor.depthReadOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customStencilTextureView) {
|
||||||
|
mDepthStencilAttachmentDescriptor.stencilLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::STENCIL);
|
||||||
|
mDepthStencilAttachmentDescriptor.stencilStoreOp = WGPURenderTarget::getStoreOperation(params, TargetBufferFlags::STENCIL);
|
||||||
|
mDepthStencilAttachmentDescriptor.stencilClearValue = params.clearStencil;
|
||||||
|
mDepthStencilAttachmentDescriptor.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0;
|
||||||
|
} else {
|
||||||
|
mDepthStencilAttachmentDescriptor.stencilLoadOp = wgpu::LoadOp::Undefined;
|
||||||
|
mDepthStencilAttachmentDescriptor.stencilStoreOp = wgpu::StoreOp::Undefined;
|
||||||
|
mDepthStencilAttachmentDescriptor.stencilReadOnly = true;
|
||||||
|
}
|
||||||
|
mHasDepthStencilAttachment = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
descriptor.colorAttachments = colorAttachments.data();
|
|
||||||
descriptor.colorAttachmentCount = colorAttachments.size();
|
descriptor.colorAttachmentCount = mColorAttachmentDescriptors.size();
|
||||||
descriptor.depthStencilAttachment = nullptr;
|
descriptor.colorAttachments = mColorAttachmentDescriptors.data();
|
||||||
descriptor.timestampWrites = nullptr;
|
descriptor.depthStencilAttachment = mHasDepthStencilAttachment ? &mDepthStencilAttachmentDescriptor : nullptr;
|
||||||
|
// descriptor.sampleCount was removed from the core spec. If your webgpu.h still has it,
|
||||||
|
// and your Dawn version expects it, you might need to set it here based on this->samples.
|
||||||
|
// e.g., descriptor.sampleCount = this->samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
math::uint2 WGPURenderTarget::getAttachmentSize() const noexcept {
|
||||||
|
if (!defaultRenderTarget) {
|
||||||
|
return {width, height};
|
||||||
|
}
|
||||||
|
// For default RT, size is dynamic and usually obtained from the swapchain.
|
||||||
|
// The caller (WebGPUDriver::beginRenderPass) should know the current swapchain size.
|
||||||
|
return {0,0};
|
||||||
|
}
|
||||||
|
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
#include <webgpu/webgpu_cpp.h>
|
#include <webgpu/webgpu_cpp.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <bitset>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -44,7 +43,6 @@ public:
|
|||||||
std::vector<wgpu::ConstantEntry> constants;
|
std::vector<wgpu::ConstantEntry> constants;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WGPUBufferObject;
|
|
||||||
|
|
||||||
// VertexBufferInfo contains layout info for Vertex Buffer based on WebGPU structs. In WebGPU each
|
// VertexBufferInfo contains layout info for Vertex Buffer based on WebGPU structs. In WebGPU each
|
||||||
// VertexBufferLayout is associated with a single vertex buffer. So number of mVertexBufferLayout
|
// VertexBufferLayout is associated with a single vertex buffer. So number of mVertexBufferLayout
|
||||||
@@ -74,8 +72,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO: can we do better in terms on heap management.
|
// TODO: can we do better in terms on heap management.
|
||||||
std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout {};
|
std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout{};
|
||||||
std::vector<std::vector<wgpu::VertexAttribute>> mAttributes {};
|
std::vector<std::vector<wgpu::VertexAttribute>> mAttributes{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WGPUVertexBuffer : public HwVertexBuffer {
|
struct WGPUVertexBuffer : public HwVertexBuffer {
|
||||||
@@ -86,33 +84,37 @@ struct WGPUVertexBuffer : public HwVertexBuffer {
|
|||||||
utils::FixedCapacityVector<wgpu::Buffer> buffers;
|
utils::FixedCapacityVector<wgpu::Buffer> buffers;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WGPUIndexBuffer : public HwIndexBuffer {
|
class WGPUBufferBase {
|
||||||
|
public:
|
||||||
|
void createBuffer(wgpu::Device const& device, wgpu::BufferUsage usage, uint32_t size,
|
||||||
|
char const* label);
|
||||||
|
void updateGPUBuffer(BufferDescriptor& bufferDescriptor, uint32_t byteOffset,
|
||||||
|
wgpu::Queue queue);
|
||||||
|
const wgpu::Buffer& getBuffer() const { return buffer; }
|
||||||
|
protected:
|
||||||
|
wgpu::Buffer buffer;
|
||||||
|
private:
|
||||||
|
// 4 bytes to hold any extra chunk we need.
|
||||||
|
std::array<uint8_t,4> mRemainderChunk;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WGPUIndexBuffer : public HwIndexBuffer, public WGPUBufferBase {
|
||||||
|
public:
|
||||||
WGPUIndexBuffer(wgpu::Device const &device, uint8_t elementSize,
|
WGPUIndexBuffer(wgpu::Device const &device, uint8_t elementSize,
|
||||||
uint32_t indexCount);
|
uint32_t indexCount);
|
||||||
|
|
||||||
wgpu::Buffer buffer;
|
|
||||||
wgpu::IndexFormat indexFormat;
|
wgpu::IndexFormat indexFormat;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WGPUBufferObject : HwBufferObject {
|
class WGPUBufferObject : public HwBufferObject, public WGPUBufferBase {
|
||||||
|
public:
|
||||||
WGPUBufferObject(wgpu::Device const &device, BufferObjectBinding bindingType, uint32_t byteCount);
|
WGPUBufferObject(wgpu::Device const &device, BufferObjectBinding bindingType, uint32_t byteCount);
|
||||||
|
|
||||||
wgpu::Buffer buffer = nullptr;
|
|
||||||
const BufferObjectBinding bufferObjectBinding;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebGPUDescriptorSetLayout final : public HwDescriptorSetLayout {
|
class WebGPUDescriptorSetLayout final : public HwDescriptorSetLayout {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum class BindGroupEntryType : uint8_t {
|
|
||||||
UNIFORM_BUFFER,
|
|
||||||
TEXTURE_VIEW,
|
|
||||||
SAMPLER
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BindGroupEntryInfo final {
|
struct BindGroupEntryInfo final {
|
||||||
uint8_t binding = 0;
|
uint8_t binding = 0;
|
||||||
BindGroupEntryType type = BindGroupEntryType::UNIFORM_BUFFER;
|
|
||||||
bool hasDynamicOffset = false;
|
bool hasDynamicOffset = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -125,7 +127,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO: If this is useful elsewhere, remove it from this class
|
// TODO: If this is useful elsewhere, remove it from this class
|
||||||
// Convert Filament Shader Stage Flags bitmask to webgpu equivilant
|
// Convert Filament Shader Stage Flags bitmask to webgpu equivalent
|
||||||
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
|
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
|
||||||
std::vector<BindGroupEntryInfo> mBindGroupEntries;
|
std::vector<BindGroupEntryInfo> mBindGroupEntries;
|
||||||
wgpu::BindGroupLayout mLayout;
|
wgpu::BindGroupLayout mLayout;
|
||||||
@@ -133,8 +135,6 @@ private:
|
|||||||
|
|
||||||
class WebGPUDescriptorSet final : public HwDescriptorSet {
|
class WebGPUDescriptorSet final : public HwDescriptorSet {
|
||||||
public:
|
public:
|
||||||
static void initializeDummyResourcesIfNotAlready(wgpu::Device const&,
|
|
||||||
wgpu::TextureFormat aColorFormat);
|
|
||||||
|
|
||||||
WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
||||||
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries);
|
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries);
|
||||||
@@ -142,30 +142,15 @@ public:
|
|||||||
|
|
||||||
wgpu::BindGroup lockAndReturn(wgpu::Device const&);
|
wgpu::BindGroup lockAndReturn(wgpu::Device const&);
|
||||||
void addEntry(unsigned int index, wgpu::BindGroupEntry&& entry);
|
void addEntry(unsigned int index, wgpu::BindGroupEntry&& entry);
|
||||||
[[nodiscard]] uint32_t const* setDynamicOffsets(uint32_t const* offsets);
|
|
||||||
[[nodiscard]] bool getIsLocked() const { return mBindGroup != nullptr; }
|
[[nodiscard]] bool getIsLocked() const { return mBindGroup != nullptr; }
|
||||||
[[nodiscard]] size_t countEntitiesWithDynamicOffsets() const;
|
[[nodiscard]] size_t countEntitiesWithDynamicOffsets() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static wgpu::Buffer sDummyUniformBuffer;
|
|
||||||
static wgpu::Texture sDummyTexture;
|
|
||||||
static wgpu::TextureView sDummyTextureView;
|
|
||||||
static wgpu::Sampler sDummySampler;
|
|
||||||
|
|
||||||
static std::vector<wgpu::BindGroupEntry> createDummyEntriesSortedByBinding(
|
|
||||||
std::vector<filament::backend::WebGPUDescriptorSetLayout::BindGroupEntryInfo> const&);
|
|
||||||
|
|
||||||
// TODO: Consider storing what we used to make the layout. However we need to essentially
|
|
||||||
// Recreate some of the info (Sampler in slot X with the actual sampler) so letting Dawn confirm
|
|
||||||
// there isn't a mismatch may be easiest.
|
|
||||||
// Also storing the wgpu ObjectBase takes care of ownership challenges in theory
|
|
||||||
wgpu::BindGroupLayout mLayout = nullptr;
|
wgpu::BindGroupLayout mLayout = nullptr;
|
||||||
static constexpr uint8_t INVALID_INDEX = MAX_DESCRIPTOR_COUNT + 1;
|
static constexpr uint8_t INVALID_INDEX = MAX_DESCRIPTOR_COUNT + 1;
|
||||||
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding {};
|
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding{};
|
||||||
std::vector<wgpu::BindGroupEntry> mEntriesSortedByBinding;
|
std::vector<wgpu::BindGroupEntry> mEntries;
|
||||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingWithDynamicOffsets {};
|
const size_t mEntriesWithDynamicOffsetsCount;
|
||||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingAdded {};
|
|
||||||
std::vector<uint32_t> mDynamicOffsets;
|
|
||||||
wgpu::BindGroup mBindGroup = nullptr;
|
wgpu::BindGroup mBindGroup = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -173,24 +158,37 @@ class WGPUTexture : public HwTexture {
|
|||||||
public:
|
public:
|
||||||
WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||||
wgpu::Device device) noexcept;
|
wgpu::Device const& device) noexcept;
|
||||||
|
|
||||||
WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
||||||
|
wgpu::TextureAspect getAspect() const { return mAspect; }
|
||||||
|
size_t getBlockWidth() const { return mBlockWidth; }
|
||||||
|
size_t getBlockHeight() const { return mBlockHeight; }
|
||||||
|
|
||||||
const wgpu::Texture& getTexture() const { return texture; }
|
[[nodiscard]] const wgpu::Texture& getTexture() const { return mTexture; }
|
||||||
const wgpu::TextureView& getTexView() const { return texView; }
|
[[nodiscard]] const wgpu::TextureView& getTexView() const { return mTexView; }
|
||||||
|
|
||||||
// Public to allow checking for support of a texture format
|
static wgpu::TextureFormat fToWGPUTextureFormat(
|
||||||
static wgpu::TextureFormat fToWGPUTextureFormat(const filament::backend::TextureFormat& fUsage);
|
filament::backend::TextureFormat const& fFormat);
|
||||||
|
static wgpu::TextureAspect fToWGPUTextureViewAspect(
|
||||||
|
filament::backend::TextureUsage const& fUsage,
|
||||||
|
filament::backend::TextureFormat const& fFormat);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wgpu::TextureView makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount);
|
wgpu::TextureView makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
|
||||||
|
SamplerType target);
|
||||||
// CreateTextureR has info for a texture and sampler. Texture Views are needed for binding,
|
// CreateTextureR has info for a texture and sampler. Texture Views are needed for binding,
|
||||||
// along with a sampler Current plan: Inherit the sampler and Texture to always exist (It is a
|
// along with a sampler Current plan: Inherit the sampler and Texture to always exist (It is a
|
||||||
// ref counted pointer) when making views. View is optional
|
// ref counted pointer) when making views. View is optional
|
||||||
wgpu::Texture texture = nullptr;
|
wgpu::Texture mTexture = nullptr;
|
||||||
wgpu::TextureView texView = nullptr;
|
wgpu::TextureUsage mUsage = wgpu::TextureUsage::None;
|
||||||
wgpu::TextureUsage fToWGPUTextureUsage(const filament::backend::TextureUsage& fUsage);
|
wgpu::TextureFormat mFormat = wgpu::TextureFormat::Undefined;
|
||||||
|
wgpu::TextureAspect mAspect = wgpu::TextureAspect::Undefined;
|
||||||
|
uint32_t mArrayLayerCount = 1;
|
||||||
|
wgpu::TextureView mTexView = nullptr;
|
||||||
|
wgpu::TextureUsage fToWGPUTextureUsage(filament::backend::TextureUsage const& fUsage);
|
||||||
|
size_t mBlockWidth;
|
||||||
|
size_t mBlockHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
||||||
@@ -199,57 +197,66 @@ struct WGPURenderPrimitive : public HwRenderPrimitive {
|
|||||||
WGPUIndexBuffer* indexBuffer = nullptr;
|
WGPUIndexBuffer* indexBuffer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WGPURenderTarget : public HwRenderTarget {
|
class WGPURenderTarget : public HwRenderTarget {
|
||||||
public:
|
public:
|
||||||
class Attachment {
|
using Attachment = TargetBufferInfo; // Using TargetBufferInfo directly for attachments
|
||||||
public:
|
|
||||||
friend class WGPURenderTarget;
|
|
||||||
|
|
||||||
Attachment() = default;
|
|
||||||
Attachment(WGPUTexture* gpuTexture, uint8_t level = 0, uint16_t layer = 0)
|
|
||||||
: level(level),
|
|
||||||
layer(layer),
|
|
||||||
texture(gpuTexture->getTexture()),
|
|
||||||
mWGPUTexture(gpuTexture) {}
|
|
||||||
operator bool() const {
|
|
||||||
return mWGPUTexture != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t level = 0;
|
|
||||||
uint16_t layer = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
wgpu::Texture texture = nullptr;
|
|
||||||
WGPUTexture* mWGPUTexture = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
WGPURenderTarget(uint32_t width, uint32_t height, uint8_t samples,
|
WGPURenderTarget(uint32_t width, uint32_t height, uint8_t samples,
|
||||||
Attachment colorAttachments[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT]);
|
const MRT& colorAttachments,
|
||||||
|
const Attachment& depthAttachment,
|
||||||
|
const Attachment& stencilAttachment);
|
||||||
|
|
||||||
|
// Default constructor for the default render target
|
||||||
WGPURenderTarget()
|
WGPURenderTarget()
|
||||||
: HwRenderTarget(0, 0),
|
: HwRenderTarget(0, 0),
|
||||||
defaultRenderTarget(true) {}
|
defaultRenderTarget(true),
|
||||||
|
samples(1) {}
|
||||||
|
|
||||||
void setUpRenderPassAttachments(wgpu::RenderPassDescriptor& descriptor,
|
// Updated signature: takes resolved views for custom RTs, and default views for default RT
|
||||||
wgpu::TextureView const& textureView, RenderPassParams const& params);
|
void setUpRenderPassAttachments(
|
||||||
|
wgpu::RenderPassDescriptor& descriptor,
|
||||||
|
RenderPassParams const& params,
|
||||||
|
// For default render target:
|
||||||
|
wgpu::TextureView const& defaultColorTextureView,
|
||||||
|
wgpu::TextureView const& defaultDepthStencilTextureView,
|
||||||
|
// For custom render targets:
|
||||||
|
wgpu::TextureView const* customColorTextureViews, // Array of views
|
||||||
|
uint32_t customColorTextureViewCount,
|
||||||
|
wgpu::TextureView const& customDepthTextureView,
|
||||||
|
wgpu::TextureView const& customStencilTextureView);
|
||||||
|
|
||||||
math::uint2 getAttachmentSize() noexcept;
|
|
||||||
|
math::uint2 getAttachmentSize() const noexcept;
|
||||||
|
|
||||||
bool isDefaultRenderTarget() const { return defaultRenderTarget; }
|
bool isDefaultRenderTarget() const { return defaultRenderTarget; }
|
||||||
uint8_t getSamples() const { return samples; }
|
uint8_t getSamples() const { return samples; }
|
||||||
|
|
||||||
Attachment getDrawColorAttachment(size_t index);
|
// Accessors for the driver to get stored attachment info
|
||||||
Attachment getReadColorAttachment(size_t index);
|
const MRT& getColorAttachmentInfos() const { return mColorAttachments; }
|
||||||
|
const Attachment& getDepthAttachmentInfo() const { return mDepthAttachment; }
|
||||||
|
const Attachment& getStencilAttachmentInfo() const { return mStencilAttachment; }
|
||||||
|
|
||||||
|
// Static helpers for load/store operations
|
||||||
static wgpu::LoadOp getLoadOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
static wgpu::LoadOp getLoadOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||||
static wgpu::StoreOp getStoreOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
static wgpu::StoreOp getStoreOperation(const RenderPassParams& params, TargetBufferFlags buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Helper to map MRT index to TargetBufferFlags
|
||||||
|
static TargetBufferFlags getTargetBufferFlagsAt(int mrtIndex);
|
||||||
|
|
||||||
bool defaultRenderTarget = false;
|
bool defaultRenderTarget = false;
|
||||||
uint8_t samples = 1;
|
uint8_t samples = 1;
|
||||||
|
|
||||||
Attachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
MRT mColorAttachments{};
|
||||||
math::uint2 attachmentSize = {};
|
Attachment mDepthAttachment{};
|
||||||
std::vector<wgpu::RenderPassColorAttachment> colorAttachments {};
|
Attachment mStencilAttachment{};
|
||||||
};
|
|
||||||
|
|
||||||
|
// Cached descriptors for the render pass
|
||||||
|
std::vector<wgpu::RenderPassColorAttachment> mColorAttachmentDescriptors;
|
||||||
|
wgpu::RenderPassDepthStencilAttachment mDepthStencilAttachmentDescriptor{};
|
||||||
|
bool mHasDepthStencilAttachment = false;
|
||||||
|
};
|
||||||
}// namespace filament::backend
|
}// namespace filament::backend
|
||||||
#endif// TNT_FILAMENT_BACKEND_WEBGPUHANDLES_H
|
#endif// TNT_FILAMENT_BACKEND_WEBGPUHANDLES_H
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ static constexpr size_t CONFIG_COMMAND_BUFFERS_SIZE = 3 * CONFIG_MIN_COMMAND
|
|||||||
|
|
||||||
using namespace filament;
|
using namespace filament;
|
||||||
using namespace filament::backend;
|
using namespace filament::backend;
|
||||||
|
using namespace filament::math;
|
||||||
|
|
||||||
#ifndef FILAMENT_IOS
|
#ifndef FILAMENT_IOS
|
||||||
#include <imageio/ImageEncoder.h>
|
#include <imageio/ImageEncoder.h>
|
||||||
@@ -45,6 +46,7 @@ namespace test {
|
|||||||
Backend BackendTest::sBackend = Backend::NOOP;
|
Backend BackendTest::sBackend = Backend::NOOP;
|
||||||
OperatingSystem BackendTest::sOperatingSystem = OperatingSystem::OTHER;
|
OperatingSystem BackendTest::sOperatingSystem = OperatingSystem::OTHER;
|
||||||
bool BackendTest::sIsMobilePlatform = false;
|
bool BackendTest::sIsMobilePlatform = false;
|
||||||
|
std::vector<std::string> BackendTest::sFailedImages;
|
||||||
|
|
||||||
void BackendTest::init(Backend backend, OperatingSystem operatingSystem, bool isMobilePlatform) {
|
void BackendTest::init(Backend backend, OperatingSystem operatingSystem, bool isMobilePlatform) {
|
||||||
sBackend = backend;
|
sBackend = backend;
|
||||||
@@ -63,11 +65,12 @@ BackendTest::~BackendTest() {
|
|||||||
flushAndWait();
|
flushAndWait();
|
||||||
mImageExpectations->evaluate();
|
mImageExpectations->evaluate();
|
||||||
// Note: Don't terminate the driver for OpenGL, as it wipes away the context and removes the buffer from the screen.
|
// Note: Don't terminate the driver for OpenGL, as it wipes away the context and removes the buffer from the screen.
|
||||||
if (sBackend == Backend::OPENGL) {
|
if (sBackend != Backend::OPENGL) {
|
||||||
return;
|
driver->terminate();
|
||||||
|
delete driver;
|
||||||
}
|
}
|
||||||
driver->terminate();
|
|
||||||
delete driver;
|
recordFailedImages();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendTest::initializeDriver() {
|
void BackendTest::initializeDriver() {
|
||||||
@@ -104,16 +107,35 @@ Handle<HwSwapChain> BackendTest::createSwapChain() {
|
|||||||
return getDriverApi().createSwapChain(view.ptr, 0);
|
return getDriverApi().createSwapChain(view.ptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendTest::fullViewport(RenderPassParams& params) {
|
PipelineState BackendTest::getColorWritePipelineState() {
|
||||||
fullViewport(params.viewport);
|
PipelineState result;
|
||||||
|
result.rasterState.colorWrite = true;
|
||||||
|
result.rasterState.depthWrite = false;
|
||||||
|
result.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendTest::fullViewport(Viewport& viewport) {
|
filament::backend::Viewport BackendTest::getFullViewport() const {
|
||||||
const NativeView& view = getNativeView();
|
const NativeView& view = getNativeView();
|
||||||
viewport.left = 0;
|
return Viewport {
|
||||||
viewport.bottom = 0;
|
.left = 0,
|
||||||
viewport.width = view.width;
|
.bottom = 0,
|
||||||
viewport.height = view.height;
|
.width = static_cast<uint32_t>(view.width),
|
||||||
|
.height = static_cast<uint32_t>(view.height)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
filament::backend::RenderPassParams BackendTest::getClearColorRenderPass(float4 color) {
|
||||||
|
RenderPassParams params = {};
|
||||||
|
params.flags.clear = TargetBufferFlags::COLOR;
|
||||||
|
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||||
|
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||||
|
params.clearColor = color;
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
filament::backend::RenderPassParams BackendTest::getNoClearRenderPass() {
|
||||||
|
return RenderPassParams{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendTest::renderTriangle(
|
void BackendTest::renderTriangle(
|
||||||
@@ -121,14 +143,9 @@ void BackendTest::renderTriangle(
|
|||||||
Handle<filament::backend::HwRenderTarget> renderTarget,
|
Handle<filament::backend::HwRenderTarget> renderTarget,
|
||||||
Handle<filament::backend::HwSwapChain> swapChain,
|
Handle<filament::backend::HwSwapChain> swapChain,
|
||||||
Handle<filament::backend::HwProgram> program) {
|
Handle<filament::backend::HwProgram> program) {
|
||||||
RenderPassParams params = {};
|
RenderPassParams params = getClearColorRenderPass();
|
||||||
fullViewport(params);
|
|
||||||
params.flags.clear = TargetBufferFlags::COLOR;
|
|
||||||
params.clearColor = {0.f, 0.f, 1.f, 1.f};
|
|
||||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
|
||||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
|
||||||
params.viewport.height = 512;
|
|
||||||
params.viewport.width = 512;
|
params.viewport.width = 512;
|
||||||
|
params.viewport.height = 512;
|
||||||
renderTriangle(pipelineLayout, renderTarget, swapChain, program, params);
|
renderTriangle(pipelineLayout, renderTarget, swapChain, program, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,8 +184,24 @@ bool BackendTest::matchesEnvironment(OperatingSystem operatingSystem) {
|
|||||||
return sOperatingSystem == operatingSystem;
|
return sOperatingSystem == operatingSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BackendTest::matchesEnvironment(OperatingSystem operatingSystem, Backend backend) {
|
void BackendTest::markImageAsFailure(std::string failedImageName) {
|
||||||
return matchesEnvironment(operatingSystem) && matchesEnvironment(backend);
|
sFailedImages.emplace_back(std::move(failedImageName));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendTest::recordFailedImages() {
|
||||||
|
if (!sFailedImages.empty()) {
|
||||||
|
std::string failedImages;
|
||||||
|
for (auto& failedTestImageName: sFailedImages) {
|
||||||
|
if (failedImages.empty()) {
|
||||||
|
failedImages = failedTestImageName;
|
||||||
|
} else {
|
||||||
|
failedImages.append(",");
|
||||||
|
failedImages.append(failedTestImageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RecordProperty("FailedImages", failedImages);
|
||||||
|
}
|
||||||
|
sFailedImages.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
class Environment : public ::testing::Environment {
|
class Environment : public ::testing::Environment {
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ public:
|
|||||||
static OperatingSystem sOperatingSystem;
|
static OperatingSystem sOperatingSystem;
|
||||||
static bool sIsMobilePlatform;
|
static bool sIsMobilePlatform;
|
||||||
|
|
||||||
|
// Takes the name of the image that wasn't correct, without the .png suffix
|
||||||
|
static void markImageAsFailure(std::string failedImageName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
BackendTest();
|
BackendTest();
|
||||||
@@ -49,9 +52,14 @@ protected:
|
|||||||
|
|
||||||
filament::backend::Handle<filament::backend::HwSwapChain> createSwapChain();
|
filament::backend::Handle<filament::backend::HwSwapChain> createSwapChain();
|
||||||
|
|
||||||
// Helper methods to set the viewport to the full extent of the swap chain.
|
static filament::backend::PipelineState getColorWritePipelineState();
|
||||||
static void fullViewport(filament::backend::RenderPassParams& params);
|
|
||||||
static void fullViewport(filament::backend::Viewport& viewport);
|
// Gets the full back buffer's viewport
|
||||||
|
filament::backend::Viewport getFullViewport() const;
|
||||||
|
// If color is unset this defaults to using opaque cyan
|
||||||
|
static filament::backend::RenderPassParams getClearColorRenderPass(
|
||||||
|
filament::math::float4 color = filament::math::float4(0, 1, 1, 1));
|
||||||
|
static filament::backend::RenderPassParams getNoClearRenderPass();
|
||||||
|
|
||||||
void renderTriangle(
|
void renderTriangle(
|
||||||
filament::backend::PipelineLayout const& pipelineLayout,
|
filament::backend::PipelineLayout const& pipelineLayout,
|
||||||
@@ -73,8 +81,13 @@ protected:
|
|||||||
|
|
||||||
static bool matchesEnvironment(Backend backend);
|
static bool matchesEnvironment(Backend backend);
|
||||||
static bool matchesEnvironment(OperatingSystem operatingSystem);
|
static bool matchesEnvironment(OperatingSystem operatingSystem);
|
||||||
static bool matchesEnvironment(OperatingSystem operatingSystem, Backend backend);
|
|
||||||
private:
|
private:
|
||||||
|
// Adds all the images that failed an ImageExpectation to the XML metadata for the current tests
|
||||||
|
// case. Add --gtest_output=xml as a command line argument to generate a test_detail.xml file in
|
||||||
|
// the directory where the tests are run.
|
||||||
|
static void recordFailedImages();
|
||||||
|
|
||||||
|
static std::vector<std::string> sFailedImages;
|
||||||
|
|
||||||
filament::backend::Driver* driver = nullptr;
|
filament::backend::Driver* driver = nullptr;
|
||||||
filament::backend::CommandBufferQueue commandBufferQueue;
|
filament::backend::CommandBufferQueue commandBufferQueue;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "utils/Hash.h"
|
#include "utils/Hash.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "BackendTest.h"
|
||||||
#include "backend/PixelBufferDescriptor.h"
|
#include "backend/PixelBufferDescriptor.h"
|
||||||
#include "private/backend/DriverApi.h"
|
#include "private/backend/DriverApi.h"
|
||||||
|
|
||||||
@@ -32,6 +33,8 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace test {
|
||||||
|
|
||||||
ScreenshotParams::ScreenshotParams(int width, int height, std::string fileName,
|
ScreenshotParams::ScreenshotParams(int width, int height, std::string fileName,
|
||||||
uint32_t expectedHash, bool isSrgb)
|
uint32_t expectedHash, bool isSrgb)
|
||||||
: mWidth(width),
|
: mWidth(width),
|
||||||
@@ -80,6 +83,10 @@ std::string ScreenshotParams::expectedFilePath() const {
|
|||||||
return absl::StrFormat("%s/%s", expectedDirectoryPath(), expectedFileName());
|
return absl::StrFormat("%s/%s", expectedDirectoryPath(), expectedFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string ScreenshotParams::filePrefix() const {
|
||||||
|
return mFileName;
|
||||||
|
}
|
||||||
|
|
||||||
ImageExpectation::ImageExpectation(const char* fileName, int lineNumber,
|
ImageExpectation::ImageExpectation(const char* fileName, int lineNumber,
|
||||||
filament::backend::DriverApi& api, ScreenshotParams params,
|
filament::backend::DriverApi& api, ScreenshotParams params,
|
||||||
filament::backend::RenderTargetHandle renderTarget)
|
filament::backend::RenderTargetHandle renderTarget)
|
||||||
@@ -113,7 +120,11 @@ void ImageExpectation::compareImage() const {
|
|||||||
#ifndef FILAMENT_IOS
|
#ifndef FILAMENT_IOS
|
||||||
LoadedPng loadedImage(mParams.expectedFilePath());
|
LoadedPng loadedImage(mParams.expectedFilePath());
|
||||||
uint32_t loadedImageHash = loadedImage.hash();
|
uint32_t loadedImageHash = loadedImage.hash();
|
||||||
EXPECT_THAT(actualHash, testing::Eq(loadedImageHash)) << mParams.expectedFileName();
|
auto compareToImageMatcher = testing::Eq(loadedImageHash);
|
||||||
|
if (!testing::Matches(compareToImageMatcher)(actualHash)) {
|
||||||
|
BackendTest::markImageAsFailure(mParams.filePrefix());
|
||||||
|
}
|
||||||
|
EXPECT_THAT(actualHash, compareToImageMatcher) << mParams.expectedFileName();
|
||||||
#endif
|
#endif
|
||||||
// For builds that can't load PNGs (currently iOS only) use the expected hash.
|
// For builds that can't load PNGs (currently iOS only) use the expected hash.
|
||||||
EXPECT_THAT(actualHash, testing::Eq(mParams.expectedHash())) << mParams.expectedFileName();
|
EXPECT_THAT(actualHash, testing::Eq(mParams.expectedHash())) << mParams.expectedFileName();
|
||||||
@@ -200,6 +211,10 @@ uint32_t RenderTargetDump::hash() const {
|
|||||||
return mInternal->hash();
|
return mInternal->hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<unsigned char>& RenderTargetDump::bytes() const {
|
||||||
|
return mInternal->bytes;
|
||||||
|
}
|
||||||
|
|
||||||
bool RenderTargetDump::bytesFilled() const {
|
bool RenderTargetDump::bytesFilled() const {
|
||||||
return mInternal->bytesFilled;
|
return mInternal->bytesFilled;
|
||||||
}
|
}
|
||||||
@@ -237,3 +252,5 @@ uint32_t LoadedPng::hash() const {
|
|||||||
const std::vector<unsigned char>& LoadedPng::bytes() const {
|
const std::vector<unsigned char>& LoadedPng::bytes() const {
|
||||||
return mBytes;
|
return mBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ do { \
|
|||||||
screenshotParams); \
|
screenshotParams); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
namespace test {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores user-provided configuration values for an image expectation
|
* Stores user-provided configuration values for an image expectation
|
||||||
*/
|
*/
|
||||||
@@ -54,6 +56,7 @@ public:
|
|||||||
static std::string expectedDirectoryPath();
|
static std::string expectedDirectoryPath();
|
||||||
std::string expectedFileName() const;
|
std::string expectedFileName() const;
|
||||||
std::string expectedFilePath() const;
|
std::string expectedFilePath() const;
|
||||||
|
const std::string filePrefix() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int mWidth;
|
int mWidth;
|
||||||
@@ -82,6 +85,12 @@ public:
|
|||||||
* @return The hash of the stored bytes.
|
* @return The hash of the stored bytes.
|
||||||
*/
|
*/
|
||||||
uint32_t hash() const;
|
uint32_t hash() const;
|
||||||
|
/**
|
||||||
|
* Gets the bytes of the render target. The hash should usually be preferable for comparisons
|
||||||
|
* but this is available for debugging.
|
||||||
|
* @return The stored bytes.
|
||||||
|
*/
|
||||||
|
const std::vector<unsigned char>& bytes() const;
|
||||||
/**
|
/**
|
||||||
* Thread safe as this is backed by an atomic.
|
* Thread safe as this is backed by an atomic.
|
||||||
* Once this returns true it will never return false.
|
* Once this returns true it will never return false.
|
||||||
@@ -153,4 +162,6 @@ private:
|
|||||||
std::vector<std::unique_ptr<ImageExpectation>> mExpectations;
|
std::vector<std::unique_ptr<ImageExpectation>> mExpectations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
|
||||||
#endif //TNT_IMAGE_EXPECTATIONS_H
|
#endif //TNT_IMAGE_EXPECTATIONS_H
|
||||||
|
|||||||
@@ -56,26 +56,35 @@ Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup
|
|||||||
mProgram = cleanup.add(api.createProgram(std::move(prog)));
|
mProgram = cleanup.add(api.createProgram(std::move(prog)));
|
||||||
|
|
||||||
if (!kLayouts.empty()) {
|
if (!kLayouts.empty()) {
|
||||||
mDescriptorSetLayout =
|
mDescriptorSetLayout = cleanup.add(
|
||||||
cleanup.add(api.createDescriptorSetLayout(DescriptorSetLayout{ kLayouts }));
|
api.createDescriptorSetLayout(DescriptorSetLayout{ .bindings = kLayouts }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filament::backend::DescriptorSetHandle Shader::createDescriptorSet(DriverApi& api) const {
|
DescriptorSetHandle Shader::createDescriptorSet(DriverApi& api) const {
|
||||||
return mCleanup.add(api.createDescriptorSet(mDescriptorSetLayout));
|
return mCleanup.add(api.createDescriptorSet(mDescriptorSetLayout));
|
||||||
}
|
}
|
||||||
|
|
||||||
filament::backend::ProgramHandle Shader::getProgram() const {
|
ProgramHandle Shader::getProgram() const {
|
||||||
assert(mProgram);
|
assert(mProgram);
|
||||||
EXPECT_THAT(mProgram, ::testing::IsTrue())
|
EXPECT_THAT(mProgram, ::testing::IsTrue())
|
||||||
<< "Shader program accessed despite being null.";
|
<< "Shader program accessed despite being null.";
|
||||||
return mProgram;
|
return mProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
filament::backend::DescriptorSetLayoutHandle Shader::getDescriptorSetLayout() const {
|
DescriptorSetLayoutHandle Shader::getDescriptorSetLayout() const {
|
||||||
EXPECT_THAT(mDescriptorSetLayout, ::testing::IsTrue())
|
EXPECT_THAT(mDescriptorSetLayout, ::testing::IsTrue())
|
||||||
<< "Shader descriptor set layout accessed despite being null.";
|
<< "Shader descriptor set layout accessed despite being null.";
|
||||||
return mDescriptorSetLayout;
|
return mDescriptorSetLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Shader::addProgramToPipelineState(PipelineState& state) const {
|
||||||
|
state.program = getProgram();
|
||||||
|
// In case another shader was set first, clear the set layout and then set this shader's values.
|
||||||
|
state.pipelineLayout.setLayout = PipelineLayout::SetLayout();
|
||||||
|
if (mDescriptorSetLayout) {
|
||||||
|
state.pipelineLayout.setLayout[0] = { getDescriptorSetLayout() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ public:
|
|||||||
filament::backend::ProgramHandle getProgram() const;
|
filament::backend::ProgramHandle getProgram() const;
|
||||||
filament::backend::DescriptorSetLayoutHandle getDescriptorSetLayout() const;
|
filament::backend::DescriptorSetLayoutHandle getDescriptorSetLayout() const;
|
||||||
|
|
||||||
|
void addProgramToPipelineState(filament::backend::PipelineState& state) const;
|
||||||
|
|
||||||
filament::backend::DescriptorSetHandle createDescriptorSet(
|
filament::backend::DescriptorSetHandle createDescriptorSet(
|
||||||
filament::backend::DriverApi& api) const;
|
filament::backend::DriverApi& api) const;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include "ShaderGenerator.h"
|
#include "ShaderGenerator.h"
|
||||||
|
|
||||||
#include <GlslangToSpv.h>
|
#include <GlslangToSpv.h>
|
||||||
#include <SPVRemapper.h>
|
|
||||||
|
|
||||||
#include <spirv_glsl.hpp>
|
#include <spirv_glsl.hpp>
|
||||||
#include <spirv_msl.hpp>
|
#include <spirv_msl.hpp>
|
||||||
@@ -119,7 +118,7 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s
|
|||||||
} else if (backend == Backend::VULKAN) {
|
} else if (backend == Backend::VULKAN) {
|
||||||
shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n");
|
shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n");
|
||||||
} else if (backend == Backend::WEBGPU) {
|
} else if (backend == Backend::WEBGPU) {
|
||||||
shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n");
|
shader.insert(pos, "#define TARGET_WEBGPU_ENVIRONMENT\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* shaderCString = shader.c_str();
|
const char* shaderCString = shader.c_str();
|
||||||
@@ -187,4 +186,16 @@ Program ShaderGenerator::getProgram(filament::backend::DriverApi&) noexcept {
|
|||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Program ShaderGenerator::getProgramWithPushConstants(filament::backend::DriverApi&,
|
||||||
|
std::array<PushConstants, filament::backend::Program::SHADER_TYPE_COUNT> constants) {
|
||||||
|
Program program;
|
||||||
|
program.shaderLanguage(mShaderLanguage);
|
||||||
|
program.shader(ShaderStage::VERTEX, mVertexBlob.data(), mVertexBlob.size());
|
||||||
|
program.shader(ShaderStage::FRAGMENT, mFragmentBlob.data(), mFragmentBlob.size());
|
||||||
|
for (auto const stage : {ShaderStage::VERTEX, ShaderStage::FRAGMENT }) {
|
||||||
|
program.pushConstants(stage, constants[uint8_t(stage)]);
|
||||||
|
}
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ public:
|
|||||||
|
|
||||||
filament::backend::Program getProgram(filament::backend::DriverApi&) noexcept;
|
filament::backend::Program getProgram(filament::backend::DriverApi&) noexcept;
|
||||||
|
|
||||||
|
using PushConstants = utils::FixedCapacityVector<filament::backend::Program::PushConstant>;
|
||||||
|
filament::backend::Program getProgramWithPushConstants(filament::backend::DriverApi&,
|
||||||
|
std::array<PushConstants, filament::backend::Program::SHADER_TYPE_COUNT> constants);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using ShaderStage = filament::backend::ShaderStage;
|
using ShaderStage = filament::backend::ShaderStage;
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ std::vector<UniformConfig> GetUniformConfig(ShaderUniformType type) {
|
|||||||
"backend_test", "test_tex", 0,
|
"backend_test", "test_tex", 0,
|
||||||
SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH, false };
|
SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH, false };
|
||||||
return {{
|
return {{
|
||||||
"test_tex", DescriptorType::SAMPLER, samplerInfo
|
"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -32,13 +32,24 @@ do {
|
|||||||
} \
|
} \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
|
#define NONFATAL_FAIL_IF(skipEnvironment, rationale) \
|
||||||
|
do { \
|
||||||
|
SkipEnvironment skip(skipEnvironment); \
|
||||||
|
if (skip.matches()) { \
|
||||||
|
ADD_FAILURE() \
|
||||||
|
<< "Failing test as the " << skip.describe() << "\n" \
|
||||||
|
<< " This test has a known failure where " \
|
||||||
|
<< rationale; \
|
||||||
|
} \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
#define FAIL_IF(skipEnvironment, rationale) \
|
#define FAIL_IF(skipEnvironment, rationale) \
|
||||||
do { \
|
do { \
|
||||||
SkipEnvironment skip(skipEnvironment); \
|
SkipEnvironment skip(skipEnvironment); \
|
||||||
if (skip.matches()) { \
|
if (skip.matches()) { \
|
||||||
GTEST_FAIL() \
|
GTEST_FAIL() \
|
||||||
<< "Failing test as the " << skip.describe() << "\n" \
|
<< "Failing test as the " << skip.describe() << "\n" \
|
||||||
<< " This test should be able to succeed but it needs to fail early because" \
|
<< " This test should be able to succeed but it needs to fail early because " \
|
||||||
<< rationale; \
|
<< rationale; \
|
||||||
} \
|
} \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ public:
|
|||||||
void updateIndices(const index_type* indices) noexcept;
|
void updateIndices(const index_type* indices) noexcept;
|
||||||
void updateIndices(const index_type* indices, int count, int offset) noexcept;
|
void updateIndices(const index_type* indices, int count, int offset) noexcept;
|
||||||
|
|
||||||
|
VertexInfoHandle getVertexBufferInfo() const { return mVertexBufferInfo; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
size_t mVertexCount = 3;
|
size_t mVertexCount = 3;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |