Compare commits

..
341 changed files with 24668 additions and 31266 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
-45
View File
@@ -1,45 +0,0 @@
name: 'Get commit message'
outputs:
msg:
value: ${{ steps.action_output.outputs.msg }}
runs:
using: "composite"
steps:
- name: Find commit message (on push)
if: github.event_name == 'push'
shell: bash
run: |
AUTHOR_NAME="${{ github.event.head_commit.author.name }}"
AUTHOR_EMAIL="${{ github.event.head_commit.author.email }}"
TSTAMP="${{ github.event.head_commit.timestamp }}"
echo "commit ${{ github.event.head_commit.id }}" >> /tmp/commit_msg.txt
echo "Author: ${AUTHOR_NAME}<${AUTHOR_EMAIL}>" >> /tmp/commit_msg.txt
echo "Date: ${TSTAMP}" >> /tmp/commit_msg.txt
echo "" >> /tmp/commit_msg.txt
echo "${{ github.event.head_commit.message }}" >> /tmp/commit_msg.txt
- name: Find commit message (PR)
shell: bash
id: checkout_code
if: github.event_name == 'pull_request'
run: |
echo "+++++ head commit message +++++"
echo "$(git log -1 --no-merges)"
echo "+++++++++++++++++++++++++++++++"
echo "hash=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
git checkout ${{ github.event.pull_request.head.sha }}
echo "$(git log -1 --no-merges)" >> /tmp/commit_msg.txt
- shell: bash
id: action_output
run: |
DELIMITER="EOF_FILE_CONTENT_$(date +%s)" # Using timestamp to make it more unique
echo "msg<<$DELIMITER" >> "$GITHUB_OUTPUT"
cat /tmp/commit_msg.txt >> "$GITHUB_OUTPUT"
echo "$DELIMITER" >> "$GITHUB_OUTPUT"
echo "----- got commit message ---"
cat /tmp/commit_msg.txt
echo "----------------------------"
- name: Cleanup Find commit message (PR)
shell: bash
if: github.event_name == 'pull_request'
run: |
git checkout ${{ steps.checkout_code.outputs.hash }}
-35
View File
@@ -1,35 +0,0 @@
name: 'Post-submit tasks'
on:
push:
branches:
- main
jobs:
update-renderdiff-goldens:
name: update-renderdiff-goldens
runs-on: 'ubuntu-24.04-4core'
steps:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- uses: ./.github/actions/linux-prereq
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- name: Prerequisites
run: pip install tifffile numpy
- name: Run update script
env:
GH_TOKEN: ${{ secrets.FILAMENTBOT_TOKEN }}
run: |
GOLDEN_BRANCH=$(echo "${{ steps.get_commit_msg.outputs.msg }}" | python3 test/renderdiff/src/commit_msg.py)
COMMIT_HASH=$(echo "${{ steps.get_commit_msg.outputs.msg }}" | head -n 1 | tr -d 'commit ')
if [[ "${GOLDEN_BRANCH}" != "main" ]]; then
git config --global user.email "filament.bot@gmail.com"
git config --global user.name "Filament Bot"
git config --global credential.helper cache
echo "branch==${GOLDEN_BRANCH}"
echo "hash==${COMMIT_HASH}"
python3 test/renderdiff/src/update_golden.py --branch=${GOLDEN_BRANCH} \
--merge-to-main --filament-tag=${COMMIT_HASH} --golden-repo-token=${GH_TOKEN}
fi
+10 -10
View File
@@ -3,10 +3,10 @@ name: Presubmit
on:
push:
branches:
- main
- main
pull_request:
branches:
- main
- main
jobs:
build-desktop-mac:
@@ -41,7 +41,8 @@ jobs:
build-windows:
name: build-windows
runs-on: windows-2022-32core
runs-on: win-2019-16core
steps:
- uses: actions/checkout@v4.1.6
with:
@@ -109,9 +110,9 @@ jobs:
fetch-depth: 0
- name: Check for manual edits to /docs
run: |
echo "${{ github.event.pull_request.head.sha }} -- ${{ github.event.pull_request.head.sha }}"
# disable for now
# bash docs_src/build/presubmit_check.sh ${{ github.event.pull_request.head.sha }}
echo "${{ github.event.pull_request.head.sha }} -- ${{ github.event.pull_request.head.sha }}"
# disable for now
# bash docs_src/build/presubmit_check.sh ${{ github.event.pull_request.head.sha }}
test-renderdiff:
name: test-renderdiff
@@ -120,21 +121,20 @@ jobs:
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- id: get_commit_msg
uses: ./.github/actions/get-commit-msg
- uses: ./.github/actions/mac-prereq
- name: Cache Mesa and deps
id: mesa-cache
uses: actions/cache@v4
with:
path: mesa
key: ${{ runner.os }}-mesa-deps-2-${{ vars.MESA_VERSION }}
- name: Prerequisites
id: prereqs
run: |
bash build/common/get-mesa.sh
pip install tifffile numpy
- name: Run Test
run: |
echo "${{ steps.get_commit_msg.outputs.msg }}" | bash test/renderdiff/test.sh
run: bash test/renderdiff/test.sh
- uses: actions/upload-artifact@v4
with:
name: presubmit-renderdiff-result
+1 -1
View File
@@ -226,7 +226,7 @@ jobs:
build-windows:
name: build-windows
runs-on: windows-2022-32core
runs-on: windows-2019-32core
if: github.event_name == 'release' || github.event.inputs.platform == 'windows'
steps:
+1 -1
View File
@@ -10,7 +10,7 @@ on:
jobs:
build-windows:
name: build-windows
runs-on: windows-2022-32core
runs-on: windows-2019-32core
steps:
- uses: actions/checkout@v4.1.6
-4
View File
@@ -97,10 +97,6 @@ Make sure you've installed the following dependencies:
- `libxcomposite-dev` (`libXcomposite-devel` on Fedora)
- `libxxf86vm-dev` (`libXxf86vm-devel` on Fedora)
```shell
sudo apt install clang-14 libglu1-mesa-dev libc++-14-dev libc++abi-14-dev ninja-build libxi-dev libxcomposite-dev libxxf86vm-dev -y
```
After dependencies have been installed, we highly recommend using the [easy build](#easy-build)
script.
-10
View File
@@ -49,12 +49,6 @@ option(FILAMENT_SUPPORTS_OSMESA "Enable OSMesa (headless GL context) for Filamen
option(FILAMENT_ENABLE_FGVIEWER "Enable the frame graph viewer" OFF)
option(FILAMENT_USE_ABSEIL_LOGGING "Use Abseil to log, may increase binary size" OFF)
# This is to disable GTAO for the short-term while we investigate a way to better manage size increases.
# On the regular filament build (where size is of less concern), we enable GTAO by default.
option(FILAMENT_DISABLE_GTAO "Disable GTAO" OFF)
set(FILAMENT_NDK_VERSION "" CACHE STRING
"Android NDK version or version prefix to be used when building for Android."
)
@@ -593,10 +587,6 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT FILAMENT_BACKEND_DEBUG_FLAG STREQU
unset(FILAMENT_BACKEND_DEBUG_FLAG)
endif()
if (FILAMENT_USE_ABSEIL_LOGGING)
add_definitions(-DFILAMENT_USE_ABSEIL_LOGGING)
endif()
# ==================================================================================================
# Material compilation flags
# ==================================================================================================
+3 -1
View File
@@ -1,9 +1,11 @@
# Filament Release Notes log
**If you are merging a PR into main**: please add the release note below, under the *Release notes
We are chaning the way Vulkan buffers are handled. We need to switch over to a managed (or view-based) model where the data stored inside the object is a proxy to a Vulkan object that can dynamically be swapped around.
for next branch cut* header.
**If you are cherry-picking a commit into an rc/ branch**: add the release note under the
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- materials: sampler now export their type in the material binary [⚠️ **New Material Version**]
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.61.1'
implementation 'com.google.android.filament:filament-android:1.60.0'
}
```
@@ -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:
```shell
pod 'Filament', '~> 1.61.1'
pod 'Filament', '~> 1.60.0'
```
## Documentation
-15
View File
@@ -7,21 +7,6 @@ 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
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.62.0
- samples: samples now have a CLI to select backend api
- materials: sampler now export their type in the material binary [⚠️ **New Material Version**]
- materials: new mutable specialization constants feature. See the [materials documentation](https://google.github.io/filament/Materials.html) for details. [⚠️ **New Material Version**]
## v1.61.1
## 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
-5
View File
@@ -59,10 +59,6 @@ add_library(smol-v STATIC IMPORTED)
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
add_library(abseil STATIC IMPORTED)
set_target_properties(abseil PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libabseil.a)
if (FILAMENT_ENABLE_FGVIEWER)
add_library(fgviewer STATIC IMPORTED)
set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
@@ -132,7 +128,6 @@ target_link_libraries(filament-jni
PRIVATE jnigraphics
PRIVATE utils
PRIVATE perfetto
PRIVATE abseil
# libgeometry is PUBLIC because gltfio uses it.
PUBLIC geometry
@@ -60,14 +60,6 @@ static void setParameter(JNIEnv* env, jlong nativeMaterialInstance, jstring name
env->ReleaseStringUTFChars(name_, name);
}
template<typename T>
static void setConstant(JNIEnv* env, jlong nativeMaterialInstance, jstring name_, T v) {
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
const char *name = env->GetStringUTFChars(name_, 0);
instance->setConstant(name, v);
env->ReleaseStringUTFChars(name_, name);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetParameterBool(JNIEnv *env, jclass,
@@ -272,13 +264,6 @@ Java_com_google_android_filament_MaterialInstance_nSetParameterTexture(
env->ReleaseStringUTFChars(name_, name);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetConstantBool(JNIEnv *env, jclass,
jlong nativeMaterialInstance, jstring name_, jboolean x) {
setConstant(env, nativeMaterialInstance, name_, bool(x));
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetScissor(
@@ -402,16 +402,6 @@ public class MaterialInstance {
nSetParameterFloat4(getNativeObject(), name, color[0], color[1], color[2], color[3]);
}
/**
* Sets the value of a bool constant.
*
* @param name the name of the material constant
* @param x the value of the material constant
*/
public void setConstant(@NonNull String name, boolean x) {
nSetConstantBool(getNativeObject(), name, x);
}
/**
* Set-up a custom scissor rectangle; by default it is disabled.
*
@@ -931,9 +921,6 @@ public class MaterialInstance {
@NonNull String name, int element, @NonNull @Size(min = 1) float[] v,
@IntRange(from = 0) int offset, @IntRange(from = 1) int count);
private static native void nSetConstantBool(long nativeMaterialInstance,
@NonNull String name, boolean x);
private static native void nSetParameterTexture(long nativeMaterialInstance,
@NonNull String name, long nativeTexture, long sampler);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.61.1
VERSION_NAME=1.60.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+2 -9
View File
@@ -41,8 +41,6 @@ for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
done
deactivate
LOCAL_PKG_CONFIG_PATH=
# Install system deps
if [[ "$OS_NAME" == "Linux" ]]; then
if [[ "$GITHUB_WORKFLOW" ]]; then
@@ -84,9 +82,6 @@ elif [[ "$OS_NAME" == "Darwin" ]]; then
fi
fi
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=true brew install autoconf automake libx11 libxext libxrandr llvm@${LLVM_VERSION} ninja meson pkg-config libxshmfence
# For reasons unknown, this is necessary for pkg-config to find homebrew's packages
LOCAL_PKG_CONFIG_PATH="/opt/homebrew/lib/pkgconfig:$PKG_CONFIG_PATH"
fi # [[ "$OS_NAME" == x ]]
LOCAL_LDFLAGS=${LDFLAGS}
@@ -139,11 +134,9 @@ fi
# -Dgallium-drivers=swrast => builds GL software rasterizer
# -Dvulkan-drivers=swrast => builds VK software rasterizer
# -Dgallium-drivers=llvmpipe is needed for GL >= 4.1 pipe-screen (see src/gallium/auxiliary/target-helpers/inline_sw_helper.h)
PKG_CONFIG_PATH=${LOCAL_PKG_CONFIG_PATH} PATH=${LOCAL_PATH} \
CXX=${LOCAL_CXX} CC=${LOCAL_CC} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
meson setup --wipe builddir/ -Dprefix="${MESA_DIR}/out" -Dglx=xlib -Dosmesa=true -Dgallium-drivers=llvmpipe,swrast -Dvulkan-drivers=swrast
PKG_CONFIG_PATH=${LOCAL_PKG_CONFIG_PATH} PATH=${LOCAL_PATH} \
CXX=${LOCAL_CXX} CC=${LOCAL_CC} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
CXX=${LOCAL_CXX} CC=${LOCAL_CC} PATH=${LOCAL_PATH} LDFLAGS=${LOCAL_LDFLAGS} CPPFLAGS=${LOCAL_CPPFLAGS} \
meson install -C builddir/
# Disable python venv
+2 -6
View File
@@ -47,11 +47,7 @@ if "%RUNNING_LOCALLY%" == "1" (
set "PATH=%PATH%;C:\Program Files\7-Zip"
)
:: Outdated windows-2019 pattern
:: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\%VISUAL_STUDIO_VERSION%\VC\Auxiliary\Build\vcvars64.bat"
call "C:\Program Files\Microsoft Visual Studio\2022\%VISUAL_STUDIO_VERSION%\VC\Auxiliary\Build\vcvars64.bat"
echo Passed vcvars64.bat
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\%VISUAL_STUDIO_VERSION%\VC\Auxiliary\Build\vcvars64.bat"
if errorlevel 1 exit /b %errorlevel%
msbuild /version
@@ -111,7 +107,7 @@ cd out\cmake-%variant%
if errorlevel 1 exit /b %errorlevel%
cmake ..\.. ^
-G "Visual Studio 17 2022" ^
-G "Visual Studio 16 2019" ^
-A x64 ^
%flag% ^
-DCMAKE_INSTALL_PREFIX=..\%variant% ^
+24 -31
View File
@@ -211,7 +211,7 @@ when using textures.
This property can dramatically change the appearance of a surface. Non-metallic surfaces have
chromatic diffuse reflection and achromatic specular reflection (reflected light does not change
color). Metallic surfaces do not have any diffuse reflection and chromatic specular reflection
(reflected light takes on the color of the surfaced as defined by `baseColor`).
(reflected light takes on the color of the surfaced as defined by `baseColor`).
The effect of `metallic` is shown in figure [metallicProperty] (click on the image to see a
larger version).
@@ -247,7 +247,7 @@ The effect of `roughness` on metallic surfaces is shown in figure [roughnessCond
When refraction through an object is enabled (using a `refractonType` of `thin` or `solid`), the
`roughness` property will also affect the refractions, as shown in figure
[roughnessRefractionProperty] (click on the image to see a larger version).
![Figure [roughnessRefractionProperty]: Refractive sphere with `roughness` varying from 0.0
(left) to 1.0 (right)](images/materials/refraction_roughness.png)
@@ -306,7 +306,7 @@ The sheen color controls the color appearance and strength of an optional sheen
base layer described by the properties above. The sheen layer always sits below the clear coat layer
if such a layer is present.
The sheen layer can be used to represent cloth and fabric materials. Please refer to
The sheen layer can be used to represent cloth and fabric materials. Please refer to
section [Cloth model] for more information about cloth and fabric materials.
The effect of `sheenColor` is shown in figure [materialSheenColor]
@@ -519,14 +519,14 @@ light to bend further away from the initial path.
Table [commonMatIOR] describes acceptable refractive indices for various types of materials.
Material | IOR
Material | IOR
--------------------------:|:-----------------
Air | 1.0
Water | 1.33
Common liquids | 1.33 to 1.5
Common gemstones | 1.58 to 2.33
Plastics, glass | 1.5 to 1.58
Other dielectric materials | 1.33 to 1.58
Water | 1.33
Common liquids | 1.33 to 1.5
Common gemstones | 1.58 to 2.33
Plastics, glass | 1.5 to 1.58
Other dielectric materials | 1.33 to 1.58
[Table [commonMatIOR]: Index of refraction of common materials]
The appearance of a refractive material will greatly depend on the `refractionType` and
@@ -1091,37 +1091,30 @@ Value
`bool` or `number`, depending on the `type` of the constant. The type must be one of the types
described in table [materialConstantsTypes].
Constants may also be specified as mutable by setting the `mutable` property to `true`. Only
`bool` spec constants may be specified as mutable.
| Type | Description | Default | May be mutable? |
|:------|:------------------------------|:--------|-----------------|
| int | A signed, 32 bit GLSL int | | no |
| float | A single-precision GLSL float | 0.0 | no |
| bool | A GLSL bool | false | yes |
Type | Description | Default
:----------------------|:-----------------------------------------|:------------------
int | A signed, 32 bit GLSL int | 0
float | A single-precision GLSL float | 0.0
bool | A GLSL bool | false
[Table [materialConstantsTypes]: Material constants types]
Description
: Lists the constant parameters accepted by your material. These constants can be set, or
"specialized", at runtime when loading a material package. Multiple materials can be loaded from
the same material package with differing constant parameter specializations. If a constant
parameter is specialized as mutable, it may be changed at any time on a per-instance basis via
`MaterialInstance::setConstant(name, value)`. Otherwise, once a material is loaded from a
material package, its constant parameters cannot be changed.
Compared to regular parameters, constant parameters allow the compiler to generate more
efficient code. Access constant parameters from the shader by prefixing the name with
`materialConstant_`. For example, a constant parameter named `myConstant` is accessed in the
shader as `materialConstant_myConstant`. If a constant parameter is not set at runtime, the
default is used.
the same material package with differing constant parameter specializations. Once a material is
loaded from a material package, its constant parameters cannot be changed. Compared to regular
parameters, constant parameters allow the compiler to generate more efficient code. Access
constant parameters from the shader by prefixing the name with `materialConstant_`. For example,
a constant parameter named `myConstant` is accessed in the shader as
`materialConstant_myConstant`. If a constant parameter is not set at runtime, the default is
used.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
constants : [
{
name : overrideAlpha,
type : bool,
mutable : true,
type : bool
},
{
name : customAlpha,
@@ -2560,7 +2553,7 @@ standard skybox material. It produces a list of 2 parameters, named `showSun` an
respectively a boolean and a cubemap texture.
```text
$ matc --reflect parameters filament/src/materials/skybox.mat
$ matc --reflect parameters filament/src/materials/skybox.mat
{
"parameters": [
{
@@ -2576,7 +2569,7 @@ $ matc --reflect parameters filament/src/materials/skybox.mat
}
]
}
```
```
### --variant-filter
+22 -37
View File
@@ -262,15 +262,10 @@ set(MATERIAL_SRCS
src/materials/ssao/mipmapDepth.mat
src/materials/ssao/sao.mat
src/materials/ssao/saoBentNormals.mat
src/materials/vsmMipmap.mat
)
if (NOT FILAMENT_DISABLE_GTAO)
list(APPEND MATERIAL_SRCS
src/materials/ssao/gtao.mat
src/materials/ssao/gtaoBentNormals.mat
)
endif()
src/materials/vsmMipmap.mat
)
set(MATERIAL_FL0_SRCS
src/materials/defaultMaterial.mat
@@ -321,10 +316,6 @@ if (FILAMENT_FORCE_PROFILING_MODE)
add_definitions(-DFILAMENT_FORCE_PROFILING_MODE)
endif()
if (FILAMENT_DISABLE_GTAO)
add_definitions(-DFILAMENT_DISABLE_GTAO)
endif()
# ==================================================================================================
# Definitions
# ==================================================================================================
@@ -472,29 +463,27 @@ add_custom_command(
APPEND
)
if (NOT FILAMENT_DISABLE_GTAO)
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}/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
)
endif()
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(
OUTPUT "${MATERIAL_DIR}/bilateralBlur.filamat"
@@ -601,10 +590,6 @@ target_link_libraries(${TARGET} PUBLIC filaflat)
target_link_libraries(${TARGET} PUBLIC filabridge)
target_link_libraries(${TARGET} PUBLIC ibl-lite)
if (FILAMENT_USE_ABSEIL_LOGGING)
target_link_libraries(${TARGET} PUBLIC absl::log)
endif()
if (FILAMENT_ENABLE_FGVIEWER)
target_link_libraries(${TARGET} PUBLIC fgviewer)
add_definitions(-DFILAMENT_ENABLE_FGVIEWER=1)
+4 -5
View File
@@ -92,7 +92,7 @@ Copy your platform's Makefile below into a `Makefile` inside the same directory.
### Linux
```make
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl -labseil
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl
CC=clang++
main: main.o
@@ -110,13 +110,12 @@ clean:
### macOS
```make
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl -labseil
FILAMENT_LIBS=-lfilament -lbackend -lbluegl -lbluevk -lfilabridge -lfilaflat -lutils -lgeometry -lsmol-v -lvkshaders -libl
FRAMEWORKS=-framework Cocoa -framework Metal -framework CoreVideo
CC=clang++
ARCH ?= $(shell uname -m)
main: main.o
$(CC) -Llib/$(ARCH)/ main.o $(FILAMENT_LIBS) $(FRAMEWORKS) -o main
$(CC) -Llib/x86_64/ main.o $(FILAMENT_LIBS) $(FRAMEWORKS) -o main
main.o: main.cpp
$(CC) -Iinclude/ -std=c++17 -c main.cpp
@@ -140,7 +139,7 @@ used to change the run-time library version.
```make
FILAMENT_LIBS=filament.lib backend.lib bluegl.lib bluevk.lib filabridge.lib filaflat.lib \
utils.lib geometry.lib smol-v.lib ibl.lib vkshaders.lib abseil.lib
utils.lib geometry.lib smol-v.lib ibl.lib vkshaders.lib
CC=cl.exe
main.exe: main.obj
+4 -30
View File
@@ -180,11 +180,8 @@ if (FILAMENT_SUPPORTS_VULKAN)
src/vulkan/VulkanAsyncHandles.h
src/vulkan/VulkanBlitter.cpp
src/vulkan/VulkanBlitter.h
src/vulkan/VulkanBuffer.cpp
src/vulkan/VulkanBuffer.h
src/vulkan/VulkanBufferCache.h
src/vulkan/VulkanBufferCache.cpp
src/vulkan/VulkanBufferProxy.h
src/vulkan/VulkanBufferProxy.cpp
src/vulkan/VulkanCommands.cpp
src/vulkan/VulkanCommands.h
src/vulkan/VulkanConstants.h
@@ -257,35 +254,16 @@ if (FILAMENT_SUPPORTS_WEBGPU)
list(APPEND SRCS
include/backend/platforms/WebGPUPlatform.h
src/webgpu/platform/WebGPUPlatform.cpp
src/webgpu/WebGPUBufferBase.cpp
src/webgpu/WebGPUBufferBase.h
src/webgpu/WebGPUBufferObject.cpp
src/webgpu/WebGPUBufferObject.h
src/webgpu/WebGPUConstants.h
src/webgpu/WebGPUDescriptorSet.cpp
src/webgpu/WebGPUDescriptorSet.h
src/webgpu/WebGPUDescriptorSetLayout.cpp
src/webgpu/WebGPUDescriptorSetLayout.h
src/webgpu/WebGPUDriver.cpp
src/webgpu/WebGPUDriver.h
src/webgpu/WebGPUIndexBuffer.cpp
src/webgpu/WebGPUIndexBuffer.h
src/webgpu/WebGPUHandles.cpp
src/webgpu/WebGPUHandles.h
src/webgpu/WebGPUPipelineCreation.cpp
src/webgpu/WebGPUPipelineCreation.h
src/webgpu/WebGPUProgram.cpp
src/webgpu/WebGPUProgram.h
src/webgpu/WebGPURenderPrimitive.h
src/webgpu/WebGPURenderTarget.cpp
src/webgpu/WebGPURenderTarget.h
src/webgpu/WebGPUStrings.h
src/webgpu/WebGPUSwapChain.cpp
src/webgpu/WebGPUSwapChain.h
src/webgpu/WebGPUTexture.cpp
src/webgpu/WebGPUTexture.h
src/webgpu/WebGPUVertexBuffer.cpp
src/webgpu/WebGPUVertexBuffer.h
src/webgpu/WebGPUVertexBufferInfo.cpp
src/webgpu/WebGPUVertexBufferInfo.h
src/webgpu/WGPUProgram.cpp
)
if (WIN32)
list(APPEND SRCS src/webgpu/platform/WebGPUPlatformWindows.cpp)
@@ -403,10 +381,6 @@ endif()
target_link_libraries(${TARGET} PUBLIC math)
target_link_libraries(${TARGET} PUBLIC utils)
if (FILAMENT_USE_ABSEIL_LOGGING)
target_link_libraries(${TARGET} PRIVATE absl::log)
endif()
# Android, iOS, and WebGL do not use bluegl.
if(FILAMENT_SUPPORTS_OPENGL AND NOT IOS AND NOT ANDROID AND NOT WEBGL)
target_link_libraries(${TARGET} PRIVATE bluegl)
@@ -204,15 +204,23 @@ public:
}, new T(std::forward<T>(functor))
};
}
// --------------------------------------------------------------------------------------------
/**
* Computes the size in bytes for a pixel of given dimensions and format
* 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
* @return The size of the specified pixel in bytes
* @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);
static constexpr size_t computePixelSize(PixelDataFormat format, PixelDataType type) noexcept {
if (type == PixelDataType::COMPRESSED) {
return 0;
}
@@ -234,7 +242,7 @@ public:
case PixelDataFormat::RGB_INTEGER:
n = 3;
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_INTEGER:
n = 4;
@@ -243,7 +251,7 @@ public:
size_t bpp = n;
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::BYTE:
// nothing to do
@@ -274,35 +282,16 @@ public:
bpp = 2;
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 bprAligned = (bpr + (alignment - 1)) & (~alignment + 1);
return bprAligned * height;
}
//! left coordinate in pixels
uint32_t left = 0;
uint32_t left = 0;
//! top coordinate in pixels
uint32_t top = 0;
uint32_t top = 0;
union {
struct {
//! stride in pixels
+1 -4
View File
@@ -20,7 +20,6 @@
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Invocable.h>
#include <utils/bitset.h>
#include <backend/DriverEnums.h>
@@ -67,7 +66,6 @@ public:
using DescriptorBindingsInfo = utils::FixedCapacityVector<Descriptor>;
using DescriptorSetInfo = std::array<DescriptorBindingsInfo, MAX_DESCRIPTOR_SET_COUNT>;
using SpecializationConstantsInfo = utils::FixedCapacityVector<SpecializationConstant>;
using MutableSpecConstantsInfo = utils::bitset8;
using ShaderBlob = utils::FixedCapacityVector<uint8_t>;
using ShaderSource = std::array<ShaderBlob, SHADER_TYPE_COUNT>;
@@ -104,8 +102,7 @@ public:
Program& descriptorBindings(backend::descriptor_set_t set,
DescriptorBindingsInfo descriptorBindings) noexcept;
Program& specializationConstants(SpecializationConstantsInfo specConstants,
uint32_t firstMutableId, MutableSpecConstantsInfo mutableSpecConstants) noexcept;
Program& specializationConstants(SpecializationConstantsInfo specConstants) noexcept;
struct PushConstant {
utils::CString name;
@@ -199,7 +199,7 @@ public:
*/
virtual bool makeCurrent(ContextType type,
SwapChain* UTILS_NONNULL drawSwapChain,
SwapChain* UTILS_NONNULL readSwapChain) = 0;
SwapChain* UTILS_NONNULL readSwapChain) noexcept = 0;
/**
* Called by the driver to make the OpenGL context active on the calling thread and bind
@@ -219,7 +219,7 @@ public:
SwapChain* UTILS_NONNULL drawSwapChain,
SwapChain* UTILS_NONNULL readSwapChain,
utils::Invocable<void()> preContextChange,
utils::Invocable<void(size_t index)> postContextChange);
utils::Invocable<void(size_t index)> postContextChange) noexcept;
/**
* Called by the backend just before calling commit()
@@ -58,7 +58,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImageTexture(ExternalTexture* texture) noexcept override;
@@ -55,7 +55,7 @@ public:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
ExternalTexture* createExternalImageTexture() noexcept override;
@@ -109,11 +109,11 @@ protected:
bool makeCurrent(ContextType type,
SwapChain* drawSwapChain,
SwapChain* readSwapChain) override;
SwapChain* readSwapChain) noexcept override;
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
utils::Invocable<void()> preContextChange,
utils::Invocable<void(size_t index)> postContextChange) override;
utils::Invocable<void(size_t index)> postContextChange) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
@@ -128,7 +128,7 @@ protected:
bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override;
/**
* Logs glGetError() to LOG(ERROR)
* Logs glGetError() to slog.e
* @param name a string giving some context on the error. Typically __func__.
*/
static void logEglError(const char* name) noexcept;
@@ -148,12 +148,12 @@ protected:
EGLContext getContextForType(ContextType type) const noexcept;
// makes the draw and read surface current without changing the current context
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) {
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept {
return egl.makeCurrent(drawSurface, readSurface);
}
// makes context current and set draw and read surfaces to EGL_NO_SURFACE
EGLBoolean makeCurrent(EGLContext context) {
EGLBoolean makeCurrent(EGLContext context) noexcept {
return egl.makeCurrent(context, mEGLDummySurface, mEGLDummySurface);
}
@@ -211,9 +211,9 @@ private:
public:
explicit EGL(EGLDisplay& dpy) : mEGLDisplay(dpy) {}
EGLBoolean makeCurrent(EGLContext context,
EGLSurface drawSurface, EGLSurface readSurface);
EGLSurface drawSurface, EGLSurface readSurface) noexcept;
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) {
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept {
return makeCurrent(mCurrentContext, drawSurface, readSurface);
}
} egl{ mEGLDisplay };
@@ -127,7 +127,7 @@ protected:
protected:
bool makeCurrent(ContextType type,
SwapChain* drawSwapChain,
SwapChain* readSwapChain) override;
SwapChain* readSwapChain) noexcept override;
private:
struct InitializeJvmForPerformanceManagerIfNeeded {
@@ -51,7 +51,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
private:
@@ -56,7 +56,7 @@ protected:
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) override;
SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
private:
@@ -53,7 +53,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
protected:
@@ -46,7 +46,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
};
@@ -22,7 +22,6 @@
#include <webgpu/webgpu_cpp.h>
#include <cstdint>
#include <vector>
namespace filament::backend {
@@ -57,10 +56,6 @@ protected:
const Platform::DriverConfig& driverConfig) noexcept override;
private:
// returns adapter request option variations applicable for the particular
// platform
[[nodiscard]] static std::vector<wgpu::RequestAdapterOptions> getAdapterOptions();
// we may consider having the driver own this in the future
wgpu::Instance mInstance;
};
@@ -72,7 +72,7 @@ public:
Range getBuffer() noexcept;
private:
void* alloc(size_t size);
void* alloc(size_t size) noexcept;
void dealloc() noexcept;
// pointer to the beginning of the circular buffer (constant)
@@ -76,7 +76,7 @@ public:
// all commands buffers (Slices) written to this point are returned by waitForCommand(). This
// call blocks until the CircularBuffer has at least mRequiredSize bytes available.
void flush();
void flush() noexcept;
// returns from waitForCommands() immediately.
void requestExit();
@@ -39,7 +39,7 @@
#define FILAMENT_DEBUG_COMMANDS_NONE 0x0
// Command debugging enabled. No logging by default.
#define FILAMENT_DEBUG_COMMANDS_ENABLE 0x1
// Command debugging enabled. Every command logged to DLOG(INFO)
// Command debugging enabled. Every command logged to slog.d
#define FILAMENT_DEBUG_COMMANDS_LOG 0x2
// Command debugging enabled. Every command logged to systrace
#define FILAMENT_DEBUG_COMMANDS_SYSTRACE 0x4
@@ -27,13 +27,13 @@ namespace filament {
class VirtualMachineEnv {
public:
// must be called before VirtualMachineEnv::get() from a thread that is attached to the JavaVM
static jint JNI_OnLoad(JavaVM* vm);
static jint JNI_OnLoad(JavaVM* vm) noexcept;
// must be called on backend thread
static VirtualMachineEnv& get() noexcept;
// can be called from any thread that already has a JniEnv
static JNIEnv* getThreadEnvironment();
static JNIEnv* getThreadEnvironment() noexcept;
// must be called from the backend thread
JNIEnv* getEnvironment() noexcept {
@@ -49,7 +49,7 @@ public:
private:
explicit VirtualMachineEnv(JavaVM* vm) noexcept;
~VirtualMachineEnv() noexcept;
JNIEnv* getEnvironmentSlow();
JNIEnv* getEnvironmentSlow() noexcept;
static utils::Mutex sLock;
static JavaVM* sVirtualMachine;
+3 -3
View File
@@ -16,7 +16,7 @@
#include "private/backend/CircularBuffer.h"
#include <utils/Logger.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/architecture.h>
#include <utils/ashmem.h>
@@ -65,7 +65,7 @@ CircularBuffer::~CircularBuffer() noexcept {
// to each others and a special case in circularize()
UTILS_NOINLINE
void* CircularBuffer::alloc(size_t size) {
void* CircularBuffer::alloc(size_t size) noexcept {
#if HAS_MMAP
void* data = nullptr;
void* vaddr = MAP_FAILED;
@@ -127,7 +127,7 @@ void* CircularBuffer::alloc(size_t size) {
"couldn't allocate " << (size * 2 / 1024) <<
" KiB of virtual address space for the command buffer";
LOG(WARNING) << "Using 'soft' CircularBuffer (" << (size * 2 / 1024) << " KiB)";
slog.w << "Using 'soft' CircularBuffer (" << (size * 2 / 1024) << " KiB)" << io::endl;
// guard page at the end
void* guard = (void*)(uintptr_t(data) + size * 2);
+18 -17
View File
@@ -20,12 +20,12 @@
#include <private/utils/Tracing.h>
#include <utils/Logger.h>
#include <utils/Mutex.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
#include <utils/ostream.h>
#include <utils/Panic.h>
#include <utils/debug.h>
#include <algorithm>
#include <mutex>
@@ -53,18 +53,18 @@ CommandBufferQueue::~CommandBufferQueue() {
}
void CommandBufferQueue::requestExit() {
std::lock_guard const lock(mLock);
std::lock_guard<utils::Mutex> const lock(mLock);
mExitRequested = EXIT_REQUESTED;
mCondition.notify_one();
}
bool CommandBufferQueue::isPaused() const noexcept {
std::lock_guard const lock(mLock);
std::lock_guard<utils::Mutex> const lock(mLock);
return mPaused;
}
void CommandBufferQueue::setPaused(bool paused) {
std::lock_guard const lock(mLock);
std::lock_guard<utils::Mutex> const lock(mLock);
if (paused) {
mPaused = true;
} else {
@@ -74,12 +74,12 @@ void CommandBufferQueue::setPaused(bool paused) {
}
bool CommandBufferQueue::isExitRequested() const {
std::lock_guard const lock(mLock);
return bool(mExitRequested);
std::lock_guard<utils::Mutex> const lock(mLock);
return (bool)mExitRequested;
}
void CommandBufferQueue::flush() {
void CommandBufferQueue::flush() noexcept {
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
CircularBuffer& circularBuffer = mCircularBuffer;
@@ -103,7 +103,7 @@ void CommandBufferQueue::flush() {
static_cast<char const*>(begin), static_cast<char const*>(end));
std::unique_lock lock(mLock);
std::unique_lock<utils::Mutex> lock(mLock);
// circular buffer is too small, we corrupted the stream
FILAMENT_CHECK_POSTCONDITION(used <= mFreeSpace) <<
@@ -121,10 +121,11 @@ void CommandBufferQueue::flush() {
#ifndef NDEBUG
size_t const totalUsed = circularBuffer.size() - mFreeSpace;
DLOG(INFO) << "CommandStream used too much space (will block): "
<< "needed space " << requiredSize << " out of " << mFreeSpace
<< ", totalUsed=" << totalUsed << ", current=" << used
<< ", queue size=" << mCommandBuffersToExecute.size() << " buffers";
slog.d << "CommandStream used too much space (will block): "
<< "needed space " << requiredSize << " out of " << mFreeSpace
<< ", totalUsed=" << totalUsed << ", current=" << used
<< ", queue size=" << mCommandBuffersToExecute.size() << " buffers"
<< io::endl;
mHighWatermark = std::max(mHighWatermark, totalUsed);
#endif
@@ -146,7 +147,7 @@ std::vector<CommandBufferQueue::Range> CommandBufferQueue::waitForCommands() con
if (!UTILS_HAS_THREADING) {
return std::move(mCommandBuffersToExecute);
}
std::unique_lock lock(mLock);
std::unique_lock<utils::Mutex> lock(mLock);
while ((mCommandBuffersToExecute.empty() || mPaused) && !mExitRequested) {
mCondition.wait(lock);
}
@@ -156,7 +157,7 @@ std::vector<CommandBufferQueue::Range> CommandBufferQueue::waitForCommands() con
void CommandBufferQueue::releaseBuffer(CommandBufferQueue::Range const& buffer) {
size_t const used = std::distance(
static_cast<char const*>(buffer.begin), static_cast<char const*>(buffer.end));
std::lock_guard const lock(mLock);
std::lock_guard<utils::Mutex> const lock(mLock);
mFreeSpace += used;
mCondition.notify_one();
}
+5 -9
View File
@@ -22,13 +22,10 @@
#include <utils/CallStack.h>
#endif
#include <private/utils/Tracing.h>
#include <utils/Logger.h>
#include <utils/Profiler.h>
#include <utils/compiler.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <utils/sstream.h>
#include <utils/Profiler.h>
#include <cstddef>
#include <functional>
@@ -132,10 +129,9 @@ void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log(std::index_seq
#if DEBUG_COMMAND_STREAM
static_assert(UTILS_HAS_RTTI, "DEBUG_COMMAND_STREAM can only be used with RTTI");
std::string command = utils::CallStack::demangleTypeName(typeid(Command).name()).c_str();
DLOG(INFO) << extractMethodName(command) << " : size=" << sizeof(Command);
utils::io::sstream parameterPack;
printParameterPack(parameterPack, std::get<I>(mArgs)...);
DLOG(INFO) << "\t" << parameterPack.c_str();
slog.d << extractMethodName(command) << " : size=" << sizeof(Command) << "\n\t";
printParameterPack(slog.d, std::get<I>(mArgs)...);
slog.d << io::endl;
#endif
}
+2 -2
View File
@@ -25,9 +25,9 @@
#include <private/utils/Tracing.h>
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <math/half.h>
@@ -149,7 +149,7 @@ void DriverBase::scheduleRelease(AcquiredImage const& image) noexcept {
void DriverBase::debugCommandBegin(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_LOG)) {
DLOG(INFO) << methodName;
utils::slog.d << methodName << utils::io::endl;
}
if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
+3 -3
View File
@@ -20,7 +20,7 @@
#include <utils/Allocator.h>
#include <utils/CString.h>
#include <utils/Logger.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/debug.h>
@@ -57,8 +57,8 @@ HandleAllocator<P0, P1, P2>::Allocator::Allocator(AreaPolicy::HeapArea const& ar
size_t const maxHeapSize = std::min(area.size(), HANDLE_INDEX_MASK * getAlignment());
if (UTILS_UNLIKELY(maxHeapSize != area.size())) {
LOG(WARNING) << "HandleAllocator heap size reduced to " << maxHeapSize << " from "
<< area.size();
slog.w << "HandleAllocator heap size reduced to "
<< maxHeapSize << " from " << area.size() << io::endl;
}
// make sure we start with a clean arena. This is needed to ensure that all blocks start
+1 -11
View File
@@ -80,18 +80,8 @@ Program& Program::attributes(AttributesInfo attributes) noexcept {
return *this;
}
Program& Program::specializationConstants(SpecializationConstantsInfo specConstants,
uint32_t firstMutableId, MutableSpecConstantsInfo mutableSpecConstants) noexcept {
// String the two lists together.
Program& Program::specializationConstants(SpecializationConstantsInfo specConstants) noexcept {
mSpecializationConstants = std::move(specConstants);
uint32_t firstMutableIndex = specConstants.size();
mSpecializationConstants.reserve(specConstants.size() + mutableSpecConstants.size());
for (uint32_t i = 0; i < mutableSpecConstants.size(); i++) {
mSpecializationConstants[i + firstMutableIndex] = SpecializationConstant {
.id = i + firstMutableId,
.value = mutableSpecConstants[i],
};
}
return *this;
}
+3 -3
View File
@@ -50,7 +50,7 @@ JavaVM* VirtualMachineEnv::getVirtualMachine() {
*/
UTILS_PUBLIC
UTILS_NOINLINE
jint VirtualMachineEnv::JNI_OnLoad(JavaVM* vm) {
jint VirtualMachineEnv::JNI_OnLoad(JavaVM* vm) noexcept {
std::lock_guard const lock(sLock);
if (sVirtualMachine) {
// It doesn't make sense for JNI_OnLoad() to be called more than once
@@ -77,7 +77,7 @@ VirtualMachineEnv& VirtualMachineEnv::get() noexcept {
}
UTILS_NOINLINE
JNIEnv* VirtualMachineEnv::getThreadEnvironment() {
JNIEnv* VirtualMachineEnv::getThreadEnvironment() noexcept {
JavaVM* const vm = getVirtualMachine();
JNIEnv* env = nullptr;
jint const result = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
@@ -101,7 +101,7 @@ VirtualMachineEnv::~VirtualMachineEnv() noexcept {
}
UTILS_NOINLINE
JNIEnv* VirtualMachineEnv::getEnvironmentSlow() {
JNIEnv* VirtualMachineEnv::getEnvironmentSlow() noexcept {
FILAMENT_CHECK_PRECONDITION(mVirtualMachine)
<< "JNI_OnLoad() has not been called";
+3 -3
View File
@@ -19,8 +19,8 @@
#include "MetalContext.h"
#include "MetalUtils.h"
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/Log.h>
namespace filament::backend {
@@ -323,7 +323,7 @@ id<MTLFunction> MetalBlitter::compileFragmentFunction(BlitFunctionKey key) const
if (!library || !function) {
if (error) {
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
LOG(ERROR) << description;
utils::slog.e << description << utils::io::endl;
}
}
FILAMENT_CHECK_POSTCONDITION(library && function)
@@ -349,7 +349,7 @@ id<MTLFunction> MetalBlitter::getBlitVertexFunction() {
if (!library || !function) {
if (error) {
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
LOG(ERROR) << description;
utils::slog.e << description << utils::io::endl;
}
}
FILAMENT_CHECK_POSTCONDITION(library && function)
@@ -18,8 +18,8 @@
#include "MetalContext.h"
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/Log.h>
#include <utils/trap.h>
#include <thread>
@@ -77,7 +77,8 @@ void MetalBufferPool::releaseBuffer(MetalBufferPoolEntry const *stage) noexcept
auto iter = mUsedStages.find(stage);
if (iter == mUsedStages.end()) {
LOG(ERROR) << "Unknown Metal buffer: " << stage->capacity << " bytes";
utils::slog.e << "Unknown Metal buffer: " << stage->capacity << " bytes"
<< utils::io::endl;
return;
}
stage->lastAccessed = mCurrentFrame;
+3 -4
View File
@@ -18,9 +18,8 @@
#include "MetalHandles.h"
#include <utils/FixedCapacityVector.h>
#include <utils/Logger.h>
#include <utils/debug.h>
#include <utils/FixedCapacityVector.h>
#include <utility>
@@ -113,8 +112,8 @@ id<MTLCommandBuffer> getPendingCommandBuffer(MetalContext* context) {
auto errorCode = (MTLCommandBufferError)buffer.error.code;
if (@available(macOS 11.0, *)) {
if (errorCode == MTLCommandBufferErrorMemoryless) {
LOG(WARNING) << "Metal: memoryless geometry limit reached. Continuing with private "
"storage mode.";
utils::slog.w << "Metal: memoryless geometry limit reached. "
"Continuing with private storage mode." << utils::io::endl;
context->memorylessLimitsReached = true;
}
}
+25 -22
View File
@@ -38,10 +38,10 @@
#include <Metal/Metal.h>
#include <QuartzCore/QuartzCore.h>
#include <utils/Invocable.h>
#include <utils/Logger.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/sstream.h>
#include <utils/Invocable.h>
#include <algorithm>
@@ -78,18 +78,20 @@ Driver* MetalDriverFactory::create(PlatformMetal* const platform, const Platform
// MetalVertexBufferInfo : 552 moderate
// -- less than or equal to 552 bytes
DLOG(INFO) << "MetalSwapChain: " << sizeof(MetalSwapChain);
DLOG(INFO) << "MetalBufferObject: " << sizeof(MetalBufferObject);
DLOG(INFO) << "MetalVertexBuffer: " << sizeof(MetalVertexBuffer);
DLOG(INFO) << "MetalVertexBufferInfo: " << sizeof(MetalVertexBufferInfo);
DLOG(INFO) << "MetalIndexBuffer: " << sizeof(MetalIndexBuffer);
DLOG(INFO) << "MetalRenderPrimitive: " << sizeof(MetalRenderPrimitive);
DLOG(INFO) << "MetalTexture: " << sizeof(MetalTexture);
DLOG(INFO) << "MetalTimerQuery: " << sizeof(MetalTimerQuery);
DLOG(INFO) << "HwStream: " << sizeof(HwStream);
DLOG(INFO) << "MetalRenderTarget: " << sizeof(MetalRenderTarget);
DLOG(INFO) << "MetalFence: " << sizeof(MetalFence);
DLOG(INFO) << "MetalProgram: " << sizeof(MetalProgram);
utils::slog.d
<< "\nMetalSwapChain: " << sizeof(MetalSwapChain)
<< "\nMetalBufferObject: " << sizeof(MetalBufferObject)
<< "\nMetalVertexBuffer: " << sizeof(MetalVertexBuffer)
<< "\nMetalVertexBufferInfo: " << sizeof(MetalVertexBufferInfo)
<< "\nMetalIndexBuffer: " << sizeof(MetalIndexBuffer)
<< "\nMetalRenderPrimitive: " << sizeof(MetalRenderPrimitive)
<< "\nMetalTexture: " << sizeof(MetalTexture)
<< "\nMetalTimerQuery: " << sizeof(MetalTimerQuery)
<< "\nHwStream: " << sizeof(HwStream)
<< "\nMetalRenderTarget: " << sizeof(MetalRenderTarget)
<< "\nMetalFence: " << sizeof(MetalFence)
<< "\nMetalProgram: " << sizeof(MetalProgram)
<< utils::io::endl;
#endif
return MetalDriver::create(platform, driverConfig);
}
@@ -133,18 +135,19 @@ MetalDriver::MetalDriver(
initializeSupportedGpuFamilies(mContext);
LOG(INFO) << "Supported GPU families: ";
utils::slog.v << "Supported GPU families: " << utils::io::endl;
if (mContext->highestSupportedGpuFamily.common > 0) {
LOG(INFO) << " MTLGPUFamilyCommon" << (int) mContext->highestSupportedGpuFamily.common;
utils::slog.v << " MTLGPUFamilyCommon" << (int) mContext->highestSupportedGpuFamily.common << utils::io::endl;
}
if (mContext->highestSupportedGpuFamily.apple > 0) {
LOG(INFO) << " MTLGPUFamilyApple" << (int) mContext->highestSupportedGpuFamily.apple;
utils::slog.v << " MTLGPUFamilyApple" << (int) mContext->highestSupportedGpuFamily.apple << utils::io::endl;
}
if (mContext->highestSupportedGpuFamily.mac > 0) {
LOG(INFO) << " MTLGPUFamilyMac" << (int) mContext->highestSupportedGpuFamily.mac;
utils::slog.v << " MTLGPUFamilyMac" << (int) mContext->highestSupportedGpuFamily.mac << utils::io::endl;
}
LOG(INFO) << "Features:";
LOG(INFO) << " readWriteTextureSupport: " << (bool) mContext->device.readWriteTextureSupport;
utils::slog.v << "Features:" << utils::io::endl;
utils::slog.v << " readWriteTextureSupport: " <<
(bool) mContext->device.readWriteTextureSupport << utils::io::endl;
// In order to support texture swizzling, the GPU needs to support it and the system be running
// iOS 13+.
@@ -585,7 +588,7 @@ void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
#if FILAMENT_METAL_DEBUG_LOG
auto handleId = rph.getId();
DEBUG_LOG("createProgramR(rph = %d, program = ", handleId);
DLOG(INFO) << program;
utils::slog.d << program << utils::io::endl;
#endif
construct_handle<MetalProgram>(rph, *mContext, std::move(program));
}
@@ -2074,7 +2077,7 @@ void MetalDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGro
error:&error];
if (error) {
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
LOG(ERROR) << description;
utils::slog.e << description << utils::io::endl;
}
assert_invariant(!error);
@@ -20,14 +20,14 @@
#include "MetalEnums.h"
#include "MetalUtils.h"
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/Log.h>
#include <utils/trap.h>
#define NSERROR_CHECK(message) \
if (error) { \
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding]; \
LOG(ERROR) << description; \
utils::slog.e << description << utils::io::endl; \
} \
FILAMENT_CHECK_POSTCONDITION(error == nil) << message;
+8 -9
View File
@@ -27,11 +27,10 @@
#include "private/backend/BackendUtils.h"
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Panic.h>
#include <utils/trap.h>
#include <utils/debug.h>
#include <math/scalar.h>
@@ -116,14 +115,14 @@ MetalSwapChain::MetalSwapChain(
type(SwapChainType::CAMETALLAYER) {
if (!(flags & SwapChain::CONFIG_TRANSPARENT) && !nativeWindow.opaque) {
LOG(WARNING) << "Warning: Filament SwapChain has no CONFIG_TRANSPARENT flag, but the "
"CAMetaLayer("
<< (__bridge void*) nativeWindow << ") has .opaque set to NO.";
utils::slog.w << "Warning: Filament SwapChain has no CONFIG_TRANSPARENT flag, "
"but the CAMetaLayer(" << (__bridge void*) nativeWindow << ")"
" has .opaque set to NO." << utils::io::endl;
}
if ((flags & SwapChain::CONFIG_TRANSPARENT) && nativeWindow.opaque) {
LOG(WARNING) << "Warning: Filament SwapChain has the CONFIG_TRANSPARENT flag, but the "
"CAMetaLayer("
<< (__bridge void*) nativeWindow << ") has .opaque set to YES.";
utils::slog.w << "Warning: Filament SwapChain has the CONFIG_TRANSPARENT flag, "
"but the CAMetaLayer(" << (__bridge void*) nativeWindow << ")"
" has .opaque set to YES." << utils::io::endl;
}
// Needed so we can use the SwapChain as a blit source.
@@ -21,7 +21,6 @@
#include <backend/Program.h>
#include <utils/JobSystem.h>
#include <utils/Logger.h>
#include <utils/Mutex.h>
#include <chrono>
@@ -148,7 +147,7 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept {
if (error) {
auto description =
[error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
LOG(WARNING) << description;
utils::slog.w << description << utils::io::endl;
errorMessage = error.localizedDescription;
}
PANIC_LOG("Failed to compile Metal program.");
@@ -179,7 +178,7 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept {
if (error) {
auto description =
[error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
LOG(WARNING) << description;
utils::slog.w << description << utils::io::endl;
errorMessage = error.localizedDescription;
}
PANIC_LOG("Failed to load main0 in Metal program.");
+3 -3
View File
@@ -18,7 +18,7 @@
#include "MetalEnums.h"
#include <utils/Logger.h>
#include <utils/Log.h>
namespace filament {
namespace backend {
@@ -95,7 +95,7 @@ id<MTLRenderPipelineState> PipelineStateCreator::operator()(id<MTLDevice> device
[NSString stringWithFormat:@"Could not create Metal pipeline state: %@",
error ? error.localizedDescription : @"unknown error"];
auto description = [errorMessage cStringUsingEncoding:NSUTF8StringEncoding];
LOG(ERROR) << description;
utils::slog.e << description << utils::io::endl;
[[NSException exceptionWithName:@"MetalRenderPipelineFailure"
reason:errorMessage
userInfo:nil] raise];
@@ -155,7 +155,7 @@ id<MTLSamplerState> SamplerStateCreator::operator()(id<MTLDevice> device,
// MTLSamplerDescriptor.
// In practice, this means shadows are not supported when running in the simulator.
if (![device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
LOG(WARNING) << "Warning: sample comparison not supported by this GPU";
utils::slog.w << "Warning: sample comparison not supported by this GPU" << utils::io::endl;
samplerDescriptor.compareFunction = MTLCompareFunctionNever;
}
#endif
+4 -3
View File
@@ -19,7 +19,7 @@
#include "MetalDriverFactory.h"
#include <utils/Logger.h>
#include <utils/Log.h>
#import <Foundation/Foundation.h>
@@ -129,8 +129,9 @@ void PlatformMetalImpl::createDeviceImpl(MetalDevice& outDevice) {
result = MTLCreateSystemDefaultDevice();
}
LOG(INFO) << "Selected physical device '"
<< [result.name cStringUsingEncoding:NSUTF8StringEncoding] << "'";
utils::slog.i << "Selected physical device '"
<< [result.name cStringUsingEncoding:NSUTF8StringEncoding] << "'"
<< utils::io::endl;
outDevice.device = result;
mDevice = result;
+45 -45
View File
@@ -162,11 +162,8 @@ void GLDescriptorSet::update(OpenGLContext&,
}, descriptors[binding].desc);
}
void GLDescriptorSet::update(OpenGLContext& gl, HandleAllocatorGL& handleAllocator,
descriptor_binding_t binding, TextureHandle th, SamplerParams params) noexcept {
GLTexture* t = th ? handleAllocator.handle_cast<GLTexture*>(th) : nullptr;
void GLDescriptorSet::update(OpenGLContext& gl,
descriptor_binding_t binding, GLTexture* t, SamplerParams params) noexcept {
assert_invariant(binding < descriptors.size());
std::visit([=, &gl](auto&& arg) mutable {
using T = std::decay_t<decltype(arg)>;
@@ -199,12 +196,20 @@ void GLDescriptorSet::update(OpenGLContext& gl, HandleAllocatorGL& handleAllocat
}
}
arg.handle = th;
arg.target = t ? t->gl.target : 0;
arg.id = t ? t->gl.id : 0;
arg.external = t ? t->gl.external : false;
if constexpr (std::is_same_v<T, Sampler> ||
std::is_same_v<T, SamplerWithAnisotropyWorkaround>) {
if constexpr (std::is_same_v<T, SamplerWithAnisotropyWorkaround>) {
arg.anisotropy = float(1u << params.anisotropyLog2);
}
if (t) {
arg.ref = t->ref;
arg.baseLevel = t->gl.baseLevel;
arg.maxLevel = t->gl.maxLevel;
arg.swizzle = t->gl.swizzle;
}
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
arg.sampler = gl.getSampler(params);
#else
@@ -220,39 +225,39 @@ void GLDescriptorSet::update(OpenGLContext& gl, HandleAllocatorGL& handleAllocat
}, descriptors[binding].desc);
}
template<typename T>
void GLDescriptorSet::updateTextureView(OpenGLContext& gl,
HandleAllocatorGL& handleAllocator, GLuint unit, GLTexture const* t) noexcept {
HandleAllocatorGL& handleAllocator, GLuint unit, T const& desc) noexcept {
// The common case is that we don't have a ref handle (we only have one if
// the texture ever had a View on it).
assert_invariant(t);
assert_invariant(t->ref);
GLTextureRef* const ref = handleAllocator.handle_cast<GLTextureRef*>(t->ref);
if (UTILS_UNLIKELY((t->gl.baseLevel != ref->baseLevel || t->gl.maxLevel != ref->maxLevel))) {
assert_invariant(desc.ref);
GLTextureRef* const ref = handleAllocator.handle_cast<GLTextureRef*>(desc.ref);
if (UTILS_UNLIKELY((desc.baseLevel != ref->baseLevel || desc.maxLevel != ref->maxLevel))) {
// If we have views, then it's still uncommon that we'll switch often
// handle the case where we reset to the original texture
GLint baseLevel = GLint(t->gl.baseLevel); // NOLINT(*-signed-char-misuse)
GLint maxLevel = GLint(t->gl.maxLevel); // NOLINT(*-signed-char-misuse)
GLint baseLevel = GLint(desc.baseLevel); // NOLINT(*-signed-char-misuse)
GLint maxLevel = GLint(desc.maxLevel); // NOLINT(*-signed-char-misuse)
if (baseLevel > maxLevel) {
baseLevel = 0;
maxLevel = 1000; // per OpenGL spec
}
// that is very unfortunate that we have to call activeTexture here
gl.activeTexture(unit);
glTexParameteri(t->gl.target, GL_TEXTURE_BASE_LEVEL, baseLevel);
glTexParameteri(t->gl.target, GL_TEXTURE_MAX_LEVEL, maxLevel);
ref->baseLevel = t->gl.baseLevel;
ref->maxLevel = t->gl.maxLevel;
glTexParameteri(desc.target, GL_TEXTURE_BASE_LEVEL, baseLevel);
glTexParameteri(desc.target, GL_TEXTURE_MAX_LEVEL, maxLevel);
ref->baseLevel = desc.baseLevel;
ref->maxLevel = desc.maxLevel;
}
if (UTILS_UNLIKELY(t->gl.swizzle != ref->swizzle)) {
if (UTILS_UNLIKELY(desc.swizzle != ref->swizzle)) {
using namespace GLUtils;
gl.activeTexture(unit);
#if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
glTexParameteri(t->gl.target, GL_TEXTURE_SWIZZLE_R, (GLint)getSwizzleChannel(t->gl.swizzle[0]));
glTexParameteri(t->gl.target, GL_TEXTURE_SWIZZLE_G, (GLint)getSwizzleChannel(t->gl.swizzle[1]));
glTexParameteri(t->gl.target, GL_TEXTURE_SWIZZLE_B, (GLint)getSwizzleChannel(t->gl.swizzle[2]));
glTexParameteri(t->gl.target, GL_TEXTURE_SWIZZLE_A, (GLint)getSwizzleChannel(t->gl.swizzle[3]));
glTexParameteri(desc.target, GL_TEXTURE_SWIZZLE_R, (GLint)getSwizzleChannel(desc.swizzle[0]));
glTexParameteri(desc.target, GL_TEXTURE_SWIZZLE_G, (GLint)getSwizzleChannel(desc.swizzle[1]));
glTexParameteri(desc.target, GL_TEXTURE_SWIZZLE_B, (GLint)getSwizzleChannel(desc.swizzle[2]));
glTexParameteri(desc.target, GL_TEXTURE_SWIZZLE_A, (GLint)getSwizzleChannel(desc.swizzle[3]));
#endif
ref->swizzle = t->gl.swizzle;
ref->swizzle = desc.swizzle;
}
}
@@ -305,31 +310,27 @@ void GLDescriptorSet::bind(
}
} else if constexpr (std::is_same_v<T, Sampler>) {
GLuint const unit = p.getTextureUnit(set, binding);
if (arg.handle) {
GLTexture const* const t = handleAllocator.handle_cast<GLTexture*>(arg.handle);
gl.bindTexture(unit, t->gl.target, t->gl.id, t->gl.external);
if (arg.target) {
gl.bindTexture(unit, arg.target, arg.id, arg.external);
gl.bindSampler(unit, arg.sampler);
if (UTILS_UNLIKELY(t->ref)) {
updateTextureView(gl, handleAllocator, unit, t);
if (UTILS_UNLIKELY(arg.ref)) {
updateTextureView(gl, handleAllocator, unit, arg);
}
} else {
gl.unbindTextureUnit(unit);
}
} else if constexpr (std::is_same_v<T, SamplerWithAnisotropyWorkaround>) {
GLuint const unit = p.getTextureUnit(set, binding);
if (arg.handle) {
GLTexture const* const t = handleAllocator.handle_cast<GLTexture*>(arg.handle);
gl.bindTexture(unit, t->gl.target, t->gl.id, t->gl.external);
if (arg.target) {
gl.bindTexture(unit, arg.target, arg.id, arg.external);
gl.bindSampler(unit, arg.sampler);
if (UTILS_UNLIKELY(t->ref)) {
updateTextureView(gl, handleAllocator, unit, t);
if (UTILS_UNLIKELY(arg.ref)) {
updateTextureView(gl, handleAllocator, unit, arg);
}
#if defined(GL_EXT_texture_filter_anisotropic)
// Driver claims to support anisotropic filtering, but it fails when set on
// the sampler, we have to set it on the texture instead.
glTexParameterf(t->gl.target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
glTexParameterf(arg.target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
std::min(gl.gets.max_anisotropy, float(arg.anisotropy)));
#endif
} else {
@@ -338,20 +339,19 @@ void GLDescriptorSet::bind(
} else if constexpr (std::is_same_v<T, SamplerGLES2>) {
// in ES2 the sampler parameters need to be set on the texture itself
GLuint const unit = p.getTextureUnit(set, binding);
if (arg.handle) {
GLTexture const* const t = handleAllocator.handle_cast<GLTexture*>(arg.handle);
gl.bindTexture(unit, t->gl.target, t->gl.id, t->gl.external);
if (arg.target) {
gl.bindTexture(unit, arg.target, arg.id, arg.external);
SamplerParams const params = arg.params;
glTexParameteri(t->gl.target, GL_TEXTURE_MIN_FILTER,
glTexParameteri(arg.target, GL_TEXTURE_MIN_FILTER,
(GLint)GLUtils::getTextureFilter(params.filterMin));
glTexParameteri(t->gl.target, GL_TEXTURE_MAG_FILTER,
glTexParameteri(arg.target, GL_TEXTURE_MAG_FILTER,
(GLint)GLUtils::getTextureFilter(params.filterMag));
glTexParameteri(t->gl.target, GL_TEXTURE_WRAP_S,
glTexParameteri(arg.target, GL_TEXTURE_WRAP_S,
(GLint)GLUtils::getWrapMode(params.wrapS));
glTexParameteri(t->gl.target, GL_TEXTURE_WRAP_T,
glTexParameteri(arg.target, GL_TEXTURE_WRAP_T,
(GLint)GLUtils::getWrapMode(params.wrapT));
#if defined(GL_EXT_texture_filter_anisotropic)
glTexParameterf(t->gl.target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
glTexParameterf(arg.target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
std::min(gl.gets.max_anisotropy, arg.anisotropy));
#endif
} else {
@@ -360,7 +360,7 @@ void GLDescriptorSet::bind(
}
}, entry.desc);
});
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void GLDescriptorSet::validate(HandleAllocatorGL& allocator,
+34 -6
View File
@@ -59,8 +59,8 @@ struct GLDescriptorSet : public HwDescriptorSet {
descriptor_binding_t binding, GLBufferObject* bo, size_t offset, size_t size) noexcept;
// update a sampler descriptor in the set
void update(OpenGLContext& gl, HandleAllocatorGL& handleAllocator,
descriptor_binding_t binding, TextureHandle th, SamplerParams params) noexcept;
void update(OpenGLContext& gl,
descriptor_binding_t binding, GLTexture* t, SamplerParams params) noexcept;
// conceptually bind the set to the command buffer
void bind(
@@ -111,19 +111,46 @@ private:
// A sampler descriptor
struct Sampler {
TextureHandle handle; // 4
uint16_t target; // 2 (GLenum)
bool external = false; // 1
bool reserved = false; // 1
GLuint id = 0; // 4
GLuint sampler = 0; // 4
Handle<GLTextureRef> ref; // 4
int8_t baseLevel = 0x7f; // 1
int8_t maxLevel = -1; // 1
std::array<TextureSwizzle, 4> swizzle{ // 4
TextureSwizzle::CHANNEL_0,
TextureSwizzle::CHANNEL_1,
TextureSwizzle::CHANNEL_2,
TextureSwizzle::CHANNEL_3
};
};
struct SamplerWithAnisotropyWorkaround {
TextureHandle handle; // 4
uint16_t target; // 2 (GLenum)
bool external = false; // 1
bool reserved = false; // 1
GLuint id = 0; // 4
GLuint sampler = 0; // 4
Handle<GLTextureRef> ref; // 4
math::half anisotropy = 1.0f; // 2
int8_t baseLevel = 0x7f; // 1
int8_t maxLevel = -1; // 1
std::array<TextureSwizzle, 4> swizzle{ // 4
TextureSwizzle::CHANNEL_0,
TextureSwizzle::CHANNEL_1,
TextureSwizzle::CHANNEL_2,
TextureSwizzle::CHANNEL_3
};
};
// A sampler descriptor for ES2
struct SamplerGLES2 {
TextureHandle handle; // 4
uint16_t target; // 2 (GLenum)
bool external = false; // 1
bool reserved = false; // 1
GLuint id = 0; // 4
SamplerParams params{}; // 4
float anisotropy = 1.0f; // 4
};
@@ -138,8 +165,9 @@ private:
};
static_assert(sizeof(Descriptor) <= 32);
template<typename T>
static void updateTextureView(OpenGLContext& gl,
HandleAllocatorGL& handleAllocator, GLuint unit, GLTexture const* t) noexcept;
HandleAllocatorGL& handleAllocator, GLuint unit, T const& desc) noexcept;
utils::FixedCapacityVector<Descriptor> descriptors; // 16
utils::bitset64 dynamicBuffers; // 8
+10 -16
View File
@@ -18,7 +18,6 @@
#include "private/backend/Driver.h"
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <utils/trap.h>
@@ -26,7 +25,6 @@
#include <string_view>
#include <stddef.h>
#include <cstdio>
namespace filament::backend {
@@ -57,21 +55,19 @@ std::string_view getGLErrorString(GLenum error) noexcept {
}
UTILS_NOINLINE
GLenum checkGLError(const char* function, size_t line) noexcept {
GLenum checkGLError(io::ostream& out, const char* function, size_t line) noexcept {
GLenum const error = glGetError();
if (UTILS_VERY_UNLIKELY(error != GL_NO_ERROR)) {
auto const string = getGLErrorString(error);
char hexError[16];
snprintf(hexError, sizeof(hexError), "%#x", error);
LOG(ERROR) << "OpenGL error " << hexError << " (" << string << ") in \"" << function
<< "\" at line " << line;
out << "OpenGL error " << io::hex << error << " (" << string << ") in \""
<< function << "\" at line " << io::dec << line << io::endl;
}
return error;
}
UTILS_NOINLINE
void assertGLError(const char* function, size_t line) noexcept {
GLenum const err = checkGLError(function, line);
void assertGLError(io::ostream& out, const char* function, size_t line) noexcept {
GLenum const err = checkGLError(out, function, line);
if (UTILS_VERY_UNLIKELY(err != GL_NO_ERROR)) {
debug_trap();
}
@@ -101,21 +97,19 @@ std::string_view getFramebufferStatusString(GLenum status) noexcept {
}
UTILS_NOINLINE
GLenum checkFramebufferStatus(GLenum target, const char* function, size_t line) noexcept {
GLenum checkFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
GLenum const status = glCheckFramebufferStatus(target);
if (UTILS_VERY_UNLIKELY(status != GL_FRAMEBUFFER_COMPLETE)) {
auto const string = getFramebufferStatusString(status);
char hexStatus[16];
snprintf(hexStatus, sizeof(hexStatus), "%#x", status);
LOG(ERROR) << "OpenGL framebuffer error " << hexStatus << " (" << string << ") in \""
<< function << "\" at line " << line;
out << "OpenGL framebuffer error " << io::hex << status << " (" << string << ") in \""
<< function << "\" at line " << io::dec << line << io::endl;
}
return status;
}
UTILS_NOINLINE
void assertFramebufferStatus(GLenum target, const char* function, size_t line) noexcept {
GLenum const status = checkFramebufferStatus(target, function, line);
void assertFramebufferStatus(io::ostream& out, GLenum target, const char* function, size_t line) noexcept {
GLenum const status = checkFramebufferStatus(out, target, function, line);
if (UTILS_VERY_UNLIKELY(status != GL_FRAMEBUFFER_COMPLETE)) {
debug_trap();
}
+10 -10
View File
@@ -33,21 +33,21 @@
namespace filament::backend::GLUtils {
std::string_view getGLErrorString(GLenum error) noexcept;
GLenum checkGLError(const char* function, size_t line) noexcept;
void assertGLError(const char* function, size_t line) noexcept;
GLenum checkGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
void assertGLError(utils::io::ostream& out, const char* function, size_t line) noexcept;
std::string_view getFramebufferStatusString(GLenum err) noexcept;
GLenum checkFramebufferStatus(GLenum target, const char* function, size_t line) noexcept;
void assertFramebufferStatus(GLenum target, const char* function, size_t line) noexcept;
GLenum checkFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char* function, size_t line) noexcept;
#ifdef NDEBUG
# define CHECK_GL_ERROR()
# define CHECK_GL_ERROR_NON_FATAL()
# define CHECK_GL_FRAMEBUFFER_STATUS(target)
# define CHECK_GL_ERROR(out)
# define CHECK_GL_ERROR_NON_FATAL(out)
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target)
#else
# define CHECK_GL_ERROR() { GLUtils::assertGLError(__func__, __LINE__); }
# define CHECK_GL_ERROR_NON_FATAL() { GLUtils::checkGLError(__func__, __LINE__); }
# define CHECK_GL_FRAMEBUFFER_STATUS(target) { GLUtils::checkFramebufferStatus( target, __func__, __LINE__); }
# define CHECK_GL_ERROR(out) { GLUtils::assertGLError(out, __func__, __LINE__); }
# define CHECK_GL_ERROR_NON_FATAL(out) { GLUtils::checkGLError(out, __func__, __LINE__); }
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); }
#endif
constexpr GLuint getComponentCount(ElementType const type) noexcept {
+51 -30
View File
@@ -22,9 +22,9 @@
#include <backend/platforms/OpenGLPlatform.h>
#include <backend/DriverEnums.h>
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <functional>
@@ -77,8 +77,8 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
state.version = (char const*)glGetString(GL_VERSION);
state.shader = (char const*)glGetString(GL_SHADING_LANGUAGE_VERSION);
LOG(INFO) << "[" << state.vendor << "], [" << state.renderer << "], "
"[" << state.version << "], [" << state.shader << "]";
slog.v << "[" << state.vendor << "], [" << state.renderer << "], "
"[" << state.version << "], [" << state.shader << "]" << io::endl;
/*
* Figure out GL / GLES version, extensions and capabilities we need to
@@ -164,33 +164,51 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
}
#endif
LOG(INFO) << "Feature level: " << +mFeatureLevel;
LOG(INFO) << "Active workarounds: ";
slog.v << "Feature level: " << +mFeatureLevel << '\n';
slog.v << "Active workarounds: " << '\n';
UTILS_NOUNROLL
for (auto [enabled, name, _] : mBugDatabase) {
if (enabled) {
LOG(INFO) << name;
slog.v << name << '\n';
}
}
flush(slog.v);
#ifndef NDEBUG
// this is useful for development
LOG(INFO) << "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = " << gets.max_anisotropy;
LOG(INFO) << "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = " << gets.max_combined_texture_image_units;
LOG(INFO) << "GL_MAX_TEXTURE_SIZE = " << gets.max_texture_size;
LOG(INFO) << "GL_MAX_CUBE_MAP_TEXTURE_SIZE = " << gets.max_cubemap_texture_size;
LOG(INFO) << "GL_MAX_3D_TEXTURE_SIZE = " << gets.max_3d_texture_size;
LOG(INFO) << "GL_MAX_ARRAY_TEXTURE_LAYERS = " << gets.max_array_texture_layers;
LOG(INFO) << "GL_MAX_DRAW_BUFFERS = " << gets.max_draw_buffers;
LOG(INFO) << "GL_MAX_RENDERBUFFER_SIZE = " << gets.max_renderbuffer_size;
LOG(INFO) << "GL_MAX_SAMPLES = " << gets.max_samples;
LOG(INFO) << "GL_MAX_TEXTURE_IMAGE_UNITS = " << gets.max_texture_image_units;
LOG(INFO) << "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = "
<< gets.max_transform_feedback_separate_attribs;
LOG(INFO) << "GL_MAX_UNIFORM_BLOCK_SIZE = " << gets.max_uniform_block_size;
LOG(INFO) << "GL_MAX_UNIFORM_BUFFER_BINDINGS = " << gets.max_uniform_buffer_bindings;
LOG(INFO) << "GL_NUM_PROGRAM_BINARY_FORMATS = " << gets.num_program_binary_formats;
LOG(INFO) << "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = " << gets.uniform_buffer_offset_alignment;
slog.v
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = "
<< gets.max_anisotropy << '\n'
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = "
<< gets.max_combined_texture_image_units << '\n'
<< "GL_MAX_TEXTURE_SIZE = "
<< gets.max_texture_size << '\n'
<< "GL_MAX_CUBE_MAP_TEXTURE_SIZE = "
<< gets.max_cubemap_texture_size << '\n'
<< "GL_MAX_3D_TEXTURE_SIZE = "
<< gets.max_3d_texture_size << '\n'
<< "GL_MAX_ARRAY_TEXTURE_LAYERS = "
<< gets.max_array_texture_layers << '\n'
<< "GL_MAX_DRAW_BUFFERS = "
<< gets.max_draw_buffers << '\n'
<< "GL_MAX_RENDERBUFFER_SIZE = "
<< gets.max_renderbuffer_size << '\n'
<< "GL_MAX_SAMPLES = "
<< gets.max_samples << '\n'
<< "GL_MAX_TEXTURE_IMAGE_UNITS = "
<< gets.max_texture_image_units << '\n'
<< "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = "
<< gets.max_transform_feedback_separate_attribs << '\n'
<< "GL_MAX_UNIFORM_BLOCK_SIZE = "
<< gets.max_uniform_block_size << '\n'
<< "GL_MAX_UNIFORM_BUFFER_BINDINGS = "
<< gets.max_uniform_buffer_bindings << '\n'
<< "GL_NUM_PROGRAM_BINARY_FORMATS = "
<< gets.num_program_binary_formats << '\n'
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = "
<< gets.uniform_buffer_offset_alignment << '\n'
;
flush(slog.v);
#endif
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
@@ -224,14 +242,15 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
if (ext.KHR_debug) {
auto cb = +[](GLenum, GLenum type, GLuint, GLenum severity, GLsizei length,
const GLchar* message, const void *) {
auto logSeverity = utils::LogSeverity::kInfo;
io::ostream* stream = &slog.i;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH: logSeverity = utils::LogSeverity::kError; break;
case GL_DEBUG_SEVERITY_MEDIUM: logSeverity = utils::LogSeverity::kWarning; break;
case GL_DEBUG_SEVERITY_LOW: logSeverity = utils::LogSeverity::kInfo; break;
case GL_DEBUG_SEVERITY_HIGH: stream = &slog.e; break;
case GL_DEBUG_SEVERITY_MEDIUM: stream = &slog.w; break;
case GL_DEBUG_SEVERITY_LOW: stream = &slog.d; break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
default: break;
}
io::ostream& out = *stream;
const char* level = ": ";
switch (type) {
case GL_DEBUG_TYPE_ERROR: level = "ERROR: "; break;
@@ -243,7 +262,7 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
case GL_DEBUG_TYPE_MARKER: level = "MARKER: "; break;
default: break;
}
LOG(LEVEL(logSeverity)) << "KHR_debug " << level << std::string_view{ message, size_t(length) };
out << "KHR_debug " << level << std::string_view{ message, size_t(length) } << io::endl;
};
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
@@ -688,8 +707,9 @@ void OpenGLContext::initExtensionsGLES(Extensions* ext, GLint major, GLint minor
GLUtils::unordered_string_set const exts = GLUtils::split(extensions);
if constexpr (DEBUG_PRINT_EXTENSIONS) {
for (auto extension: exts) {
DLOG(INFO) << "\"" << std::string_view(extension) << "\"";
slog.d << "\"" << std::string_view(extension) << "\"\n";
}
flush(slog.d);
}
// figure out and initialize the extensions we need
@@ -763,8 +783,9 @@ void OpenGLContext::initExtensionsGL(Extensions* ext, GLint major, GLint minor)
}
if constexpr (DEBUG_PRINT_EXTENSIONS) {
for (auto extension: exts) {
DLOG(INFO) << "\"" << std::string_view(extension) << "\"";
slog.d << "\"" << std::string_view(extension) << "\"\n";
}
flush(slog.d);
}
using namespace std::literals;
@@ -1024,7 +1045,7 @@ GLuint OpenGLContext::getSamplerSlow(SamplerParams params) const noexcept {
std::min(gets.max_anisotropy, anisotropy));
}
#endif
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
mSamplerMap[params] = s;
return s;
}
+76 -126
View File
@@ -48,13 +48,12 @@
#include <type_traits>
#include <utils/BitmaskEnum.h>
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/CString.h>
#include <utils/Invocable.h>
#include <utils/Logger.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/Slice.h>
#include <utils/Systrace.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
@@ -185,18 +184,20 @@ OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* platform,
// GLVertexBufferInfo : 132 moderate
// -- less than or equal to 136 bytes
DLOG(INFO) << "GLSwapChain: " << sizeof(GLSwapChain);
DLOG(INFO) << "GLBufferObject: " << sizeof(GLBufferObject);
DLOG(INFO) << "GLVertexBuffer: " << sizeof(GLVertexBuffer);
DLOG(INFO) << "GLVertexBufferInfo: " << sizeof(GLVertexBufferInfo);
DLOG(INFO) << "GLIndexBuffer: " << sizeof(GLIndexBuffer);
DLOG(INFO) << "GLRenderPrimitive: " << sizeof(GLRenderPrimitive);
DLOG(INFO) << "GLTexture: " << sizeof(GLTexture);
DLOG(INFO) << "GLTimerQuery: " << sizeof(GLTimerQuery);
DLOG(INFO) << "GLStream: " << sizeof(GLStream);
DLOG(INFO) << "GLRenderTarget: " << sizeof(GLRenderTarget);
DLOG(INFO) << "GLFence: " << sizeof(GLFence);
DLOG(INFO) << "OpenGLProgram: " << sizeof(OpenGLProgram);
slog.d
<< "\nGLSwapChain: " << sizeof(GLSwapChain)
<< "\nGLBufferObject: " << sizeof(GLBufferObject)
<< "\nGLVertexBuffer: " << sizeof(GLVertexBuffer)
<< "\nGLVertexBufferInfo: " << sizeof(GLVertexBufferInfo)
<< "\nGLIndexBuffer: " << sizeof(GLIndexBuffer)
<< "\nGLRenderPrimitive: " << sizeof(GLRenderPrimitive)
<< "\nGLTexture: " << sizeof(GLTexture)
<< "\nGLTimerQuery: " << sizeof(GLTimerQuery)
<< "\nGLStream: " << sizeof(GLStream)
<< "\nGLRenderTarget: " << sizeof(GLRenderTarget)
<< "\nGLFence: " << sizeof(GLFence)
<< "\nOpenGLProgram: " << sizeof(OpenGLProgram)
<< io::endl;
#endif
// here we check we're on a supported version of GL before initializing the driver
@@ -288,7 +289,7 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
mStreamsWithPendingAcquiredImage.reserve(8);
#ifndef NDEBUG
LOG(INFO) << "OS version: " << mPlatform.getOSVersion();
slog.i << "OS version: " << mPlatform.getOSVersion() << io::endl;
#endif
// Timer queries are core in GL 3.3, otherwise we need EXT_disjoint_timer_query
@@ -667,7 +668,7 @@ void OpenGLDriver::createIndexBufferR(
gl.bindVertexArray(nullptr);
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->gl.buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, nullptr, getBufferUsage(usage));
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
@@ -692,7 +693,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
glBufferData(bo->gl.binding, byteCount, nullptr, getBufferUsage(usage));
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
@@ -729,7 +730,7 @@ void OpenGLDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
// this records the index buffer into the currently bound VAO
gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib->gl.buffer);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
@@ -759,7 +760,7 @@ void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
}
construct<OpenGLProgram>(ph, *this, std::move(program));
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
UTILS_NOINLINE
@@ -931,12 +932,7 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
if (gl.features.multisample_texture) {
// multi-sample texture on GL 3.2 / GLES 3.1 and above
if (depth <= 1) {
// We forcibly change the target to 2D-multisample only for flat texture.
// A depth value greater than 1 may indicate multiview usage, which requires
// GL_TEXTURE_2D_ARRAY. Also 2D MSAA won't work with non-flat texture anyway.
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
}
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
} else {
// Turn off multi-sampling for that texture. It's just not supported.
}
@@ -952,7 +948,7 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
renderBufferStorage(t->gl.id, internalFormat, w, h, samples);
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
@@ -998,7 +994,7 @@ void OpenGLDriver::createTextureViewR(Handle<HwTexture> th,
assert_invariant(ref);
ref->count++;
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
@@ -1061,7 +1057,7 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
assert_invariant(ref);
ref->count++;
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createTextureExternalImage2R(Handle<HwTexture> th, SamplerType target,
@@ -1212,19 +1208,14 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
#if defined(BACKEND_OPENGL_LEVEL_GLES31)
if (gl.features.multisample_texture) {
// multi-sample texture on GL 3.2 / GLES 3.1 and above
if (depth <= 1) {
// We forcibly change the target to 2D-multisample only for flat texture.
// A depth value greater than 1 may indicate multiview usage, which requires
// GL_TEXTURE_2D_ARRAY. Also 2D MSAA won't work with non-flat texture anyway.
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
}
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
} else {
// Turn off multi-sampling for that texture. It's just not supported.
}
#endif
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer const* vb) {
@@ -1462,15 +1453,8 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
#if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_IOS)
if (layerCount > 1) {
// if layerCount > 1, it means we use the multiview extension.
if (rt->gl.samples > 1) {
// For MSAA
glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, attachment,
t->gl.id, 0, rt->gl.samples, binfo.layer, layerCount);
}
else {
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment, t->gl.id, 0,
binfo.layer, layerCount);
}
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment,
t->gl.id, 0, binfo.layer, layerCount);
} else
#endif // !defined(__EMSCRIPTEN__) && !defined(FILAMENT_IOS)
{
@@ -1484,7 +1468,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
// we shouldn't be here
break;
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
} else
#ifndef __EMSCRIPTEN__
#ifdef GL_EXT_multisampled_render_to_texture
@@ -1505,7 +1489,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
GL_RENDERBUFFER, t->gl.id);
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
} else
#endif // GL_EXT_multisampled_render_to_texture
#endif // __EMSCRIPTEN__
@@ -1587,13 +1571,13 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
break;
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
rt->gl.resolve |= resolveFlags;
CHECK_GL_ERROR()
CHECK_GL_FRAMEBUFFER_STATUS(GL_FRAMEBUFFER)
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
}
void OpenGLDriver::renderBufferStorage(GLuint rbo, GLenum internalformat, uint32_t width, // NOLINT(readability-convert-member-functions-to-static)
@@ -1622,7 +1606,7 @@ void OpenGLDriver::renderBufferStorage(GLuint rbo, GLenum internalformat, uint32
// unbind the renderbuffer, to avoid any later confusion
glBindRenderbuffer(GL_RENDERBUFFER, 0);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createDefaultRenderTargetR(
@@ -1719,7 +1703,7 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
if (UTILS_LIKELY(!getContext().isES2())) {
glDrawBuffers((GLsizei)maxDrawBuffers, bufs);
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
#endif
@@ -1759,7 +1743,7 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
assert_invariant(any(targets & TargetBufferFlags::ALL));
assert_invariant(tmin == tmax);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::createFenceR(Handle<HwFence> fh, int) {
@@ -2110,7 +2094,7 @@ void OpenGLDriver::setAcquiredImage(Handle<HwStream> sh, void* hwbuffer, const m
if (UTILS_UNLIKELY(glstream->user_thread.pending.image)) {
scheduleRelease(glstream->user_thread.pending);
LOG(WARNING) << "Acquired image is set more than once per frame.";
slog.w << "Acquired image is set more than once per frame." << io::endl;
}
glstream->user_thread.pending = mPlatform.transformAcquiredImage({
@@ -2530,36 +2514,13 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
mPlatform.makeCurrent(scDraw->swapChain, scRead->swapChain,
[this]() {
for (auto t: mTexturesWithStreamsAttached) {
if (t->hwStream->streamType == StreamType::NATIVE) {
mPlatform.detach(t->hwStream->stream);
}
}
// OpenGL context is about to change, unbind everything
mContext.unbindEverything();
},
[this](size_t index) {
for (auto t: mTexturesWithStreamsAttached) {
if (t->hwStream->streamType == StreamType::NATIVE) {
if (t->externalTexture) {
glGenTextures(1, &t->externalTexture->id);
t->gl.id = t->externalTexture->id;
} else {
glGenTextures(1, &t->gl.id);
}
mPlatform.attach(t->hwStream->stream, t->gl.id);
mContext.updateTexImage(GL_TEXTURE_EXTERNAL_OES, t->gl.id);
}
}
// force invalidation of all bound descriptor sets
decltype(mInvalidDescriptorSetBindings) changed;
changed.setValue((1 << MAX_DESCRIPTOR_SET_COUNT) - 1);
mInvalidDescriptorSetBindings |= changed;
// OpenGL context has changed, resynchronize the state with the cache
mContext.synchronizeStateAndCache(index);
DLOG(INFO) << "*** OpenGL context change : " << (index ? "protected" : "default");
slog.d << "*** OpenGL context change : " << (index ? "protected" : "default") << io::endl;
});
mCurrentDrawSwapChain = scDraw;
@@ -2600,7 +2561,7 @@ void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
vb->bufferObjectsVersion = (version + 1) % kMaxVersion;
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::updateIndexBuffer(
@@ -2617,7 +2578,7 @@ void OpenGLDriver::updateIndexBuffer(
scheduleDestroy(std::move(p));
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::registerBufferObjectStreams(Handle<HwBufferObject> boh, BufferObjectStreamDescriptor&& streams) {
@@ -2697,7 +2658,7 @@ void OpenGLDriver::updateBufferObject(
scheduleDestroy(std::move(bd));
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::updateBufferObjectUnsynchronized(
@@ -2744,7 +2705,7 @@ retry:
scheduleDestroy(std::move(bd));
}
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
#endif
}
@@ -2794,7 +2755,7 @@ void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
glGenerateMipmap(t->gl.target);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::setTextureData(GLTexture const* t, uint32_t level,
@@ -2903,7 +2864,7 @@ void OpenGLDriver::setTextureData(GLTexture const* t, uint32_t level,
scheduleDestroy(std::move(p));
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::setCompressedTextureData(GLTexture const* t, uint32_t level,
@@ -2989,7 +2950,7 @@ void OpenGLDriver::setCompressedTextureData(GLTexture const* t, uint32_t level,
scheduleDestroy(std::move(p));
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) {
@@ -3031,7 +2992,6 @@ void OpenGLDriver::attachStream(GLTexture* t, GLStream* hwStream) noexcept {
switch (hwStream->streamType) {
case StreamType::NATIVE:
mPlatform.attach(hwStream->stream, t->gl.id);
mContext.updateTexImage(GL_TEXTURE_EXTERNAL_OES, t->gl.id);
break;
case StreamType::ACQUIRED:
break;
@@ -3060,12 +3020,7 @@ void OpenGLDriver::detachStream(GLTexture* t) noexcept {
break;
}
if (t->externalTexture) {
glGenTextures(1, &t->externalTexture->id);
t->gl.id = t->externalTexture->id;
} else {
glGenTextures(1, &t->gl.id);
}
glGenTextures(1, &t->gl.id);
t->hwStream = nullptr;
}
@@ -3089,14 +3044,8 @@ void OpenGLDriver::replaceStream(GLTexture* texture, GLStream* newStream) noexce
switch (newStream->streamType) {
case StreamType::NATIVE:
if (texture->externalTexture) {
glGenTextures(1, &texture->externalTexture->id);
texture->gl.id = texture->externalTexture->id;
} else {
glGenTextures(1, &texture->gl.id);
}
glGenTextures(1, &texture->gl.id);
mPlatform.attach(newStream->stream, texture->gl.id);
mContext.updateTexImage(GL_TEXTURE_EXTERNAL_OES, texture->gl.id);
break;
case StreamType::ACQUIRED:
// Just re-use the old texture id.
@@ -3152,7 +3101,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
TargetBufferFlags discardFlags = params.flags.discardStart & rt->targets;
GLuint const fbo = gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
CHECK_GL_FRAMEBUFFER_STATUS(GL_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
// each render-pass starts with a disabled scissor
gl.disable(GL_SCISSOR_TEST);
@@ -3164,7 +3113,7 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
if (attachmentCount) {
gl.procs.invalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
} else {
// It's important to clear the framebuffer before drawing, as it resets
// the fb to a known state (resets fb compression and possibly other things).
@@ -3251,7 +3200,7 @@ void OpenGLDriver::endRenderPass(int) {
if (attachmentCount) {
gl.procs.invalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
}
@@ -3297,13 +3246,13 @@ void OpenGLDriver::resolvePass(ResolveAction action, GLRenderTarget const* rt,
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, read);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, draw);
CHECK_GL_FRAMEBUFFER_STATUS(GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(GL_DRAW_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_DRAW_FRAMEBUFFER)
gl.disable(GL_SCISSOR_TEST);
glBlitFramebuffer(0, 0, (GLint)rt->width, (GLint)rt->height,
0, 0, (GLint)rt->width, (GLint)rt->height, mask, GL_NEAREST);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
#endif
}
@@ -3482,7 +3431,7 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
if (buffer) {
gl.bindFramebuffer(GL_FRAMEBUFFER, s->gl.fbo_read ? s->gl.fbo_read : s->gl.fbo);
glReadPixels(GLint(x), GLint(y), GLint(width), GLint(height), glFormat, glType, buffer);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
// now we need to flip the buffer vertically to match our API
size_t const stride = p.stride ? p.stride : width;
@@ -3514,7 +3463,7 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
glBufferData(GL_PIXEL_PACK_BUFFER, pboSize, nullptr, GL_STATIC_DRAW);
glReadPixels(GLint(x), GLint(y), GLint(width), GLint(height), glFormat, glType, nullptr);
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
// we're forced to make a copy on the heap because otherwise it deletes std::function<> copy
// constructor.
@@ -3554,7 +3503,7 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
glDeleteBuffers(1, &pbo);
scheduleDestroy(std::move(p));
delete pUserBuffer;
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
});
#endif
}
@@ -3579,7 +3528,7 @@ void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
glCopyBufferSubData(bo->gl.binding, GL_PIXEL_PACK_BUFFER, offset, 0, size);
gl.bindBuffer(bo->gl.binding, 0);
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
// then, we schedule a mapBuffer of the PBO later, once the fence has signaled
auto* pUserBuffer = new BufferDescriptor(std::move(p));
@@ -3596,7 +3545,7 @@ void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
glDeleteBuffers(1, &pbo);
scheduleDestroy(std::move(p));
delete pUserBuffer;
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
});
} else {
gl.bindBuffer(bo->gl.binding, bo->gl.id);
@@ -3609,7 +3558,7 @@ void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
}
gl.bindBuffer(bo->gl.binding, 0);
scheduleDestroy(std::move(p));
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
#endif
}
@@ -3639,7 +3588,7 @@ void OpenGLDriver::whenFrameComplete(const std::function<void()>& fn) noexcept {
void OpenGLDriver::whenGpuCommandsComplete(const std::function<void()>& fn) noexcept {
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
mGpuCommandCompleteOps.emplace_back(sync, fn);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::executeGpuCommandsCompleteOps() noexcept {
@@ -3759,7 +3708,8 @@ void OpenGLDriver::updateDescriptorSetTexture(
TextureHandle th,
SamplerParams params) {
GLDescriptorSet* ds = handle_cast<GLDescriptorSet*>(dsh);
ds->update(mContext, mHandleAllocator, binding, th, params);
GLTexture* t = th ? handle_cast<GLTexture*>(th) : nullptr;
ds->update(mContext, binding, t, params);
}
void OpenGLDriver::flush(int) {
@@ -3857,7 +3807,7 @@ void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags,
}
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLDriver::resolve(
@@ -3968,7 +3918,7 @@ void OpenGLDriver::blit(
case SamplerType::SAMPLER_EXTERNAL:
break;
}
CHECK_GL_FRAMEBUFFER_STATUS(GL_DRAW_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_DRAW_FRAMEBUFFER)
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fbo[1]);
switch (s->target) {
@@ -3994,14 +3944,14 @@ void OpenGLDriver::blit(
case SamplerType::SAMPLER_EXTERNAL:
break;
}
CHECK_GL_FRAMEBUFFER_STATUS(GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_READ_FRAMEBUFFER)
gl.disable(GL_SCISSOR_TEST);
glBlitFramebuffer(
srcOrigin.x, srcOrigin.y, srcOrigin.x + size.x, srcOrigin.y + size.y,
dstOrigin.x, dstOrigin.y, dstOrigin.x + size.x, dstOrigin.y + size.y,
mask, GL_NEAREST);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
gl.unbindFramebuffer(GL_DRAW_FRAMEBUFFER);
gl.unbindFramebuffer(GL_READ_FRAMEBUFFER);
@@ -4064,15 +4014,15 @@ void OpenGLDriver::blitDEPRECATED(TargetBufferFlags buffers,
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, s->gl.fbo);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, d->gl.fbo);
CHECK_GL_FRAMEBUFFER_STATUS(GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(GL_DRAW_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_DRAW_FRAMEBUFFER)
gl.disable(GL_SCISSOR_TEST);
glBlitFramebuffer(
srcRect.left, srcRect.bottom, srcRect.right(), srcRect.top(),
dstRect.left, dstRect.bottom, dstRect.right(), dstRect.top(),
GL_COLOR_BUFFER_BIT, glFilterMode);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
#endif
}
@@ -4199,9 +4149,9 @@ void OpenGLDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t ins
#endif
#if FILAMENT_ENABLE_MATDBG
CHECK_GL_ERROR_NON_FATAL()
CHECK_GL_ERROR_NON_FATAL(utils::slog.e)
#else
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
#endif
}
@@ -4231,9 +4181,9 @@ void OpenGLDriver::draw2GLES2(uint32_t indexOffset, uint32_t indexCount, uint32_
reinterpret_cast<const void*>(indexOffset << rp->gl.indicesShift));
#if FILAMENT_ENABLE_MATDBG
CHECK_GL_ERROR_NON_FATAL()
CHECK_GL_ERROR_NON_FATAL(utils::slog.e)
#else
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
#endif
}
@@ -4283,9 +4233,9 @@ void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, uint3 workGroupCou
#endif // BACKEND_OPENGL_LEVEL_GLES31
#if FILAMENT_ENABLE_MATDBG
CHECK_GL_ERROR_NON_FATAL()
CHECK_GL_ERROR_NON_FATAL(utils::slog.e)
#else
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
#endif
}
@@ -64,7 +64,7 @@ utils::CString OpenGLPlatform::getRendererString(Driver const* driver) {
}
void OpenGLPlatform::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
utils::Invocable<void()>, utils::Invocable<void(size_t)>) {
utils::Invocable<void()>, utils::Invocable<void(size_t)>) noexcept {
makeCurrent(getCurrentContextType(), drawSwapChain, readSwapChain);
}
@@ -214,7 +214,7 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
case DescriptorType::INPUT_ATTACHMENT:
break;
}
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
}
@@ -114,14 +114,14 @@ void TimerQueryNativeFactory::createTimerQuery(GLTimerQuery* tq) {
tq->state = std::make_shared<GLTimerQuery::State>();
mContext.procs.genQueries(1u, &tq->state->gl.query);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void TimerQueryNativeFactory::destroyTimerQuery(GLTimerQuery* tq) {
assert_invariant(tq->state);
mContext.procs.deleteQueries(1u, &tq->state->gl.query);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
tq->state.reset();
}
@@ -131,14 +131,14 @@ void TimerQueryNativeFactory::beginTimeElapsedQuery(GLTimerQuery* tq) {
tq->state->elapsed.store(int64_t(TimerQueryResult::NOT_READY), std::memory_order_relaxed);
mContext.procs.beginQuery(GL_TIME_ELAPSED, tq->state->gl.query);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
void TimerQueryNativeFactory::endTimeElapsedQuery(OpenGLDriver& driver, GLTimerQuery* tq) {
assert_invariant(tq->state);
mContext.procs.endQuery(GL_TIME_ELAPSED);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
std::weak_ptr<GLTimerQuery::State> const weak = tq->state;
@@ -153,7 +153,7 @@ void TimerQueryNativeFactory::endTimeElapsedQuery(OpenGLDriver& driver, GLTimerQ
GLuint available = 0;
context.procs.getQueryObjectuiv(state->gl.query, GL_QUERY_RESULT_AVAILABLE, &available);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
if (!available) {
// we need to try this one again later
return false;
@@ -23,7 +23,6 @@
#include "OpenGLDriver.h"
#include <iterator>
#include <optional>
#include <private/backend/BackendUtils.h>
#include <backend/DriverEnums.h>
@@ -31,14 +30,14 @@
#include <private/utils/Tracing.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/debug.h>
#include <utils/FixedCapacityVector.h>
#include <utils/JobSystem.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <utils/Panic.h>
#include <algorithm>
#include <array>
@@ -65,9 +64,9 @@ static std::string to_string(bool const b) { return b ? "true" : "false"; }
static std::string to_string(int const i) { return std::to_string(i); }
static std::string to_string(float const f) { return "float(" + std::to_string(f) + ")"; }
static void logCompilationError(ShaderStage shaderType, const char* name, GLuint shaderId,
CString const& sourceCode) noexcept;
static void logProgramLinkError(char const* name, GLuint program) noexcept;
static void logCompilationError(io::ostream& out, ShaderStage shaderType, const char* name,
GLuint shaderId, CString const& sourceCode) noexcept;
static void logProgramLinkError(io::ostream& out, char const* name, GLuint program) noexcept;
static void process_GOOGLE_cpp_style_line_directive(OpenGLContext const& context, char* source,
size_t len) noexcept;
@@ -111,17 +110,7 @@ struct ShaderCompilerService::OpenGLProgramToken : ProgramToken {
cond.wait(l, [this] { return signaled; });
}
// This is invoked upon token completion, which occurs after a successful `gl.program`
// population or upon cancellation. In either scenario, the callback handle must be submitted
// to notify the caller that resource loading has concluded.
void trySubmittingCallback() noexcept {
if (handle) {
compiler.submitCallbackHandle(*handle);
handle = std::nullopt;
}
}
std::optional<CallbackManager::Handle> handle{};
CallbackManager::Handle handle{};
BlobCacheKey key;
// Used for the `THREAD_POOL` mode.
@@ -131,7 +120,7 @@ struct ShaderCompilerService::OpenGLProgramToken : ProgramToken {
};
ShaderCompilerService::OpenGLProgramToken::~OpenGLProgramToken() {
trySubmittingCallback();
compiler.submitCallbackHandle(handle);
}
/* static */ void ShaderCompilerService::setUserData(const program_token_t& token,
@@ -350,7 +339,7 @@ GLuint ShaderCompilerService::getProgram(program_token_t& token) {
// Cleanup the token.
token->compiler.cancelTickOp(token);
token = nullptr; // This will try submitting a callback handle to the callback manager.
token = nullptr;// This will submit a callback condition (handle) to the callback manager.
}
void ShaderCompilerService::tick() {
@@ -403,7 +392,7 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) {
// Cleanup the token.
token->compiler.cancelTickOp(token);
token = nullptr;
token = nullptr;// This will submit a callback condition (handle) to the callback manager.
return program;
}
@@ -433,9 +422,8 @@ void ShaderCompilerService::ensureTokenIsReady(program_token_t const& token) {
// just log warnings here instead of repeatedly checking compile status. If this turns
// out to be a real issue later, we would need to consider doing the canonical way.
if (!isCompileCompleted(token)) {
LOG(WARNING)
<< "Shader compilation for OpenGL program " << token->name.c_str_safe()
<< " is not completed yet. The following program link may not succeed.";
slog.w << "Shader compilation for OpenGL program " << token->name.c_str_safe()
<< " is not completed yet. The following program link may not succeed.";
}
linkProgram(mDriver.getContext(), token);
@@ -645,7 +633,8 @@ void ShaderCompilerService::executeTickOps() noexcept {
}
// Something went wrong. Log the error message.
const ShaderStage type = static_cast<ShaderStage>(i);
logCompilationError(type, token->name.c_str_safe(), shader, token->shaderSourceCode[i]);
logCompilationError(slog.e, type, token->name.c_str_safe(), shader,
token->shaderSourceCode[i]);
}
}
@@ -670,7 +659,6 @@ void ShaderCompilerService::executeTickOps() noexcept {
}
glLinkProgram(program);
token->gl.program = program;
token->trySubmittingCallback();
}
/* static */ bool ShaderCompilerService::isLinkCompleted(program_token_t const& token) noexcept {
@@ -697,7 +685,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
glGetProgramiv(token->gl.program, GL_LINK_STATUS, &status);
if (UTILS_UNLIKELY(status != GL_TRUE)) {
// Something went wrong. Log the error message.
logProgramLinkError(token->name.c_str_safe(), token->gl.program);
logProgramLinkError(slog.e, token->name.c_str_safe(), token->gl.program);
linked = false;
}
// No need to keep the shaders around regardless of the result of the program linking.
@@ -747,7 +735,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
// ------------------------------------------------------------------------------------------------
UTILS_NOINLINE
/* static */ void logCompilationError(ShaderStage shaderType, const char* name,
/* static */ void logCompilationError(io::ostream& out, ShaderStage shaderType, const char* name,
GLuint const shaderId, UTILS_UNUSED_IN_RELEASE CString const& sourceCode) noexcept {
{ // scope for the temporary string storage
@@ -769,9 +757,8 @@ UTILS_NOINLINE
CString infoLog(length);
glGetShaderInfoLog(shaderId, length, nullptr, infoLog.data());
LOG(ERROR) << "Compilation error in " << to_string(shaderType) << " shader \"" << name
<< "\":";
LOG(ERROR) << "\"" << infoLog.c_str() << "\"";
out << "Compilation error in " << to_string(shaderType) << " shader \"" << name << "\":\n"
<< "\"" << infoLog.c_str() << "\"" << io::endl;
}
#ifndef NDEBUG
@@ -786,25 +773,26 @@ UTILS_NOINLINE
} else {
line = shader.substr(start, end - start);
}
LOG(ERROR) << lc++ << ": " << line.c_str();
out << lc++ << ": " << line.c_str() << '\n';
if (end == std::string::npos) {
break;
}
start = end + 1;
}
LOG(ERROR) << "";
out << io::endl;
#endif
}
UTILS_NOINLINE
/* static */ void logProgramLinkError(char const* name, GLuint program) noexcept {
/* static */ void logProgramLinkError(io::ostream& out, char const* name, GLuint program) noexcept {
GLint length = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
CString infoLog(length);
glGetProgramInfoLog(program, length, nullptr, infoLog.data());
LOG(ERROR) << "Link error in \"" << name << "\":\n" << "\"" << infoLog.c_str() << "\"";
out << "Link error in \"" << name << "\":\n"
<< "\"" << infoLog.c_str() << "\"" << io::endl;
}
// If usages of the Google-style line directive are present, remove them, as some
@@ -70,9 +70,6 @@ PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glMaxShaderCompilerThreadsKHR;
#ifdef GL_OVR_multiview
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR;
#endif
#ifdef GL_OVR_multiview_multisampled_render_to_texture
PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC glFramebufferTextureMultisampleMultiviewOVR;
#endif
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
// On Android, If we want to support a build system less than ANDROID_API 21, we need to
@@ -126,9 +123,6 @@ void importGLESExtensionsEntryPoints() {
#ifdef GL_OVR_multiview
getProcAddress(glFramebufferTextureMultiviewOVR, "glFramebufferTextureMultiviewOVR");
#endif
#ifdef GL_OVR_multiview_multisampled_render_to_texture
getProcAddress(glFramebufferTextureMultisampleMultiviewOVR, "glFramebufferTextureMultisampleMultiviewOVR");
#endif
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
getProcAddress(glDispatchCompute, "glDispatchCompute");
#endif
-3
View File
@@ -154,9 +154,6 @@ extern PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glMaxShaderCompilerThreadsKHR;
#ifdef GL_OVR_multiview
extern PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR;
#endif
#ifdef GL_OVR_multiview_multisampled_render_to_texture
extern PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC glFramebufferTextureMultisampleMultiviewOVR;
#endif
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
extern PFNGLDISPATCHCOMPUTEPROC glDispatchCompute;
#endif
@@ -96,7 +96,7 @@ CocoaExternalImage::SharedGl::~SharedGl() noexcept {
CocoaExternalImage::CocoaExternalImage(const CVOpenGLTextureCacheRef textureCache,
const SharedGl &sharedGl) noexcept : mSharedGl(sharedGl), mTextureCache(textureCache) {
glGenFramebuffers(1, &mFBO);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
CocoaExternalImage::~CocoaExternalImage() noexcept {
@@ -125,7 +125,7 @@ bool CocoaExternalImage::set(CVPixelBufferRef image) noexcept {
mTexture = createTextureFromImage(image);
mRgbaTexture = encodeCopyRectangleToTexture2D(CVOpenGLTextureGetName(mTexture),
CVPixelBufferGetWidth(image), CVPixelBufferGetHeight(image));
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
return true;
}
@@ -182,33 +182,33 @@ GLuint CocoaExternalImage::encodeCopyRectangleToTexture2D(GLuint rectangle,
// Create a texture to hold the result of the blit image.
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
// source textures
glBindSampler(0, mSharedGl.sampler);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE, rectangle);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
// destination texture
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_FRAMEBUFFER_STATUS(GL_FRAMEBUFFER)
CHECK_GL_ERROR()
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
CHECK_GL_ERROR(utils::slog.e)
// draw
glViewport(0, 0, width, height);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
glUseProgram(mSharedGl.program);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
glDisableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
mState.restore();
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
return texture;
}
@@ -119,7 +119,7 @@ CocoaTouchExternalImage::CocoaTouchExternalImage(const CVOpenGLESTextureCacheRef
glGenFramebuffers(1, &mFBO);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
}
CocoaTouchExternalImage::~CocoaTouchExternalImage() noexcept {
@@ -247,7 +247,7 @@ GLuint CocoaTouchExternalImage::encodeColorConversionPass(GLuint yPlaneTexture,
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
// source textures
glBindSampler(0, mSharedGl.sampler);
@@ -261,8 +261,8 @@ GLuint CocoaTouchExternalImage::encodeColorConversionPass(GLuint yPlaneTexture,
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
CHECK_GL_ERROR()
CHECK_GL_FRAMEBUFFER_STATUS(GL_FRAMEBUFFER)
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
// geometry
glBindVertexArray(0);
@@ -275,7 +275,7 @@ GLuint CocoaTouchExternalImage::encodeColorConversionPass(GLuint yPlaneTexture,
glUseProgram(mSharedGl.program);
glDrawArrays(GL_TRIANGLES, 0, 3);
CHECK_GL_ERROR()
CHECK_GL_ERROR(utils::slog.e)
mState.restore();
@@ -20,9 +20,9 @@
#include <backend/Platform.h>
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#if __has_include(<android/surface_texture.h>)
@@ -59,7 +59,7 @@ void ExternalStreamManagerAndroid::destroy(ExternalStreamManagerAndroid* pExtern
ExternalStreamManagerAndroid::ExternalStreamManagerAndroid() noexcept
: mVm(VirtualMachineEnv::get()) {
if (__builtin_available(android 28, *)) {
DLOG(INFO) << "Using ASurfaceTexture";
slog.d << "Using ASurfaceTexture" << io::endl;
}
}
@@ -255,7 +255,7 @@ void PlatformCocoaGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept
}
bool PlatformCocoaGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) {
SwapChain* readSwapChain) noexcept {
ASSERT_PRECONDITION_NON_FATAL(drawSwapChain == readSwapChain,
"ContextManagerCocoa does not support using distinct draw/read swap chains.");
CocoaGLSwapChain* swapChain = (CocoaGLSwapChain*)drawSwapChain;
@@ -155,7 +155,7 @@ uint32_t PlatformCocoaTouchGL::getDefaultFramebufferObject() noexcept {
}
bool PlatformCocoaTouchGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) {
SwapChain* readSwapChain) noexcept {
ASSERT_PRECONDITION_NON_FATAL(drawSwapChain == readSwapChain,
"PlatformCocoaTouchGL does not support using distinct draw/read swap chains.");
CAEAGLLayer* const glLayer = (__bridge CAEAGLLayer*) drawSwapChain;
@@ -32,9 +32,9 @@
#endif
#include <utils/compiler.h>
#include <utils/Invocable.h>
#include <utils/Logger.h>
#include <utils/debug.h>
#include <utils/Invocable.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <algorithm>
@@ -74,7 +74,7 @@ void PlatformEGL::logEglError(const char* name) noexcept {
}
void PlatformEGL::logEglError(const char* name, EGLint error) noexcept {
LOG(ERROR) << name << " failed with " << getEglErrorName(error);
slog.e << name << " failed with " << getEglErrorName(error) << io::endl;
}
const char* PlatformEGL::getEglErrorName(EGLint error) noexcept {
@@ -101,7 +101,7 @@ void PlatformEGL::clearGlError() noexcept {
// clear GL error that may have been set by previous calls
GLenum const error = glGetError();
if (error != GL_NO_ERROR) {
LOG(WARNING) << "Ignoring pending GL error " << io::hex << error;
slog.w << "Ignoring pending GL error " << io::hex << error << io::endl;
}
}
@@ -142,7 +142,7 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& drive
}
if (UTILS_UNLIKELY(!initialized)) {
LOG(ERROR) << "eglInitialize failed";
slog.e << "eglInitialize failed" << io::endl;
return nullptr;
}
@@ -577,18 +577,18 @@ OpenGLPlatform::ContextType PlatformEGL::getCurrentContextType() const noexcept
}
bool PlatformEGL::makeCurrent(ContextType type,
SwapChain* drawSwapChain, SwapChain* readSwapChain) {
SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept {
SwapChainEGL const* const dsc = static_cast<SwapChainEGL const*>(drawSwapChain);
SwapChainEGL const* const rsc = static_cast<SwapChainEGL const*>(readSwapChain);
EGLContext context = getContextForType(type);
EGLBoolean const success = egl.makeCurrent(context, dsc->sur, rsc->sur);
return success == EGL_TRUE;
return success == EGL_TRUE ? true : false;
}
void PlatformEGL::makeCurrent(SwapChain* drawSwapChain,
SwapChain* readSwapChain,
Invocable<void()> preContextChange,
Invocable<void(size_t index)> postContextChange) {
Invocable<void(size_t index)> postContextChange) noexcept {
assert_invariant(drawSwapChain);
assert_invariant(readSwapChain);
@@ -796,7 +796,7 @@ void PlatformEGL::Config::erase(EGLint name) noexcept {
// ------------------------------------------------------------------------------------------------
EGLBoolean PlatformEGL::EGL::makeCurrent(EGLContext context, EGLSurface drawSurface,
EGLSurface readSurface) {
EGLSurface readSurface) noexcept {
if (UTILS_UNLIKELY((
mCurrentContext != context ||
drawSurface != mCurrentDrawSurface || readSurface != mCurrentReadSurface))) {
@@ -29,12 +29,13 @@
#include <android/native_window.h>
#include <android/hardware_buffer.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/android/PerformanceHintManager.h>
#include <utils/compiler.h>
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <utils/Panic.h>
#include <utils/Log.h>
#include <utils/compiler.h>
#include <utils/ostream.h>
#include <EGL/egl.h>
@@ -134,7 +135,7 @@ static constexpr const std::string_view kNativeWindowInvalidMsg =
bool PlatformEGLAndroid::makeCurrent(ContextType type,
SwapChain* drawSwapChain,
SwapChain* readSwapChain) {
SwapChain* readSwapChain) noexcept {
// fast & safe path
if (UTILS_LIKELY(!mAssertNativeWindowIsValid)) {
@@ -326,7 +327,7 @@ bool PlatformEGLAndroid::setImage(ExternalImageEGLAndroid const* eglExternalImag
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
if (eglImage == EGL_NO_IMAGE_KHR) {
// Handle error
LOG(ERROR) << "Failed to create EGL image";
slog.e << "Failed to create EGL image" << io::endl;
glDeleteTextures(1, &texture->id);
return false;
}
@@ -339,7 +340,7 @@ bool PlatformEGLAndroid::setImage(ExternalImageEGLAndroid const* eglExternalImag
glBindTexture(texture->target, texture->id);
GLenum error = glGetError();
if (UTILS_UNLIKELY(error != GL_NO_ERROR)) {
LOG(ERROR) << "Error after glBindTexture: " << error;
slog.e << "Error after glBindTexture: " << error << io::endl;
glDeleteTextures(1, &texture->id);
eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);
glActiveTexture(prevActiveTexture);
@@ -349,7 +350,7 @@ bool PlatformEGLAndroid::setImage(ExternalImageEGLAndroid const* eglExternalImag
glEGLImageTargetTexture2DOES(texture->target, static_cast<GLeglImageOES>(eglImage));
error = glGetError();
if (UTILS_UNLIKELY(error != GL_NO_ERROR)) {
LOG(ERROR) << "Error after glEGLImageTargetTexture2DOES: " << error;
slog.e << "Error after glEGLImageTargetTexture2DOES: " << error << io::endl;
glDeleteTextures(1, &texture->id);
eglDestroyImageKHR(eglGetCurrentDisplay(), eglImage);
glActiveTexture(prevActiveTexture);
@@ -407,7 +408,7 @@ AcquiredImage PlatformEGLAndroid::transformAcquiredImage(AcquiredImage source) n
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(pHardwareBuffer);
if (!clientBuffer) {
LOG(ERROR) << "Unable to get EGLClientBuffer from AHardwareBuffer.";
slog.e << "Unable to get EGLClientBuffer from AHardwareBuffer." << io::endl;
return {};
}
@@ -426,7 +427,7 @@ AcquiredImage PlatformEGLAndroid::transformAcquiredImage(AcquiredImage source) n
EGLImageKHR eglImage = eglCreateImageKHR(mEGLDisplay,
EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attributes.data());
if (eglImage == EGL_NO_IMAGE_KHR) {
LOG(ERROR) << "eglCreateImageKHR returned no image.";
slog.e << "eglCreateImageKHR returned no image." << io::endl;
return {};
}
@@ -441,7 +442,7 @@ AcquiredImage PlatformEGLAndroid::transformAcquiredImage(AcquiredImage source) n
auto patchedCallback = [](void* image, void* userdata) {
Closure* closure = (Closure*)userdata;
if (eglDestroyImageKHR(closure->display, (EGLImageKHR) image) == EGL_FALSE) {
LOG(ERROR) << "eglDestroyImageKHR failed.";
slog.e << "eglDestroyImageKHR failed." << io::endl;
}
closure->acquiredImage.callback(closure->acquiredImage.image, closure->acquiredImage.userData);
delete closure;
@@ -21,9 +21,9 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/Log.h>
#include <utils/Panic.h>
using namespace utils;
@@ -42,12 +42,12 @@ backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext,
const Platform::DriverConfig& driverConfig) noexcept {
EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_API);
if (UTILS_UNLIKELY(!bindAPI)) {
LOG(ERROR) << "eglBindAPI EGL_OPENGL_API failed";
slog.e << "eglBindAPI EGL_OPENGL_API failed" << io::endl;
return nullptr;
}
int bindBlueGL = bluegl::bind();
if (UTILS_UNLIKELY(bindBlueGL != 0)) {
LOG(ERROR) << "bluegl bind failed";
slog.e << "bluegl bind failed" << io::endl;
return nullptr;
}
@@ -16,7 +16,7 @@
#include <backend/platforms/PlatformGLX.h>
#include <utils/Logger.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <X11/Xlib.h>
@@ -84,7 +84,7 @@ static PFNGLXGETPROCADDRESSPROC getProcAddress;
static bool loadLibraries() {
g_glx.library = dlopen(LIBRARY_GLX, RTLD_LOCAL | RTLD_NOW);
if (!g_glx.library) {
LOG(ERROR) << "Could not find library " << LIBRARY_GLX;
utils::slog.e << "Could not find library " << LIBRARY_GLX << utils::io::endl;
return false;
}
@@ -115,7 +115,7 @@ static bool loadLibraries() {
g_x11.library = dlopen(LIBRARY_X11, RTLD_LOCAL | RTLD_NOW);
if (!g_x11.library) {
LOG(ERROR) << "Could not find library " << LIBRARY_X11;
utils::slog.e << "Could not find library " << LIBRARY_X11 << utils::io::endl;
return false;
}
@@ -134,7 +134,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
// Get the display device
mGLXDisplay = g_x11.openDisplay(NULL);
if (mGLXDisplay == nullptr) {
LOG(ERROR) << "Failed to open X display. (exiting).";
utils::slog.e << "Failed to open X display. (exiting)." << utils::io::endl;
exit(1);
}
@@ -145,7 +145,8 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
r = g_glx.queryContext(mGLXDisplay, sharedCtx, GLX_FBCONFIG_ID, &usedFbId);
if (r != 0) {
LOG(ERROR) << "Failed to get GLX_FBCONFIG_ID from shared GL context.";
utils::slog.e << "Failed to get GLX_FBCONFIG_ID from shared GL context."
<< utils::io::endl;
return nullptr;
}
@@ -153,7 +154,7 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
GLXFBConfig* fbConfigs = g_glx.getFbConfigs(mGLXDisplay, 0, &numConfigs);
if (fbConfigs == nullptr) {
LOG(ERROR) << "Failed to get the available GLXFBConfigs.";
utils::slog.e << "Failed to get the available GLXFBConfigs." << utils::io::endl;
return nullptr;
}
@@ -163,7 +164,8 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
for (int i = 0; i < numConfigs; ++i) {
r = g_glx.getFbConfigAttrib(mGLXDisplay, fbConfigs[i], GLX_FBCONFIG_ID, &fbId);
if (r != 0) {
LOG(ERROR) << "Failed to get GLX_FBCONFIG_ID for entry " << i << ".";
utils::slog.e << "Failed to get GLX_FBCONFIG_ID for entry " << i << "."
<< utils::io::endl;
continue;
}
@@ -174,7 +176,8 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
}
if (fbIndex < 0) {
LOG(ERROR) << "Failed to find an `GLXFBConfig` with the requested ID.";
utils::slog.e << "Failed to find an `GLXFBConfig` with the requested ID."
<< utils::io::endl;
return nullptr;
}
@@ -199,7 +202,8 @@ Driver* PlatformGLX::createDriver(void* sharedGLContext,
getProcAddress((GLubyte*)"glXCreateContextAttribsARB");
if (glXCreateContextAttribs == nullptr) {
LOG(INFO) << "Unable to retrieve function pointer for `glXCreateContextAttribs()`.";
utils::slog.i << "Unable to retrieve function pointer for `glXCreateContextAttribs()`."
<< utils::io::endl;
return nullptr;
}
@@ -262,7 +266,7 @@ void PlatformGLX::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
bool PlatformGLX::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) {
SwapChain* readSwapChain) noexcept {
g_glx.setCurrentContext(mGLXDisplay,
(GLXDrawable)drawSwapChain, (GLXDrawable)readSwapChain, mGLXContext);
return true;
@@ -169,7 +169,7 @@ void PlatformOSMesa::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
bool PlatformOSMesa::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) {
SwapChain* readSwapChain) noexcept {
OSMesaAPI* api = (OSMesaAPI*) mOsMesaApi;
OSMesaSwapchain* impl = (OSMesaSwapchain*) drawSwapChain;
@@ -32,7 +32,7 @@
#include "GL/glext.h"
#include "GL/wglext.h"
#include <utils/Logger.h>
#include <utils/Log.h>
#include <utils/Panic.h>
namespace {
@@ -55,7 +55,8 @@ void reportWindowsError(DWORD dwError) {
0, nullptr
);
LOG(ERROR) << "Windows error code: " << dwError << ". " << lpMessageBuffer;
utils::slog.e << "Windows error code: " << dwError << ". " << lpMessageBuffer
<< utils::io::endl;
LocalFree(lpMessageBuffer);
}
@@ -105,7 +106,7 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
HDC whdc = mWhdc = GetDC(mHWnd);
if (whdc == NULL) {
dwError = GetLastError();
LOG(ERROR) << "CreateWindowA() failed";
utils::slog.e << "CreateWindowA() failed" << utils::io::endl;
goto error;
}
@@ -116,7 +117,8 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
tempContext = wglCreateContext(whdc);
if (!wglMakeCurrent(whdc, tempContext)) {
dwError = GetLastError();
LOG(ERROR) << "wglMakeCurrent() failed, whdc=" << whdc << ", tempContext=" << tempContext;
utils::slog.e << "wglMakeCurrent() failed, whdc=" << whdc << ", tempContext=" <<
tempContext << utils::io::endl;
goto error;
}
@@ -140,7 +142,7 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
}
if (!mContext) {
LOG(ERROR) << "wglCreateContextAttribs() failed, whdc=" << whdc;
utils::slog.e << "wglCreateContextAttribs() failed, whdc=" << whdc << utils::io::endl;
goto error;
}
@@ -150,7 +152,8 @@ Driver* PlatformWGL::createDriver(void* sharedGLContext,
if (!wglMakeCurrent(whdc, mContext)) {
dwError = GetLastError();
LOG(ERROR) << "wglMakeCurrent() failed, whdc=" << whdc << ", mContext=" << mContext;
utils::slog.e << "wglMakeCurrent() failed, whdc=" << whdc << ", mContext=" <<
mContext << utils::io::endl;
goto error;
}
@@ -259,7 +262,7 @@ void PlatformWGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
bool PlatformWGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) {
SwapChain* readSwapChain) noexcept {
ASSERT_PRECONDITION_NON_FATAL(drawSwapChain == readSwapChain,
"PlatformWGL does not support distinct draw/read swap chains.");
@@ -47,7 +47,7 @@ void PlatformWebGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
bool PlatformWebGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) {
SwapChain* readSwapChain) noexcept {
return true;
}
@@ -40,7 +40,7 @@ inline void blitFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect, V
FVK_LOGD << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
<< " layout=" << src.getLayout()
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
<< " layout=" << dst.getLayout();
<< " layout=" << dst.getLayout() << utils::io::endl;
}
VkImageSubresourceRange const srcRange = src.getSubresourceRange();
@@ -80,7 +80,7 @@ inline void resolveFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect
FVK_LOGD << "Fast blit from=" << src.texture->getVkImage() << ",level=" << (int) src.level
<< " layout=" << src.getLayout()
<< " to=" << dst.texture->getVkImage() << ",level=" << (int) dst.level
<< " layout=" << dst.getLayout();
<< " layout=" << dst.getLayout() << utils::io::endl;
}
VkImageSubresourceRange const srcRange = src.getSubresourceRange();
@@ -14,32 +14,49 @@
* limitations under the License.
*/
#include "VulkanBufferProxy.h"
#include "VulkanCommands.h"
#include "VulkanBuffer.h"
#include "VulkanMemory.h"
#include "VulkanBufferCache.h"
#include "VulkanMemory.h"
#include <utils/Panic.h>
using namespace bluevk;
namespace filament::backend {
VulkanBufferProxy::VulkanBufferProxy(VmaAllocator allocator, VulkanStagePool& stagePool,
VulkanBufferCache& bufferCache, VulkanBufferUsage usage, uint32_t numBytes)
: mStagePool(stagePool),
mBufferCache(bufferCache),
mBuffer(mBufferCache.acquire(usage, numBytes)),
VulkanBuffer::VulkanBuffer(VmaAllocator allocator, VulkanStagePool& stagePool,
VkBufferUsageFlags usage, uint32_t numBytes)
: mAllocator(allocator),
mStagePool(stagePool),
mUsage(usage),
mUpdatedOffset(0),
mUpdatedBytes(0) {}
mUpdatedBytes(0) {
// for now make sure that only 1 bit is set in usage
// (because loadFromCpu() assumes that somewhat)
assert_invariant(usage && !(usage & (usage - 1)));
void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* cpuData,
uint32_t byteOffset, uint32_t numBytes) {
// Note: this should be stored within the command buffer before going out of
// scope, so that the command buffer can manage its lifecycle.
fvkmemory::resource_ptr<VulkanStage::Segment> stage = mStagePool.acquireStage(numBytes);
commands.acquire(stage);
stage->copy(0, cpuData, numBytes);
// Create the VkBuffer.
VkBufferCreateInfo bufferInfo {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = numBytes,
.usage = usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT
};
VmaAllocationCreateInfo allocInfo { .usage = VMA_MEMORY_USAGE_GPU_ONLY };
vmaCreateBuffer(mAllocator, &bufferInfo, &allocInfo, &mGpuBuffer, &mGpuMemory, nullptr);
}
VulkanBuffer::~VulkanBuffer() {
vmaDestroyBuffer(mAllocator, mGpuBuffer, mGpuMemory);
}
void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint32_t byteOffset,
uint32_t numBytes) {
VulkanStage const* stage = mStagePool.acquireStage(numBytes);
void* mapped;
vmaMapMemory(mAllocator, stage->memory, &mapped);
memcpy(mapped, cpuData, numBytes);
vmaUnmapMemory(mAllocator, stage->memory);
vmaFlushAllocation(mAllocator, stage->memory, 0, numBytes);
// If there was a previous update, then we need to make sure the following write is properly
// synced with the previous read.
@@ -47,13 +64,13 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
(byteOffset >= mUpdatedOffset && byteOffset <= (mUpdatedOffset + mUpdatedBytes))) {
VkAccessFlags srcAccess = 0;
VkPipelineStageFlags srcStage = 0;
if (getUsage() == VulkanBufferUsage::UNIFORM) {
if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
srcAccess = VK_ACCESS_SHADER_READ_BIT;
srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else if (getUsage() == VulkanBufferUsage::VERTEX) {
} else if (mUsage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) {
srcAccess = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} else if (getUsage() == VulkanBufferUsage::INDEX) {
} else if (mUsage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT) {
srcAccess = VK_ACCESS_INDEX_READ_BIT;
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
}
@@ -64,20 +81,20 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = getVkBuffer(),
.buffer = mGpuBuffer,
.offset = byteOffset,
.size = numBytes,
};
vkCmdPipelineBarrier(commands.buffer(), srcStage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
nullptr, 1, &barrier, 0, nullptr);
vkCmdPipelineBarrier(cmdbuf, srcStage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1,
&barrier, 0, nullptr);
}
VkBufferCopy region = {
.srcOffset = stage->offset(),
.srcOffset = 0,
.dstOffset = byteOffset,
.size = numBytes,
};
vkCmdCopyBuffer(commands.buffer(), stage->buffer(), getVkBuffer(), 1, &region);
vkCmdCopyBuffer(cmdbuf, stage->buffer, mGpuBuffer, 1, &region);
mUpdatedOffset = byteOffset;
mUpdatedBytes = numBytes;
@@ -89,16 +106,16 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
if (getUsage() == VulkanBufferUsage::VERTEX) {
if (mUsage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) {
dstAccessMask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} else if (getUsage() == VulkanBufferUsage::INDEX) {
} else if (mUsage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT) {
dstAccessMask |= VK_ACCESS_INDEX_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} else if (getUsage() == VulkanBufferUsage::UNIFORM) {
} else if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
} else if (getUsage() == VulkanBufferUsage::SHADER_STORAGE) {
} else if (mUsage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
// TODO: implement me
}
@@ -108,21 +125,13 @@ void VulkanBufferProxy::loadFromCpu(VulkanCommandBuffer& commands, const void* c
.dstAccessMask = dstAccessMask,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = getVkBuffer(),
.buffer = mGpuBuffer,
.offset = byteOffset,
.size = numBytes,
};
vkCmdPipelineBarrier(commands.buffer(), VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 0,
nullptr, 1, &barrier, 0, nullptr);
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 0, nullptr, 1,
&barrier, 0, nullptr);
}
VkBuffer VulkanBufferProxy::getVkBuffer() const noexcept {
return mBuffer->getGpuBuffer()->vkbuffer;
}
VulkanBufferUsage VulkanBufferProxy::getUsage() const noexcept {
return mBuffer->getGpuBuffer()->usage;
}
}// namespace filament::backend
} // namespace filament::backend
+21 -22
View File
@@ -17,36 +17,35 @@
#ifndef TNT_FILAMENT_BACKEND_VULKANBUFFER_H
#define TNT_FILAMENT_BACKEND_VULKANBUFFER_H
#include "VulkanContext.h"
#include "VulkanStagePool.h"
#include "VulkanMemory.h"
#include "memory/Resource.h"
#include <functional>
namespace filament::backend {
class VulkanBuffer : public fvkmemory::Resource {
// Encapsulates a Vulkan buffer, its attached DeviceMemory and a staging area.
class VulkanBuffer {
public:
// Because we need to recycle the unused `VulkanGpuBuffer`, we allow for a callback that the
// "Pool" can use to acquire the buffer back.
using OnRecycle = std::function<void(VulkanGpuBuffer const*)>;
VulkanBuffer(VulkanGpuBuffer const* gpuBuffer, OnRecycle&& onRecycleFn)
: mGpuBuffer(gpuBuffer),
mOnRecycleFn(onRecycleFn) {}
~VulkanBuffer() {
if (mOnRecycleFn) {
mOnRecycleFn(mGpuBuffer);
}
VulkanBuffer(VmaAllocator allocator, VulkanStagePool& stagePool, VkBufferUsageFlags usage,
uint32_t numBytes);
~VulkanBuffer();
void loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint32_t byteOffset,
uint32_t numBytes);
VkBuffer getGpuBuffer() const {
return mGpuBuffer;
}
VulkanGpuBuffer const* getGpuBuffer() const { return mGpuBuffer; }
private:
VulkanGpuBuffer const* mGpuBuffer;
OnRecycle mOnRecycleFn;
VmaAllocator mAllocator;
VulkanStagePool& mStagePool;
VmaAllocation mGpuMemory = VK_NULL_HANDLE;
VkBuffer mGpuBuffer = VK_NULL_HANDLE;
VkBufferUsageFlags mUsage = {};
uint32_t mUpdatedOffset = 0;
uint32_t mUpdatedBytes = 0;
};
}// namespace filament::backend
} // namespace filament::backend
#endif// TNT_FILAMENT_BACKEND_VULKANBUFFER_H
#endif // TNT_FILAMENT_BACKEND_VULKANBUFFER_H
@@ -1,207 +0,0 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "VulkanBufferCache.h"
#include "VulkanBuffer.h"
#include "VulkanConstants.h"
#include "VulkanMemory.h"
#include "memory/Resource.h"
#include "memory/ResourceManager.h"
#include <utility>
namespace filament::backend {
namespace {
VkBufferUsageFlags getVkBufferUsage(VulkanBufferUsage usage) {
switch (usage) {
case VulkanBufferUsage::VERTEX:
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
case VulkanBufferUsage::INDEX:
return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
case VulkanBufferUsage::UNIFORM:
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
case VulkanBufferUsage::SHADER_STORAGE:
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
case VulkanBufferUsage::UNKNOWN:
return 0;
}
return 0;
}
}// namespace
VulkanBufferCache::VulkanBufferCache(VulkanContext const& context,
fvkmemory::ResourceManager& resourceManager, VmaAllocator allocator)
: mContext(context),
mResourceManager(resourceManager),
mAllocator(allocator) {}
fvkmemory::resource_ptr<VulkanBuffer> VulkanBufferCache::acquire(VulkanBufferUsage usage,
uint32_t numBytes) noexcept {
assert_invariant(usage != VulkanBufferUsage::UNKNOWN);
BufferPool& bufferPool = getPool(usage);
// First check if an allocation exists whose capacity is greater than or equal to the requested
// size.
auto iter = bufferPool.lower_bound(numBytes);
if (iter != bufferPool.end()) {
VulkanGpuBuffer const* gpuBuffer = iter->second.gpuBuffer;
bufferPool.erase(iter);
return fvkmemory::resource_ptr<VulkanBuffer>::construct(&mResourceManager, gpuBuffer,
[this](VulkanGpuBuffer const* gpuBuffer) { this->release(gpuBuffer); });
}
// We were not able to find a sufficiently large allocation, so create a new one that is
// recycled after being yielded.
VulkanGpuBuffer const* gpuBuffer = allocate(usage, numBytes);
return fvkmemory::resource_ptr<VulkanBuffer>::construct(&mResourceManager, gpuBuffer,
[this](VulkanGpuBuffer const* gpuBuffer) { this->release(gpuBuffer); });
}
void VulkanBufferCache::gc() noexcept {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("VulkanBufferCache::gc");
// If this is one of the first few frames, return early to avoid wrapping unsigned integers.
constexpr uint32_t TIME_BEFORE_EVICTION = 3;
if (++mCurrentFrame <= TIME_BEFORE_EVICTION) {
return;
}
const uint64_t evictionTime = mCurrentFrame - TIME_BEFORE_EVICTION;
// Destroy buffers that have not been used for several frames.
for (auto& bufferPool: mGpuBufferPools) {
for (auto poolIter = bufferPool.begin(); poolIter != bufferPool.end();) {
if (poolIter->second.lastAccessed < evictionTime) {
#if FVK_ENABLED(FVK_DEBUG_VULKAN_BUFFER_CACHE)
FVK_LOGD << "VulkanBufferCache - Destroyed vkBuffer "
<< poolIter->second.gpuBuffer->vkbuffer << " with usage "
<< static_cast<int>(poolIter->second.gpuBuffer->usage) << utils::io::endl;
#endif// FVK_DEBUG_VULKAN_BUFFER_CACHE
destroy(poolIter->second.gpuBuffer);
poolIter = bufferPool.erase(poolIter);
} else {
++poolIter;
}
}
}
FVK_SYSTRACE_END();
}
void VulkanBufferCache::terminate() noexcept {
for (auto& bufferPool: mGpuBufferPools) {
for (auto& poolEntry: bufferPool) {
destroy(poolEntry.second.gpuBuffer);
}
bufferPool.clear();
}
}
void VulkanBufferCache::release(VulkanGpuBuffer const* gpuBuffer) noexcept {
assert_invariant(gpuBuffer != nullptr);
BufferPool& bufferPool = getPool(gpuBuffer->usage);
bufferPool.insert(std::make_pair(gpuBuffer->numBytes, UnusedGpuBuffer{
.lastAccessed = mCurrentFrame,
.gpuBuffer = gpuBuffer,
}));
}
VulkanGpuBuffer const* VulkanBufferCache::allocate(VulkanBufferUsage usage,
uint32_t numBytes) noexcept {
VkBufferCreateInfo const bufferInfo{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = numBytes,
// `VK_BUFFER_USAGE_TRANSFER_DST_BIT` is needed to allow updating the buffer through
// a staging using `vkCmdCopyBuffer`.
.usage = getVkBufferUsage(usage) | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
};
VmaAllocationCreateFlags vmaFlags = 0;
if (usage == VulkanBufferUsage::UNIFORM) {
// In the case of UMA, the uniform buffers will always be mappable
if (mContext.isUnifiedMemoryArchitecture()) {
vmaFlags |= VMA_ALLOCATION_CREATE_MAPPED_BIT |
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
}
}
VulkanGpuBuffer* gpuBuffer = new VulkanGpuBuffer{
.numBytes = numBytes,
.usage = usage,
};
VmaAllocationCreateInfo const allocInfo{
.flags = vmaFlags,
.usage = VMA_MEMORY_USAGE_AUTO,
.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
};
UTILS_UNUSED_IN_RELEASE VkResult result = vmaCreateBuffer(mAllocator, &bufferInfo, &allocInfo,
&gpuBuffer->vkbuffer, &gpuBuffer->vmaAllocation, &gpuBuffer->allocationInfo);
#if FVK_ENABLED(FVK_DEBUG_VULKAN_BUFFER_CACHE)
if (result != VK_SUCCESS) {
FVK_LOGE << "VulkanBufferCache - failed to allocate a new vkBuffer of size " << numBytes
<< " and usage " << static_cast<int>(usage) << ", error: " << result
<< utils::io::endl;
} else {
FVK_LOGD << "VulkanBufferCache - allocated a vkBuffer " << gpuBuffer->vkbuffer
<< " of size " << numBytes << " and usage = " << static_cast<int>(usage)
<< " successfully" << utils::io::endl;
}
#endif// FVK_DEBUG_VULKAN_BUFFER_CACHE
return gpuBuffer;
}
void VulkanBufferCache::destroy(VulkanGpuBuffer const* gpuBuffer) noexcept {
vmaDestroyBuffer(mAllocator, gpuBuffer->vkbuffer, gpuBuffer->vmaAllocation);
delete gpuBuffer;
gpuBuffer = nullptr;
}
VulkanBufferCache::BufferPool& VulkanBufferCache::getPool(VulkanBufferUsage usage) noexcept {
int poolIndex = -1;
switch (usage) {
case VulkanBufferUsage::VERTEX:
poolIndex = 0;
break;
case VulkanBufferUsage::INDEX:
poolIndex = 1;
break;
case VulkanBufferUsage::UNIFORM:
poolIndex = 2;
break;
case VulkanBufferUsage::SHADER_STORAGE:
poolIndex = 3;
break;
case VulkanBufferUsage::UNKNOWN:
PANIC_LOG("There's no pool for buffers with unkown usage.");
break;
}
assert_invariant(poolIndex >= 0 && poolIndex < MAX_POOL_COUNT);
return mGpuBufferPools[poolIndex];
}
}// namespace filament::backend
@@ -1,84 +0,0 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_VULKANBUFFERCACHE_H
#define TNT_FILAMENT_BACKEND_VULKANBUFFERCACHE_H
#include "VulkanBuffer.h"
#include "VulkanContext.h"
#include "VulkanMemory.h"
#include "memory/Resource.h"
#include "memory/ResourceManager.h"
#include <map>
namespace filament::backend {
class VulkanBufferCache {
public:
VulkanBufferCache(VulkanContext const& context, fvkmemory::ResourceManager& resourceManager,
VmaAllocator allocator);
// `VulkanBufferCache` is not copyable.
VulkanBufferCache(const VulkanBufferCache&) = delete;
VulkanBufferCache& operator=(const VulkanBufferCache&) = delete;
// Allocates or reuse a new VkBuffer that is device local.
// In the case of Unified memory architecture, uniform buffers are also host visible.
fvkmemory::resource_ptr<VulkanBuffer> acquire(VulkanBufferUsage usage,
uint32_t numBytes) noexcept;
// Evicts old unused `VulkanGpuBuffer` and bumps the current frame number
void gc() noexcept;
// Destroys all unused `VulkanGpuBuffer`.
// This should be called while the context's VkDevice is still alive.
void terminate() noexcept;
private:
struct UnusedGpuBuffer {
uint64_t lastAccessed;
VulkanGpuBuffer const* gpuBuffer;
};
using BufferPool = std::multimap<uint32_t, UnusedGpuBuffer>;
// Return a `VulkanGpuBuffer` back to its corresponding pool
void release(VulkanGpuBuffer const* gpuBuffer) noexcept;
// Allocate a new VkBuffer from the VMA pool of the corresponding `numBytes` and `usage`.
VulkanGpuBuffer const* allocate(VulkanBufferUsage usage, uint32_t numBytes) noexcept;
// Destroy the corresponding VkBuffer and return the VkDeviceMemory to the VMA pool.
void destroy(VulkanGpuBuffer const* gpuBuffer) noexcept;
BufferPool& getPool(VulkanBufferUsage usage) noexcept;
VulkanContext const& mContext;
fvkmemory::ResourceManager& mResourceManager;
VmaAllocator mAllocator;
// Buffers can be recycled, after they are released. Each type of buffer have its own pool
static constexpr int MAX_POOL_COUNT = 4;
BufferPool mGpuBufferPools[MAX_POOL_COUNT];
// Store the current "time" (really just a frame count) and LRU eviction parameters.
uint64_t mCurrentFrame = 0;
};
}// namespace filament::backend
#endif// TNT_FILAMENT_BACKEND_VULKANBUFFERCACHE_H
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_VULKANBUFFERPROXY_H
#define TNT_FILAMENT_BACKEND_VULKANBUFFERPROXY_H
#include "VulkanBufferCache.h"
#include "VulkanCommands.h"
#include "VulkanContext.h"
#include "VulkanMemory.h"
#include "VulkanStagePool.h"
namespace filament::backend {
// This class acts as a dynamic wrapper for a `VulkanBuffer`. It allows you to modify the
// `VulkanBuffer` it references at runtime, wihtout affecting any external objects.
class VulkanBufferProxy {
public:
VulkanBufferProxy(VmaAllocator allocator, VulkanStagePool& stagePool,
VulkanBufferCache& bufferCache, VulkanBufferUsage usage, uint32_t numBytes);
void loadFromCpu(VulkanCommandBuffer& commands, const void* cpuData, uint32_t byteOffset,
uint32_t numBytes);
VkBuffer getVkBuffer() const noexcept;
VulkanBufferUsage getUsage() const noexcept;
private:
VulkanStagePool& mStagePool;
VulkanBufferCache& mBufferCache;
fvkmemory::resource_ptr<VulkanBuffer> mBuffer;
uint32_t mUpdatedOffset = 0;
uint32_t mUpdatedBytes = 0;
};
}// namespace filament::backend
#endif// TNT_FILAMENT_BACKEND_VULKANBUFFERPROXY_H
@@ -215,7 +215,7 @@ VkSemaphore VulkanCommandBuffer::submit() {
}
FVK_LOGI << ") "
<< " signal=" << mSubmission
<< " fence=" << mFence;
<< " fence=" << mFence << utils::io::endl;
#endif
mFenceStatus->setStatus(VK_NOT_READY);
@@ -224,7 +224,7 @@ VkSemaphore VulkanCommandBuffer::submit() {
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
if (result != VK_SUCCESS) {
FVK_LOGD << "Failed command buffer submission result: " << result;
FVK_LOGD << "Failed command buffer submission result: " << result << utils::io::endl;
}
#endif
assert_invariant(result == VK_SUCCESS);
@@ -490,7 +490,7 @@ void VulkanCommands::pushGroupMarker(char const* str, VulkanGroupMarkers::Timest
mProtectedPool->pushMarker(str, timestamp);
}
#if FVK_ENABLED(FVK_DEBUG_PRINT_GROUP_MARKERS)
FVK_LOGD << "----> " << str;
FVK_LOGD << "----> " << str << utils::io::endl;
#endif
}
@@ -502,7 +502,8 @@ void VulkanCommands::popGroupMarker() {
auto const& startTime = ret.second;
auto const endTime = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = endTime - startTime;
FVK_LOGD << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms";
FVK_LOGD << "<---- " << marker << " elapsed: " << (diff.count() * 1000) << " ms"
<< utils::io::endl;
#else
mPool->popMarker();
#endif // FVK_DEBUG_PRINT_GROUP_MARKERS
+9 -11
View File
@@ -17,7 +17,7 @@
#ifndef TNT_FILAMENT_BACKEND_VULKANCONSTANTS_H
#define TNT_FILAMENT_BACKEND_VULKANCONSTANTS_H
#include <utils/Logger.h>
#include <utils/Log.h>
#include <stdint.h>
@@ -73,16 +73,14 @@
#define FVK_DEBUG_RESOURCE_LEAK 0x00010000
// Set this to enable logging "only" to one output stream. This is useful in the case where we want
// to debug with print statements and want ordered logging (e.g LOG(INFO) and LOG(ERROR) will not
// appear in order of calls).
// to debug with print statements and want ordered logging (e.g slog.i and slog.e will not appear in
// order of calls).
#define FVK_DEBUG_FORCE_LOG_TO_I 0x00020000
// Enable a minimal set of traces to assess the performance of the backend.
// All other debug features must be disabled.
#define FVK_DEBUG_PROFILING 0x00040000
#define FVK_DEBUG_VULKAN_BUFFER_CACHE 0x00080000
// Useful default combinations
#define FVK_DEBUG_EVERYTHING (0xFFFFFFFF & ~FVK_DEBUG_PROFILING)
#define FVK_DEBUG_PERFORMANCE \
@@ -95,7 +93,7 @@
#endif
#ifndef NDEBUG
#define FVK_DEBUG_FLAGS (FVK_DEBUG_PERFORMANCE | FVK_DEBUG_FORWARDED_FLAG | FVK_DEBUG_DEBUG_UTILS | FVK_DEBUG_GROUP_MARKERS | FVK_DEBUG_VALIDATION)
#define FVK_DEBUG_FLAGS (FVK_DEBUG_PERFORMANCE | FVK_DEBUG_FORWARDED_FLAG)
#else
#define FVK_DEBUG_FLAGS 0
#endif
@@ -174,15 +172,15 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION));
#endif
#if FVK_ENABLED(FVK_DEBUG_FORCE_LOG_TO_I)
#define FVK_LOGI LOG(INFO)
#define FVK_LOGI (utils::slog.i)
#define FVK_LOGD FVK_LOGI
#define FVK_LOGE FVK_LOGI
#define FVK_LOGW FVK_LOGI
#else
#define FVK_LOGE LOG(ERROR)
#define FVK_LOGW LOG(WARNING)
#define FVK_LOGD DLOG(INFO)
#define FVK_LOGI LOG(INFO)
#define FVK_LOGE (utils::slog.e)
#define FVK_LOGW (utils::slog.w)
#define FVK_LOGD (utils::slog.d)
#define FVK_LOGI (utils::slog.i)
#endif
// All vkCreate* functions take an optional allocator. For now we select the default allocator by
+5 -5
View File
@@ -71,23 +71,23 @@ struct VulkanRenderPass {
struct VulkanContext {
public:
static uint32_t selectMemoryType(VkPhysicalDeviceMemoryProperties const& memoryProperties,
uint32_t types, VkFlags reqs) {
uint32_t flags, VkFlags reqs) {
for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
if (types & 1) {
if (flags & 1) {
if ((memoryProperties.memoryTypes[i].propertyFlags & reqs) == reqs) {
return i;
}
}
types >>= 1;
flags >>= 1;
}
return (uint32_t) VK_MAX_MEMORY_TYPES;
}
inline uint32_t selectMemoryType(uint32_t types, VkFlags reqs) const {
inline uint32_t selectMemoryType(uint32_t flags, VkFlags reqs) const {
if ((reqs & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0) {
assert_invariant(isProtectedMemorySupported());
}
return selectMemoryType(mMemoryProperties, types, reqs);
return selectMemoryType(mMemoryProperties, flags, reqs);
}
inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const {
@@ -320,7 +320,7 @@ void VulkanDescriptorSetCache::updateBuffer(fvkmemory::resource_ptr<VulkanDescri
uint8_t binding, fvkmemory::resource_ptr<VulkanBufferObject> bufferObject,
VkDeviceSize offset, VkDeviceSize size) noexcept {
VkDescriptorBufferInfo const info = {
.buffer = bufferObject->buffer.getVkBuffer(),
.buffer = bufferObject->buffer.getGpuBuffer(),
.offset = offset,
.range = size,
};
+42 -50
View File
@@ -19,8 +19,7 @@
#include "CommandStreamDispatcher.h"
#include "SystraceProfile.h"
#include "VulkanAsyncHandles.h"
#include "VulkanBufferCache.h"
#include "VulkanBufferProxy.h"
#include "VulkanBuffer.h"
#include "VulkanCommands.h"
#include "VulkanDriverFactory.h"
#include "VulkanHandles.h"
@@ -85,11 +84,7 @@ VmaAllocator createAllocator(VkInstance instance, VkPhysicalDevice physicalDevic
.vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2KHR
#endif
};
VmaAllocatorCreateInfo const allocatorInfo{
// Disable the internal VMA synchronization because the backend is singled threaded.
// Improve CPU performance when using VMA functions. The backend will guarantee that all
// access to VMA is done in a thread safe way.
.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT,
VmaAllocatorCreateInfo const allocatorInfo {
.physicalDevice = physicalDevice,
.device = device,
.pVulkanFunctions = &funcs,
@@ -104,15 +99,15 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallback(VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location,
int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) {
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
FVK_LOGE << "VULKAN ERROR: (" << pLayerPrefix << ") " << pMessage;
FVK_LOGE << "VULKAN ERROR: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
} else {
// TODO: emit best practices warnings about aggressive pipeline barriers.
if (strstr(pMessage, "ALL_GRAPHICS_BIT") || strstr(pMessage, "ALL_COMMANDS_BIT")) {
return VK_FALSE;
}
FVK_LOGW << "VULKAN WARNING: (" << pLayerPrefix << ") " << pMessage;
FVK_LOGW << "VULKAN WARNING: (" << pLayerPrefix << ") " << pMessage << utils::io::endl;
}
FVK_LOGE;
FVK_LOGE << utils::io::endl;
return VK_FALSE;
}
#endif // FVK_ENABLED(FVK_DEBUG_VALIDATION)
@@ -122,16 +117,18 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback(VkDebugUtilsMessageSeverityFla
VkDebugUtilsMessageTypeFlagsEXT types, const VkDebugUtilsMessengerCallbackDataEXT* cbdata,
void* pUserData) {
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
FVK_LOGE << "VULKAN ERROR: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage;
FVK_LOGE << "VULKAN ERROR: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
<< utils::io::endl;
} else {
// TODO: emit best practices warnings about aggressive pipeline barriers.
if (strstr(cbdata->pMessage, "ALL_GRAPHICS_BIT")
|| strstr(cbdata->pMessage, "ALL_COMMANDS_BIT")) {
return VK_FALSE;
}
FVK_LOGW << "VULKAN WARNING: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage;
FVK_LOGW << "VULKAN WARNING: (" << cbdata->pMessageIdName << ") " << cbdata->pMessage
<< utils::io::endl;
}
FVK_LOGE << "";
FVK_LOGE << utils::io::endl;
return VK_FALSE;
}
#endif // FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
@@ -212,8 +209,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
mPlatform->getProtectedGraphicsQueueFamilyIndex(), &mContext),
mPipelineLayoutCache(mPlatform->getDevice()),
mPipelineCache(mPlatform->getDevice()),
mStagePool(mAllocator, &mResourceManager, &mCommands, &mContext.getPhysicalDeviceLimits()),
mBufferCache(context, mResourceManager, mAllocator),
mStagePool(mAllocator, &mCommands),
mFramebufferCache(mPlatform->getDevice()),
mYcbcrConversionCache(mPlatform->getDevice()),
mSamplerCache(mPlatform->getDevice()),
@@ -274,18 +270,20 @@ Driver* VulkanDriver::create(VulkanPlatform* platform, VulkanContext const& cont
// VulkanRenderTarget : 312 few
// -- less than or equal to 312 bytes
FVK_LOGD << "VulkanSwapChain: " << sizeof(VulkanSwapChain);
FVK_LOGD << "VulkanBufferObject: " << sizeof(VulkanBufferObject);
FVK_LOGD << "VulkanVertexBuffer: " << sizeof(VulkanVertexBuffer);
FVK_LOGD << "VulkanVertexBufferInfo: " << sizeof(VulkanVertexBufferInfo);
FVK_LOGD << "VulkanIndexBuffer: " << sizeof(VulkanIndexBuffer);
FVK_LOGD << "VulkanRenderPrimitive: " << sizeof(VulkanRenderPrimitive);
FVK_LOGD << "VulkanTexture: " << sizeof(VulkanTexture);
FVK_LOGD << "VulkanTimerQuery: " << sizeof(VulkanTimerQuery);
FVK_LOGD << "HwStream: " << sizeof(HwStream);
FVK_LOGD << "VulkanRenderTarget: " << sizeof(VulkanRenderTarget);
FVK_LOGD << "VulkanFence: " << sizeof(VulkanFence);
FVK_LOGD << "VulkanProgram: " << sizeof(VulkanProgram);
FVK_LOGD
<< "\nVulkanSwapChain: " << sizeof(VulkanSwapChain)
<< "\nVulkanBufferObject: " << sizeof(VulkanBufferObject)
<< "\nVulkanVertexBuffer: " << sizeof(VulkanVertexBuffer)
<< "\nVulkanVertexBufferInfo: " << sizeof(VulkanVertexBufferInfo)
<< "\nVulkanIndexBuffer: " << sizeof(VulkanIndexBuffer)
<< "\nVulkanRenderPrimitive: " << sizeof(VulkanRenderPrimitive)
<< "\nVulkanTexture: " << sizeof(VulkanTexture)
<< "\nVulkanTimerQuery: " << sizeof(VulkanTimerQuery)
<< "\nHwStream: " << sizeof(HwStream)
<< "\nVulkanRenderTarget: " << sizeof(VulkanRenderTarget)
<< "\nVulkanFence: " << sizeof(VulkanFence)
<< "\nVulkanProgram: " << sizeof(VulkanProgram)
<< utils::io::endl;
#endif
assert_invariant(platform);
@@ -330,6 +328,7 @@ void VulkanDriver::terminate() {
// descriptorSetLayoutCache
mExternalImageManager.terminate();
mStagePool.terminate();
mPipelineCache.terminate();
mFramebufferCache.terminate();
mSamplerCache.terminate();
@@ -340,15 +339,6 @@ void VulkanDriver::terminate() {
// Before terminating ResourceManager, we must make sure all of the resource_ptrs have been unset.
mResourceManager.terminate();
// Must come after `mResourceManager`.
// Before terminating the memory pool, we must make sure all the VulkanBufferMemory are yielded
// back to the pool.
mBufferCache.terminate();
// Before terminating stagePool, we need all resources to have been
// reclaimed, as they perform cleanup within the stage pool.
mStagePool.terminate();
#if FVK_ENABLED(FVK_DEBUG_RESOURCE_LEAK)
mResourceManager.print();
#endif
@@ -381,7 +371,6 @@ void VulkanDriver::collectGarbage() {
mCommands.gc();
mDescriptorSetCache.gc();
mStagePool.gc();
mBufferCache.gc();
mFramebufferCache.gc();
mPipelineCache.gc();
@@ -525,7 +514,7 @@ void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType ele
FVK_SYSTRACE_SCOPE();
auto elementSize = (uint8_t) getElementTypeSize(elementType);
auto ib = resource_ptr<VulkanIndexBuffer>::make(&mResourceManager, ibh, mAllocator, mStagePool,
mBufferCache, elementSize, indexCount);
elementSize, indexCount);
ib.inc();
}
@@ -542,7 +531,7 @@ void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byte
BufferObjectBinding bindingType, BufferUsage usage) {
FVK_SYSTRACE_SCOPE();
auto bo = resource_ptr<VulkanBufferObject>::make(&mResourceManager, boh, mAllocator, mStagePool,
mBufferCache, byteCount, bindingType);
byteCount, bindingType);
bo.inc();
}
@@ -795,12 +784,14 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
mResourceManager.gc();
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it";
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it"
<< utils::io::endl;
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
}
if (flags & backend::SWAP_CHAIN_CONFIG_PROTECTED_CONTENT) {
if (!isProtectedContentSupported()) {
FVK_LOGW << "protected swapchain requested, but Platform does not support it";
FVK_LOGW << "protected swapchain requested, but Platform does not support it"
<< utils::io::endl;
}
}
auto swapChain = resource_ptr<VulkanSwapChain>::make(&mResourceManager, sch, mPlatform,
@@ -811,7 +802,8 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
uint32_t height, uint64_t flags) {
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it";
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it"
<< utils::io::endl;
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
}
assert_invariant(width > 0 && height > 0 && "Vulkan requires non-zero swap chain dimensions.");
@@ -1231,7 +1223,7 @@ void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor
VulkanCommandBuffer& commands = mCommands.get();
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
commands.acquire(ib);
ib->buffer.loadFromCpu(commands, p.buffer, byteOffset, p.size);
ib->buffer.loadFromCpu(commands.buffer(), p.buffer, byteOffset, p.size);
scheduleDestroy(std::move(p));
}
@@ -1246,7 +1238,7 @@ void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescript
auto bo = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
commands.acquire(bo);
bo->buffer.loadFromCpu(commands, bd.buffer, byteOffset, bd.size);
bo->buffer.loadFromCpu(commands.buffer(), bd.buffer, byteOffset, bd.size);
scheduleDestroy(std::move(bd));
}
@@ -1257,7 +1249,7 @@ void VulkanDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> boh,
auto bo = resource_ptr<VulkanBufferObject>::cast(&mResourceManager, boh);
commands.acquire(bo);
// TODO: implement unsynchronized version
bo->buffer.loadFromCpu(commands, bd.buffer, byteOffset, bd.size);
bo->buffer.loadFromCpu(commands.buffer(), bd.buffer, byteOffset, bd.size);
scheduleDestroy(std::move(bd));
}
@@ -1299,7 +1291,7 @@ TimerQueryResult VulkanDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint
uint64_t const end = results.endTime;
if (begin >= end) {
// TODO: queries might have ran on different command buffers.
FVK_LOGW << "Timestamps are not monotonically increasing. ";
FVK_LOGW << "Timestamps are not monotonically increasing. " << utils::io::endl;
*elapsedTime = 0;
return TimerQueryResult::ERROR;
}
@@ -1630,8 +1622,8 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
mReadPixels.run(
srcTarget, x, y, width, height, mPlatform->getGraphicsQueueFamilyIndex(),
std::move(pbd),
[&context = mContext](uint32_t types, VkFlags reqs) {
return context.selectMemoryType(types, reqs);
[&context = mContext](uint32_t reqs, VkFlags flags) {
return context.selectMemoryType(reqs, flags);
},
[this](PixelBufferDescriptor&& pbd) {
scheduleDestroy(std::move(pbd));
@@ -1906,7 +1898,7 @@ void VulkanDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
// avoid rebinding these if they are already bound, but since we do not (yet) support subranges
// it would be rare for a client to make consecutive draw calls with the same render primitive.
vkCmdBindVertexBuffers(cmdbuffer, 0, bufferCount, buffers, offsets);
vkCmdBindIndexBuffer(cmdbuffer, prim->indexBuffer->buffer.getVkBuffer(), 0,
vkCmdBindIndexBuffer(cmdbuffer, prim->indexBuffer->buffer.getGpuBuffer(), 0,
prim->indexBuffer->indexType);
}
@@ -2037,7 +2029,7 @@ void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, cons
assert_invariant(inRenderPass);
inRenderPass = false;
} else if (inRenderPass && OUTSIDE_COMMANDS.find(command) != OUTSIDE_COMMANDS.end()) {
FVK_LOGE << command.data() << " issued inside a render pass.";
FVK_LOGE << command.data() << " issued inside a render pass." << utils::io::endl;
}
#endif
}
+1 -4
View File
@@ -18,17 +18,15 @@
#define TNT_FILAMENT_BACKEND_VULKANDRIVER_H
#include "VulkanBlitter.h"
#include "VulkanBufferCache.h"
#include "VulkanConstants.h"
#include "VulkanContext.h"
#include "VulkanFboCache.h"
#include "VulkanHandles.h"
#include "VulkanMemory.h"
#include "VulkanPipelineCache.h"
#include "VulkanQueryManager.h"
#include "VulkanReadPixels.h"
#include "VulkanSamplerCache.h"
#include "VulkanStagePool.h"
#include "VulkanQueryManager.h"
#include "VulkanYcbcrConversionCache.h"
#include "vulkan/VulkanDescriptorSetCache.h"
#include "vulkan/VulkanDescriptorSetLayoutCache.h"
@@ -140,7 +138,6 @@ private:
VulkanPipelineLayoutCache mPipelineLayoutCache;
VulkanPipelineCache mPipelineCache;
VulkanStagePool mStagePool;
VulkanBufferCache mBufferCache;
VulkanFboCache mFramebufferCache;
VulkanYcbcrConversionCache mYcbcrConversionCache;
VulkanSamplerCache mSamplerCache;
@@ -100,7 +100,8 @@ VkFramebuffer VulkanFboCache::getFramebuffer(FboKey const& config) noexcept {
<< "for render pass " << config.renderPass << ", "
<< "samples = " << int(config.samples) << ", "
<< "depth = " << (config.depth ? 1 : 0) << ", "
<< "attachmentCount = " << attachmentCount;
<< "attachmentCount = " << attachmentCount
<< utils::io::endl;
#endif
VkFramebufferCreateInfo info {
@@ -340,7 +341,8 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept
<< "needsResolveMask = " << int(config.needsResolveMask) << ", "
<< "usesLazilyAllocatedMemory = " << int(config.usesLazilyAllocatedMemory) << ", "
<< "viewCount = " << int(config.viewCount) << ", "
<< "colorAttachmentCount[0] = " << subpasses[0].colorAttachmentCount;
<< "colorAttachmentCount[0] = " << subpasses[0].colorAttachmentCount
<< utils::io::endl;
#endif
return renderPass;
@@ -287,7 +287,7 @@ VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
FVK_LOGD << "Created VulkanProgram " << builder << ", shaders = (" << modules[0]
<< ", " << modules[1] << ")";
<< ", " << modules[1] << ")" << utils::io::endl;
#endif
}
@@ -583,22 +583,22 @@ void VulkanVertexBuffer::setBuffer(fvkmemory::resource_ptr<VulkanBufferObject> b
int8_t const* const attribToBuffer = vbi->getAttributeToBuffer();
for (uint8_t attribIndex = 0; attribIndex < count; attribIndex++) {
if (attribToBuffer[attribIndex] == static_cast<int8_t>(index)) {
vkbuffers[attribIndex] = bufferObject->buffer.getVkBuffer();
vkbuffers[attribIndex] = bufferObject->buffer.getGpuBuffer();
}
}
mResources.push_back(bufferObject);
}
VulkanBufferObject::VulkanBufferObject(VmaAllocator allocator, VulkanStagePool& stagePool,
VulkanBufferCache& bufferCache, uint32_t byteCount, BufferObjectBinding bindingType)
uint32_t byteCount, BufferObjectBinding bindingType)
: HwBufferObject(byteCount),
buffer(allocator, stagePool, bufferCache, getBufferObjectUsage(bindingType), byteCount),
buffer(allocator, stagePool, getBufferObjectUsage(bindingType), byteCount),
bindingType(bindingType) {}
VulkanRenderPrimitive::VulkanRenderPrimitive(PrimitiveType pt,
fvkmemory::resource_ptr<VulkanVertexBuffer> vb,
fvkmemory::resource_ptr<VulkanIndexBuffer> ib)
: HwRenderPrimitive{ .type = pt },
: HwRenderPrimitive{.type = pt},
vertexBuffer(vb),
indexBuffer(ib) {}
+18 -21
View File
@@ -21,21 +21,20 @@
#include "DriverBase.h"
#include "VulkanAsyncHandles.h"
#include "VulkanBufferCache.h"
#include "VulkanBufferProxy.h"
#include "VulkanBuffer.h"
#include "VulkanFboCache.h"
#include "VulkanSwapChain.h"
#include "VulkanTexture.h"
#include "vulkan/memory/Resource.h"
#include "vulkan/utils/Definitions.h"
#include "vulkan/utils/StaticVector.h"
#include "vulkan/utils/Definitions.h"
#include <backend/Program.h>
#include <utils/bitset.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Mutex.h>
#include <utils/StructureOfArrays.h>
#include <utils/bitset.h>
#include <array>
@@ -429,22 +428,21 @@ private:
};
struct VulkanIndexBuffer : public HwIndexBuffer, fvkmemory::Resource {
VulkanIndexBuffer(VmaAllocator allocator, VulkanStagePool& stagePool,
VulkanBufferCache& bufferCache, uint8_t elementSize, uint32_t indexCount)
VulkanIndexBuffer(VmaAllocator allocator, VulkanStagePool& stagePool, uint8_t elementSize,
uint32_t indexCount)
: HwIndexBuffer(elementSize, indexCount),
buffer(allocator, stagePool, bufferCache, VulkanBufferUsage::INDEX,
elementSize * indexCount),
buffer(allocator, stagePool, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, elementSize * indexCount),
indexType(elementSize == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32) {}
VulkanBufferProxy buffer;
VulkanBuffer buffer;
const VkIndexType indexType;
};
struct VulkanBufferObject : public HwBufferObject, fvkmemory::Resource {
VulkanBufferObject(VmaAllocator allocator, VulkanStagePool& stagePool,
VulkanBufferCache& bufferCache, uint32_t byteCount, BufferObjectBinding bindingType);
VulkanBufferObject(VmaAllocator allocator, VulkanStagePool& stagePool, uint32_t byteCount,
BufferObjectBinding bindingType);
VulkanBufferProxy buffer;
VulkanBuffer buffer;
const BufferObjectBinding bindingType;
};
@@ -457,19 +455,18 @@ struct VulkanRenderPrimitive : public HwRenderPrimitive, fvkmemory::Resource {
fvkmemory::resource_ptr<VulkanIndexBuffer> indexBuffer;
};
inline constexpr VulkanBufferUsage getBufferObjectUsage(BufferObjectBinding bindingType) noexcept {
switch (bindingType) {
inline constexpr VkBufferUsageFlagBits getBufferObjectUsage(
BufferObjectBinding bindingType) noexcept {
switch(bindingType) {
case BufferObjectBinding::VERTEX:
return VulkanBufferUsage::VERTEX;
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
case BufferObjectBinding::UNIFORM:
return VulkanBufferUsage::UNIFORM;
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
case BufferObjectBinding::SHADER_STORAGE:
return VulkanBufferUsage::SHADER_STORAGE;
// when adding more buffer-types here, make sure to update VulkanBuffer::loadFromCpu()
// if necessary.
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
// when adding more buffer-types here, make sure to update VulkanBuffer::loadFromCpu()
// if necessary.
}
return VulkanBufferUsage::UNKNOWN;
}
} // namespace filament::backend
@@ -37,24 +37,4 @@ VK_DEFINE_HANDLE(VmaAllocator)
VK_DEFINE_HANDLE(VmaAllocation)
VK_DEFINE_HANDLE(VmaPool)
namespace filament::backend {
enum class VulkanBufferUsage : uint8_t {
UNKNOWN,
VERTEX,
INDEX,
UNIFORM,
SHADER_STORAGE,
};
struct VulkanGpuBuffer {
VkBuffer vkbuffer = VK_NULL_HANDLE;
VmaAllocation vmaAllocation = VK_NULL_HANDLE;
VmaAllocationInfo allocationInfo;
uint32_t numBytes = 0;
VulkanBufferUsage usage = VulkanBufferUsage::UNKNOWN;
};
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_VULKANMEMORY_H
@@ -218,7 +218,8 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
FVK_LOGD << "vkCreateGraphicsPipelines with shaders = ("
<< shaderStages[0].module << ", " << shaderStages[1].module << ")";
<< shaderStages[0].module << ", " << shaderStages[1].module << ")"
<< utils::io::endl;
#endif
PipelineCacheEntry cacheEntry = {
.lastUsed = mCurrentTime,
@@ -227,7 +228,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
VKALLOC, &cacheEntry.handle);
assert_invariant(error == VK_SUCCESS);
if (error != VK_SUCCESS) {
FVK_LOGE << "vkCreateGraphicsPipelines error " << error;
FVK_LOGE << "vkCreateGraphicsPipelines error " << error << utils::io::endl;
return nullptr;
}
return &mPipelines.emplace(mPipelineRequirements, cacheEntry).first.value();
@@ -241,7 +242,7 @@ void VulkanPipelineCache::bindProgram(fvkmemory::resource_ptr<VulkanProgram> pro
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
if (mPipelineRequirements.shaders[0] == VK_NULL_HANDLE ||
mPipelineRequirements.shaders[1] == VK_NULL_HANDLE) {
FVK_LOGE << "Binding missing shader: " << program->name.c_str();
FVK_LOGE << "Binding missing shader: " << program->name.c_str() << utils::io::endl;
}
#endif
}
@@ -42,7 +42,7 @@ fvkmemory::resource_ptr<VulkanTimerQuery> VulkanQueryManager::getNextQuery(
fvkmemory::ResourceManager* resourceManager) {
auto unused = ~mUsed;
if (unused.empty()) {
FVK_LOGE << "More than " << mUsed.size() << " timers are not supported.";
FVK_LOGE << "More than " << mUsed.size() << " timers are not supported." << utils::io::endl;
return {};
}
@@ -143,7 +143,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
mTaskHandler = std::make_unique<TaskHandler>();
}
VkCommandPool const cmdpool = mCommandPool;
VkCommandPool& cmdpool = mCommandPool;
fvkmemory::resource_ptr<VulkanTexture> srcTexture = srcTarget->getColor0().texture;
assert_invariant(srcTexture);
@@ -152,17 +152,17 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
= srcFormat == VK_FORMAT_B8G8R8A8_UNORM || srcFormat == VK_FORMAT_B8G8R8A8_SRGB;
// Create a host visible, linearly tiled image as a staging area.
VkImageCreateInfo const imageInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.format = srcFormat,
.extent = { width, height, 1 },
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_LINEAR,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
VkImageCreateInfo const imageInfo{
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.format = srcFormat,
.extent = {width, height, 1},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_LINEAR,
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
};
VkImage stagingImage;
@@ -171,7 +171,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
#if FVK_ENABLED(FVK_DEBUG_READ_PIXELS)
FVK_LOGD << "readPixels created image=" << stagingImage
<< " to copy from image=" << srcTexture->getVkImage()
<< " src-layout=" << srcTexture->getLayout(0, 0);
<< " src-layout=" << srcTexture->getLayout(0, 0) << utils::io::endl;
#endif
VkMemoryRequirements memReqs;
@@ -188,27 +188,28 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
memoryTypeIndex = selectMemoryFunc(memReqs.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
FVK_LOGW
<< "readPixels is slow because VK_MEMORY_PROPERTY_HOST_CACHED_BIT is not available";
<< "readPixels is slow because VK_MEMORY_PROPERTY_HOST_CACHED_BIT is not available"
<< utils::io::endl;
}
FILAMENT_CHECK_POSTCONDITION(memoryTypeIndex < VK_MAX_MEMORY_TYPES)
<< "VulkanReadPixels: unable to find a memory type that meets requirements.";
VkMemoryAllocateInfo const allocInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = memReqs.size,
.memoryTypeIndex = memoryTypeIndex,
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = memReqs.size,
.memoryTypeIndex = memoryTypeIndex,
};
vkAllocateMemory(device, &allocInfo, VKALLOC, &stagingMemory);
vkBindImageMemory(device, stagingImage, stagingMemory, 0);
VkCommandBuffer cmdbuffer;
VkCommandBufferAllocateInfo const allocateInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = cmdpool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
VkCommandBufferAllocateInfo const allocateInfo{
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = cmdpool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
};
vkAllocateCommandBuffers(device, &allocateInfo, &cmdbuffer);
@@ -303,8 +304,9 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
cmdpool, cmdbuffer, pUserBuffer,
fence = readCompleteFence]() mutable {
VkResult status = vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
// Fence hasn't been reached. Try waiting again.
if (status != VK_SUCCESS) {
FVK_LOGE << "Failed to wait for readPixels fence";
FVK_LOGE << "Failed to wait for readPixels fence" << utils::io::endl;
return;
}
@@ -322,7 +324,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
fvkutils::getComponentCount(srcFormat), srcPixels,
static_cast<int>(subResourceLayout.rowPitch), static_cast<int>(width),
static_cast<int>(height), swizzle)) {
FVK_LOGE << "Unsupported PixelDataFormat or PixelDataType";
FVK_LOGE << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl;
}
vkUnmapMemory(device, stagingMemory);
+56 -129
View File
@@ -28,119 +28,46 @@ static constexpr uint32_t TIME_BEFORE_EVICTION = 3;
namespace filament::backend {
namespace {
// Note: these are temporary values, they will be configurable.
static constexpr uint32_t MAX_EMPTY_STAGES_TO_RETAIN = 1;
constexpr uint32_t STAGE_SIZE = 1048576;
}// namespace
fvkmemory::resource_ptr<VulkanStage::Segment> VulkanStage::acquireSegment(
fvkmemory::ResourceManager* resManager, uint32_t numBytes) {
auto segment = fvkmemory::resource_ptr<Segment>::construct(resManager, mAllocator, this,
mCurrentOffset, [this](uint32_t offset) { mSegments.erase(offset); });
mSegments.insert({ mCurrentOffset, segment.get() });
// constexpr uint32_t BLOCK_SIZE = 16;
// uint32_t const additional = BLOCK_SIZE - (numBytes % BLOCK_SIZE);
// numBytes += (additional != BLOCK_SIZE ? additional : 0);
mCurrentOffset += numBytes;
return segment;
}
VkResult VulkanStage::Segment::copy(size_t dstOffset, void const* src, size_t writeSize) {
// uint8_t* mapped = ((uint8_t*) mapping()) + dstOffset;
// memcpy(mapped, src, writeSize);
// return vmaFlushAllocation(mAllocator, memory(), offset() + dstOffset, writeSize);
return vmaCopyMemoryToAllocation(mAllocator, src, memory(), offset() + dstOffset, writeSize);
}
VulkanStagePool::VulkanStagePool(VmaAllocator allocator, fvkmemory::ResourceManager* resManager,
VulkanCommands* commands, const VkPhysicalDeviceLimits* deviceLimits)
VulkanStagePool::VulkanStagePool(VmaAllocator allocator, VulkanCommands* commands)
: mAllocator(allocator),
mResManager(resManager),
mCommands(commands),
mDeviceLimits(deviceLimits) {}
mCommands(commands) {}
fvkmemory::resource_ptr<VulkanStage::Segment> VulkanStagePool::acquireStage(uint32_t numBytes) {
// Apply alignment to the byte count to ensure that, when we later flush
// data written by the host, we only flush the atoms that we modified, and
// no adjacent atoms.
numBytes = alignToNonCoherentAtomSize(numBytes);
// First check if a stage segment exists whose capacity is greater than or
// equal to the requested size.
auto iter = mStages.lower_bound(numBytes);
VulkanStage* pStage;
if (iter != mStages.end()) {
pStage = iter->second;
mStages.erase(iter);
} else {
pStage = allocateNewStage(std::max(numBytes, STAGE_SIZE));
VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) {
// First check if a stage exists whose capacity is greater than or equal to the requested size.
auto iter = mFreeStages.lower_bound(numBytes);
if (iter != mFreeStages.end()) {
auto stage = iter->second;
mFreeStages.erase(iter);
stage->lastAccessed = mCurrentFrame;
mUsedStages.push_back(stage);
return stage;
}
// We were not able to find a sufficiently large stage, so create a new one.
VulkanStage* stage = new VulkanStage({
.memory = VK_NULL_HANDLE,
.buffer = VK_NULL_HANDLE,
.capacity = numBytes,
.lastAccessed = mCurrentFrame,
});
// Note: this allocation updates `currentOffset` and `segments` within
// the parent stage. When destroyed, it will update `segments`.
fvkmemory::resource_ptr<VulkanStage::Segment> pSegment = pStage->acquireSegment(mResManager, numBytes);
// Update the stage's metadata, and reinsert it with the remaining segment
// capacity.
uint32_t spaceRemaining = pStage->capacity() - pStage->currentOffset();
mStages.insert({ spaceRemaining, pStage });
return pSegment;
}
uint32_t VulkanStagePool::alignToNonCoherentAtomSize(uint32_t bytes) {
VkDeviceSize alignment = mDeviceLimits->nonCoherentAtomSize;
if (alignment == 0) {
return bytes;
}
uint32_t remainder = bytes % alignment;
return remainder == 0 ? bytes : bytes + (alignment - remainder);
}
VulkanStage* VulkanStagePool::allocateNewStage(uint32_t capacity) {
VkBufferCreateInfo bufferInfo{
// Create the VkBuffer.
mUsedStages.push_back(stage);
VkBufferCreateInfo bufferInfo {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = alignToNonCoherentAtomSize(capacity),
.size = numBytes,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
};
VmaAllocationCreateInfo allocInfo { .usage = VMA_MEMORY_USAGE_CPU_ONLY };
VkBuffer buffer;
VmaAllocation memory;
VkResult result =
vmaCreateBuffer(mAllocator, &bufferInfo, &allocInfo, &buffer, &memory, nullptr);
UTILS_UNUSED_IN_RELEASE VkResult result = vmaCreateBuffer(mAllocator, &bufferInfo,
&allocInfo, &stage->buffer, &stage->memory, nullptr);
#if FVK_ENABLED(FVK_DEBUG_STAGING_ALLOCATION)
if (result != VK_SUCCESS) {
FVK_LOGE << "Allocation error: " << result;
} else {
FVK_LOGD << "Allocated stage with hndl " << buffer;
FVK_LOGE << "Allocation error: " << result << utils::io::endl;
}
#endif
void* pMapping = nullptr;
if (result == VK_SUCCESS) {
result = vmaMapMemory(mAllocator, memory, &pMapping);
#if FVK_ENABLED(FVK_DEBUG_STAGING_ALLOCATION)
if (result != VK_SUCCESS) {
FVK_LOGE << "Memory mapping erryr: " << result << utils::io::endl;
}
#endif
}
return new VulkanStage(mAllocator, memory, buffer, capacity, pMapping);
}
void VulkanStagePool::destroyStage(VulkanStage const*&& stage) {
assert(stage->isSafeToReset()); // Ensure all segments have been reset already.
vmaUnmapMemory(mAllocator, stage->memory());
vmaDestroyBuffer(mAllocator, stage->buffer(), stage->memory());
delete stage;
return stage;
}
VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, PixelDataType type,
@@ -214,34 +141,27 @@ void VulkanStagePool::gc() noexcept {
}
const uint64_t evictionTime = mCurrentFrame - TIME_BEFORE_EVICTION;
decltype(mStages) freeStages;
freeStages.swap(mStages);
uint8_t freeStageCount = 0; // Assuming we'll never have > 255 free stages
for (auto& pair : freeStages) {
// First, find any stages that have no segments within them.
if (pair.second->isSafeToReset()) {
if (++freeStageCount > MAX_EMPTY_STAGES_TO_RETAIN) {
#if FVK_ENABLED(FVK_DEBUG_STAGING_ALLOCATION)
FVK_LOGD << "Destroying a staging buffer with hndl " << pair.second->buffer()
<< utils::io::endl;
#endif
destroyStage(std::move(pair.second));
continue;
}
#if FVK_ENABLED(FVK_DEBUG_STAGING_ALLOCATION)
if (pair.first == 0) {
FVK_LOGD << "Recycling an unused staging buffer with hndl " << pair.second->buffer()
<< utils::io::endl;
}
#endif
// Note - this segment is free, make sure the structure is cleared
// and reinsert it into our free stage list.
pair.second->reset();
mStages.insert({ pair.second->capacity(), pair.second });
// Destroy buffers that have not been used for several frames.
decltype(mFreeStages) freeStages;
freeStages.swap(mFreeStages);
for (auto pair : freeStages) {
if (pair.second->lastAccessed < evictionTime) {
vmaDestroyBuffer(mAllocator, pair.second->buffer, pair.second->memory);
delete pair.second;
} else {
mStages.insert(pair);
mFreeStages.insert(pair);
}
}
// Reclaim buffers that are no longer being used by any command buffer.
decltype(mUsedStages) usedStages;
usedStages.swap(mUsedStages);
for (auto stage : usedStages) {
if (stage->lastAccessed < evictionTime) {
stage->lastAccessed = mCurrentFrame;
mFreeStages.insert(std::make_pair(stage->capacity, stage));
} else {
mUsedStages.push_back(stage);
}
}
@@ -272,10 +192,17 @@ void VulkanStagePool::gc() noexcept {
}
void VulkanStagePool::terminate() noexcept {
for (auto& pair : mStages) {
destroyStage(std::move(pair.second));
for (auto stage : mUsedStages) {
vmaDestroyBuffer(mAllocator, stage->buffer, stage->memory);
delete stage;
}
mStages.clear();
mUsedStages.clear();
for (auto pair : mFreeStages) {
vmaDestroyBuffer(mAllocator, pair.second->buffer, pair.second->memory);
delete pair.second;
}
mFreeStages.clear();
for (auto image : mUsedImages) {
vmaDestroyImage(mAllocator, image->image, image->memory);
+15 -129
View File
@@ -17,11 +17,8 @@
#ifndef TNT_FILAMENT_BACKEND_VULKANSTAGEPOOL_H
#define TNT_FILAMENT_BACKEND_VULKANSTAGEPOOL_H
#include "VulkanMemory.h"
#include "backend/DriverEnums.h"
#include "vulkan/memory/Resource.h"
#include "vulkan/memory/ResourceManager.h"
#include "vulkan/memory/ResourcePointer.h"
#include "VulkanMemory.h"
#include <map>
#include <unordered_set>
@@ -31,99 +28,12 @@ namespace filament::backend {
class VulkanCommands;
// Object representing a shared CPU-GPU staging area, which can be subdivided
// into smaller buffers as needed.
class VulkanStage {
public:
VulkanStage(VmaAllocator allocator, VmaAllocation memory, VkBuffer buffer, uint32_t capacity,
void* mapping)
: mAllocator(allocator),
mMemory(memory),
mBuffer(buffer),
mCapacity(capacity),
mMapping(mapping) {}
~VulkanStage() = default;
VulkanStage(const VulkanStage& other) = delete;
VulkanStage(VulkanStage&& other) = delete;
VulkanStage& operator=(const VulkanStage& other) = delete;
VulkanStage& operator=(VulkanStage&& other) = delete;
class Segment : public fvkmemory::Resource {
public:
using OnRecycle = std::function<void(uint32_t offset)>;
Segment(VmaAllocator allocator, VulkanStage* parentStage, uint32_t offset,
OnRecycle&& onRecycleFn)
: mAllocator(allocator),
mParentStage(parentStage),
mOffset(offset),
mOnRecycleFn(onRecycleFn) {}
~Segment() {
if (mOnRecycleFn) {
mOnRecycleFn(offset());
}
}
// Should not be copying this around.
Segment(const Segment& other) = delete;
Segment(Segment&& other) = delete;
Segment& operator=(const Segment& other) = delete;
Segment& operator=(Segment&& other) = delete;
inline VkBuffer buffer() const { return mParentStage->buffer(); }
inline VmaAllocation memory() const { return mParentStage->memory(); }
inline uint32_t offset() const { return mOffset; }
VkResult copy(size_t dstOffset, void const* src, size_t writeSize);
inline void* mapping() const {
return reinterpret_cast<void*>(
reinterpret_cast<char*>(mParentStage->mapping()) + offset());
}
private:
// Ensure parent class can access the terminate method.
friend class VulkanStage;
VmaAllocator const mAllocator;
VulkanStage* const mParentStage;
uint32_t const mOffset;
OnRecycle mOnRecycleFn;
};
inline VmaAllocation memory() const { return mMemory; }
inline VkBuffer buffer() const { return mBuffer; }
inline uint32_t capacity() const { return mCapacity; }
inline void* mapping() const { return mMapping; }
inline uint32_t currentOffset() { return mCurrentOffset; }
inline bool isSafeToReset() const { return mSegments.empty(); }
inline void reset() { mCurrentOffset = 0; }
// Marks a region of the block as "in-use", and provides information about
// the allocated region to the caller. Note: this assumes that numBytes
// is aligned to the physical device's nonCoherentAtomSize.
fvkmemory::resource_ptr<Segment> acquireSegment(fvkmemory::ResourceManager* resManager,
uint32_t numBytes);
private:
VmaAllocator const mAllocator;
const VmaAllocation mMemory;
const VkBuffer mBuffer;
const uint32_t mCapacity;
void* mMapping;
uint32_t mCurrentOffset = 0;
// Maps the start offset of a vulkan stage block to the stage block,
// for easy deletions later. This is managed by the blocks themselves, in an
// RAII pattern, during construction and destruction.
std::unordered_map<uint32_t, Segment*> mSegments;
// Immutable POD representing a shared CPU-GPU staging area.
struct VulkanStage {
VmaAllocation memory;
VkBuffer buffer;
uint32_t capacity;
mutable uint64_t lastAccessed;
};
struct VulkanStageImage {
@@ -139,15 +49,11 @@ struct VulkanStageImage {
// This class manages two types of host-mappable staging areas: buffer stages and image stages.
class VulkanStagePool {
public:
VulkanStagePool(VmaAllocator allocator, fvkmemory::ResourceManager* resManager,
VulkanCommands* commands, const VkPhysicalDeviceLimits* deviceLimits);
VulkanStagePool(VmaAllocator allocator, VulkanCommands* commands);
// Finds or creates a stage block whose capacity is at least the given
// number of bytes. Internally, creates and manages and subdivides large
// buffers so that we have less objects around that we have to keep track
// of.
// This function is NOT thread-safe.
fvkmemory::resource_ptr<VulkanStage::Segment> acquireStage(uint32_t numBytes);
// Finds or creates a stage whose capacity is at least the given number of bytes.
// The stage is automatically released back to the pool after TIME_BEFORE_EVICTION frames.
VulkanStage const* acquireStage(uint32_t numBytes);
// Images have VK_IMAGE_LAYOUT_GENERAL and must not be transitioned to any other layout
VulkanStageImage const* acquireImage(PixelDataFormat format, PixelDataType type,
@@ -158,37 +64,17 @@ public:
// Destroys all unused stages and asserts that there are no stages currently in use.
// This should be called while the context's VkDevice is still alive.
// Note: it is expected that all resources have been reclaimed before this
// is called. It is also expected that this stage pool does not hold any
// resource_ptrs, as this would lead to undefined behavior.
void terminate() noexcept;
private:
VmaAllocator mAllocator;
fvkmemory::ResourceManager* mResManager;
VulkanCommands* mCommands;
const VkPhysicalDeviceLimits* mDeviceLimits;
// Takes a number of bytes, and aligns it to the non-coherent atom size.
// This allows us to ensure that when we flush buffers from the host, we
// never flush more atoms than we need to.
uint32_t alignToNonCoherentAtomSize(uint32_t numBytes);
// Allocates a new stage buffer, and optionally subdivides it into stage
// blocks. If subdivideBlocks is true, predefined divisions will be used.
// Otherwise, it's expected that capacity is defined to a value, and that
// is the size that will be used for the buffer (as well as the only block
// being created).
VulkanStage* allocateNewStage(uint32_t capacity);
// Performs any bookkeeping required to delete a VulkanStage object; namely,
// unmapping memory, freeing the allocation, and deleting the VulkanStage
// object. Note: takes an r-value because after this call, `stage` won't
// exist.
void destroyStage(VulkanStage const*&& stage);
// Use an ordered multimap for quick (capacity => stage) lookups using lower_bound().
std::multimap<uint32_t, VulkanStage*> mStages;
std::multimap<uint32_t, VulkanStage const*> mFreeStages;
// Simple unordered set for stashing a list of in-use stages that can be reclaimed later.
std::vector<VulkanStage const*> mUsedStages;
std::unordered_set<VulkanStageImage const*> mFreeImages;
std::vector<VulkanStageImage const*> mUsedImages;
+27 -81
View File
@@ -25,7 +25,6 @@
#include <backend/DriverEnums.h>
#include <private/backend/BackendUtils.h>
#include <utils/compiler.h>
#include <utils/Panic.h>
using namespace bluevk;
@@ -188,8 +187,8 @@ VkImageUsageFlags getUsage(VulkanContext const& context, uint8_t samples,
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(physicalDevice, vkFormat, &props);
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << vkFormat
<< " is not sampleable with optimal tiling.";
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << vkFormat << " is not "
"sampleable with optimal tiling." << utils::io::endl;
}
}
#endif
@@ -219,40 +218,6 @@ VkImageUsageFlags getUsage(VulkanContext const& context, uint8_t samples,
return usage;
}
void adjustedMemcpy(PixelBufferDescriptor const& p, size_t width, size_t height,
size_t depth, std::function<void(size_t, uint8_t*, size_t)> cpy) {
uint8_t* buf = (uint8_t*) p.buffer;
size_t const pixelSize = PixelBufferDescriptor::computeDataSize(p.format, p.type, 1, 1, 1);
size_t const pbdStride = p.stride ? p.stride : width;
// Slow path of copying row by row
assert_invariant(pbdStride >= width);
if (UTILS_UNLIKELY(p.left > 0 || p.top > 0 || pbdStride > width)) {
size_t const pbdRowSize =
PixelBufferDescriptor::computeDataSize(p.format, p.type, pbdStride, 1, p.alignment);
size_t const pbdHeight = p.size / pixelSize / pbdStride / depth;
size_t const pbdLayerSize = pbdRowSize * pbdHeight;
size_t const rowSize = width * pixelSize;
size_t const layerSize = width * height * pixelSize;
// Size of a row to write
size_t const writeSize = std::min(pbdStride - p.left, width) * pixelSize;
for (size_t z = 0; z < depth; z++) {
for (size_t y = p.top; y < pbdHeight; y++) {
uint8_t* buf = (uint8_t*) p.buffer +
((p.left * pixelSize) + (y * pbdRowSize) + (z * pbdLayerSize));
uint32_t const offset = (y - p.top) * rowSize + z * layerSize;
cpy(offset, buf, writeSize);
}
}
} else {
size_t const writeSize = pixelSize * (width * height * depth);
cpy(0, buf, writeSize);
}
}
} // anonymous namespace
VulkanTextureState::VulkanTextureState(VulkanStagePool& stagePool, VulkanCommands* commands,
@@ -361,7 +326,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
imageInfo.flags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
} else {
FVK_LOGW << "Note: creating 2D views on 3D image is not available on this platform. "
<< "i.e. we cannot render to slices of a 3D image";
<< "i.e. we cannot render to slices of a 3D image" << utils::io::endl;
}
} else if (target == SamplerType::SAMPLER_CUBEMAP) {
imageInfo.arrayLayers = 6;
@@ -420,7 +385,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
<< "type = " << imageInfo.imageType << ", "
<< "flags = " << imageInfo.flags << ", "
<< "target = " << static_cast<int>(target) <<", "
<< "format = " << vkFormat;
<< "format = " << vkFormat << utils::io::endl;
}
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "Unable to create image."
<< " error=" << static_cast<int32_t>(result);
@@ -515,43 +480,30 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt
assert_invariant(hostData->size > 0 && "Data is empty");
// Otherwise, use vkCmdCopyBufferToImage.
size_t const bpp =
PixelBufferDescriptor::computeDataSize(hostData->format, hostData->type, 1, 1, 1);
size_t const writeSize = width * height * depth * bpp;
// Note: the following stageSegment must be stored within the command buffer
// before going out of scope, to ensure proper bookkeeping within the
// staging buffer pool.
fvkmemory::resource_ptr<VulkanStage::Segment> stageSegment =
mState->mStagePool.acquireStage(writeSize);
assert_invariant(stageSegment->memory());
adjustedMemcpy(*hostData, width, height, depth,
[&stageSegment](size_t dstOffset, uint8_t* src, size_t numBytes) {
stageSegment->copy(dstOffset, src, numBytes);
});
// vmaFlushAllocation(mState->mAllocator, stageSegment->memory(), stageSegment->offset(),
// writeSize);
void* mapped = nullptr;
VulkanStage const* stage = mState->mStagePool.acquireStage(hostData->size);
assert_invariant(stage->memory);
vmaMapMemory(mState->mAllocator, stage->memory, &mapped);
memcpy(mapped, hostData->buffer, hostData->size);
vmaUnmapMemory(mState->mAllocator, stage->memory);
vmaFlushAllocation(mState->mAllocator, stage->memory, 0, hostData->size);
VulkanCommandBuffer& commands = mState->mCommands->get();
VkCommandBuffer const cmdbuf = commands.buffer();
commands.acquire(stageSegment);
commands.acquire(fvkmemory::resource_ptr<VulkanTexture>::cast(this));
bool const isDepth = getImageAspect() & VK_IMAGE_ASPECT_DEPTH_BIT;
VkBufferImageCopy copyRegion = {
.bufferOffset = stageSegment->offset(),
.bufferOffset = {},
.bufferRowLength = {},
.bufferImageHeight = {},
.imageSubresource = {
.aspectMask = VkImageAspectFlags(
isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT),
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = miplevel,
.baseArrayLayer = 0,
.layerCount = 1,
.layerCount = 1
},
.imageOffset = { int32_t(xoffset), int32_t(yoffset), int32_t(zoffset) },
.imageExtent = { width, height, depth },
.imageExtent = { width, height, depth }
};
VkImageSubresourceRange transitionRange = {
@@ -559,7 +511,7 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt
.baseMipLevel = miplevel,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
.layerCount = 1
};
// Vulkan specifies subregions for 3D textures differently than from 2D arrays.
@@ -584,28 +536,20 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt
transitionLayout(&commands, transitionRange, newLayout);
vkCmdCopyBufferToImage(cmdbuf, stageSegment->buffer(), mState->mTextureImage, newVkLayout, 1,
&copyRegion);
vkCmdCopyBufferToImage(cmdbuf, stage->buffer, mState->mTextureImage, newVkLayout, 1, &copyRegion);
transitionLayout(&commands, transitionRange, nextLayout);
}
void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& data, uint32_t width,
void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& hostData, uint32_t width,
uint32_t height, uint32_t depth, uint32_t miplevel) {
// Otherwise, use vkCmdCopyBufferToImage.
size_t const bpp = PixelBufferDescriptor::computeDataSize(data.format, data.type, 1, 1, 1);
size_t const writeSize = width * height * depth * bpp;
void* mapped = nullptr;
VulkanStageImage const* stage
= mState->mStagePool.acquireImage(data.format, data.type, width, height);
= mState->mStagePool.acquireImage(hostData.format, hostData.type, width, height);
vmaMapMemory(mState->mAllocator, stage->memory, &mapped);
adjustedMemcpy(data, width, height, depth,
[&mapped](size_t, uint8_t* src, size_t numBytes) {
memcpy(mapped, src, numBytes);
});
memcpy(mapped, hostData.buffer, hostData.size);
vmaUnmapMemory(mState->mAllocator, stage->memory);
vmaFlushAllocation(mState->mAllocator, stage->memory, 0, writeSize);
vmaFlushAllocation(mState->mAllocator, stage->memory, 0, hostData.size);
VulkanCommandBuffer& commands = mState->mCommands->get();
VkCommandBuffer const cmdbuf = commands.buffer();
@@ -737,14 +681,14 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR
<< range.levelCount << ")" << " from=" << oldLayout << " to=" << newLayout
<< " format=" << mState->mVkFormat << " depth="
<< fvkutils::isVkDepthFormat(mState->mVkFormat)
<< " slice-by-slice=" << transitionSliceBySlice;
<< " slice-by-slice=" << transitionSliceBySlice << utils::io::endl;
#endif
} else {
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
FVK_LOGD << "transition texture=" << mState->mTextureImage << " (" << range.baseArrayLayer
<< "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << ","
<< range.levelCount << ")" << " to=" << newLayout
<< " is skipped because of no change in layout";
<< " is skipped because of no change in layout" << utils::io::endl;
#endif
}
@@ -855,7 +799,8 @@ void VulkanTexture::print() const {
level < (mPrimaryViewRange.baseMipLevel + mPrimaryViewRange.levelCount);
FVK_LOGD << "[" << mState->mTextureImage << "]: (" << layer << "," << level
<< ")=" << getLayout(layer, level)
<< " primary=" << primary;
<< " primary=" << primary
<< utils::io::endl;
}
}
@@ -864,7 +809,8 @@ void VulkanTexture::print() const {
FVK_LOGD << "[" << mState->mTextureImage << ", imageView=" << view.second << "]=>"
<< " (" << range.baseArrayLayer << "," << range.baseMipLevel << ")"
<< " count=(" << range.layerCount << "," << range.levelCount << ")"
<< " aspect=" << range.aspectMask << " viewType=" << view.first.type;
<< " aspect=" << range.aspectMask << " viewType=" << view.first.type
<< utils::io::endl;
}
}
#endif
@@ -26,7 +26,6 @@ template ResourceType getTypeEnum<VulkanIndexBuffer>() noexcept;
template ResourceType getTypeEnum<VulkanProgram>() noexcept;
template ResourceType getTypeEnum<VulkanRenderTarget>() noexcept;
template ResourceType getTypeEnum<VulkanSwapChain>() noexcept;
template ResourceType getTypeEnum<VulkanStage::Segment>() noexcept;
template ResourceType getTypeEnum<VulkanRenderPrimitive>() noexcept;
template ResourceType getTypeEnum<VulkanTexture>() noexcept;
template ResourceType getTypeEnum<VulkanTextureState>() noexcept;
@@ -36,7 +35,6 @@ template ResourceType getTypeEnum<VulkanVertexBufferInfo>() noexcept;
template ResourceType getTypeEnum<VulkanDescriptorSetLayout>() noexcept;
template ResourceType getTypeEnum<VulkanDescriptorSet>() noexcept;
template ResourceType getTypeEnum<VulkanFence>() noexcept;
template ResourceType getTypeEnum<VulkanBuffer>() noexcept;
template<typename D>
ResourceType getTypeEnum() noexcept {
@@ -55,9 +53,6 @@ ResourceType getTypeEnum() noexcept {
if constexpr (std::is_same_v<D, VulkanSwapChain>) {
return ResourceType::SWAP_CHAIN;
}
if constexpr (std::is_same_v<D, VulkanStage::Segment>) {
return ResourceType::STAGE_SEGMENT;
}
if constexpr (std::is_same_v<D, VulkanRenderPrimitive>) {
return ResourceType::RENDER_PRIMITIVE;
}
@@ -85,9 +80,6 @@ ResourceType getTypeEnum() noexcept {
if constexpr (std::is_same_v<D, VulkanFence>) {
return ResourceType::FENCE;
}
if constexpr (std::is_same_v<D, VulkanBuffer>) {
return ResourceType::VULKAN_BUFFER;
}
return ResourceType::UNDEFINED_TYPE;
}
@@ -103,8 +95,6 @@ std::string getTypeStr(ResourceType type) {
return "RenderTarget";
case ResourceType::SWAP_CHAIN:
return "SwapChain";
case ResourceType::STAGE_SEGMENT:
return "Stage::Segment";
case ResourceType::RENDER_PRIMITIVE:
return "RenderPrimitive";
case ResourceType::TEXTURE:
@@ -123,8 +113,6 @@ std::string getTypeStr(ResourceType type) {
return "DescriptorSet";
case ResourceType::FENCE:
return "Fence";
case ResourceType::VULKAN_BUFFER:
return "VulkanBuffer";
case ResourceType::UNDEFINED_TYPE:
return "";
}

Some files were not shown because too many files have changed in this diff Show More